Modified:
branches/branch_5_0/connector-j/CHANGES
branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.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/ResultSetMetaData.java
branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java
branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java
trunk/connector-j/CHANGES
trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
trunk/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java
trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java
trunk/connector-j/src/com/mysql/jdbc/ResultSet.java
trunk/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java
trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java
trunk/connector-j/src/testsuite/regression/ResultSetRegressionTest.java
Log:
Fixed BUG#21379 - column names don't match metadata in cases
where server doesn't return original column names (column functions)
thus breaking compatibility with applications that expect 1-1 mappings
between findColumn() and rsmd.getColumnName(), usually manifests itself
as "Can't find column ('')" exceptions.
Fixed potential bugs for .getBoolean() with non-numeric, non-string, non-bit columns (plus
some cleanup of ResultSet.getBoolean()).
Modified: branches/branch_5_0/connector-j/CHANGES
===================================================================
--- branches/branch_5_0/connector-j/CHANGES 2006-08-01 05:00:42 UTC (rev 5587)
+++ branches/branch_5_0/connector-j/CHANGES 2006-08-01 05:14:40 UTC (rev 5588)
@@ -1,6 +1,14 @@
# Changelog
# $Id$
+nn-nn-06 - Version 5.0.4
+
+ - Fixed BUG#21379 - column names don't match metadata in cases
+ where server doesn't return original column names (column functions)
+ thus breaking compatibility with applications that expect 1-1 mappings
+ between findColumn() and rsmd.getColumnName(), usually manifests itself
+ as "Can't find column ('')" exceptions.
+
07-26-06 - Version 5.0.3
- Fixed BUG#20650 - Statement.cancel() causes NullPointerException
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
---
branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2006-08-01
05:00:42 UTC (rev 5587)
+++
branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -1316,6 +1316,16 @@
+ " by Connection.setAutoCommit() and Connection.setTransactionIsolation(), rather
than querying the database?",
"3.1.7", PERFORMANCE_CATEGORY, Integer.MIN_VALUE);
+ private BooleanConnectionProperty useOldAliasMetadataBehavior = new
BooleanConnectionProperty(
+ "useOldAliasMetadataBehavior",
+ false,
+ "Should the driver use the legacy behavior for \"AS\" clauses on columns and tables,
and only "
+ + "return aliases (if any) for ResultSetMetaData.getColumnName() or
ResultSetMetaData.getTableName() "
+ + "rather than the original column/table name?",
+ "5.0.4",
+ MISC_CATEGORY,
+ Integer.MIN_VALUE);
+
private BooleanConnectionProperty useOldUTF8Behavior = new BooleanConnectionProperty(
"useOldUTF8Behavior",
false,
@@ -3738,5 +3748,11 @@
this.noAccessToProcedureBodies.setValue(flag);
}
+ public boolean getUseOldAliasMetadataBehavior() {
+ return this.useOldAliasMetadataBehavior.getValueAsBoolean();
+ }
+ public void setUseOldAliasMetadataBehavior(boolean flag) {
+ this.useOldAliasMetadataBehavior.setValue(flag);
+ }
}
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java
===================================================================
---
branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java 2006-08-01
05:00:42 UTC (rev 5587)
+++
branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -33,7 +33,7 @@
MysqlParameterMetadata(Field[] fieldInfo, int parameterCount) {
- this.metadata = new ResultSetMetaData(fieldInfo);
+ this.metadata = new ResultSetMetaData(fieldInfo, false);
this.parameterCount = parameterCount;
}
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-08-01
05:00:42 UTC (rev 5587)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -1808,7 +1808,8 @@
this.pstmtResultMetaData = mdRs.getMetaData();
} else {
this.pstmtResultMetaData = new ResultSetMetaData(
- new Field[0]);
+ new Field[0],
+ this.connection.getUseOldAliasMetadataBehavior());
}
} finally {
SQLException sqlExRethrow = null;
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-08-01 05:00:42
UTC (rev 5587)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-08-01 05:14:40
UTC (rev 5588)
@@ -1444,49 +1444,105 @@
* if a database access error occurs
*/
public boolean getBoolean(int columnIndex) throws SQLException {
- if (!this.isBinaryEncoded) {
- checkColumnBounds(columnIndex);
+
+ checkColumnBounds(columnIndex);
- //
- // MySQL 5.0 and newer have an actual BIT type,
- // so we need to check for that here...
- //
+ //
+ // MySQL 5.0 and newer have an actual BIT type,
+ // so we need to check for that here...
+ //
- int columnIndexMinusOne = columnIndex - 1;
+ int columnIndexMinusOne = columnIndex - 1;
- Field field = this.fields[columnIndexMinusOne];
+ Field field = this.fields[columnIndexMinusOne];
- if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
- if (this.thisRow[columnIndexMinusOne] == null) {
- this.wasNullFlag = true;
+ if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
+ return byteArrayToBoolean(columnIndexMinusOne);
+ }
- return false;
- }
+ this.wasNullFlag = false;
+
+ int sqlType = field.getSQLType();
+
+ switch (sqlType) {
+ case Types.BIT:
+ case Types.BOOLEAN:
+ case Types.TINYINT:
+ case Types.SMALLINT:
+ case Types.INTEGER:
+ case Types.BIGINT:
+ case Types.DECIMAL:
+ case Types.NUMERIC:
+ case Types.REAL:
+ case Types.FLOAT:
+ case Types.DOUBLE:
+ long boolVal = getLong(columnIndex, false);
- this.wasNullFlag = false;
-
- if (((byte[]) this.thisRow[columnIndexMinusOne]).length == 0) {
- return false;
+ return (boolVal == -1 || boolVal > 0);
+ default:
+ if (this.connection.getPedantic()) {
+ // Table B-6 from JDBC spec
+ switch (sqlType) {
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ case Types.DATE:
+ case Types.TIME:
+ case Types.TIMESTAMP:
+ case Types.CLOB:
+ case Types.BLOB:
+ case Types.ARRAY:
+ case Types.REF:
+ case Types.DATALINK:
+ case Types.STRUCT:
+ case Types.JAVA_OBJECT:
+ throw SQLError.createSQLException("Required type conversion not allowed",
+ SQLError.SQL_STATE_INVALID_CHARACTER_VALUE_FOR_CAST);
}
-
- byte boolVal = ((byte[]) this.thisRow[columnIndexMinusOne])[0];
-
- return (boolVal > 0);
}
-
+
+ if (sqlType == Types.BINARY ||
+ sqlType == Types.VARBINARY ||
+ sqlType == Types.LONGVARBINARY ||
+ sqlType == Types.BLOB) {
+ return byteArrayToBoolean(columnIndexMinusOne);
+ }
+
+ if (this.useUsageAdvisor) {
+ issueConversionViaParsingWarning("getBoolean()", columnIndex,
+ this.thisRow[columnIndex], this.fields[columnIndex],
+ new int[] {
+ MysqlDefs.FIELD_TYPE_BIT,
+ MysqlDefs.FIELD_TYPE_DOUBLE,
+ MysqlDefs.FIELD_TYPE_TINY,
+ MysqlDefs.FIELD_TYPE_SHORT,
+ MysqlDefs.FIELD_TYPE_LONG,
+ MysqlDefs.FIELD_TYPE_LONGLONG,
+ MysqlDefs.FIELD_TYPE_FLOAT });
+ }
+
String stringVal = getString(columnIndex);
- if ((stringVal != null) && (stringVal.length() > 0)) {
- int c = Character.toLowerCase(stringVal.charAt(0));
+ return getBooleanFromString(stringVal, columnIndex);
+ }
+ }
- return ((c == 't') || (c == 'y') || (c == '1') || stringVal
- .equals("-1"));
- }
+ private boolean byteArrayToBoolean(int columnIndexMinusOne) {
+ if (this.thisRow[columnIndexMinusOne] == null) {
+ this.wasNullFlag = true;
return false;
}
- return getNativeBoolean(columnIndex);
+ this.wasNullFlag = false;
+
+ if (((byte[]) this.thisRow[columnIndexMinusOne]).length == 0) {
+ return false;
+ }
+
+ byte boolVal = ((byte[]) this.thisRow[columnIndexMinusOne])[0];
+
+ return (boolVal == -1 || boolVal > 0);
}
/**
@@ -2607,6 +2663,10 @@
* if a database access error occurs
*/
public long getLong(int columnIndex) throws SQLException {
+ return getLong(columnIndex, true);
+ }
+
+ private long getLong(int columnIndex, boolean overflowCheck) throws SQLException {
if (!this.isBinaryEncoded) {
checkRowPos();
@@ -2654,7 +2714,7 @@
if (!needsFullParse) {
try {
return parseLongWithOverflowCheck(columnIndex,
- longAsBytes, null);
+ longAsBytes, null, overflowCheck);
} catch (NumberFormatException nfe) {
try {
// To do: Warn of over/underflow???
@@ -2690,7 +2750,7 @@
if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) {
return parseLongWithOverflowCheck(columnIndex, null,
- val);
+ val, overflowCheck);
}
// Convert floating point
@@ -2713,7 +2773,7 @@
}
}
- return getNativeLong(columnIndex);
+ return getNativeLong(columnIndex, overflowCheck, true);
}
/**
@@ -2741,7 +2801,7 @@
}
if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) {
- return parseLongWithOverflowCheck(columnIndex, null, val);
+ return parseLongWithOverflowCheck(columnIndex, null, val, true);
}
// Convert floating point
@@ -2778,7 +2838,8 @@
public java.sql.ResultSetMetaData getMetaData() throws SQLException {
checkClosed();
- return new com.mysql.jdbc.ResultSetMetaData(this.fields);
+ return new com.mysql.jdbc.ResultSetMetaData(this.fields,
+ this.connection.getUseOldAliasMetadataBehavior());
}
/**
@@ -2979,78 +3040,6 @@
}
/**
- * Get the value of a column in the current row as a Java boolean
- *
- * @param columnIndex
- * the first column is 1, the second is 2...
- *
- * @return the column value, false for SQL NULL
- *
- * @exception SQLException
- * if a database access error occurs
- */
- protected boolean getNativeBoolean(int columnIndex) throws SQLException {
- int columnIndexMinusOne = columnIndex - 1;
-
- Field field = this.fields[columnIndexMinusOne];
-
- if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
- if (this.thisRow[columnIndexMinusOne] == null) {
- this.wasNullFlag = true;
-
- return false;
- }
-
- this.wasNullFlag = false;
-
- if (((byte[]) this.thisRow[columnIndexMinusOne]).length == 0) {
- return false;
- }
-
- byte boolVal = ((byte[]) this.thisRow[columnIndexMinusOne])[0];
-
- return (boolVal == -1 || boolVal > 0);
-
- }
-
- this.wasNullFlag = false;
-
- switch (field.getSQLType()) {
- case Types.BIT:
- case Types.BOOLEAN:
- case Types.TINYINT:
- case Types.SMALLINT:
- case Types.INTEGER:
- case Types.BIGINT:
- case Types.DECIMAL:
- case Types.NUMERIC:
- case Types.REAL:
- case Types.FLOAT:
- case Types.DOUBLE:
- byte boolVal = getNativeByte(columnIndex);
-
- return (boolVal == -1 || boolVal > 0);
- default:
- if (this.useUsageAdvisor) {
- issueConversionViaParsingWarning("getBoolean()", columnIndex,
- this.thisRow[columnIndex], this.fields[columnIndex],
- new int[] {
- MysqlDefs.FIELD_TYPE_BIT,
- MysqlDefs.FIELD_TYPE_DOUBLE,
- MysqlDefs.FIELD_TYPE_TINY,
- MysqlDefs.FIELD_TYPE_SHORT,
- MysqlDefs.FIELD_TYPE_LONG,
- MysqlDefs.FIELD_TYPE_LONGLONG,
- MysqlDefs.FIELD_TYPE_FLOAT });
- }
-
- String stringVal = getNativeConvertToString(columnIndex, field);
-
- return getBooleanFromString(stringVal, columnIndex);
- }
- }
-
- /**
* Get the value of a column in the current row as a Java byte.
*
* @param columnIndex
@@ -3332,7 +3321,7 @@
case Types.BIT:
return String.valueOf(getNumericRepresentationOfSQLBitType(columnIndex));
case Types.BOOLEAN:
- boolean booleanVal = getNativeBoolean(columnIndex);
+ boolean booleanVal = getBoolean(columnIndex);
if (this.wasNullFlag) {
return null;
@@ -6788,7 +6777,7 @@
}
private long parseLongWithOverflowCheck(int columnIndex,
- byte[] valueAsBytes, String valueAsString)
+ byte[] valueAsBytes, String valueAsString, boolean doCheck)
throws NumberFormatException, SQLException {
long longValue = 0;
@@ -6813,9 +6802,9 @@
longValue = Long.parseLong(valueAsString);
}
- if (this.connection.getJdbcCompliantTruncationForReads()) {
- if (longValue == Integer.MIN_VALUE
- || longValue == Integer.MAX_VALUE) {
+ if (doCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+ if (longValue == Long.MIN_VALUE
+ || longValue == Long.MAX_VALUE) {
double valueAsDouble = Double
.parseDouble(valueAsString == null ? new String(
valueAsBytes) : valueAsString);
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java 2006-08-01
05:00:42 UTC (rev 5587)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -78,15 +78,17 @@
}
Field[] fields;
-
+ boolean useOldAliasBehavior = false;
+
/**
* Initialise for a result with a tuple set and a field descriptor set
*
* @param fields
* the array of field descriptors
*/
- public ResultSetMetaData(Field[] fields) {
+ public ResultSetMetaData(Field[] fields, boolean useOldAliasBehavior) {
this.fields = fields;
+ this.useOldAliasBehavior = useOldAliasBehavior;
}
/**
@@ -224,6 +226,10 @@
* if a database access error occurs
*/
public String getColumnLabel(int column) throws SQLException {
+ if (this.useOldAliasBehavior) {
+ return getColumnName(column);
+ }
+
return getField(column).getColumnLabel();
}
@@ -239,7 +245,17 @@
* if a databvase access error occurs
*/
public String getColumnName(int column) throws SQLException {
- return getField(column).getNameNoAliases();
+ if (this.useOldAliasBehavior) {
+ return getField(column).getName();
+ }
+
+ String name = getField(column).getNameNoAliases();
+
+ if (name != null && name.length() == 0) {
+ return getField(column).getName();
+ }
+
+ return name;
}
/**
@@ -479,6 +495,10 @@
* if a database access error occurs
*/
public String getTableName(int column) throws SQLException {
+ if (this.useOldAliasBehavior) {
+ return getField(column).getTableName();
+ }
+
return getField(column).getTableNameNoAliases();
}
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-08-01
05:00:42 UTC (rev 5587)
+++
branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -825,7 +825,8 @@
return null;
}
- return new ResultSetMetaData(this.resultFields);
+ return new ResultSetMetaData(this.resultFields,
+ this.connection.getUseOldAliasMetadataBehavior());
}
/**
Modified:
branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java
===================================================================
---
branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-08-01
05:00:42 UTC (rev 5587)
+++
branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -25,6 +25,7 @@
package testsuite.regression;
import java.io.Reader;
+import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
@@ -3503,4 +3504,215 @@
closeMemberJDBCResources();
}
}
+
+ public void testBooleans() throws Exception {
+ if (versionMeetsMinimum(5, 0)) {
+ try {
+ createTable("testBooleans",
+ "(ob int, field1 BOOLEAN, field2 TINYINT, field3 SMALLINT, field4 INT, field5
MEDIUMINT, field6 BIGINT, field7 FLOAT, field8 DOUBLE, field9 DECIMAL, field10
VARCHAR(32), field11 BINARY(3), field12 VARBINARY(3), field13 BLOB)");
+ this.pstmt = this.conn
+ .prepareStatement("INSERT INTO testBooleans VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?)");
+
+ this.pstmt.setInt(1, 1);
+ this.pstmt.setBoolean(2, false);
+ this.pstmt.setByte(3, (byte)0);
+ this.pstmt.setInt(4, 0);
+ this.pstmt.setInt(5, 0);
+ this.pstmt.setInt(6, 0);
+ this.pstmt.setLong(7, 0);
+ this.pstmt.setFloat(8, 0);
+ this.pstmt.setDouble(9, 0);
+ this.pstmt.setBigDecimal(10, new BigDecimal("0"));
+ this.pstmt.setString(11, "false");
+ this.pstmt.setBytes(12, new byte[] { 0 });
+ this.pstmt.setBytes(13, new byte[] { 0 });
+ this.pstmt.setBytes(14, new byte[] { 0 });
+
+ this.pstmt.executeUpdate();
+
+ this.pstmt.setInt(1, 2);
+ this.pstmt.setBoolean(2, true);
+ this.pstmt.setByte(3, (byte)1);
+ this.pstmt.setInt(4, 1);
+ this.pstmt.setInt(5, 1);
+ this.pstmt.setInt(6, 1);
+ this.pstmt.setLong(7, 1);
+ this.pstmt.setFloat(8, 1);
+ this.pstmt.setDouble(9, 1);
+ this.pstmt.setBigDecimal(10, new BigDecimal("1"));
+ this.pstmt.setString(11, "true");
+ this.pstmt.setBytes(12, new byte[] { 1 });
+ this.pstmt.setBytes(13, new byte[] { 1 });
+ this.pstmt.setBytes(14, new byte[] { 1 });
+ this.pstmt.executeUpdate();
+
+ this.pstmt.setInt(1, 3);
+ this.pstmt.setBoolean(2, true);
+ this.pstmt.setByte(3, (byte)1);
+ this.pstmt.setInt(4, 1);
+ this.pstmt.setInt(5, 1);
+ this.pstmt.setInt(6, 1);
+ this.pstmt.setLong(7, 1);
+ this.pstmt.setFloat(8, 1);
+ this.pstmt.setDouble(9, 1);
+ this.pstmt.setBigDecimal(10, new BigDecimal("1"));
+ this.pstmt.setString(11, "true");
+ this.pstmt.setBytes(12, new byte[] { 2 });
+ this.pstmt.setBytes(13, new byte[] { 2 });
+ this.pstmt.setBytes(14, new byte[] { 2 });
+ this.pstmt.executeUpdate();
+
+ this.pstmt.setInt(1, 4);
+ this.pstmt.setBoolean(2, true);
+ this.pstmt.setByte(3, (byte)1);
+ this.pstmt.setInt(4, 1);
+ this.pstmt.setInt(5, 1);
+ this.pstmt.setInt(6, 1);
+ this.pstmt.setLong(7, 1);
+ this.pstmt.setFloat(8, 1);
+ this.pstmt.setDouble(9, 1);
+ this.pstmt.setBigDecimal(10, new BigDecimal("1"));
+ this.pstmt.setString(11, "true");
+ this.pstmt.setBytes(12, new byte[] { -1 });
+ this.pstmt.setBytes(13, new byte[] { -1 });
+ this.pstmt.setBytes(14, new byte[] { -1 });
+ this.pstmt.executeUpdate();
+
+ this.pstmt.setInt(1, 5);
+ this.pstmt.setBoolean(2, false);
+ this.pstmt.setByte(3, (byte)0);
+ this.pstmt.setInt(4, 0);
+ this.pstmt.setInt(5, 0);
+ this.pstmt.setInt(6, 0);
+ this.pstmt.setLong(7, 0);
+ this.pstmt.setFloat(8, 0);
+ this.pstmt.setDouble(9, 0);
+ this.pstmt.setBigDecimal(10, new BigDecimal("0"));
+ this.pstmt.setString(11, "false");
+ this.pstmt.setBytes(12, new byte[] { 0, 0 });
+ this.pstmt.setBytes(13, new byte[] { 0, 0 });
+ this.pstmt.setBytes(14, new byte[] { 0, 0 });
+ this.pstmt.executeUpdate();
+
+ this.pstmt.setInt(1, 6);
+ this.pstmt.setBoolean(2, true);
+ this.pstmt.setByte(3, (byte)1);
+ this.pstmt.setInt(4, 1);
+ this.pstmt.setInt(5, 1);
+ this.pstmt.setInt(6, 1);
+ this.pstmt.setLong(7, 1);
+ this.pstmt.setFloat(8, 1);
+ this.pstmt.setDouble(9, 1);
+ this.pstmt.setBigDecimal(10, new BigDecimal("1"));
+ this.pstmt.setString(11, "true");
+ this.pstmt.setBytes(12, new byte[] { 1, 0 });
+ this.pstmt.setBytes(13, new byte[] { 1, 0 });
+ this.pstmt.setBytes(14, new byte[] { 1, 0 });
+ this.pstmt.executeUpdate();
+
+ this.pstmt.setInt(1, 7);
+ this.pstmt.setBoolean(2, false);
+ this.pstmt.setByte(3, (byte)0);
+ this.pstmt.setInt(4, 0);
+ this.pstmt.setInt(5, 0);
+ this.pstmt.setInt(6, 0);
+ this.pstmt.setLong(7, 0);
+ this.pstmt.setFloat(8, 0);
+ this.pstmt.setDouble(9, 0);
+ this.pstmt.setBigDecimal(10, new BigDecimal("0"));
+ this.pstmt.setString(11, "");
+ this.pstmt.setBytes(12, new byte[] {});
+ this.pstmt.setBytes(13, new byte[] {});
+ this.pstmt.setBytes(14, new byte[] {});
+ this.pstmt.executeUpdate();
+
+ this.rs = this.stmt
+ .executeQuery("SELECT field1, field2, field3, field4, field5, field6, field7,
field8, field9, field10, field11, field12, field13 FROM testBooleans ORDER BY ob");
+
+ boolean[] testVals = new boolean[] { false, true, true, true,
+ false, true, false };
+
+ int i = 0;
+
+ while (this.rs.next()) {
+ for (int j = 0; j > 13; j++) {
+ assertEquals("For field_" + (j + 1) + ", row " + (i + 1), testVals[i], this.rs
+ .getBoolean(j + 1));
+ }
+
+ i++;
+ }
+
+ this.rs = this.conn
+ .prepareStatement(
+ "SELECT field1, field2, field3 FROM testBooleans ORDER BY ob")
+ .executeQuery();
+
+ i = 0;
+
+ while (this.rs.next()) {
+ for (int j = 0; j > 13; j++) {
+ assertEquals("For field_" + (j + 1) + ", row " + (i + 1), testVals[i], this.rs
+ .getBoolean(j + 1));
+ }
+
+ i++;
+ }
+ } finally {
+ closeMemberJDBCResources();
+ }
+ }
+ }
+
+ /**
+ * Tests fix(es) for BUG#21379 - column names don't match metadata
+ * in cases where server doesn't return original column names (functions)
+ * thus breaking compatibility with applications that expect 1-1 mappings
+ * between findColumn() and rsmd.getColumnName().
+ *
+ * @throws Exception if the test fails.
+ */
+ public void testBug21379() throws Exception {
+ try {
+ //
+ // Test the 1-1 mapping between rs.findColumn() and rsmd.getColumnName()
+ // in the case where original column names are not returned,
+ // thus preserving pre-C/J 5.0 behavior for these cases
+ //
+
+ this.rs = this.stmt.executeQuery("SELECT LAST_INSERT_ID() AS id");
+ this.rs.next();
+ assertEquals("id", this.rs.getMetaData().getColumnName(1));
+ assertEquals(1, this.rs.findColumn("id"));
+
+ if (versionMeetsMinimum(4, 1)) {
+ //
+ // test complete emulation of C/J 3.1 and earlier behavior
+ // through configuration option
+ //
+
+ createTable("testBug21379", "(field1 int)");
+ Connection legacyConn = null;
+ Statement legacyStmt = null;
+
+ try {
+ Properties props = new Properties();
+ props.setProperty("", "true");
+ legacyConn = getConnectionWithProps(props);
+ legacyStmt = legacyConn.createStatement();
+
+ this.rs = legacyStmt.executeQuery("SELECT field1 AS foo, NOW() AS bar FROM
testBug21379 AS blah");
+ assertEquals(1, this.rs.findColumn("foo"));
+ assertEquals(2, this.rs.findColumn("bar"));
+ assertEquals("testBug21379", this.rs.getMetaData().getTableName(1));
+ } finally {
+ if (legacyConn != null) {
+ legacyConn.close();
+ }
+ }
+ }
+ } finally {
+ closeMemberJDBCResources();
+ }
+ }
}
Modified: trunk/connector-j/CHANGES
===================================================================
--- trunk/connector-j/CHANGES 2006-08-01 05:00:42 UTC (rev 5587)
+++ trunk/connector-j/CHANGES 2006-08-01 05:14:40 UTC (rev 5588)
@@ -1,6 +1,14 @@
# Changelog
# $Id$
+nn-nn-06 - Version 5.0.4
+
+ - Fixed BUG#21379 - column names don't match metadata in cases
+ where server doesn't return original column names (column functions)
+ thus breaking compatibility with applications that expect 1-1 mappings
+ between findColumn() and rsmd.getColumnName(), usually manifests itself
+ as "Can't find column ('')" exceptions.
+
07-26-06 - Version 5.0.3
- Fixed BUG#20650 - Statement.cancel() causes NullPointerException
Modified: trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2006-08-01 05:00:42 UTC
(rev 5587)
+++ trunk/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2006-08-01 05:14:40 UTC
(rev 5588)
@@ -1316,6 +1316,16 @@
+ " by Connection.setAutoCommit() and Connection.setTransactionIsolation(), rather
than querying the database?",
"3.1.7", PERFORMANCE_CATEGORY, Integer.MIN_VALUE);
+ private BooleanConnectionProperty useOldAliasMetadataBehavior = new
BooleanConnectionProperty(
+ "useOldAliasMetadataBehavior",
+ false,
+ "Should the driver use the legacy behavior for \"AS\" clauses on columns and tables,
and only "
+ + "return aliases (if any) for ResultSetMetaData.getColumnName() or
ResultSetMetaData.getTableName() "
+ + "rather than the original column/table name?",
+ "5.0.4",
+ MISC_CATEGORY,
+ Integer.MIN_VALUE);
+
private BooleanConnectionProperty useOldUTF8Behavior = new BooleanConnectionProperty(
"useOldUTF8Behavior",
false,
@@ -3738,5 +3748,11 @@
this.noAccessToProcedureBodies.setValue(flag);
}
+ public boolean getUseOldAliasMetadataBehavior() {
+ return this.useOldAliasMetadataBehavior.getValueAsBoolean();
+ }
+ public void setUseOldAliasMetadataBehavior(boolean flag) {
+ this.useOldAliasMetadataBehavior.setValue(flag);
+ }
}
Modified: trunk/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java 2006-08-01 05:00:42
UTC (rev 5587)
+++ trunk/connector-j/src/com/mysql/jdbc/MysqlParameterMetadata.java 2006-08-01 05:14:40
UTC (rev 5588)
@@ -33,7 +33,7 @@
MysqlParameterMetadata(Field[] fieldInfo, int parameterCount) {
- this.metadata = new ResultSetMetaData(fieldInfo);
+ this.metadata = new ResultSetMetaData(fieldInfo, false);
this.parameterCount = parameterCount;
}
Modified: trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2006-08-01 05:00:42 UTC
(rev 5587)
+++ trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2006-08-01 05:14:40 UTC
(rev 5588)
@@ -1807,7 +1807,8 @@
this.pstmtResultMetaData = mdRs.getMetaData();
} else {
this.pstmtResultMetaData = new ResultSetMetaData(
- new Field[0]);
+ new Field[0],
+ this.connection.getUseOldAliasMetadataBehavior());
}
} finally {
SQLException sqlExRethrow = null;
Modified: trunk/connector-j/src/com/mysql/jdbc/ResultSet.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-08-01 05:00:42 UTC (rev 5587)
+++ trunk/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-08-01 05:14:40 UTC (rev 5588)
@@ -1444,49 +1444,105 @@
* if a database access error occurs
*/
public boolean getBoolean(int columnIndex) throws SQLException {
- if (!this.isBinaryEncoded) {
- checkColumnBounds(columnIndex);
+
+ checkColumnBounds(columnIndex);
- //
- // MySQL 5.0 and newer have an actual BIT type,
- // so we need to check for that here...
- //
+ //
+ // MySQL 5.0 and newer have an actual BIT type,
+ // so we need to check for that here...
+ //
- int columnIndexMinusOne = columnIndex - 1;
+ int columnIndexMinusOne = columnIndex - 1;
- Field field = this.fields[columnIndexMinusOne];
+ Field field = this.fields[columnIndexMinusOne];
- if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
- if (this.thisRow[columnIndexMinusOne] == null) {
- this.wasNullFlag = true;
+ if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
+ return byteArrayToBoolean(columnIndexMinusOne);
+ }
- return false;
- }
+ this.wasNullFlag = false;
+
+ int sqlType = field.getSQLType();
+
+ switch (sqlType) {
+ case Types.BIT:
+ case Types.BOOLEAN:
+ case Types.TINYINT:
+ case Types.SMALLINT:
+ case Types.INTEGER:
+ case Types.BIGINT:
+ case Types.DECIMAL:
+ case Types.NUMERIC:
+ case Types.REAL:
+ case Types.FLOAT:
+ case Types.DOUBLE:
+ long boolVal = getLong(columnIndex, false);
- this.wasNullFlag = false;
-
- if (((byte[]) this.thisRow[columnIndexMinusOne]).length == 0) {
- return false;
+ return (boolVal == -1 || boolVal > 0);
+ default:
+ if (this.connection.getPedantic()) {
+ // Table B-6 from JDBC spec
+ switch (sqlType) {
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ case Types.DATE:
+ case Types.TIME:
+ case Types.TIMESTAMP:
+ case Types.CLOB:
+ case Types.BLOB:
+ case Types.ARRAY:
+ case Types.REF:
+ case Types.DATALINK:
+ case Types.STRUCT:
+ case Types.JAVA_OBJECT:
+ throw SQLError.createSQLException("Required type conversion not allowed",
+ SQLError.SQL_STATE_INVALID_CHARACTER_VALUE_FOR_CAST);
}
-
- byte boolVal = ((byte[]) this.thisRow[columnIndexMinusOne])[0];
-
- return (boolVal > 0);
}
-
+
+ if (sqlType == Types.BINARY ||
+ sqlType == Types.VARBINARY ||
+ sqlType == Types.LONGVARBINARY ||
+ sqlType == Types.BLOB) {
+ return byteArrayToBoolean(columnIndexMinusOne);
+ }
+
+ if (this.useUsageAdvisor) {
+ issueConversionViaParsingWarning("getBoolean()", columnIndex,
+ this.thisRow[columnIndex], this.fields[columnIndex],
+ new int[] {
+ MysqlDefs.FIELD_TYPE_BIT,
+ MysqlDefs.FIELD_TYPE_DOUBLE,
+ MysqlDefs.FIELD_TYPE_TINY,
+ MysqlDefs.FIELD_TYPE_SHORT,
+ MysqlDefs.FIELD_TYPE_LONG,
+ MysqlDefs.FIELD_TYPE_LONGLONG,
+ MysqlDefs.FIELD_TYPE_FLOAT });
+ }
+
String stringVal = getString(columnIndex);
- if ((stringVal != null) && (stringVal.length() > 0)) {
- int c = Character.toLowerCase(stringVal.charAt(0));
+ return getBooleanFromString(stringVal, columnIndex);
+ }
+ }
- return ((c == 't') || (c == 'y') || (c == '1') || stringVal
- .equals("-1"));
- }
+ private boolean byteArrayToBoolean(int columnIndexMinusOne) {
+ if (this.thisRow[columnIndexMinusOne] == null) {
+ this.wasNullFlag = true;
return false;
}
- return getNativeBoolean(columnIndex);
+ this.wasNullFlag = false;
+
+ if (((byte[]) this.thisRow[columnIndexMinusOne]).length == 0) {
+ return false;
+ }
+
+ byte boolVal = ((byte[]) this.thisRow[columnIndexMinusOne])[0];
+
+ return (boolVal == -1 || boolVal > 0);
}
/**
@@ -2607,6 +2663,10 @@
* if a database access error occurs
*/
public long getLong(int columnIndex) throws SQLException {
+ return getLong(columnIndex, true);
+ }
+
+ private long getLong(int columnIndex, boolean overflowCheck) throws SQLException {
if (!this.isBinaryEncoded) {
checkRowPos();
@@ -2654,7 +2714,7 @@
if (!needsFullParse) {
try {
return parseLongWithOverflowCheck(columnIndex,
- longAsBytes, null);
+ longAsBytes, null, overflowCheck);
} catch (NumberFormatException nfe) {
try {
// To do: Warn of over/underflow???
@@ -2690,7 +2750,7 @@
if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) {
return parseLongWithOverflowCheck(columnIndex, null,
- val);
+ val, overflowCheck);
}
// Convert floating point
@@ -2713,7 +2773,7 @@
}
}
- return getNativeLong(columnIndex);
+ return getNativeLong(columnIndex, overflowCheck, true);
}
/**
@@ -2741,7 +2801,7 @@
}
if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) {
- return parseLongWithOverflowCheck(columnIndex, null, val);
+ return parseLongWithOverflowCheck(columnIndex, null, val, true);
}
// Convert floating point
@@ -2778,7 +2838,8 @@
public java.sql.ResultSetMetaData getMetaData() throws SQLException {
checkClosed();
- return new com.mysql.jdbc.ResultSetMetaData(this.fields);
+ return new com.mysql.jdbc.ResultSetMetaData(this.fields,
+ this.connection.getUseOldAliasMetadataBehavior());
}
/**
@@ -2998,78 +3059,6 @@
}
/**
- * Get the value of a column in the current row as a Java boolean
- *
- * @param columnIndex
- * the first column is 1, the second is 2...
- *
- * @return the column value, false for SQL NULL
- *
- * @exception SQLException
- * if a database access error occurs
- */
- protected boolean getNativeBoolean(int columnIndex) throws SQLException {
- int columnIndexMinusOne = columnIndex - 1;
-
- Field field = this.fields[columnIndexMinusOne];
-
- if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
- if (this.thisRow[columnIndexMinusOne] == null) {
- this.wasNullFlag = true;
-
- return false;
- }
-
- this.wasNullFlag = false;
-
- if (((byte[]) this.thisRow[columnIndexMinusOne]).length == 0) {
- return false;
- }
-
- byte boolVal = ((byte[]) this.thisRow[columnIndexMinusOne])[0];
-
- return (boolVal == -1 || boolVal > 0);
-
- }
-
- this.wasNullFlag = false;
-
- switch (field.getSQLType()) {
- case Types.BIT:
- case Types.BOOLEAN:
- case Types.TINYINT:
- case Types.SMALLINT:
- case Types.INTEGER:
- case Types.BIGINT:
- case Types.DECIMAL:
- case Types.NUMERIC:
- case Types.REAL:
- case Types.FLOAT:
- case Types.DOUBLE:
- byte boolVal = getNativeByte(columnIndex);
-
- return (boolVal == -1 || boolVal > 0);
- default:
- if (this.useUsageAdvisor) {
- issueConversionViaParsingWarning("getBoolean()", columnIndex,
- this.thisRow[columnIndex], this.fields[columnIndex],
- new int[] {
- MysqlDefs.FIELD_TYPE_BIT,
- MysqlDefs.FIELD_TYPE_DOUBLE,
- MysqlDefs.FIELD_TYPE_TINY,
- MysqlDefs.FIELD_TYPE_SHORT,
- MysqlDefs.FIELD_TYPE_LONG,
- MysqlDefs.FIELD_TYPE_LONGLONG,
- MysqlDefs.FIELD_TYPE_FLOAT });
- }
-
- String stringVal = getNativeConvertToString(columnIndex, field);
-
- return getBooleanFromString(stringVal, columnIndex);
- }
- }
-
- /**
* Get the value of a column in the current row as a Java byte.
*
* @param columnIndex
@@ -3351,7 +3340,7 @@
case Types.BIT:
return String.valueOf(getNumericRepresentationOfSQLBitType(columnIndex));
case Types.BOOLEAN:
- boolean booleanVal = getNativeBoolean(columnIndex);
+ boolean booleanVal = getBoolean(columnIndex);
if (this.wasNullFlag) {
return null;
@@ -6807,7 +6796,7 @@
}
private long parseLongWithOverflowCheck(int columnIndex,
- byte[] valueAsBytes, String valueAsString)
+ byte[] valueAsBytes, String valueAsString, boolean doCheck)
throws NumberFormatException, SQLException {
long longValue = 0;
@@ -6832,9 +6821,9 @@
longValue = Long.parseLong(valueAsString);
}
- if (this.connection.getJdbcCompliantTruncationForReads()) {
- if (longValue == Integer.MIN_VALUE
- || longValue == Integer.MAX_VALUE) {
+ if (doCheck && this.connection.getJdbcCompliantTruncationForReads()) {
+ if (longValue == Long.MIN_VALUE
+ || longValue == Long.MAX_VALUE) {
double valueAsDouble = Double
.parseDouble(valueAsString == null ? new String(
valueAsBytes) : valueAsString);
Modified: trunk/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java 2006-08-01 05:00:42 UTC
(rev 5587)
+++ trunk/connector-j/src/com/mysql/jdbc/ResultSetMetaData.java 2006-08-01 05:14:40 UTC
(rev 5588)
@@ -75,6 +75,7 @@
}
Field[] fields;
+ boolean useOldAliasBehavior = false;
/**
* Initialise for a result with a tuple set and a field descriptor set
@@ -82,8 +83,9 @@
* @param fields
* the array of field descriptors
*/
- public ResultSetMetaData(Field[] fields) {
+ public ResultSetMetaData(Field[] fields, boolean useOldAliasBehavior) {
this.fields = fields;
+ this.useOldAliasBehavior = useOldAliasBehavior;
}
/**
@@ -221,6 +223,10 @@
* if a database access error occurs
*/
public String getColumnLabel(int column) throws SQLException {
+ if (this.useOldAliasBehavior) {
+ return getColumnName(column);
+ }
+
return getField(column).getColumnLabel();
}
@@ -236,9 +242,19 @@
* if a databvase access error occurs
*/
public String getColumnName(int column) throws SQLException {
- return getField(column).getNameNoAliases();
+ if (this.useOldAliasBehavior) {
+ return getField(column).getName();
}
+ String name = getField(column).getNameNoAliases();
+
+ if (name != null && name.length() == 0) {
+ return getField(column).getName();
+ }
+
+ return name;
+ }
+
/**
* What is a column's SQL Type? (java.sql.Type int)
*
@@ -476,6 +492,10 @@
* if a database access error occurs
*/
public String getTableName(int column) throws SQLException {
+ if (this.useOldAliasBehavior) {
+ return getField(column).getTableName();
+ }
+
return getField(column).getTableNameNoAliases();
}
Modified: trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-08-01 05:00:42
UTC (rev 5587)
+++ trunk/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-08-01 05:14:40
UTC (rev 5588)
@@ -821,7 +821,8 @@
return null;
}
- return new ResultSetMetaData(this.resultFields);
+ return new ResultSetMetaData(this.resultFields,
+ this.connection.getUseOldAliasMetadataBehavior());
}
/**
Modified: trunk/connector-j/src/testsuite/regression/ResultSetRegressionTest.java
===================================================================
--- trunk/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-08-01
05:00:42 UTC (rev 5587)
+++ trunk/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-08-01
05:14:40 UTC (rev 5588)
@@ -3503,4 +3503,56 @@
closeMemberJDBCResources();
}
}
+
+ /**
+ * Tests fix(es) for BUG#21379 - column names don't match metadata
+ * in cases where server doesn't return original column names (functions)
+ * thus breaking compatibility with applications that expect 1-1 mappings
+ * between findColumn() and rsmd.getColumnName().
+ *
+ * @throws Exception if the test fails.
+ */
+ public void testBug21379() throws Exception {
+ try {
+ //
+ // Test the 1-1 mapping between rs.findColumn() and rsmd.getColumnName()
+ // in the case where original column names are not returned,
+ // thus preserving pre-C/J 5.0 behavior for these cases
+ //
+
+ this.rs = this.stmt.executeQuery("SELECT LAST_INSERT_ID() AS id");
+ this.rs.next();
+ assertEquals("id", this.rs.getMetaData().getColumnName(1));
+ assertEquals(1, this.rs.findColumn("id"));
+
+ if (versionMeetsMinimum(4, 1)) {
+ //
+ // test complete emulation of C/J 3.1 and earlier behavior
+ // through configuration option
+ //
+
+ createTable("testBug21379", "(field1 int)");
+ Connection legacyConn = null;
+ Statement legacyStmt = null;
+
+ try {
+ Properties props = new Properties();
+ props.setProperty("", "true");
+ legacyConn = getConnectionWithProps(props);
+ legacyStmt = legacyConn.createStatement();
+
+ this.rs = legacyStmt.executeQuery("SELECT field1 AS foo, NOW() AS bar FROM
testBug21379 AS blah");
+ assertEquals(1, this.rs.findColumn("foo"));
+ assertEquals(2, this.rs.findColumn("bar"));
+ assertEquals("testBug21379", this.rs.getMetaData().getTableName(1));
+ } finally {
+ if (legacyConn != null) {
+ legacyConn.close();
+ }
+ }
+ }
+ } finally {
+ closeMemberJDBCResources();
+ }
+ }
}
| Thread |
|---|
| • Connector/J commit: r5588 - branches/branch_5_0/connector-j branches/branch_5_0/connector-j/src/com/mysql/jdbc branches/branch_5_0/connector-j/src/tes... | mmatthews | 1 Aug |