List:Internals« Previous MessageNext Message »
From:mmatthews Date:September 23 2005 5:14pm
Subject:Connector/J commit: r4296 - in branches/branch_3_1/connector-j: . src/com/mysql/jdbc src/testsuite/regression
View as plain text  
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/regressionmmatthews23 Sep