From: Date: June 16 2006 11:50pm Subject: Connector/J commit: r5403 - in branches: branch_3_1/connector-j branch_3_1/connector-j/src/com/mysql/jdbc branch_3_1/connector-j/src/testsuite/regression branch_5_0/connector-j branch_5_0/connector-j/src/com/mysql/jdbc branch_5_0/connector-j/src/testsuite/regression branch_5_1/connector-j branch_5_1/connector-j/src/com/mysql/jdbc branch_5_1/connector-j/src/testsuite branch_5_1/connector-j/src/testsuite/regression List-Archive: http://lists.mysql.com/commits/7786 X-Bug: 20306 Message-Id: <200606162150.k5GLo77m022557@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/branch_3_1/connector-j/CHANGES branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java branches/branch_5_0/connector-j/CHANGES branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java branches/branch_5_1/connector-j/CHANGES branches/branch_5_1/connector-j/src/com/mysql/jdbc/ResultSet.java branches/branch_5_1/connector-j/src/testsuite/BaseTestCase.java branches/branch_5_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java Log: - Fixed BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT returns incorrect values when using server-side prepared statements. Modified: branches/branch_3_1/connector-j/CHANGES =================================================================== --- branches/branch_3_1/connector-j/CHANGES 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_3_1/connector-j/CHANGES 2006-06-16 21:50:01 UTC (rev 5403) @@ -17,6 +17,9 @@ - Fixed BUG#16791 - NullPointerException in MysqlDataSourceFactory due to Reference containing RefAddrs with null content. + - Fixed BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT + returns incorrect values when using server-side prepared statements. + 05-26-06 - Version 3.1.13 - Fixed BUG#15464 - INOUT parameter does not store IN value. Modified: branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java =================================================================== --- branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_3_1/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -3527,7 +3527,9 @@ this.wasNullFlag = false; - switch (this.fields[columnIndex].getMysqlType()) { + Field f= this.fields[columnIndex]; + + switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_DOUBLE: byte[] bits = (byte[]) this.thisRow[columnIndex]; @@ -3542,15 +3544,37 @@ return Double.longBitsToDouble(valueAsLong); case MysqlDefs.FIELD_TYPE_TINY: - return (double) getNativeByte(columnIndex + 1); + if (!f.isUnsigned()) { + return (double) getNativeByte(columnIndex + 1); + } + + return (double) getNativeShort(columnIndex + 1); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: - return (double) getNativeShort(columnIndex + 1); + if (!f.isUnsigned()) { + return (double) getNativeShort(columnIndex + 1); + } + + return (double) getNativeInt(columnIndex + 1); case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: - return (double) getNativeInt(columnIndex + 1); + if (!f.isUnsigned()) { + return (double) getNativeInt(columnIndex + 1); + } + + return (double) getNativeLong(columnIndex + 1); case MysqlDefs.FIELD_TYPE_LONGLONG: - return (double) getNativeLong(columnIndex + 1); + valueAsLong = getNativeLong(columnIndex + 1); + + if (!f.isUnsigned()) { + return (double) valueAsLong; + } + + BigInteger asBigInt = convertLongToUlong(valueAsLong); + + // TODO: Check for overflow + + return asBigInt.doubleValue(); case MysqlDefs.FIELD_TYPE_FLOAT: return (double) getNativeFloat(columnIndex + 1); case MysqlDefs.FIELD_TYPE_BIT: @@ -3599,24 +3623,63 @@ this.wasNullFlag = false; - // TODO: Truncation check - switch (this.fields[columnIndex].getMysqlType()) { + Field f = this.fields[columnIndex]; + + switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_BIT: long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1); return valueAsLong; case MysqlDefs.FIELD_TYPE_DOUBLE: + + // Only foolproof way to check for overflow + // Not efficient, but if you don't want to be inefficient, use the + // correct binding for the type! + + Double valueAsDouble = new Double(getNativeDouble(columnIndex + 1)); + + float valueAsFloat = valueAsDouble.floatValue(); + + if (this.connection.getJdbcCompliantTruncationForReads() && + valueAsFloat == Float.NEGATIVE_INFINITY || + valueAsFloat == Float.POSITIVE_INFINITY) { + throwRangeException(valueAsDouble.toString(), + columnIndex + 1, Types.FLOAT); + } + return (float) getNativeDouble(columnIndex + 1); case MysqlDefs.FIELD_TYPE_TINY: - return (float) getNativeByte(columnIndex + 1); + if (!f.isUnsigned()) { + return (float) getNativeByte(columnIndex + 1); + } + + return (float) getNativeShort(columnIndex + 1); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: - return (float) getNativeShort(columnIndex + 1); + if (!f.isUnsigned()) { + return (float) getNativeShort(columnIndex + 1); + } + + return (float) getNativeInt(columnIndex + 1); case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: - return (float) getNativeInt(columnIndex + 1); + if (!f.isUnsigned()) { + return (float) getNativeInt(columnIndex + 1); + } + + return (float) getNativeLong(columnIndex + 1); case MysqlDefs.FIELD_TYPE_LONGLONG: - return (float) getNativeLong(columnIndex + 1); + valueAsLong = getNativeLong(columnIndex + 1); + + if (!f.isUnsigned()) { + return (float) valueAsLong; + } + + BigInteger asBigInt = convertLongToUlong(valueAsLong); + + // TODO: Check for overflow + + return asBigInt.floatValue(); case MysqlDefs.FIELD_TYPE_FLOAT: byte[] bits = (byte[]) this.thisRow[columnIndex]; @@ -3643,7 +3706,7 @@ return getFloatFromString(stringVal, columnIndex + 1); } } - + /** * JDBC 2.0 Get a REF(<structured-type>) column. * @@ -7899,11 +7962,11 @@ return (short)valueAsLong; case MysqlDefs.FIELD_TYPE_TINY: - byte tinyintVal = getNativeByte(columnIndex + 1); + byte tinyintVal = getNativeByte(columnIndex + 1, false); - if (!f.isUnsigned()) { - return tinyintVal; - } + if (!f.isUnsigned() || tinyintVal >= 0) { + return tinyintVal; + } return (short)(tinyintVal + (short)256); case MysqlDefs.FIELD_TYPE_SHORT: Modified: branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java =================================================================== --- branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_3_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -2483,6 +2483,47 @@ } } + /** + * Tests fix for BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT + * returns incorrect values when using server-side prepared statements. + * + * @throws Exception if the test fails. + */ + public void testBug20306() throws Exception { + createTable("testBug20306", "(field1 TINYINT UNSIGNED, field2 TINYINT UNSIGNED)"); + this.stmt.executeUpdate("INSERT INTO testBug20306 VALUES (2, 133)"); + try { + this.pstmt = this.conn.prepareStatement("SELECT field1, field2 FROM testBug20306"); + this.rs = this.pstmt.executeQuery(); + this.rs.next(); + checkBug20306(); + + this.rs = this.stmt.executeQuery("SELECT field1, field2 FROM testBug20306"); + this.rs.next(); + checkBug20306(); + + } finally { + closeMemberJDBCResources(); + } + } + + private void checkBug20306() throws Exception { + assertEquals(2, this.rs.getByte(1)); + assertEquals(2, this.rs.getInt(1)); + assertEquals(2, this.rs.getShort(1)); + assertEquals(2, this.rs.getLong(1)); + assertEquals(2.0, this.rs.getFloat(1), 0); + assertEquals(2.0, this.rs.getDouble(1), 0); + assertEquals(2, this.rs.getBigDecimal(1).intValue()); + + assertEquals(133, this.rs.getInt(2)); + assertEquals(133, this.rs.getShort(2)); + assertEquals(133, this.rs.getLong(2)); + assertEquals(133.0, this.rs.getFloat(2), 0); + assertEquals(133.0, this.rs.getDouble(2), 0); + assertEquals(133, this.rs.getBigDecimal(2).intValue()); + } + /** * Tests fix for BUG#20479 - Updatable result set throws ClassCastException * when there is row data and moveToInsertRow() is called. Modified: branches/branch_5_0/connector-j/CHANGES =================================================================== --- branches/branch_5_0/connector-j/CHANGES 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_0/connector-j/CHANGES 2006-06-16 21:50:01 UTC (rev 5403) @@ -160,6 +160,9 @@ - Fixed BUG#16791 - NullPointerException in MysqlDataSourceFactory due to Reference containing RefAddrs with null content. + - Fixed BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT + returns incorrect values when using server-side prepared statements. + 05-26-06 - Version 3.1.13 - Fixed BUG#15464 - INOUT parameter does not store IN value. Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -1567,7 +1567,7 @@ if (decimalIndex != -1) { double valueAsDouble = Double.parseDouble(stringVal); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Byte.MIN_VALUE || valueAsDouble > Byte.MAX_VALUE) { throwRangeException(stringVal, columnIndex, @@ -1580,7 +1580,7 @@ long valueAsLong = Long.parseLong(stringVal); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), @@ -2294,13 +2294,17 @@ float f = Float.parseFloat(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (f == Float.MIN_VALUE || f == Float.MAX_VALUE) { - double valAsDouble = Double.parseDouble(val); - if (valAsDouble < Float.MIN_VALUE - || valAsDouble > Float.MAX_VALUE) { - throwRangeException(String.valueOf(valAsDouble), + Double valueAsDouble = new Double(val); + + float valueAsFloat = valueAsDouble.floatValue(); + + if (this.connection.getJdbcCompliantTruncationForReads() && + valueAsFloat == Float.NEGATIVE_INFINITY || + valueAsFloat == Float.POSITIVE_INFINITY) { + throwRangeException(valueAsDouble.toString(), columnIndex, Types.FLOAT); } } @@ -2312,17 +2316,20 @@ return 0; // for NULL } catch (NumberFormatException nfe) { try { - double valAsDouble = Double.parseDouble(val); + Double valueAsDouble = new Double(val); + float valueAsFloat = valueAsDouble.floatValue(); + + if (this.connection.getJdbcCompliantTruncationForReads()) { - if (this.connection.getJdbcCompliantTruncation()) { - if (Math.abs(valAsDouble - Float.MIN_VALUE) > 1 - || Math.abs(valAsDouble - Float.MAX_VALUE) > 1) { - throwRangeException(String.valueOf(valAsDouble), + if (this.connection.getJdbcCompliantTruncationForReads() && + valueAsFloat == Float.NEGATIVE_INFINITY || + valueAsFloat == Float.POSITIVE_INFINITY) { + throwRangeException(valueAsDouble.toString(), columnIndex, Types.FLOAT); } } - return (float) valAsDouble; + return valueAsFloat; } catch (NumberFormatException newNfe) { ; // ignore, it's not a number } @@ -2516,7 +2523,7 @@ int valueAsInt = Integer.parseInt(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsInt == Integer.MIN_VALUE || valueAsInt == Integer.MAX_VALUE) { long valueAsLong = Long.parseLong(val); @@ -2537,7 +2544,7 @@ double valueAsDouble = Double.parseDouble(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -2553,7 +2560,7 @@ try { double valueAsDouble = Double.parseDouble(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3095,7 +3102,7 @@ short valueAsShort = (valueAsByte >= 0) ? valueAsByte : (short)(valueAsByte + (short)256); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsShort > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsShort), columnIndex + 1, Types.TINYINT); @@ -3108,7 +3115,7 @@ case MysqlDefs.FIELD_TYPE_YEAR: valueAsShort = getNativeShort(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsShort < Byte.MIN_VALUE || valueAsShort > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsShort), @@ -3121,7 +3128,7 @@ case MysqlDefs.FIELD_TYPE_LONG: int valueAsInt = getNativeInt(columnIndex + 1, false); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsInt < Byte.MIN_VALUE || valueAsInt > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.TINYINT); @@ -3133,7 +3140,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: float valueAsFloat = getNativeFloat(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsFloat < Byte.MIN_VALUE || valueAsFloat > Byte.MAX_VALUE) { @@ -3147,7 +3154,7 @@ case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Byte.MIN_VALUE || valueAsDouble > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3160,7 +3167,7 @@ case MysqlDefs.FIELD_TYPE_LONGLONG: valueAsLong = getNativeLong(columnIndex + 1, false, true); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), @@ -3791,15 +3798,22 @@ return valueAsLong; case MysqlDefs.FIELD_TYPE_DOUBLE: - double valueAsDouble = getNativeDouble(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation() && - (valueAsDouble < Float.MIN_VALUE || - valueAsDouble > Float.MAX_VALUE)) { - throwRangeException(String.valueOf(valueAsDouble), + // Only foolproof way to check for overflow + // Not efficient, but if you don't want to be inefficient, use the + // correct binding for the type! + + Double valueAsDouble = new Double(getNativeDouble(columnIndex + 1)); + + float valueAsFloat = valueAsDouble.floatValue(); + + if (this.connection.getJdbcCompliantTruncationForReads() && + valueAsFloat == Float.NEGATIVE_INFINITY || + valueAsFloat == Float.POSITIVE_INFINITY) { + throwRangeException(valueAsDouble.toString(), columnIndex + 1, Types.FLOAT); } - + return (float) getNativeDouble(columnIndex + 1); case MysqlDefs.FIELD_TYPE_TINY: if (!f.isUnsigned()) { @@ -3934,7 +3948,7 @@ valueAsLong = (valueAsInt >= 0) ? valueAsInt : valueAsInt + 4294967296L; - if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && valueAsLong > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.INTEGER); @@ -3944,7 +3958,7 @@ case MysqlDefs.FIELD_TYPE_LONGLONG: valueAsLong = getNativeLong(columnIndex + 1, false, true); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), @@ -3956,7 +3970,7 @@ case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3968,7 +3982,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: valueAsDouble = getNativeFloat(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -4075,7 +4089,7 @@ BigInteger asBigInt = convertLongToUlong(valueAsLong); - if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && ((asBigInt.compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0 ) || (asBigInt.compareTo(new BigInteger(String.valueOf(Long.MIN_VALUE))) < 0))) { throwRangeException(asBigInt.toString(), @@ -4087,7 +4101,7 @@ case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -4099,7 +4113,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: valueAsDouble = getNativeFloat(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -4178,12 +4192,12 @@ switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_TINY: - byte tinyintVal = getNativeByte(columnIndex + 1); + byte tinyintVal = getNativeByte(columnIndex + 1, false); - if (!f.isUnsigned()) { - return tinyintVal; + if (!f.isUnsigned() || tinyintVal >= 0) { + return tinyintVal; } - + return (short)(tinyintVal + (short)256); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: @@ -4197,7 +4211,7 @@ int valueAsInt = asShort & 0xffff; - if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && valueAsInt > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.SMALLINT); @@ -4209,7 +4223,7 @@ if (!f.isUnsigned()) { valueAsInt = getNativeInt(columnIndex + 1, false); - if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && valueAsInt > Short.MAX_VALUE || valueAsInt < Short.MIN_VALUE) { throwRangeException(String.valueOf(valueAsInt), @@ -4221,7 +4235,7 @@ long valueAsLong = getNativeLong(columnIndex + 1, false, true); - if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && valueAsLong > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.SMALLINT); @@ -4233,7 +4247,7 @@ valueAsLong = getNativeLong(columnIndex + 1, false, false); if (!f.isUnsigned()) { - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), @@ -4246,7 +4260,7 @@ BigInteger asBigInt = convertLongToUlong(valueAsLong); - if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads() && ((asBigInt.compareTo(new BigInteger(String.valueOf(Short.MAX_VALUE))) > 0 ) || (asBigInt.compareTo(new BigInteger(String.valueOf(Short.MIN_VALUE))) < 0))) { throwRangeException(asBigInt.toString(), @@ -4258,7 +4272,7 @@ case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Short.MIN_VALUE || valueAsDouble > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -4270,7 +4284,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: float valueAsFloat = getNativeFloat(columnIndex + 1); - if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsFloat < Short.MIN_VALUE || valueAsFloat > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsFloat), @@ -6686,7 +6700,7 @@ double valueAsDouble = Double.parseDouble(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex, @@ -6722,7 +6736,7 @@ intValue = Integer.parseInt(valueAsString); } - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (intValue == Integer.MIN_VALUE || intValue == Integer.MAX_VALUE) { long valueAsLong = Long .parseLong(valueAsString == null ? new String( @@ -6748,7 +6762,7 @@ double valueAsDouble = Double.parseDouble(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(val, columnIndex, Types.BIGINT); @@ -6784,7 +6798,7 @@ longValue = Long.parseLong(valueAsString); } - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (longValue == Integer.MIN_VALUE || longValue == Integer.MAX_VALUE) { double valueAsDouble = Double @@ -6811,7 +6825,7 @@ double valueAsDouble = Double.parseDouble(val); - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (valueAsDouble < Short.MIN_VALUE || valueAsDouble > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex, @@ -6848,7 +6862,7 @@ shortValue = Short.parseShort(valueAsString); } - if (this.connection.getJdbcCompliantTruncation()) { + if (this.connection.getJdbcCompliantTruncationForReads()) { if (shortValue == Short.MIN_VALUE || shortValue == Short.MAX_VALUE) { long valueAsLong = Long .parseLong(valueAsString == null ? new String( Modified: branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java =================================================================== --- branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_0/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -3374,4 +3374,45 @@ } } } + + /** + * Tests fix for BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT + * returns incorrect values when using server-side prepared statements. + * + * @throws Exception if the test fails. + */ + public void testBug20306() throws Exception { + createTable("testBug20306", "(field1 TINYINT UNSIGNED, field2 TINYINT UNSIGNED)"); + this.stmt.executeUpdate("INSERT INTO testBug20306 VALUES (2, 133)"); + try { + this.pstmt = this.conn.prepareStatement("SELECT field1, field2 FROM testBug20306"); + this.rs = this.pstmt.executeQuery(); + this.rs.next(); + checkBug20306(); + + this.rs = this.stmt.executeQuery("SELECT field1, field2 FROM testBug20306"); + this.rs.next(); + checkBug20306(); + + } finally { + closeMemberJDBCResources(); + } + } + + private void checkBug20306() throws Exception { + assertEquals(2, this.rs.getByte(1)); + assertEquals(2, this.rs.getInt(1)); + assertEquals(2, this.rs.getShort(1)); + assertEquals(2, this.rs.getLong(1)); + assertEquals(2.0, this.rs.getFloat(1), 0); + assertEquals(2.0, this.rs.getDouble(1), 0); + assertEquals(2, this.rs.getBigDecimal(1).intValue()); + + assertEquals(133, this.rs.getInt(2)); + assertEquals(133, this.rs.getShort(2)); + assertEquals(133, this.rs.getLong(2)); + assertEquals(133.0, this.rs.getFloat(2), 0); + assertEquals(133.0, this.rs.getDouble(2), 0); + assertEquals(133, this.rs.getBigDecimal(2).intValue()); + } } Modified: branches/branch_5_1/connector-j/CHANGES =================================================================== --- branches/branch_5_1/connector-j/CHANGES 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_1/connector-j/CHANGES 2006-06-16 21:50:01 UTC (rev 5403) @@ -134,6 +134,9 @@ - Fixed BUG#16791 - NullPointerException in MysqlDataSourceFactory due to Reference containing RefAddrs with null content. + - Fixed BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT + returns incorrect values when using server-side prepared statements. + 05-26-06 - Version 3.1.13 - Fixed BUG#15464 - INOUT parameter does not store IN value. Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/ResultSet.java =================================================================== --- branches/branch_5_1/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/ResultSet.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -4187,10 +4187,10 @@ switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_TINY: - byte tinyintVal = getNativeByte(columnIndex + 1); + byte tinyintVal = getNativeByte(columnIndex + 1, false); - if (!f.isUnsigned()) { - return tinyintVal; + if (!f.isUnsigned() || tinyintVal >= 0) { + return tinyintVal; } return (short) (tinyintVal + (short) 256); Modified: branches/branch_5_1/connector-j/src/testsuite/BaseTestCase.java =================================================================== --- branches/branch_5_1/connector-j/src/testsuite/BaseTestCase.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_1/connector-j/src/testsuite/BaseTestCase.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -516,4 +516,28 @@ return false; } } + + protected void closeMemberJDBCResources() { + if (this.rs != null) { + ResultSet toClose = this.rs; + this.rs = null; + + try { + toClose.close(); + } catch (SQLException sqlEx) { + // ignore + } + } + + if (this.pstmt != null) { + PreparedStatement toClose = this.pstmt; + this.pstmt = null; + + try { + toClose.close(); + } catch (SQLException sqlEx) { + // ignore + } + } + } } Modified: branches/branch_5_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java =================================================================== --- branches/branch_5_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-06-16 20:58:36 UTC (rev 5402) +++ branches/branch_5_1/connector-j/src/testsuite/regression/ResultSetRegressionTest.java 2006-06-16 21:50:01 UTC (rev 5403) @@ -3072,5 +3072,45 @@ } } } + + /** + * Tests fix for BUG#20306 - ResultSet.getShort() for UNSIGNED TINYINT + * returns incorrect values when using server-side prepared statements. + * + * @throws Exception if the test fails. + */ + public void testBug20306() throws Exception { + createTable("testBug20306", "(field1 TINYINT UNSIGNED, field2 TINYINT UNSIGNED)"); + this.stmt.executeUpdate("INSERT INTO testBug20306 VALUES (2, 133)"); + try { + this.pstmt = this.conn.prepareStatement("SELECT field1, field2 FROM testBug20306"); + this.rs = this.pstmt.executeQuery(); + this.rs.next(); + checkBug20306(); + + this.rs = this.stmt.executeQuery("SELECT field1, field2 FROM testBug20306"); + this.rs.next(); + checkBug20306(); + + } finally { + closeMemberJDBCResources(); + } + } + private void checkBug20306() throws Exception { + assertEquals(2, this.rs.getByte(1)); + assertEquals(2, this.rs.getInt(1)); + assertEquals(2, this.rs.getShort(1)); + assertEquals(2, this.rs.getLong(1)); + assertEquals(2.0, this.rs.getFloat(1), 0); + assertEquals(2.0, this.rs.getDouble(1), 0); + assertEquals(2, this.rs.getBigDecimal(1).intValue()); + + assertEquals(133, this.rs.getInt(2)); + assertEquals(133, this.rs.getShort(2)); + assertEquals(133, this.rs.getLong(2)); + assertEquals(133.0, this.rs.getFloat(2), 0); + assertEquals(133.0, this.rs.getDouble(2), 0); + assertEquals(133, this.rs.getBigDecimal(2).intValue()); + } }