List:Commits« Previous MessageNext Message »
From:mmatthews Date:September 26 2007 12:02pm
Subject:Connector/J commit: r6593 - in trunk: . connector-j connector-j/src/com/mysql/jdbc connector-j/src/com/mysql/jdbc/interceptors
View as plain text  
Added:
   trunk/connector-j/src/com/mysql/jdbc/ConnectionLifecycleInterceptor.java
   trunk/connector-j/src/com/mysql/jdbc/Extension.java
   trunk/connector-j/src/com/mysql/jdbc/IterateBlock.java
   trunk/connector-j/src/com/mysql/jdbc/interceptors/SessionAssociationInterceptor.java
Modified:
   trunk/
   trunk/connector-j/CHANGES
   trunk/connector-j/src/com/mysql/jdbc/CharsetMapping.java
   trunk/connector-j/src/com/mysql/jdbc/Connection.java
   trunk/connector-j/src/com/mysql/jdbc/ConnectionImpl.java
   trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
   trunk/connector-j/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
   trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
   trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties
   trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java
   trunk/connector-j/src/com/mysql/jdbc/ResultSetImpl.java
   trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java
   trunk/connector-j/src/com/mysql/jdbc/StatementInterceptor.java
   trunk/connector-j/src/com/mysql/jdbc/Util.java
   trunk/connector-j/src/com/mysql/jdbc/interceptors/ResultSetScannerInterceptor.java
   trunk/connector-j/src/com/mysql/jdbc/interceptors/ServerStatusDiffInterceptor.java
Log:
Merged revisions 6587-6592 via svnmerge from 
svn+ssh://mmatthews@stripped/connectors-svnroot/connector-j/branches/branch_5_1

.......
  r6587 | mmatthews | 2007-09-15 15:58:27 -0500 (Sat, 15 Sep 2007) | 6 lines
  
   Added "autoSlowLog" configuration property, overrides 
  
        "slowQueryThreshold*" properties, driver determines slow
  
        queries by those that are slower than 5 * stddev of the mean
  
        query time (outside the 96% percentile).
  
  
  
  Externalized some utf-8 related connection property descriptions.
.......
  r6588 | mmatthews | 2007-09-15 16:01:29 -0500 (Sat, 15 Sep 2007) | 3 lines
  
  Only update row "validity" on navigation, reduces time spent in value retrieval when seeing if we're on a valid row or not.
  
  
  
  Moved a hot method call (to get a configuration that stays the same for the lifetime of a connection) to a field that is set during instantiation.
.......
  r6589 | mmatthews | 2007-09-15 21:05:52 -0500 (Sat, 15 Sep 2007) | 1 line
  
  Added mapings for new 4-byte utf8, utf16 and utf32 collations/charsets for 5.2/6.0 server.
.......
  r6590 | mmatthews | 2007-09-26 05:28:04 -0500 (Wed, 26 Sep 2007) | 1 line
  
  Added ability to hook into connection lifecycle events via an extension interface.
.......
  r6591 | mmatthews | 2007-09-26 05:30:30 -0500 (Wed, 26 Sep 2007) | 1 line
  
  Added actual interface you need to _implement_ for StatementInterceptors.
.......
  r6592 | mmatthews | 2007-09-26 06:44:41 -0500 (Wed, 26 Sep 2007) | 1 line
  
  Clarification of utf-8 blob mappings for the TINYBLOB type.
.......



Property changes on: trunk
___________________________________________________________________
Name: svnmerge-integrated
   - /branches/branch_5_0:1-6572 /branches/branch_5_1:1-6566,6576-6577,6584
   + /branches/branch_5_0:1-6572 /branches/branch_5_1:1-6566,6576-6577,6584,6587-6592

Modified: trunk/connector-j/CHANGES
===================================================================
--- trunk/connector-j/CHANGES	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/CHANGES	2007-09-26 12:02:47 UTC (rev 6593)
@@ -1,10 +1,16 @@
 # Changelog
 # $Id$
+nn-nn-07 - Version 5.1.4 
 
+    - Added "autoSlowLog" configuration property, overrides 
+      "slowQueryThreshold*" properties, driver determines slow
+      queries by those that are slower than 5 * stddev of the mean
+      query time (outside the 96% percentile).
+      
 09-07-07 - Version 5.1.3 RC
 
 	- Setting "useBlobToStoreUTF8OutsideBMP" to "true" tells the
-	  driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR
+	  driver to treat [MEDIUM/LONG/TINY]BLOB columns as [LONG]VARCHAR
 	  columns holding text encoded in UTF-8 that has characters
 	  outside the BMP (4-byte encodings), which MySQL server
 	  can't handle natively.

Modified: trunk/connector-j/src/com/mysql/jdbc/CharsetMapping.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/CharsetMapping.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/CharsetMapping.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -191,7 +191,9 @@
 	        + "GREEK =			greek,"
 	        + "EUCKR =			euckr,"
 	        + "GB2312 =		gb2312,"
-	        + "LATIN2 =		latin2");
+	        + "LATIN2 =		latin2,"
+	        + "UTF-16 = 	>5.2.0 utf16,"
+	        + "UTF-32 = 	>5.2.0 utf32");
 
 		HashMap javaToMysqlMap = new HashMap();
 
@@ -287,7 +289,7 @@
 
 		MULTIBYTE_CHARSETS = Collections.unmodifiableMap(tempMapMulti);
 
-		INDEX_TO_CHARSET = new String[211];
+		INDEX_TO_CHARSET = new String[255];
 
 		try {
 			INDEX_TO_CHARSET[1] = getJavaEncodingForMysqlEncoding("big5", null);
@@ -540,7 +542,36 @@
 					null);
 			INDEX_TO_CHARSET[210] = getJavaEncodingForMysqlEncoding("utf8",
 					null);
-
+			// 5.2+ charsets
+			INDEX_TO_CHARSET[211] = getJavaEncodingForMysqlEncoding("utf8",
+					null);
+			
+			for (int i = 212; i < 224; i++) {
+				INDEX_TO_CHARSET[i] = NOT_USED;
+			}
+			
+			for (int i = 224; i <= 243; i++) {
+				INDEX_TO_CHARSET[i] = getJavaEncodingForMysqlEncoding("utf8",
+						null);
+			}
+			
+			for (int i = 101; i<= 120; i++) {
+				INDEX_TO_CHARSET[i] = getJavaEncodingForMysqlEncoding("utf16",
+						null);
+			}
+			
+			for (int i = 160; i<= 179; i++) {
+				INDEX_TO_CHARSET[i] = getJavaEncodingForMysqlEncoding("utf32",
+						null);
+			}
+			
+			for (int i = 244; i < 254; i++) {
+				INDEX_TO_CHARSET[i] = NOT_USED;
+			}
+			
+			INDEX_TO_CHARSET[254] = getJavaEncodingForMysqlEncoding("utf8",
+					null);
+			
 			// Sanity check
 			
 			for (int i = 1; i < INDEX_TO_CHARSET.length; i++) {
@@ -552,7 +583,7 @@
 			// ignore, it won't happen in this case
 		}
 		
-		INDEX_TO_COLLATION = new String[211];
+		INDEX_TO_COLLATION = new String[255];
 		
 		INDEX_TO_COLLATION[1] = "big5_chinese_ci";
 		INDEX_TO_COLLATION[2] = "latin2_czech_cs";
@@ -682,6 +713,101 @@
 		INDEX_TO_COLLATION[209] = "utf8_esperanto_ci";
 		INDEX_TO_COLLATION[210] = "utf8_hungarian_ci";
 		
+		// TODO: Remove duplicates
+		
+		INDEX_TO_COLLATION[33] ="utf8mb3_general_ci";
+		INDEX_TO_COLLATION[83] ="utf8mb3_bin";
+		INDEX_TO_COLLATION[192] ="utf8mb3_unicode_ci";
+		INDEX_TO_COLLATION[193] ="utf8mb3_icelandic_ci";
+		INDEX_TO_COLLATION[194] ="utf8mb3_latvian_ci";
+		INDEX_TO_COLLATION[195] ="utf8mb3_romanian_ci";
+		INDEX_TO_COLLATION[196] ="utf8mb3_slovenian_ci";
+		INDEX_TO_COLLATION[197] ="utf8mb3_polish_ci";
+		INDEX_TO_COLLATION[198] ="utf8mb3_estonian_ci";
+		INDEX_TO_COLLATION[199] ="utf8mb3_spanish_ci";
+		INDEX_TO_COLLATION[200] ="utf8mb3_swedish_ci";
+		INDEX_TO_COLLATION[201] ="utf8mb3_turkish_ci";
+		INDEX_TO_COLLATION[202] ="utf8mb3_czech_ci";
+		INDEX_TO_COLLATION[203] ="utf8mb3_danish_ci";
+		INDEX_TO_COLLATION[204] ="utf8mb3_lithuanian_ci";
+		INDEX_TO_COLLATION[205] ="utf8mb3_slovak_ci";
+		INDEX_TO_COLLATION[206] ="utf8mb3_spanish2_ci";
+		INDEX_TO_COLLATION[207] ="utf8mb3_roman_ci";
+		INDEX_TO_COLLATION[208] ="utf8mb3_persian_ci";
+		INDEX_TO_COLLATION[209] ="utf8mb3_esperanto_ci";
+		INDEX_TO_COLLATION[210] ="utf8mb3_hungarian_ci";
+		INDEX_TO_COLLATION[211] ="utf8mb3_sinhala_ci";
+		INDEX_TO_COLLATION[254] ="utf8mb3_general_cs";
+		
+		INDEX_TO_COLLATION[45] ="utf8_general_ci";
+		INDEX_TO_COLLATION[46] ="utf8_bin";
+		INDEX_TO_COLLATION[224] ="utf8_unicode_ci";
+		INDEX_TO_COLLATION[225] ="utf8_icelandic_ci";
+		INDEX_TO_COLLATION[226] ="utf8_latvian_ci";
+		INDEX_TO_COLLATION[227] ="utf8_romanian_ci";
+		INDEX_TO_COLLATION[228] ="utf8_slovenian_ci";
+		INDEX_TO_COLLATION[229] ="utf8_polish_ci";
+		INDEX_TO_COLLATION[230] ="utf8_estonian_ci";
+		INDEX_TO_COLLATION[231] ="utf8_spanish_ci";
+		INDEX_TO_COLLATION[232] ="utf8_swedish_ci";
+		INDEX_TO_COLLATION[233] ="utf8_turkish_ci";
+		INDEX_TO_COLLATION[234] ="utf8_czech_ci";
+		INDEX_TO_COLLATION[235] ="utf8_danish_ci";
+		INDEX_TO_COLLATION[236] ="utf8_lithuanian_ci";
+		INDEX_TO_COLLATION[237] ="utf8_slovak_ci";
+		INDEX_TO_COLLATION[238] ="utf8_spanish2_ci";
+		INDEX_TO_COLLATION[239] ="utf8_roman_ci";
+		INDEX_TO_COLLATION[240] ="utf8_persian_ci";
+		INDEX_TO_COLLATION[241] ="utf8_esperanto_ci";
+		INDEX_TO_COLLATION[242] ="utf8_hungarian_ci";
+		INDEX_TO_COLLATION[243] ="utf8_sinhala_ci";
+		
+		INDEX_TO_COLLATION[54] = "utf16_general_ci";
+		INDEX_TO_COLLATION[55] = "utf16_bin";
+		INDEX_TO_COLLATION[101] = "utf16_unicode_ci";
+		INDEX_TO_COLLATION[102] = "utf16_icelandic_ci";
+		INDEX_TO_COLLATION[103] = "utf16_latvian_ci";
+		INDEX_TO_COLLATION[104] = "utf16_romanian_ci";
+		INDEX_TO_COLLATION[105] = "utf16_slovenian_ci";
+		INDEX_TO_COLLATION[106] = "utf16_polish_ci";
+		INDEX_TO_COLLATION[107] = "utf16_estonian_ci";
+		INDEX_TO_COLLATION[108] = "utf16_spanish_ci";
+		INDEX_TO_COLLATION[109] = "utf16_swedish_ci";
+		INDEX_TO_COLLATION[110] = "utf16_turkish_ci";
+		INDEX_TO_COLLATION[111] = "utf16_czech_ci";
+		INDEX_TO_COLLATION[112] = "utf16_danish_ci";
+		INDEX_TO_COLLATION[113] = "utf16_lithuanian_ci";
+		INDEX_TO_COLLATION[114] = "utf16_slovak_ci";
+		INDEX_TO_COLLATION[115] = "utf16_spanish2_ci";
+		INDEX_TO_COLLATION[116] = "utf16_roman_ci";
+		INDEX_TO_COLLATION[117] = "utf16_persian_ci";
+		INDEX_TO_COLLATION[118] = "utf16_esperanto_ci";
+		INDEX_TO_COLLATION[119] = "utf16_hungarian_ci";
+		INDEX_TO_COLLATION[120] = "utf16_sinhala_ci";
+		
+		INDEX_TO_COLLATION[60] = "utf32_general_ci";
+		INDEX_TO_COLLATION[61] = "utf32_bin";
+		INDEX_TO_COLLATION[160] = "utf32_unicode_ci";
+		INDEX_TO_COLLATION[161] = "utf32_icelandic_ci";
+		INDEX_TO_COLLATION[162] = "utf32_latvian_ci";
+		INDEX_TO_COLLATION[163] = "utf32_romanian_ci";
+		INDEX_TO_COLLATION[164] = "utf32_slovenian_ci";
+		INDEX_TO_COLLATION[165] = "utf32_polish_ci";
+		INDEX_TO_COLLATION[166] = "utf32_estonian_ci";
+		INDEX_TO_COLLATION[167] = "utf32_spanish_ci";
+		INDEX_TO_COLLATION[168] = "utf32_swedish_ci";
+		INDEX_TO_COLLATION[169] = "utf32_turkish_ci";
+		INDEX_TO_COLLATION[170] = "utf32_czech_ci";
+		INDEX_TO_COLLATION[171] = "utf32_danish_ci";
+		INDEX_TO_COLLATION[172] = "utf32_lithuanian_ci";
+		INDEX_TO_COLLATION[173] = "utf32_slovak_ci";
+		INDEX_TO_COLLATION[174] = "utf32_spanish2_ci";
+		INDEX_TO_COLLATION[175] = "utf32_roman_ci";
+		INDEX_TO_COLLATION[176] = "utf32_persian_ci";
+		INDEX_TO_COLLATION[177] = "utf32_esperanto_ci";
+		INDEX_TO_COLLATION[178] = "utf32_hungarian_ci";
+		INDEX_TO_COLLATION[179] = "utf32_sinhala_ci";
+		
 		Map indexMap = new TreeMap(String.CASE_INSENSITIVE_ORDER);
 		
 		for (int i = 0; i < INDEX_TO_CHARSET.length; i++) {

Modified: trunk/connector-j/src/com/mysql/jdbc/Connection.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/Connection.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/Connection.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -343,5 +343,9 @@
 	 */
 	public abstract boolean versionMeetsMinimum(int major, int minor,
 			int subminor) throws SQLException;
+	
+	public abstract void reportQueryTime(long millisOrNanos);
+	
+	public abstract boolean isAbonormallyLongQuery(long millisOrNanos);
 
 }
\ No newline at end of file

Modified: trunk/connector-j/src/com/mysql/jdbc/ConnectionImpl.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ConnectionImpl.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/ConnectionImpl.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -39,6 +39,7 @@
 import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -166,7 +167,15 @@
 
 	private static final Map serverConfigByUrl = new HashMap();
 
+	private long queryTimeCount;
+	private double queryTimeSum;
+	private double queryTimeSumSquares;
+	private double queryTimeMean;
+	
 	private static Timer cancelTimer;
+	
+	private List connectionLifecycleInterceptors;
+	
 	private static final Constructor JDBC_4_CONNECTION_CTOR;
 	
 	static {
@@ -1426,7 +1435,15 @@
 	 * @exception SQLException
 	 *                if a database access error occurs
 	 */
-	public void close() throws SQLException {
+	public synchronized void close() throws SQLException {
+		if (this.connectionLifecycleInterceptors != null) {
+			new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
+				void forEach(Object each) throws SQLException {
+					((ConnectionLifecycleInterceptor)each).close();
+				}
+			}.doForAll();
+		}
+		
 		realClose(true, true, false, null);
 	}
 
@@ -1497,8 +1514,25 @@
 	public void commit() throws SQLException {
 		synchronized (getMutex()) {
 			checkClosed();
-	
+			
 			try {
+				if (this.connectionLifecycleInterceptors != null) {
+					IterateBlock iter = new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
+
+						void forEach(Object each) throws SQLException {
+							if (!((ConnectionLifecycleInterceptor)each).commit()) {
+								this.stopIterating = true;
+							}
+						}
+					};
+					
+					iter.doForAll();
+					
+					if (!iter.fullIteration()) {
+						return;
+					}
+				}
+				
 				// no-op if _relaxAutoCommit == true
 				if (this.autoCommit && !getRelaxAutoCommit()) {
 					throw SQLError.createSQLException("Can't call commit when autocommit=true");
@@ -3252,6 +3286,25 @@
 	 *             DOCUMENT ME!
 	 */
 	private void initializePropsFromServer() throws SQLException {
+		String connectionInterceptorClasses = getConnectionLifecycleInterceptors();
+		
+		this.connectionLifecycleInterceptors = null;
+		
+		if (connectionInterceptorClasses != null) {
+			this.connectionLifecycleInterceptors = Util.loadExtensions(this, this.props, 
+					connectionInterceptorClasses, 
+					"Connection.badLifecycleInterceptor");
+			
+			Iterator iter = this.connectionLifecycleInterceptors.iterator();
+			
+			new IterateBlock(iter) {
+				void forEach(Object each) throws SQLException {
+					// TODO: Fully initialize, or continue on error?
+					((ConnectionLifecycleInterceptor)each).init(ConnectionImpl.this, props);
+				}
+			}.doForAll();
+		}
+		
 		setSessionVariables();
 
 		//
@@ -3655,7 +3708,33 @@
 			stmt = createStatement();
 			stmt.setEscapeProcessing(false);
 
-			results = stmt.executeQuery("SHOW VARIABLES");
+			String query = "SHOW VARIABLES";
+			
+			if (versionMeetsMinimum(5, 0, 3)) {
+				query = "SHOW VARIABLES WHERE Variable_name ='language'"
+					+ " OR Variable_name = 'net_write_timeout'"
+					+ " OR Variable_name = 'interactive_timeout'"
+					+ " OR Variable_name = 'wait_timeout'"
+					+ " OR Variable_name = 'character_set_client'"
+					+ " OR Variable_name = 'character_set_connection'"
+					+ " OR Variable_name = 'character_set'"
+					+ " OR Variable_name = 'character_set_server'"
+					+ " OR Variable_name = 'tx_isolation'"
+					+ " OR Variable_name = 'transaction_isolation'"
+					+ " OR Variable_name = 'character_set_results'"
+					+ " OR Variable_name = 'timezone'"
+					+ " OR Variable_name = 'time_zone'"
+					+ " OR Variable_name = 'system_time_zone'"
+					+ " OR Variable_name = 'lower_case_table_names'"
+					+ " OR Variable_name = 'max_allowed_packet'"
+					+ " OR Variable_name = 'net_buffer_length'"
+					+ " OR Variable_name = 'sql_mode'"
+					+ " OR Variable_name = 'query_cache_type'"
+					+ " OR Variable_name = 'query_cache_size'"
+					+ " OR Variable_name = 'init_connect'";
+			}
+			
+			results = stmt.executeQuery(query);
 
 			while (results.next()) {
 				this.serverVariables.put(results.getString(1), results
@@ -4433,6 +4512,22 @@
 			checkClosed();
 	
 			try {
+				if (this.connectionLifecycleInterceptors != null) {
+					IterateBlock iter = new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
+
+						void forEach(Object each) throws SQLException {
+							if (!((ConnectionLifecycleInterceptor)each).rollback()) {
+								this.stopIterating = true;
+							}
+						}
+					};
+					
+					iter.doForAll();
+					
+					if (!iter.fullIteration()) {
+						return;
+					}
+				}
 				// no-op if _relaxAutoCommit == true
 				if (this.autoCommit && !getRelaxAutoCommit()) {
 					throw SQLError.createSQLException(
@@ -4467,13 +4562,30 @@
 	/**
 	 * @see Connection#rollback(Savepoint)
 	 */
-	public void rollback(Savepoint savepoint) throws SQLException {
+	public void rollback(final Savepoint savepoint) throws SQLException {
 
 		if (versionMeetsMinimum(4, 0, 14) || versionMeetsMinimum(4, 1, 1)) {
 			synchronized (getMutex()) {
 				checkClosed();
 	
 				try {
+					if (this.connectionLifecycleInterceptors != null) {
+						IterateBlock iter = new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
+
+							void forEach(Object each) throws SQLException {
+								if (!((ConnectionLifecycleInterceptor)each).rollback(savepoint)) {
+									this.stopIterating = true;
+								}
+							}
+						};
+						
+						iter.doForAll();
+						
+						if (!iter.fullIteration()) {
+							return;
+						}
+					}
+					
 					StringBuffer rollbackQuery = new StringBuffer(
 							"ROLLBACK TO SAVEPOINT ");
 					rollbackQuery.append('`');
@@ -4658,9 +4770,26 @@
 	 * @exception SQLException
 	 *                if a database access error occurs
 	 */
-	public void setAutoCommit(boolean autoCommitFlag) throws SQLException {
+	public void setAutoCommit(final boolean autoCommitFlag) throws SQLException {
 		synchronized (getMutex()) {
 			checkClosed();
+			
+			if (this.connectionLifecycleInterceptors != null) {
+				IterateBlock iter = new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
+
+					void forEach(Object each) throws SQLException {
+						if (!((ConnectionLifecycleInterceptor)each).setAutoCommit(autoCommitFlag)) {
+							this.stopIterating = true;
+						}
+					}
+				};
+				
+				iter.doForAll();
+				
+				if (!iter.fullIteration()) {
+					return;
+				}
+			}
 	
 			if (getAutoReconnectForPools()) {
 				setHighAvailability(true);
@@ -4728,7 +4857,7 @@
 	 * @throws SQLException
 	 *             if a database access error occurs
 	 */
-	public void setCatalog(String catalog) throws SQLException {
+	public void setCatalog(final String catalog) throws SQLException {
 		synchronized (getMutex()) {
 			checkClosed();
 	
@@ -4737,6 +4866,23 @@
 						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 			}
 			
+			if (this.connectionLifecycleInterceptors != null) {
+				IterateBlock iter = new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
+
+					void forEach(Object each) throws SQLException {
+						if (!((ConnectionLifecycleInterceptor)each).setCatalog(catalog)) {
+							this.stopIterating = true;
+						}
+					}
+				};
+				
+				iter.doForAll();
+				
+				if (!iter.fullIteration()) {
+					return;
+				}
+			}
+			
 			if (getUseLocalSessionState()) {
 				if (this.lowerCaseTableNames) {
 					if (this.database.equalsIgnoreCase(catalog)) {
@@ -5259,4 +5405,22 @@
 	public void setStatementComment(String comment) {
 		this.statementComment = comment;
 	}
+	
+	public synchronized void reportQueryTime(long millisOrNanos) {
+		this.queryTimeCount++;
+		this.queryTimeSum += millisOrNanos;
+		this.queryTimeSumSquares += (millisOrNanos * millisOrNanos);
+		this.queryTimeMean = ((this.queryTimeMean * (this.queryTimeCount - 1)) + millisOrNanos)
+				/ this.queryTimeCount;
+	}
+	
+	public synchronized boolean isAbonormallyLongQuery(long millisOrNanos) {
+		if (this.queryTimeCount < 15) {
+			return false; // need a minimum amount for this to make sense
+		}
+		
+		double stddev = Math.sqrt((this.queryTimeSumSquares - ((this.queryTimeSum*this.queryTimeSum) / this.queryTimeCount)) / (this.queryTimeCount - 1));
+		
+		return millisOrNanos > (this.queryTimeMean + 5 * stddev);
+	}
 }

Copied: trunk/connector-j/src/com/mysql/jdbc/ConnectionLifecycleInterceptor.java (from rev 6592, branches/branch_5_1/connector-j/src/com/mysql/jdbc/ConnectionLifecycleInterceptor.java)

Modified: trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -1566,4 +1566,12 @@
     public abstract boolean getFunctionsNeverReturnBlobs();
 
     public abstract void setFunctionsNeverReturnBlobs(boolean flag);
+    
+	public abstract boolean getAutoSlowLog();
+
+	public abstract void setAutoSlowLog(boolean flag);
+	
+	public abstract String getConnectionLifecycleInterceptors();
+
+	public abstract void setConnectionLifecycleInterceptors(String interceptors);
 }

Modified: trunk/connector-j/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -755,16 +755,19 @@
 			Messages.getString("ConnectionProperties.blobSendChunkSize"), //$NON-NLS-1$
 			"3.1.9", PERFORMANCE_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
 	
+	private BooleanConnectionProperty autoSlowLog = new BooleanConnectionProperty(
+			"autoSlowLog", true,
+			Messages.getString("ConnectionProperties.autoSlowLog"),
+			"5.1.4", DEBUGING_PROFILING_CATEGORY, Integer.MIN_VALUE);
+	
 	private BooleanConnectionProperty blobsAreStrings = new BooleanConnectionProperty(
             "blobsAreStrings", false,
-            "Should the driver always treat BLOBs as Strings - specifically to work around dubious metadata "
-            + "returned by the server for GROUP BY clauses?",
+            Messages.getString("ConnectionProperties.blobsAreStrings"),
             "5.0.8", MISC_CATEGORY, Integer.MIN_VALUE);
 
 	private BooleanConnectionProperty functionsNeverReturnBlobs = new BooleanConnectionProperty(
             "functionsNeverReturnBlobs", false,
-            "Should the driver always treat data from functions returning BLOBs as Strings - specifically to work around dubious metadata "
-            + "returned by the server for GROUP BY clauses?",
+            Messages.getString("ConnectionProperties.functionsNeverReturnBlobs"),
             "5.0.8", MISC_CATEGORY, Integer.MIN_VALUE);
 			
 	private BooleanConnectionProperty cacheCallableStatements = new BooleanConnectionProperty(
@@ -843,6 +846,12 @@
 			Messages.getString("ConnectionProperties.connectionCollation"), //$NON-NLS-1$
 			"3.0.13", MISC_CATEGORY, 7); //$NON-NLS-1$
 
+	private StringConnectionProperty connectionLifecycleInterceptors = new StringConnectionProperty(
+			"connectionLifecycleInterceptors", //$NON-NLS-1$
+			null,
+			Messages.getString("ConnectionProperties.connectionLifecycleInterceptors"),
+			"5.1.4", CONNECTION_AND_AUTH_CATEGORY, Integer.MAX_VALUE);
+			
 	private IntegerConnectionProperty connectTimeout = new IntegerConnectionProperty(
 			"connectTimeout", 0, 0, Integer.MAX_VALUE, //$NON-NLS-1$
 			Messages.getString("ConnectionProperties.connectTimeout"), //$NON-NLS-1$
@@ -4256,4 +4265,20 @@
     public void setFunctionsNeverReturnBlobs(boolean flag) {
         this.functionsNeverReturnBlobs.setValue(flag);
     }
+
+	public boolean getAutoSlowLog() {
+		return this.autoSlowLog.getValueAsBoolean();
+	}
+
+	public void setAutoSlowLog(boolean flag) {
+		this.autoSlowLog.setValue(flag);
+	}
+
+	public String getConnectionLifecycleInterceptors() {
+		return this.connectionLifecycleInterceptors.getValueAsString();
+	}
+
+	public void setConnectionLifecycleInterceptors(String interceptors) {
+		this.connectionLifecycleInterceptors.setValue(interceptors);
+	}
 }

Modified: trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -66,26 +66,7 @@
  *          Exp $
  */
 public class DatabaseMetaData implements java.sql.DatabaseMetaData {
-	protected abstract class IterateBlock {
-		IteratorWithCleanup iterator;
 
-		IterateBlock(IteratorWithCleanup i) {
-			iterator = i;
-		}
-
-		public void doForAll() throws SQLException {
-			try {
-				while (iterator.hasNext()) {
-					forEach(iterator.next());
-				}
-			} finally {
-				iterator.close();
-			}
-		}
-
-		abstract void forEach(Object each) throws SQLException;
-	}
-
 	protected abstract class IteratorWithCleanup {
 		abstract void close() throws SQLException;
 

Copied: trunk/connector-j/src/com/mysql/jdbc/Extension.java (from rev 6592, branches/branch_5_1/connector-j/src/com/mysql/jdbc/Extension.java)

Copied: trunk/connector-j/src/com/mysql/jdbc/IterateBlock.java (from rev 6592, branches/branch_5_1/connector-j/src/com/mysql/jdbc/IterateBlock.java)

Modified: trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2007-09-26 12:02:47 UTC (rev 6593)
@@ -447,6 +447,9 @@
 ConnectionProperties.autoGenerateTestcaseScript=Should the driver dump the SQL it is executing, including server-side prepared statements to STDERR?
 ConnectionProperties.autoReconnect=Should the driver try to re-establish stale and/or dead connections? If enabled the driver will throw an exception for a queries issued on a stale or dead connection, which belong to the current transaction, but will attempt reconnect before the next query issued on the connection in a new transaction. The use of this feature is not recommended, because it has side effects related to session state and data consistency when applications don't handle SQLExceptions properly, and is only designed to be used when you are unable to configure your application to handle SQLExceptions resulting from dead and stale connections properly. Alternatively, investigate setting the MySQL server variable "wait_timeout" to some high value rather than the default of 8 hours.
 ConnectionProperties.autoReconnectForPools=Use a reconnection strategy appropriate for connection pools (defaults to 'false')
+ConnectionProperties.autoSlowLog=Instead of using slowQueryThreshold* to determine if a query is slow enough to be logged, maintain statistics that allow the driver to determine queries that are outside the 99th percentile?
+ConnectionProperties.blobsAreStrings=Should the driver always treat BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?
+ConnectionProperties.functionsNeverReturnBlobs=Should the driver always treat data from functions returning BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?
 ConnectionProperties.blobSendChunkSize=Chunk to use when sending BLOB/CLOBs via ServerPreparedStatements
 ConnectionProperties.cacheCallableStatements=Should the driver cache the parsing stage of CallableStatements
 ConnectionProperties.cachePrepStmts=Should the driver cache the parsing stage of PreparedStatements of client-side prepared statements, the "check" for suitability of server-side prepared and server-side prepared statements themselves?
@@ -460,6 +463,7 @@
 ConnectionProperties.clobberStreamingResults=This will cause a 'streaming' ResultSet to be automatically closed, and any outstanding data still streaming from the server to be discarded if another query is executed before all the data has been read from the server.
 ConnectionProperties.clobCharacterEncoding=The character encoding to use for sending and retrieving TEXT, MEDIUMTEXT and LONGTEXT values instead of the configured connection characterEncoding
 ConnectionProperties.connectionCollation=If set, tells the server to use this collation via 'set collation_connection'
+ConnectionProperties.connectionLifecycleInterceptors=A comma-delimited list of classes that implement "com.mysql.jdbc.ConnectionLifecycleInterceptor" that should notified of connection lifecycle events (creation, destruction, commit, rollback, setCatalog and setAutoCommit) and potentially alter the execution of these commands. ConnectionLifecycleInterceptors are "stackable", more than one interceptor may be specified via the configuration property as a comma-delimited list, with the interceptors executed in order from left to right.
 ConnectionProperties.connectTimeout=Timeout for socket connect (in milliseconds), with 0 being no timeout. Only works on JDK-1.4 or newer. Defaults to '0'.
 ConnectionProperties.continueBatchOnError=Should the driver continue processing batch commands if one statement fails. The JDBC spec allows either way (defaults to 'true').
 ConnectionProperties.createDatabaseIfNotExist=Creates the database given in the URL if it doesn't yet exist. Assumes the configured user has permissions to create databases.
@@ -536,7 +540,7 @@
 ConnectionProperties.slowQueryThresholdNanos=If 'useNanosForElapsedTime' is set to true, and this property is set to a non-zero value, the driver will use this threshold (in nanosecond units) to determine if a query was slow.
 ConnectionProperties.socketFactory=The name of the class that the driver should use for creating socket connections to the server. This class must implement the interface 'com.mysql.jdbc.SocketFactory' and have public no-args constructor.
 ConnectionProperties.socketTimeout=Timeout on network socket operations (0, the default means no timeout).
-ConnectionProperties.statementInterceptors=A comma-delimited list of classes that implement "" that should be placed "in between" query execution to influence the results. StatementInterceptors are "chainable", the results returned by the "current" interceptor will be passed on to the next in in the chain, from left-to-right order, as specified in this property. 
+ConnectionProperties.statementInterceptors=A comma-delimited list of classes that implement "com.mysql.jdbc.StatementInterceptor" that should be placed "in between" query execution to influence the results. StatementInterceptors are "chainable", the results returned by the "current" interceptor will be passed on to the next in in the chain, from left-to-right order, as specified in this property. 
 ConnectionProperties.strictFloatingPoint=Used only in older versions of compliance test
 ConnectionProperties.strictUpdates=Should the driver do strict checking (all primary keys selected) of updatable result sets (true, false, defaults to 'true')?
 ConnectionProperties.overrideSupportsIEF=Should the driver return "true" for DatabaseMetaData.supportsIntegrityEnhancementFacility() even if the database doesn't support it to workaround applications that require this method to return "true" to signal support of foreign keys, even though the SQL specification states that this facility contains much more than just foreign key support (one such application being OpenOffice)?

Modified: trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/MysqlIO.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -257,6 +257,8 @@
             this.packetDebugRingBuffer = new LinkedList();
         }
 
+        this.useAutoSlowLog = this.connection.getAutoSlowLog();
+        
         this.useBufferRowSizeThreshold = useBufferRowSizeThreshold;
         this.useDirectRowUnpack = this.connection.getUseDirectRowUnpack();
 
@@ -322,36 +324,18 @@
 		}
     }
 
-    protected void initializeStatementInterceptors(String interceptorClasses, Properties props) throws SQLException {
-    	List interceptorsToCreate = StringUtils.split(interceptorClasses, ",", true);
+    protected void initializeStatementInterceptors(String interceptorClasses,
+			Properties props) throws SQLException {
+		this.statementInterceptors = Util.loadExtensions(this.connection, props, 
+				interceptorClasses,
+				"MysqlIo.BadStatementInterceptor");
+	}
 
-    	this.statementInterceptors = new LinkedList();
-
-    	Iterator iter = interceptorsToCreate.iterator();
-
-    	String classname = null;
-
-    	try {
-    		while (iter.hasNext()) {
-    			classname = iter.next().toString();
-    			StatementInterceptor interceptorInstance = (StatementInterceptor)Class.forName(classname).newInstance();
-    			interceptorInstance.init(this.connection, props);
-
-    			this.statementInterceptors.add(interceptorInstance);
-    		}
-    	} catch (Throwable t) {
-    		SQLException sqlEx = SQLError.createSQLException(Messages.getString("MysqlIo.BadStatementInterceptor", new Object[] {classname}));
-    		sqlEx.initCause(t);
-
-    		throw sqlEx;
-    	}
-    }
-
     /**
-     * Does the server send back extra column info?
-     *
-     * @return true if so
-     */
+	 * Does the server send back extra column info?
+	 * 
+	 * @return true if so
+	 */
     public boolean hasLongColumnInfo() {
         return this.hasLongColumnInfo;
     }
@@ -1861,6 +1845,7 @@
     }
 
     private int statementExecutionDepth = 0;
+	private boolean useAutoSlowLog;
 
     /**
      * Send a query stored in a packet directly to the server.
@@ -1990,10 +1975,23 @@
 
 	    		if (this.profileSql) {
 	    			shouldExtractQuery = true;
-	    		} else if (this.logSlowQueries &&
-	    				((queryEndTime - queryStartTime) > this.connection.getSlowQueryThresholdMillis())) {
-	    			shouldExtractQuery = true;
-	    			queryWasSlow = true;
+	    		} else if (this.logSlowQueries) {
+	    			long queryTime = queryEndTime - queryStartTime;
+	    			
+	    			boolean logSlow = false;
+	    			
+	    			if (this.useAutoSlowLog) {
+	    				logSlow = queryTime > this.connection.getSlowQueryThresholdMillis();
+	    			} else {
+	    				logSlow = this.connection.isAbonormallyLongQuery(queryTime);
+	    				
+	    				this.connection.reportQueryTime(queryTime);
+	    			}
+	    			
+	    			if (logSlow) {
+	    				shouldExtractQuery = true;
+	    				queryWasSlow = true;
+	    			}
 	    		}
 
 	    		if (shouldExtractQuery) {

Modified: trunk/connector-j/src/com/mysql/jdbc/ResultSetImpl.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ResultSetImpl.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/ResultSetImpl.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -330,6 +330,10 @@
 
 	private boolean padCharsWithSpace = false;
 
+	private boolean jdbcCompliantTruncationForReads;
+	
+	private boolean useFastIntParsing = true;
+	
 	protected final static char[] EMPTY_SPACE = new char[255];
 	
 	static {
@@ -443,6 +447,8 @@
 			this.profileSql = this.connection.getProfileSql();
 			this.retainOwningStatement = 
 				this.connection.getRetainStatementAfterResultSetClose();
+			this.jdbcCompliantTruncationForReads = this.connection.getJdbcCompliantTruncationForReads();
+			this.useFastIntParsing = this.connection.getUseFastIntParsing();
 		}
 
 		this.owningStatement = creatorStmt;
@@ -617,6 +623,8 @@
 			}
 		}
 
+		setRowPositionValidity();
+		
 		return b;
 	}
 
@@ -651,6 +659,8 @@
 			this.rowData.afterLast();
 			this.thisRow = null;
 		}
+		
+		setRowPositionValidity();
 	}
 
 	/**
@@ -686,6 +696,8 @@
 		
 		this.rowData.beforeFirst();
 		this.thisRow = null;
+		
+		setRowPositionValidity();
 	}
 
 	// ---------------------------------------------------------------------
@@ -801,24 +813,32 @@
 	protected void checkRowPos() throws SQLException {
 		checkClosed();
 
-		if (!this.rowData.isDynamic() && (this.rowData.size() == 0)) {
-			throw SQLError.createSQLException(
-					Messages
-							.getString("ResultSet.Illegal_operation_on_empty_result_set"),
+		if (!this.onValidRow) {
+			throw SQLError.createSQLException(this.invalidRowReason, 
 					SQLError.SQL_STATE_GENERAL_ERROR);
 		}
-
-		if (this.rowData.isBeforeFirst()) {
-			throw SQLError.createSQLException(Messages
-					.getString("ResultSet.Before_start_of_result_set_146"),
-					SQLError.SQL_STATE_GENERAL_ERROR); //$NON-NLS-1$
+	}
+	
+	private boolean onValidRow = false;
+	private String invalidRowReason = null;
+	
+	private void setRowPositionValidity() throws SQLException {
+		if (!this.rowData.isDynamic() && (this.rowData.size() == 0)) {
+			this.invalidRowReason = Messages
+			.getString("ResultSet.Illegal_operation_on_empty_result_set");//$NON-NLS-1$
+			this.onValidRow = false;
+		} else if (this.rowData.isBeforeFirst()) {
+			this.invalidRowReason = Messages
+					.getString("ResultSet.Before_start_of_result_set_146"); //$NON-NLS-1$
+			this.onValidRow = false;
+		} else if (this.rowData.isAfterLast()) {
+			this.invalidRowReason = Messages
+					.getString("ResultSet.After_end_of_result_set_148"); //$NON-NLS-1$
+			this.onValidRow = false;
+		} else {
+			this.onValidRow = true;
+			this.invalidRowReason = null;
 		}
-
-		if (this.rowData.isAfterLast()) {
-			throw SQLError.createSQLException(Messages
-					.getString("ResultSet.After_end_of_result_set_148"),
-					SQLError.SQL_STATE_GENERAL_ERROR); //$NON-NLS-1$
-		}
 	}
 
 	/**
@@ -1079,22 +1099,27 @@
 	public boolean first() throws SQLException {
 		checkClosed();
 
+		boolean b = true;
+		
 		if (this.rowData.isEmpty()) {
-			return false;
+			b = false;
+		} else {
+	
+			if (this.onInsertRow) {
+				this.onInsertRow = false;
+			}
+	
+			if (this.doingUpdates) {
+				this.doingUpdates = false;
+			}
+	
+			this.rowData.beforeFirst();
+			this.thisRow = this.rowData.next();
 		}
 
-		if (this.onInsertRow) {
-			this.onInsertRow = false;
-		}
-
-		if (this.doingUpdates) {
-			this.doingUpdates = false;
-		}
-
-		this.rowData.beforeFirst();
-		this.thisRow = this.rowData.next();
-
-		return true;
+		setRowPositionValidity();
+		
+		return b;
 	}
 
 	/**
@@ -1749,7 +1774,7 @@
 			if (decimalIndex != -1) {
 				double valueAsDouble = Double.parseDouble(stringVal);
 
-				if (this.connection.getJdbcCompliantTruncationForReads()) {
+				if (this.jdbcCompliantTruncationForReads) {
 					if (valueAsDouble < Byte.MIN_VALUE
 							|| valueAsDouble > Byte.MAX_VALUE) {
 						throwRangeException(stringVal, columnIndex,
@@ -1762,7 +1787,7 @@
 
 			long valueAsLong = Long.parseLong(stringVal);
 
-			if (this.connection.getJdbcCompliantTruncationForReads()) {
+			if (this.jdbcCompliantTruncationForReads) {
 				if (valueAsLong < Byte.MIN_VALUE
 						|| valueAsLong > Byte.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsLong),
@@ -2489,7 +2514,7 @@
 
 				float f = Float.parseFloat(val);
 
-				if (this.connection.getJdbcCompliantTruncationForReads()) {
+				if (this.jdbcCompliantTruncationForReads) {
 					if (f == Float.MIN_VALUE || f == Float.MAX_VALUE) {
 						double valAsDouble = Double.parseDouble(val);
 
@@ -2514,9 +2539,9 @@
 				Double valueAsDouble = new Double(val);
 				float valueAsFloat = valueAsDouble.floatValue();
 				
-				if (this.connection.getJdbcCompliantTruncationForReads()) {
+				if (this.jdbcCompliantTruncationForReads) {
 
-					if (this.connection.getJdbcCompliantTruncationForReads() && 
+					if (this.jdbcCompliantTruncationForReads && 
 							valueAsFloat == Float.NEGATIVE_INFINITY ||
 							valueAsFloat == Float.POSITIVE_INFINITY) {
 						throwRangeException(valueAsDouble.toString(), 
@@ -2554,7 +2579,7 @@
 
 		if (!this.isBinaryEncoded) {
 			int columnIndexMinusOne = columnIndex - 1;
-			if (this.connection.getUseFastIntParsing()) {
+			if (this.useFastIntParsing) {
 				checkColumnBounds(columnIndex);
 
 				if (this.thisRow.isNull(columnIndexMinusOne)) {
@@ -2657,7 +2682,7 @@
 				if (this.fields[columnIndexMinusOne].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
 					long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex);
 
-					if (this.connection.getJdbcCompliantTruncationForReads()
+					if (this.jdbcCompliantTruncationForReads
 							&& (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE)) {
 						throwRangeException(String.valueOf(valueAsLong),
 								columnIndex, Types.INTEGER);
@@ -2717,7 +2742,7 @@
 					
 					int valueAsInt = Integer.parseInt(val);
 
-					if (this.connection.getJdbcCompliantTruncationForReads()) {
+					if (this.jdbcCompliantTruncationForReads) {
 						if (valueAsInt == Integer.MIN_VALUE
 								|| valueAsInt == Integer.MAX_VALUE) {
 							long valueAsLong = Long.parseLong(val);
@@ -2738,7 +2763,7 @@
 
 				double valueAsDouble = Double.parseDouble(val);
 
-				if (this.connection.getJdbcCompliantTruncationForReads()) {
+				if (this.jdbcCompliantTruncationForReads) {
 					if (valueAsDouble < Integer.MIN_VALUE
 							|| valueAsDouble > Integer.MAX_VALUE) {
 						throwRangeException(String.valueOf(valueAsDouble),
@@ -2754,7 +2779,7 @@
 			try {
 				double valueAsDouble = Double.parseDouble(val);
 
-				if (this.connection.getJdbcCompliantTruncationForReads()) {
+				if (this.jdbcCompliantTruncationForReads) {
 					if (valueAsDouble < Integer.MIN_VALUE
 							|| valueAsDouble > Integer.MAX_VALUE) {
 						throwRangeException(String.valueOf(valueAsDouble),
@@ -2796,7 +2821,7 @@
 			
 			int columnIndexMinusOne = columnIndex - 1;
 			
-			if (this.connection.getUseFastIntParsing()) {
+			if (this.useFastIntParsing) {
 			
 				checkColumnBounds(columnIndex);
 
@@ -3234,7 +3259,7 @@
 		case MysqlDefs.FIELD_TYPE_BIT:
 			long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1);
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() &&
+			if (overflowCheck && this.jdbcCompliantTruncationForReads &&
 					(valueAsLong < Byte.MIN_VALUE
 							|| valueAsLong > Byte.MAX_VALUE)) {
 				throwRangeException(String.valueOf(valueAsLong), columnIndex + 1,
@@ -3252,7 +3277,7 @@
 			short valueAsShort = (valueAsByte >= 0) ? 
 					valueAsByte : (short)(valueAsByte + (short)256);
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsShort > Byte.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsShort),
 							columnIndex + 1, Types.TINYINT);
@@ -3265,7 +3290,7 @@
 		case MysqlDefs.FIELD_TYPE_YEAR:
 			valueAsShort = getNativeShort(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsShort < Byte.MIN_VALUE
 						|| valueAsShort > Byte.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsShort),
@@ -3278,7 +3303,7 @@
 		case MysqlDefs.FIELD_TYPE_LONG:
 			int valueAsInt = getNativeInt(columnIndex + 1, false);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsInt < Byte.MIN_VALUE || valueAsInt > Byte.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsInt),
 							columnIndex + 1, Types.TINYINT);
@@ -3290,7 +3315,7 @@
 		case MysqlDefs.FIELD_TYPE_FLOAT:
 			float valueAsFloat = getNativeFloat(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsFloat < Byte.MIN_VALUE
 						|| valueAsFloat > Byte.MAX_VALUE) {
 
@@ -3304,7 +3329,7 @@
 		case MysqlDefs.FIELD_TYPE_DOUBLE:
 			double valueAsDouble = getNativeDouble(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsDouble < Byte.MIN_VALUE
 						|| valueAsDouble > Byte.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsDouble),
@@ -3317,7 +3342,7 @@
 		case MysqlDefs.FIELD_TYPE_LONGLONG:
 			valueAsLong = getNativeLong(columnIndex + 1, false, true);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsLong < Byte.MIN_VALUE
 						|| valueAsLong > Byte.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsLong),
@@ -3938,7 +3963,7 @@
 			
 			float valueAsFloat = valueAsDouble.floatValue();
 			
-			if (this.connection.getJdbcCompliantTruncationForReads() && 
+			if (this.jdbcCompliantTruncationForReads && 
 					valueAsFloat == Float.NEGATIVE_INFINITY ||
 					valueAsFloat == Float.POSITIVE_INFINITY) {
 				throwRangeException(valueAsDouble.toString(), 
@@ -4035,7 +4060,7 @@
 		case MysqlDefs.FIELD_TYPE_BIT:
 			long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1);
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() &&
+			if (overflowCheck && this.jdbcCompliantTruncationForReads &&
 					(valueAsLong < Integer.MIN_VALUE
 							|| valueAsLong > Integer.MAX_VALUE)) {
 				throwRangeException(String.valueOf(valueAsLong), columnIndex + 1,
@@ -4072,7 +4097,7 @@
 			valueAsLong = (valueAsInt >= 0) ? 
 					valueAsInt : valueAsInt + 4294967296L; 
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() &&
+			if (overflowCheck && this.jdbcCompliantTruncationForReads &&
 					valueAsLong > Integer.MAX_VALUE) {
 				throwRangeException(String.valueOf(valueAsLong),
 						columnIndex + 1, Types.INTEGER);
@@ -4082,7 +4107,7 @@
 		case MysqlDefs.FIELD_TYPE_LONGLONG:
 			valueAsLong = getNativeLong(columnIndex + 1, false, true);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsLong < Integer.MIN_VALUE
 						|| valueAsLong > Integer.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsLong),
@@ -4094,7 +4119,7 @@
 		case MysqlDefs.FIELD_TYPE_DOUBLE:
 			double valueAsDouble = getNativeDouble(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsDouble < Integer.MIN_VALUE
 						|| valueAsDouble > Integer.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsDouble),
@@ -4106,7 +4131,7 @@
 		case MysqlDefs.FIELD_TYPE_FLOAT:
 			valueAsDouble = getNativeFloat(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsDouble < Integer.MIN_VALUE
 						|| valueAsDouble > Integer.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsDouble),
@@ -4202,7 +4227,7 @@
 			
 			BigInteger asBigInt = convertLongToUlong(valueAsLong);
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && 
+			if (overflowCheck && this.jdbcCompliantTruncationForReads && 
 					((asBigInt.compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0 ) ||
 					 (asBigInt.compareTo(new BigInteger(String.valueOf(Long.MIN_VALUE))) < 0))) {
 				throwRangeException(asBigInt.toString(),
@@ -4214,7 +4239,7 @@
 		case MysqlDefs.FIELD_TYPE_DOUBLE:
 			double valueAsDouble = getNativeDouble(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsDouble < Long.MIN_VALUE
 						|| valueAsDouble > Long.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsDouble),
@@ -4226,7 +4251,7 @@
 		case MysqlDefs.FIELD_TYPE_FLOAT:
 			valueAsDouble = getNativeFloat(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsDouble < Long.MIN_VALUE
 						|| valueAsDouble > Long.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsDouble),
@@ -4323,7 +4348,7 @@
 			
 			int valueAsInt = asShort & 0xffff;
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() &&
+			if (overflowCheck && this.jdbcCompliantTruncationForReads &&
 					valueAsInt > Short.MAX_VALUE) {
 				throwRangeException(String.valueOf(valueAsInt),
 						columnIndex + 1, Types.SMALLINT);
@@ -4335,7 +4360,7 @@
 			if (!f.isUnsigned()) {
 				valueAsInt = getNativeInt(columnIndex + 1, false);
 				
-				if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() &&
+				if (overflowCheck && this.jdbcCompliantTruncationForReads &&
 						valueAsInt > Short.MAX_VALUE ||
 						valueAsInt < Short.MIN_VALUE) {
 					throwRangeException(String.valueOf(valueAsInt),
@@ -4347,7 +4372,7 @@
 			
 			long valueAsLong = getNativeLong(columnIndex + 1, false, true);
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() &&
+			if (overflowCheck && this.jdbcCompliantTruncationForReads &&
 					valueAsLong > Short.MAX_VALUE) {
 				throwRangeException(String.valueOf(valueAsLong),
 						columnIndex + 1, Types.SMALLINT);
@@ -4359,7 +4384,7 @@
 			valueAsLong = getNativeLong(columnIndex + 1, false, false);
 			
 			if (!f.isUnsigned()) {
-				if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+				if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 					if (valueAsLong < Short.MIN_VALUE
 							|| valueAsLong > Short.MAX_VALUE) {
 						throwRangeException(String.valueOf(valueAsLong),
@@ -4372,7 +4397,7 @@
 			
 			BigInteger asBigInt = convertLongToUlong(valueAsLong);
 			
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && 
+			if (overflowCheck && this.jdbcCompliantTruncationForReads && 
 					((asBigInt.compareTo(new BigInteger(String.valueOf(Short.MAX_VALUE))) > 0 ) ||
 					 (asBigInt.compareTo(new BigInteger(String.valueOf(Short.MIN_VALUE))) < 0))) {
 				throwRangeException(asBigInt.toString(),
@@ -4384,7 +4409,7 @@
 		case MysqlDefs.FIELD_TYPE_DOUBLE:
 			double valueAsDouble = getNativeDouble(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsDouble < Short.MIN_VALUE
 						|| valueAsDouble > Short.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsDouble),
@@ -4396,7 +4421,7 @@
 		case MysqlDefs.FIELD_TYPE_FLOAT:
 			float valueAsFloat = getNativeFloat(columnIndex + 1);
 
-			if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+			if (overflowCheck && this.jdbcCompliantTruncationForReads) {
 				if (valueAsFloat < Short.MIN_VALUE
 						|| valueAsFloat > Short.MAX_VALUE) {
 					throwRangeException(String.valueOf(valueAsFloat),
@@ -5196,7 +5221,7 @@
 		if (!this.isBinaryEncoded) {
 			checkRowPos();
 			
-			if (this.connection.getUseFastIntParsing()) {
+			if (this.useFastIntParsing) {
 				
 				checkColumnBounds(columnIndex);
 
@@ -5245,7 +5270,7 @@
 						if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
 							long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex);
 							
-							if (this.connection.getJdbcCompliantTruncationForReads() &&
+							if (this.jdbcCompliantTruncationForReads &&
 									(valueAsLong < Short.MIN_VALUE
 											|| valueAsLong > Short.MAX_VALUE)) {
 								throwRangeException(String.valueOf(valueAsLong), columnIndex,
@@ -5297,7 +5322,7 @@
 				if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
 					long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex);
 					
-					if (this.connection.getJdbcCompliantTruncationForReads() &&
+					if (this.jdbcCompliantTruncationForReads &&
 							(valueAsLong < Short.MIN_VALUE
 									|| valueAsLong > Short.MAX_VALUE)) {
 						throwRangeException(String.valueOf(valueAsLong), columnIndex,
@@ -6887,26 +6912,31 @@
 	public boolean last() throws SQLException {
 		checkClosed();
 
+		boolean b = true;
+		
 		if (this.rowData.size() == 0) {
-			return false;
-		}
+			b = false;
+		} else {
 
-		if (this.onInsertRow) {
-			this.onInsertRow = false;
+			if (this.onInsertRow) {
+				this.onInsertRow = false;
+			}
+	
+			if (this.doingUpdates) {
+				this.doingUpdates = false;
+			}
+	
+			if (this.thisRow != null) {
+				this.thisRow.closeOpenStreams();
+			}
+			
+			this.rowData.beforeLast();
+			this.thisRow = this.rowData.next();
 		}
 
-		if (this.doingUpdates) {
-			this.doingUpdates = false;
-		}
-
-		if (this.thisRow != null) {
-			this.thisRow.closeOpenStreams();
-		}
+		setRowPositionValidity();
 		
-		this.rowData.beforeLast();
-		this.thisRow = this.rowData.next();
-
-		return true;
+		return b;
 	}
 
 	// /////////////////////////////////////////
@@ -7006,6 +7036,8 @@
 			}
 		}
 
+		setRowPositionValidity();
+		
 		return b;
 	}
 
@@ -7017,7 +7049,7 @@
 
 		double valueAsDouble = Double.parseDouble(val);
 
-		if (this.connection.getJdbcCompliantTruncationForReads()) {
+		if (this.jdbcCompliantTruncationForReads) {
 			if (valueAsDouble < Integer.MIN_VALUE
 					|| valueAsDouble > Integer.MAX_VALUE) {
 				throwRangeException(String.valueOf(valueAsDouble), columnIndex,
@@ -7042,7 +7074,7 @@
 	private void checkForIntegerTruncation(int columnIndex,
 			byte[] valueAsBytes, String valueAsString, int intValue)
 			throws SQLException {
-		if (this.connection.getJdbcCompliantTruncationForReads()) {
+		if (this.jdbcCompliantTruncationForReads) {
 			if (intValue == Integer.MIN_VALUE || intValue == Integer.MAX_VALUE) {
 				long valueAsLong = Long
 						.parseLong(valueAsString == null ? new String(
@@ -7066,7 +7098,7 @@
 
 		double valueAsDouble = Double.parseDouble(val);
 
-		if (this.connection.getJdbcCompliantTruncationForReads()) {
+		if (this.jdbcCompliantTruncationForReads) {
 			if (valueAsDouble < Long.MIN_VALUE
 					|| valueAsDouble > Long.MAX_VALUE) {
 				throwRangeException(val, columnIndex, Types.BIGINT);
@@ -7115,7 +7147,7 @@
 			longValue = Long.parseLong(valueAsString);
 		}
 
-		if (doCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+		if (doCheck && this.jdbcCompliantTruncationForReads) {
 			checkForLongTruncation(columnIndex, valueAsBytes, valueAsString,
 					longValue);
 		}
@@ -7148,7 +7180,7 @@
 
 		double valueAsDouble = Double.parseDouble(val);
 
-		if (this.connection.getJdbcCompliantTruncationForReads()) {
+		if (this.jdbcCompliantTruncationForReads) {
 			if (valueAsDouble < Short.MIN_VALUE
 					|| valueAsDouble > Short.MAX_VALUE) {
 				throwRangeException(String.valueOf(valueAsDouble), columnIndex,
@@ -7185,7 +7217,7 @@
 			shortValue = Short.parseShort(valueAsString);
 		}
 
-		if (this.connection.getJdbcCompliantTruncationForReads()) {
+		if (this.jdbcCompliantTruncationForReads) {
 			if (shortValue == Short.MIN_VALUE || shortValue == Short.MAX_VALUE) {
 				long valueAsLong = Long
 						.parseLong(valueAsString == null ? new String(
@@ -7232,21 +7264,27 @@
 			this.thisRow.closeOpenStreams();
 		}
 		
+		boolean b = true;
+		
 		if ((rowIndex - 1) >= 0) {
 			rowIndex--;
 			this.rowData.setCurrentRow(rowIndex);
 			this.thisRow = this.rowData.getAt(rowIndex);
 
-			return true;
+			b = true;
 		} else if ((rowIndex - 1) == -1) {
 			rowIndex--;
 			this.rowData.setCurrentRow(rowIndex);
 			this.thisRow = null;
 
-			return false;
+			b = false;
 		} else {
-			return false;
+			b = false;
 		}
+		
+		setRowPositionValidity();
+		
+		return b;
 	}
 
 	/**
@@ -7519,6 +7557,8 @@
 		checkClosed();
 
 		if (this.rowData.size() == 0) {
+			setRowPositionValidity();
+			
 			return false;
 		}
 
@@ -7529,6 +7569,8 @@
 		this.rowData.moveRowRelative(rows);
 		this.thisRow = this.rowData.getAt(this.rowData.getCurrentRowNumber());
 
+		setRowPositionValidity();
+		
 		return (!this.rowData.isAfterLast() && !this.rowData.isBeforeFirst());
 	}
 

Modified: trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -360,6 +360,7 @@
 				!this.connection.versionMeetsMinimum(4, 1, 10);
 		}
 		
+		this.useAutoSlowLog = this.connection.getAutoSlowLog();
 		this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
 		this.hasLimitClause = (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1); //$NON-NLS-1$
 		this.firstCharOfStmt = StringUtils.firstNonWsCharUc(sql);
@@ -523,6 +524,8 @@
 
 	protected boolean isCached = false;
 
+	private boolean useAutoSlowLog;
+
 	protected void setClosed(boolean flag) {
 		this.isClosed = flag;
 	}
@@ -1281,9 +1284,17 @@
 				if (logSlowQueries || gatherPerformanceMetrics) {
 					long elapsedTime = queryEndTime - begin;
 
-					if (logSlowQueries
-							&& (elapsedTime >= mysql.getSlowQueryThreshold())) {
-						queryWasSlow = true;
+					if (logSlowQueries) {
+		    			if (this.useAutoSlowLog) {
+		    				queryWasSlow = elapsedTime > this.connection.getSlowQueryThresholdMillis();
+		    			} else {
+		    				queryWasSlow = this.connection.isAbonormallyLongQuery(elapsedTime);
+		    				
+		    				this.connection.reportQueryTime(elapsedTime);
+		    			}
+					}
+
+					if (queryWasSlow) {
 						
 						StringBuffer mesgBuf = new StringBuffer(
 								48 + this.originalSql.length());

Modified: trunk/connector-j/src/com/mysql/jdbc/StatementInterceptor.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/StatementInterceptor.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/StatementInterceptor.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -38,7 +38,7 @@
  * @version $Id: $
  */
 
-public interface StatementInterceptor {
+public interface StatementInterceptor extends Extension {
 
 	/**
 	 * Called once per connection that wants to use the interceptor
@@ -133,4 +133,11 @@
 	 * executed for the top-level "original" query.
 	 */
 	public abstract boolean executeTopLevelOnly();
+
+	/**
+	 * Called by the driver when this extension should release any resources
+	 * it is holding and cleanup internally before the connection is
+	 * closed.
+	 */
+	public abstract void destroy();
 }
\ No newline at end of file

Modified: trunk/connector-j/src/com/mysql/jdbc/Util.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/Util.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/Util.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -35,7 +35,10 @@
 import java.sql.SQLException;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.TimeZone;
 
 /**
@@ -554,4 +557,37 @@
 
 		return diffMap;
 	}
+	
+	public static List loadExtensions(Connection conn,
+			Properties props, String extensionClassNames,
+			String errorMessageKey) throws SQLException {
+		List extensionList = new LinkedList();
+
+		List interceptorsToCreate = StringUtils.split(extensionClassNames, ",",
+				true);
+
+		Iterator iter = interceptorsToCreate.iterator();
+
+		String className = null;
+
+		try {
+			while (iter.hasNext()) {
+				className = iter.next().toString();
+				Extension extensionInstance = (Extension) Class.forName(
+						className).newInstance();
+				extensionInstance.init(conn, props);
+
+				extensionList.add(extensionInstance);
+			}
+		} catch (Throwable t) {
+			SQLException sqlEx = SQLError.createSQLException(Messages
+					.getString(errorMessageKey, new Object[] { className }));
+			sqlEx.initCause(t);
+
+			throw sqlEx;
+		}
+
+		return extensionList;
+	}
+
 }
\ No newline at end of file

Modified: trunk/connector-j/src/com/mysql/jdbc/interceptors/ResultSetScannerInterceptor.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/interceptors/ResultSetScannerInterceptor.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/interceptors/ResultSetScannerInterceptor.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -104,4 +104,9 @@
 	public boolean executeTopLevelOnly() {
 		return false;
 	}
+
+	public void destroy() {
+		// TODO Auto-generated method stub
+		
+	}
 }
\ No newline at end of file

Modified: trunk/connector-j/src/com/mysql/jdbc/interceptors/ServerStatusDiffInterceptor.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/interceptors/ServerStatusDiffInterceptor.java	2007-09-26 11:44:41 UTC (rev 6592)
+++ trunk/connector-j/src/com/mysql/jdbc/interceptors/ServerStatusDiffInterceptor.java	2007-09-26 12:02:47 UTC (rev 6593)
@@ -99,4 +99,9 @@
 	public boolean executeTopLevelOnly() {
 		return true;
 	}
+
+	public void destroy() {
+		// TODO Auto-generated method stub
+		
+	}
 }

Copied: trunk/connector-j/src/com/mysql/jdbc/interceptors/SessionAssociationInterceptor.java (from rev 6592, branches/branch_5_1/connector-j/src/com/mysql/jdbc/interceptors/SessionAssociationInterceptor.java)

Thread
Connector/J commit: r6593 - in trunk: . connector-j connector-j/src/com/mysql/jdbc connector-j/src/com/mysql/jdbc/interceptorsmmatthews26 Sep