List:Commits« Previous MessageNext Message »
From:mmatthews Date:April 4 2006 9:47pm
Subject:Connector/J commit: r5135 - in branches/branch_5_0/connector-j: . src/com/mysql/jdbc
View as plain text  
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/PreparedStatement.java
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.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
Log:
    - Removed work done for BUG#14652, and instead loosened synchronization
      to solve a number of deadlock issues in BUG#18719, BUG#18367, BUG#17709
      and BUG#15067. New strategy basically makes Connection instances threadsafe
      and thus shareable across threads, and anything else threadsafe, but not 
      necessarily shareable across threads due to JDBC API interactions that 
      can cause non-obvious behavior and/or deadlock scenarios to occur since
      the API is not designed to be used from multiple threads at once. 
      
      Therefore, unless external synchronization is provided, clients should
      not allow multiple threads to share a given statement or result set. Examples
      of issues with the API itself not being multi-thread suitable include, 
      but are not limited to race conditions between modifiers and execution and 
      retrieval methods on statements and result sets that are not synchronizable 
      such as ResultSet.get*() and traversal methods, or Statement.execute*() closing 
      result sets without effectively making the driver itself serializable across the 
      board.
      
      These changes should not have any effect on "normal" J(2)EE use cases
      where only one thread ever uses a connection instance and the objects created by
      it.
      
    - Use a java.util.Timer to schedule cancellation of queries via
      Statement.setQueryTimeout() rather than one thread per potential cancellation.
      
      A new thread will be used to actually cancel a running query, as there's potential
      for a cancel request to block other cancel requests if all run from the
      same thread.

Modified: branches/branch_5_0/connector-j/CHANGES
===================================================================
--- branches/branch_5_0/connector-j/CHANGES	2006-04-04 19:47:49 UTC (rev 5134)
+++ branches/branch_5_0/connector-j/CHANGES	2006-04-04 21:47:37 UTC (rev 5135)
@@ -100,7 +100,35 @@
       temporary tables.
       
     - Removed redundant code in com.mysql.jdbc.MysqlIO.
+    
+    - Removed work done for BUG#14652, and instead loosened synchronization
+      to solve a number of deadlock issues in BUG#18719, BUG#18367, BUG#17709
+      and BUG#15067. New strategy basically makes Connection instances threadsafe
+      and thus shareable across threads, and anything else threadsafe, but not 
+      necessarily shareable across threads due to JDBC API interactions that 
+      can cause non-obvious behavior and/or deadlock scenarios to occur since
+      the API is not designed to be used from multiple threads at once. 
       
+      Therefore, unless external synchronization is provided, clients should
+      not allow multiple threads to share a given statement or result set. Examples
+      of issues with the API itself not being multi-thread suitable include, 
+      but are not limited to race conditions between modifiers and execution and 
+      retrieval methods on statements and result sets that are not synchronizable 
+      such as ResultSet.get*() and traversal methods, or Statement.execute*() closing 
+      result sets without effectively making the driver itself serializable across the 
+      board.
+      
+      These changes should not have any effect on "normal" J(2)EE use cases
+      where only one thread ever uses a connection instance and the objects created by
+      it.
+      
+    - Use a java.util.Timer to schedule cancellation of queries via
+      Statement.setQueryTimeout() rather than one thread per potential cancellation.
+      
+      A new thread will be used to actually cancel a running query, as there's potential
+      for a cancel request to block other cancel requests if all run from the
+      same thread.
+      
 xx-xx-06 - Version 3.1.13
 
     - Fixed BUG#15464 - INOUT parameter does not store IN value.

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	2006-04-04 19:47:49 UTC (rev 5134)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java	2006-04-04 21:47:37 UTC (rev 5135)
@@ -65,6 +65,7 @@
 import java.util.Stack;
 import java.util.StringTokenizer;
 import java.util.TimeZone;
+import java.util.Timer;
 import java.util.TreeMap;
 
 /**
@@ -1052,6 +1053,8 @@
 
 	private static final Map serverConfigByUrl = new HashMap();
 
+	private static Timer cancelTimer;
+
 	static {
 		mapTransIsolationNameToValue = new HashMap(8);
 		mapTransIsolationNameToValue.put("READ-UNCOMMITED", new Integer(
@@ -1119,6 +1122,10 @@
 		return sqlExceptionWithNewMessage;
 	}
 
+	protected static Timer getCancelTimer() {
+		return cancelTimer;
+	}
+
 	private static synchronized int getNextRoundRobinHostIndex(String url,
 			List hostList) {
 		if (roundRobinStatsMap == null) {
@@ -1143,6 +1150,18 @@
 		return index[0];
 	}
 
+	private static boolean nullSafeCompare(String s1, String s2) {
+		if (s1 == null && s2 == null) {
+			return true;
+		}
+
+		if (s1 == null && s2 != null) {
+			return false;
+		}
+
+		return s1.equals(s2);
+	}
+
 	/** Are we in autoCommit mode? */
 	private boolean autoCommit = true;
 
@@ -1225,18 +1244,18 @@
 
 	/** The I/O abstraction interface (network conn to MySQL server */
 	private MysqlIO io = null;
-
+	
 	private boolean isClientTzUTC = false;
-
+	
 	/** Has this connection been closed? */
 	private boolean isClosed = true;
 
 	/** Is this connection associated with a global tx? */
 	private boolean isInGlobalTx = false;
-	
+
 	/** Is this connection running inside a JDK-1.3 VM? */
 	private boolean isRunningOnJDK13 = false;
-	
+
 	/** isolation level */
 	private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
 
@@ -1376,17 +1395,19 @@
 	 * disabled by user)
 	 */
 	private boolean useServerPreparedStmts = false;
-
+	
 	private LRUCache serverSideStatementCheckCache;
 
 	private LRUCache serverSideStatementCache;
-
 	private Calendar sessionCalendar;
+	private Calendar utcCalendar;
 	
-	private Calendar utcCalendar;
-
 	private String origHostToConnectTo;
+	
 	private int origPortToConnectTo;
+
+	// we don't want to be able to publicly clone this...
+	
 	private String origDatabaseToConnectTo;
 	
 	/**
@@ -1411,7 +1432,7 @@
 			String databaseToConnectTo, String url)
 			throws SQLException {
 		this.charsetToNumBytesMap = new HashMap();
-
+		this.cancelTimer = new Timer(true);
 		this.connectionCreationTimeMillis = System.currentTimeMillis();
 		this.pointOfOrigin = new Throwable();
 		
@@ -1547,16 +1568,6 @@
 		}
 	}
 
-	// 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);
-	}
-	
 	private void addToHistogram(int[] histogramCounts,
 			long[] histogramBreakpoints, long value, int numberOfTimes,
 			long currentLowerBound, long currentUpperBound) {
@@ -1694,7 +1705,7 @@
 			this.indexToCharsetMapping = CharsetMapping.INDEX_TO_CHARSET;
 		}
 	}
-
+	
 	private boolean canHandleAsServerPreparedStatement(String sql) 
 		throws SQLException {
 		if (sql == null || sql.length() == 0) {
@@ -1722,7 +1733,7 @@
 		
 		return canHandleAsServerPreparedStatementNoCache(sql);
 	}
-	
+
 	private boolean canHandleAsServerPreparedStatementNoCache(String sql) 
 		throws SQLException {
 		boolean canHandleAsStatement = true;
@@ -2178,6 +2189,20 @@
 		}
 	}
 
+	private void closeStatement(java.sql.Statement stmt) {
+		if (stmt != null) {
+			try {
+				stmt.close();
+			} catch (SQLException sqlEx) {
+				; // ignore
+			}
+
+			stmt = null;
+		}
+	}
+
+	// --------------------------JDBC 2.0-----------------------------
+
 	/**
 	 * The method commit() makes all changes made since the previous
 	 * commit/rollback permanent and releases any database locks currently held
@@ -2263,8 +2288,6 @@
 		}
 	}
 
-	// --------------------------JDBC 2.0-----------------------------
-
 	/**
 	 * Sets up client character set for MySQL-4.1 and newer if the user This
 	 * must be done before any further communication with the server!
@@ -2860,6 +2883,39 @@
 		}
 	}
 
+	private void createPreparedStatementCaches() {
+		int cacheSize = getPreparedStatementCacheSize();
+		
+		this.cachedPreparedStatementParams = new HashMap(cacheSize);
+		
+		this.serverSideStatementCheckCache = new LRUCache(cacheSize);
+		
+		this.serverSideStatementCache = new LRUCache(cacheSize) {
+			protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
+				if (this.maxElements <= 1) {
+					return false;
+				}
+				
+				boolean removeIt = super.removeEldestEntry(eldest);
+				
+				if (removeIt) {
+					ServerPreparedStatement ps = 
+						(ServerPreparedStatement)eldest.getValue();
+					ps.isCached = false;
+					ps.setClosed(false);
+					
+					try {
+						ps.close();
+					} catch (SQLException sqlEx) {
+						// punt
+					}
+				}
+				
+				return removeIt;
+			}
+		};
+	}
+
 	/**
 	 * SQL statements without parameters are normally executed using Statement
 	 * objects. If the same SQL statement is executed many times, it is more
@@ -2918,6 +2974,14 @@
 		System.err.println(query);
 	}
 
+	protected Connection duplicate() throws SQLException {
+		return new Connection(	this.origHostToConnectTo, 
+				this.origPortToConnectTo,
+				this.props,
+				this.origDatabaseToConnectTo,
+				this.myURL);
+	}
+
 	/**
 	 * Send a query to the server. Returns one of the ResultSet objects. This is
 	 * synchronized, so Statement's queries will be serialized.
@@ -3198,6 +3262,18 @@
 	}
 
 	/**
+	 * Optimization to only use one calendar per-session, or calculate it for
+	 * each call, depending on user configuration
+	 */
+	protected Calendar getCalendarInstanceForSessionOrNew() {
+		if (getDynamicCalendars()) {
+			return Calendar.getInstance();
+		}
+
+		return getSessionLockedCalendar();
+	}
+
+	/**
 	 * Return the connections current catalog name, or null if no catalog name
 	 * is set, or we dont support catalogs.
 	 * <p>
@@ -3548,6 +3624,12 @@
 		return this.io.getServerVersion();
 	}
 
+	protected Calendar getSessionLockedCalendar() {
+	
+		return this.sessionCalendar;
+	}
+	
+	
 	/**
 	 * Get this Connection's current transaction isolation mode.
 	 * 
@@ -3650,6 +3732,10 @@
 		return this.user;
 	}
 
+	protected Calendar getUtcCalendar() {
+		return this.utcCalendar;
+	}
+
 	/**
 	 * The first warning reported by calls on this Connection is returned.
 	 * <B>Note:</B> Sebsequent warnings will be changed to this
@@ -3666,8 +3752,7 @@
 	public boolean hasSameProperties(Connection c) {
 		return this.props.equals(c.props);
 	}
-	
-	
+
 	protected void incrementNumberOfPreparedExecutes() {
 		if (getGatherPerformanceMetrics()) {
 			this.numberOfPreparedExecutes++;
@@ -3678,7 +3763,7 @@
 			this.numberOfQueriesIssued++;
 		}
 	}
-
+	
 	protected void incrementNumberOfPrepares() {
 		if (getGatherPerformanceMetrics()) {
 			this.numberOfPrepares++;
@@ -3727,39 +3812,6 @@
 		}
 	}
 
-	private void createPreparedStatementCaches() {
-		int cacheSize = getPreparedStatementCacheSize();
-		
-		this.cachedPreparedStatementParams = new HashMap(cacheSize);
-		
-		this.serverSideStatementCheckCache = new LRUCache(cacheSize);
-		
-		this.serverSideStatementCache = new LRUCache(cacheSize) {
-			protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
-				if (this.maxElements <= 1) {
-					return false;
-				}
-				
-				boolean removeIt = super.removeEldestEntry(eldest);
-				
-				if (removeIt) {
-					ServerPreparedStatement ps = 
-						(ServerPreparedStatement)eldest.getValue();
-					ps.isCached = false;
-					ps.setClosed(false);
-					
-					try {
-						ps.close();
-					} catch (SQLException sqlEx) {
-						// punt
-					}
-				}
-				
-				return removeIt;
-			}
-		};
-	}
-
 	/**
 	 * Sets varying properties that depend on server information. Called once we
 	 * have connected to the server.
@@ -4012,7 +4064,15 @@
 	public boolean isClosed() {
 		return this.isClosed;
 	}
-	
+
+	protected boolean isCursorFetchEnabled() throws SQLException {
+		return (versionMeetsMinimum(5, 0, 2) && getUseCursorFetch());
+	}
+
+	public boolean isInGlobalTx() {
+		return this.isInGlobalTx;
+	}
+
 	/**
 	 * Is this connection connected to the first host in the list if
 	 * there is a list of servers in the URL?
@@ -4051,6 +4111,57 @@
 		return this.readOnly;
 	}
 
+	protected boolean isRunningOnJDK13() {
+		return this.isRunningOnJDK13;
+	}
+
+	public synchronized boolean isSameResource(Connection otherConnection) {
+		if (otherConnection == null) {
+			return false;
+		}
+		
+		boolean directCompare = true;
+		
+		String otherHost = otherConnection.origHostToConnectTo;
+		String otherOrigDatabase = otherConnection.origDatabaseToConnectTo;
+		String otherCurrentCatalog = otherConnection.database;
+		
+		if (!nullSafeCompare(otherHost, this.origHostToConnectTo)) {
+			directCompare = false;
+		} else if (otherHost != null & otherHost.indexOf(",") == -1 && 
+				otherHost.indexOf(":") == -1) {
+			// need to check port numbers
+			directCompare = (otherConnection.origPortToConnectTo == 
+				this.origPortToConnectTo);
+		}
+		
+		if (directCompare) {
+			if (!nullSafeCompare(otherOrigDatabase, this.origDatabaseToConnectTo)) {			directCompare = false;
+				directCompare = false;
+			} else if (!nullSafeCompare(otherCurrentCatalog, this.database)) {
+				directCompare = false;
+			}
+		}
+
+		if (directCompare) {
+			return true;
+		}
+		
+		// Has the user explicitly set a resourceId?
+		String otherResourceId = otherConnection.getResourceId();
+		String myResourceId = getResourceId();
+		
+		if (otherResourceId != null || myResourceId != null) {
+			directCompare = nullSafeCompare(otherResourceId, myResourceId);
+			
+			if (directCompare) {
+				return true;
+			}
+		}
+		
+		return false;	
+	}
+
 	protected boolean isServerTzUTC() {
 		return this.isServerTzUTC;
 	}
@@ -4575,6 +4686,12 @@
 
 	}
 
+	protected void recachePreparedStatement(ServerPreparedStatement pstmt) {
+		synchronized (this.serverSideStatementCache) {
+			this.serverSideStatementCache.put(pstmt.originalSql, pstmt);
+		}
+	}
+
 	/**
 	 * DOCUMENT ME!
 	 * 
@@ -5142,6 +5259,10 @@
 		// do nothing
 	}
 
+	public void setInGlobalTx(boolean flag) {
+		this.isInGlobalTx = flag;
+	}
+
 	// exposed for testing
 	/**
 	 * @param preferSlaveDuringFailover
@@ -5207,18 +5328,6 @@
 		}
 	}
 
-	private void closeStatement(java.sql.Statement stmt) {
-		if (stmt != null) {
-			try {
-				stmt.close();
-			} catch (SQLException sqlEx) {
-				; // ignore
-			}
-
-			stmt = null;
-		}
-	}
-
 	/**
 	 * @see Connection#setSavepoint(String)
 	 */
@@ -5336,7 +5445,7 @@
 					SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
 		}
 	}
-
+	
 	/**
 	 * JDBC 2.0 Install a type-map object as the default type-map for this
 	 * connection
@@ -5349,7 +5458,7 @@
 	public synchronized void setTypeMap(java.util.Map map) throws SQLException {
 		this.typeMap = map;
 	}
-
+	
 	/**
 	 * Should we try to connect back to the master? We try when we've been
 	 * failed over >= this.secondsBeforeRetryMaster _or_ we've issued >
@@ -5365,7 +5474,7 @@
 
 		return tryFallback;
 	}
-
+	
 	/**
 	 * Used by MiniAdmin to shutdown a MySQL server
 	 * 
@@ -5380,7 +5489,7 @@
 					+ "'", SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 	}
-
+	
 	/**
 	 * DOCUMENT ME!
 	 * 
@@ -5389,7 +5498,7 @@
 	public boolean supportsIsolationLevel() {
 		return this.hasIsolationLevels;
 	}
-
+	
 	/**
 	 * DOCUMENT ME!
 	 * 
@@ -5398,7 +5507,7 @@
 	public boolean supportsQuotedIdentifiers() {
 		return this.hasQuotedIdentifiers;
 	}
-
+	
 	/**
 	 * DOCUMENT ME!
 	 * 
@@ -5407,7 +5516,7 @@
 	public boolean supportsTransactions() {
 		return this.transactionsSupported;
 	}
-
+	
 	/**
 	 * Remove the given statement from the list of open statements
 	 * 
@@ -5449,7 +5558,7 @@
 			}
 		}
 	}
-
+	
 	boolean useAnsiQuotedIdentifiers() {
 		return this.useAnsiQuotes;
 	}
@@ -5465,112 +5574,10 @@
 		}
 	}
 
-	protected void recachePreparedStatement(ServerPreparedStatement pstmt) {
-		synchronized (this.serverSideStatementCache) {
-			this.serverSideStatementCache.put(pstmt.originalSql, pstmt);
-		}
-	}
-	
 	public boolean versionMeetsMinimum(int major, int minor, int subminor)
 			throws SQLException {
 		checkClosed();
 
 		return this.io.versionMeetsMinimum(major, minor, subminor);
 	}
-	
-	public synchronized boolean isSameResource(Connection otherConnection) {
-		if (otherConnection == null) {
-			return false;
-		}
-		
-		boolean directCompare = true;
-		
-		String otherHost = otherConnection.origHostToConnectTo;
-		String otherOrigDatabase = otherConnection.origDatabaseToConnectTo;
-		String otherCurrentCatalog = otherConnection.database;
-		
-		if (!nullSafeCompare(otherHost, this.origHostToConnectTo)) {
-			directCompare = false;
-		} else if (otherHost != null & otherHost.indexOf(",") == -1 && 
-				otherHost.indexOf(":") == -1) {
-			// need to check port numbers
-			directCompare = (otherConnection.origPortToConnectTo == 
-				this.origPortToConnectTo);
-		}
-		
-		if (directCompare) {
-			if (!nullSafeCompare(otherOrigDatabase, this.origDatabaseToConnectTo)) {			directCompare = false;
-				directCompare = false;
-			} else if (!nullSafeCompare(otherCurrentCatalog, this.database)) {
-				directCompare = false;
-			}
-		}
-
-		if (directCompare) {
-			return true;
-		}
-		
-		// Has the user explicitly set a resourceId?
-		String otherResourceId = otherConnection.getResourceId();
-		String myResourceId = getResourceId();
-		
-		if (otherResourceId != null || myResourceId != null) {
-			directCompare = nullSafeCompare(otherResourceId, myResourceId);
-			
-			if (directCompare) {
-				return true;
-			}
-		}
-		
-		return false;	
-	}
-	
-	private static boolean nullSafeCompare(String s1, String s2) {
-		if (s1 == null && s2 == null) {
-			return true;
-		}
-
-		if (s1 == null && s2 != null) {
-			return false;
-		}
-
-		return s1.equals(s2);
-	}
-	
-	protected boolean isCursorFetchEnabled() throws SQLException {
-		return (versionMeetsMinimum(5, 0, 2) && getUseCursorFetch());
-	}
-	
-	/**
-	 * Optimization to only use one calendar per-session, or calculate it for
-	 * each call, depending on user configuration
-	 */
-	protected Calendar getCalendarInstanceForSessionOrNew() {
-		if (getDynamicCalendars()) {
-			return Calendar.getInstance();
-		}
-
-		return getSessionLockedCalendar();
-	}
-	
-	protected Calendar getSessionLockedCalendar() {
-	
-		return this.sessionCalendar;
-	}
-	
-	protected Calendar getUtcCalendar() {
-		return this.utcCalendar;
-	}
-
-	protected boolean isRunningOnJDK13() {
-		return this.isRunningOnJDK13;
-	}
-	
-	public boolean isInGlobalTx() {
-		return this.isInGlobalTx;
-	}
-
-	public void setInGlobalTx(boolean flag) {
-		this.isInGlobalTx = flag;
-	}
 }

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	2006-04-04 19:47:49 UTC (rev 5134)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java	2006-04-04 21:47:37 UTC (rev 5135)
@@ -50,7 +50,7 @@
 import java.util.Locale;
 import java.util.TimeZone;
 
-import com.mysql.jdbc.Statement.CancelThread;
+import com.mysql.jdbc.Statement.CancelTask;
 import com.mysql.jdbc.exceptions.MySQLTimeoutException;
 import com.mysql.jdbc.profiler.ProfilerEvent;
 
@@ -1124,27 +1124,33 @@
 
 		ResultSet rs;
 		
-		CancelThread timeoutThread = null;
+		CancelTask timeoutTask = null;
 
 		try {
 			if (this.timeout != 0
 					&& this.connection.versionMeetsMinimum(5, 0, 0)) {
-				timeoutThread = new CancelThread(this.timeout);
-				new Thread(timeoutThread).start();
+				timeoutTask = new CancelTask();
+				this.connection.getCancelTimer().schedule(timeoutTask, 
+						this.timeout);
 			}
 			
 			rs = this.connection.execSQL(this, null, maxRowsToRetrieve, sendPacket,
 				this.resultSetType, this.resultSetConcurrency,
 				createStreamingResultSet, this.currentCatalog,
 				unpackFields, isBatch);
+			
+			if (timeoutTask != null) {
+				timeoutTask.cancel();
+				timeoutTask = null;
+			}
 		
 			if (this.wasCancelled) {
 				this.wasCancelled = false;
 				throw new MySQLTimeoutException();
 			}
 		} finally {
-			if (timeoutThread != null) {
-				timeoutThread.dontCancel();
+			if (timeoutTask != null) {
+				timeoutTask.cancel();
 			}
 		}
 

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java	2006-04-04 19:47:49 UTC (rev 5134)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java	2006-04-04 21:47:37 UTC (rev 5135)
@@ -3800,7 +3800,7 @@
 	 *                if a database access error occurs
 	 */
 	protected int getNativeInt(int columnIndex) throws SQLException {
-		return getNativeInt(columnIndex, false);
+		return getNativeInt(columnIndex, true);
 	}
 	
 	protected int getNativeInt(int columnIndex, boolean overflowCheck) throws SQLException {
@@ -3927,7 +3927,7 @@
 	 *                if a database access error occurs
 	 */
 	protected long getNativeLong(int columnIndex) throws SQLException {
-		return getNativeLong(columnIndex, false, true);
+		return getNativeLong(columnIndex, true, true);
 	}
 	
 	protected long getNativeLong(int columnIndex, boolean overflowCheck, 
@@ -3959,13 +3959,13 @@
 				return getNativeShort(columnIndex + 1);
 			}
 
-			return getNativeInt(columnIndex + 1);
+			return getNativeInt(columnIndex + 1, false);
 		case MysqlDefs.FIELD_TYPE_YEAR:
 
 			return getNativeShort(columnIndex + 1);
 		case MysqlDefs.FIELD_TYPE_INT24:
 		case MysqlDefs.FIELD_TYPE_LONG:
-			int asInt = getNativeInt(columnIndex + 1);
+			int asInt = getNativeInt(columnIndex + 1, false);
 			
 			if (!f.isUnsigned() || asInt >= 0) {
 				return asInt;

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	2006-04-04 19:47:49 UTC (rev 5134)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java	2006-04-04 21:47:37 UTC (rev 5135)
@@ -24,7 +24,7 @@
  */
 package com.mysql.jdbc;
 
-import com.mysql.jdbc.Statement.CancelThread;
+import com.mysql.jdbc.Statement.CancelTask;
 import com.mysql.jdbc.exceptions.MySQLTimeoutException;
 import com.mysql.jdbc.profiler.ProfileEventSink;
 import com.mysql.jdbc.profiler.ProfilerEvent;
@@ -1147,22 +1147,22 @@
 
 			this.wasCancelled = false;
 			
-			CancelThread timeoutThread = null;
+			CancelTask timeoutTask = null;
 
 			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();
+						&& this.connection.versionMeetsMinimum(5, 0, 0)) {
+					timeoutTask = new CancelTask();
+					this.connection.getCancelTimer().schedule(timeoutTask, 
+							this.timeout);
 				}
 				
 				Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE,
 					null, packet, false, null);
 				
-				if (timeoutThread != null) {
-					timeoutThread.dontCancel();
-					timeoutThread = null;
+				if (timeoutTask != null) {
+					timeoutTask.cancel();
+					timeoutTask = null;
 				}
 				
 				if (this.wasCancelled) {
@@ -1243,8 +1243,8 @@
 				
 				return rs;
 			} finally {
-				if (timeoutThread != null) {
-					timeoutThread.dontCancel();
+				if (timeoutTask != null) {
+					timeoutTask.cancel();
 				}
 			}
 		}

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	2006-04-04 19:47:49 UTC (rev 5134)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Statement.java	2006-04-04 21:47:37 UTC (rev 5135)
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.TimerTask;
 
 /**
  * A Statement object is used for executing a static SQL statement and obtaining
@@ -81,59 +82,50 @@
 	 * 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 {
+	class CancelTask extends TimerTask {
 
-		boolean shouldCancel = true;
-
-		long waitForMillis = 0;
-
 		long connectionId = 0;
 
-		CancelThread(long timeoutMillis) throws SQLException {
-			waitForMillis = timeoutMillis;
+		CancelTask() throws SQLException {
 			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;
+			Thread cancelThread = new Thread() {
 
-				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());
+				public void run() {
+					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());
+						if (cancelConn != null) {
+							try {
+								cancelConn.close();
+							} catch (SQLException sqlEx) {
+								throw new RuntimeException(sqlEx.toString());
+							}
 						}
 					}
 				}
-			}
+			};
+
+			cancelThread.start();
 		}
 	}
 
@@ -615,13 +607,14 @@
 			if (useServerFetch()) {
 				rs = createResultSetUsingServerFetch(sql);
 			} else {
-				CancelThread timeoutThread = null;
+				CancelTask timeoutTask = null;
 
 				try {
 					if (this.timeout != 0
 							&& this.connection.versionMeetsMinimum(5, 0, 0)) {
-						timeoutThread = new CancelThread(this.timeout);
-						new Thread(timeoutThread).start();
+						timeoutTask = new CancelTask();
+						this.connection.getCancelTimer().schedule(timeoutTask, 
+								this.timeout);
 					}
 
 					String oldCatalog = null;
@@ -695,6 +688,11 @@
 								this.currentCatalog, (cachedMetaData == null));
 					}
 
+					if (timeoutTask != null) {
+						timeoutTask.cancel();
+						timeoutTask = null;
+					}
+					
 					if (oldCatalog != null) {
 						this.connection.setCatalog(oldCatalog);
 					}
@@ -704,8 +702,8 @@
 						throw new MySQLTimeoutException();
 					}
 				} finally {
-					if (timeoutThread != null) {
-						timeoutThread.dontCancel();
+					if (timeoutTask != null) {
+						timeoutTask.cancel();
 					}
 				}
 			}
@@ -1074,13 +1072,14 @@
 				return this.results;
 			}
 
-			CancelThread timeoutThread = null;
+			CancelTask timeoutTask = null;
 
 			try {
 				if (this.timeout != 0
 						&& this.connection.versionMeetsMinimum(5, 0, 0)) {
-					timeoutThread = new CancelThread(this.timeout);
-					new Thread(timeoutThread).start();
+					timeoutTask = new CancelTask();
+					this.connection.getCancelTimer().schedule(timeoutTask, 
+							this.timeout);
 				}
 
 				String oldCatalog = null;
@@ -1147,6 +1146,11 @@
 							this.currentCatalog, (cachedMetaData == null));
 				}
 
+				if (timeoutTask != null) {
+					timeoutTask.cancel();
+					timeoutTask = null;
+				}
+				
 				if (oldCatalog != null) {
 					this.connection.setCatalog(oldCatalog);
 				}
@@ -1157,8 +1161,8 @@
 					throw new MySQLTimeoutException();
 				}
 			} finally {
-				if (timeoutThread != null) {
-					timeoutThread.dontCancel();
+				if (timeoutTask != null) {
+					timeoutTask.cancel();
 				}
 			}
 
@@ -1252,13 +1256,14 @@
 			// must happen in sequence, so synchronize
 			// on the same mutex that _conn is using
 		
-			CancelThread timeoutThread = null;
+			CancelTask timeoutTask = null;
 
 			try {
 				if (this.timeout != 0
 						&& this.connection.versionMeetsMinimum(5, 0, 0)) {
-					timeoutThread = new CancelThread(this.timeout);
-					new Thread(timeoutThread).start();
+					timeoutTask = new CancelTask();
+					this.connection.getCancelTimer().schedule(timeoutTask, 
+							this.timeout);
 				}
 
 				String oldCatalog = null;
@@ -1286,6 +1291,11 @@
 						this.currentCatalog,
 						true /* force read of field info on DML */,
 						isBatch);
+				
+				if (timeoutTask != null) {
+					timeoutTask.cancel();
+					timeoutTask = null;
+				}
 
 				if (oldCatalog != null) {
 					this.connection.setCatalog(oldCatalog);
@@ -1296,8 +1306,8 @@
 					throw new MySQLTimeoutException();
 				}
 			} finally {
-				if (timeoutThread != null) {
-					timeoutThread.dontCancel();
+				if (timeoutTask != null) {
+					timeoutTask.cancel();
 				}
 			}
 		}

Thread
Connector/J commit: r5135 - in branches/branch_5_0/connector-j: . src/com/mysql/jdbcmmatthews4 Apr