New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AWS MySQL script execution raises UnableToExecuteStatementException when includes begin..end;
block under certain conditions
#2554
Comments
begin..end;
block under certain conditionsbegin..end;
block under certain conditions
Hi, so this does not seem to be specific to the AWS driver. I can make the following test pass: @Test
public void testIssue2554() {
String sqlScript = "CREATE PROCEDURE QWE()\n" +
"BEGIN\n" +
"END;\n" +
"SELECT 1 FROM DUAL;\n" +
"SELECT 1 FROM DUAL;\n" +
"SELECT 1 FROM DUAL;\n" +
"SELECT 1 FROM DUAL;\n";
int[] result = extension.getJdbi().withHandle(h -> h.createScript(sqlScript).execute());
assertThat(result).isEqualTo(new int[] {0, -1, -1, -1, -1});
} by commenting out these lines: https://github.com/jdbi/jdbi/blob/master/core/src/main/java/org/jdbi/v3/core/internal/SqlScriptParser.java#L114-L116 otherwise I get:
the difference is that the parser right now (with 3.42.0) creates
as separate statements and with the lines removed, it does
note the missing semicolon at the end of the first statement. However, removing the lines above fails this test in core/TestScript` /**
* <p>
* Test for correct handling of semicolons in sql containing begin/end blocks.
* </p>
* <p>
* Class {@link Script} splits sql scripts into lists of statements by semicolon ({@code ;}) and then batch-executes them.<br>
* Statements may contain {@code BEGIN...END} blocks containing subordinated statements (also ending in semicolons).<br>
* Only semicolons on the highest level (i.e. outside any block) actually signal the end of an sql statement.
* </p>
* @throws SQLException on failure to create the database handle
*/
@Test
public void testOracleScriptWithBeginEndBlock() throws SQLException {
String sql = getClasspathSqlLocator().getResource("script/oracle-with-begin-end-blocks.sql");
try (Script script = new Script(HandleAccess.createHandle(), sql)) {
List<String> statements = script.getStatements();
assertThat(statements).hasSize(3);
// local variable of CharSequence not String because
// CharSequence.chars() since Java 1.8 <=> String.chars() since Java 9
CharSequence lastStmt = statements.get(2);
assertThat(lastStmt)
.startsWith("CREATE OR REPLACE TRIGGER EXAMPLE_TRIGGER")
.endsWith("END;")
.hasLineCount(15)
.has(new Condition<>(s -> 7 == s.chars().filter(ch -> ch == ';').count(), "count semicolons"));
}
} Note that this test exists to explicitly test that there is a semicolon at the end of an I feel we are now in the "different SQL dialects" territory, something that we always tried to keep away from. I need someone else to look at this. @stevenschlansker? |
I think the oracle script test is more checking that the script inner semicolons are preserved, not that the |
It seems the fix for 2021 was too overeager in keeping the last semicolon; at least for modern oracle this seems not to be needed but in turn it breaks MySQL scripting (jdbi#2554). Remove the special casing for the last semicolon after an `END` statement.
Turns out that MySQL and Oracle simply have differing ideas on what a statement in a script should be. Oracle needs the trailing semicolons, MySQL throws syntax errors (when using the rewriteBatchedStatements=true setting, otherwise it reports a much saner "cannot issue select statements with update" type of error message. Added a switch that retains the default behavior but can be flipped to allow the error case described in jdbi#2554 to work. Reported by @IrinaTerlizhenko, thank you for this!
No, there is specific code in the parser that ensures that the final semicolon stays there. Turns out that oracle does need it while MySQL calls it a syntax error. The proposed PR (#2559) makes that configurable. I am afraid, @IrinaTerlizhenko as "keeping the semicolon" is the current behavior, you will need to add a minor modification to your code. Assuming that you are using MySQL uniformly, call I actually think that the error message is a red herring / a bug in the driver as the driver behaves dramatically different if This will be 3.43.0, there are two new bug reports that I would like to glance at briefly before releasing; expect a release later this week. |
Turns out that MySQL and Oracle simply have differing ideas on what a statement in a script should be. Oracle needs the trailing semicolons, MySQL throws syntax errors (when using the rewriteBatchedStatements=true setting, otherwise it reports a much saner "cannot issue select statements with update" type of error message. Added a switch that retains the default behavior but can be flipped to allow the error case described in jdbi#2554 to work. Reported by @IrinaTerlizhenko, thank you for this!
This should be finally laid to rest with the next release. |
Script execution fails in case the following conditions are satisfied:
begin..end
blockrewriteBatchedStatements=true
parameter is set in the connection stringThe issue is reproducible in
3.42.0
and doesn't appear in3.30.0
. Cannot easily check versions in between because of the previous bug #2535.JDBI versions:
3.42.0
Java version:
11
MySQL version:
8.0.32
JDBC Driver:
software.aws.rds:aws-mysql-jdbc:1.1.11
Test to reproduce:
Other 4 statements can be anything, used
SELECT 1 FROM DUAL;
here.I managed to track this issue down to the place in
aws-mysql-jdbc
driver: https://github.com/awslabs/aws-mysql-jdbc/blob/820cab7e48dc7f2324ee2522f3d15d673adc3c6b/src/main/user-impl/java/com/mysql/cj/jdbc/StatementImpl.java#L841C25-L841C25Checking the SQL statements in debug mode there, the difference that I see that after
END;
there is a trailing semicolon, while for other statements it is removed when preparing a batch. If I run the same test with3.30.0
JDBI version, I also see no semicolon afterEND
.The text was updated successfully, but these errors were encountered: