Skip to content

Commit b369d81

Browse files
committed
Fix for Bug#118234 (Bug#37975837), A potential bugs in Mysql Connector/J.
Change-Id: I7680705cdb675434e8e51192f0af84319e541b49
1 parent af0aa94 commit b369d81

5 files changed

Lines changed: 61 additions & 19 deletions

File tree

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Version 9.6.0
55

6+
- Fix for Bug#118234 (Bug#37975837), A potential bugs in Mysql Connector/J.
7+
68
- Fix for Bug#113413 (Bug#36107426), Connection.changeUser cannot be done after DriverManager.loginTimeout elapses.
79
Thanks to Kazuhisa Kawashima for his contribution.
810

src/build/java/instrumentation/TranslateExceptions.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,7 @@ public static void main(String[] args) throws Exception {
379379
catchRuntimeException(clazz, clazz.getDeclaredMethod("createResultSetUsingServerFetch", new CtClass[] { ctString }), EXCEPTION_INTERCEPTOR_GETTER);
380380
catchRuntimeException(clazz, clazz.getDeclaredMethod("doPingInstead", new CtClass[] {}), EXCEPTION_INTERCEPTOR_GETTER);
381381
catchRuntimeException(clazz, clazz.getDeclaredMethod("executeInternal", new CtClass[] { ctString, CtClass.booleanType }), EXCEPTION_INTERCEPTOR_GETTER);
382-
catchRuntimeException(clazz,
383-
clazz.getDeclaredMethod("executeBatchUsingMultiQueries", new CtClass[] { CtClass.booleanType, CtClass.intType, CtClass.longType }),
382+
catchRuntimeException(clazz, clazz.getDeclaredMethod("executeBatchUsingMultiQueries", new CtClass[] { CtClass.longType }),
384383
EXCEPTION_INTERCEPTOR_GETTER);
385384
catchRuntimeException(clazz, clazz.getDeclaredMethod("executeUpdateInternal", new CtClass[] { ctString, CtClass.booleanType, CtClass.booleanType }),
386385
EXCEPTION_INTERCEPTOR_GETTER);

src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ ConnectionProperties.categoryUserDefined=User-defined properties
10531053
# ConnectionProperty Descriptions
10541054
#
10551055

1056-
ConnectionProperties.allowMultiQueries=Allow the use of ";" to delimit multiple queries during one statement. This option does not affect the ''addBatch()'' and ''executeBatch()'' methods, which rely on ''rewriteBatchStatements'' instead.
1056+
ConnectionProperties.allowMultiQueries=Allow the use of ";" to delimit multiple queries during one statement. This option does not affect the ''addBatch()'' and ''executeBatch()'' methods, which rely on ''rewriteBatchedStatements'' instead.
10571057
ConnectionProperties.allowNANandINF=Should the driver allow NaN or +/- INF values in ''PreparedStatement.setDouble()''?
10581058
ConnectionProperties.allowPublicKeyRetrieval=Allows special handshake round-trip to get an RSA public key directly from server.
10591059
ConnectionProperties.allowReplicaDownConnections=By default, a replication-aware connection will fail to connect when configured replica hosts are all unavailable at initial connection. Setting this property to "true" allows to establish the initial connection. It won''t prevent failures when switching to replicas i.e. by setting the replication connection to read-only state. The property ''readFromSourceWhenNoReplicas'' should be used for this purpose.

src/main/user-impl/java/com/mysql/cj/jdbc/StatementImpl.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -907,12 +907,10 @@ protected long[] executeBatchInternal() throws SQLException {
907907

908908
if (batchedArgs != null) {
909909
int nbrCommands = batchedArgs.size();
910-
911-
this.batchedGeneratedKeys = new ArrayList<>(batchedArgs.size());
910+
this.batchedGeneratedKeys = new ArrayList<>(nbrCommands);
912911

913912
if (this.rewriteBatchedStatements.getValue() && nbrCommands > 4) {
914-
boolean multiQueriesEnabled = locallyScopedConn.getPropertySet().getBooleanProperty(PropertyKey.allowMultiQueries).getValue();
915-
return executeBatchUsingMultiQueries(multiQueriesEnabled, nbrCommands, individualStatementTimeout);
913+
return executeBatchUsingMultiQueries(individualStatementTimeout);
916914
}
917915

918916
timeoutTask = startQueryTimer(this, individualStatementTimeout);
@@ -1014,34 +1012,30 @@ protected final boolean hasDeadlockOrTimeoutRolledBackTx(SQLException ex) {
10141012
/**
10151013
* Rewrites batch into a single query to send to the server. This method will constrain each batch to be shorter than max_allowed_packet on the server.
10161014
*
1017-
* @param multiQueriesEnabled
1018-
* is multi-queries syntax allowed?
1019-
* @param nbrCommands
1020-
* number of queries in a batch
10211015
* @param individualStatementTimeout
10221016
* timeout for a single query in a batch
10231017
*
10241018
* @return update counts in the same manner as executeBatch()
10251019
* @throws SQLException
10261020
* if a database access error occurs or this method is called on a closed PreparedStatement
10271021
*/
1028-
private long[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled, int nbrCommands, long individualStatementTimeout) throws SQLException {
1022+
private long[] executeBatchUsingMultiQueries(long individualStatementTimeout) throws SQLException {
10291023
JdbcConnection locallyScopedConn = checkClosed();
10301024

10311025
Lock connectionLock = locallyScopedConn.getConnectionLock();
10321026
connectionLock.lock();
10331027
try {
1028+
boolean multiQueriesEnabled = locallyScopedConn.getPropertySet().getBooleanProperty(PropertyKey.allowMultiQueries).getValue();
10341029
if (!multiQueriesEnabled) {
1035-
this.session.enableMultiQueries();
1030+
this.session.enableMultiQueries(); // Temporarily enable multi-queries.
10361031
}
10371032

10381033
java.sql.Statement batchStmt = null;
1039-
10401034
CancelQueryTask timeoutTask = null;
1041-
10421035
try {
1036+
List<Object> batchedArgs = this.query.getBatchedArgs();
1037+
int nbrCommands = batchedArgs.size();
10431038
long[] updateCounts = new long[nbrCommands];
1044-
10451039
for (int i = 0; i < nbrCommands; i++) {
10461040
updateCounts[i] = Statement.EXECUTE_FAILED;
10471041
}
@@ -1074,14 +1068,17 @@ private long[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled, int nb
10741068
SQLException sqlEx = null;
10751069

10761070
int argumentSetsInBatchSoFar = 0;
1077-
1071+
boolean batchContainsResultSetProducingQuery = false;
10781072
for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
10791073
String nextQuery = (String) this.query.getBatchedArgs().get(commandIndex);
10801074

10811075
if (queryBuf.length() > 0 && ((queryBuf.length() + nextQuery.length()) * numberOfBytesPerChar + 1 /* for semicolon */
10821076
+ NativeConstants.HEADER_LENGTH) * escapeAdjust + 32 > this.maxAllowedPacket.getValue()) {
10831077
try {
1084-
batchStmt.execute(queryBuf.toString(), java.sql.Statement.RETURN_GENERATED_KEYS);
1078+
if (batchContainsResultSetProducingQuery) {
1079+
throw SQLError.createSQLException(Messages.getString("Statement.46"), "01S03", getExceptionInterceptor());
1080+
}
1081+
batchStmt.executeUpdate(queryBuf.toString(), java.sql.Statement.RETURN_GENERATED_KEYS);
10851082
} catch (SQLException ex) {
10861083
sqlEx = handleExceptionForBatch(commandIndex, argumentSetsInBatchSoFar, updateCounts, ex);
10871084
}
@@ -1090,16 +1087,21 @@ private long[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled, int nb
10901087

10911088
queryBuf = new StringBuilder();
10921089
argumentSetsInBatchSoFar = 0;
1090+
batchContainsResultSetProducingQuery = false;
10931091
}
10941092

1093+
batchContainsResultSetProducingQuery = batchContainsResultSetProducingQuery || !isNonResultSetProducingQuery(nextQuery);
10951094
queryBuf.append(nextQuery);
10961095
queryBuf.append(";");
10971096
argumentSetsInBatchSoFar++;
10981097
}
10991098

11001099
if (queryBuf.length() > 0) {
11011100
try {
1102-
batchStmt.execute(queryBuf.toString(), java.sql.Statement.RETURN_GENERATED_KEYS);
1101+
if (batchContainsResultSetProducingQuery) {
1102+
throw SQLError.createSQLException(Messages.getString("Statement.46"), "01S03", getExceptionInterceptor());
1103+
}
1104+
batchStmt.executeUpdate(queryBuf.toString(), java.sql.Statement.RETURN_GENERATED_KEYS);
11031105
} catch (SQLException ex) {
11041106
sqlEx = handleExceptionForBatch(commandIndex - 1, argumentSetsInBatchSoFar, updateCounts, ex);
11051107
}

src/test/java/testsuite/regression/StatementRegressionTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14674,4 +14674,43 @@ void testBug119245() throws Exception {
1467414674
assertDoesNotThrow(() -> this.stmt.executeQuery("SELECT INTOpos FROM testBug119245").close());
1467514675
}
1467614676

14677+
/**
14678+
* Tests fix for Bug#118234 (Bug#37975837), A potential bugs in Mysql Connector/J.
14679+
*
14680+
* @throws Exception
14681+
*/
14682+
@Test
14683+
public void testBug118234() throws Exception {
14684+
boolean rwBS = false;
14685+
14686+
do {
14687+
Properties props = new Properties();
14688+
props.setProperty(PropertyKey.rewriteBatchedStatements.getKeyName(), Boolean.toString(rwBS));
14689+
14690+
for (int numQueries = 1; numQueries <= 5; numQueries++) { // Batch is rewritten as multi-query when batch size is above 4 queries.
14691+
String testCase = String.format("Case [rwBS: %s, NumSelects: %d]", rwBS ? "Y" : "N", numQueries);
14692+
14693+
try (Connection testConn = getConnectionWithProps(props)) {
14694+
Statement testStmt = testConn.createStatement();
14695+
testStmt.addBatch("SET @testBug118234 = 'Connector/J'");
14696+
for (int i = 0; i < numQueries; i++) {
14697+
testStmt.addBatch("SELECT 1");
14698+
}
14699+
assertThrows(testCase, BatchUpdateException.class,
14700+
"Statement\\.executeUpdate\\(\\) or Statement\\.executeLargeUpdate\\(\\) cannot issue statements that produce result sets\\.",
14701+
testStmt::executeBatch);
14702+
14703+
this.rs = testStmt.executeQuery("SELECT @testBug118234");
14704+
assertTrue(this.rs.next(), testCase);
14705+
if (rwBS && numQueries >= 4) { // Entire rewritten batch fails.
14706+
assertNull(this.rs.getString(1), testCase);
14707+
} else {
14708+
assertEquals("Connector/J", this.rs.getString(1), testCase);
14709+
}
14710+
assertFalse(this.rs.next(), testCase);
14711+
}
14712+
}
14713+
} while (rwBS = !rwBS);
14714+
}
14715+
1467714716
}

0 commit comments

Comments
 (0)