Mercurial > hg > monetdb-java
changeset 175:8700d9ef2ace
Added possibility via a connection property to let the JDBC driver
return columnType value Types.VARCHAR instead of Types.CLOB in case
the result column of a ResultSet or parameter in a PreparedStatement
is of data type 'clob'.
With this connection property set, you can reduce the overhead when
working with clob column data from generic JDBC programs.
author | Martin van Dinther <martin.van.dinther@monetdbsolutions.com> |
---|---|
date | Thu, 28 Sep 2017 16:17:51 +0200 (2017-09-28) |
parents | bac9345e7d99 |
children | e701b51b3552 |
files | ChangeLog src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java |
diffstat | 5 files changed, 83 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,28 @@ # ChangeLog file for monetdb-java # This file is updated with Maddlog +* Thu Sep 28 2017 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> +- Added possibility to let the JDBC driver return columnType value + Types.VARCHAR instead of Types.CLOB in case the result column of a + ResultSet or parameter in a PreparedStatement is of data type 'clob'. + To enable this behavior provide it as JDBC connection URL property: + treat_clob_as_varchar=true + For example: jdbc:monetdb://localhost:50000/demo?treat_clob_as_varchar=true + See also: + https://www.monetdb.org/Documentation/Manuals/SQLreference/Programming/JDBC + This custom clob mapping informs generic JDBC programs to fetch clob + column values via method ResultSet.getString() instead of getClob() + and Clob.getCharacterStream() and next fetching from the stream. + As MonetDB server MAPI communication protocol do not support + streaming of parts of a CLOB value, the current implementation is to + send over the whole CLOB value as a string. Therefore there is no + performance gain when fetching those Clob values via getClob() and + getCharacterStream(). In fact it creates a lot of overhead (additional + objects and method calls) and triples the amount of needed Java Heap memory + for each Clob value! + With this connection property set, you can reduce this overhead when + working with clob column data from generic JDBC programs. + * Thu Sep 7 2017 Martin van Dinther <martin.van.dinther@monetdbsolutions.com> - Implemented PreparedStatement methods setNCharacterStream(int, Reader) and setNCharacterStream(int, Reader, long).
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @@ -141,8 +141,10 @@ public class MonetConnection /** The language which is used */ final int lang; - /** Whether or not BLOB is mapped to BINARY within the driver */ - private final boolean blobIsBinary; + /** Whether or not BLOB is mapped to Types.VARBINARY instead of Types.BLOB within this connection */ + private boolean treatBlobAsVarBinary = false; + /** Whether or not CLOB is mapped to Types.VARCHAR instead of Types.CLOB within this connection */ + private boolean treatClobAsVarChar = false; /** * Constructor of a Connection for MonetDB. At this moment the @@ -201,12 +203,18 @@ public class MonetConnection if (hash != null) conn_props.setProperty("hash", hash); - String blobIsBinary_prop = props.getProperty("treat_blob_as_binary"); - if (blobIsBinary_prop != null) { - blobIsBinary = Boolean.parseBoolean(blobIsBinary_prop); - conn_props.setProperty("treat_blob_as_binary", Boolean.toString(blobIsBinary)); - } else { - blobIsBinary = false; + String treatBlobAsVarBinary_prop = props.getProperty("treat_blob_as_binary"); + if (treatBlobAsVarBinary_prop != null) { + treatBlobAsVarBinary = Boolean.parseBoolean(treatBlobAsVarBinary_prop); + conn_props.setProperty("treat_blob_as_binary", Boolean.toString(treatBlobAsVarBinary)); + typeMap.put("blob", Byte[].class); + } + + String treatClobAsVarChar_prop = props.getProperty("treat_clob_as_varchar"); + if (treatClobAsVarChar_prop != null) { + treatClobAsVarChar = Boolean.parseBoolean(treatClobAsVarChar_prop); + conn_props.setProperty("treat_clob_as_varchar", Boolean.toString(treatClobAsVarChar)); + typeMap.put("clob", String.class); } int sockTimeout = 0; @@ -1252,8 +1260,11 @@ public class MonetConnection } } catch (SQLException se) { String msg = se.getMessage(); - // System.out.println("Con.isValid(): " + msg); - if (msg != null && msg.equals("Current transaction is aborted (please ROLLBACK)")) { + // System.out.println(se.getSQLState() + " Con.isValid(): " + msg); + if (msg != null && msg.equalsIgnoreCase("Current transaction is aborted (please ROLLBACK)")) { + // Must use equalsIgnoreCase() here because up to Jul2017 release 'Current' was 'current' so with lowercase c. + // It changed to 'Current' after Jul2017 release. We need to support all server versions. + // SQLState = 25005 isValid = true; } /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */ @@ -1371,7 +1382,9 @@ public class MonetConnection name.equals("so_timeout") || name.equals("debug") || name.equals("hash") || - name.equals("treat_blob_as_binary")) { + name.equals("treat_blob_as_binary") || + name.equals("treat_clob_as_varchar")) + { conn_props.setProperty(name, value); } else { addWarning("setClientInfo: " + name + "is not a recognised property", "01M07"); @@ -1571,12 +1584,22 @@ public class MonetConnection } /** - * Returns whether the BLOB type should be mapped to BINARY type. + * Returns whether the JDBC BLOB type should be mapped to VARBINARY type. + * This allows generic JDBC programs to fetch Blob data via getBytes() + * instead of getBlob() and Blob.getBinaryStream() to reduce overhead. */ - boolean getBlobAsBinary() { - return blobIsBinary; + boolean mapBlobAsVarBinary() { + return treatBlobAsVarBinary; } + /** + * Returns whether the JDBC CLOB type should be mapped to VARCHAR type. + * This allows generic JDBC programs to fetch Clob data via getString() + * instead of getClob() and Clob.getCharacterStream() to reduce overhead. + */ + boolean mapClobAsVarChar() { + return treatClobAsVarChar; + } /** * Sends the given string to MonetDB as special transaction command.
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in @@ -253,6 +253,11 @@ final public class MonetDriver implement prop.description = "Whether BLOBs on the server should be treated as BINARY types, thus mapped to byte[]"; props.add(prop); + prop = new DriverPropertyInfo("treat_clob_as_varchar", "false"); + prop.required = false; + prop.description = "Whether CLOBs on the server should be treated and handled as VARCHAR types in the JDBC driver"; // recommend for increased performance due to less overhead + props.add(prop); + prop = new DriverPropertyInfo("so_timeout", "0"); prop.required = false; prop.description = "Defines the maximum time to wait in milliseconds on a blocking read socket call"; // this corresponds to the Connection.setNetworkTimeout() method introduced in JDBC 4.1
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java @@ -156,6 +156,14 @@ public class MonetPreparedStatement for (int i = 0; rs.next(); i++) { monetdbType[i] = rs.getString(type_colnr); javaType[i] = MonetDriver.getJavaType(monetdbType[i]); + if (javaType[i] == Types.CLOB) { + if (connection.mapClobAsVarChar()) + javaType[i] = Types.VARCHAR; + } else + if (javaType[i] == Types.BLOB) { + if (connection.mapBlobAsVarBinary()) + javaType[i] = Types.VARBINARY; + } digits[i] = rs.getInt(digits_colnr); scale[i] = rs.getInt(scale_colnr); if (rscolcnt == 3)
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java @@ -196,14 +196,21 @@ public class MonetResultSet * thereby improving getXyz() method performance. */ private void populateJdbcSQLtypesArray() { + MonetConnection connection = null; + try { + connection = (MonetConnection)statement.getConnection(); + } catch (SQLException se) { /* ignore it */ } + for (int i = 0; i < types.length; i++) { int javaSQLtype = MonetDriver.getJavaType(types[i]); JdbcSQLTypes[i] = javaSQLtype; + if (javaSQLtype == Types.CLOB) { + if (connection != null && connection.mapClobAsVarChar()) + JdbcSQLTypes[i] = Types.VARCHAR; + } else if (javaSQLtype == Types.BLOB) { - try { - if (((MonetConnection)statement.getConnection()).getBlobAsBinary()) - JdbcSQLTypes[i] = Types.BINARY; - } catch (SQLException se) { /* ignore it */ } + if (connection != null && connection.mapBlobAsVarBinary()) + JdbcSQLTypes[i] = Types.VARBINARY; } } }