Skip to content

Commit

Permalink
Fix for Bug#66430 (16714868), setCatalog on connection leaves ServerP…
Browse files Browse the repository at this point in the history
…reparedStatement cache for old catalog.
  • Loading branch information
fjssilva committed Apr 4, 2017
1 parent aeba572 commit 44631dd
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -2,6 +2,8 @@
# $Id$
mm-dd-yy - Version 5.1.42

- Fix for Bug#66430 (16714868), setCatalog on connection leaves ServerPreparedStatement cache for old catalog.

- Fix for Bug#83662 (25048406), NullPointerException while reading NULL boolean value from DB.

- Fix for Bug#83368 (24841670), 5.1.40 regression: wasNull not updated when calling getInt for a bit column.
Expand Down
14 changes: 11 additions & 3 deletions src/com/mysql/jdbc/ConnectionImpl.java
Expand Up @@ -4061,7 +4061,8 @@ public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType
if (this.useServerPreparedStmts && canServerPrepare) {
if (this.getCachePreparedStatements()) {
synchronized (this.serverSideStatementCache) {
pStmt = (com.mysql.jdbc.ServerPreparedStatement) this.serverSideStatementCache.remove(sql);
pStmt = (com.mysql.jdbc.ServerPreparedStatement) this.serverSideStatementCache
.remove(makePreparedStatementCacheKey(this.database, sql));

if (pStmt != null) {
((com.mysql.jdbc.ServerPreparedStatement) pStmt).setClosed(false);
Expand Down Expand Up @@ -4251,11 +4252,18 @@ public void realClose(boolean calledExplicitly, boolean issueRollback, boolean s

}

private String makePreparedStatementCacheKey(String catalog, String query) {
StringBuilder key = new StringBuilder();
key.append("/*").append(catalog).append("*/");
key.append(query);
return key.toString();
}

public void recachePreparedStatement(ServerPreparedStatement pstmt) throws SQLException {
synchronized (getConnectionMutex()) {
if (getCachePreparedStatements() && pstmt.isPoolable()) {
synchronized (this.serverSideStatementCache) {
this.serverSideStatementCache.put(pstmt.originalSql, pstmt);
this.serverSideStatementCache.put(makePreparedStatementCacheKey(pstmt.currentCatalog, pstmt.originalSql), pstmt);
}
}
}
Expand All @@ -4265,7 +4273,7 @@ public void decachePreparedStatement(ServerPreparedStatement pstmt) throws SQLEx
synchronized (getConnectionMutex()) {
if (getCachePreparedStatements() && pstmt.isPoolable()) {
synchronized (this.serverSideStatementCache) {
this.serverSideStatementCache.remove(pstmt.originalSql);
this.serverSideStatementCache.remove(makePreparedStatementCacheKey(pstmt.currentCatalog, pstmt.originalSql));
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions src/testsuite/regression/StatementRegressionTest.java
Expand Up @@ -8140,4 +8140,68 @@ public ResultSetInternalMethods preProcess(String sql, com.mysql.jdbc.Statement
return super.preProcess(sql, interceptedStatement, connection);
}
}

/**
* Tests fix for Bug#66430 - setCatalog on connection leaves ServerPreparedStatement cache for old catalog.
*/
public void testBug66430() throws Exception {
createDatabase("testBug66430DB1");
createTable("testBug66430DB1.testBug66430", "(id INT)");
this.stmt.executeUpdate("INSERT INTO testBug66430DB1.testBug66430 VALUES (1)");

createDatabase("testBug66430DB2");
createTable("testBug66430DB2.testBug66430", "(id INT)");
this.stmt.executeUpdate("INSERT INTO testBug66430DB2.testBug66430 VALUES (2)");

boolean useSPS = false;
boolean cachePS = false;
do {
final String testCase = String.format("Case: [useSPS: %s, cachePS: %s ]", useSPS ? "Y" : "N", cachePS ? "Y" : "N");

Properties props = new Properties();
props.setProperty("cachePrepStmts", Boolean.toString(cachePS));
props.setProperty("useServerPrepStmts", Boolean.toString(useSPS));

Connection testConn = getConnectionWithProps(props);

testConn.setCatalog("testBug66430DB1");
PreparedStatement testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(testCase, this.rs.next());
assertEquals(testCase, 1, this.rs.getInt(1));
assertFalse(testCase, this.rs.next());
testPStmt.close();

testConn.setCatalog("testBug66430DB2");
testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(testCase, this.rs.next());
assertEquals(testCase, 2, this.rs.getInt(1));
assertFalse(testCase, this.rs.next());
testPStmt.close();

// Do it again to make sure cached prepared statements behave correctly.
testConn.setCatalog("testBug66430DB1");
testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(testCase, this.rs.next());
assertEquals(testCase, 1, this.rs.getInt(1));
assertFalse(testCase, this.rs.next());
testPStmt.close();

testConn.setCatalog("testBug66430DB2");
testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(testCase, this.rs.next());
assertEquals(testCase, 2, this.rs.getInt(1));
assertFalse(testCase, this.rs.next());
testPStmt.close();

testConn.close();
} while ((useSPS = !useSPS) || (cachePS = !cachePS));
}
}

0 comments on commit 44631dd

Please sign in to comment.