You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2020/07/29 02:27:16 UTC

[shardingsphere] branch master updated: Fix #6408 : Cannot find JDBC type '2003' in PostgreSQL column type (#6474)

This is an automated email from the ASF dual-hosted git repository.

zhangyonglun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 221f733  Fix #6408 :  Cannot find JDBC type '2003' in PostgreSQL column type (#6474)
221f733 is described below

commit 221f733a386e374279090805ef6ccc6fc929b1ad
Author: sandynz <42...@users.noreply.github.com>
AuthorDate: Wed Jul 29 10:27:01 2020 +0800

    Fix #6408 :  Cannot find JDBC type '2003' in PostgreSQL column type (#6474)
    
    * Support PostgreSQL array type (#6408)
    
    * Support PostgreSQL array type, unit test (#6408)
    
    * Support PostgreSQL array type, follow review suggestion (#6408)
---
 .../constant/PostgreSQLArrayColumnType.java        | 135 +++++++++++++++++++++
 .../command/query/PostgreSQLColumnDescription.java |  20 ++-
 .../constant/PostgreSQLArrayColumnTypeTest.java    |  38 ++++++
 .../query/PostgreSQLColumnDescriptionTest.java     |  45 +++++++
 .../infra/executor/sql/QueryResult.java            |  10 +-
 .../jdbc/queryresult/MemoryQueryResult.java        |   7 +-
 .../jdbc/queryresult/StreamQueryResult.java        |   7 +-
 .../binary/bind/PostgreSQLComBindExecutor.java     |   6 +-
 .../query/text/PostgreSQLComQueryExecutor.java     |   6 +-
 9 files changed, 267 insertions(+), 7 deletions(-)

diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLArrayColumnType.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLArrayColumnType.java
new file mode 100644
index 0000000..a535931
--- /dev/null
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLArrayColumnType.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.db.protocol.postgresql.constant;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Array column types for PostgreSQL.
+ */
+public class PostgreSQLArrayColumnType {
+    
+    private static final String ORIGINAL_RECORD_LINES =
+        "_aclitem 1034\n"
+            + "_array_tc_0 16425\n"
+            + "_array_tc_1 16433\n"
+            + "_bit 1561\n"
+            + "_bool 1000\n"
+            + "_box 1020\n"
+            + "_bpchar 1014\n"
+            + "_bytea 1001\n"
+            + "_cardinal_number 13031\n"
+            + "_char 1002\n"
+            + "_character_data 13034\n"
+            + "_cid 1012\n"
+            + "_cidr 651\n"
+            + "_circle 719\n"
+            + "_cstring 1263\n"
+            + "_date 1182\n"
+            + "_daterange 3913\n"
+            + "_float4 1021\n"
+            + "_float8 1022\n"
+            + "_gtsvector 3644\n"
+            + "_inet 1041\n"
+            + "_int2 1005\n"
+            + "_int2vector 1006\n"
+            + "_int4 1007\n"
+            + "_int4range 3905\n"
+            + "_int8 1016\n"
+            + "_int8range 3927\n"
+            + "_interval 1187\n"
+            + "_json 199\n"
+            + "_jsonb 3807\n"
+            + "_jsonpath 4073\n"
+            + "_line 629\n"
+            + "_lseg 1018\n"
+            + "_macaddr 1040\n"
+            + "_macaddr8 775\n"
+            + "_money 791\n"
+            + "_name 1003\n"
+            + "_numeric 1231\n"
+            + "_numrange 3907\n"
+            + "_oid 1028\n"
+            + "_oidvector 1013\n"
+            + "_path 1019\n"
+            + "_pg_foreign_data_wrappers 13265\n"
+            + "_pg_foreign_servers 13274\n"
+            + "_pg_foreign_table_columns 13258\n"
+            + "_pg_foreign_tables 13284\n"
+            + "_pg_lsn 3221\n"
+            + "_pg_user_mappings 13294\n"
+            + "_point 1017\n"
+            + "_polygon 1027\n"
+            + "_record 2287\n"
+            + "_refcursor 2201\n"
+            + "_regclass 2210\n"
+            + "_regconfig 3735\n"
+            + "_regdictionary 3770\n"
+            + "_regnamespace 4090\n"
+            + "_regoper 2208\n"
+            + "_regoperator 2209\n"
+            + "_regproc 1008\n"
+            + "_regprocedure 2207\n"
+            + "_regrole 4097\n"
+            + "_regtype 2211\n"
+            + "_sql_identifier 13036\n"
+            + "_test_array 16395\n"
+            + "_text 1009\n"
+            + "_tid 1010\n"
+            + "_time 1183\n"
+            + "_time_stamp 13041\n"
+            + "_timestamp 1115\n"
+            + "_timestamptz 1185\n"
+            + "_timetz 1270\n"
+            + "_tsquery 3645\n"
+            + "_tsrange 3909\n"
+            + "_tstzrange 3911\n"
+            + "_tsvector 3643\n"
+            + "_txid_snapshot 2949\n"
+            + "_uuid 2951\n"
+            + "_varbit 1563\n"
+            + "_varchar 1015\n"
+            + "_xid 1011\n"
+            + "_xml 143\n"
+            + "_yes_or_no 13043";
+    
+    private static final Map<String, Integer> COLUMN_TYPE_NAME_OID_MAP = new HashMap<>(128, 1.0F);
+    
+    static {
+        for (String line : ORIGINAL_RECORD_LINES.split("\n")) {
+            String[] values = line.split(" ");
+            COLUMN_TYPE_NAME_OID_MAP.put(values[0], Integer.parseInt(values[1]));
+        }
+    }
+    
+    /**
+     * Get type oid by database-specific column type name.
+     *
+     * @param columnTypeName PostgreSQL column type name, e.g. <code>int4</code>
+     * @return type oid, e.g. <code>23</code> for <code>int4</code>
+     * @throws IllegalArgumentException if no type oid could be found
+     */
+    public static int getTypeOidByColumnTypeName(final String columnTypeName) throws IllegalArgumentException {
+        if (COLUMN_TYPE_NAME_OID_MAP.containsKey(columnTypeName)) {
+            return COLUMN_TYPE_NAME_OID_MAP.get(columnTypeName);
+        }
+        throw new IllegalArgumentException(String.format("Cannot find PostgreSQL type oid for columnTypeName '%s'", columnTypeName));
+    }
+    
+}
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescription.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescription.java
index f8c703d..7259ac4 100644
--- a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescription.java
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescription.java
@@ -17,13 +17,19 @@
 
 package org.apache.shardingsphere.db.protocol.postgresql.packet.command.query;
 
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
 import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLArrayColumnType;
 import org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLColumnType;
 
 /**
  * Column description for PostgreSQL.
  */
 @Getter
+@Slf4j
 public final class PostgreSQLColumnDescription {
     
     private final String columnName;
@@ -40,10 +46,20 @@ public final class PostgreSQLColumnDescription {
     
     private final int dataFormat = 0;
     
-    public PostgreSQLColumnDescription(final String columnName, final int columnIndex, final int columnType, final int columnLength) {
+    public PostgreSQLColumnDescription(final String columnName, final int columnIndex, final int columnType, final int columnLength, final ResultSetMetaData resultSetMetaData) {
         this.columnName = columnName;
         this.columnIndex = columnIndex;
-        this.typeOID = PostgreSQLColumnType.valueOfJDBCType(columnType).getValue();
+        if (Types.ARRAY == columnType && null != resultSetMetaData) {
+            String columnTypeName = null;
+            try {
+                columnTypeName = resultSetMetaData.getColumnTypeName(columnIndex);
+            } catch (final SQLException ex) {
+                log.error("getColumnTypeName failed, columnName={}, columnIndex={}", columnName, columnIndex, ex);
+            }
+            this.typeOID = PostgreSQLArrayColumnType.getTypeOidByColumnTypeName(columnTypeName);
+        } else {
+            this.typeOID = PostgreSQLColumnType.valueOfJDBCType(columnType).getValue();
+        }
         this.columnLength = columnLength;
     }
 }
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLArrayColumnTypeTest.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLArrayColumnTypeTest.java
new file mode 100644
index 0000000..352363c
--- /dev/null
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLArrayColumnTypeTest.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.db.protocol.postgresql.constant;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class PostgreSQLArrayColumnTypeTest {
+    
+    @Test
+    public void assertIntegerArrayGot() {
+        int columnTypeName = PostgreSQLArrayColumnType.getTypeOidByColumnTypeName("_int4");
+        assertThat(columnTypeName, is(1007));
+    }
+    
+    @Test(expected = IllegalArgumentException.class)
+    public void assertIllegalArgExThrown() {
+        PostgreSQLArrayColumnType.getTypeOidByColumnTypeName("not_exist_type");
+    }
+    
+}
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescriptionTest.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescriptionTest.java
new file mode 100644
index 0000000..b622cfe
--- /dev/null
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/PostgreSQLColumnDescriptionTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.db.protocol.postgresql.packet.command.query;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class PostgreSQLColumnDescriptionTest {
+    
+    @Test
+    public void assertIntegerTypeOid() {
+        PostgreSQLColumnDescription description = new PostgreSQLColumnDescription("age", 1, Types.INTEGER, 4, null);
+        assertThat(description.getTypeOID(), is(23));
+    }
+    
+    @Test
+    public void assertIntegerArrayTypeOid() throws SQLException {
+        ResultSetMetaData resultSetMetaData = Mockito.mock(ResultSetMetaData.class);
+        Mockito.when(resultSetMetaData.getColumnTypeName(2)).thenReturn("_int4");
+        PostgreSQLColumnDescription description = new PostgreSQLColumnDescription("ages", 2, Types.ARRAY, 12, resultSetMetaData);
+        assertThat(description.getTypeOID(), is(1007));
+    }
+    
+}
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/QueryResult.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/QueryResult.java
index 84822d4..2509d52 100644
--- a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/QueryResult.java
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/QueryResult.java
@@ -18,6 +18,7 @@
 package org.apache.shardingsphere.infra.executor.sql;
 
 import java.io.InputStream;
+import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.util.Calendar;
 
@@ -25,7 +26,14 @@ import java.util.Calendar;
  * Query result form SQL.
  */
 public interface QueryResult {
-    
+
+    /**
+     * Get JDBC ResultSetMetaData.
+     *
+     * @return JDBC ResultSetMetaData
+     */
+    ResultSetMetaData getResultSetMetaData();
+
     /**
      * iterate next data.
      *
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/MemoryQueryResult.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/MemoryQueryResult.java
index 2e62131..35d4c26 100644
--- a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/MemoryQueryResult.java
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/MemoryQueryResult.java
@@ -111,7 +111,12 @@ public final class MemoryQueryResult implements QueryResult {
                 return resultSet.getObject(columnIndex);
         }
     }
-    
+
+    @Override
+    public ResultSetMetaData getResultSetMetaData() {
+        return resultSetMetaData;
+    }
+
     @Override
     public boolean next() {
         if (rows.hasNext()) {
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/StreamQueryResult.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/StreamQueryResult.java
index 18e0aba..ee2e1e1 100644
--- a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/StreamQueryResult.java
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/resourced/jdbc/queryresult/StreamQueryResult.java
@@ -44,7 +44,12 @@ public final class StreamQueryResult implements QueryResult {
         resultSetMetaData = resultSet.getMetaData();
         this.resultSet = resultSet;
     }
-    
+
+    @Override
+    public ResultSetMetaData getResultSetMetaData() {
+        return resultSetMetaData;
+    }
+
     @Override
     public boolean next() throws SQLException {
         return resultSet.next();
diff --git a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/binary/bind/PostgreSQLComBindExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/binary/bind/PostgreSQLComBindExecutor.java
index ea5ab51..667b169 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/binary/bind/PostgreSQLComBindExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/binary/bind/PostgreSQLComBindExecutor.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.proxy.frontend.postgresql.command.query.binary.bind;
 
+import java.sql.ResultSetMetaData;
 import lombok.Getter;
 import org.apache.shardingsphere.db.protocol.packet.DatabasePacket;
 import org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLColumnType;
@@ -29,6 +30,7 @@ import org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.bin
 import org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.text.PostgreSQLDataRowPacket;
 import org.apache.shardingsphere.db.protocol.postgresql.packet.generic.PostgreSQLCommandCompletePacket;
 import org.apache.shardingsphere.db.protocol.postgresql.packet.generic.PostgreSQLErrorResponsePacket;
+import org.apache.shardingsphere.infra.executor.sql.QueryResult;
 import org.apache.shardingsphere.infra.executor.sql.raw.execute.result.query.QueryHeader;
 import org.apache.shardingsphere.proxy.backend.communication.DatabaseCommunicationEngine;
 import org.apache.shardingsphere.proxy.backend.communication.DatabaseCommunicationEngineFactory;
@@ -117,9 +119,11 @@ public final class PostgreSQLComBindExecutor implements QueryCommandExecutor {
     
     private List<PostgreSQLColumnDescription> getPostgreSQLColumnDescriptions(final QueryResponse queryResponse) {
         List<PostgreSQLColumnDescription> result = new LinkedList<>();
+        List<QueryResult> queryResults = queryResponse.getQueryResults();
+        ResultSetMetaData resultSetMetaData = queryResults.size() > 0 ? queryResults.get(0).getResultSetMetaData() : null;
         int columnIndex = 0;
         for (QueryHeader each : queryResponse.getQueryHeaders()) {
-            result.add(new PostgreSQLColumnDescription(each.getColumnName(), ++columnIndex, each.getColumnType(), each.getColumnLength()));
+            result.add(new PostgreSQLColumnDescription(each.getColumnName(), ++columnIndex, each.getColumnType(), each.getColumnLength(), resultSetMetaData));
         }
         return result;
     }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/text/PostgreSQLComQueryExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/text/PostgreSQLComQueryExecutor.java
index 9fc8db2..a6fabff 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/text/PostgreSQLComQueryExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/text/PostgreSQLComQueryExecutor.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.proxy.frontend.postgresql.command.query.text;
 
+import java.sql.ResultSetMetaData;
 import lombok.Getter;
 import org.apache.shardingsphere.db.protocol.packet.DatabasePacket;
 import org.apache.shardingsphere.db.protocol.postgresql.packet.PostgreSQLPacket;
@@ -27,6 +28,7 @@ import org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.tex
 import org.apache.shardingsphere.db.protocol.postgresql.packet.generic.PostgreSQLCommandCompletePacket;
 import org.apache.shardingsphere.db.protocol.postgresql.packet.generic.PostgreSQLErrorResponsePacket;
 import org.apache.shardingsphere.infra.database.type.DatabaseTypes;
+import org.apache.shardingsphere.infra.executor.sql.QueryResult;
 import org.apache.shardingsphere.infra.executor.sql.raw.execute.result.query.QueryHeader;
 import org.apache.shardingsphere.proxy.backend.communication.jdbc.connection.BackendConnection;
 import org.apache.shardingsphere.proxy.backend.response.BackendResponse;
@@ -102,9 +104,11 @@ public final class PostgreSQLComQueryExecutor implements QueryCommandExecutor {
     
     private List<PostgreSQLColumnDescription> getPostgreSQLColumnDescriptions(final QueryResponse queryResponse) {
         List<PostgreSQLColumnDescription> result = new LinkedList<>();
+        List<QueryResult> queryResults = queryResponse.getQueryResults();
+        ResultSetMetaData resultSetMetaData = queryResults.size() > 0 ? queryResults.get(0).getResultSetMetaData() : null;
         int columnIndex = 0;
         for (QueryHeader each : queryResponse.getQueryHeaders()) {
-            result.add(new PostgreSQLColumnDescription(each.getColumnName(), ++columnIndex, each.getColumnType(), each.getColumnLength()));
+            result.add(new PostgreSQLColumnDescription(each.getColumnName(), ++columnIndex, each.getColumnType(), each.getColumnLength(), resultSetMetaData));
         }
         return result;
     }