Re: Binary protocol support for JDBC

Поиск
Список
Период
Сортировка
От Radosław Smogura
Тема Re: Binary protocol support for JDBC
Дата
Msg-id 201007202243.07075.rsmogura@softperience.eu
обсуждение исходный текст
Ответ на Re: Binary protocol support for JDBC  (Kris Jurka <books@ejurka.com>)
Список 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

В списке pgsql-jdbc по дате отправления:

Предыдущее
От: Florence Cousin
Дата:
Сообщение: Patch for the documentation (PGResultSetMetaData)
Следующее
От: Radosław Smogura
Дата:
Сообщение: Re: Binary protocol support for JDBC