Modified:
branches/branch_5_0/connector-j/CHANGES
branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java
branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java
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
branches/branch_5_0/connector-j/src/com/mysql/jdbc/exceptions/MySQLTimeoutException.java
branches/branch_5_0/connector-j/src/testsuite/simple/StatementsTest.java
Log:
- Implementation of Statement.cancel() and Statement.setQueryTimeout().
Both require MySQL-5.0.0 or newer server, require a separate connection
to issue the "KILL QUERY" command, and in the case of setQueryTimeout()
creates an additional thread to handle the timeout functionality.
Note: Failures to cancel the statement for setQueryTimeout() may manifest
themselves as RuntimeExceptions rather than failing silently, as there
is currently no way to unblock the thread that is executing the query being
cancelled due to timeout expiration and have it throw the exception
instead.
Modified: branches/branch_5_0/connector-j/CHANGES
===================================================================
--- branches/branch_5_0/connector-j/CHANGES 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/CHANGES 2005-12-06 23:10:38 UTC (rev 4659)
@@ -76,8 +76,19 @@
(usually not recommended, but the JDBC spec allows it anyways),
part of fix to BUG#14972).
-xx-xx-05 - Version 3.1.12
+ - Implementation of Statement.cancel() and Statement.setQueryTimeout().
+ Both require MySQL-5.0.0 or newer server, require a separate connection
+ to issue the "KILL QUERY" command, and in the case of setQueryTimeout()
+ creates an additional thread to handle the timeout functionality.
+
+ Note: Failures to cancel the statement for setQueryTimeout() may manifest
+ themselves as RuntimeExceptions rather than failing silently, as there
+ is currently no way to unblock the thread that is executing the query being
+ cancelled due to timeout expiration and have it throw the exception
+ instead.
+11-30-05 - Version 3.1.12
+
- Fixed client-side prepared statement bug with embedded ? inside
quoted identifiers (it was recognized as a placeholder, when it
was not).
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -1390,6 +1390,12 @@
private Calendar utcCalendar;
+ private String origHostToConnectTo;
+ private int origPortToConnectTo;
+ private String origDatabaseToConnectTo;
+ private String origUrl;
+
+
/**
* Creates a connection to a MySQL Server.
*
@@ -1414,6 +1420,14 @@
this.connectionCreationTimeMillis = System.currentTimeMillis();
this.pointOfOrigin = new Throwable();
+ // Stash away for later, used to clone this connection for Statement.cancel
+ // and Statement.setQueryTimeout().
+ //
+
+ this.origHostToConnectTo = hostToConnectTo;
+ this.origPortToConnectTo = portToConnectTo;
+ this.origDatabaseToConnectTo = databaseToConnectTo;
+
try {
Blob.class.getMethod("truncate", new Class[] {Long.TYPE});
@@ -1537,6 +1551,17 @@
}
}
+ // we don't want to be able to publicly clone this...
+
+ protected Connection duplicate() throws SQLException {
+ return new Connection( this.origHostToConnectTo,
+ this.origPortToConnectTo,
+ this.props,
+ this.origDatabaseToConnectTo,
+ this.myURL,
+ null);
+ }
+
private void addToHistogram(int[] histogramCounts,
long[] histogramBreakpoints, long value, int numberOfTimes,
long currentLowerBound, long currentUpperBound) {
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -237,6 +237,7 @@
private boolean useConnectWithDb;
private boolean needToGrabQueryFromPacket;
private boolean autoGenerateTestcaseScript;
+ private long threadId;
/**
* Constructor: Connect to the MySQL server and setup a stream connection.
@@ -1021,7 +1022,7 @@
this.colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15); // guess? Not noted in changelog
this.useNewUpdateCounts = versionMeetsMinimum(3, 22, 5);
- buf.readLong(); // thread id -- we don't use it
+ threadId = buf.readLong();
this.seed = buf.readString();
this.serverCapabilities = 0;
@@ -3839,4 +3840,8 @@
return fetchedRows;
}
+
+ protected long getThreadId() {
+ return threadId;
+ }
}
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 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -49,6 +49,8 @@
import java.util.Locale;
import java.util.TimeZone;
+import com.mysql.jdbc.Statement.CancelThread;
+import com.mysql.jdbc.exceptions.MySQLTimeoutException;
import com.mysql.jdbc.profiler.ProfilerEvent;
/**
@@ -922,13 +924,35 @@
Buffer sendPacket, boolean createStreamingResultSet,
boolean queryIsSelectOnly, boolean unpackFields, boolean isBatch)
throws SQLException {
+ this.wasCancelled = false;
+
this.numberOfExecutions++;
ResultSet rs;
- rs = this.connection.execSQL(this, null, maxRowsToRetrieve, sendPacket,
+
+ CancelThread timeoutThread = null;
+
+ try {
+ if (this.timeout != 0
+ && this.connection.versionMeetsMinimum(5, 0, 0)) {
+ timeoutThread = new CancelThread(this.timeout);
+ new Thread(timeoutThread).start();
+ }
+
+ rs = this.connection.execSQL(this, null, maxRowsToRetrieve, sendPacket,
this.resultSetType, this.resultSetConcurrency,
createStreamingResultSet, false, this.currentCatalog,
unpackFields, USES_VARIABLES_UNKNOWN, isBatch);
+
+ if (this.wasCancelled) {
+ this.wasCancelled = false;
+ throw new MySQLTimeoutException();
+ }
+ } finally {
+ if (timeoutThread != null) {
+ timeoutThread.dontCancel();
+ }
+ }
return rs;
}
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 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -24,6 +24,8 @@
*/
package com.mysql.jdbc;
+import com.mysql.jdbc.Statement.CancelThread;
+import com.mysql.jdbc.exceptions.MySQLTimeoutException;
import com.mysql.jdbc.profiler.ProfileEventSink;
import com.mysql.jdbc.profiler.ProfilerEvent;
@@ -1142,79 +1144,104 @@
begin = System.currentTimeMillis();
}
- Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE,
- null, packet, false, null);
-
+ this.wasCancelled = false;
+ CancelThread timeoutThread = null;
- this.connection.incrementNumberOfPreparedExecutes();
-
- if (this.connection.getProfileSql()) {
- this.eventSink = ProfileEventSink.getInstance(this.connection);
-
- this.eventSink.consumeEvent(new ProfilerEvent(
- ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$
- this.connection.getId(), this.statementId, -1, System
- .currentTimeMillis(), (int) (System
- .currentTimeMillis() - begin), null,
- new Throwable(), truncateQueryToLog(asSql(true))));
- }
-
- com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this,
- maxRowsToRetrieve, this.resultSetType,
- this.resultSetConcurrency, createStreamingResultSet,
- this.currentCatalog, resultPacket, true, this.fieldCount,
- true);
-
+ try {
+ if (this.timeout != 0
+ && this.connection.versionMeetsMinimum(5, 0, 0)
+ && usingCursor /* FIXME: Not supported currently */) {
+ timeoutThread = new CancelThread(this.timeout);
+ new Thread(timeoutThread).start();
+ }
+
+ Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE,
+ null, packet, false, null);
+
+ if (timeoutThread != null) {
+ timeoutThread.dontCancel();
+ timeoutThread = null;
+ }
+
+ if (this.wasCancelled) {
+ this.wasCancelled = false;
+ throw new MySQLTimeoutException();
+ }
- if (!createStreamingResultSet &&
- this.serverNeedsResetBeforeEachExecution) {
- serverResetStatement(); // clear any long data...
- }
-
- this.sendTypesToServer = false;
- this.results = rs;
-
- if (this.connection.getLogSlowQueries()
- || this.connection.getGatherPerformanceMetrics()) {
- long elapsedTime = System.currentTimeMillis() - begin;
-
+ this.connection.incrementNumberOfPreparedExecutes();
+
+ if (this.connection.getProfileSql()) {
+ this.eventSink = ProfileEventSink.getInstance(this.connection);
+
+ this.eventSink.consumeEvent(new ProfilerEvent(
+ ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$
+ this.connection.getId(), this.statementId, -1, System
+ .currentTimeMillis(), (int) (System
+ .currentTimeMillis() - begin), null,
+ new Throwable(), truncateQueryToLog(asSql(true))));
+ }
+
+ com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this,
+ maxRowsToRetrieve, this.resultSetType,
+ this.resultSetConcurrency, createStreamingResultSet,
+ this.currentCatalog, resultPacket, true, this.fieldCount,
+ true);
+
+
+ if (!createStreamingResultSet &&
+ this.serverNeedsResetBeforeEachExecution) {
+ serverResetStatement(); // clear any long data...
+ }
+
+ this.sendTypesToServer = false;
+ this.results = rs;
+
if (this.connection.getLogSlowQueries()
- && (elapsedTime >= this.connection
- .getSlowQueryThresholdMillis())) {
- StringBuffer mesgBuf = new StringBuffer(
- 48 + this.originalSql.length());
- mesgBuf.append(Messages
- .getString("ServerPreparedStatement.15")); //$NON-NLS-1$
- mesgBuf.append(this.connection
- .getSlowQueryThresholdMillis());
- mesgBuf.append(Messages
- .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$
- mesgBuf.append(elapsedTime);
- mesgBuf.append(Messages
- .getString("ServerPreparedStatement.16")); //$NON-NLS-1$
-
- mesgBuf.append("as prepared: ");
- mesgBuf.append(this.originalSql);
- mesgBuf.append("\n\n with parameters bound:\n\n");
- mesgBuf.append(asSql(true));
-
- this.connection.getLog().logWarn(mesgBuf.toString());
-
- if (this.connection.getExplainSlowQueries()) {
- String queryAsString = asSql(true);
-
- mysql.explainSlowQuery(queryAsString.getBytes(),
- queryAsString);
+ || this.connection.getGatherPerformanceMetrics()) {
+ long elapsedTime = System.currentTimeMillis() - begin;
+
+ if (this.connection.getLogSlowQueries()
+ && (elapsedTime >= this.connection
+ .getSlowQueryThresholdMillis())) {
+ StringBuffer mesgBuf = new StringBuffer(
+ 48 + this.originalSql.length());
+ mesgBuf.append(Messages
+ .getString("ServerPreparedStatement.15")); //$NON-NLS-1$
+ mesgBuf.append(this.connection
+ .getSlowQueryThresholdMillis());
+ mesgBuf.append(Messages
+ .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$
+ mesgBuf.append(elapsedTime);
+ mesgBuf.append(Messages
+ .getString("ServerPreparedStatement.16")); //$NON-NLS-1$
+
+ mesgBuf.append("as prepared: ");
+ mesgBuf.append(this.originalSql);
+ mesgBuf.append("\n\n with parameters bound:\n\n");
+ mesgBuf.append(asSql(true));
+
+ this.connection.getLog().logWarn(mesgBuf.toString());
+
+ if (this.connection.getExplainSlowQueries()) {
+ String queryAsString = asSql(true);
+
+ mysql.explainSlowQuery(queryAsString.getBytes(),
+ queryAsString);
+ }
}
+
+ if (this.connection.getGatherPerformanceMetrics()) {
+ this.connection.registerQueryExecutionTime(elapsedTime);
+ }
}
-
- if (this.connection.getGatherPerformanceMetrics()) {
- this.connection.registerQueryExecutionTime(elapsedTime);
+
+ return rs;
+ } finally {
+ if (timeoutThread != null) {
+ timeoutThread.dontCancel();
}
}
-
- return rs;
}
}
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 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Statement.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -24,6 +24,7 @@
*/
package com.mysql.jdbc;
+import com.mysql.jdbc.exceptions.MySQLTimeoutException;
import com.mysql.jdbc.profiler.ProfileEventSink;
import com.mysql.jdbc.profiler.ProfilerEvent;
import com.mysql.jdbc.util.LRUCache;
@@ -54,7 +55,8 @@
* </p>
*
* @author Mark Matthews
- * @version $Id$
+ * @version $Id: Statement.java 4624 2005-11-28 14:24:29 -0600 (Mon, 28 Nov
+ * 2005) mmatthews $
*
* @see java.sql.Statement
* @see ResultSet
@@ -74,6 +76,67 @@
java.sql.ResultSetMetaData metadata;
}
+ /**
+ * Thread used to implement query timeouts...Eventually we could be more
+ * efficient and have one thread with timers, but this is a straightforward
+ * and simple way to implement a feature that isn't used all that often.
+ */
+ class CancelThread implements Runnable {
+
+ boolean shouldCancel = true;
+
+ long waitForMillis = 0;
+
+ long connectionId = 0;
+
+ CancelThread(long timeoutMillis) throws SQLException {
+ waitForMillis = timeoutMillis;
+ connectionId = connection.getIO().getThreadId();
+ }
+
+ void dontCancel() {
+ shouldCancel = false;
+ }
+
+ public void run() {
+ try {
+ Thread.sleep(waitForMillis);
+ } catch (InterruptedException iEx) {
+ // ignore
+ }
+
+ if (shouldCancel) {
+ Connection cancelConn = null;
+ java.sql.Statement cancelStmt = null;
+
+ try {
+ cancelConn = connection.duplicate();
+ cancelStmt = cancelConn.createStatement();
+ cancelStmt.execute("KILL QUERY " + connectionId);
+ wasCancelled = true;
+ } catch (SQLException sqlEx) {
+ throw new RuntimeException(sqlEx.toString());
+ } finally {
+ if (cancelStmt != null) {
+ try {
+ cancelStmt.close();
+ } catch (SQLException sqlEx) {
+ throw new RuntimeException(sqlEx.toString());
+ }
+ }
+
+ if (cancelConn != null) {
+ try {
+ cancelConn.close();
+ } catch (SQLException sqlEx) {
+ throw new RuntimeException(sqlEx.toString());
+ }
+ }
+ }
+ }
+ }
+ }
+
/** Used to generate IDs when profiling. */
protected static int statementCounter = 1;
@@ -83,6 +146,8 @@
public final static byte USES_VARIABLES_UNKNOWN = -1;
+ protected boolean wasCancelled = false;
+
/** Holds batched commands */
protected List batchedArgs;
@@ -167,9 +232,9 @@
/** The warnings chain. */
protected SQLWarning warningChain = null;
- /**
- * Should this statement hold results open over .close() irregardless
- * of connection's setting?
+ /**
+ * Should this statement hold results open over .close() irregardless of
+ * connection's setting?
*/
protected boolean holdResultsOpenOverClose = false;
@@ -186,7 +251,8 @@
*/
public Statement(Connection c, String catalog) throws SQLException {
if ((c == null) || c.isClosed()) {
- throw SQLError.createSQLException(Messages.getString("Statement.0"), //$NON-NLS-1$
+ throw SQLError.createSQLException(
+ Messages.getString("Statement.0"), //$NON-NLS-1$
SQLError.SQL_STATE_CONNECTION_NOT_OPEN); //$NON-NLS-1$ //$NON-NLS-2$
}
@@ -211,7 +277,7 @@
setFetchSize(defaultFetchSize);
}
}
-
+
if (this.connection.getUseUnicode()) {
this.charEncoding = this.connection.getEncoding();
@@ -260,13 +326,32 @@
}
/**
- * Cancels this Statement object if both the DBMS and
- * driver support aborting an SQL statement. This method
- * can be used by one thread to cancel a statement
- * that is being executed by another thread.
+ * Cancels this Statement object if both the DBMS and driver support
+ * aborting an SQL statement. This method can be used by one thread to
+ * cancel a statement that is being executed by another thread.
*/
public void cancel() throws SQLException {
- // No-op
+ if (this.connection.versionMeetsMinimum(5, 0, 0)) {
+ Connection cancelConn = null;
+ java.sql.Statement cancelStmt = null;
+
+ try {
+ cancelConn = connection.duplicate();
+ cancelStmt = cancelConn.createStatement();
+ cancelStmt.execute("KILL QUERY "
+ + this.connection.getIO().getThreadId());
+ this.wasCancelled = true;
+ } finally {
+ if (cancelStmt != null) {
+ cancelStmt.close();
+ }
+
+ if (cancelConn != null) {
+ cancelConn.close();
+ }
+ }
+
+ }
}
// --------------------------JDBC 2.0-----------------------------
@@ -279,7 +364,8 @@
*/
protected void checkClosed() throws SQLException {
if (this.isClosed) {
- throw SQLError.createSQLException(Messages.getString("Statement.49"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.49"), //$NON-NLS-1$
SQLError.SQL_STATE_CONNECTION_NOT_OPEN); //$NON-NLS-1$
}
}
@@ -307,7 +393,8 @@
|| StringUtils.startsWithIgnoreCaseAndWs(sql, "DROP") //$NON-NLS-1$
|| StringUtils.startsWithIgnoreCaseAndWs(sql, "CREATE") //$NON-NLS-1$
|| StringUtils.startsWithIgnoreCaseAndWs(sql, "ALTER")) { //$NON-NLS-1$
- throw SQLError.createSQLException(Messages.getString("Statement.57"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.57"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
}
@@ -324,12 +411,14 @@
*/
protected void checkNullOrEmptyQuery(String sql) throws SQLException {
if (sql == null) {
- throw SQLError.createSQLException(Messages.getString("Statement.59"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.59"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
}
if (sql.length() == 0) {
- throw SQLError.createSQLException(Messages.getString("Statement.61"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.61"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
}
}
@@ -398,6 +487,34 @@
}
/**
+ * @param sql
+ * @return
+ */
+ private ResultSet createResultSetUsingServerFetch(String sql)
+ throws SQLException {
+ java.sql.PreparedStatement pStmt = this.connection.prepareStatement(
+ sql, this.resultSetType, this.resultSetConcurrency);
+
+ pStmt.setFetchSize(this.fetchSize);
+
+ pStmt.execute();
+
+ //
+ // Need to be able to get resultset irrespective if we issued DML or
+ // not to make this work.
+ //
+ ResultSet rs = ((com.mysql.jdbc.Statement) pStmt)
+ .getResultSetInternal();
+
+ rs
+ .setStatementUsedForFetchingRows((com.mysql.jdbc.PreparedStatement) pStmt);
+
+ this.results = rs;
+
+ return rs;
+ }
+
+ /**
* We only stream result sets when they are forward-only, read-only, and the
* fetch size has been set to Integer.MIN_VALUE
*
@@ -435,6 +552,8 @@
* if a database access error occurs
*/
public synchronized boolean execute(String sql) throws SQLException {
+ this.wasCancelled = false;
+
checkNullOrEmptyQuery(sql);
checkClosed();
@@ -447,7 +566,8 @@
isSelect = false;
if (this.connection.isReadOnly()) {
- throw SQLError.createSQLException(Messages.getString("Statement.27") //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.27") //$NON-NLS-1$
+ Messages.getString("Statement.28"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
@@ -455,8 +575,7 @@
if (this.doEscapeProcessing) {
Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
- this.connection.serverSupportsConvertFn(),
- this.connection);
+ this.connection.serverSupportsConvertFn(), this.connection);
if (escapedSqlResult instanceof String) {
sql = (String) escapedSqlResult;
@@ -485,81 +604,108 @@
if (useServerFetch()) {
rs = createResultSetUsingServerFetch(sql);
} else {
- String oldCatalog = null;
-
- if (!this.connection.getCatalog().equals(this.currentCatalog)) {
- oldCatalog = this.connection.getCatalog();
- this.connection.setCatalog(this.currentCatalog);
- }
-
- //
- // Check if we have cached metadata for this query...
- //
- if (this.connection.getCacheResultSetMetadata()) {
- cachedMetaData = getCachedMetaData(sql);
- }
-
- //
- // Only apply max_rows to selects
- //
- if (this.connection.useMaxRows()) {
- int rowLimit = -1;
-
- if (isSelect) {
- if (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1) { //$NON-NLS-1$
- rowLimit = this.maxRows;
- } else {
- if (this.maxRows <= 0) {
- this.connection.execSQL(this,
- "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, //$NON-NLS-1$
- null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
- java.sql.ResultSet.CONCUR_READ_ONLY, false,
- false, this.currentCatalog, true); //$NON-NLS-1$
+ CancelThread timeoutThread = null;
+
+ try {
+ if (this.timeout != 0
+ && this.connection.versionMeetsMinimum(5, 0, 0)) {
+ timeoutThread = new CancelThread(this.timeout);
+ new Thread(timeoutThread).start();
+ }
+
+ String oldCatalog = null;
+
+ if (!this.connection.getCatalog().equals(
+ this.currentCatalog)) {
+ oldCatalog = this.connection.getCatalog();
+ this.connection.setCatalog(this.currentCatalog);
+ }
+
+ //
+ // Check if we have cached metadata for this query...
+ //
+ if (this.connection.getCacheResultSetMetadata()) {
+ cachedMetaData = getCachedMetaData(sql);
+ }
+
+ //
+ // Only apply max_rows to selects
+ //
+ if (this.connection.useMaxRows()) {
+ int rowLimit = -1;
+
+ if (isSelect) {
+ if (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1) { //$NON-NLS-1$
+ rowLimit = this.maxRows;
} else {
- this.connection
- .execSQL(
- this,
- "SET OPTION SQL_SELECT_LIMIT=" + this.maxRows, //$NON-NLS-1$
- -1,
- null,
- java.sql.ResultSet.TYPE_FORWARD_ONLY,
- java.sql.ResultSet.CONCUR_READ_ONLY,
- false, false, this.currentCatalog,
- true); //$NON-NLS-1$
+ if (this.maxRows <= 0) {
+ this.connection
+ .execSQL(
+ this,
+ "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, //$NON-NLS-1$
+ null,
+ java.sql.ResultSet.TYPE_FORWARD_ONLY,
+ java.sql.ResultSet.CONCUR_READ_ONLY,
+ false, false,
+ this.currentCatalog, true); //$NON-NLS-1$
+ } else {
+ this.connection
+ .execSQL(
+ this,
+ "SET OPTION SQL_SELECT_LIMIT=" + this.maxRows, //$NON-NLS-1$
+ -1,
+ null,
+ java.sql.ResultSet.TYPE_FORWARD_ONLY,
+ java.sql.ResultSet.CONCUR_READ_ONLY,
+ false, false,
+ this.currentCatalog, true); //$NON-NLS-1$
+ }
}
+ } else {
+ this.connection
+ .execSQL(
+ this,
+ "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
+ java.sql.ResultSet.TYPE_FORWARD_ONLY,
+ java.sql.ResultSet.CONCUR_READ_ONLY,
+ false, false, this.currentCatalog,
+ true); //$NON-NLS-1$
}
+
+ // Finally, execute the query
+ rs = this.connection.execSQL(this, sql, rowLimit, null,
+ this.resultSetType, this.resultSetConcurrency,
+ createStreamingResultSet(), isSelect,
+ this.currentCatalog, (cachedMetaData == null));
} else {
- this.connection.execSQL(this,
- "SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
- java.sql.ResultSet.TYPE_FORWARD_ONLY,
- java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
- this.currentCatalog, true); //$NON-NLS-1$
+ rs = this.connection.execSQL(this, sql, -1, null,
+ this.resultSetType, this.resultSetConcurrency,
+ createStreamingResultSet(), isSelect,
+ this.currentCatalog, (cachedMetaData == null));
}
-
- // Finally, execute the query
- rs = this.connection.execSQL(this, sql, rowLimit, null,
- this.resultSetType, this.resultSetConcurrency,
- createStreamingResultSet(), isSelect,
- this.currentCatalog, (cachedMetaData == null));
- } else {
- rs = this.connection.execSQL(this, sql, -1, null,
- this.resultSetType, this.resultSetConcurrency,
- createStreamingResultSet(), isSelect,
- this.currentCatalog, (cachedMetaData == null));
+
+ if (oldCatalog != null) {
+ this.connection.setCatalog(oldCatalog);
+ }
+
+ if (this.wasCancelled) {
+ this.wasCancelled = false;
+ throw new MySQLTimeoutException();
+ }
+ } finally {
+ if (timeoutThread != null) {
+ timeoutThread.dontCancel();
+ }
}
-
- if (oldCatalog != null) {
- this.connection.setCatalog(oldCatalog);
- }
}
-
+
this.lastInsertId = rs.getUpdateID();
-
+
if (rs != null) {
this.results = rs;
-
+
rs.setFirstCharOfQuery(firstNonWsChar);
-
+
if (rs.reallyResult()) {
if (cachedMetaData != null) {
initializeResultsMetadataFromCache(sql, cachedMetaData,
@@ -572,7 +718,7 @@
}
}
}
-
+
return ((rs != null) && rs.reallyResult());
}
}
@@ -674,7 +820,8 @@
*/
public synchronized int[] executeBatch() throws SQLException {
if (this.connection.isReadOnly()) {
- throw SQLError.createSQLException(Messages.getString("Statement.34") //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.34") //$NON-NLS-1$
+ Messages.getString("Statement.35"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
@@ -688,47 +835,48 @@
synchronized (this.connection.getMutex()) {
try {
int[] updateCounts = null;
-
+
if (this.batchedArgs != null) {
int nbrCommands = this.batchedArgs.size();
updateCounts = new int[nbrCommands];
-
+
for (int i = 0; i < nbrCommands; i++) {
updateCounts[i] = -3;
}
-
+
SQLException sqlEx = null;
-
+
int commandIndex = 0;
-
+
for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
try {
- updateCounts[commandIndex] = executeUpdate((String) this.batchedArgs
- .get(commandIndex), true);
+ updateCounts[commandIndex] = executeUpdate(
+ (String) this.batchedArgs.get(commandIndex),
+ true);
} catch (SQLException ex) {
updateCounts[commandIndex] = EXECUTE_FAILED;
-
+
if (this.connection.getContinueBatchOnError()) {
sqlEx = ex;
} else {
int[] newUpdateCounts = new int[commandIndex];
- System.arraycopy(updateCounts, 0, newUpdateCounts,
- 0, commandIndex);
-
+ System.arraycopy(updateCounts, 0,
+ newUpdateCounts, 0, commandIndex);
+
throw new java.sql.BatchUpdateException(ex
.getMessage(), ex.getSQLState(), ex
.getErrorCode(), newUpdateCounts);
}
}
}
-
+
if (sqlEx != null) {
- throw new java.sql.BatchUpdateException(sqlEx.getMessage(),
- sqlEx.getSQLState(), sqlEx.getErrorCode(),
- updateCounts);
+ throw new java.sql.BatchUpdateException(sqlEx
+ .getMessage(), sqlEx.getSQLState(), sqlEx
+ .getErrorCode(), updateCounts);
}
}
-
+
return (updateCounts != null) ? updateCounts : new int[0];
} finally {
clearBatch();
@@ -749,14 +897,15 @@
*/
public synchronized java.sql.ResultSet executeQuery(String sql)
throws SQLException {
+ this.wasCancelled = false;
+
checkNullOrEmptyQuery(sql);
checkClosed();
if (this.doEscapeProcessing) {
Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
- this.connection.serverSupportsConvertFn(),
- this.connection);
+ this.connection.serverSupportsConvertFn(), this.connection);
if (escapedSqlResult instanceof String) {
sql = (String) escapedSqlResult;
@@ -786,23 +935,33 @@
synchronized (this.connection.getMutex()) {
if (useServerFetch()) {
this.results = createResultSetUsingServerFetch(sql);
-
+
return this.results;
- } else {
+ }
+
+ CancelThread timeoutThread = null;
+
+ try {
+ if (this.timeout != 0
+ && this.connection.versionMeetsMinimum(5, 0, 0)) {
+ timeoutThread = new CancelThread(this.timeout);
+ new Thread(timeoutThread).start();
+ }
+
String oldCatalog = null;
-
+
if (!this.connection.getCatalog().equals(this.currentCatalog)) {
oldCatalog = this.connection.getCatalog();
this.connection.setCatalog(this.currentCatalog);
}
-
+
//
// Check if we have cached metadata for this query...
//
if (this.connection.getCacheResultSetMetadata()) {
cachedMetaData = getCachedMetaData(sql);
}
-
+
if (this.connection.useMaxRows()) {
// We need to execute this all together
// So synchronize on the Connection's mutex (because
@@ -822,7 +981,8 @@
"SET OPTION SQL_SELECT_LIMIT=DEFAULT", -1, null, //$NON-NLS-1$
java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY,
- false, false, this.currentCatalog, true); //$NON-NLS-1$
+ false, false, this.currentCatalog,
+ true); //$NON-NLS-1$
} else {
this.connection
.execSQL(
@@ -831,14 +991,16 @@
null,
java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY,
- false, false, this.currentCatalog, true); //$NON-NLS-1$
+ false, false, this.currentCatalog,
+ true); //$NON-NLS-1$
}
-
- this.results = this.connection.execSQL(this, sql, -1, null,
- this.resultSetType, this.resultSetConcurrency,
+
+ this.results = this.connection.execSQL(this, sql, -1,
+ null, this.resultSetType,
+ this.resultSetConcurrency,
createStreamingResultSet(), true,
this.currentCatalog, (cachedMetaData == null));
-
+
if (oldCatalog != null) {
this.connection.setCatalog(oldCatalog);
}
@@ -846,22 +1008,33 @@
} else {
this.results = this.connection.execSQL(this, sql, -1, null,
this.resultSetType, this.resultSetConcurrency,
- createStreamingResultSet(), true, this.currentCatalog,
- (cachedMetaData == null));
+ createStreamingResultSet(), true,
+ this.currentCatalog, (cachedMetaData == null));
}
-
+
if (oldCatalog != null) {
this.connection.setCatalog(oldCatalog);
}
+
+ if (this.wasCancelled) {
+ this.wasCancelled = false;
+
+ throw new MySQLTimeoutException();
+ }
+ } finally {
+ if (timeoutThread != null) {
+ timeoutThread.dontCancel();
+ }
}
-
+
this.lastInsertId = this.results.getUpdateID();
-
+
/*
* if (!this.results.reallyResult()) { if
* (!this.connection.getAutoCommit()) { this.connection.rollback(); }
*
- * throw SQLError.createSQLException(Messages.getString("Statement.40"),
+ * throw
+ * SQLError.createSQLException(Messages.getString("Statement.40"),
* //$NON-NLS-1$ SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ }
*/
if (cachedMetaData != null) {
@@ -873,7 +1046,7 @@
null /* will be created */, this.results);
}
}
-
+
return this.results;
}
}
@@ -896,20 +1069,25 @@
public synchronized int executeUpdate(String sql) throws SQLException {
return executeUpdate(sql, false);
}
-
- protected synchronized int executeUpdate(String sql, boolean isBatch) throws SQLException {
+
+ protected synchronized int executeUpdate(String sql, boolean isBatch)
+ throws SQLException {
+ this.wasCancelled = false;
+
checkNullOrEmptyQuery(sql);
checkClosed();
if (this.connection.isReadOnly()) {
- throw SQLError.createSQLException(Messages.getString("Statement.42") //$NON-NLS-1$
+ 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$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.46"), //$NON-NLS-1$
"01S03"); //$NON-NLS-1$
}
@@ -917,8 +1095,7 @@
if (this.doEscapeProcessing) {
Object escapedSqlResult = EscapeProcessor.escapeSQL(sql,
- this.connection.serverSupportsConvertFn(),
- this.connection);
+ this.connection.serverSupportsConvertFn(), this.connection);
if (escapedSqlResult instanceof String) {
sql = (String) escapedSqlResult;
@@ -939,33 +1116,53 @@
ResultSet rs = null;
synchronized (this.connection.getMutex()) {
- String oldCatalog = null;
+ CancelThread timeoutThread = null;
- if (!this.connection.getCatalog().equals(this.currentCatalog)) {
- oldCatalog = this.connection.getCatalog();
- this.connection.setCatalog(this.currentCatalog);
- }
+ try {
+ if (this.timeout != 0
+ && this.connection.versionMeetsMinimum(5, 0, 0)) {
+ timeoutThread = new CancelThread(this.timeout);
+ new Thread(timeoutThread).start();
+ }
- //
- // Only apply max_rows to selects
- //
- if (this.connection.useMaxRows()) {
- this.connection.execSQL(this,
- "SET OPTION SQL_SELECT_LIMIT=DEFAULT", //$NON-NLS-1$
- -1, null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
- java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
- this.currentCatalog, true);
- }
+ String oldCatalog = null;
- rs = this.connection
- .execSQL(this, sql, -1, null,
- java.sql.ResultSet.TYPE_FORWARD_ONLY,
+ if (!this.connection.getCatalog().equals(this.currentCatalog)) {
+ oldCatalog = this.connection.getCatalog();
+ this.connection.setCatalog(this.currentCatalog);
+ }
+
+ //
+ // Only apply max_rows to selects
+ //
+ if (this.connection.useMaxRows()) {
+ this.connection.execSQL(
+ this,
+ "SET OPTION SQL_SELECT_LIMIT=DEFAULT", //$NON-NLS-1$
+ -1, null, java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
- this.currentCatalog, true /* force read of field info on DML */,
- USES_VARIABLES_FALSE, isBatch);
+ this.currentCatalog, true);
+ }
- if (oldCatalog != null) {
- this.connection.setCatalog(oldCatalog);
+ rs = this.connection.execSQL(this, sql, -1, null,
+ java.sql.ResultSet.TYPE_FORWARD_ONLY,
+ java.sql.ResultSet.CONCUR_READ_ONLY, false, false,
+ this.currentCatalog,
+ true /* force read of field info on DML */,
+ USES_VARIABLES_FALSE, isBatch);
+
+ if (oldCatalog != null) {
+ this.connection.setCatalog(oldCatalog);
+ }
+
+ if (this.wasCancelled) {
+ this.wasCancelled = false;
+ throw new MySQLTimeoutException();
+ }
+ } finally {
+ if (timeoutThread != null) {
+ timeoutThread.dontCancel();
+ }
}
}
@@ -1043,6 +1240,14 @@
}
/**
+ * Required by JDBC spec
+ */
+ /*
+ * protected void finalize() throws Throwable { if (!this.isClosed) {
+ * realClose(false); } }
+ */
+
+ /**
* @see Statement#executeUpdate(String, String[])
*/
public int executeUpdate(String sql, String[] generatedKeyNames)
@@ -1070,17 +1275,6 @@
}
/**
- * Required by JDBC spec
- */
- /*
- protected void finalize() throws Throwable {
- if (!this.isClosed) {
- realClose(false);
- }
- }
-*/
-
- /**
* Returns cached metadata (or null if not cached) for the given query,
* which must match _exactly_. Note this method is guarded against
* concurrent access via the synchronized{} block in execute() and
@@ -1101,6 +1295,19 @@
}
/**
+ * Optimization to only use one calendar per-session, or calculate it for
+ * each call, depending on user configuration
+ */
+ protected synchronized Calendar getCalendarInstanceForSessionOrNew() {
+ if (this.connection != null) {
+ return this.connection.getCalendarInstanceForSessionOrNew();
+ } else {
+ // punt, no connection around
+ return new GregorianCalendar();
+ }
+ }
+
+ /**
* JDBC 2.0 Return the Connection that produced the Statement.
*
* @return the Connection that produced the Statement
@@ -1159,7 +1366,7 @@
Field[] fields = new Field[1];
fields[0] = new Field("", "GENERATED_KEY", Types.BIGINT, 17); //$NON-NLS-1$ //$NON-NLS-2$
fields[0].setConnection(this.connection);
-
+
ArrayList rowSet = new ArrayList();
long beginAt = getLastInsertID();
@@ -1326,7 +1533,8 @@
break;
default:
- throw SQLError.createSQLException(Messages.getString("Statement.19"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.19"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
@@ -1463,6 +1671,10 @@
return java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
+ protected synchronized ResultSet getResultSetInternal() {
+ return this.results;
+ }
+
/**
* JDBC 2.0 Determine the result set type.
*
@@ -1528,10 +1740,9 @@
*/
public synchronized java.sql.SQLWarning getWarnings() throws SQLException {
checkClosed();
-
- if (this.connection != null &&
- !this.connection.isClosed() &&
- this.connection.versionMeetsMinimum(4, 1, 0)) {
+
+ if (this.connection != null && !this.connection.isClosed()
+ && this.connection.versionMeetsMinimum(4, 1, 0)) {
SQLWarning pendingWarningsFromServer = SQLError
.convertShowWarningsToSQLWarnings(this.connection);
@@ -1606,8 +1817,8 @@
* @throws SQLException
* if an error occurs
*/
- protected void realClose(boolean calledExplicitly,
- boolean closeOpenResults) throws SQLException {
+ protected void realClose(boolean calledExplicitly, boolean closeOpenResults)
+ throws SQLException {
if (this.isClosed) {
return;
}
@@ -1618,7 +1829,8 @@
+ Messages.getString("Statement.64"); //$NON-NLS-1$
this.eventSink.consumeEvent(new ProfilerEvent(
- ProfilerEvent.TYPE_WARN, "", //$NON-NLS-1$
+ ProfilerEvent.TYPE_WARN,
+ "", //$NON-NLS-1$
this.currentCatalog, this.connection.getId(), this
.getId(), -1, System.currentTimeMillis(), 0,
null, this.pointOfOrigin, message));
@@ -1629,7 +1841,7 @@
if (closeOpenResults) {
closeOpenResults = !this.holdResultsOpenOverClose;
}
-
+
if (closeOpenResults && this.connection != null
&& !this.connection.getHoldResultsOpenOverStatementClose()) {
try {
@@ -1652,7 +1864,6 @@
}
}
-
this.results = null;
this.connection = null;
this.warningChain = null;
@@ -1717,7 +1928,8 @@
break;
default:
- throw SQLError.createSQLException(Messages.getString("Statement.5"), //$NON-NLS-1$
+ throw SQLError.createSQLException(
+ Messages.getString("Statement.5"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
}
@@ -1740,13 +1952,18 @@
if (((rows < 0) && (rows != Integer.MIN_VALUE))
|| ((this.maxRows != 0) && (this.maxRows != -1) && (rows > this
.getMaxRows()))) {
- throw SQLError.createSQLException(Messages.getString("Statement.7"), //$NON-NLS-1$
+ throw SQLError.createSQLException(
+ Messages.getString("Statement.7"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
}
this.fetchSize = rows;
}
+ protected void setHoldResultsOpenOverClose(boolean holdResultsOpenOverClose) {
+ this.holdResultsOpenOverClose = holdResultsOpenOverClose;
+ }
+
/**
* Sets the maxFieldSize
*
@@ -1758,7 +1975,8 @@
*/
public synchronized void setMaxFieldSize(int max) throws SQLException {
if (max < 0) {
- throw SQLError.createSQLException(Messages.getString("Statement.11"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.11"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
@@ -1766,7 +1984,8 @@
.getMaxAllowedPacket() : MysqlIO.getMaxBuf();
if (max > maxBuf) {
- throw SQLError.createSQLException(Messages.getString("Statement.13", //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages.getString(
+ "Statement.13", //$NON-NLS-1$
new Object[] { new Long(maxBuf) }), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
@@ -1787,10 +2006,11 @@
*/
public synchronized void setMaxRows(int max) throws SQLException {
if ((max > MysqlDefs.MAX_ROWS) || (max < 0)) {
- throw SQLError.createSQLException(
- Messages.getString("Statement.15") + max //$NON-NLS-1$
- + " > " //$NON-NLS-1$ //$NON-NLS-2$
- + MysqlDefs.MAX_ROWS + ".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
+ throw SQLError
+ .createSQLException(
+ Messages.getString("Statement.15") + max //$NON-NLS-1$
+ + " > " //$NON-NLS-1$ //$NON-NLS-2$
+ + MysqlDefs.MAX_ROWS + ".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
}
if (max == 0) {
@@ -1824,7 +2044,8 @@
*/
public void setQueryTimeout(int seconds) throws SQLException {
if (seconds < 0) {
- throw SQLError.createSQLException(Messages.getString("Statement.21"), //$NON-NLS-1$
+ throw SQLError.createSQLException(Messages
+ .getString("Statement.21"), //$NON-NLS-1$
SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
}
@@ -1850,65 +2071,14 @@
synchronized void setResultSetType(int typeFlag) {
this.resultSetType = typeFlag;
}
-
+
/**
* @return
*/
private boolean useServerFetch() throws SQLException {
- return this.connection.isCursorFetchEnabled()
- && this.fetchSize > 0
+ return this.connection.isCursorFetchEnabled() && this.fetchSize > 0
&& this.resultSetConcurrency == ResultSet.CONCUR_READ_ONLY
&& this.resultSetType == ResultSet.TYPE_FORWARD_ONLY;
}
-
- /**
- * @param sql
- * @return
- */
- private ResultSet createResultSetUsingServerFetch(String sql)
- throws SQLException {
- java.sql.PreparedStatement pStmt = this.connection.prepareStatement(
- sql, this.resultSetType, this.resultSetConcurrency);
-
- pStmt.setFetchSize(this.fetchSize);
-
- pStmt.execute();
-
- //
- // Need to be able to get resultset irrespective if we issued DML or
- // not to make this work.
- //
- ResultSet rs = ((com.mysql.jdbc.Statement) pStmt)
- .getResultSetInternal();
-
- rs
- .setStatementUsedForFetchingRows((com.mysql.jdbc.PreparedStatement) pStmt);
-
- this.results = rs;
-
- return rs;
- }
-
-
- protected synchronized ResultSet getResultSetInternal() {
- return this.results;
- }
-
- /**
- * Optimization to only use one calendar per-session, or calculate it for
- * each call, depending on user configuration
- */
- protected synchronized Calendar getCalendarInstanceForSessionOrNew() {
- if (this.connection != null) {
- return this.connection.getCalendarInstanceForSessionOrNew();
- } else {
- // punt, no connection around
- return new GregorianCalendar();
- }
- }
-
- protected void setHoldResultsOpenOverClose(boolean holdResultsOpenOverClose) {
- this.holdResultsOpenOverClose = holdResultsOpenOverClose;
- }
}
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/exceptions/MySQLTimeoutException.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/exceptions/MySQLTimeoutException.java 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/exceptions/MySQLTimeoutException.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -38,6 +38,11 @@
}
public MySQLTimeoutException() {
- super();
+ super("Statement cancelled due to timeout or client request");
}
+
+ public int getErrorCode() {
+ // TODO Auto-generated method stub
+ return super.getErrorCode();
+ }
}
Modified: branches/branch_5_0/connector-j/src/testsuite/simple/StatementsTest.java
===================================================================
--- branches/branch_5_0/connector-j/src/testsuite/simple/StatementsTest.java 2005-12-06 01:02:27 UTC (rev 4658)
+++ branches/branch_5_0/connector-j/src/testsuite/simple/StatementsTest.java 2005-12-06 23:10:38 UTC (rev 4659)
@@ -27,6 +27,7 @@
import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
import java.io.Reader;
+import java.rmi.server.UID;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -45,7 +46,8 @@
* DOCUMENT ME!
*
* @author Mark Matthews
- * @version $Id$
+ * @version $Id: StatementsTest.java 4494 2005-10-31 22:30:34 -0600 (Mon, 31 Oct
+ * 2005) mmatthews $
*/
public class StatementsTest extends BaseTestCase {
private static final int MAX_COLUMN_LENGTH = 255;
@@ -280,27 +282,27 @@
this.stmt.setFetchSize(Integer.MIN_VALUE);
this.stmt
.executeUpdate("INSERT INTO statement_test (strdata1) values ('blah')");
-
+
int autoIncKeyFromApi = -1;
this.rs = this.stmt.getGeneratedKeys();
-
+
if (this.rs.next()) {
autoIncKeyFromApi = this.rs.getInt(1);
} else {
fail("Failed to retrieve AUTO_INCREMENT using Statement.getGeneratedKeys()");
}
-
+
this.rs.close();
-
+
int autoIncKeyFromFunc = -1;
this.rs = this.stmt.executeQuery("SELECT LAST_INSERT_ID()");
-
+
if (this.rs.next()) {
autoIncKeyFromFunc = this.rs.getInt(1);
} else {
fail("Failed to retrieve AUTO_INCREMENT using LAST_INSERT_ID()");
}
-
+
if ((autoIncKeyFromApi != -1) && (autoIncKeyFromFunc != -1)) {
assertTrue(
"Key retrieved from API ("
@@ -319,7 +321,7 @@
;
}
}
-
+
this.rs = null;
}
}
@@ -522,6 +524,200 @@
}
}
+ public void testCancelStatement() throws Exception {
+
+ Connection cancelConn = null;
+
+ try {
+ cancelConn = getConnectionWithProps(null);
+ final Statement cancelStmt = cancelConn.createStatement();
+
+ cancelStmt.setQueryTimeout(10);
+
+ long begin = System.currentTimeMillis();
+
+ try {
+ cancelStmt.execute("SELECT SLEEP(30)");
+ } catch (SQLException sqlEx) {
+ assertTrue("Probably wasn't actually cancelled", System
+ .currentTimeMillis()
+ - begin < 30000);
+ }
+
+ // Make sure we can still use the connection...
+
+ this.rs = cancelStmt.executeQuery("SELECT 1");
+
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+
+ cancelStmt.setQueryTimeout(0);
+
+ new Thread() {
+
+ public void run() {
+ try {
+ try {
+ sleep(5000);
+ } catch (InterruptedException iEx) {
+ // ignore
+ }
+
+ cancelStmt.cancel();
+ } catch (SQLException sqlEx) {
+ throw new RuntimeException(sqlEx.toString());
+ }
+ }
+
+ }.start();
+
+ begin = System.currentTimeMillis();
+
+ try {
+ cancelStmt.execute("SELECT SLEEP(30)");
+ } catch (SQLException sqlEx) {
+ assertTrue("Probably wasn't actually cancelled", System
+ .currentTimeMillis()
+ - begin < 30000);
+ }
+
+ // Make sure we can still use the connection...
+
+ this.rs = cancelStmt.executeQuery("SELECT 1");
+
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+
+ final PreparedStatement cancelPstmt = cancelConn.prepareStatement("SELECT SLEEP(30)");
+
+ cancelPstmt.setQueryTimeout(10);
+
+ begin = System.currentTimeMillis();
+
+ try {
+ cancelPstmt.execute();
+ } catch (SQLException sqlEx) {
+ assertTrue("Probably wasn't actually cancelled", System
+ .currentTimeMillis()
+ - begin < 30000);
+ }
+
+ // Make sure we can still use the connection...
+
+ this.rs = cancelStmt.executeQuery("SELECT 1");
+
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+
+ cancelPstmt.setQueryTimeout(0);
+
+ new Thread() {
+
+ public void run() {
+ try {
+ try {
+ sleep(5000);
+ } catch (InterruptedException iEx) {
+ // ignore
+ }
+
+
+ cancelPstmt.cancel();
+ } catch (SQLException sqlEx) {
+ throw new RuntimeException(sqlEx.toString());
+ }
+ }
+
+ }.start();
+
+ begin = System.currentTimeMillis();
+
+ try {
+ cancelPstmt.execute();
+ } catch (SQLException sqlEx) {
+ assertTrue("Probably wasn't actually cancelled", System
+ .currentTimeMillis()
+ - begin < 30000);
+ }
+
+ // Make sure we can still use the connection...
+
+ this.rs = cancelStmt.executeQuery("SELECT 1");
+
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+
+ final PreparedStatement cancelClientPstmt = ((com.mysql.jdbc.Connection)cancelConn).clientPrepareStatement("SELECT SLEEP(30)");
+
+ cancelClientPstmt.setQueryTimeout(10);
+
+ begin = System.currentTimeMillis();
+
+ try {
+ cancelClientPstmt.execute();
+ } catch (SQLException sqlEx) {
+ assertTrue("Probably wasn't actually cancelled", System
+ .currentTimeMillis()
+ - begin < 30000);
+ }
+
+ // Make sure we can still use the connection...
+
+ this.rs = cancelStmt.executeQuery("SELECT 1");
+
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+
+ cancelClientPstmt.setQueryTimeout(0);
+
+ new Thread() {
+
+ public void run() {
+ try {
+ try {
+ sleep(5000);
+ } catch (InterruptedException iEx) {
+ // ignore
+ }
+
+
+ cancelClientPstmt.cancel();
+ } catch (SQLException sqlEx) {
+ throw new RuntimeException(sqlEx.toString());
+ }
+ }
+
+ }.start();
+
+ begin = System.currentTimeMillis();
+
+ try {
+ cancelClientPstmt.execute();
+ } catch (SQLException sqlEx) {
+ assertTrue("Probably wasn't actually cancelled", System
+ .currentTimeMillis()
+ - begin < 30000);
+ }
+
+ // Make sure we can still use the connection...
+
+ this.rs = cancelStmt.executeQuery("SELECT 1");
+
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+ } finally {
+ if (this.rs != null) {
+ ResultSet toClose = this.rs;
+ this.rs = null;
+ toClose.close();
+ }
+
+ if (cancelConn != null) {
+ cancelConn.close();
+ }
+ }
+ }
+
/**
* DOCUMENT ME!
*
@@ -688,24 +884,24 @@
if (!isRunningOnJdk131()) {
int insertIdFromGeneratedKeys = Integer.MIN_VALUE;
-
+
this.stmt
.executeUpdate("INSERT INTO statement_test (strdata1, strdata2) values ('a', 'a'), ('b', 'b'), ('c', 'c')");
this.rs = this.stmt.getGeneratedKeys();
-
+
if (this.rs.next()) {
insertIdFromGeneratedKeys = this.rs.getInt(1);
}
-
+
this.rs.close();
this.rs = this.stmt.executeQuery("SELECT LAST_INSERT_ID()");
-
+
int insertIdFromServer = Integer.MIN_VALUE;
-
+
if (this.rs.next()) {
insertIdFromServer = this.rs.getInt(1);
}
-
+
assertEquals(insertIdFromGeneratedKeys, insertIdFromServer);
}
} finally {
@@ -971,6 +1167,64 @@
}
}
+ /**
+ * Tests for PreparedStatement.setObject()
+ *
+ * @throws Exception
+ */
+ public void testSetObject() throws Exception {
+ Properties props = new Properties();
+ props.put("noDatetimeStringSync", "true"); // value=true for #5
+ Connection conn1 = getConnectionWithProps(props);
+ Statement stmt1 = conn1.createStatement();
+ stmt1.executeUpdate("DROP TABLE IF EXISTS t1");
+ stmt1.executeUpdate("CREATE TABLE t1 (" + "c1 DECIMAL," // instance of
+ // String
+ + "c2 VARCHAR(255)," // instance of String
+ + "c3 BLOB," // instance of byte[]
+ + "c4 DATE," // instance of java.util.Date
+ + "c5 TIMESTAMP," // instance of String
+ + "c6 TIME," // instance of String
+ + "c7 TIME)"); // instance of java.sql.Timestamp
+
+ this.pstmt = conn1
+ .prepareStatement("INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?, ?)");
+
+ long currentTime = System.currentTimeMillis();
+
+ this.pstmt.setObject(1, "1000", Types.DECIMAL);
+ this.pstmt.setObject(2, "2000", Types.VARCHAR);
+ this.pstmt.setObject(3, new byte[] { 0 }, Types.BLOB);
+ this.pstmt.setObject(4, new java.util.Date(currentTime), Types.DATE);
+ this.pstmt.setObject(5, "2000-01-01 23-59-59", Types.TIMESTAMP);
+ this.pstmt.setObject(6, "11:22:33", Types.TIME);
+ this.pstmt
+ .setObject(7, new java.sql.Timestamp(currentTime), Types.TIME);
+ this.pstmt.execute();
+ this.rs = stmt1.executeQuery("SELECT * FROM t1");
+ this.rs.next();
+
+ assertEquals("1000", this.rs.getString(1));
+ assertEquals("2000", this.rs.getString(2));
+ assertEquals(1, ((byte[]) this.rs.getObject(3)).length);
+ assertEquals(0, ((byte[]) this.rs.getObject(3))[0]);
+ assertEquals(new java.sql.Date(currentTime).toString(), this.rs
+ .getDate(4).toString());
+
+ if (versionMeetsMinimum(4, 1)) {
+ assertEquals("2000-01-01 23:59:59", this.rs.getString(5));
+ } else {
+ assertEquals("20000101235959", this.rs.getString(5));
+ }
+
+ assertEquals("11:22:33", this.rs.getString(6));
+ assertEquals(new java.sql.Time(currentTime).toString(), this.rs
+ .getString(7));
+ }
+
+ // Server-side prepared statements can only reset streamed data
+ // in-toto, not piecemiel.
+
public void testStreamChange() throws Exception {
createTable("testStreamChange",
"(field1 varchar(32), field2 int, field3 TEXT, field4 BLOB)");
@@ -1039,9 +1293,6 @@
}
}
- // Server-side prepared statements can only reset streamed data
- // in-toto, not piecemiel.
-
public void testTruncationOnRead() throws Exception {
this.rs = this.stmt.executeQuery("SELECT '" + Long.MAX_VALUE + "'");
this.rs.next();
@@ -1166,55 +1417,4 @@
}
}
-
- /**
- * Tests for PreparedStatement.setObject()
- *
- * @throws Exception
- */
- public void testSetObject() throws Exception {
- Properties props = new Properties();
- props.put("noDatetimeStringSync", "true"); // value=true for #5
- Connection conn1 = getConnectionWithProps(props);
- Statement stmt1 = conn1.createStatement();
- stmt1.executeUpdate("DROP TABLE IF EXISTS t1");
- stmt1.executeUpdate("CREATE TABLE t1 ("
- + "c1 DECIMAL," // instance of String
- + "c2 VARCHAR(255)," // instance of String
- + "c3 BLOB," // instance of byte[]
- + "c4 DATE," // instance of java.util.Date
- + "c5 TIMESTAMP," // instance of String
- + "c6 TIME," // instance of String
- + "c7 TIME)"); // instance of java.sql.Timestamp
-
- this.pstmt = conn1.prepareStatement("INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?, ?)");
-
- long currentTime = System.currentTimeMillis();
-
- this.pstmt.setObject(1, "1000", Types.DECIMAL);
- this.pstmt.setObject(2, "2000", Types.VARCHAR);
- this.pstmt.setObject(3, new byte[]{0}, Types.BLOB);
- this.pstmt.setObject(4, new java.util.Date(currentTime), Types.DATE);
- this.pstmt.setObject(5, "2000-01-01 23-59-59", Types.TIMESTAMP);
- this.pstmt.setObject(6, "11:22:33", Types.TIME);
- this.pstmt.setObject(7, new java.sql.Timestamp(currentTime), Types.TIME);
- this.pstmt.execute();
- this.rs = stmt1.executeQuery("SELECT * FROM t1");
- this.rs.next();
-
- assertEquals("1000", this.rs.getString(1));
- assertEquals("2000", this.rs.getString(2));
- assertEquals(1, ((byte[]) this.rs.getObject(3)).length);
- assertEquals(0, ((byte[]) this.rs.getObject(3))[0]);
- assertEquals(new java.sql.Date(currentTime).toString(), this.rs.getDate(4).toString());
-
- if (versionMeetsMinimum(4, 1)) {
- assertEquals("2000-01-01 23:59:59", this.rs.getString(5));
- } else {
- assertEquals("20000101235959", this.rs.getString(5));
- }
-
- assertEquals("11:22:33", this.rs.getString(6));
- assertEquals(new java.sql.Time(currentTime).toString(), this.rs.getString(7));
- }
}
| Thread |
|---|
| • Connector/J commit: r4659 - in branches/branch_5_0/connector-j: . src/com/mysql/jdbc src/com/mysql/jdbc/exceptions src/testsuite/simple | mmatthews | 7 Dec |