[Commits] Rev 404: Implement lazy parsing of result set metadata. in file:///H:/bzr/mariadb-jdbc-push/

Vladislav Vaintroub wlad at montyprogram.com
Tue Feb 12 16:56:31 EET 2013


At file:///H:/bzr/mariadb-jdbc-push/

------------------------------------------------------------
revno: 404
revision-id: wlad at montyprogram.com-20130212145623-af1bwz5guqm8alvd
parent: wlad at montyprogram.com-20130211191151-mgm8kchekex1a68c
committer: Vladislav Vaintroub <wlad at montyprogram.com>
branch nick: mariadb-jdbc-push
timestamp: Tue 2013-02-12 15:56:23 +0100
message:
  Implement lazy parsing of result set metadata. 
  Avoid calling expensive String constructors unless necessary.
-------------- next part --------------
=== modified file 'src/main/java/org/mariadb/jdbc/MySQLResultSet.java'
--- a/src/main/java/org/mariadb/jdbc/MySQLResultSet.java	2013-01-15 01:18:28 +0000
+++ b/src/main/java/org/mariadb/jdbc/MySQLResultSet.java	2013-02-12 14:56:23 +0000
@@ -72,7 +72,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 
@@ -3693,19 +3692,11 @@ public class MySQLResultSet implements R
     */
     static ResultSet createResultSet(String[] columnNames, MySQLType.Type[] columnTypes, String[][] data, 
             MySQLProtocol protocol)  {
-        
-        MySQLColumnInformation.Builder b = new MySQLColumnInformation.Builder();
-        b.catalog("").charsetNumber((short)33).db("").flags(EnumSet.noneOf(ColumnFlags.class));
-
         int N = columnNames.length;
         ColumnInformation[] columns = new ColumnInformation[N];
         
         for (int i = 0; i < N ; i++) {
-           if (columnTypes[i] == MySQLType.Type.BIT)
-               b.length(1);
-           else
-               b.length(0);
-           columns[i] = b.name(columnNames[i]).type(new MySQLType(columnTypes[i])).build();
+            columns[i] = MySQLColumnInformation.create(columnNames[i],columnTypes[i]);
         }
         
         byte[] BOOL_TRUE = {1};

=== modified file 'src/main/java/org/mariadb/jdbc/internal/common/ColumnInformation.java'
--- a/src/main/java/org/mariadb/jdbc/internal/common/ColumnInformation.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/common/ColumnInformation.java	2013-02-12 14:56:23 +0000
@@ -79,5 +79,5 @@ public interface ColumnInformation {
     boolean isBinary();
     Set<ColumnFlags> getFlags();
 
-    void updateDisplaySize(int displayLength);
+    //void updateDisplaySize(int displayLength);
 }

=== modified file 'src/main/java/org/mariadb/jdbc/internal/common/packet/RawPacket.java'
--- a/src/main/java/org/mariadb/jdbc/internal/common/packet/RawPacket.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/common/packet/RawPacket.java	2013-02-12 14:56:23 +0000
@@ -89,7 +89,7 @@ public final class RawPacket {
      * @param byteBuffer the byte buffer containing the packet
      * @param packetSeq the packet sequence
      */
-    private RawPacket(final ByteBuffer byteBuffer, final int packetSeq) {
+    public  RawPacket(final ByteBuffer byteBuffer, final int packetSeq) {
         this.byteBuffer = byteBuffer;
         this.packetSeq = packetSeq;
     }

=== modified file 'src/main/java/org/mariadb/jdbc/internal/common/packet/buffer/Reader.java'
--- a/src/main/java/org/mariadb/jdbc/internal/common/packet/buffer/Reader.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/common/packet/buffer/Reader.java	2013-02-12 14:56:23 +0000
@@ -139,6 +139,15 @@ public class Reader {
         return bytesToSkip;
     }
 
+    public Reader skipLengthEncodedBytes() throws IOException {
+        long encLength = getLengthEncodedBinary();
+        if (encLength == -1) {
+               return null;
+        }
+        skipBytes((int)encLength);
+        return this;
+    }
+    
     public int read24bitword() throws IOException {
         final byte[] tmpArr = new byte[3];
         for (int i = 0; i < 3; i++) {

=== modified file 'src/main/java/org/mariadb/jdbc/internal/common/queryresults/InsertIdQueryResult.java'
--- a/src/main/java/org/mariadb/jdbc/internal/common/queryresults/InsertIdQueryResult.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/common/queryresults/InsertIdQueryResult.java	2013-02-12 14:56:23 +0000
@@ -55,7 +55,6 @@ import org.mariadb.jdbc.internal.mysql.M
 import org.mariadb.jdbc.internal.mysql.MySQLType;
 
 import java.util.ArrayList;
-import java.util.EnumSet;
 import java.util.List;
 
 
@@ -99,10 +98,8 @@ public class InsertIdQueryResult extends
         if (ci != null)
             return ci;
 
-        MySQLColumnInformation.Builder b = new MySQLColumnInformation.Builder();
-        MySQLColumnInformation info = b.db("").catalog("").charsetNumber((short) 0).decimals((byte) 0).name("insert_id" +
-                "").originalName("insert_id").flags(EnumSet.noneOf(ColumnFlags.class)).
-                originalTable("").table("").type(new MySQLType(MySQLType.Type.BIGINT)).build();
+        MySQLColumnInformation info = MySQLColumnInformation.create("insert_id", MySQLType.Type.BIGINT);
+
 
          ci =  new ArrayList<ColumnInformation>();
          ci.add(info);

=== modified file 'src/main/java/org/mariadb/jdbc/internal/mysql/MySQLColumnInformation.java'
--- a/src/main/java/org/mariadb/jdbc/internal/mysql/MySQLColumnInformation.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/mysql/MySQLColumnInformation.java	2013-02-12 14:56:23 +0000
@@ -1,232 +1,167 @@
-/*
-MariaDB Client for Java
-
-Copyright (c) 2012 Monty Program Ab.
-
-This library is free software; you can redistribute it and/or modify it under
-the terms of the GNU Lesser General Public License as published by the Free
-Software Foundation; either version 2.1 of the License, or (at your option)
-any later version.
-
-This library is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
-for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with this library; if not, write to Monty Program Ab info at montyprogram.com.
-
-This particular MariaDB Client for Java file is work
-derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to
-the following copyright and notice provisions:
-
-Copyright (c) 2009-2011, Marcus Eriksson
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-Neither the name of the driver nor the names of its contributors may not be
-used to endorse or promote products derived from this software without specific
-prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS  AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
-OF SUCH DAMAGE.
-*/
-
-package org.mariadb.jdbc.internal.mysql;
-
-import org.mariadb.jdbc.internal.common.ColumnInformation;
-import org.mariadb.jdbc.internal.common.DataType;
-import org.mariadb.jdbc.internal.common.queryresults.ColumnFlags;
-
-import java.sql.Types;
-import java.util.Collections;
-import java.util.Set;
-
-
-
-public class MySQLColumnInformation implements ColumnInformation {
-    private final String catalog;
-    private final String db;
-    private final String table;
-    private final String orgTable;
-    private final String name;
-    private final String orgName;
-    private final short charsetNumber;
-    private final long length;
-    private final DataType type;
-    private final byte decimals;
-    private final Set<ColumnFlags> flags;
-    private int displayWidth = 0;
-
-    public MySQLColumnInformation(final Builder builder) {
-        this.catalog = builder.catalog;
-        this.db = builder.db;
-        this.table = builder.table;
-        this.orgTable = builder.originalTable;
-        this.name = builder.name;
-        this.orgName = builder.originalName;
-        this.charsetNumber = builder.charsetNumber;
-        this.length = builder.length;
-        this.decimals = builder.decimals;
-        this.flags = Collections.unmodifiableSet(builder.flags);
-
-        int sqlType = builder.type.getSqlType();
-
-        if ((sqlType == Types.BLOB || sqlType == Types.VARBINARY || sqlType == Types.BINARY || sqlType == Types.LONGVARBINARY )
-                && !isBinary()) {
-           /* MySQL Text datatype */
-           this.type = new MySQLType(MySQLType.Type.VARCHAR);
-        } else {
-           this.type = builder.type;
-        }
-    }
-
-    public String getCatalog() {
-        return catalog;
-    }
-
-    public String getDb() {
-        return db;
-    }
-
-    public String getTable() {
-        return table;
-    }
-
-    public String getOriginalTable() {
-        return orgTable;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getOriginalName() {
-        return orgName;
-    }
-
-    public short getCharsetNumber() {
-        return charsetNumber;
-    }
-
-    public long getLength() {
-        return length;
-    }
-
-    public DataType getType() {
-        return type;
-    }
-
-    public byte getDecimals() {
-        return decimals;
-    }
-
-    public Set<ColumnFlags> getFlags() {
-        return flags;
-    }
-
-    public boolean isSigned() {
-        return !flags.contains(ColumnFlags.UNSIGNED);
-    }
-
-    public boolean isBinary() {
-       return (flags.contains(ColumnFlags.BINARY) || getCharsetNumber() == 63);
-    }
-    public void updateDisplaySize(final int displayLength) {
-        if (displayLength > displayWidth) {
-            this.displayWidth = displayLength;
-        }
-    }
-
-    public static class Builder {
-        private String catalog;
-        private String db;
-        private String table;
-        private String originalTable;
-        private String name;
-        private String originalName;
-        private short charsetNumber;
-        private int length;
-        private DataType type;
-        private Set<ColumnFlags> flags;
-        private byte decimals;
-
-        public Builder catalog(final String catalog) {
-            this.catalog = catalog;
-            return this;
-        }
-
-        public Builder db(final String db) {
-            this.db = db;
-            return this;
-        }
-
-        public Builder table(final String table) {
-            this.table = table;
-            return this;
-        }
-
-        public Builder originalTable(final String orgTable) {
-            this.originalTable = orgTable;
-            return this;
-        }
-
-        public Builder name(final String name) {
-            this.name = name;
-            return this;
-        }
-
-        public Builder originalName(final String orgName) {
-            this.originalName = orgName;
-            return this;
-        }
-
-        public Builder skipMe(final long bytesSkipped) {
-            return this;
-        }
-
-        public Builder charsetNumber(final short charsetNumber) {
-            this.charsetNumber = charsetNumber;
-            return this;
-        }
-
-        public Builder length(final int length) {
-            this.length = length;
-            return this;
-        }
-
-        public Builder type(final DataType dataType) {
-            this.type = dataType;
-            return this;
-        }
-
-        public Builder flags(final Set<ColumnFlags> columnFlags) {
-            this.flags = columnFlags;
-            return this;
-        }
-
-        public Builder decimals(final byte decimals) {
-            this.decimals = decimals;
-            return this;
-        }
-
-        public MySQLColumnInformation build() {
-            return new MySQLColumnInformation(this);
-        }
-    }
+package org.mariadb.jdbc.internal.mysql;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.sql.Types;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.mariadb.jdbc.internal.common.ColumnInformation;
+import org.mariadb.jdbc.internal.common.DataType;
+import org.mariadb.jdbc.internal.common.packet.RawPacket;
+import org.mariadb.jdbc.internal.common.packet.buffer.Reader;
+import org.mariadb.jdbc.internal.common.queryresults.ColumnFlags;
+
+public class MySQLColumnInformation implements ColumnInformation {
+    RawPacket buffer;
+    private short charsetNumber;
+    private long length;
+    private DataType type;
+    private byte decimals;
+    private Set<ColumnFlags> flags;
+
+    public static MySQLColumnInformation create(String name, MySQLType.Type type) {
+        try {
+            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
+            for (int i = 0; i < 4; i++) {
+                baos.write(new byte[] {1,0}); // catalog, empty string
+            }
+            for (int i = 0 ; i < 2; i ++) {
+                baos.write(new byte[] {(byte)name.length()});
+                baos.write(name.getBytes());
+            }
+            baos.write(0xc);
+            baos.write(new byte[]{33,0});  /* charset  = UTF8 */
+            baos.write(new byte[]{1, 0 ,0, 0});  /*  length */
+            baos.write(MySQLType.toServer(type.getSqlType()));
+            baos.write(new byte[]{0,0});   /* flags */
+            baos.write(0); /* decimals */
+            baos.write(new byte[]{0,0});   /* filler */
+            return new MySQLColumnInformation(new RawPacket(ByteBuffer.wrap(baos.toByteArray()).order(ByteOrder.LITTLE_ENDIAN),0));
+        }  catch (IOException ioe) {
+            throw new RuntimeException("unexpected condition",ioe);
+        }
+    }
+
+
+    public MySQLColumnInformation(RawPacket buffer) throws IOException {
+        this.buffer = buffer;
+        buffer.getByteBuffer().mark();
+        Reader reader = new Reader(buffer);
+
+        /*
+        lenenc_str     catalog
+        lenenc_str     schema
+        lenenc_str     table
+        lenenc_str     org_table
+        lenenc_str     name
+        lenenc_str     org_name
+        lenenc_int     length of fixed-length fields [0c]
+        2              character set
+        4              column length
+        1              type
+        2              flags
+        1              decimals
+        2              filler [00] [00]
+
+         */
+        reader.skipLengthEncodedBytes();  /* catalog */
+        reader.skipLengthEncodedBytes();  /* db */
+        reader.skipLengthEncodedBytes();  /* table */
+        reader.skipLengthEncodedBytes();  /* original table */
+        reader.skipLengthEncodedBytes();  /* name */
+        reader.skipLengthEncodedBytes();  /* org_name */
+        reader.skipBytes(1);
+        charsetNumber = reader.readShort();
+        length = reader.readInt();
+        type = MySQLType.fromServer(reader.readByte());
+        flags = parseFlags(reader.readShort());
+        decimals = reader.readByte();
+
+
+        int sqlType= type.getSqlType();
+
+        if ((sqlType == Types.BLOB || sqlType == Types.VARBINARY || sqlType == Types.BINARY || sqlType == Types.LONGVARBINARY )
+                && !isBinary()) {
+           /* MySQL Text datatype */
+           type = new MySQLType(MySQLType.Type.VARCHAR);
+        }
+    }
+
+    private static Set<ColumnFlags> parseFlags(final short i) {
+          final Set<ColumnFlags> retFlags = EnumSet.noneOf(ColumnFlags.class);
+          for (final ColumnFlags fieldFlag : ColumnFlags.values()) {
+              if ((i & fieldFlag.flag()) == fieldFlag.flag()) {
+                  retFlags.add(fieldFlag);
+              }
+          }
+          return retFlags;
+    }
+
+    private String getString(int idx) {
+        try  {
+            buffer.getByteBuffer().reset();
+            buffer.getByteBuffer().mark();
+            Reader reader = new Reader(buffer);
+            for(int i = 0; i < idx ; i++) {
+               reader.skipLengthEncodedBytes();
+            }
+            return new String(reader.getLengthEncodedBytes(),"UTF-8");
+        }  catch (Exception e) {
+            throw new RuntimeException("this does not happen",e);
+        }
+    }
+    public String getCatalog() {
+        return null;
+    }
+
+    public String getDb() {
+        return getString(1);
+    }
+
+    public String getTable() {
+        return getString(2);
+    }
+
+    public String getOriginalTable() {
+        return getString(3);
+    }
+
+    public String getName() {
+        return getString(4);
+    }
+
+    public String getOriginalName() {
+        return getString(5);
+    }
+
+    public short getCharsetNumber() {
+        return charsetNumber;
+    }
+
+    public long getLength() {
+        return length;
+    }
+
+    public DataType getType() {
+        return type;
+    }
+
+    public byte getDecimals() {
+        return decimals;
+    }
+
+    public Set<ColumnFlags> getFlags() {
+        return flags;
+    }
+
+    public boolean isSigned() {
+        return !flags.contains(ColumnFlags.UNSIGNED);
+    }
+
+    public boolean isBinary() {
+       return (flags.contains(ColumnFlags.BINARY) || getCharsetNumber() == 63);
+    }
+
 }
\ No newline at end of file

=== modified file 'src/main/java/org/mariadb/jdbc/internal/mysql/MySQLType.java'
--- a/src/main/java/org/mariadb/jdbc/internal/mysql/MySQLType.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/mysql/MySQLType.java	2013-02-12 14:56:23 +0000
@@ -176,4 +176,42 @@ public class MySQLType implements DataTy
                 return new MySQLType(Type.VARCHAR);
         }
     }
+
+    public static byte toServer(int javaType) {
+
+        switch (javaType) {
+            case Types.TINYINT:
+                return 1;
+            case Types.SMALLINT:
+                return 2;
+            case Types.INTEGER:
+                return 3;
+            case Types.FLOAT:
+                return 4;
+            case Types.DOUBLE:
+                return 5;
+            case Types.NULL:
+                return 6;
+            case Types.TIMESTAMP:
+                return 7;
+            case Types.BIGINT:
+                return 8;
+            case Types.DATE:
+                return 10;
+            case Types.TIME:
+                return 11;
+            case Types.VARCHAR:
+                return 15;
+            case Types.BIT:
+                return 16;
+            case Types.BOOLEAN:
+                return 16;
+            case Types.DECIMAL:
+                return (byte)246;
+            case Types.CHAR:
+                return (byte)254;
+            default:
+                return (byte)255;
+        }
+    }
 }
\ No newline at end of file

=== modified file 'src/main/java/org/mariadb/jdbc/internal/mysql/packet/MySQLFieldPacket.java'
--- a/src/main/java/org/mariadb/jdbc/internal/mysql/packet/MySQLFieldPacket.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/mysql/packet/MySQLFieldPacket.java	2013-02-12 14:56:23 +0000
@@ -51,14 +51,8 @@ package org.mariadb.jdbc.internal.mysql.
 
 import org.mariadb.jdbc.internal.common.ColumnInformation;
 import org.mariadb.jdbc.internal.common.packet.RawPacket;
-import org.mariadb.jdbc.internal.common.packet.buffer.Reader;
-import org.mariadb.jdbc.internal.common.queryresults.ColumnFlags;
 import org.mariadb.jdbc.internal.mysql.MySQLColumnInformation;
-import org.mariadb.jdbc.internal.mysql.MySQLType;
-
 import java.io.IOException;
-import java.util.EnumSet;
-import java.util.Set;
 
 /**
  * Creates column information from field packets.
@@ -85,31 +79,7 @@ n (Length Coded Binary)    default
     */
 
     public static ColumnInformation columnInformationFactory(final RawPacket rawPacket) throws IOException {
-        final Reader reader = new Reader(rawPacket);
-        return new MySQLColumnInformation.Builder()
-                .catalog(reader.getLengthEncodedString())
-                .db(reader.getLengthEncodedString())
-                .table(reader.getLengthEncodedString())
-                .originalTable(reader.getLengthEncodedString())
-                .name(reader.getLengthEncodedString())
-                .originalName(reader.getLengthEncodedString())
-                .skipMe(reader.skipBytes(1))
-                .charsetNumber(reader.readShort())
-                .length(reader.readInt())
-                .type(MySQLType.fromServer(reader.readByte()))
-                .flags(parseFlags(reader.readShort()))
-                .decimals(reader.readByte())
-                .skipMe(reader.skipBytes(2))
-                .build();
+        return new MySQLColumnInformation(rawPacket);
     }
 
-    private static Set<ColumnFlags> parseFlags(final short i) {
-        final Set<ColumnFlags> retFlags = EnumSet.noneOf(ColumnFlags.class);
-        for (final ColumnFlags fieldFlag : ColumnFlags.values()) {
-            if ((i & fieldFlag.flag()) == fieldFlag.flag()) {
-                retFlags.add(fieldFlag);
-            }
-        }
-        return retFlags;
-    }
 }
\ No newline at end of file

=== modified file 'src/main/java/org/mariadb/jdbc/internal/mysql/packet/MySQLRowPacket.java'
--- a/src/main/java/org/mariadb/jdbc/internal/mysql/packet/MySQLRowPacket.java	2012-12-21 18:15:36 +0000
+++ b/src/main/java/org/mariadb/jdbc/internal/mysql/packet/MySQLRowPacket.java	2013-02-12 14:56:23 +0000
@@ -90,7 +90,6 @@ public class MySQLRowPacket {
             }
             final ValueObject dvo = new MySQLValueObject(reader.getLengthEncodedBytes(), currentColumn);
             columns.add(dvo);
-            currentColumn.updateDisplaySize(dvo.getDisplayLength());
         }
         return columns;
     }



More information about the commits mailing list