Reputation: 643
I have a Spring CRUD application, with an Oracle SQL database.
I have several integration tests and use the @Sql
annotation to run .sql files which put the database in a desired state before running the test. I have had no problem with any of my .sql scripts so far, although they have all be very simple INSERT and DROP statements.
I am now trying to set up a scenario in which the database holds thousands of records in a particular table. I am not bothered about the content, only the number of records.
In order to replicate this scenario, I have written the following SQL script:
DECLARE
id integer := 1;
BEGIN
WHILE id <= 3000
LOOP
INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE)
VALUES (id, 'John', 'Smith', 32);
id := id + 1;
END LOOP;
END;
I have ran this script using IntelliJ and it works as expected.
However, when I put the script into a @Sql annotation, I run into the following error:
org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [sql/setUp.sql]: DECLARE id integer := 1; nested exception is java.sql.SQLException: ORA-06550: line 1, column 23:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
I am at a loss as to the solution; I have encountered similar issues where the solution was just a missing semi-colon, but that doesn't seem to be the case here. What's even more mystifying is that I tried running the following script via the @Sql annotation:
BEGIN
INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE)
VALUES (1, 'John', 'Smith', 32);
END;
This produced the following error, which makes even less sense:
org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [sql/test.sql]: BEGIN INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE) VALUES (1, 'John', 'Smith', 32); nested exception is java.sql.SQLException: ORA-06550: line 1, column 87:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
;
Most interesting to note is that removing the BEGIN and END statements (leaving just the INSERT INTO statement) works.
So does Spring JDBC simply not support BEGIN/END blocks? Are there limitations to the pre test @Sql annotation that I'm not aware of? Or have I missed something painfully obvious?
Upvotes: 1
Views: 1727
Reputation: 643
Thanks to @MarkRotteveel for his suggestion, I have discovered the solution to this issue.
JDBC was indeed running each line of the script as if it was a separate statement, which is incompatible with statement blocks. This is because the separator
is set to the ;
symbol by default, causing JDBC to treat each block of code ended with a ;
as if it was a separate script. I set this separator to the EOF symbol, which caused JDBC to treat the whole file as a single script.
My original test code looked something like this:
@Sql(scripts = {"sql/cleanup.sql", "sql/setUp.sql"})
public void testWithThousandsOfRecords() {
// do tests
}
My test code now looks like this:
@Sql(scripts = "sql/cleanup.sql")
@Sql(scripts = "sql/setUp.sql", config = @SqlConfig(separator = ScriptUtils.EOF_STATEMENT_SEPARATOR))
public void testWithThousandsOfRecords() {
// do tests
}
Note that I had to separate my cleanup and setUp scripts, as changing the separator may break some scripts that worked before.
Upvotes: 2