Modified:
branches/branch_3_1/connector-j/CHANGES
branches/branch_3_1/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java
branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java
Log:
Workaround for BUG#13374 - ResultSet.getStatement()
on closed result set returns NULL (as per JDBC 4.0 spec,
but not backwards-compatible). Set the connection property
"retainStatementAfterResultSetClose" to "true" to be able
to retrieve a ResultSet's statement after the ResultSet has
been closed via .getStatement() (the default is "false", to
be JDBC-compliant and to reduce the chance that code using
JDBC leaks Statement instances).
Modified: branches/branch_3_1/connector-j/CHANGES
===================================================================
--- branches/branch_3_1/connector-j/CHANGES 2005-09-23 00:06:52 UTC (rev 4295)
+++ branches/branch_3_1/connector-j/CHANGES 2005-09-23 15:14:37 UTC (rev 4296)
@@ -160,6 +160,15 @@
will fail, because it's reading the response to the empty
LOAD DATA INFILE packet sent to the server.
+ - Workaround for BUG#13374 - ResultSet.getStatement()
+ on closed result set returns NULL (as per JDBC 4.0 spec,
+ but not backwards-compatible). Set the connection property
+ "retainStatementAfterResultSetClose" to "true" to be able
+ to retrieve a ResultSet's statement after the ResultSet has
+ been closed via .getStatement() (the default is "false", to
+ be JDBC-compliant and to reduce the chance that code using
+ JDBC leaks Statement instances).
+
06-23-05 - Version 3.1.10-stable
- Fixed connecting without a database specified raised an exception
Modified: branches/branch_3_1/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
---
branches/branch_3_1/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2005-09-23
00:06:52 UTC (rev 4295)
+++
branches/branch_3_1/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2005-09-23
15:14:37 UTC (rev 4296)
@@ -535,14 +535,14 @@
private static final String PERFORMANCE_CATEGORY = "Performance Extensions";
- private static final ArrayList PROPERTY_LIST = new ArrayList();
-
private static final String SECURITY_CATEGORY = "Security";
private static final String[] PROPERTY_CATEGORIES = new String[] {
CONNECTION_AND_AUTH_CATEGORY, HA_CATEGORY, SECURITY_CATEGORY,
PERFORMANCE_CATEGORY, DEBUGING_PROFILING_CATEGORY, MISC_CATEGORY };
+ private static final ArrayList PROPERTY_LIST = new ArrayList();
+
private static final String STANDARD_LOGGER_NAME = StandardLogger.class
.getName();
@@ -639,16 +639,17 @@
private boolean autoGenerateTestcaseScriptAsBoolean = false;
private BooleanConnectionProperty autoReconnect = new BooleanConnectionProperty(
- "autoReconnect", false,
- "Should the driver try to re-establish bad connections? "
- + " If enabled the driver will throw an exception for a query issued on a stale or
dead connection, " +
- " but will attempt reconnect before the next query issued on the connection. This
feature " +
- "is not recommended, because it has side effects related to session state and data
consistency when applications don't" +
- "handle SQLExceptions properly, and is only designed to be used " +
- "when you are unable to write your application to handle SQLExceptions resulting from
dead and" +
- "stale connections properly. Alternatively, investigate setting the MySQL server
variable \"wait_timeout\"" +
- "to some high value rather than the default of 8 hours.", "1.1",
- HA_CATEGORY, 0);
+ "autoReconnect",
+ false,
+ "Should the driver try to re-establish bad connections? "
+ + " If enabled the driver will throw an exception for a query issued on a stale or
dead connection, "
+ + " but will attempt reconnect before the next query issued on the connection. This
feature "
+ + "is not recommended, because it has side effects related to session state and data
consistency when applications don't"
+ + "handle SQLExceptions properly, and is only designed to be used "
+ + "when you are unable to write your application to handle SQLExceptions resulting
from dead and"
+ + "stale connections properly. Alternatively, investigate setting the MySQL server
variable \"wait_timeout\""
+ + "to some high value rather than the default of 8 hours.",
+ "1.1", HA_CATEGORY, 0);
private BooleanConnectionProperty autoReconnectForPools = new BooleanConnectionProperty(
"autoReconnectForPools",
@@ -1057,6 +1058,13 @@
"Require SSL connection if useSSL=true? (defaults to 'false').",
"3.1.0", SECURITY_CATEGORY, 3);
+ private BooleanConnectionProperty retainStatementAfterResultSetClose = new
BooleanConnectionProperty(
+ "retainStatementAfterResultSetClose",
+ false,
+ "Should the driver retain the Statement reference in a ResultSet after
ResultSet.close()"
+ + " has been called. This is not JDBC-compliant after JDBC-4.0.",
+ "3.1.11", MISC_CATEGORY, Integer.MIN_VALUE);
+
private BooleanConnectionProperty rollbackOnPooledClose = new BooleanConnectionProperty(
"rollbackOnPooledClose",
true,
@@ -2006,6 +2014,10 @@
return this.requireSSL.getValueAsBoolean();
}
+ protected boolean getRetainStatementAfterResultSetClose() {
+ return this.retainStatementAfterResultSetClose.getValueAsBoolean();
+ }
+
/**
* @return Returns the rollbackOnPooledClose.
*/
@@ -3091,6 +3103,10 @@
this.requireSSL.setValue(property);
}
+ protected void setRetainStatementAfterResultSetClose(boolean flag) {
+ this.retainStatementAfterResultSetClose.setValue(flag);
+ }
+
/**
* @param rollbackOnPooledClose
* The rollbackOnPooledClose to set.
Modified: branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java
===================================================================
--- branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java 2005-09-23 00:06:52
UTC (rev 4295)
+++ branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java 2005-09-23 15:14:37
UTC (rev 4296)
@@ -261,6 +261,8 @@
protected java.sql.Statement wrapperStatement;
+ protected boolean retainOwningStatement;
+
/**
* Create a result set for an executeUpdate statement.
*
@@ -282,6 +284,13 @@
this.connection = conn;
this.owningStatement = creatorStmt;
+
+ this.retainOwningStatement = false;
+
+ if (this.connection != null) {
+ this.retainOwningStatement =
+ this.connection.getRetainStatementAfterResultSetClose();
+ }
}
/**
@@ -373,6 +382,13 @@
this.connection.reportNumberOfTablesAccessed(tableNamesMap.size());
}
+
+ this.retainOwningStatement = false;
+
+ if (this.connection != null) {
+ retainOwningStatement =
+ this.connection.getRetainStatementAfterResultSetClose();
+ }
}
/**
@@ -4386,12 +4402,8 @@
case Types.VARBINARY:
case Types.LONGVARBINARY:
if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_GEOMETRY) {
- return getBytes(columnIndex, true);
- } else if (!field.isBlob()) {
- return getString(columnIndex);
- } else if (!field.isBinary()) {
- return getString(columnIndex);
- } else {
+ return getBytes(columnIndex);
+ } else if (field.isBinary() || field.isBlob()) {
byte[] data = getBytes(columnIndex);
if (this.connection.getAutoDeserialize()) {
@@ -4418,6 +4430,8 @@
} catch (IOException ex) {
obj = data; // not serialized?
}
+ } else {
+ return getString(columnIndex);
}
}
@@ -4427,6 +4441,7 @@
return data;
}
+
case Types.DATE:
if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR
&& !this.connection.getYearIsDateType()) {
@@ -4913,6 +4928,15 @@
* if a database-access error occurs
*/
public java.sql.Statement getStatement() throws SQLException {
+ if (this.isClosed && !this.retainOwningStatement) {
+ throw new SQLException(
+ "Operation not allowed on closed ResultSet. Statements "
+ + "can be retained over result set closure by setting the connection property "
+ + "\"retainStatementAfterResultSetClose\" to \"true\".",
+ SQLError.SQL_STATE_GENERAL_ERROR);
+
+ }
+
if (this.wrapperStatement != null) {
return this.wrapperStatement;
}
@@ -6328,7 +6352,7 @@
if (this.isClosed) {
return;
}
-
+
try {
if (this.useUsageAdvisor) {
if (!calledExplicitly) {
@@ -6434,7 +6458,11 @@
this.fullColumnNameToIndex = null;
this.eventSink = null;
this.warningChain = null;
- this.owningStatement = null;
+
+ if (!this.retainOwningStatement) {
+ this.owningStatement = null;
+ }
+
this.catalog = null;
this.serverInfo = null;
this.thisRow = null;
Modified:
branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java
===================================================================
---
branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2005-09-23
00:06:52 UTC (rev 4295)
+++
branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2005-09-23
15:14:37 UTC (rev 4296)
@@ -1976,6 +1976,58 @@
}
}
+ /**
+ * Tests fix for BUG#13374 - ResultSet.getStatement()
+ * on closed result set returns NULL (as per JDBC 4.0 spec,
+ * but not backwards-compatible).
+ *
+ * @throws Exception if the test fails
+ */
+
+ public void testBug13374() throws Exception {
+ Statement retainStmt = null;
+ Connection retainConn = null;
+
+ try {
+ Properties props = new Properties();
+
+ props.setProperty("retainStatementAfterResultSetClose",
+ "true");
+
+ retainConn = getConnectionWithProps(props);
+
+ retainStmt = retainConn.createStatement();
+
+ this.rs = retainStmt.executeQuery("SELECT 1");
+ this.rs.close();
+ assertNotNull(this.rs.getStatement());
+
+ this.rs = this.stmt.executeQuery("SELECT 1");
+ this.rs.close();
+
+ try {
+ this.rs.getStatement();
+ } catch (SQLException sqlEx) {
+ assertEquals(sqlEx.getSQLState(),
+ SQLError.SQL_STATE_GENERAL_ERROR);
+ }
+
+ } finally {
+ if (this.rs != null) {
+ this.rs.close();
+ this.rs = null;
+ }
+
+ if (retainStmt != null) {
+ retainStmt.close();
+ }
+
+ if (retainConn != null) {
+ retainConn.close();
+ }
+ }
+ }
+
public void testNPEWithUsageAdvisor() throws Exception {
Connection advisorConn = null;
| Thread |
|---|
| • Connector/J commit: r4296 - in branches/branch_3_1/connector-j: . src/com/mysql/jdbc src/testsuite/regression | mmatthews | 23 Sep |