Index: pgjdbc.tmp8/org/postgresql/jdbc2/AbstractJdbc2Connection.java =================================================================== --- pgjdbc.tmp8.orig/org/postgresql/jdbc2/AbstractJdbc2Connection.java +++ pgjdbc.tmp8/org/postgresql/jdbc2/AbstractJdbc2Connection.java @@ -143,6 +143,11 @@ public abstract class AbstractJdbc2Conne BitSet binaryOids = new BitSet(); if (binaryTransfer && protoConnection.getProtocolVersion() >= 3) { binaryOids.set(Oid.BYTEA); + binaryOids.set(Oid.INT2); + binaryOids.set(Oid.INT4); + binaryOids.set(Oid.INT8); + binaryOids.set(Oid.FLOAT4); + binaryOids.set(Oid.FLOAT8); } // split for receive and send for better control Index: pgjdbc.tmp8/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java =================================================================== --- pgjdbc.tmp8.orig/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java +++ pgjdbc.tmp8/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java @@ -26,6 +26,7 @@ import java.util.Calendar; import java.util.Locale; import org.postgresql.core.*; import org.postgresql.largeobject.*; +import org.postgresql.util.ByteConverter; import org.postgresql.util.PGobject; import org.postgresql.util.PGbytea; import org.postgresql.util.PGtokenizer; @@ -1878,6 +1879,12 @@ public abstract class AbstractJdbc2Resul checkResultSet(columnIndex); if (wasNullFlag) return false; // SQL NULL + + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + return readDoubleValue(this_row[col], fields[col].getOID(), + "boolean") == 1; + } return toBoolean( getString(columnIndex) ); } @@ -1891,6 +1898,15 @@ public abstract class AbstractJdbc2Resul if (wasNullFlag) return 0; // SQL NULL + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + // there is no Oid for byte so must always do conversion from + // some other numeric type + return (byte) + readLongValue(this_row[col], fields[col].getOID(), Byte.MIN_VALUE, + Byte.MAX_VALUE, "byte"); + } + String s = getString(columnIndex); if (s != null ) @@ -1940,6 +1956,16 @@ public abstract class AbstractJdbc2Resul if (wasNullFlag) return 0; // SQL NULL + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + int oid = fields[col].getOID(); + if (oid == Oid.INT2) { + return ByteConverter.int2(this_row[col], 0); + } + return (short) readLongValue(this_row[col], oid, Short.MIN_VALUE, + Short.MAX_VALUE, "short"); + } + String s = getFixedString(columnIndex); if (s != null) @@ -1982,6 +2008,16 @@ public abstract class AbstractJdbc2Resul if (wasNullFlag) return 0; // SQL NULL + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + int oid = fields[col].getOID(); + if (oid == Oid.INT4) { + return ByteConverter.int4(this_row[col], 0); + } + return (int) readLongValue(this_row[col], oid, Integer.MIN_VALUE, + Integer.MAX_VALUE, "int"); + } + Encoding encoding = connection.getEncoding(); if (encoding.hasAsciiNumbers()) { try { @@ -1998,6 +2034,16 @@ public abstract class AbstractJdbc2Resul if (wasNullFlag) return 0; // SQL NULL + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + int oid = fields[col].getOID(); + if (oid == Oid.INT8) { + return ByteConverter.int8(this_row[col], 0); + } + return readLongValue(this_row[col], oid, Long.MIN_VALUE, + Long.MAX_VALUE, "long"); + } + Encoding encoding = connection.getEncoding(); if (encoding.hasAsciiNumbers()) { try { @@ -2197,6 +2243,15 @@ public abstract class AbstractJdbc2Resul if (wasNullFlag) return 0; // SQL NULL + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + int oid = fields[col].getOID(); + if (oid == Oid.FLOAT4) { + return ByteConverter.float4(this_row[col], 0); + } + return (float) readDoubleValue(this_row[col], oid, "float"); + } + return toFloat( getFixedString(columnIndex) ); } @@ -2206,6 +2261,15 @@ public abstract class AbstractJdbc2Resul if (wasNullFlag) return 0; // SQL NULL + if (isBinary(columnIndex)) { + int col = columnIndex - 1; + int oid = fields[col].getOID(); + if (oid == Oid.FLOAT8) { + return ByteConverter.float8(this_row[col], 0); + } + return readDoubleValue(this_row[col], oid, "double"); + } + return toDouble( getFixedString(columnIndex) ); } @@ -2924,6 +2988,88 @@ public abstract class AbstractJdbc2Resul } } + /** + * Converts any numeric binary field to double value. This method + * does no overflow checking. + * + * @param bytes The bytes of the numeric field. + * @param oid The oid of the field. + * @param targetType The target type. Used for error reporting. + * @return The value as double. + * @throws PSQLException If the field type is not supported numeric type. + */ + private double readDoubleValue(byte[] bytes, int oid, + String targetType) throws PSQLException { + // currently implemented binary encoded fields + switch (oid) { + case Oid.INT2: + return ByteConverter.int2(bytes, 0); + case Oid.INT4: + return ByteConverter.int4(bytes, 0); + case Oid.INT8: + // might not fit but there still should be no overflow checking + return ByteConverter.int8(bytes, 0); + case Oid.FLOAT4: + return ByteConverter.float4(bytes, 0); + case Oid.FLOAT8: + return ByteConverter.float8(bytes, 0); + } + throw new PSQLException (GT.tr("Cannot convert the column of type {0} to requested type {1}.", + new Object[]{Oid.toString(oid), targetType}), + PSQLState.DATA_TYPE_MISMATCH); + } + + /** + * Converts any numeric binary field to long value. + *
+ * This method is used by getByte,getShort,getInt and getLong. + * It must support a subset of the following java types that use Binary + * encoding. (fields that use text encoding use a different code path). + *
+ * byte,short,int,long,float,double,BigDecimal,boolean,string
.
+
+ * @param bytes The bytes of the numeric field.
+ * @param oid The oid of the field.
+ * @param minVal the minimum value allowed.
+ * @param minVal the maximum value allowed.
+ * @param targetType The target type. Used for error reporting.
+ * @return The value as long.
+ * @throws PSQLException If the field type is not supported numeric type
+ * or if the value is out of range.
+ */
+ private long readLongValue(byte[] bytes, int oid, long minVal, long maxVal,
+ String targetType)
+ throws PSQLException {
+ long val;
+ // currently implemented binary encoded fields
+ switch (oid) {
+ case Oid.INT2:
+ val = ByteConverter.int2(bytes, 0);
+ break;
+ case Oid.INT4:
+ val = ByteConverter.int4(bytes, 0);
+ break;
+ case Oid.INT8:
+ val = ByteConverter.int8(bytes, 0);
+ break;
+ case Oid.FLOAT4:
+ val = (long) ByteConverter.float4(bytes, 0);
+ break;
+ case Oid.FLOAT8:
+ val = (long) ByteConverter.float8(bytes, 0);
+ break;
+ default:
+ throw new PSQLException (GT.tr("Cannot convert the column of type {0} to requested type {1}.",
+ new Object[]{Oid.toString(oid), targetType}),
+ PSQLState.DATA_TYPE_MISMATCH);
+ }
+ if (val < minVal || val > maxVal) {
+ throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{targetType, Long.valueOf(val)}),
+ PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
+ }
+ return val;
+ }
+
protected void updateValue(int columnIndex, Object value) throws SQLException {
checkUpdateable();
Index: pgjdbc.tmp8/org/postgresql/util/ByteConverter.java
===================================================================
--- /dev/null
+++ pgjdbc.tmp8/org/postgresql/util/ByteConverter.java
@@ -0,0 +1,157 @@
+/*-------------------------------------------------------------------------
+ *
+ * Copyright (c) 2006, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgjdbc/org/postgresql/util/ByteConverter.java,v 1.1 2006/10/30 18:30:16 jurka Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+package org.postgresql.util;
+
+/**
+ * Helper methods to parse java base types from byte arrays.
+ *
+ * @author Mikko Tiihonen
+ */
+public class ByteConverter {
+
+ private ByteConverter() {
+ // prevent instantiation of static helper class
+ }
+
+ /**
+ * Parses a long value from the byte array.
+ *
+ * @param bytes The byte array to parse.
+ * @param idx The starting index of the parse in the byte array.
+ * @return parsed long value.
+ */
+ public static long int8(byte[] bytes, int idx) {
+ return
+ ((long)(bytes[idx+0] & 255) << 56) +
+ ((long)(bytes[idx+1] & 255) << 48) +
+ ((long)(bytes[idx+2] & 255) << 40) +
+ ((long)(bytes[idx+3] & 255) << 32) +
+ ((long)(bytes[idx+4] & 255) << 24) +
+ ((long)(bytes[idx+5] & 255) << 16) +
+ ((long)(bytes[idx+6] & 255) << 8) +
+ ((long)(bytes[idx+7] & 255) );
+ }
+
+ /**
+ * Parses an int value from the byte array.
+ *
+ * @param bytes The byte array to parse.
+ * @param idx The starting index of the parse in the byte array.
+ * @return parsed int value.
+ */
+ public static int int4(byte[] bytes, int idx) {
+ return
+ ((bytes[idx ] & 255) << 24) +
+ ((bytes[idx+1] & 255) << 16) +
+ ((bytes[idx+2] & 255) << 8) +
+ ((bytes[idx+3] & 255) );
+ }
+
+ /**
+ * Parses a short value from the byte array.
+ *
+ * @param bytes The byte array to parse.
+ * @param idx The starting index of the parse in the byte array.
+ * @return parsed short value.
+ */
+ public static short int2(byte[] bytes, int idx) {
+ return (short)
+ (((bytes[idx ] & 255) << 8) +
+ ((bytes[idx+1] & 255) ));
+ }
+
+ /**
+ * Parses a float value from the byte array.
+ *
+ * @param bytes The byte array to parse.
+ * @param idx The starting index of the parse in the byte array.
+ * @return parsed float value.
+ */
+ public static float float4(byte[] bytes, int idx) {
+ return Float.intBitsToFloat(int4(bytes, idx));
+ }
+
+ /**
+ * Parses a double value from the byte array.
+ *
+ * @param bytes The byte array to parse.
+ * @param idx The starting index of the parse in the byte array.
+ * @return parsed double value.
+ */
+ public static double float8(byte[] bytes, int idx) {
+ return Double.longBitsToDouble(int8(bytes, idx));
+ }
+
+ /**
+ * Encodes a long value to the byte array.
+ *
+ * @param target The byte array to encode to.
+ * @param idx The starting index in the byte array.
+ * @param value The value to encode.
+ */
+ public static void int8(byte[] target, int idx, long value) {
+ target[idx+0] = (byte) (value >>> 56);
+ target[idx+1] = (byte) (value >>> 48);
+ target[idx+2] = (byte) (value >>> 40);
+ target[idx+3] = (byte) (value >>> 32);
+ target[idx+4] = (byte) (value >>> 24);
+ target[idx+5] = (byte) (value >>> 16);
+ target[idx+6] = (byte) (value >>> 8);
+ target[idx+7] = (byte) value;
+ }
+
+ /**
+ * Encodes a int value to the byte array.
+ *
+ * @param target The byte array to encode to.
+ * @param idx The starting index in the byte array.
+ * @param value The value to encode.
+ */
+ public static void int4(byte[] target, int idx, int value) {
+ target[idx+0] = (byte) (value >>> 24);
+ target[idx+1] = (byte) (value >>> 16);
+ target[idx+2] = (byte) (value >>> 8);
+ target[idx+3] = (byte) value;
+ }
+
+ /**
+ * Encodes a int value to the byte array.
+ *
+ * @param target The byte array to encode to.
+ * @param idx The starting index in the byte array.
+ * @param value The value to encode.
+ */
+ public static void int2(byte[] target, int idx, int value) {
+ target[idx+0] = (byte) (value >>> 8);
+ target[idx+1] = (byte) value;
+ }
+
+ /**
+ * Encodes a int value to the byte array.
+ *
+ * @param target The byte array to encode to.
+ * @param idx The starting index in the byte array.
+ * @param value The value to encode.
+ */
+ public static void float4(byte[] target, int idx, float value) {
+ int4(target, idx, Float.floatToRawIntBits(value));
+ }
+
+ /**
+ * Encodes a int value to the byte array.
+ *
+ * @param target The byte array to encode to.
+ * @param idx The starting index in the byte array.
+ * @param value The value to encode.
+ */
+ public static void float8(byte[] target, int idx, double value) {
+ int8(target, idx, Double.doubleToRawLongBits(value));
+ }
+}