From: Date: February 5 2007 7:44pm Subject: Connector/J commit: r6303 - branches/branch_5_0/connector-j branches/branch_5_0/connector-j/src/com/mysql/jdbc trunk/connector-j trunk/connector-j/src/com/mysql/jdbc List-Archive: http://lists.mysql.com/commits/19333 X-Bug: 25836 Message-Id: <200702051844.l15IiDkm016986@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/branch_5_0/connector-j/CHANGES branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java branches/branch_5_0/connector-j/src/com/mysql/jdbc/Statement.java trunk/connector-j/CHANGES trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java trunk/connector-j/src/com/mysql/jdbc/Statement.java Log: - When using cached metadata, skip field-level metadata packets coming from the server, rather than reading them and discarding them without creating com.mysql.jdbc.Field instances. - Fixed BUG#25836 - Statement execution which timed out doesn't always throw MySQLTimeoutException. - Throw exceptions encountered during timeout to thread calling Statement.execute*(), rather than RuntimeException. Modified: branches/branch_5_0/connector-j/CHANGES =================================================================== --- branches/branch_5_0/connector-j/CHANGES 2007-02-05 16:40:02 UTC (rev 6302) +++ branches/branch_5_0/connector-j/CHANGES 2007-02-05 18:44:10 UTC (rev 6303) @@ -116,6 +116,16 @@ returns keywords for MySQL-5.1, and doesn't distinguish between different versions of the server. + - When using cached metadata, skip field-level metadata packets coming from + the server, rather than reading them and discarding them without creating + com.mysql.jdbc.Field instances. + + - Fixed BUG#25836 - Statement execution which timed out doesn't always + throw MySQLTimeoutException. + + - Throw exceptions encountered during timeout to thread + calling Statement.execute*(), rather than RuntimeException. + 10-20-06 - Version 5.0.4 - Fixed BUG#21379 - column names don't match metadata in cases Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-02-05 16:40:02 UTC (rev 6302) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -1242,6 +1242,11 @@ if (timeoutTask != null) { timeoutTask.cancel(); + + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask = null; } Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2007-02-05 16:40:02 UTC (rev 6302) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -1176,6 +1176,11 @@ if (timeoutTask != null) { timeoutTask.cancel(); + + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask = null; } Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/Statement.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/Statement.java 2007-02-05 16:40:02 UTC (rev 6302) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Statement.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -71,7 +71,8 @@ class CancelTask extends TimerTask { long connectionId = 0; - + SQLException caughtWhileCancelling = null; + CancelTask() throws SQLException { connectionId = connection.getIO().getThreadId(); } @@ -92,7 +93,14 @@ wasCancelled = true; } } catch (SQLException sqlEx) { - throw new RuntimeException(sqlEx.toString()); + caughtWhileCancelling = sqlEx; + } catch (NullPointerException npe) { + // Case when connection closed while starting to cancel + // We can't easily synchronize this, because then one thread + // can't cancel() a running query + + // ignore, we shouldn't re-throw this, because the connection's + // already closed, so the statement has been timed out. } finally { if (cancelStmt != null) { try { @@ -338,6 +346,14 @@ + this.connection.getIO().getThreadId()); this.wasCancelled = true; } + } catch (NullPointerException npe) { + // Case when connection closed while starting to cancel + // We can't easily synchronize this, because then one thread + // can't cancel() a running query + + throw SQLError.createSQLException(Messages + .getString("Statement.49"), //$NON-NLS-1$ + SQLError.SQL_STATE_CONNECTION_NOT_OPEN); //$NON-NLS-1$ } finally { if (cancelStmt != null) { cancelStmt.close(); @@ -551,7 +567,6 @@ public boolean execute(String sql) throws SQLException { checkClosed(); - Connection locallyScopedConn = this.connection; synchronized (locallyScopedConn.getMutex()) { @@ -612,7 +627,9 @@ rs = createResultSetUsingServerFetch(sql); } else { CancelTask timeoutTask = null; - + + String oldCatalog = null; + try { if (this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) { @@ -621,7 +638,7 @@ this.timeoutInMillis); } - String oldCatalog = null; + if (!locallyScopedConn.getCatalog().equals( this.currentCatalog)) { @@ -691,15 +708,15 @@ createStreamingResultSet(), this.currentCatalog, (cachedMetaData == null)); } - + if (timeoutTask != null) { + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask.cancel(); timeoutTask = null; } - - if (oldCatalog != null) { - locallyScopedConn.setCatalog(oldCatalog); - } synchronized (this.cancelTimeoutMutex) { if (this.wasCancelled) { @@ -707,10 +724,14 @@ throw new MySQLTimeoutException(); } } - } finally { + } finally { if (timeoutTask != null) { timeoutTask.cancel(); } + + if (oldCatalog != null) { + locallyScopedConn.setCatalog(oldCatalog); + } } } @@ -1106,7 +1127,9 @@ } CancelTask timeoutTask = null; - + + String oldCatalog = null; + try { if (this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) { @@ -1115,8 +1138,6 @@ this.timeoutInMillis); } - String oldCatalog = null; - if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) { oldCatalog = locallyScopedConn.getCatalog(); locallyScopedConn.setCatalog(this.currentCatalog); @@ -1180,14 +1201,14 @@ } if (timeoutTask != null) { + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask.cancel(); timeoutTask = null; } - if (oldCatalog != null) { - locallyScopedConn.setCatalog(oldCatalog); - } - synchronized (this.cancelTimeoutMutex) { if (this.wasCancelled) { this.wasCancelled = false; @@ -1198,6 +1219,10 @@ if (timeoutTask != null) { timeoutTask.cancel(); } + + if (oldCatalog != null) { + locallyScopedConn.setCatalog(oldCatalog); + } } this.lastInsertId = this.results.getUpdateID(); @@ -1287,7 +1312,9 @@ // on the same mutex that _conn is using CancelTask timeoutTask = null; - + + String oldCatalog = null; + try { if (this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) { @@ -1296,8 +1323,6 @@ this.timeoutInMillis); } - String oldCatalog = null; - if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) { oldCatalog = locallyScopedConn.getCatalog(); locallyScopedConn.setCatalog(this.currentCatalog); @@ -1323,14 +1348,14 @@ isBatch); if (timeoutTask != null) { + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask.cancel(); timeoutTask = null; } - if (oldCatalog != null) { - locallyScopedConn.setCatalog(oldCatalog); - } - synchronized (this.cancelTimeoutMutex) { if (this.wasCancelled) { this.wasCancelled = false; @@ -1341,6 +1366,10 @@ if (timeoutTask != null) { timeoutTask.cancel(); } + + if (oldCatalog != null) { + locallyScopedConn.setCatalog(oldCatalog); + } } } @@ -1986,12 +2015,14 @@ } } + this.isClosed = true; + this.results = null; this.connection = null; this.warningChain = null; this.openResults = null; this.batchedGeneratedKeys = null; - this.isClosed = true; + this.cancelTimeoutMutex = null; } /** Modified: trunk/connector-j/CHANGES =================================================================== --- trunk/connector-j/CHANGES 2007-02-05 16:40:02 UTC (rev 6302) +++ trunk/connector-j/CHANGES 2007-02-05 18:44:10 UTC (rev 6303) @@ -111,7 +111,17 @@ all reserved words for current MySQL version. The current fix/implementation returns keywords for MySQL-5.1, and doesn't distinguish between different versions of the server. - + + - When using cached metadata, skip field-level metadata packets coming from + the server, rather than reading them and discarding them without creating + com.mysql.jdbc.Field instances. + + - Fixed BUG#25836 - Statement execution which timed out doesn't always + throw MySQLTimeoutException. + + - Throw exceptions encountered during timeout to thread + calling Statement.execute*(), rather than RuntimeException. + 10-20-06 - Version 5.0.4 - Fixed BUG#21379 - column names don't match metadata in cases Modified: trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java 2007-02-05 16:40:02 UTC (rev 6302) +++ trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -366,21 +366,22 @@ Buffer packet; // The packet from the server Field[] fields = null; + // Read in the column information + if (unpackFieldInfo) { fields = new Field[(int) columnCount]; - } - - // Read in the column information - for (int i = 0; i < columnCount; i++) { - Buffer fieldPacket = null; - - fieldPacket = readPacket(); - if (unpackFieldInfo) { + for (int i = 0; i < columnCount; i++) { + Buffer fieldPacket = null; + + fieldPacket = readPacket(); fields[i] = unpackField(fieldPacket, false); } + } else { + for (int i = 0; i < columnCount; i++) { + skipPacket(); + } } - packet = reuseAndReadPacket(this.reusablePacket); readServerStatusForResultSets(packet); @@ -487,6 +488,64 @@ } /** + * Reads and discards a single MySQL packet from the input stream. + * + * @throws SQLException if the network fails while skipping the + * packet. + */ + protected final void skipPacket() throws SQLException { + try { + + int lengthRead = readFully(this.mysqlInput, this.packetHeaderBuf, + 0, 4); + + if (lengthRead < 4) { + forceClose(); + throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$ + } + + int packetLength = (this.packetHeaderBuf[0] & 0xff) + + ((this.packetHeaderBuf[1] & 0xff) << 8) + + ((this.packetHeaderBuf[2] & 0xff) << 16); + + if (this.traceProtocol) { + StringBuffer traceMessageBuf = new StringBuffer(); + + traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$ + traceMessageBuf.append(packetLength); + traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$ + traceMessageBuf.append(StringUtils.dumpAsHex( + this.packetHeaderBuf, 4)); + + this.connection.getLog().logTrace(traceMessageBuf.toString()); + } + + byte multiPacketSeq = this.packetHeaderBuf[3]; + + if (!this.packetSequenceReset) { + if (this.enablePacketDebug && this.checkPacketSequence) { + checkPacketSequencing(multiPacketSeq); + } + } else { + this.packetSequenceReset = false; + } + + this.readPacketSequence = multiPacketSeq; + + this.mysqlInput.skip(packetLength); + } catch (IOException ioEx) { + throw new CommunicationsException(this.connection, + this.lastPacketSentTimeMs, ioEx); + } catch (OutOfMemoryError oom) { + try { + this.connection.realClose(false, false, true, oom); + } finally { + throw oom; + } + } + } + + /** * Read one packet from the MySQL server * * @return the packet from the server. Modified: trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-02-05 16:40:02 UTC (rev 6302) +++ trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -1253,7 +1253,9 @@ boolean queryIsSelectOnly, boolean unpackFields, Field[] metadataFromCache, boolean isBatch) throws SQLException { - this.wasCancelled = false; + synchronized (this.cancelTimeoutMutex) { + this.wasCancelled = false; + } Connection locallyScopedConnection= this.connection; @@ -1278,12 +1280,19 @@ if (timeoutTask != null) { timeoutTask.cancel(); + + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask = null; } - if (this.wasCancelled) { - this.wasCancelled = false; - throw new MySQLTimeoutException(); + synchronized (this.cancelTimeoutMutex) { + if (this.wasCancelled) { + this.wasCancelled = false; + throw new MySQLTimeoutException(); + } } } finally { if (timeoutTask != null) { Modified: trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2007-02-05 16:40:02 UTC (rev 6302) +++ trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -1175,7 +1175,9 @@ begin = System.currentTimeMillis(); } - this.wasCancelled = false; + synchronized (this.cancelTimeoutMutex) { + this.wasCancelled = false; + } CancelTask timeoutTask = null; @@ -1192,12 +1194,19 @@ if (timeoutTask != null) { timeoutTask.cancel(); + + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask = null; } - if (this.wasCancelled) { - this.wasCancelled = false; - throw new MySQLTimeoutException(); + synchronized (this.cancelTimeoutMutex) { + if (this.wasCancelled) { + this.wasCancelled = false; + throw new MySQLTimeoutException(); + } } this.connection.incrementNumberOfPreparedExecutes(); Modified: trunk/connector-j/src/com/mysql/jdbc/Statement.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/Statement.java 2007-02-05 16:40:02 UTC (rev 6302) +++ trunk/connector-j/src/com/mysql/jdbc/Statement.java 2007-02-05 18:44:10 UTC (rev 6303) @@ -70,7 +70,8 @@ class CancelTask extends TimerTask { long connectionId = 0; - + SQLException caughtWhileCancelling = null; + CancelTask() throws SQLException { connectionId = connection.getIO().getThreadId(); } @@ -84,12 +85,21 @@ java.sql.Statement cancelStmt = null; try { - cancelConn = connection.duplicate(); - cancelStmt = cancelConn.createStatement(); - cancelStmt.execute("KILL QUERY " + connectionId); - wasCancelled = true; + synchronized (cancelTimeoutMutex) { + cancelConn = connection.duplicate(); + cancelStmt = cancelConn.createStatement(); + cancelStmt.execute("KILL QUERY " + connectionId); + wasCancelled = true; + } } catch (SQLException sqlEx) { - throw new RuntimeException(sqlEx.toString()); + caughtWhileCancelling = sqlEx; + } catch (NullPointerException npe) { + // Case when connection closed while starting to cancel + // We can't easily synchronize this, because then one thread + // can't cancel() a running query + + // ignore, we shouldn't re-throw this, because the connection's + // already closed, so the statement has been timed out. } finally { if (cancelStmt != null) { try { @@ -114,6 +124,11 @@ } } + /** Mutex to prevent race between returning query results and noticing + that we're timed-out or cancelled. */ + + protected Object cancelTimeoutMutex = new Object(); + /** Used to generate IDs when profiling. */ protected static int statementCounter = 1; @@ -544,11 +559,12 @@ public boolean execute(String sql) throws SQLException { checkClosed(); - Connection locallyScopedConn = this.connection; synchronized (locallyScopedConn.getMutex()) { - this.wasCancelled = false; + synchronized (this.cancelTimeoutMutex) { + this.wasCancelled = false; + } checkNullOrEmptyQuery(sql); @@ -603,7 +619,9 @@ rs = createResultSetUsingServerFetch(sql); } else { CancelTask timeoutTask = null; - + + String oldCatalog = null; + try { if (this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) { @@ -612,7 +630,7 @@ this.timeoutInMillis); } - String oldCatalog = null; + if (!locallyScopedConn.getCatalog().equals( this.currentCatalog)) { @@ -624,7 +642,7 @@ // Check if we have cached metadata for this query... // if (locallyScopedConn.getCacheResultSetMetadata()) { - cachedMetaData = getCachedMetaData(sql); + cachedMetaData = locallyScopedConn.getCachedMetaData(sql); } // @@ -682,24 +700,30 @@ createStreamingResultSet(), this.currentCatalog, (cachedMetaData == null)); } - + if (timeoutTask != null) { + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask.cancel(); timeoutTask = null; } - - if (oldCatalog != null) { - locallyScopedConn.setCatalog(oldCatalog); - } - if (this.wasCancelled) { - this.wasCancelled = false; - throw new MySQLTimeoutException(); + synchronized (this.cancelTimeoutMutex) { + if (this.wasCancelled) { + this.wasCancelled = false; + throw new MySQLTimeoutException(); + } } - } finally { + } finally { if (timeoutTask != null) { timeoutTask.cancel(); } + + if (oldCatalog != null) { + locallyScopedConn.setCatalog(oldCatalog); + } } } @@ -712,11 +736,11 @@ if (rs.reallyResult()) { if (cachedMetaData != null) { - initializeResultsMetadataFromCache(sql, cachedMetaData, + locallyScopedConn.initializeResultsMetadataFromCache(sql, cachedMetaData, this.results); } else { if (this.connection.getCacheResultSetMetadata()) { - initializeResultsMetadataFromCache(sql, + locallyScopedConn.initializeResultsMetadataFromCache(sql, null /* will be created */, this.results); } } @@ -726,7 +750,7 @@ return ((rs != null) && rs.reallyResult()); } } - + /** * @see Statement#execute(String, int) */ @@ -1049,12 +1073,12 @@ Connection locallyScopedConn = this.connection; synchronized (locallyScopedConn.getMutex()) { - this.wasCancelled = false; + synchronized (this.cancelTimeoutMutex) { + this.wasCancelled = false; + } checkNullOrEmptyQuery(sql); - - - + if (this.doEscapeProcessing) { Object escapedSqlResult = EscapeProcessor.escapeSQL(sql, locallyScopedConn.serverSupportsConvertFn(), this.connection); @@ -1092,7 +1116,9 @@ } CancelTask timeoutTask = null; - + + String oldCatalog = null; + try { if (this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) { @@ -1101,8 +1127,6 @@ this.timeoutInMillis); } - String oldCatalog = null; - if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) { oldCatalog = locallyScopedConn.getCatalog(); locallyScopedConn.setCatalog(this.currentCatalog); @@ -1112,7 +1136,7 @@ // Check if we have cached metadata for this query... // if (locallyScopedConn.getCacheResultSetMetadata()) { - cachedMetaData = getCachedMetaData(sql); + cachedMetaData = locallyScopedConn.getCachedMetaData(sql); } if (locallyScopedConn.useMaxRows()) { @@ -1166,45 +1190,42 @@ } if (timeoutTask != null) { + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask.cancel(); timeoutTask = null; } - if (oldCatalog != null) { - locallyScopedConn.setCatalog(oldCatalog); + synchronized (this.cancelTimeoutMutex) { + if (this.wasCancelled) { + this.wasCancelled = false; + throw new MySQLTimeoutException(); + } } - - if (this.wasCancelled) { - this.wasCancelled = false; - - throw new MySQLTimeoutException(); - } } finally { if (timeoutTask != null) { timeoutTask.cancel(); } + + if (oldCatalog != null) { + locallyScopedConn.setCatalog(oldCatalog); + } } this.lastInsertId = this.results.getUpdateID(); - /* - * if (!this.results.reallyResult()) { if - * (!this.connection.getAutoCommit()) { this.connection.rollback(); } - * - * throw - * SQLError.createSQLException(Messages.getString("Statement.40"), - * //$NON-NLS-1$ SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ } - */ if (cachedMetaData != null) { - initializeResultsMetadataFromCache(sql, cachedMetaData, + locallyScopedConn.initializeResultsMetadataFromCache(sql, cachedMetaData, this.results); } else { if (this.connection.getCacheResultSetMetadata()) { - initializeResultsMetadataFromCache(sql, + locallyScopedConn.initializeResultsMetadataFromCache(sql, null /* will be created */, this.results); } } - + return this.results; } } @@ -1229,18 +1250,20 @@ } protected int executeUpdate(String sql, boolean isBatch) - throws SQLException { + throws SQLException { checkClosed(); - + Connection locallyScopedConn = this.connection; - + char firstStatementChar = StringUtils.firstNonWsCharUc(sql); ResultSet rs = null; synchronized (locallyScopedConn.getMutex()) { - this.wasCancelled = false; - + synchronized (this.cancelTimeoutMutex) { + this.wasCancelled = false; + } + checkNullOrEmptyQuery(sql); if (this.doEscapeProcessing) { @@ -1253,32 +1276,34 @@ sql = ((EscapeProcessorResult) escapedSqlResult).escapedSql; } } - + if (locallyScopedConn.isReadOnly()) { throw SQLError.createSQLException(Messages .getString("Statement.42") //$NON-NLS-1$ + Messages.getString("Statement.43"), //$NON-NLS-1$ SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ } - + if (StringUtils.startsWithIgnoreCaseAndWs(sql, "select")) { //$NON-NLS-1$ throw SQLError.createSQLException(Messages .getString("Statement.46"), //$NON-NLS-1$ - "01S03"); //$NON-NLS-1$ + "01S03"); //$NON-NLS-1$ } - + if (this.results != null) { if (!locallyScopedConn.getHoldResultsOpenOverStatementClose()) { this.results.realClose(false); } } - + // The checking and changing of catalogs // must happen in sequence, so synchronize // on the same mutex that _conn is using - + CancelTask timeoutTask = null; + String oldCatalog = null; + try { if (this.timeoutInMillis != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) { @@ -1287,8 +1312,6 @@ this.timeoutInMillis); } - String oldCatalog = null; - if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) { oldCatalog = locallyScopedConn.getCatalog(); locallyScopedConn.setCatalog(this.currentCatalog); @@ -1312,24 +1335,30 @@ this.currentCatalog, true /* force read of field info on DML */, isBatch); - + if (timeoutTask != null) { + if (timeoutTask.caughtWhileCancelling != null) { + throw timeoutTask.caughtWhileCancelling; + } + timeoutTask.cancel(); timeoutTask = null; } - if (oldCatalog != null) { - locallyScopedConn.setCatalog(oldCatalog); + synchronized (this.cancelTimeoutMutex) { + if (this.wasCancelled) { + this.wasCancelled = false; + throw new MySQLTimeoutException(); + } } - - if (this.wasCancelled) { - this.wasCancelled = false; - throw new MySQLTimeoutException(); - } } finally { if (timeoutTask != null) { timeoutTask.cancel(); } + + if (oldCatalog != null) { + locallyScopedConn.setCatalog(oldCatalog); + } } } @@ -1352,6 +1381,7 @@ return truncatedUpdateCount; } + /** * @see Statement#executeUpdate(String, int) */ @@ -2041,12 +2071,14 @@ } } + this.isClosed = true; + this.results = null; this.connection = null; this.warningChain = null; this.openResults = null; this.batchedGeneratedKeys = null; - this.isClosed = true; + this.cancelTimeoutMutex = null; } /**