From: mmatthews Date: December 21 2005 10:51pm Subject: Connector/J commit: r4728 - branches/branch_5_0/connector-j/src/com/mysql/jdbc List-Archive: http://lists.mysql.com/commits/342 Message-Id: <200512212251.jBLMpqs8004906@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java Log: Fixups for UNSIGNED values with server-side prepared statements. 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 2005-12-21 01:02:50 UTC (rev 4727) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ResultSet.java 2005-12-21 22:51:50 UTC (rev 4728) @@ -2987,6 +2987,10 @@ * if a database access error occurs */ protected byte getNativeByte(int columnIndex) throws SQLException { + return getNativeByte(columnIndex, true); + } + + protected byte getNativeByte(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); @@ -3019,25 +3023,27 @@ case MysqlDefs.FIELD_TYPE_TINY: byte valueAsByte = ((byte[]) this.thisRow[columnIndex])[0]; - if (!field.isUnsigned() || valueAsByte >= 0) { - short valueAsShort = (short)(valueAsByte + (short)256); - - if (this.connection.getJdbcCompliantTruncation()) { - if (valueAsShort > Byte.MAX_VALUE) { - throwRangeException(String.valueOf(valueAsShort), - columnIndex + 1, Types.TINYINT); - } + if (!field.isUnsigned()) { + return valueAsByte; + } + + short valueAsShort = (valueAsByte >= 0) ? + valueAsByte : (short)(valueAsByte + (short)256); + + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (valueAsShort > Byte.MAX_VALUE) { + throwRangeException(String.valueOf(valueAsShort), + columnIndex + 1, Types.TINYINT); } - - return (byte)valueAsShort; } - return valueAsByte; + return (byte)valueAsShort; + case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: - int valueAsShort = getNativeShort(columnIndex + 1); + valueAsShort = getNativeShort(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsShort < Byte.MIN_VALUE || valueAsShort > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsShort), @@ -3048,9 +3054,9 @@ return (byte) valueAsShort; case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: - int valueAsInt = getNativeInt(columnIndex + 1); + int valueAsInt = getNativeInt(columnIndex + 1, false); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsInt < Byte.MIN_VALUE || valueAsInt > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.TINYINT); @@ -3062,7 +3068,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: float valueAsFloat = getNativeFloat(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsFloat < Byte.MIN_VALUE || valueAsFloat > Byte.MAX_VALUE) { @@ -3076,7 +3082,7 @@ case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsDouble < Byte.MIN_VALUE || valueAsDouble > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3087,9 +3093,9 @@ return (byte) valueAsDouble; case MysqlDefs.FIELD_TYPE_LONGLONG: - long valueAsLong = getNativeLong(columnIndex + 1); + long valueAsLong = getNativeLong(columnIndex + 1, false, true); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), @@ -3248,7 +3254,7 @@ return String.valueOf(booleanVal); case Types.TINYINT: - byte tinyintVal = getNativeByte(columnIndex); + byte tinyintVal = getNativeByte(columnIndex, false); if (this.wasNullFlag) { return null; @@ -3264,7 +3270,7 @@ case Types.SMALLINT: - int intVal = getNativeInt(columnIndex); + int intVal = getNativeInt(columnIndex, false); if (this.wasNullFlag) { return null; @@ -3279,7 +3285,7 @@ return String.valueOf(intVal); case Types.INTEGER: - intVal = getNativeInt(columnIndex); + intVal = getNativeInt(columnIndex, false); if (this.wasNullFlag) { return null; @@ -3298,7 +3304,7 @@ case Types.BIGINT: if (!field.isUnsigned()) { - longVal = getNativeLong(columnIndex); + longVal = getNativeLong(columnIndex, false, true); if (this.wasNullFlag) { return null; @@ -3307,7 +3313,7 @@ return String.valueOf(longVal); } - longVal = getNativeLong(columnIndex); + longVal = getNativeLong(columnIndex, false, false); if (this.wasNullFlag) { return null; @@ -3603,7 +3609,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]; @@ -3618,15 +3626,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); @@ -3674,20 +3704,52 @@ this.wasNullFlag = false; - // TODO: Truncation check - switch (this.fields[columnIndex].getMysqlType()) { + Field f = this.fields[columnIndex]; + + switch (f.getMysqlType()) { 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), + 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); + long 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]; @@ -3727,6 +3789,10 @@ * if a database access error occurs */ protected int getNativeInt(int columnIndex) throws SQLException { + return getNativeInt(columnIndex, false); + } + + protected int getNativeInt(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); @@ -3745,7 +3811,7 @@ switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_TINY: - byte tinyintVal = getNativeByte(columnIndex + 1); + byte tinyintVal = getNativeByte(columnIndex + 1, false); if (!f.isUnsigned() || tinyintVal >= 0) { return tinyintVal; @@ -3753,15 +3819,14 @@ return tinyintVal + 256; case MysqlDefs.FIELD_TYPE_SHORT: - short asShort = getNativeShort(columnIndex + 1); + case MysqlDefs.FIELD_TYPE_YEAR: + short asShort = getNativeShort(columnIndex + 1, false); if (!f.isUnsigned() || asShort >= 0) { return asShort; } return asShort + 65536; - case MysqlDefs.FIELD_TYPE_YEAR: - return getNativeShort(columnIndex + 1); case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: byte[] bits = (byte[]) this.thisRow[columnIndex]; @@ -3769,11 +3834,24 @@ int valueAsInt = (bits[0] & 0xff) | ((bits[1] & 0xff) << 8) | ((bits[2] & 0xff) << 16) | ((bits[3] & 0xff) << 24); - return valueAsInt; + if (!f.isUnsigned()) { + return valueAsInt; + } + + long valueAsLong = (valueAsInt >= 0) ? + valueAsInt : valueAsInt + 4294967296L; + + if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + valueAsLong > Integer.MAX_VALUE) { + throwRangeException(String.valueOf(valueAsLong), + columnIndex + 1, Types.INTEGER); + } + + return (int)valueAsLong; case MysqlDefs.FIELD_TYPE_LONGLONG: - long valueAsLong = getNativeLong(columnIndex + 1); + valueAsLong = getNativeLong(columnIndex + 1, false, true); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), @@ -3785,7 +3863,7 @@ case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3797,7 +3875,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: valueAsDouble = getNativeFloat(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3838,6 +3916,11 @@ * if a database access error occurs */ protected long getNativeLong(int columnIndex) throws SQLException { + return getNativeLong(columnIndex, false, true); + } + + protected long getNativeLong(int columnIndex, boolean overflowCheck, + boolean expandUnsignedLong) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); @@ -3891,21 +3974,25 @@ | ((long) (bits[6] & 0xff) << 48) | ((long) (bits[7] & 0xff) << 56); - // - // TODO: Actually do this check - // - // if (f.isUnsigned()) { - // if (this.connection.getJdbcCompliantTruncation()) { - // throwRangeException(String.valueOf(valueAsDouble), columnIndex + - // 1, Types.BIGINT); - // } - // } + if (!f.isUnsigned() || !expandUnsignedLong) { + return valueAsLong; + } + + BigInteger asBigInt = convertLongToUlong(valueAsLong); + + if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + ((asBigInt.compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0 ) || + (asBigInt.compareTo(new BigInteger(String.valueOf(Long.MIN_VALUE))) < 0))) { + throwRangeException(asBigInt.toString(), + columnIndex + 1, Types.BIGINT); + } + + return getLongFromString(asBigInt.toString(), columnIndex + 1); - return valueAsLong; case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3917,7 +4004,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: valueAsDouble = getNativeFloat(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -3974,6 +4061,10 @@ * if a database access error occurs */ protected short getNativeShort(int columnIndex) throws SQLException { + return getNativeShort(columnIndex, true); + } + + protected short getNativeShort(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); @@ -4001,15 +4092,17 @@ return (short)(tinyintVal + (short)256); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: - short asShort = getNativeShort(columnIndex + 1); + byte[] bits = (byte[]) this.thisRow[columnIndex]; + short asShort = (short) ((bits[0] & 0xff) | ((bits[1] & 0xff) << 8)); + if (!f.isUnsigned()) { return asShort; } - int valueAsInt = asShort + 65536; + int valueAsInt = asShort & 0xffff; - if (this.connection.getJdbcCompliantTruncation() && + if (overflowCheck && this.connection.getJdbcCompliantTruncation() && valueAsInt > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.SMALLINT); @@ -4018,28 +4111,59 @@ return (short)valueAsInt; case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: - byte[] bits = (byte[]) this.thisRow[columnIndex]; - - valueAsInt = (bits[0] & 0xff) | ((bits[1] & 0xff) << 8) - | ((bits[2] & 0xff) << 16) | ((bits[3] & 0xff) << 24); - - return (short)valueAsInt; + if (!f.isUnsigned()) { + valueAsInt = getNativeInt(columnIndex + 1, false); + + if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + valueAsInt > Short.MAX_VALUE || + valueAsInt < Short.MIN_VALUE) { + throwRangeException(String.valueOf(valueAsInt), + columnIndex + 1, Types.SMALLINT); + } + + return (short)valueAsInt; + } + + long valueAsLong = getNativeLong(columnIndex + 1, false, true); + + if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + valueAsLong > Short.MAX_VALUE) { + throwRangeException(String.valueOf(valueAsLong), + columnIndex + 1, Types.SMALLINT); + } + + return (short)valueAsLong; + case MysqlDefs.FIELD_TYPE_LONGLONG: - long valueAsLong = getNativeLong(columnIndex + 1); - - if (this.connection.getJdbcCompliantTruncation()) { - if (valueAsLong < Integer.MIN_VALUE - || valueAsLong > Integer.MAX_VALUE) { - throwRangeException(String.valueOf(valueAsLong), - columnIndex + 1, Types.INTEGER); + valueAsLong = getNativeLong(columnIndex + 1, false, false); + + if (!f.isUnsigned()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { + if (valueAsLong < Short.MIN_VALUE + || valueAsLong > Short.MAX_VALUE) { + throwRangeException(String.valueOf(valueAsLong), + columnIndex + 1, Types.SMALLINT); + } } + + return (short) valueAsLong; } + + BigInteger asBigInt = convertLongToUlong(valueAsLong); + + if (overflowCheck && this.connection.getJdbcCompliantTruncation() && + ((asBigInt.compareTo(new BigInteger(String.valueOf(Short.MAX_VALUE))) > 0 ) || + (asBigInt.compareTo(new BigInteger(String.valueOf(Short.MIN_VALUE))) < 0))) { + throwRangeException(asBigInt.toString(), + columnIndex + 1, Types.SMALLINT); + } + + return (short)getIntFromString(asBigInt.toString(), columnIndex + 1); - return (short) valueAsLong; case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsDouble < Short.MIN_VALUE || valueAsDouble > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), @@ -4051,7 +4175,7 @@ case MysqlDefs.FIELD_TYPE_FLOAT: float valueAsFloat = getNativeFloat(columnIndex + 1); - if (this.connection.getJdbcCompliantTruncation()) { + if (overflowCheck && this.connection.getJdbcCompliantTruncation()) { if (valueAsFloat < Short.MIN_VALUE || valueAsFloat > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsFloat),