List:Commits« Previous MessageNext Message »
From:mmatthews Date:May 28 2008 4:53pm
Subject:Connector/J commit: r6775 - in branches/branch_5_1: . src/com/mysql/jdbc src/com/mysql/jdbc/jdbc2/optional src/testsuite/regression
View as plain text  
Modified:
   branches/branch_5_1/CHANGES
   branches/branch_5_1/src/com/mysql/jdbc/ConnectionProperties.java
   branches/branch_5_1/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
   branches/branch_5_1/src/com/mysql/jdbc/LocalizedErrorMessages.properties
   branches/branch_5_1/src/com/mysql/jdbc/ReplicationConnection.java
   branches/branch_5_1/src/com/mysql/jdbc/ResultSetImpl.java
   branches/branch_5_1/src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java
   branches/branch_5_1/src/testsuite/regression/ResultSetRegressionTest.java
Log:
Fixed BUG#35610, BUG#35150- ResultSet.findColumn() and ResultSet.get...(String) doesn't
allow
      column names to be used, and isn't congruent with ResultSetMetadata.getColumnName().
      
      By default, we follow the JDBC Specification here, in that the 4.0 behavior
	  is correct. Calling programs should use ResultSetMetaData.getColumnLabel() to
dynamically determine
	  the correct "name" to pass to ResultSet.findColumn() or ResultSet.get...(String)
whether or not the
	  query specifies an alias via "AS" for the column. ResultSetMetaData.getColumnName()
will return the
	  actual name of the column, if it exists, and this name can *not* be used as input to
ResultSet.findColumn()
	  or ResultSet.get...(String).
	  
	  The JDBC-3.0 (and earlier) specification has a bug, but you can get the buggy behavior
	  (allowing column names *and* labels to be used for ResultSet.findColumn() and
get...(String)) by setting   "useColumnNamesInFindColumn" to "true".

Modified: branches/branch_5_1/CHANGES
===================================================================
--- branches/branch_5_1/CHANGES	2008-05-27 14:28:41 UTC (rev 6774)
+++ branches/branch_5_1/CHANGES	2008-05-28 14:53:25 UTC (rev 6775)
@@ -36,6 +36,20 @@
 	- Fixed BUG#36830 - DBMD.getColumns() doesn't return correct COLUMN_SIZE for SET
columns. The
 	  logic wasn't accounting for the ","s in the column size.
 	  
+    - Fixed BUG#35610, BUG#35150- ResultSet.findColumn() and ResultSet.get...(String)
doesn't allow
+      column names to be used, and isn't congruent with
ResultSetMetadata.getColumnName().
+      
+      By default, we follow the JDBC Specification here, in that the 4.0 behavior
+	  is correct. Calling programs should use ResultSetMetaData.getColumnLabel() to
dynamically determine
+	  the correct "name" to pass to ResultSet.findColumn() or ResultSet.get...(String)
whether or not the
+	  query specifies an alias via "AS" for the column. ResultSetMetaData.getColumnName()
will return the
+	  actual name of the column, if it exists, and this name can *not* be used as input to
ResultSet.findColumn()
+	  or ResultSet.get...(String).
+	  
+	  The JDBC-3.0 (and earlier) specification has a bug, but you can get the buggy behavior
+	  (allowing column names *and* labels to be used for ResultSet.findColumn() and
get...(String)) by setting 
+	  "useColumnNamesInFindColumn" to "true".
+	  
 03-06-08 - Version 5.1.6
 
     - JDBC-4.0-ized XAConnections and datasources.

Modified: branches/branch_5_1/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
--- branches/branch_5_1/src/com/mysql/jdbc/ConnectionProperties.java	2008-05-27 14:28:41
UTC (rev 6774)
+++ branches/branch_5_1/src/com/mysql/jdbc/ConnectionProperties.java	2008-05-28 14:53:25
UTC (rev 6775)
@@ -1594,4 +1594,8 @@
 	public int getSelfDestructOnPingMaxOperations();
 
 	public void setSelfDestructOnPingMaxOperations(int maxOperations);
+	
+	public boolean getUseColumnNamesInFindColumn();
+
+	public void setUseColumnNamesInFindColumn(boolean flag);
 }

Modified: branches/branch_5_1/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
===================================================================
--- branches/branch_5_1/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2008-05-27
14:28:41 UTC (rev 6774)
+++ branches/branch_5_1/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2008-05-28
14:53:25 UTC (rev 6775)
@@ -1434,6 +1434,12 @@
 			Messages.getString("ConnectionProperties.useCompression"), //$NON-NLS-1$
 			"3.0.17", CONNECTION_AND_AUTH_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
 
+	private BooleanConnectionProperty useColumnNamesInFindColumn = new
BooleanConnectionProperty(
+			"useColumnNamesInFindColumn",
+			false, 
+			Messages.getString("ConnectionProperties.useColumnNamesInFindColumn"), //$NON-NLS-1$
+			"5.1.7", MISC_CATEGORY, Integer.MAX_VALUE); //$NON-NLS-1$
+	
 	private StringConnectionProperty useConfigs = new StringConnectionProperty(
 			"useConfigs", //$NON-NLS-1$
 			null,
@@ -4359,4 +4365,12 @@
 	public void setSelfDestructOnPingMaxOperations(int maxOperations) {
 		this.selfDestructOnPingMaxOperations.setValue(maxOperations);
 	}
+
+	public boolean getUseColumnNamesInFindColumn() {
+		return this.useColumnNamesInFindColumn.getValueAsBoolean();
+	}
+
+	public void setUseColumnNamesInFindColumn(boolean flag) {
+		this.useColumnNamesInFindColumn.setValue(flag);
+	}
 }

Modified: branches/branch_5_1/src/com/mysql/jdbc/LocalizedErrorMessages.properties
===================================================================
--- branches/branch_5_1/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2008-05-27
14:28:41 UTC (rev 6774)
+++ branches/branch_5_1/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2008-05-28
14:53:25 UTC (rev 6775)
@@ -612,7 +612,7 @@
 ConnectionProperties.utf8OutsideBmpExcludedColumnNamePattern=When
"useBlobToStoreUTF8OutsideBMP" is set to "true", column names matching the given regex
will still be treated as BLOBs unless they match the regex specified for
"utf8OutsideBmpIncludedColumnNamePattern". The regex must follow the patterns used for
the java.util.regex package.
 ConnectionProperties.utf8OutsideBmpIncludedColumnNamePattern=Used to specify exclusion
rules to "utf8OutsideBmpExcludedColumnNamePattern". The regex must follow the patterns
used for the java.util.regex package.
 ConnectionProperties.useLegacyDatetimeCode=Use code for DATE/TIME/DATETIME/TIMESTAMP
handling in result sets and statements that consistently handles timezone conversions
from client to server and back again, or use the legacy code for these datatypes that has
been in the driver for backwards-compatibility?
-
+ConnectionProperties.useColumnNamesInFindColumn=Prior to JDBC-4.0, the JDBC specification
had a bug related to what could be given as a "column name" to ResultSet methods like
findColumn(), or getters that took a String property. JDBC-4.0 clarified "column name" to
mean the label, as given in an "AS" clause and returned by
ResultSetMetaData.getColumnLabel(), and if no AS clause, the column name. Setting this
property to "true" will give behavior that is congruent to JDBC-3.0 and earlier versions
of the JDBC specification, but which because of the specification bug could give
unexpected results. This property is preferred over "useOldAliasMetadataBehavior" unless
you need the specific behavior that it provides with respect to ResultSetMetadata.
 # 
 # Error Messages for Connection Properties
 #

Modified: branches/branch_5_1/src/com/mysql/jdbc/ReplicationConnection.java
===================================================================
--- branches/branch_5_1/src/com/mysql/jdbc/ReplicationConnection.java	2008-05-27 14:28:41
UTC (rev 6774)
+++ branches/branch_5_1/src/com/mysql/jdbc/ReplicationConnection.java	2008-05-28 14:53:25
UTC (rev 6775)
@@ -2328,4 +2328,12 @@
 	public void setInGlobalTx(boolean flag) {
 		this.currentConnection.setInGlobalTx(flag);
 	}
+
+	public boolean getUseColumnNamesInFindColumn() {
+		return this.currentConnection.getUseColumnNamesInFindColumn();
+	}
+
+	public void setUseColumnNamesInFindColumn(boolean flag) {
+		// TODO Auto-generated method stub
+	}
 }

Modified: branches/branch_5_1/src/com/mysql/jdbc/ResultSetImpl.java
===================================================================
--- branches/branch_5_1/src/com/mysql/jdbc/ResultSetImpl.java	2008-05-27 14:28:41 UTC (rev
6774)
+++ branches/branch_5_1/src/com/mysql/jdbc/ResultSetImpl.java	2008-05-28 14:53:25 UTC (rev
6775)
@@ -191,7 +191,7 @@
 	protected String catalog = null;
 
 	/** Map column names (and all of their permutations) to column indices */
-	protected Map columnNameToIndex = null;
+	protected Map columnLabelToIndex = null;
 
 	/** Keep track of columns accessed */
 	protected boolean[] columnUsed = null;
@@ -233,6 +233,8 @@
 	/** Map of fully-specified column names to column indices */
 	protected Map fullColumnNameToIndex = null;
 
+	protected Map columnNameToIndex = null;
+	
 	protected boolean hasBuiltIndexMapping = false;
 
 	/**
@@ -326,6 +328,7 @@
 	private boolean jdbcCompliantTruncationForReads;
 	
 	private boolean useFastIntParsing = true;
+	private boolean useColumnNamesInFindColumn;
 	
 	protected final static char[] EMPTY_SPACE = new char[255];
 	
@@ -482,6 +485,8 @@
 		} // else called by Connection.initializeResultsMetadataFromCache() when cached
 		useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode();
 		
+		this.useColumnNamesInFindColumn = this.connection.getUseColumnNamesInFindColumn();
+		
 		setRowPositionValidity();
 	}
 
@@ -709,8 +714,9 @@
 	 */
 	public void buildIndexMapping() throws SQLException {
 		int numFields = this.fields.length;
+		this.columnLabelToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER);
+		this.fullColumnNameToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER);
 		this.columnNameToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER);
-		this.fullColumnNameToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER);
 		
 		
 		// We do this in reverse order, so that the 'first' column
@@ -727,16 +733,21 @@
 		//
 		for (int i = numFields - 1; i >= 0; i--) {
 			Integer index = Constants.integerValueOf(i);
-			String columnName = this.fields[i].getName();
+			String columnName = this.fields[i].getOriginalName();
+			String columnLabel = this.fields[i].getName();
 			String fullColumnName = this.fields[i].getFullName();
 
-			if (columnName != null) {			
-				this.columnNameToIndex.put(columnName, index);
+			if (columnLabel != null) {			
+				this.columnLabelToIndex.put(columnLabel, index);
 			}
 
 			if (fullColumnName != null) {
 				this.fullColumnNameToIndex.put(fullColumnName, index);
 			}
+			
+			if (columnName != null) {
+				this.columnNameToIndex.put(columnName, index);
+			}
 		}
 
 		// set the flag to prevent rebuilding...
@@ -928,14 +939,14 @@
 	public void populateCachedMetaData(CachedResultSetMetaData cachedMetaData)
 		throws SQLException {
 		cachedMetaData.fields = this.fields;
-		cachedMetaData.columnNameToIndex = this.columnNameToIndex;
+		cachedMetaData.columnNameToIndex = this.columnLabelToIndex;
 		cachedMetaData.fullColumnNameToIndex = this.fullColumnNameToIndex;
 		cachedMetaData.metadata = getMetaData();
 	}
 	
 	public void initializeFromCachedMetaData(CachedResultSetMetaData cachedMetaData) {
 		this.fields = cachedMetaData.fields;
-		this.columnNameToIndex = cachedMetaData.columnNameToIndex;
+		this.columnLabelToIndex = cachedMetaData.columnNameToIndex;
 		this.fullColumnNameToIndex = cachedMetaData.fullColumnNameToIndex;
 		this.hasBuiltIndexMapping = true;
 	}
@@ -1053,7 +1064,8 @@
 	// ---------------------------------------------------------------------
 
 
-	/**
+	/*
+	 * [For JDBC-3.0 and older -
http://java.sun.com/j2se/1.5.0/docs/api/java/sql/ResultSet.html#findColumn(java.lang.String)]
 	 * Map a ResultSet column name to a ResultSet column index
 	 * 
 	 * @param columnName
@@ -1063,6 +1075,16 @@
 	 * 
 	 * @exception SQLException
 	 *                if a database access error occurs
+	 *                
+	 * [For JDBC-4.0 and newer -
http://java.sun.com/javase/6/docs/api/java/sql/ResultSet.html#findColumn(java.lang.String)]
+	 * 
+	 * Maps the given ResultSet column label to its ResultSet column index.
+	 * 
+	 * @param columnLabel
+	 *            the label for the column specified with the SQL AS clause. If the 
+	 *            SQL AS clause was not specified, then the label is the name of the column
+	 *            
+	 * @return the column index of the given column name
 	 */
 	public synchronized int findColumn(String columnName) throws SQLException {
 		Integer index;
@@ -1071,12 +1093,16 @@
 			buildIndexMapping();
 		}
 
-		index = (Integer) this.columnNameToIndex.get(columnName);
+		index = (Integer) this.columnLabelToIndex.get(columnName);
 
+		if (index == null && this.useColumnNamesInFindColumn) {
+			index = (Integer) this.columnNameToIndex.get(columnName);
+		}
+		
 		if (index == null) {
 			index = (Integer) this.fullColumnNameToIndex.get(columnName);
 		}
-
+		
 		if (index != null) {
 			return index.intValue() + 1;
 		}
@@ -7495,7 +7521,7 @@
 			this.rowData = null;
 			this.defaultTimeZone = null;
 			this.fields = null;
-			this.columnNameToIndex = null;
+			this.columnLabelToIndex = null;
 			this.fullColumnNameToIndex = null;
 			this.eventSink = null;
 			this.warningChain = null;

Modified: branches/branch_5_1/src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java
===================================================================
---
branches/branch_5_1/src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java	2008-05-27
14:28:41 UTC (rev 6774)
+++
branches/branch_5_1/src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java	2008-05-28
14:53:25 UTC (rev 6775)
@@ -28,6 +28,7 @@
 import java.sql.SQLException;
 import java.sql.Savepoint;
 import java.sql.Statement;
+import java.util.Map;
 import java.util.TimeZone;
 
 import com.mysql.jdbc.Connection;
@@ -2538,4 +2539,12 @@
 	public void setSelfDestructOnPingSecondsLifetime(int seconds) {
 		this.mc.setSelfDestructOnPingSecondsLifetime(seconds);
 	}
+
+	public boolean getUseColumnNamesInFindColumn() {
+		return this.mc.getUseColumnNamesInFindColumn();
+	}
+
+	public void setUseColumnNamesInFindColumn(boolean flag) {
+		this.mc.setUseColumnNamesInFindColumn(flag);
+	}
 }

Modified: branches/branch_5_1/src/testsuite/regression/ResultSetRegressionTest.java
===================================================================
--- branches/branch_5_1/src/testsuite/regression/ResultSetRegressionTest.java	2008-05-27
14:28:41 UTC (rev 6774)
+++ branches/branch_5_1/src/testsuite/regression/ResultSetRegressionTest.java	2008-05-28
14:53:25 UTC (rev 6775)
@@ -4681,4 +4681,79 @@
 			closeMemberJDBCResources();
 		}
 	}
+	
+	/**
+	 * Tests fix for BUG#35610, BUG#35150. We follow the JDBC Spec here, in that the 4.0
behavior
+	 * is correct, the JDBC-3.0 (and earlier) spec has a bug, but you can get the buggy
behavior
+	 * (allowing column names *and* labels to be used) by setting
"useColumnNamesInFindColumn" to
+	 * "true".
+	 * 
+	 * @throws Exception
+	 */
+	public void testBug35610() throws Exception {
+		createTable("testBug35610", "(field1 int, field2 int, field3 int)");
+		this.stmt.executeUpdate("INSERT INTO testBug35610 VALUES (1, 2, 3)");
+		exercise35610(this.stmt, false);
+		exercise35610(getConnectionWithProps("useColumnNamesInFindColumn=true").createStatement(),
true);
+	}
+	
+	private void exercise35610(Statement configuredStmt, boolean force30Behavior) throws
Exception {
+		try {
+			this.rs = configuredStmt.executeQuery("SELECT field1 AS f1, field2 AS f2, field3 FROM
testBug35610");
+			
+			ResultSetMetaData rsmd = this.rs.getMetaData();
+			
+			assertEquals("field1", rsmd.getColumnName(1));
+			assertEquals("field2", rsmd.getColumnName(2));
+			assertEquals("f1", rsmd.getColumnLabel(1));
+			assertEquals("f2", rsmd.getColumnLabel(2));
+			
+
+			
+			assertEquals("field3", rsmd.getColumnName(3));
+			assertEquals("field3", rsmd.getColumnLabel(3));
+			
+			this.rs.next();
+			
+			// From ResultSet.html#getInt(java.lang.String) in JDBC-4.0
+			//
+			// Retrieves the value of the designated column in the current row of this ResultSet
+			// object as an int in the Java programming language.
+			//
+			// Parameters:
+			// columnLabel - the label for the column specified with the SQL AS clause. If the 
+			//               SQL AS clause was not specified, then the label is the name of the
column
+			//
+			
+			assertEquals(1, this.rs.getInt("f1"));
+			assertEquals(2, this.rs.getInt("f2"));
+			assertEquals(3, this.rs.getInt("field3"));
+			
+			// Pre-JDBC 4.0, some versions of the spec say "column name *or* label"
+			// for the column name argument...
+			
+			if (force30Behavior) {
+				assertEquals(1, this.rs.getInt("field1"));
+				assertEquals(2, this.rs.getInt("field2"));
+			}
+			
+			if (!force30Behavior) {
+				try {
+					this.rs.findColumn("field1");
+					fail("findColumn(\"field1\" should have failed with an exception");
+				} catch (SQLException sqlEx) {
+					// expected
+				}
+				
+				try {
+					this.rs.findColumn("field2");
+					fail("findColumn(\"field2\" should have failed with an exception");
+				} catch (SQLException sqlEx) {
+					// expected
+				}
+			}
+		} finally {
+			closeMemberJDBCResources();
+		}
+	}
 }

Thread
Connector/J commit: r6775 - in branches/branch_5_1: . src/com/mysql/jdbc src/com/mysql/jdbc/jdbc2/optional src/testsuite/regressionmmatthews28 May