From: | Radosław Smogura <rsmogura(at)softperience(dot)eu> |
---|---|
To: | pgsql-jdbc(at)postgresql(dot)org |
Subject: | Re: Binary protocol support for JDBC |
Date: | 2010-07-20 20:43:06 |
Message-ID: | 201007202243.07075.rsmogura@softperience.eu |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-jdbc |
I searched something about this, but I culdn't find :)
It looks like this what I've done, so I will only send BigDeciaml read code.
Below :) some Sysout trashes left, but works, I've tested
public BigDecimal getBigDecimal(int columnIndex, int scale) throws
SQLException
{
checkResultSet(columnIndex);
if (wasNullFlag)
return null;
final int column = columnIndex - 1;
if (fields[column].getFormat() == Field.BINARY_FORMAT) {
//TODO Extract this do getBinaryBigDeciaml to support NaN
if (fields[column].getOID() != Oid.NUMERIC)
throw new PSQLException("Conversion in binary form not fully
implemented yet.", PSQLState.NOT_IMPLEMENTED);
byte[] number = this_row[column];
short ndigits = (short) (((number[0] & 0xff) << 8) | (number[1] &
0xff));
short weight = (short) (((number[2] & 0xff) << 8) | (number[3] &
0xff));
short sign = (short) (((number[4] & 0xff) << 8) | (number[5] &
0xff));
short dscale = (short) (((number[6] & 0xff) << 8) | (number[7] &
0xff));
if (sign == (short) 0xC000) {
//Numeric NaN - BigDecimal doesn't support this
throw new PSQLException("The numeric value is NaN - can't
convert to BigDecimal",
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
final int bigDecimalSign = sign == 0x4000 ? -1 : 1;
// System.out.println("ndigits=" + ndigits
// +",\n wieght=" + weight
// +",\n sign=" + sign
// +",\n dscale=" + dscale);
//// for (int i=8; i < number.length; i++) {
// System.out.println("numer[i]=" + (int) (number[i] & 0xff));
// }
int tail = ndigits % 4;
int bytesToParse = (ndigits - tail) * 2 + 8;
// System.out.println("numberParseLength="+numberParseLength);
int i;
BigInteger unscaledValue = BigInteger.ZERO;
final BigInteger nbase = getNBase();
final BigInteger nbasePow2 = getNBasePow2();
final BigInteger nbasePow4 = getNBasePow4();
final long nbaseLong = AbstractJdbc2ResultSet.nbaseLong;
final long nbaseLongPow2 = AbstractJdbc2ResultSet.nbaseLongPow2;
final int nbaseInt = (int) AbstractJdbc2ResultSet.nbaseInt;
//final long nbasePow2Long = nbaseLong * nbaseLong;
byte[] buffer = new byte[8];
// System.out.println("tail = " + tail + " bytesToParse = " +
bytesToParse);
for (i=8; i < bytesToParse; i+=8) {
//This Hi and Lo aren't bytes Hi Li, but decimal Hi Lo!!! (Big
& Small)
long valHi = (((number[i] & 0xff) << 8) | (number[i+1] & 0xff))
* 10000
+ (((number[i+2] & 0xff) << 8) | (number[i+3] & 0xff));
long valLo = (((number[i+4] & 0xff) << 8) | (number[i+5] &
0xff)) * 10000
+ (((number[i+6] & 0xff) << 8) | (number[i+7] & 0xff));
long val = valHi * nbaseLongPow2 + valLo;
buffer[0] = (byte)(val >>> 56);
buffer[1] = (byte)(val >>> 48);
buffer[2] = (byte)(val >>> 40);
buffer[3] = (byte)(val >>> 32);
buffer[4] = (byte)(val >>> 24);
buffer[5] = (byte)(val >>> 16);
buffer[6] = (byte)(val >>> 8);
buffer[7] = (byte)(val >>> 0);
BigInteger valBigInteger = new BigInteger(bigDecimalSign,
buffer);
unscaledValue =
unscaledValue.multiply(nbasePow4).add(valBigInteger);
// System.out.println("Value (8) = " + val + ", unscaled =" +
unscaledValue
// +", valBI = "+ valBigInteger);
}
tail = tail % 2;
bytesToParse = (ndigits - tail) * 2 + 8;
//System.out.println("tail = " + tail + " bytesToParse = " +
bytesToParse);
buffer = new byte[4];
for (;i < bytesToParse; i+=4) {
int val = (((number[i] & 0xff) << 8) | (number[i+1] & 0xff)) *
nbaseInt
+ (((number[i+2] & 0xff) << 8) | (number[i+3] & 0xff));
buffer[0] = (byte)(val >>> 24);
buffer[1] = (byte)(val >>> 16);
buffer[2] = (byte)(val >>> 8);
buffer[3] = (byte)val;
BigInteger valBigInteger = new BigInteger(bigDecimalSign,
buffer);
unscaledValue =
unscaledValue.multiply(nbasePow2).add(valBigInteger);
// System.out.println("Value (4) = " + val + ", unscaled =" +
unscaledValue
// +", valBI = "+ valBigInteger);
}
//Add the rest of number
//System.out.println("tail = " + tail + " bytesToParse = " +
bytesToParse);
if (tail % 2 == 1){
buffer = new byte[2];
buffer[0] = number[number.length - 2];
buffer[1] = number[number.length - 1];
BigInteger valBigInteger = new BigInteger(buffer);
unscaledValue =
unscaledValue.multiply(nbase).add(valBigInteger);
// System.out.println("Value (2) unscaled =" + unscaledValue
// +", valBI = "+ valBigInteger);
}
//System.out.println("Final unscaled value " + unscaledValue);
//if (sign == 0x4000)
// unscaledValue = unscaledValue.negate();
//Calculate scale offset
final int databaseScale = (ndigits - weight - 1)*4; // Number of
digits in nabse
//TODO This number of digits should be calculeted depending on
nbase (getNbase());
BigDecimal result = new BigDecimal(unscaledValue, databaseScale);
//System.out.println("Final result " + result);
if (scale == -1)
return result;
else
return result.setScale(scale);
}else {
Encoding encoding = connection.getEncoding();
if (encoding.hasAsciiNumbers()) {
try {
return getFastBigDecimal(columnIndex);
} catch (NumberFormatException ex) {
}
}
return toBigDecimal( getFixedString(columnIndex), scale );
}
}
> On Tue, 20 Jul 2010, Rados?aw Smogura wrote:
> > I partially, and for "test", implemented retrieval data in binary mode
> > (instead of text mode) for some Jdbc2 types, because I see great
> > performance boost (25% - 50%) on implemented types I think about
> > including this work to main JDBC branch.
>
> Are you aware of the existing work in this area?
>
> http://wiki.postgresql.org/wiki/JDBC-BinaryTransfer
>
> > This should be done without problem, because I added binary parameter to
> > Connection and Datasources, so user can decide to use binary mode
> > retrieve or current text mode (default). Currently I implemented
> > retrieve of short, int, long, date and BigDecimal. Other simple and
> > basic types, used in typically application I will implement shortly.
>
> One of the difficulties in the existing patch is knowing when to request
> binary transfer and when to request text transfer because for the first
> execution the datatypes are not known. How have you addressed
> this problem?
>
> Kris Jurka
From | Date | Subject | |
---|---|---|---|
Next Message | Radosław Smogura | 2010-07-20 20:45:54 | Re: Binary protocol support for JDBC |
Previous Message | Florence Cousin | 2010-07-20 20:40:21 | Patch for the documentation (PGResultSetMetaData) |