use of com.mysql.cj.jdbc.ServerPreparedStatement in project aws-mysql-jdbc by awslabs.
the class StatementsTest method testServerPreparedStatementsCaching.
/**
* WL#11101 - Remove de-cache and close of SSPSs on double call to close()
*
* @throws Exception
*/
@Test
public void testServerPreparedStatementsCaching() throws Exception {
// Non prepared statements must be non-poolable by default.
assertFalse(this.stmt.isPoolable());
Field stmtsCacheField = ConnectionImpl.class.getDeclaredField("serverSideStatementCache");
stmtsCacheField.setAccessible(true);
ToIntFunction<Connection> getStmtsCacheSize = (c) -> {
try {
LRUCache<?, ?> stmtsCacheObj = (LRUCache<?, ?>) stmtsCacheField.get(c);
return stmtsCacheObj == null ? -1 : stmtsCacheObj.size();
} catch (IllegalArgumentException | IllegalAccessException e) {
fail("Fail getting the statemets cache size.");
return -1;
}
};
Function<Connection, ServerPreparedStatement> getStmtsCacheSingleElem = (c) -> {
try {
@SuppressWarnings("unchecked") LRUCache<?, ServerPreparedStatement> stmtsCacheObj = (LRUCache<?, ServerPreparedStatement>) stmtsCacheField.get(c);
return stmtsCacheObj.get(stmtsCacheObj.keySet().iterator().next());
} catch (IllegalArgumentException | IllegalAccessException e) {
fail("Fail getting the statemets cache element.");
return null;
}
};
final String sql1 = "SELECT 1, ?";
final String sql2 = "SELECT 2, ?";
boolean useSPS = false;
boolean cachePS = false;
do {
Properties props = new Properties();
props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), Boolean.toString(useSPS));
props.setProperty(PropertyKey.cachePrepStmts.getKeyName(), Boolean.toString(cachePS));
props.setProperty(PropertyKey.prepStmtCacheSize.getKeyName(), "5");
boolean cachedSPS = useSPS && cachePS;
/*
* Cache the prepared statement and de-cache it later.
* (*) if server prepared statement and caching is enabled.
*/
{
JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(props);
PreparedStatement testPstmt = testConn.prepareStatement(sql1);
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertTrue(testPstmt.isPoolable());
// Caches this PS (*).
testPstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
// No-op.
testPstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
if (cachedSPS) {
assertTrue(testPstmt.isPoolable());
// De-caches this PS; it gets automatically closed (*).
testPstmt.setPoolable(false);
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(0, getStmtsCacheSize.applyAsInt(testConn));
}
// No-op.
testPstmt.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertThrows(SQLException.class, "No operations allowed after statement closed\\.", () -> {
testPstmt.setPoolable(false);
return null;
});
assertThrows(SQLException.class, "No operations allowed after statement closed\\.", () -> {
testPstmt.isPoolable();
return null;
});
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
/*
* Set not to cache the prepared statement.
* (*) if server prepared statement and caching is enabled.
*/
{
JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(props);
PreparedStatement testPstmt = testConn.prepareStatement(sql1);
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertTrue(testPstmt.isPoolable());
// Don't cache this PS (*).
testPstmt.setPoolable(false);
assertFalse(testPstmt.isPoolable());
// Doesn't cache this PS (*).
testPstmt.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
// No-op.
testPstmt.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertThrows(SQLException.class, "No operations allowed after statement closed\\.", () -> {
testPstmt.setPoolable(true);
return null;
});
assertThrows(SQLException.class, "No operations allowed after statement closed\\.", () -> {
testPstmt.isPoolable();
return null;
});
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
/*
* Set not to cache the prepared statement but change mind before closing it.
* Reuse the cached prepared statement and don't re-cache it.
* (*) if server prepared statement and caching is enabled.
*/
{
JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(props);
PreparedStatement testPstmt = testConn.prepareStatement(sql1);
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
// Don't cache this PS (*).
testPstmt.setPoolable(false);
assertFalse(testPstmt.isPoolable());
testPstmt.setPoolable(true);
// Changed my mind, let it be cached (*).
assertTrue(testPstmt.isPoolable());
// Caches this PS (*).
testPstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
// No-op.
testPstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
PreparedStatement testPstmtOld = testPstmt;
// Takes the cached statement (*), or creates a fresh one.
testPstmt = testConn.prepareStatement(sql1);
if (cachedSPS) {
assertSame(testPstmtOld, testPstmt);
} else {
assertNotSame(testPstmtOld, testPstmt);
}
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertTrue(testPstmt.isPoolable());
// Don't cache this PS (*).
testPstmt.setPoolable(false);
assertFalse(testPstmt.isPoolable());
// Doesn't cache this PS (*).
testPstmt.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
testPstmtOld = testPstmt;
// Creates a fresh prepared statement.
testPstmt = testConn.prepareStatement(sql1);
assertNotSame(testPstmtOld, testPstmt);
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertTrue(testPstmt.isPoolable());
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
/*
* Caching of multiple copies of same prepared statement.
* (*) if server prepared statement and caching is enabled.
*/
{
int psCount = 5;
JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(props);
PreparedStatement[] testPstmts = new PreparedStatement[psCount];
for (int i = 0; i < psCount; i++) {
testPstmts[i] = testConn.prepareStatement(sql1);
}
assertEquals(5, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
for (int i = 0; i < psCount; i++) {
assertTrue(testPstmts[i].isPoolable());
// Caches this PS and replaces existing if same (*).
testPstmts[i].close();
assertEquals(cachedSPS ? psCount - i : psCount - i - 1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
if (cachedSPS) {
assertSame(testPstmts[i], getStmtsCacheSingleElem.apply(testConn));
}
}
PreparedStatement testPstmt = testConn.prepareStatement(sql1);
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
for (int i = 0; i < psCount; i++) {
if (cachedSPS && i == psCount - 1) {
assertSame(testPstmts[i], testPstmt);
} else {
assertNotSame(testPstmts[i], testPstmt);
}
}
// Don't cache this PS (*).
testPstmt.setPoolable(false);
// Doesn't cache this PS (*).
testPstmt.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
/*
* Combine caching different prepared statements.
* (*) if server prepared statement and caching is enabled.
*/
{
int psCount = 5;
JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(props);
PreparedStatement[] testPstmts1 = new PreparedStatement[psCount];
for (int i = 0; i < psCount; i++) {
testPstmts1[i] = testConn.prepareStatement(sql1);
}
PreparedStatement testPstmt = testConn.prepareStatement(sql2);
assertEquals(6, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
assertTrue(testPstmt.isPoolable());
// Caches this PS (*).
testPstmt.close();
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
for (int i = 0; i < psCount; i++) {
assertTrue(testPstmts1[i].isPoolable());
// Caches this PS and replaces existing if same (*).
testPstmts1[i].close();
assertEquals(cachedSPS ? psCount - i + 1 : psCount - i - 1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 2 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
PreparedStatement testPstmt1 = testConn.prepareStatement(sql1);
assertEquals(cachedSPS ? 2 : 1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
for (int i = 0; i < psCount; i++) {
if (cachedSPS && i == psCount - 1) {
assertSame(testPstmts1[i], testPstmt1);
} else {
assertNotSame(testPstmts1[i], testPstmt1);
}
}
PreparedStatement testPstmt2 = testConn.prepareStatement(sql2);
assertEquals(2, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
if (cachedSPS) {
assertSame(testPstmt, testPstmt2);
} else {
assertNotSame(testPstmt, testPstmt2);
}
// Don't cache this PS (*).
testPstmt1.setPoolable(false);
// Doesn't cache this PS (*).
testPstmt1.close();
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
// Don't cache this PS (*).
testPstmt2.setPoolable(false);
// Doesn't cache this PS (*).
testPstmt2.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
} while ((useSPS = !useSPS) || (cachePS = !cachePS));
}
use of com.mysql.cj.jdbc.ServerPreparedStatement in project aws-mysql-jdbc by awslabs.
the class ResultSetRegressionTest method testBug25650385.
/**
* Tests fix for BUG#25650385, GETBYTE() RETURNS ERROR FOR BINARY() FLD.
*
* @throws Exception
*/
@Test
public void testBug25650385() throws Exception {
/*
* getByte (recommended for TINYINT):
* TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, BOOLEAN, CHAR , VARCHAR , LONGVARCHAR, ROWID
*/
createTable("testBug25650385", "(b1 blob(12), c1 char(12), c2 binary(12), i1 int, c3 char(12) CHARACTER SET binary)");
this.stmt.execute("INSERT INTO testBug25650385 values (10, 'a', 48, 10, 23)");
Properties props = new Properties();
props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
for (boolean useSSPS : new boolean[] { false, true }) {
for (boolean jdbcCompliantTruncation : new boolean[] { false, true }) {
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "" + useSSPS);
props.setProperty(PropertyKey.jdbcCompliantTruncation.getKeyName(), "" + jdbcCompliantTruncation);
Connection c1 = getConnectionWithProps(props);
this.pstmt = c1.prepareStatement("select * from testBug25650385");
if (useSSPS) {
assertTrue(this.pstmt instanceof ServerPreparedStatement);
}
ResultSet rs1 = this.pstmt.executeQuery();
assertTrue(rs1.next());
// from blob(12)
assertEquals('1', rs1.getBytes(1)[0]);
if (jdbcCompliantTruncation) {
assertThrows(SQLDataException.class, "Value '10' is outside of valid range for type java.lang.Byte", new Callable<Void>() {
public Void call() throws Exception {
rs1.getByte(1);
return null;
}
});
} else {
assertEquals('1', rs1.getByte(1));
}
assertEquals(10, rs1.getInt(1));
assertEquals(10L, rs1.getLong(1));
assertEquals(10, rs1.getShort(1));
assertEquals("10", rs1.getString(1));
// from c1 char(12)
assertEquals('a', rs1.getBytes(2)[0]);
assertEquals('a', rs1.getByte(2));
assertThrows(SQLDataException.class, "Cannot determine value type from string 'a'", new Callable<Void>() {
public Void call() throws Exception {
rs1.getInt(2);
return null;
}
});
assertThrows(SQLDataException.class, "Cannot determine value type from string 'a'", new Callable<Void>() {
public Void call() throws Exception {
rs1.getLong(2);
return null;
}
});
assertThrows(SQLDataException.class, "Cannot determine value type from string 'a'", new Callable<Void>() {
public Void call() throws Exception {
rs1.getShort(2);
return null;
}
});
assertEquals("a", rs1.getString(2));
// from c2 binary(12)
assertEquals('4', rs1.getBytes(3)[0]);
if (jdbcCompliantTruncation) {
assertThrows(SQLDataException.class, "Value '48.+ is outside of valid range for type java.lang.Byte", new Callable<Void>() {
public Void call() throws Exception {
rs1.getByte(3);
return null;
}
});
} else {
assertEquals('4', rs1.getByte(3));
}
assertThrows(SQLDataException.class, "Cannot determine value type from string '48.+", new Callable<Void>() {
public Void call() throws Exception {
rs1.getInt(3);
return null;
}
});
assertThrows(SQLDataException.class, "Cannot determine value type from string '48.+", new Callable<Void>() {
public Void call() throws Exception {
rs1.getLong(3);
return null;
}
});
assertThrows(SQLDataException.class, "Cannot determine value type from string '48.+", new Callable<Void>() {
public Void call() throws Exception {
rs1.getShort(3);
return null;
}
});
assertTrue(rs1.getString(3).startsWith("48"));
// from i1 int
if (useSSPS) {
assertEquals(10, rs1.getBytes(4)[0]);
} else {
assertEquals('1', rs1.getBytes(4)[0]);
}
assertEquals(10, rs1.getByte(4));
assertEquals(10, rs1.getInt(4));
assertEquals(10, rs1.getLong(4));
assertEquals(10, rs1.getShort(4));
assertEquals("10", rs1.getString(4));
// from c3 char(12) CHARACTER SET binary
assertEquals('2', rs1.getBytes(5)[0]);
if (jdbcCompliantTruncation) {
assertThrows(SQLDataException.class, "Value '23.+ is outside of valid range for type java.lang.Byte", new Callable<Void>() {
public Void call() throws Exception {
rs1.getByte(5);
return null;
}
});
} else {
assertEquals('2', rs1.getByte(5));
}
assertThrows(SQLDataException.class, "Cannot determine value type from string '23.+", new Callable<Void>() {
public Void call() throws Exception {
rs1.getInt(5);
return null;
}
});
assertThrows(SQLDataException.class, "Cannot determine value type from string '23.+", new Callable<Void>() {
public Void call() throws Exception {
rs1.getLong(5);
return null;
}
});
assertThrows(SQLDataException.class, "Cannot determine value type from string '23.+", new Callable<Void>() {
public Void call() throws Exception {
rs1.getShort(5);
return null;
}
});
assertTrue(rs1.getString(5).startsWith("23"));
}
}
}
use of com.mysql.cj.jdbc.ServerPreparedStatement in project aws-mysql-jdbc by awslabs.
the class ResultSetRegressionTest method testBug31747910.
/**
* Tests fix for Bug#31747910, BUG 30474158 FIX IMPROVES JDBC COMPLIANCE BUT CHANGES DEFAULT RESULTSETTYPE HANDLING.
*
* @throws Exception
*/
@Test
public void testBug31747910() throws Exception {
createTable("testBug31747910", "(id INT)");
this.stmt.executeUpdate("INSERT INTO testBug31747910 VALUES (1), (2), (3), (4), (5)");
/*
* Expected exceptions with default RS type and:
* 0. static;
* 1. streaming;
* 2. streaming & scroll-tolerant;
* 3. cursor-based;
* 4. cursor-based & scroll-tolerant.
*/
String[] connOpts = new String[] { "useSSL=false,allowPublicKeyRetrieval=true", "useSSL=false,allowPublicKeyRetrieval=true", "useSSL=false,allowPublicKeyRetrieval=true,scrollTolerantForwardOnly=true", "useSSL=false,allowPublicKeyRetrieval=true,useCursorFetch=true", "useSSL=false,allowPublicKeyRetrieval=true,useCursorFetch=true,scrollTolerantForwardOnly=true" };
int[] fetchSize = new int[] { 0, Integer.MIN_VALUE, Integer.MIN_VALUE, 2, 2 };
for (int i = 0; i < connOpts.length; i++) {
for (int j = 0; j < 3; j++) {
// Statement; PreparedStatement and ServerPreparedStatement.
Connection testConn = null;
Statement testStmt = null;
switch(j) {
case 0:
// Default behavior using Statement
testConn = getConnectionWithProps(connOpts[i]);
testStmt = testConn.createStatement();
if (fetchSize[i] != 0) {
testStmt.setFetchSize(fetchSize[i]);
}
this.rs = testStmt.executeQuery("SELECT * FROM testBug31747910");
break;
case 1:
// Default behavior using PreparedStatement
testConn = getConnectionWithProps(connOpts[i]);
testStmt = testConn.prepareStatement("SELECT * FROM testBug31747910");
if (fetchSize[i] != 0) {
testStmt.setFetchSize(fetchSize[i]);
}
this.rs = ((PreparedStatement) testStmt).executeQuery();
break;
case 2:
// Default behavior using ServerPreparedStatement
testConn = getConnectionWithProps("useServerPrepStmts=true," + connOpts[i]);
testStmt = testConn.prepareStatement("SELECT * FROM testBug31747910");
if (fetchSize[i] != 0) {
testStmt.setFetchSize(fetchSize[i]);
}
this.rs = ((PreparedStatement) testStmt).executeQuery();
break;
}
assertTrue(this.rs.next());
assertEquals(1, this.rs.getInt(1));
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> this.rs.last());
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> this.rs.previous());
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> this.rs.first());
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> this.rs.absolute(3));
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> this.rs.relative(-1));
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> {
this.rs.beforeFirst();
return null;
});
assertThrows(SQLException.class, "Operation not allowed for a result set of type ResultSet\\.TYPE_FORWARD_ONLY\\.", () -> {
this.rs.afterLast();
return null;
});
testStmt.close();
testConn.close();
}
}
// Scroll-tolerant behavior using: Statement; PreparedStatement; ServerPreparedStatement.
for (int i = 0; i < 3; i++) {
Connection testConn = null;
Statement testStmt = null;
switch(i) {
case 0:
// Scroll-tolerant using Statement
testConn = getConnectionWithProps("useSSL=false,allowPublicKeyRetrieval=true,scrollTolerantForwardOnly=true");
testStmt = testConn.createStatement();
this.rs = testStmt.executeQuery("SELECT * FROM testBug31747910");
break;
case 1:
// Scroll-tolerant using PreparedStatement
testConn = getConnectionWithProps("useSSL=false,allowPublicKeyRetrieval=true,scrollTolerantForwardOnly=true");
testStmt = testConn.prepareStatement("SELECT * FROM testBug31747910");
this.rs = ((PreparedStatement) testStmt).executeQuery();
break;
case 2:
// Scroll-tolerant using ServerPreparedStatement
testConn = getConnectionWithProps("useSSL=false,allowPublicKeyRetrieval=true,useServerPrepStmts=true,scrollTolerantForwardOnly=true");
testStmt = testConn.prepareStatement("SELECT * FROM testBug31747910");
this.rs = ((PreparedStatement) testStmt).executeQuery();
break;
}
assertTrue(this.rs.next());
assertEquals(1, this.rs.getInt(1));
assertTrue(this.rs.last());
assertEquals(5, this.rs.getInt(1));
assertTrue(this.rs.previous());
assertEquals(4, this.rs.getInt(1));
assertTrue(this.rs.first());
assertEquals(1, this.rs.getInt(1));
assertTrue(this.rs.absolute(3));
assertEquals(3, this.rs.getInt(1));
assertTrue(this.rs.relative(-1));
assertEquals(2, this.rs.getInt(1));
this.rs.beforeFirst();
assertTrue(this.rs.isBeforeFirst());
this.rs.afterLast();
assertTrue(this.rs.isAfterLast());
testStmt.close();
testConn.close();
}
}
use of com.mysql.cj.jdbc.ServerPreparedStatement in project aws-mysql-jdbc by awslabs.
the class StatementRegressionTest method testBug66430.
/**
* Tests fix for Bug#66430 - setCatalog on connection leaves ServerPreparedStatement cache for old catalog.
*
* @throws Exception
*/
@Test
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(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.cachePrepStmts.getKeyName(), Boolean.toString(cachePS));
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), Boolean.toString(useSPS));
Connection testConn = getConnectionWithProps(props);
if (((JdbcConnection) testConn).getPropertySet().<DatabaseTerm>getEnumProperty(PropertyKey.databaseTerm).getValue() == DatabaseTerm.SCHEMA) {
testConn.setSchema("testBug66430DB1");
} else {
testConn.setCatalog("testBug66430DB1");
}
PreparedStatement testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(this.rs.next(), testCase);
assertEquals(1, this.rs.getInt(1), testCase);
assertFalse(this.rs.next(), testCase);
testPStmt.close();
if (((JdbcConnection) testConn).getPropertySet().<DatabaseTerm>getEnumProperty(PropertyKey.databaseTerm).getValue() == DatabaseTerm.SCHEMA) {
testConn.setSchema("testBug66430DB2");
} else {
testConn.setCatalog("testBug66430DB2");
}
testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(this.rs.next(), testCase);
assertEquals(2, this.rs.getInt(1), testCase);
assertFalse(this.rs.next(), testCase);
testPStmt.close();
// Do it again to make sure cached prepared statements behave correctly.
if (((JdbcConnection) testConn).getPropertySet().<DatabaseTerm>getEnumProperty(PropertyKey.databaseTerm).getValue() == DatabaseTerm.SCHEMA) {
testConn.setSchema("testBug66430DB1");
} else {
testConn.setCatalog("testBug66430DB1");
}
testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(this.rs.next(), testCase);
assertEquals(1, this.rs.getInt(1), testCase);
assertFalse(this.rs.next(), testCase);
testPStmt.close();
if (((JdbcConnection) testConn).getPropertySet().<DatabaseTerm>getEnumProperty(PropertyKey.databaseTerm).getValue() == DatabaseTerm.SCHEMA) {
testConn.setSchema("testBug66430DB2");
} else {
testConn.setCatalog("testBug66430DB2");
}
testPStmt = testConn.prepareStatement("SELECT * FROM testBug66430 WHERE id > ?");
testPStmt.setInt(1, 0);
this.rs = testPStmt.executeQuery();
assertTrue(this.rs.next(), testCase);
assertEquals(2, this.rs.getInt(1), testCase);
assertFalse(this.rs.next(), testCase);
testPStmt.close();
testConn.close();
} while ((useSPS = !useSPS) || (cachePS = !cachePS));
}
use of com.mysql.cj.jdbc.ServerPreparedStatement in project aws-mysql-jdbc by awslabs.
the class StatementRegressionTest method testBug87429.
/**
* Tests fix for Bug#87429 - repeated close of ServerPreparedStatement causes memory leak.
*
* Original de-cache on double close() behavior modified by:
* WL#11101 - Remove de-cache and close of SSPSs on double call to close().
*
* @throws Exception
*/
@Test
public void testBug87429() throws Exception {
Field stmtsCacheField = ConnectionImpl.class.getDeclaredField("serverSideStatementCache");
stmtsCacheField.setAccessible(true);
ToIntFunction<Connection> getStmtsCacheSize = (c) -> {
try {
LRUCache<?, ?> stmtsCacheObj = (LRUCache<?, ?>) stmtsCacheField.get(c);
return stmtsCacheObj == null ? -1 : stmtsCacheObj.size();
} catch (IllegalArgumentException | IllegalAccessException e) {
fail("Fail getting the statemets cache size.");
return -1;
}
};
final String sql1 = "SELECT 1, ?";
final String sql2 = "SELECT 2, ?";
boolean useSPS = false;
boolean cachePS = false;
do {
Properties props = new Properties();
props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), Boolean.toString(useSPS));
props.setProperty(PropertyKey.cachePrepStmts.getKeyName(), Boolean.toString(cachePS));
props.setProperty(PropertyKey.prepStmtCacheSize.getKeyName(), "5");
boolean cachedSPS = useSPS && cachePS;
JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(props);
// Single PreparedStatement, closed multiple times.
for (int i = 0; i < 100; i++) {
this.pstmt = testConn.prepareStatement(sql1);
assertTrue(this.pstmt.isPoolable());
assertEquals(1, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
// Close & cache.
this.pstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
// No-op.
this.pstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
// No-op.
this.pstmt.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 1 : -1, getStmtsCacheSize.applyAsInt(testConn));
try {
// De-caches the statement or no-op if not cached.
this.pstmt.setPoolable(false);
} catch (SQLException e) {
assertFalse(cachedSPS, "Exception [" + e.getMessage() + "] not expected.");
}
// No-op.
this.pstmt.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
}
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
assertEquals(cachedSPS ? 0 : -1, getStmtsCacheSize.applyAsInt(testConn));
testConn = (JdbcConnection) getConnectionWithProps(props);
// Multiple PreparedStatements interchanged, two queries, closed multiple times.
for (int i = 0; i < 100; i++) {
for (int j = 1; j <= 4; j++) {
PreparedStatement pstmt1 = testConn.prepareStatement(j == 1 ? sql2 : sql1);
PreparedStatement pstmt2 = testConn.prepareStatement(j == 2 ? sql2 : sql1);
PreparedStatement pstmt3 = testConn.prepareStatement(j == 3 ? sql2 : sql1);
PreparedStatement pstmt4 = testConn.prepareStatement(j == 4 ? sql2 : sql1);
assertEquals(4, testConn.getActiveStatementCount());
// Close and cache statements successively.
pstmt4.close();
// No-op.
pstmt4.close();
assertEquals(cachedSPS ? 4 : 3, testConn.getActiveStatementCount());
pstmt3.close();
// No-op.
pstmt3.close();
assertEquals(cachedSPS ? (j >= 3 ? 4 : 3) : 2, testConn.getActiveStatementCount());
pstmt2.close();
// No-op.
pstmt2.close();
assertEquals(cachedSPS ? (j >= 2 ? 3 : 2) : 1, testConn.getActiveStatementCount());
pstmt1.close();
// No-op.
pstmt1.close();
assertEquals(cachedSPS ? 2 : 0, testConn.getActiveStatementCount());
// No-ops.
pstmt4.close();
pstmt4.close();
pstmt3.close();
pstmt3.close();
pstmt2.close();
pstmt2.close();
pstmt1.close();
pstmt1.close();
assertEquals(cachedSPS ? 2 : 0, testConn.getActiveStatementCount());
// De-cache statements successively.
try {
// De-caches the statement or no-op if not cached.
pstmt4.setPoolable(false);
} catch (SQLException e) {
assertFalse(cachedSPS && j == 4, "Exception [" + e.getMessage() + "] not expected.");
}
// No-op.
pstmt4.close();
assertEquals(cachedSPS ? (j < 4 ? 2 : 1) : 0, testConn.getActiveStatementCount());
try {
// De-caches the statement or no-op if not cached.
pstmt3.setPoolable(false);
} catch (SQLException e) {
assertFalse(cachedSPS && j == 3, "Exception [" + e.getMessage() + "] not expected.");
}
// No-op.
pstmt3.close();
assertEquals(cachedSPS ? (j < 3 ? 2 : 1) : 0, testConn.getActiveStatementCount());
try {
// De-caches the statement or no-op if not cached.
pstmt2.setPoolable(false);
} catch (SQLException e) {
assertFalse(cachedSPS && j == 2, "Exception [" + e.getMessage() + "] not expected.");
}
// No-op.
pstmt2.close();
assertEquals(cachedSPS ? 1 : 0, testConn.getActiveStatementCount());
try {
// De-caches the statement or no-op if not cached.
pstmt1.setPoolable(false);
} catch (SQLException e) {
assertFalse(cachedSPS, "Exception [" + e.getMessage() + "] not expected.");
}
// No-op.
pstmt1.close();
assertEquals(0, testConn.getActiveStatementCount());
}
}
testConn.close();
assertEquals(0, testConn.getActiveStatementCount());
} while ((useSPS = !useSPS) || (cachePS = !cachePS));
}
Aggregations