Skip to content

Commit aed62b7

Browse files
committed
Fix for Bug#118201 (Bug#37971552), A potential bug in Mysql Connector/J.
Change-Id: I97982f134d40c8f640deaa31ab17a965e1863311
1 parent d4bcee9 commit aed62b7

File tree

5 files changed

+105
-12
lines changed

5 files changed

+105
-12
lines changed

CHANGES

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

44
Version 9.4.0
55

6+
- Fix for Bug#118201 (Bug#37971552), A potential bug in Mysql Connector/J.
7+
68
- Fix for Bug#44791 (Bug#11753361), Setting/getting holdability on connection does not work properly.
79

810
- Fix for Bug#21294134, DBMD.GETPROCEDURECOLUMNS() IS UNABLE TO DEAL WITH PROCEDURE COLUMNS WITH SPACES.

src/main/core-api/java/com/mysql/cj/util/StringUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ public static byte[] getBytesNullTerminated(String value, String encoding) {
15681568
return asBytes;
15691569
}
15701570

1571-
public static boolean canHandleAsServerPreparedStatementNoCache(String sql, ServerVersion serverVersion, boolean allowMultiQueries,
1571+
public static boolean canHandleAsServerPreparedStatementNoCache(String sql, ServerVersion serverVersion, boolean multiQueriesEnabled,
15721572
boolean noBackslashEscapes, boolean useAnsiQuotes) {
15731573
// Can't use server-side prepare for CALL
15741574
if (startsWithIgnoreCaseAndNonAlphaNumeric(sql, "CALL")) {
@@ -1580,7 +1580,7 @@ public static boolean canHandleAsServerPreparedStatementNoCache(String sql, Serv
15801580
boolean allowBackslashEscapes = !noBackslashEscapes;
15811581
String quoteChar = useAnsiQuotes ? "\"" : "'";
15821582

1583-
if (allowMultiQueries) {
1583+
if (multiQueriesEnabled) {
15841584
if (StringUtils.indexOfIgnoreCase(0, sql, ";", quoteChar, quoteChar,
15851585
allowBackslashEscapes ? SearchMode.__BSE_MRK_COM_MYM_HNT_WS : SearchMode.__MRK_COM_MYM_HNT_WS) != -1) {
15861586
canHandleAsStatement = false;

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -490,32 +490,29 @@ private boolean canHandleAsServerPreparedStatement(String sql) throws SQLExcepti
490490
return false;
491491
}
492492

493-
boolean allowMultiQueries = this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue()
493+
boolean multiQueriesEnabled = this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue()
494494
|| this.propertySet.getBooleanProperty(PropertyKey.rewriteBatchedStatements).getValue();
495495

496496
if (this.cachePrepStmts.getValue()) {
497497
this.serverSideStatementCheckCacheLock.lock();
498498
try {
499499
Boolean flag = this.serverSideStatementCheckCache.get(sql);
500-
501500
if (flag != null) {
502501
return flag.booleanValue();
503502
}
504503

505-
boolean canHandle = StringUtils.canHandleAsServerPreparedStatementNoCache(sql, getServerVersion(), allowMultiQueries,
504+
boolean canHandle = StringUtils.canHandleAsServerPreparedStatementNoCache(sql, getServerVersion(), multiQueriesEnabled,
506505
this.session.getServerSession().isNoBackslashEscapesSet(), this.session.getServerSession().useAnsiQuotedIdentifiers());
507-
508506
if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) {
509-
this.serverSideStatementCheckCache.put(sql, canHandle ? Boolean.TRUE : Boolean.FALSE);
507+
this.serverSideStatementCheckCache.put(sql, canHandle);
510508
}
511-
512509
return canHandle;
513510
} finally {
514511
this.serverSideStatementCheckCacheLock.unlock();
515512
}
516513
}
517514

518-
return StringUtils.canHandleAsServerPreparedStatementNoCache(sql, getServerVersion(), allowMultiQueries,
515+
return StringUtils.canHandleAsServerPreparedStatementNoCache(sql, getServerVersion(), multiQueriesEnabled,
519516
this.session.getServerSession().isNoBackslashEscapesSet(), this.session.getServerSession().useAnsiQuotedIdentifiers());
520517
}
521518

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -910,9 +910,8 @@ protected long[] executeBatchInternal() throws SQLException {
910910

911911
this.batchedGeneratedKeys = new ArrayList<>(batchedArgs.size());
912912

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

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

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14242,4 +14242,99 @@ public void testBug77658() throws Exception {
1424214242
interruptorExecService.shutdown();
1424314243
}
1424414244

14245+
/**
14246+
* Tests fix for Bug#118201 (Bug#37971552), A potential bug in Mysql Connector/J.
14247+
*
14248+
* @throws Exception
14249+
*/
14250+
@Test
14251+
void testBug118201() throws Exception {
14252+
createTable("testBug118201", "(id INT PRIMARY KEY)");
14253+
14254+
boolean mltQry = false;
14255+
boolean rwBS = false;
14256+
boolean contBE = false;
14257+
boolean useSPS = false;
14258+
14259+
Properties props = new Properties();
14260+
do {
14261+
props.setProperty(PropertyKey.allowMultiQueries.getKeyName(), Boolean.toString(mltQry));
14262+
props.setProperty(PropertyKey.rewriteBatchedStatements.getKeyName(), Boolean.toString(rwBS));
14263+
props.setProperty(PropertyKey.continueBatchOnError.getKeyName(), Boolean.toString(contBE));
14264+
14265+
this.stmt.execute("TRUNCATE TABLE testBug118201");
14266+
this.stmt.executeUpdate("INSERT INTO testBug118201 VALUES (3)");
14267+
14268+
// Test Statement.
14269+
String testCase = String.format("Case [mulitQueries: %s, rwBS: %s, contBE: %s]", mltQry ? "Y" : "N", rwBS ? "Y" : "N", contBE ? "Y" : "N");
14270+
try (Connection testConn = getConnectionWithProps(props)) {
14271+
Statement testStmt = testConn.createStatement();
14272+
testStmt.addBatch("INSERT INTO testBug118201 VALUES (1)");
14273+
testStmt.addBatch("INSERT INTO testBug118201 VALUES (2)");
14274+
testStmt.addBatch("INSERT INTO testBug118201 VALUES (3)");
14275+
testStmt.addBatch("INSERT INTO testBug118201 VALUES (4)");
14276+
testStmt.addBatch("INSERT INTO testBug118201 VALUES (5)");
14277+
assertThrows(BatchUpdateException.class, "(?i)Duplicate entry '3' for key 'testBug118201.PRIMARY'", testStmt::executeBatch);
14278+
}
14279+
14280+
this.rs = this.stmt.executeQuery("SELECT * FROM testBug118201");
14281+
assertTrue(this.rs.next(), testCase);
14282+
assertEquals(1, this.rs.getInt(1), testCase);
14283+
assertTrue(this.rs.next(), testCase);
14284+
assertEquals(2, this.rs.getInt(1), testCase);
14285+
assertTrue(this.rs.next(), testCase);
14286+
assertEquals(3, this.rs.getInt(1), testCase);
14287+
if (!rwBS && contBE) {
14288+
assertTrue(this.rs.next(), testCase);
14289+
assertEquals(4, this.rs.getInt(1), testCase);
14290+
assertTrue(this.rs.next(), testCase);
14291+
assertEquals(5, this.rs.getInt(1), testCase);
14292+
}
14293+
assertFalse(this.rs.next(), testCase);
14294+
14295+
do {
14296+
this.stmt.execute("TRUNCATE TABLE testBug118201");
14297+
this.stmt.executeUpdate("INSERT INTO testBug118201 VALUES (3)");
14298+
14299+
// Test client and server PreparedStatement.
14300+
testCase = String.format("Case [mulitQueries: %s, rwBS: %s, contBE: %s, useSPS: %s]", mltQry ? "Y" : "N", rwBS ? "Y" : "N", contBE ? "Y" : "N",
14301+
useSPS ? "Y" : "N");
14302+
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), Boolean.toString(useSPS));
14303+
try (Connection testConn = getConnectionWithProps(props)) {
14304+
PreparedStatement testPstmt = testConn.prepareStatement("INSERT INTO testBug118201 VALUES (?)");
14305+
testPstmt.setInt(1, 1);
14306+
testPstmt.addBatch();
14307+
testPstmt.setInt(1, 2);
14308+
testPstmt.addBatch();
14309+
testPstmt.setInt(1, 3);
14310+
testPstmt.addBatch();
14311+
testPstmt.setInt(1, 4);
14312+
testPstmt.addBatch();
14313+
testPstmt.setInt(1, 5);
14314+
testPstmt.addBatch();
14315+
assertThrows(BatchUpdateException.class, "(?i)Duplicate entry '3' for key 'testBug118201.PRIMARY'", testPstmt::executeBatch);
14316+
}
14317+
14318+
this.rs = this.stmt.executeQuery("SELECT * FROM testBug118201");
14319+
assertTrue(this.rs.next(), testCase);
14320+
if (rwBS) {
14321+
assertEquals(3, this.rs.getInt(1), testCase);
14322+
} else {
14323+
assertEquals(1, this.rs.getInt(1), testCase);
14324+
assertTrue(this.rs.next(), testCase);
14325+
assertEquals(2, this.rs.getInt(1), testCase);
14326+
assertTrue(this.rs.next(), testCase);
14327+
assertEquals(3, this.rs.getInt(1), testCase);
14328+
if (contBE) {
14329+
assertTrue(this.rs.next(), testCase);
14330+
assertEquals(4, this.rs.getInt(1), testCase);
14331+
assertTrue(this.rs.next(), testCase);
14332+
assertEquals(5, this.rs.getInt(1), testCase);
14333+
}
14334+
}
14335+
assertFalse(this.rs.next(), testCase);
14336+
} while (useSPS = !useSPS);
14337+
} while ((mltQry = !mltQry) || (rwBS = !rwBS) || (contBE = !contBE));
14338+
}
14339+
1424514340
}

0 commit comments

Comments
 (0)