Mercurial > hg > monetdb-java
changeset 87:2b5e32efb1a4 embedded
Made all the mappings for the MAPI connection, now it needs to be added on the Embedded connection. Changed the compilation target to 1.8 because of the timezones. Implemented some JDBC methods as well.
line wrap: on
line diff
--- a/build.xml +++ b/build.xml @@ -18,7 +18,6 @@ Copyright 1997 - July 2008 CWI, August 2 <project name="MonetDB_Java_Drivers" default="default" basedir="."> - <!-- set global properties for this build --> <property name="srcdir" value="src/main/java" /> <property name="libdir" value="lib" /> @@ -33,17 +32,12 @@ Copyright 1997 - July 2008 CWI, August 2 <property file="build.properties" /> - <property name="jdbc-jar" - value="${jardir}/monetdb-jdbc-${JDBC_MAJOR}.${JDBC_MINOR}.jar" /> - <property name="jdbcclient-jar" - value="${jardir}/jdbcclient.jar" /> - <property name="jmonetdb-jar" - value="${jardir}/jmonetdb.jar" /> - <property name="mcl-jar" - value="${jardir}/monetdb-mcl-${MCL_MAJOR}.${MCL_MINOR}.jar" /> + <property name="jdbc-jar" value="${jardir}/monetdb-jdbc-${JDBC_MAJOR}.${JDBC_MINOR}.jar" /> + <property name="jdbcclient-jar" value="${jardir}/jdbcclient.jar" /> + <property name="jmonetdb-jar" value="${jardir}/jmonetdb.jar" /> + <property name="mcl-jar" value="${jardir}/monetdb-mcl-${MCL_MAJOR}.${MCL_MINOR}.jar" /> - <property name="mero-control-jar" - value="${jardir}/merocontrol.jar" /> + <property name="mero-control-jar" value="${jardir}/merocontrol.jar" /> <!-- @@ -56,8 +50,11 @@ Copyright 1997 - July 2008 CWI, August 2 since EOL. 2015-07-16, sjoerd@acm.org + Update Compile it to Java 8 for the simplicity of the implementation of the driver + 2017-01-03, ferreira@cwi.nl + --> - <property name="jvm.version" value="1.7" /> + <property name="jvm.version" value="1.8" /> <property name="javac.flags" value="-Xlint:-options" /> <!-- full target -->
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetBlob.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetBlob.java @@ -42,9 +42,6 @@ public class MonetBlob implements Blob, * * After free has been called, any attempt to invoke a method other than free will result in a SQLException being * thrown. If free is called multiple times, the subsequent calls to free are treated as a no-op. - * - * @throws SQLException if an error occurs releasing the Blob's resources - * @throws SQLFeatureNotSupportedException - if the JDBC driver does not support this method */ @Override public void free() throws SQLException { @@ -56,7 +53,6 @@ public class MonetBlob implements Blob, * * @return a stream containing the BLOB data * @throws SQLException if there is an error accessing the BLOB value - * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method */ @Override public InputStream getBinaryStream() throws SQLException { @@ -75,7 +71,6 @@ public class MonetBlob implements Blob, * @return InputStream through which the partial Blob value can be read. * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes in the Blob or if pos + * length is greater than the number of bytes in the Blob - * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method */ @Override public InputStream getBinaryStream(long pos, long length) throws SQLException {
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetClob.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetClob.java @@ -48,11 +48,13 @@ public class MonetClob implements Clob, * Retrieves the CLOB value designated by this Clob object as an ascii stream. * * @return a java.io.InputStream object containing the CLOB data - * @throws SQLFeatureNotSupportedException this JDBC driver does not support this method + * @throws SQLException if there is an error accessing the CLOB value */ @Override public InputStream getAsciiStream() throws SQLException { - throw new SQLFeatureNotSupportedException("Operation getAsciiStream() currently not supported", "0A000"); + if (buffer.length() == 0) + throw new SQLException("This Clob has been freed", "M1M20"); + return new ByteArrayInputStream(buffer.toString().getBytes()); } /** @@ -60,11 +62,13 @@ public class MonetClob implements Clob, * (or as a stream of characters). * * @return a java.io.Reader object containing the CLOB data - * @throws SQLFeatureNotSupportedException this JDBC driver does not support this method + * @throws SQLException if there is an error accessing the CLOB value */ @Override public Reader getCharacterStream() throws SQLException { - throw new SQLFeatureNotSupportedException("Operation getCharacterStream() currently not supported", "0A000"); + if (buffer.length() == 0) + throw new SQLException("This Clob has been freed", "M1M20"); + return new StringReader(buffer.toString()); } /** @@ -75,12 +79,13 @@ public class MonetClob implements Clob, * Clob is at position 1. * @param length the length in characters of the partial value to be retrieved. * @return Reader through which the partial Clob value can be read. - * @throws SQLFeatureNotSupportedException this JDBC driver does not support this method + * @throws SQLException if there is an error accessing the CLOB value */ @Override public Reader getCharacterStream(long pos, long length) throws SQLException { - throw new SQLFeatureNotSupportedException("Operation getCharacterStream(long, long) currently not supported", - "0A000"); + if (buffer.length() == 0) + throw new SQLException("This Clob has been freed", "M1M20"); + return new StringReader(buffer.substring((int)(pos - 1), (int)(pos - 1 + length))); } /** @@ -209,7 +214,7 @@ public class MonetClob implements Clob, public void truncate(long len) throws SQLException { if (buffer.length() == 0) throw new SQLException("This Clob has been freed", "M1M20"); - // this command is a no-op + buffer.setLength((int) len); } /**
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @@ -1,7 +1,7 @@ package nl.cwi.monetdb.jdbc; -import nl.cwi.monetdb.jdbc.types.INET; -import nl.cwi.monetdb.jdbc.types.URL; +import nl.cwi.monetdb.jdbc.types.MonetINET; +import nl.cwi.monetdb.jdbc.types.MonetURL; import nl.cwi.monetdb.mcl.connection.*; import nl.cwi.monetdb.mcl.connection.SenderThread; import nl.cwi.monetdb.mcl.connection.mapi.MapiLanguage; @@ -71,8 +71,8 @@ public abstract class MonetConnection ex /** The Connection specific mapping of user defined types to Java types */ private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() { private static final long serialVersionUID = 1L; { - put("inet", INET.class); - put("url", URL.class); + put("inet", MonetINET.class); + put("url", MonetURL.class); } }; @@ -80,13 +80,13 @@ public abstract class MonetConnection ex // (only when you deal with it of course) /** A Map containing all (active) Statements created from this Connection */ private Map<Statement,?> statements = new WeakHashMap<Statement, Object>(); - /** The number of results we receive from the server at once */ private int curReplySize = -1; // the server by default uses -1 (all) - /** Whether or not BLOB is mapped to BINARY within the driver */ private final boolean blobIsBinary; - + /** Whether or not CLOB is mapped to LONGVARCHAR within the driver */ + private final boolean clobIsLongChar; + /** The underlying proticol provided by the connection (MAPI or embedded) */ protected AbstractProtocol protocol; /** @@ -97,22 +97,19 @@ public abstract class MonetConnection ex * @throws IOException if an error occurs */ public MonetConnection(Properties props, String database, String hash, IMonetDBLanguage language, - boolean blobIsBinary) throws IOException { + boolean blobIsBinary, boolean clobIsLongChar) throws IOException { this.conn_props = props; this.database = database; this.hash = hash; this.language = language; this.blobIsBinary = blobIsBinary; + this.clobIsLongChar = clobIsLongChar; } public IMonetDBLanguage getLanguage() { return language; } - public void setClosed(boolean closed) { - this.closed = closed; - } - public AbstractProtocol getProtocol() { return this.protocol; } @@ -350,11 +347,9 @@ public abstract class MonetConnection ex } /** - * Retrieves this Connection object's current transaction isolation - * level. + * Retrieves this Connection object's current transaction isolation level. * - * @return the current transaction isolation level, which will be - * Connection.TRANSACTION_SERIALIZABLE + * @return the current transaction isolation level, which will be Connection.TRANSACTION_SERIALIZABLE */ @Override public int getTransactionIsolation() { @@ -366,8 +361,7 @@ public abstract class MonetConnection ex * Unless the application has added an entry, the type map returned * will be empty. * - * @return the java.util.Map object associated with this Connection - * object + * @return the java.util.Map object associated with this Connection object */ @Override public Map<String,Class<?>> getTypeMap() { @@ -381,22 +375,19 @@ public abstract class MonetConnection ex * the method SQLWarning.getNextWarning on the warning that was * retrieved previously. * - * This method may not be called on a closed connection; doing so - * will cause an SQLException to be thrown. + * This method may not be called on a closed connection; doing so will cause an SQLException to be thrown. * * Note: Subsequent warnings will be chained to this SQLWarning. * * @return the first SQLWarning object or null if there are none - * @throws SQLException if a database access error occurs or this method is - * called on a closed connection + * @throws SQLException if a database access error occurs or this method is called on a closed connection */ @Override public SQLWarning getWarnings() throws SQLException { if (closed) { throw new SQLException("Cannot call on closed Connection", "M1M20"); } - // if there are no warnings, this will be null, which fits with the - // specification. + // if there are no warnings, this will be null, which fits with the specification. return warnings; } @@ -412,8 +403,7 @@ public abstract class MonetConnection ex * can determine that a connection is invalid by catching any * exceptions that might be thrown when an operation is attempted. * - * @return true if this Connection object is closed; false if it is - * still open + * @return true if this Connection object is closed; false if it is still open */ @Override public boolean isClosed() { @@ -443,7 +433,8 @@ public abstract class MonetConnection ex public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) {return null;} @Override - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {return null;} + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) {return null;} /** * Creates a PreparedStatement object for sending parameterized SQL @@ -474,7 +465,8 @@ public abstract class MonetConnection ex */ @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); + return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + ResultSet.HOLD_CURSORS_OVER_COMMIT); } /** @@ -498,7 +490,8 @@ public abstract class MonetConnection ex * type and concurrency */ @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { return prepareStatement(sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT); } @@ -529,9 +522,11 @@ public abstract class MonetConnection ex * concurrency, and holdability */ @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { try { - PreparedStatement ret = new MonetPreparedStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability, sql); + PreparedStatement ret = new MonetPreparedStatement(this, resultSetType, resultSetConcurrency, + resultSetHoldability, sql); // store it in the map for when we close... statements.put(ret, null); return ret; @@ -1035,7 +1030,6 @@ public abstract class MonetConnection ex return new Properties(conn_props); } - /** * Sets the value of the client info property specified by name to the value specified by value. * Applications may use the DatabaseMetaData.getClientInfoProperties method to determine @@ -1085,16 +1079,10 @@ public abstract class MonetConnection ex return; } // only set value for supported property names - if (name.equals("host") || - name.equals("port") || - name.equals("user") || - name.equals("password") || - name.equals("database") || - name.equals("language") || - name.equals("so_timeout") || - name.equals("debug") || - name.equals("hash") || - name.equals("treat_blob_as_binary")) { + if (name.equals("host") || name.equals("port") || name.equals("user") || name.equals("password") || + name.equals("database") || name.equals("language") || name.equals("so_timeout") || + name.equals("debug") || name.equals("hash") || name.equals("treat_blob_as_binary") || + name.equals("treat_clob_as_longvarchar") || name.equals("embedded") || name.equals("directory")) { conn_props.setProperty(name, value); } else { addWarning("setClientInfo: " + name + "is not a recognised property", "01M07"); @@ -1263,6 +1251,13 @@ public abstract class MonetConnection ex } /** + * Returns whether the CLOB type should be mapped to LONGVARCHAR type. + */ + public boolean getClobAsLongChar() { + return clobIsLongChar; + } + + /** * Sends the given string to MonetDB as regular statement, making sure there is a prompt after the command is sent. * All possible returned information is discarded. Encountered errors are reported. *
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDataSource.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDataSource.java @@ -29,12 +29,14 @@ import java.util.logging.Logger; * @version 0.1 */ public class MonetDataSource extends MonetWrapper implements DataSource { - private String description; - private int loginTimeout = 0; + private String user; - // insecure, but how to do it better? - private String password; - private String url; + private String password; // insecure, but how to do it better? + private String description = "MonetDB database"; + private String url = "jdbc:monetdb://localhost/"; + private int loginTimeout; + private String embeddedDirectory; + private final MonetDriver driver = new MonetDriver(); // the following properties are also standard: // private String dataSourceName; @@ -42,17 +44,7 @@ public class MonetDataSource extends Mon // private String serverName; // private String role; - private final MonetDriver driver; - - /** - * Constructor of a MonetDataSource which uses default settings for a connection. You probably want to change this - * setting using the method setURL. - */ - public MonetDataSource() { - description = "MonetDB database"; - url = "jdbc:monetdb://localhost/"; - driver = new MonetDriver(); - } + public MonetDataSource() {} /** * Attempts to establish a connection with the data source that this DataSource object represents. @@ -75,12 +67,16 @@ public class MonetDataSource extends Mon */ @Override public Connection getConnection(String username, String password) throws SQLException { - if (loginTimeout > 0) { - /// could enable Socket.setSoTimeout(int timeout) here... - } Properties props = new Properties(); props.put("user", username); props.put("password", password); + if (loginTimeout > 0) { + props.put("so_timeout", Integer.toString(loginTimeout)); + } + if(embeddedDirectory != null) { + props.put("embedded", "true"); + props.put("directory", embeddedDirectory); + } return driver.connect(url, props); } @@ -186,7 +182,25 @@ public class MonetDataSource extends Mon this.description = description; } - /** + /** + * Gets the embedded connection directory. If null, then a MAPI connection will be created instead. + * + * @return The embedded connection directory String. If null, then a MAPI connection will be created instead. + */ + public String getEmbeddedDirectory() { + return embeddedDirectory; + } + + /** + * Sets the embedded connection directory, thus making the connection embedded. + * + * @param embeddedDirectory The embedded connection directory to set + */ + public void setEmbeddedDirectory(String embeddedDirectory) { + this.embeddedDirectory = embeddedDirectory; + } + + /** * Return the parent Logger of all the Loggers used by this data * source. This should be the Logger farthest from the root Logger * that is still an ancestor of all of the Loggers used by this data
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java @@ -1694,12 +1694,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database access error occurs */ @Override - public ResultSet getProcedures( - String catalog, - String schemaPattern, - String procedureNamePattern - ) throws SQLException - { + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) + throws SQLException { StringBuilder query = new StringBuilder(980); query.append("SELECT cast(null as varchar(1)) AS \"PROCEDURE_CAT\", " + "\"schemas\".\"name\" AS \"PROCEDURE_SCHEM\", " + @@ -1800,12 +1796,8 @@ public class MonetDatabaseMetaData exten * @see #getSearchStringEscape */ @Override - public ResultSet getProcedureColumns( - String catalog, - String schemaPattern, - String procedureNamePattern, - String columnNamePattern - ) throws SQLException { + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, + String columnNamePattern) throws SQLException { StringBuilder query = new StringBuilder(2900); query.append("SELECT cast(null as varchar(1)) AS \"PROCEDURE_CAT\", " + "\"schemas\".\"name\" AS \"PROCEDURE_SCHEM\", " + @@ -1932,13 +1924,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database-access error occurs. */ @Override - public ResultSet getTables( - String catalog, - String schemaPattern, - String tableNamePattern, - String types[] - ) throws SQLException - { + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) + throws SQLException { // as of Jul2015 release the sys.tables.type values (0 through 6) is extended with new values 10, 11, 20, and 30 (for system and temp tables/views). // as of Jul2015 release we also have a new table: sys.table_types with names for the new table types // for correct behavior we need to know if the server is using the old (pre Jul2015) or new sys.tables.type values @@ -2035,9 +2022,7 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getSchemas(String catalog, String schemaPattern) - throws SQLException - { + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { StringBuilder query = new StringBuilder(170); query.append("SELECT \"name\" AS \"TABLE_SCHEM\", " + "cast(null as char(1)) AS \"TABLE_CATALOG\" " + @@ -2183,13 +2168,8 @@ public class MonetDatabaseMetaData exten * @see #getSearchStringEscape */ @Override - public ResultSet getColumns( - String catalog, - String schemaPattern, - String tableNamePattern, - String columnNamePattern - ) throws SQLException - { + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) + throws SQLException { StringBuilder query = new StringBuilder(2450); query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + @@ -2274,13 +2254,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getColumnPrivileges( - String catalog, - String schemaPattern, - String tableNamePattern, - String columnNamePattern - ) throws SQLException - { + public ResultSet getColumnPrivileges(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { StringBuilder query = new StringBuilder(1100); query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + @@ -2363,12 +2338,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getTablePrivileges( - String catalog, - String schemaPattern, - String tableNamePattern - ) throws SQLException - { + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { StringBuilder query = new StringBuilder(1000); query.append("SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + @@ -2452,14 +2423,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getBestRowIdentifier( - String catalog, - String schema, - String table, - int scope, - boolean nullable - ) throws SQLException - { + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) + throws SQLException { StringBuilder query = new StringBuilder(1500); query.append("SELECT CAST(").append(DatabaseMetaData.bestRowSession).append(" AS smallint) AS \"SCOPE\", " + "\"columns\".\"name\" AS \"COLUMN_NAME\", " + @@ -2532,12 +2497,7 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getVersionColumns( - String catalog, - String schema, - String table - ) throws SQLException - { + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { // MonetDB currently does not have columns which update themselves, so return an empty ResultSet String query = "SELECT CAST(0 as smallint) AS \"SCOPE\", " + @@ -2575,12 +2535,7 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getPrimaryKeys( - String catalog, - String schema, - String table - ) throws SQLException - { + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { StringBuilder query = new StringBuilder(600); query.append("SELECT cast(null AS varchar(1)) AS \"TABLE_CAT\", " + "\"schemas\".\"name\" AS \"TABLE_SCHEM\", " + @@ -2614,7 +2569,6 @@ public class MonetDatabaseMetaData exten return executeMetaDataQuery(query.toString()); } - private final static String keyQuery = "SELECT cast(null AS varchar(1)) AS \"PKTABLE_CAT\", " + "\"pkschema\".\"name\" AS \"PKTABLE_SCHEM\", " + @@ -2709,9 +2663,7 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getImportedKeys(String catalog, String schema, String table) - throws SQLException - { + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { StringBuilder query = new StringBuilder(keyQuery.length() + 250); query.append(keyQuery); @@ -2792,9 +2744,7 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database error occurs */ @Override - public ResultSet getExportedKeys(String catalog, String schema, String table) - throws SQLException - { + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { StringBuilder query = new StringBuilder(keyQuery.length() + 250); query.append(keyQuery); @@ -2881,15 +2831,8 @@ public class MonetDatabaseMetaData exten * @see #getImportedKeys */ @Override - public ResultSet getCrossReference( - String pcatalog, - String pschema, - String ptable, - String fcatalog, - String fschema, - String ftable - ) throws SQLException - { + public ResultSet getCrossReference(String pcatalog, String pschema, String ptable, String fcatalog, String fschema, + String ftable) throws SQLException { StringBuilder query = new StringBuilder(keyQuery.length() + 350); query.append(keyQuery); @@ -3062,14 +3005,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database occurs */ @Override - public ResultSet getIndexInfo( - String catalog, - String schema, - String table, - boolean unique, - boolean approximate - ) throws SQLException - { + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) + throws SQLException { String table_row_count = "0"; if (!approximate && schema != null && table != null && schema.length() > 0 && table.length() > 0) { @@ -3156,8 +3093,7 @@ public class MonetDatabaseMetaData exten /** - * Does the database support the concurrency type in combination - * with the given result set type? + * Does the database support the concurrency type in combination with the given result set type? * * @param type - defined in java.sql.ResultSet * @param concurrency - type defined in java.sql.ResultSet @@ -3165,9 +3101,7 @@ public class MonetDatabaseMetaData exten * @throws SQLException - if a database access error occurs */ @Override - public boolean supportsResultSetConcurrency(int type, int concurrency) - throws SQLException - { + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { // These combinations are not supported! if (type == ResultSet.TYPE_SCROLL_SENSITIVE) return false; @@ -3256,13 +3190,8 @@ public class MonetDatabaseMetaData exten * */ @Override - public ResultSet getUDTs( - String catalog, - String schemaPattern, - String typeNamePattern, - int[] types - ) throws SQLException - { + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) + throws SQLException { StringBuilder query = new StringBuilder(990); if (types != null && types.length > 0) { query.append("SELECT * FROM ("); @@ -3336,8 +3265,7 @@ public class MonetDatabaseMetaData exten /** * Retrieves whether this database supports savepoints. * - * @return <code>true</code> if savepoints are supported; - * <code>false</code> otherwise + * @return <code>true</code> if savepoints are supported; <code>false</code> otherwise */ @Override public boolean supportsSavepoints() { @@ -3345,11 +3273,9 @@ public class MonetDatabaseMetaData exten } /** - * Retrieves whether this database supports named parameters to callable - * statements. + * Retrieves whether this database supports named parameters to callable statements. * - * @return <code>true</code> if named parameters are supported; - * <code>false</code> otherwise + * @return <code>true</code> if named parameters are supported; <code>false</code> otherwise */ @Override public boolean supportsNamedParameters() { @@ -3358,12 +3284,10 @@ public class MonetDatabaseMetaData exten /** * Retrieves whether it is possible to have multiple <code>ResultSet</code> objects - * returned from a <code>CallableStatement</code> object - * simultaneously. + * returned from a <code>CallableStatement</code> object simultaneously. * * @return <code>true</code> if a <code>CallableStatement</code> object - * can return multiple <code>ResultSet</code> objects - * simultaneously; <code>false</code> otherwise + * can return multiple <code>ResultSet</code> objects simultaneously; <code>false</code> otherwise */ @Override public boolean supportsMultipleOpenResults() { @@ -3371,11 +3295,10 @@ public class MonetDatabaseMetaData exten } /** - * Retrieves whether auto-generated keys can be retrieved after - * a statement has been executed. + * Retrieves whether auto-generated keys can be retrieved after a statement has been executed. * - * @return <code>true</code> if auto-generated keys can be retrieved - * after a statement has executed; <code>false</code> otherwise + * @return <code>true</code> if auto-generated keys can be retrieved after a statement has executed; + * <code>false</code> otherwise */ @Override public boolean supportsGetGeneratedKeys() { @@ -3422,17 +3345,10 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database access error occurs */ @Override - public ResultSet getSuperTypes( - String catalog, - String schemaPattern, - String typeNamePattern - ) throws SQLException - { - String query = - "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " + + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + String query = "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " + "cast(null as char(1)) AS \"SUPERTYPE_CAT\", '' AS \"SUPERTYPE_SCHEM\", '' AS \"SUPERTYPE_NAME\" " + "WHERE 1 = 0"; - return executeMetaDataQuery(query); } @@ -3469,17 +3385,9 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database access error occurs */ @Override - public ResultSet getSuperTables( - String catalog, - String schemaPattern, - String tableNamePattern - ) throws SQLException - { - String query = - "SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + - "'' AS \"TABLE_SCHEM\", '' AS \"TABLE_NAME\", '' AS \"SUPERTABLE_NAME\" " + - "WHERE 1 = 0"; - + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + String query = "SELECT cast(null as char(1)) AS \"TABLE_CAT\", " + + "'' AS \"TABLE_SCHEM\", '' AS \"TABLE_NAME\", '' AS \"SUPERTABLE_NAME\" WHERE 1 = 0"; return executeMetaDataQuery(query); } @@ -3553,15 +3461,9 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database access error occurs */ @Override - public ResultSet getAttributes( - String catalog, - String schemaPattern, - String typeNamePattern, - String attributeNamePattern - ) throws SQLException - { - String query = - "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " + + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, + String attributeNamePattern) throws SQLException { + String query = "SELECT cast(null as char(1)) AS \"TYPE_CAT\", '' AS \"TYPE_SCHEM\", '' AS \"TYPE_NAME\", " + "'' AS \"ATTR_NAME\", CAST(0 as int) AS \"DATA_TYPE\", '' AS \"ATTR_TYPE_NAME\", CAST(0 as int) AS \"ATTR_SIZE\", " + "CAST(0 as int) AS \"DECIMAL_DIGITS\", CAST(0 as int) AS \"NUM_PREC_RADIX\", CAST(0 as int) AS \"NULLABLE\", " + "'' AS \"REMARKS\", '' AS \"ATTR_DEF\", CAST(0 as int) AS \"SQL_DATA_TYPE\", " + @@ -3570,15 +3472,13 @@ public class MonetDatabaseMetaData exten "'' AS \"SCOPE_CATALOG\", '' AS \"SCOPE_SCHEMA\", '' AS \"SCOPE_TABLE\", " + "CAST(0 as smallint) AS \"SOURCE_DATA_TYPE\" " + "WHERE 1 = 0"; - return executeMetaDataQuery(query); } /** * Retrieves whether this database supports the given result set holdability. * - * @param holdability one of the following constants: - * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or + * @param holdability one of the following constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> * @return <code>true</code> if so; <code>false</code> otherwise * @see Connection @@ -3591,12 +3491,10 @@ public class MonetDatabaseMetaData exten } /** - * Retrieves the default holdability of this <code>ResultSet</code> - * object. + * Retrieves the default holdability of this <code>ResultSet</code> object. * - * @return the default holdability; either - * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or - * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> + * @return the default holdability; either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or + * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> */ @Override public int getResultSetHoldability() { @@ -3674,9 +3572,7 @@ public class MonetDatabaseMetaData exten /** * Indicates whether the SQLSTATEs returned by <code>SQLException.getSQLState</code> * is X/Open (now known as Open Group) SQL CLI or SQL:2003. - * @return the type of SQLSTATEs, one of: - * sqlStateXOpen or - * sqlStateSQL + * @return the type of SQLSTATEs, one of: sqlStateXOpen or sqlStateSQL */ @Override public int getSQLStateType() { @@ -3685,8 +3581,7 @@ public class MonetDatabaseMetaData exten } /** - * Indicates whether updates made to a LOB are made on a copy or directly - * to the LOB. + * Indicates whether updates made to a LOB are made on a copy or directly to the LOB. * @return <code>true</code> if updates are made to a copy of the LOB; * <code>false</code> if updates are made directly to the LOB */ @@ -3711,9 +3606,8 @@ public class MonetDatabaseMetaData exten //== 1.6 methods (JDBC 4) /** - * Indicates whether or not this data source supports the SQL ROWID - * type, and if so the lifetime for which a RowId object remains - * valid. + * Indicates whether or not this data source supports the SQL ROWID type, and if so the lifetime for which a RowId + * object remains valid. * * @return ROWID_UNSUPPORTED for now */ @@ -3724,8 +3618,7 @@ public class MonetDatabaseMetaData exten } /** - * Get the schema names available in this database. The results - * are ordered by schema name. + * Get the schema names available in this database. The results are ordered by schema name. * * <P>The schema column is: * <OL> @@ -3733,8 +3626,7 @@ public class MonetDatabaseMetaData exten * <LI><B>TABLE_CATALOG</B> String => catalog name (may be null) * </OL> * - * @return ResultSet each row has a single String column that is a - * schema name + * @return ResultSet each row has a single String column that is a schema name * @throws SQLException if a database error occurs */ @Override @@ -3743,8 +3635,8 @@ public class MonetDatabaseMetaData exten } /** - * Retrieves whether this database supports invoking user-defined or - * vendor functions using the stored procedure escape syntax. + * Retrieves whether this database supports invoking user-defined or vendor functions using the stored procedure + * escape syntax. * * @return true if so; false otherwise */ @@ -3787,8 +3679,8 @@ public class MonetDatabaseMetaData exten * * The ResultSet is sorted by the NAME column * - * @return A ResultSet object; each row is a supported client info - * property, none in case of MonetDB's current JDBC driver + * @return A ResultSet object; each row is a supported client info property, none in case of MonetDB's current JDBC + * driver * @throws SQLException if a database access error occurs */ @Override @@ -3852,12 +3744,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database access error occurs */ @Override - public ResultSet getFunctions( - String catalog, - String schemaPattern, - String functionNamePattern) - throws SQLException - { + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) + throws SQLException { StringBuilder query = new StringBuilder(800); query.append("SELECT cast(null as varchar(1)) AS \"FUNCTION_CAT\", " + "\"schemas\".\"name\" AS \"FUNCTION_SCHEM\", " + @@ -3952,13 +3840,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException - if a database access error occurs */ @Override - public ResultSet getFunctionColumns( - String catalog, - String schemaPattern, - String functionNamePattern, - String columnNamePattern) - throws SQLException - { + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, + String columnNamePattern) throws SQLException { StringBuilder query = new StringBuilder(2600); query.append("SELECT DISTINCT CAST(null as char(1)) AS \"FUNCTION_CAT\", " + "\"schemas\".\"name\" AS \"FUNCTION_SCHEM\", " + @@ -4051,13 +3934,8 @@ public class MonetDatabaseMetaData exten * @throws SQLException if a database access error occurs */ @Override - public ResultSet getPseudoColumns( - String catalog, - String schemaPattern, - String tableNamePattern, - String columnNamePattern) - throws SQLException - { + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { // MonetDB currently does not support pseudo or hidden columns, so return an empty ResultSet String query = "SELECT CAST(null as char(1)) AS \"TABLE_CAT\", " +
deleted file mode 100644 --- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. - */ - -package nl.cwi.monetdb.jdbc; - -import nl.cwi.monetdb.mcl.connection.MonetDBConnectionFactory; - -import java.net.URI; -import java.net.URISyntaxException; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.DriverManager; -import java.sql.DriverPropertyInfo; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.sql.Types; -import java.util.*; -import java.util.Map.Entry; -import java.util.logging.Logger; - -/** - * A Driver suitable for the MonetDB database. - * - * This driver will be used by the DriverManager to determine if an URL - * is to be handled by this driver, and if it does, then this driver - * will supply a Connection suitable for MonetDB. - * - * This class has no explicit constructor, the default constructor - * generated by the Java compiler will be sufficient since nothing has - * to be set in order to use this driver. - * - * This Driver supports MonetDB database URLs. MonetDB URLs are defined - * as: - * <tt>jdbc:monetdb://<host>[:<port>]/<database></tt> - * where [:<port>] denotes that a port is optional. If not - * given the default (@JDBC_DEF_PORT@) will be used. - * - * @author Fabian Groffen - * @version @JDBC_MAJOR@.@JDBC_MINOR@ (@JDBC_VER_SUFFIX@) - */ -final public class MonetDriver implements Driver { - // the url kind will be jdbc:monetdb://<host>[:<port>]/<database> - // Chapter 9.2.1 from Sun JDBC 3.0 specification - /** The prefix of a MonetDB url */ - private static final String MONETURL = "jdbc:monetdb://"; - /** Major version of this driver */ - private static final int DRIVERMAJOR = 4; - /** Minor version of this driver */ - private static final int DRIVERMINOR = 1; - /** Version suffix string */ - private static final String DRIVERVERSIONSUFFIX = "@JDBC_VER_SUFFIX@ based on MCL v@MCL_MAJOR@.@MCL_MINOR@"; - // We're not fully compliant, but what we support is compliant - /** Whether this driver is JDBC compliant or not */ - private static final boolean MONETJDBCCOMPLIANT = false; - - /** MonetDB default port to connect to */ - private static final String PORT = "50000"; - - public static String getPORT() { - return PORT; - } - - // initialize this class: register it at the DriverManager - // Chapter 9.2 from Sun JDBC 3.0 specification - static { - try { - DriverManager.registerDriver(new MonetDriver()); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - //== methods of interface Driver - - /** - * Retrieves whether the driver thinks that it can open a connection to the - * given URL. Typically drivers will return true if they understand the - * subprotocol specified in the URL and false if they do not. - * - * @param url the URL of the database - * @return true if this driver understands the given URL; false otherwise - */ - public boolean acceptsURL(String url) { - return url != null && url.startsWith(MONETURL); - } - - /** - * Attempts to make a database connection to the given URL. The driver - * should return "null" if it realizes it is the wrong kind of driver to - * connect to the given URL. This will be common, as when the JDBC driver - * manager is asked to connect to a given URL it passes the URL to each - * loaded driver in turn. - * - * The driver should throw an SQLException if it is the right driver to - * connect to the given URL but has trouble connecting to the database. - * - * The java.util.Properties argument can be used to pass arbitrary string - * tag/value pairs as connection arguments. Normally at least "user" and - * "password" properties should be included in the Properties object. - * - * @param url the URL of the database to which to connect - * @param info a list of arbitrary string tag/value pairs as connection - * arguments. Normally at least a "user" and "password" property - * should be included - * @return a Connection object that represents a connection to the URL - * @throws SQLException if a database access error occurs - */ - public Connection connect(String url, Properties info) throws SQLException { - int tmp; - Properties props = new Properties(); - props.put("port", PORT); - props.putAll(info); - info = props; - - // url should be of style jdbc:monetdb://<host>/<database> - if (!acceptsURL(url)) - throw new SQLException("Invalid URL: it does not start with: " + MONETURL, "08M26"); - - // remove leading "jdbc:" so the rest is a valid hierarchical URI - URI uri; - try { - uri = new URI(url.substring(5)); - } catch (URISyntaxException e) { - throw new SQLException(e.toString(), "08M26"); - } - - String uri_host = uri.getHost(); - if (uri_host == null) - throw new SQLException("Invalid URL: no hostname given or unparsable in '" + url + "'", "08M26"); - info.put("host", uri_host); - - int uri_port = uri.getPort(); - if (uri_port > 0) - info.put("port", "" + uri_port); - - // check the database - String uri_path = uri.getPath(); - if (uri_path != null && uri_path.length() != 0) { - uri_path = uri_path.substring(1); - if (!uri_path.trim().isEmpty()) - info.put("database", uri_path); - } - - String uri_query = uri.getQuery(); - if (uri_query != null) { - // handle additional arguments - String args[] = uri_query.split("&"); - for (String arg : args) { - tmp = arg.indexOf('='); - if (tmp > 0) - info.put(arg.substring(0, tmp), arg.substring(tmp + 1)); - } - } - - // finally return the Connection as requested - return MonetDBConnectionFactory.CreateMonetDBJDBCConnection(info); - } - - /** - * Retrieves the driver's major version number. Initially this should be 1. - * - * @return this driver's major version number - */ - public int getMajorVersion() { - return DRIVERMAJOR; - } - - /** - * Gets the driver's minor version number. Initially this should be 0. - * - * @return this driver's minor version number - */ - public int getMinorVersion() { - return DRIVERMINOR; - } - - /** - * Gets information about the possible properties for this driver. - * - * The getPropertyInfo method is intended to allow a generic GUI tool to - * discover what properties it should prompt a human for in order to get - * enough information to connect to a database. Note that depending on the - * values the human has supplied so far, additional values may become - * necessary, so it may be necessary to iterate though several calls to the - * getPropertyInfo method. - * - * @param url the URL of the database to which to connect - * @param info a proposed list of tag/value pairs that will be sent on connect open - * @return an array of DriverPropertyInfo objects describing possible properties. This array may be an empty array - * if no properties are required. - */ - public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) { - if (!acceptsURL(url)) - return null; - - List<DriverPropertyInfo> props = new ArrayList<>(); - - DriverPropertyInfo prop = new DriverPropertyInfo("user", info.getProperty("user")); - prop.required = true; - prop.description = "The user loginname to use when authenticating on the database server"; - props.add(prop); - - prop = new DriverPropertyInfo("password", info.getProperty("password")); - prop.required = true; - prop.description = "The password to use when authenticating on the database server"; - props.add(prop); - - prop = new DriverPropertyInfo("debug", "false"); - prop.required = false; - prop.description = "Whether or not to create a log file for debugging purposes"; - props.add(prop); - - prop = new DriverPropertyInfo("logfile", ""); - prop.required = false; - prop.description = "The filename to write the debug log to. Only takes effect if debug is set to true. If the file exists, an incrementing number is added, till the filename is unique."; - props.add(prop); - - prop = new DriverPropertyInfo("language", "sql"); - prop.required = false; - prop.description = "What language to use for MonetDB conversations (experts only)"; - props.add(prop); - - prop = new DriverPropertyInfo("hash", ""); - prop.required = false; - prop.description = "Force the use of the given hash algorithm during challenge response (one of SHA1, MD5, plain)"; - props.add(prop); - - prop = new DriverPropertyInfo("follow_redirects", "true"); - prop.required = false; - prop.description = "Whether redirects issued by the server should be followed"; - props.add(prop); - - prop = new DriverPropertyInfo("treat_blob_as_binary", "false"); - prop.required = false; - prop.description = "Whether BLOBs on the server should be treated as BINARY types, thus mapped to byte[]"; - 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 - props.add(prop); - - prop = new DriverPropertyInfo("embedded", "false"); - prop.required = false; - prop.description = "Whether or not to use an embedded MonetDB connection"; - props.add(prop); - - DriverPropertyInfo[] dpi = new DriverPropertyInfo[props.size()]; - return props.toArray(dpi); - } - - /** - * Reports whether this driver is a genuine JDBC Compliant&tm; driver. A - * driver may only report true here if it passes the JDBC compliance tests; - * otherwise it is required to return false. - * - * JDBC compliance requires full support for the JDBC API and full support - * for SQL 92 Entry Level. It is expected that JDBC compliant drivers will - * be available for all the major commercial databases. - * - * This method is not intended to encourage the development of non-JDBC - * compliant drivers, but is a recognition of the fact that some vendors are - * interested in using the JDBC API and framework for lightweight databases - * that do not support full database functionality, or for special databases - * such as document information retrieval where a SQL implementation may not - * be feasible. - * - * @return true if this driver is JDBC Compliant; false otherwise - */ - public boolean jdbcCompliant() { - return MONETJDBCCOMPLIANT; - } - - //== end methods of interface driver - - /** A static Map containing the mapping between MonetDB types and Java SQL types */ - /* use SELECT sqlname, * FROM sys.types order by 1, id; to view all MonetDB types */ - /* see http://docs.oracle.com/javase/7/docs/api/java/sql/Types.html to view all supported java SQL types */ - private static Map<String, Integer> typeMap = new HashMap<>(); - static { - // fill the typeMap once - // typeMap.put("any", Types.???); - typeMap.put("bigint", Types.BIGINT); - typeMap.put("blob", Types.BLOB); - typeMap.put("boolean", Types.BOOLEAN); - typeMap.put("char", Types.CHAR); - typeMap.put("clob", Types.CLOB); - typeMap.put("date", Types.DATE); - typeMap.put("decimal", Types.DECIMAL); - typeMap.put("double", Types.DOUBLE); - typeMap.put("geometry", Types.OTHER); - typeMap.put("geometrya", Types.OTHER); - typeMap.put("hugeint", Types.NUMERIC); //but we will convert to java.math.BigInteger - typeMap.put("inet", Types.OTHER); - typeMap.put("int", Types.INTEGER); - typeMap.put("json", Types.OTHER); - // typeMap.put("mbr", Types.???); - typeMap.put("month_interval", Types.INTEGER); - // typeMap.put("oid", Types.BIGINT); - // typeMap.put("ptr", Types.???); - typeMap.put("real", Types.REAL); - typeMap.put("sec_interval", Types.BIGINT); - typeMap.put("smallint", Types.SMALLINT); - // typeMap.put("table", Types.???); - typeMap.put("time", Types.TIME); - typeMap.put("timestamp", Types.TIMESTAMP); - typeMap.put("timestamptz", Types.TIMESTAMP); - // new in Java 8: Types.TIMESTAMP_WITH_TIMEZONE (value 2014). Can't use it yet as we compile for java 7 - typeMap.put("timetz", Types.TIME); - // new in Java 8: Types.TIME_WITH_TIMEZONE (value 2013). Can't use it yet as we compile for java 7 - typeMap.put("tinyint", Types.TINYINT); - typeMap.put("url", Types.OTHER); - typeMap.put("uuid", Types.OTHER); - typeMap.put("varchar", Types.VARCHAR); - typeMap.put("wrd", Types.BIGINT); - } - - /** - * Returns the java.sql.Types equivalent of the given MonetDB type. - * - * @param type the type as used by MonetDB - * @return the matching java.sql.Types constant or java.sql.Types.OTHER if nothing matched on the given string - */ - public static int getJavaType(String type) { - // match the currentColumns type on a java.sql.Types constant - Integer tp = typeMap.get(type); - if (tp != null) { - return tp; - } else { - // this should not be able to happen do not assert, since maybe future versions introduce new types - return Types.OTHER; - } - } - - private static String TypeMapppingSQL = null; // cache to optimise getSQLTypeMap() - - /** - * Returns a String usable in an SQL statement to map the server types - * to values of java.sql.Types using the global static type map. - * The returned string will be a SQL CASE x statement where the x is - * replaced with the given currentColumns name (or expression) string. - * - * @param column a String representing the value that should be evaluated in the SQL CASE statement - * @return a SQL CASE statement - */ - static String getSQLTypeMap(String column) { - if (TypeMapppingSQL == null) { - // first time, compose TypeMappping SQL string - StringBuilder val = new StringBuilder((typeMap.size() * (7 + 7 + 7 + 4)) + 14); - for (Entry<String, Integer> entry : typeMap.entrySet()) { - val.append(" WHEN '").append(entry.getKey()).append("' THEN ").append(entry.getValue().toString()); - } - val.append(" ELSE ").append(Types.OTHER).append(" END"); - // as the typeMap is static, cache this SQL part for all next calls - TypeMapppingSQL = val.toString(); - } - return "CASE " + column + TypeMapppingSQL; - } - - /** - * Returns a touched up identifying version string of this driver. - * - * @return the version string - */ - public static String getDriverVersion() { - return "" + DRIVERMAJOR + "." + DRIVERMINOR + " (" + DRIVERVERSIONSUFFIX + ")"; - } - - public static int getDriverMajorVersion() { - return DRIVERMAJOR; - } - - public static int getDriverMinorVersion() { - return DRIVERMINOR; - } - - /** - * Return the parent Logger of all the Loggers used by this data - * source. This should be the Logger farthest from the root Logger - * that is still an ancestor of all of the Loggers used by this data - * source. Configuring this Logger will affect all of the log - * messages generated by the data source. In the worst case, this - * may be the root Logger. - * - * @return the parent Logger for this data source - * @throws SQLFeatureNotSupportedException if the data source does not use java.util.logging - */ - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException("java.util.logging not in use", "0A000"); - } -}
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java.in @@ -135,7 +135,7 @@ final public class MonetDriver implement DriverPropertyInfo prop = new DriverPropertyInfo("user", info.getProperty("user")); prop.required = true; - prop.description = "The user loginname to use when authenticating on the database server"; + prop.description = "The user name to use when authenticating on the database server"; props.add(prop); prop = new DriverPropertyInfo("password", info.getProperty("password")); @@ -143,29 +143,34 @@ final public class MonetDriver implement prop.description = "The password to use when authenticating on the database server"; props.add(prop); - prop = new DriverPropertyInfo("language", "sql"); - prop.required = false; - prop.description = "What language to use for MonetDB conversations (experts only)"; - props.add(prop); - prop = new DriverPropertyInfo("hash", ""); prop.required = false; prop.description = "Force the use of the given hash algorithm during challenge response (one of SHA1, MD5, plain)"; props.add(prop); + prop = new DriverPropertyInfo("language", "sql"); + prop.required = false; + prop.description = "What language to use for MonetDB conversations (experts only)"; + props.add(prop); + prop = new DriverPropertyInfo("follow_redirects", "true"); prop.required = false; - prop.description = "Whether redirects issued by the server should be followed"; + prop.description = "Whether redirects issued by the server should be followed (MAPI connection only)"; props.add(prop); prop = new DriverPropertyInfo("treat_blob_as_binary", "false"); prop.required = false; - prop.description = "Whether BLOBs on the server should be treated as BINARY types, thus mapped to byte[]"; + prop.description = "Whether BLOBs on the server should be treated as BINARY types, thus mapped to byte[] (MAPI connection only)"; + props.add(prop); + + prop = new DriverPropertyInfo("treat_clob_as_longvarchar", "false"); + prop.required = false; + prop.description = "Whether CLOBs on the server should be treated as LONGVARCHAR types, thus mapped to String (MAPI connection only)"; 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 + prop.description = "Defines the maximum time to wait in milliseconds on a blocking read socket call (MAPI connection only)"; // this corresponds to the Connection.setNetworkTimeout() method introduced in JDBC 4.1 props.add(prop); prop = new DriverPropertyInfo("embedded", "false"); @@ -173,6 +178,11 @@ final public class MonetDriver implement prop.description = "Whether or not to use an embedded MonetDB connection"; props.add(prop); + prop = new DriverPropertyInfo("directory", ""); + prop.required = false; + prop.description = "The directory of the database farm (Embedded connection only)"; + props.add(prop); + DriverPropertyInfo[] dpi = new DriverPropertyInfo[props.size()]; return props.toArray(dpi); } @@ -232,11 +242,9 @@ final public class MonetDriver implement // typeMap.put("table", Types.???); typeMap.put("time", Types.TIME); typeMap.put("timestamp", Types.TIMESTAMP); - typeMap.put("timestamptz", Types.TIMESTAMP); - // new in Java 8: Types.TIMESTAMP_WITH_TIMEZONE (value 2014). Can't use it yet as we compile for java 7 - typeMap.put("timetz", Types.TIME); - // new in Java 8: Types.TIME_WITH_TIMEZONE (value 2013). Can't use it yet as we compile for java 7 - typeMap.put("tinyint", Types.TINYINT); + typeMap.put("timestamptz", Types.TIMESTAMP_WITH_TIMEZONE); + typeMap.put("timetz", Types.TIME_WITH_TIMEZONE); + typeMap.put("tinyint", Types.TINYINT); //but we will convert to java.lang.Byte typeMap.put("url", Types.OTHER); typeMap.put("uuid", Types.OTHER); typeMap.put("varchar", Types.VARCHAR); @@ -395,7 +403,6 @@ final public class MonetDriver implement MonetConnection res; boolean isEmbedded = Boolean.parseBoolean(props.getProperty("embedded", "false")); - boolean blobIsBinary = Boolean.valueOf(props.getProperty("treat_blob_as_binary", "false")); String language = props.getProperty("language", "sql"); String username = props.getProperty("user", null); String password = props.getProperty("password", null); @@ -418,9 +425,8 @@ final public class MonetDriver implement throw new SQLException("EmbeddedConnection Class not found!"); } res = (MonetConnection) EmbeddedConnectionClass - .getDeclaredConstructor(Properties.class, String.class, String.class, String.class, - Boolean.TYPE, String.class) - .newInstance(props, database, hash, language, blobIsBinary, directory); + .getDeclaredConstructor(Properties.class, String.class, String.class, String.class, String.class) + .newInstance(props, database, hash, language, directory); } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) { throw new SQLException(e); @@ -434,6 +440,9 @@ final public class MonetDriver implement if (password == null || password.trim().isEmpty()) throw new IllegalArgumentException("password should not be null or empty"); + boolean blobIsBinary = Boolean.valueOf(props.getProperty("treat_blob_as_binary", "false")); + boolean clobIsLongChar = Boolean.valueOf(props.getProperty("treat_clob_as_longvarchar", "false")); + boolean negative1 = false, failedparse1 = false; int port = 0; try { @@ -463,7 +472,7 @@ final public class MonetDriver implement props.setProperty("so_timeout", "0"); } try { - res = new MapiConnection(props, database, hash, language, blobIsBinary, hostname, port); + res = new MapiConnection(props, database, hash, language, blobIsBinary, clobIsLongChar, hostname, port); } catch (IOException e) { throw new SQLException(e); }
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java @@ -11,6 +11,7 @@ package nl.cwi.monetdb.jdbc; import nl.cwi.monetdb.mcl.connection.ControlCommands; import nl.cwi.monetdb.mcl.responses.ResultSetResponse; +import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.Reader; import java.io.IOException; @@ -19,26 +20,7 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.net.URL; import java.nio.CharBuffer; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.NClob; -import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; -import java.sql.Ref; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.RowId; -import java.sql.SQLData; -import java.sql.SQLDataException; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.sql.SQLOutput; -import java.sql.SQLXML; -import java.sql.Struct; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; +import java.sql.*; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Map; @@ -222,16 +204,15 @@ public class MonetPreparedStatement exte return getResultSet(); } - /** override the executeQuery from the Statement to throw an SQLException*/ + /** override the executeQuery from the Statement to throw an SQLException */ @Override public ResultSet executeQuery(String q) throws SQLException { throw new SQLException("This method is not available in a PreparedStatement!", "M1M05"); } /** - * Executes the SQL statement in this PreparedStatement object, which must - * be an SQL INSERT, UPDATE or DELETE statement; or an SQL statement that - * returns nothing, such as a DDL statement. + * Executes the SQL statement in this PreparedStatement object, which must be an SQL INSERT, UPDATE or DELETE + * statement; or an SQL statement that returns nothing, such as a DDL statement. * * @return either (1) the row count for INSERT, UPDATE, or DELETE * statements or (2) 0 for SQL statements that return nothing @@ -241,19 +222,18 @@ public class MonetPreparedStatement exte public int executeUpdate() throws SQLException { if (execute()) throw new SQLException("Query produced a result set", "M1M17"); - return getUpdateCount(); } - /** override the executeUpdate from the Statement to throw an SQLException*/ + /** override the executeUpdate from the Statement to throw an SQLException */ @Override public int executeUpdate(String q) throws SQLException { throw new SQLException("This method is not available in a PreparedStatement!", "M1M05"); } /** - * Returns the index (0..size-1) in the backing arrays for the given - * resultset column number or an SQLException when not found + * Returns the index (0..size-1) in the backing arrays for the given resultset column number or an SQLException + * when not found */ private int getColumnIdx(int colnr) throws SQLException { int curcol = 0; @@ -337,7 +317,7 @@ public class MonetPreparedStatement exte * query call to pull the IS_AUTOINCREMENT value for this column. * See also ResultSetMetaData.isAutoIncrement() */ - // For now we simply allways return false. + // For now we simply always return false. return false; } @@ -350,21 +330,14 @@ public class MonetPreparedStatement exte @Override public boolean isCaseSensitive(int column) throws SQLException { switch (getColumnType(column)) { + case Types.CLOB: case Types.CHAR: - case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness - case Types.CLOB: - return true; case Types.VARCHAR: - String monettype = getColumnTypeName(column); - if (monettype != null) { - // data of type inet or uuid is not case sensitive - if ("inet".equals(monettype) || "uuid".equals(monettype)) - return false; - } + case Types.LONGVARCHAR: + return true; + default: return true; } - - return false; } /** @@ -404,21 +377,15 @@ public class MonetPreparedStatement exte public boolean isSigned(int column) throws SQLException { // we can hardcode this, based on the colum type switch (getColumnType(column)) { - case Types.NUMERIC: - case Types.DECIMAL: case Types.TINYINT: case Types.SMALLINT: case Types.INTEGER: case Types.REAL: - case Types.FLOAT: case Types.DOUBLE: case Types.BIGINT: + case Types.NUMERIC: + case Types.DECIMAL: return true; - case Types.BIT: // we don't use type BIT, it's here for completeness - case Types.BOOLEAN: - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: default: return false; } @@ -701,21 +668,15 @@ public class MonetPreparedStatement exte public boolean isSigned(int param) throws SQLException { // we can hardcode this, based on the column type switch (getParameterType(param)) { - case Types.NUMERIC: - case Types.DECIMAL: case Types.TINYINT: case Types.SMALLINT: case Types.INTEGER: + case Types.REAL: + case Types.DOUBLE: case Types.BIGINT: - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: + case Types.NUMERIC: + case Types.DECIMAL: return true; - case Types.BIT: // we don't use type BIT, it's here for completeness - case Types.BOOLEAN: - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: default: return false; } @@ -1021,30 +982,45 @@ public class MonetPreparedStatement exte * Sets the designated parameter to the given Blob object. The driver * converts this to an SQL BLOB value when it sends it to the database. * - * @param i the first parameter is 1, the second is 2, ... - * @param x a Blob object that maps an SQL BLOB value + * @param parameterIndex the first parameter is 1, the second is 2, ... + * @param stream an object that contains the data to set the parameter value to * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method */ @Override - public void setBlob(int i, InputStream x) throws SQLException { - throw newSQLFeatureNotSupportedException("setBlob"); + public void setBlob(int parameterIndex, InputStream stream) throws SQLException { + if (stream == null) { + setNull(parameterIndex, -1); + return; + } + // Some buffer. Size of 8192 is default for BufferedReader, so... + byte[] arr = new byte[8192]; + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + int numChars; + try { + while ((numChars = stream.read(arr, 0, arr.length)) > 0) { + buf.write(arr, 0, numChars); + } + setBytes(parameterIndex, buf.toByteArray()); + } catch (IOException e) { + throw new SQLException(e); + } } /** * Sets the designated parameter to the given Blob object. The driver * converts this to an SQL BLOB value when it sends it to the database. * - * @param i the first parameter is 1, the second is 2, ... + * @param parameterIndex the first parameter is 1, the second is 2, ... * @param x a Blob object that maps an SQL BLOB value * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method */ @Override - public void setBlob(int i, Blob x) throws SQLException { - throw newSQLFeatureNotSupportedException("setBlob"); + public void setBlob(int parameterIndex, Blob x) throws SQLException { + if (x == null) { + setNull(parameterIndex, -1); + return; + } + setBytes(parameterIndex, x.getBytes(0, (int) x.length())); } /** @@ -1058,17 +1034,27 @@ public class MonetPreparedStatement exte * may have to do extra work to determine whether the parameter data * should be sent to the server as a LONGVARBINARY or a BLOB. * - * @param i the first parameter is 1, the second is 2, ... - * @param is an object that contains the data to set the parameter - * value to + * @param parameterIndex the first parameter is 1, the second is 2, ... + * @param stream an object that contains the data to set the parameter value to * @param length the number of bytes in the parameter data * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method */ @Override - public void setBlob(int i, InputStream is, long length) throws SQLException { - throw newSQLFeatureNotSupportedException("setBlob"); + public void setBlob(int parameterIndex, InputStream stream, long length) throws SQLException { + if (stream == null) { + setNull(parameterIndex, -1); + return; + } + try { + byte[] arr = new byte[(int) length]; + ByteArrayOutputStream buf = new ByteArrayOutputStream((int) length); + + int numChars = stream.read(arr, 0, (int) length); + buf.write(arr, 0, numChars); + setBytes(parameterIndex, buf.toByteArray()); + } catch (IOException e) { + throw new SQLException(e); + } } /** @@ -1098,7 +1084,7 @@ public class MonetPreparedStatement exte setValue(parameterIndex, "" + x); } - static final String HEXES = "0123456789ABCDEF"; + private static final String HEXES = "0123456789ABCDEF"; /** * Sets the designated parameter to the given Java array of bytes. The * driver converts this to an SQL VARBINARY or LONGVARBINARY (depending @@ -1169,8 +1155,6 @@ public class MonetPreparedStatement exte * @param parameterIndex the first parameter is 1, the second is 2, ... * @param reader the java.io.Reader object that contains the Unicode data * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method */ @Override public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { @@ -1228,8 +1212,6 @@ public class MonetPreparedStatement exte * @param reader an object that contains the data to set the parameter * value to * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method */ @Override public void setClob(int i, Reader reader) throws SQLException { @@ -1276,7 +1258,7 @@ public class MonetPreparedStatement exte } // simply serialise the CLOB into a variable for now... far from // efficient, but might work for a few cases... - CharBuffer buf = CharBuffer.allocate((int)length); // have to down cast :( + CharBuffer buf = CharBuffer.allocate((int) length); // have to down cast :( try { reader.read(buf); } catch (IOException e) { @@ -1298,7 +1280,7 @@ public class MonetPreparedStatement exte * @throws SQLException if a database access error occurs */ @Override - public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { + public void setDate(int parameterIndex, Date x) throws SQLException { setDate(parameterIndex, x, null); } @@ -1317,7 +1299,7 @@ public class MonetPreparedStatement exte * @throws SQLException if a database access error occurs */ @Override - public void setDate(int parameterIndex, java.sql.Date x, Calendar cal) throws SQLException { + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { if (x == null) { setNull(parameterIndex, -1); return; @@ -1623,108 +1605,130 @@ public class MonetPreparedStatement exte if (x instanceof String) { switch (targetSqlType) { case Types.TINYINT: + byte val1; + try { + val1 = Byte.parseByte((String)x); + } catch (NumberFormatException e) { + val1 = 0; + } + setByte(parameterIndex, val1); + break; case Types.SMALLINT: - case Types.INTEGER: - { - int val; + short val2; try { - val = Integer.parseInt((String)x); + val2 = Short.parseShort((String)x); } catch (NumberFormatException e) { - val = 0; + val2 = 0; } - setInt(parameterIndex, val); - } break; - case Types.BIGINT: - { - long val; + setShort(parameterIndex, val2); + break; + case Types.INTEGER: + int val3; try { - val = Long.parseLong((String)x); + val3 = Integer.parseInt((String)x); } catch (NumberFormatException e) { - val = 0; + val3 = 0; } - setLong(parameterIndex, val); - } break; + setInt(parameterIndex, val3); + break; + case Types.BIGINT: + long val4; + try { + val4 = Long.parseLong((String)x); + } catch (NumberFormatException e) { + val4 = 0; + } + setLong(parameterIndex, val4); + break; case Types.REAL: - { - float val; + float val5; try { - val = Float.parseFloat((String)x); + val5 = Float.parseFloat((String)x); } catch (NumberFormatException e) { - val = 0; + val5 = 0; } - setFloat(parameterIndex, val); - } break; - case Types.FLOAT: + setFloat(parameterIndex, val5); + break; case Types.DOUBLE: - { - double val; + double val6; try { - val = Double.parseDouble((String)x); + val6 = Double.parseDouble((String)x); } catch (NumberFormatException e) { - val = 0; + val6 = 0; } - setDouble(parameterIndex, val); - } break; - case Types.DECIMAL: + setDouble(parameterIndex, val6); + break; case Types.NUMERIC: - { - BigDecimal val; + BigInteger val7; try { - val = new BigDecimal((String)x); + val7 = new BigInteger((String)x); } catch (NumberFormatException e) { try { - val = new BigDecimal(0.0); + val7 = BigInteger.ZERO; + } catch (NumberFormatException ex) { + throw new SQLException("Internal error: unable to create template BigInteger: " + ex.getMessage(), "M0M03"); + } + } + setObject(parameterIndex, val7); + break; + case Types.DECIMAL: + BigDecimal val8; + try { + val8 = new BigDecimal((String)x); + } catch (NumberFormatException e) { + try { + val8 = BigDecimal.ZERO; } catch (NumberFormatException ex) { throw new SQLException("Internal error: unable to create template BigDecimal: " + ex.getMessage(), "M0M03"); } } - val = val.setScale(scale, BigDecimal.ROUND_HALF_UP); - setBigDecimal(parameterIndex, val); - } break; - case Types.BIT: + val8 = val8.setScale(scale, BigDecimal.ROUND_HALF_UP); + setBigDecimal(parameterIndex, val8); + break; case Types.BOOLEAN: setBoolean(parameterIndex, Boolean.valueOf((String) x)); - break; + break; case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: setString(parameterIndex, (String)x); - break; - case Types.BINARY: - case Types.VARBINARY: + break; case Types.LONGVARBINARY: setBytes(parameterIndex, ((String)x).getBytes()); - break; + break; + case Types.BLOB: + setBlob(parameterIndex, new MonetBlob(((String)x).getBytes())); + break; + case Types.CLOB: + setClob(parameterIndex, new MonetClob((String)x)); + break; case Types.DATE: - { - java.sql.Date val; - try { - val = java.sql.Date.valueOf((String)x); - } catch (IllegalArgumentException e) { - val = new java.sql.Date(0L); - } - setDate(parameterIndex, val); - } break; - case Types.TIME: - { - Time val; + Date val9; try { - val = Time.valueOf((String)x); + val9 = Date.valueOf((String)x); } catch (IllegalArgumentException e) { - val = new Time(0L); + val9 = new Date(0L); } - setTime(parameterIndex, val); - } break; + setDate(parameterIndex, val9); + break; + case Types.TIME: + Time val10; + try { + val10 = Time.valueOf((String)x); + } catch (IllegalArgumentException e) { + val10 = new Time(0L); + } + setTime(parameterIndex, val10); + break; case Types.TIMESTAMP: - { - Timestamp val; + Timestamp val11; try { - val = Timestamp.valueOf((String)x); + val11 = Timestamp.valueOf((String)x); } catch (IllegalArgumentException e) { - val = new Timestamp(0L); + val11 = new Timestamp(0L); } - setTimestamp(parameterIndex, val); - } break; + setTimestamp(parameterIndex, val11); + break; case Types.NCHAR: case Types.NVARCHAR: case Types.LONGNVARCHAR: @@ -1732,55 +1736,53 @@ public class MonetPreparedStatement exte default: throw new SQLException("Conversion not allowed", "M1M05"); } - } else if (x instanceof BigDecimal || x instanceof Byte || x instanceof Short || x instanceof Integer || x instanceof Long || x instanceof Float || x instanceof Double) { + } else if (x instanceof BigDecimal || x instanceof BigInteger || x instanceof Byte || x instanceof Short || x instanceof Integer || x instanceof Long || x instanceof Float || x instanceof Double) { Number num = (Number)x; switch (targetSqlType) { case Types.TINYINT: setByte(parameterIndex, num.byteValue()); - break; + break; case Types.SMALLINT: setShort(parameterIndex, num.shortValue()); - break; + break; case Types.INTEGER: setInt(parameterIndex, num.intValue()); - break; + break; case Types.BIGINT: - if (x instanceof BigDecimal) { - BigDecimal bd = (BigDecimal)x; - setLong(parameterIndex, bd.setScale(scale, BigDecimal.ROUND_HALF_UP).longValue()); - } else { - setLong(parameterIndex, num.longValue()); - } - break; + setLong(parameterIndex, num.longValue()); + break; case Types.REAL: setFloat(parameterIndex, num.floatValue()); - break; - case Types.FLOAT: + break; case Types.DOUBLE: setDouble(parameterIndex, num.doubleValue()); - break; + break; + case Types.NUMERIC: + if (x instanceof BigInteger) { + setObject(parameterIndex, x); + } else { + setObject(parameterIndex, new BigInteger(Integer.toString(num.intValue()))); + } + break; case Types.DECIMAL: - case Types.NUMERIC: if (x instanceof BigDecimal) { setBigDecimal(parameterIndex, (BigDecimal)x); } else { - setBigDecimal(parameterIndex, - new BigDecimal(num.doubleValue())); + setBigDecimal(parameterIndex, new BigDecimal(num.doubleValue())); } - break; - case Types.BIT: + break; case Types.BOOLEAN: if (num.doubleValue() != 0.0) { setBoolean(parameterIndex, true); } else { setBoolean(parameterIndex, false); } - break; + break; case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: setString(parameterIndex, x.toString()); - break; + break; default: throw new SQLException("Conversion not allowed", "M1M05"); } @@ -1789,122 +1791,97 @@ public class MonetPreparedStatement exte switch (targetSqlType) { case Types.TINYINT: setByte(parameterIndex, (byte)(val ? 1 : 0)); - break; + break; case Types.SMALLINT: setShort(parameterIndex, (short)(val ? 1 : 0)); - break; + break; case Types.INTEGER: setInt(parameterIndex, (val ? 1 : 0)); // do not cast to (int) as it generates a compiler warning - break; + break; case Types.BIGINT: setLong(parameterIndex, (long)(val ? 1 : 0)); - break; + break; case Types.REAL: setFloat(parameterIndex, (float)(val ? 1.0 : 0.0)); - break; - case Types.FLOAT: + break; case Types.DOUBLE: setDouble(parameterIndex, (val ? 1.0 : 0.0)); // do no cast to (double) as it generates a compiler warning - break; - case Types.DECIMAL: + break; case Types.NUMERIC: - { - BigDecimal dec; - try { - dec = new BigDecimal(val ? 1.0 : 0.0); - } catch (NumberFormatException e) { - throw new SQLException("Internal error: unable to create template BigDecimal: " + e.getMessage(), "M0M03"); - } - setBigDecimal(parameterIndex, dec); - } break; + setObject(parameterIndex, val ? BigInteger.ONE : BigInteger.ZERO); + break; + case Types.DECIMAL: + setBigDecimal(parameterIndex, val ? BigDecimal.ONE : BigDecimal.ZERO); + break; case Types.BIT: case Types.BOOLEAN: setBoolean(parameterIndex, val); - break; + break; case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: setString(parameterIndex, "" + val); - break; - default: - throw new SQLException("Conversion not allowed", "M1M05"); - } - } else if (x instanceof BigInteger) { - BigInteger num = (BigInteger)x; - switch (targetSqlType) { - case Types.BIGINT: - setLong(parameterIndex, num.longValue()); - break; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - setString(parameterIndex, x.toString()); - break; + break; default: throw new SQLException("Conversion not allowed", "M1M05"); } } else if (x instanceof byte[]) { switch (targetSqlType) { - case Types.BINARY: - case Types.VARBINARY: case Types.LONGVARBINARY: - setBytes(parameterIndex, (byte[])x); - break; + setBytes(parameterIndex, (byte[]) x); + break; + case Types.BLOB: + setBlob(parameterIndex, new MonetBlob((byte[]) x)); + break; default: throw new SQLException("Conversion not allowed", "M1M05"); } - } else if (x instanceof java.sql.Date || x instanceof Timestamp || x instanceof Time || x instanceof Calendar || x instanceof java.util.Date) { + } else if (x instanceof Date || x instanceof Timestamp || x instanceof Time || x instanceof Calendar || x instanceof java.util.Date) { switch (targetSqlType) { case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: setString(parameterIndex, x.toString()); - break; + break; case Types.DATE: if (x instanceof Time) { throw new SQLException("Conversion not allowed", "M1M05"); - } else if (x instanceof java.sql.Date) { - setDate(parameterIndex, (java.sql.Date)x); + } else if (x instanceof Date) { + setDate(parameterIndex, (Date)x); } else if (x instanceof Timestamp) { - setDate(parameterIndex, new java.sql.Date(((Timestamp)x).getTime())); + setDate(parameterIndex, new Date(((Timestamp)x).getTime())); } else if (x instanceof java.util.Date) { - setDate(parameterIndex, new java.sql.Date( - ((java.util.Date)x).getTime())); + setDate(parameterIndex, new Date(((java.util.Date)x).getTime())); } else { //Calendar - setDate(parameterIndex, new java.sql.Date( - ((Calendar)x).getTimeInMillis())); + setDate(parameterIndex, new Date(((Calendar)x).getTimeInMillis())); } - break; + break; case Types.TIME: if (x instanceof Time) { setTime(parameterIndex, (Time)x); - } else if (x instanceof java.sql.Date) { + } else if (x instanceof Date) { throw new SQLException("Conversion not allowed", "M1M05"); } else if (x instanceof Timestamp) { setTime(parameterIndex, new Time(((Timestamp)x).getTime())); } else if (x instanceof java.util.Date) { - setTime(parameterIndex, new java.sql.Time( - ((java.util.Date)x).getTime())); + setTime(parameterIndex, new Time(((java.util.Date)x).getTime())); } else { //Calendar - setTime(parameterIndex, new Time( - ((Calendar)x).getTimeInMillis())); + setTime(parameterIndex, new Time(((Calendar)x).getTimeInMillis())); } - break; + break; case Types.TIMESTAMP: if (x instanceof Time) { throw new SQLException("Conversion not allowed", "M1M05"); - } else if (x instanceof java.sql.Date) { - setTimestamp(parameterIndex, new Timestamp(((java.sql.Date)x).getTime())); + } else if (x instanceof Date) { + setTimestamp(parameterIndex, new Timestamp(((Date)x).getTime())); } else if (x instanceof Timestamp) { setTimestamp(parameterIndex, (Timestamp)x); } else if (x instanceof java.util.Date) { - setTimestamp(parameterIndex, new java.sql.Timestamp( - ((java.util.Date)x).getTime())); + setTimestamp(parameterIndex, new Timestamp(((java.util.Date)x).getTime())); } else { //Calendar - setTimestamp(parameterIndex, new Timestamp( - ((Calendar)x).getTimeInMillis())); + setTimestamp(parameterIndex, new Timestamp(((Calendar)x).getTimeInMillis())); } - break; + break; default: throw new SQLException("Conversion not allowed", "M1M05"); } @@ -1923,8 +1900,6 @@ public class MonetPreparedStatement exte setURL(parameterIndex, (java.net.URL)x); } else if (x instanceof RowId) { setRowId(parameterIndex, (RowId)x); - /*} else if (x instanceof NClob) { NClob is a subclass od Clob - throw newSQLFeatureNotSupportedException("setObject() with object of type NClob");*/ } else if (x instanceof SQLXML) { throw newSQLFeatureNotSupportedException("setObject() with object of type SQLXML"); } else if (x instanceof SQLData) { // not in JDBC4.1??? @@ -1938,10 +1913,8 @@ public class MonetPreparedStatement exte // representation is given, but we need to prefix it // with the actual sqltype the server expects, or we // will get an error back - setValue( - paramnr, - sqltype + " '" + x.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "'" - ); + setValue(paramnr, + sqltype + " '" + x.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "'"); } @Override @@ -1990,12 +1963,12 @@ public class MonetPreparedStatement exte } @Override - public void writeDate(java.sql.Date x) throws SQLException { + public void writeDate(Date x) throws SQLException { setDate(paramnr, x); } @Override - public void writeTime(java.sql.Time x) throws SQLException { + public void writeTime(Time x) throws SQLException { setTime(paramnr, x); } @@ -2310,7 +2283,7 @@ public class MonetPreparedStatement exte */ @Override public void setURL(int parameterIndex, URL x) throws SQLException { - throw newSQLFeatureNotSupportedException("setURL"); + setString(parameterIndex, x.toString()); } /**
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java @@ -8,8 +8,10 @@ package nl.cwi.monetdb.jdbc; -import nl.cwi.monetdb.jdbc.types.INET; -import nl.cwi.monetdb.jdbc.types.URL; +import nl.cwi.monetdb.jdbc.types.MonetINET; +import nl.cwi.monetdb.jdbc.types.MonetURL; +import nl.cwi.monetdb.mcl.connection.helpers.GregorianCalendarParser; +import nl.cwi.monetdb.mcl.protocol.ProtocolException; import nl.cwi.monetdb.mcl.responses.DataBlockResponse; import nl.cwi.monetdb.mcl.responses.ResultSetResponse; @@ -17,7 +19,9 @@ import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; +import java.math.BigInteger; import java.net.MalformedURLException; +import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; @@ -39,6 +43,7 @@ import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; +import java.text.ParsePosition; import java.util.*; /** @@ -165,17 +170,15 @@ public class MonetResultSet extends Mone /** * Moves the cursor to the given row number in this ResultSet object. * - * If the row number is positive, the cursor moves to the given row number - * with respect to the beginning of the result set. The first row is row 1, - * the second is row 2, and so on. + * If the row number is positive, the cursor moves to the given row number with respect to the beginning of the + * result set. The first row is row 1, the second is row 2, and so on. * - * If the given row number is negative, the cursor moves to an absolute row - * position with respect to the end of the result set. For example, calling - * the method absolute(-1) positions the cursor on the last row; calling the + * If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the + * result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the * method absolute(-2) moves the cursor to the next-to-last row, and so on. * - * An attempt to position the cursor beyond the first/last row in the result - * set leaves the cursor before the first row or after the last row. + * An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first + * row or after the last row. * Note: calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). * * @param row the number of the row to which the cursor should move. A positive number indicates the row number @@ -297,19 +300,42 @@ public class MonetResultSet extends Mone public Array getArray(int columnIndex) throws SQLException { throw newSQLFeatureNotSupportedException("getArray"); } + @Override public Array getArray(String colName) throws SQLException { throw newSQLFeatureNotSupportedException("getArray"); } - /* Mapi doesn't allow something for streams at the moment, thus all not implemented for now */ @Override public InputStream getAsciiStream(int columnIndex) throws SQLException { - throw newSQLFeatureNotSupportedException("getAsciiStream"); + try { + if(setLastNullValue(columnIndex - 1)) { + return null; + } + switch (JdbcSQLTypes[columnIndex - 1]) { + case Types.BLOB: + return getClob(columnIndex).getAsciiStream(); + case Types.CLOB: + return getClob(columnIndex).getAsciiStream(); + case Types.LONGVARBINARY: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + return new ByteArrayInputStream(getBytes(columnIndex)); + default: + throw new SQLException("Conversion from " + types[columnIndex - 1] + + " to ascii stream not supported", "M1M05"); + } + } catch (ClassCastException ex) { + throw new SQLException(ex.getMessage()); + } catch (IndexOutOfBoundsException e) { + throw newSQLInvalidColumnIndexException(columnIndex); + } } + @Override public InputStream getAsciiStream(String columnName) throws SQLException { - throw newSQLFeatureNotSupportedException("getAsciiStream"); + return getAsciiStream(findColumn(columnName)); } @Override @@ -325,69 +351,57 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a stream of uninterpreted bytes. The - * value can then be read in chunks from the stream. This method is - * particularly suitable for retrieving large LONGVARBINARY values. + * Retrieves the value of the designated column in the current row of this ResultSet object as a stream of + * uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly suitable + * for retrieving large LONGVARBINARY values. * <br/><br/> - * Note: All the data in the returned stream must be read prior to - * getting the value of any other column. The next call to a getter - * method implicitly closes the stream. Also, a stream may return 0 - * when the method InputStream.available is called whether there is - * data available or not. + * Note: All the data in the returned stream must be read prior to getting the value of any other column. The next + * call to a getter method implicitly closes the stream. Also, a stream may return 0 when the method + * InputStream.available is called whether there is data available or not. * * @param columnIndex the first column is 1, the second is 2, ... - * @return a Java input stream that delivers the database column - * value as a stream of uninterpreted bytes; if the value is SQL - * NULL, the value returned is null - * @throws SQLException if the columnIndex is not valid; if a - * database access error occurs or this method is called on a closed - * result set + * @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the + * value is SQL NULL, the value returned is null + * @throws SQLException if the columnIndex is not valid; if a database access error occurs or this method is called + * on a closed result set */ @Override public InputStream getBinaryStream(int columnIndex) throws SQLException { - try { - switch (JdbcSQLTypes[columnIndex - 1]) { - case Types.BLOB: - Blob blob = getBlob(columnIndex); - if (blob == null) - return null; - return blob.getBinaryStream(); - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - byte[] bte = getBytes(columnIndex); - if (bte == null) - return null; - return new ByteArrayInputStream(bte); - } - throw new SQLException("Cannot operate on " + types[columnIndex - 1] + " type", "M1M05"); - } catch (IndexOutOfBoundsException e) { - throw newSQLInvalidColumnIndexException(columnIndex); - } + try { + if(setLastNullValue(columnIndex - 1)) { + return null; + } + switch (JdbcSQLTypes[columnIndex - 1]) { + case Types.BLOB: + return getBlob(columnIndex).getBinaryStream(); + case Types.LONGVARBINARY: + return new ByteArrayInputStream(getBytes(columnIndex)); + default: + throw new SQLException("Conversion from " + types[columnIndex - 1] + + " to binary stream not supported", "M1M05"); + } + } catch (ClassCastException ex) { + throw new SQLException(ex.getMessage()); + } catch (IndexOutOfBoundsException e) { + throw newSQLInvalidColumnIndexException(columnIndex); + } } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a stream of uninterpreted bytes. The - * value can then be read in chunks from the stream. This method is - * particularly suitable for retrieving large LONGVARBINARY values. - * <br/><br/> - * Note: All the data in the returned stream must be read prior to - * getting the value of any other column. The next call to a getter - * method implicitly closes the stream. Also, a stream may return 0 - * when the method available is called whether there is data - * available or not. + * Retrieves the value of the designated column in the current row of this ResultSet object as a stream of + * uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly suitable + * for retrieving large LONGVARBINARY values. + * <br/><br/> + * Note: All the data in the returned stream must be read prior to getting the value of any other column. The next + * call to a getter method implicitly closes the stream. Also, a stream may return 0 when the method available is + * called whether there is data available or not. * - * @param columnName the label for the column specified with - * the SQL AS clause. If the SQL AS clause was not specified, then - * the label is the name of the column - * @return a Java input stream that delivers the database column - * value as a stream of uninterpreted bytes; if the value is SQL - * NULL, the result is null - * @throws SQLException if the columnLabel is not valid; if a - * database access error occurs or this method is called on a closed - * result set + * @param columnName the label for the column specified with the SQL AS clause. If the SQL AS clause was not + * specified, then the label is the name of the column + * @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the + * value is SQL NULL, the result is null + * @throws SQLException if the columnLabel is not valid; if a database access error occurs or this method is called + * on a closed result set */ @Override public InputStream getBinaryStream(String columnName) throws SQLException { @@ -422,9 +436,8 @@ public class MonetResultSet extends Mone * object. * * @param columnName the name of the column - * @return a java.io.Reader object that contains the column value; - * if the value is SQL NULL, the value returned is null in - * the Java programming language. + * @return a java.io.Reader object that contains the column value; if the value is SQL NULL, the value returned is + * null in the Java programming language. * @throws SQLException if a database access error occurs */ @Override @@ -433,18 +446,14 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a java.io.Reader object. It is - * intended for use when accessing NCHAR,NVARCHAR and LONGNVARCHAR - * columns. + * Retrieves the value of the designated column in the current row of this ResultSet object as a java.io.Reader + * object. It is intended for use when accessing NCHAR, NVARCHAR and LONGNVARCHAR columns. * * @param columnIndex the first column is 1, the second is 2, ... - * @return a java.io.Reader object that contains the column value; - * if the value is SQL NULL, the value returned is null in - * the Java programming language. + * @return a java.io.Reader object that contains the column value; if the value is SQL NULL, the value returned is + * null in the Java programming language. * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method + * @throws SQLFeatureNotSupportedException the JDBC driver does not support this method */ @Override public Reader getNCharacterStream(int columnIndex) throws SQLException { @@ -452,15 +461,12 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a java.io.Reader object. It is - * intended for use when accessing NCHAR,NVARCHAR and LONGNVARCHAR - * columns. + * Retrieves the value of the designated column in the current row of this ResultSet object as a java.io.Reader + * object. It is intended for use when accessing NCHAR, NVARCHAR and LONGNVARCHAR columns. * * @param columnName the name of the column - * @return a java.io.Reader object that contains the column value; - * if the value is SQL NULL, the value returned is null in - * the Java programming language. + * @return a java.io.Reader object that contains the column value; if the value is SQL NULL, the value returned is + * null in the Java programming language. * @throws SQLException if a database access error occurs * @throws SQLFeatureNotSupportedException the JDBC driver does * not support this method @@ -493,14 +499,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a Blob object in the Java programming - * language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a Blob object in the + * Java programming language. * - * @param colName the name of the column from which to retrieve - * the value - * @return a Blob object representing the SQL BLOB value in the - * specified column + * @param colName the name of the column from which to retrieve the value + * @return a Blob object representing the SQL BLOB value in the specified column * @throws SQLException if a database access error occurs */ @Override @@ -509,13 +512,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a Clob object in the + * Retrieves the value of the designated column in the current row of this ResultSet object as a Clob object in the * Java programming language. * * @param columnIndex the first column is 1, the second is 2, ... - * @return a Clob object representing the SQL CLOB value in the - * specified column + * @return a Clob object representing the SQL CLOB value in the specified column * @throws SQLException if a database access error occurs */ @Override @@ -533,14 +534,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a Clob object in the + * Retrieves the value of the designated column in the current row of this ResultSet object as a Clob object in the * Java programming language. * - * @param colName the name of the column from which to retrieve - * the value - * @return a Clob object representing the SQL CLOB value in the - * specified column + * @param colName the name of the column from which to retrieve the value + * @return a Clob object representing the SQL CLOB value in the specified column * @throws SQLException if a database access error occurs */ @Override @@ -549,16 +547,13 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a NClob object in the + * Retrieves the value of the designated column in the current row of this ResultSet object as a NClob object in the * Java programming language. * * @param i the first column is 1, the second is 2, ... - * @return a NClob object representing the SQL NCLOB value in the - * specified column + * @return a NClob object representing the SQL NCLOB value in the specified column * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method + * @throws SQLFeatureNotSupportedException the JDBC driver does not support this method */ @Override public NClob getNClob(int i) throws SQLException { @@ -566,17 +561,13 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a NClob object in the + * Retrieves the value of the designated column in the current row of this ResultSet object as a NClob object in the * Java programming language. * - * @param colName the name of the column from which to retrieve - * the value - * @return a NClob object representing the SQL NCLOB value in the - * specified column + * @param colName the name of the column from which to retrieve the value + * @return a NClob object representing the SQL NCLOB value in the specified column * @throws SQLException if a database access error occurs - * @throws SQLFeatureNotSupportedException the JDBC driver does - * not support this method + * @throws SQLFeatureNotSupportedException the JDBC driver does not support this method */ @Override public NClob getNClob(String colName) throws SQLException { @@ -665,12 +656,11 @@ public class MonetResultSet extends Mone // See Sun JDBC Specification 3.0 Table B-6 /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a boolean in the Java programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a boolean in the Java + * programming language. * * @param columnIndex the first column is 1, the second is 2, ... - * @return the column value; if the value is SQL NULL, the value returned - * is false + * @return the column value; if the value is SQL NULL, the value returned is false * @throws SQLException if there is no such column */ @Override @@ -685,7 +675,7 @@ public class MonetResultSet extends Mone return currentBlock.getBooleanValue(columnIndex - 1); case Types.CHAR: case Types.VARCHAR: - case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness + case Types.LONGVARCHAR: case Types.CLOB: String val = currentBlock.getValueAsString(columnIndex - 1); if ("false".equalsIgnoreCase(val) || "0".equals(val)) @@ -693,21 +683,24 @@ public class MonetResultSet extends Mone if ("true".equalsIgnoreCase(val) || "1".equals(val)) return true; throw newSQLInvalidColumnIndexException(columnIndex); - case Types.BIT: // MonetDB doesn't use type BinaryDigit, it's here for completeness case Types.TINYINT: + return getByte(columnIndex) != 0; case Types.SMALLINT: + return getShort(columnIndex) != 0; case Types.INTEGER: return getInt(columnIndex) != 0; case Types.BIGINT: return getLong(columnIndex) != 0L; + case Types.REAL: + return getFloat(columnIndex) != 0.0f; case Types.DOUBLE: - case Types.FLOAT: - case Types.REAL: - return getDouble(columnIndex) != 0.0; + return getDouble(columnIndex) != 0.0d; + case Types.NUMERIC: + BigInteger huge = (BigInteger) currentBlock.getValueAsObject(columnIndex - 1); + return huge.compareTo(BigInteger.ZERO) != 0; case Types.DECIMAL: - case Types.NUMERIC: return getBigDecimal(columnIndex).compareTo(BigDecimal.ZERO) != 0; - default: + default: //OTHERS, BLOB, LONGVARBINARY, TIME... throw new SQLException("Conversion from " + types[columnIndex - 1] + " to boolean type not supported", "M1M05"); } @@ -719,12 +712,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a boolean in the Java programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a boolean in the Java + * programming language. * * @param columnName the SQL name of the column - * @return the column value; if the value is SQL NULL, the value returned - * is false + * @return the column value; if the value is SQL NULL, the value returned is false * @throws SQLException if the ResultSet object does not contain columnName */ @Override @@ -733,12 +725,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a byte in the Java programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a byte in the Java + * programming language. * * @param columnIndex the first column is 1, the second is 2, ... - * @return the column value; if the value is SQL NULL, the value returned - * is 0 + * @return the column value; if the value is SQL NULL, the value returned is 0 * @throws SQLException if a database access error occurs */ @Override @@ -788,8 +779,6 @@ public class MonetResultSet extends Mone switch (JdbcSQLTypes[columnIndex - 1]) { case Types.BLOB: return ((MonetBlob) currentBlock.getObjectValue(columnIndex - 1)).getBuffer(); - case Types.BINARY: - case Types.VARBINARY: case Types.LONGVARBINARY: // unpack the HEX (BLOB) notation to real bytes return (byte[]) currentBlock.getObjectValue(columnIndex - 1); @@ -804,13 +793,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a byte array in the Java programming language. The - * bytes represent the raw values returned by the driver. + * Retrieves the value of the designated column in the current row of this ResultSet object as a byte array in the + * Java programming language. The bytes represent the raw values returned by the driver. * * @param columnName the SQL name of the column - * @return the column value; if the value is SQL NULL, the value returned - * is null + * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLException if a database access error occurs */ @Override @@ -819,14 +806,12 @@ public class MonetResultSet extends Mone } /** - * Retrieves the concurrency mode of this ResultSet object. The concurrency - * used is determined by the Statement object that created the result set. + * Retrieves the concurrency mode of this ResultSet object. The concurrency used is determined by the Statement + * object that created the result set. * - * NOTE: MonetDB only supports read-only result sets, and will always return - * ResultSet.CONCUR_READ_ONLY + * NOTE: MonetDB only supports read-only result sets, and will always return ResultSet.CONCUR_READ_ONLY * - * @return the concurrency type, either ResultSet.CONCUR_READ_ONLY or - * ResultSet.CONCUR_UPDATABLE + * @return the concurrency type, either ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE */ @Override public int getConcurrency() { @@ -847,9 +832,8 @@ public class MonetResultSet extends Mone * cursor used by a ResultSet object. The current row of a ResultSet object * is also the current row of this SQL cursor. * - * Note: If positioned update is not supported, a SQLException is thrown. - * MonetDB currently doesn't support updates, so the SQLException is - * thrown for now. + * Note: If positioned update is not supported, a SQLException is thrown. MonetDB currently doesn't support updates, + * so the SQLException is thrown for now. * * @return the SQL name for this ResultSet object's cursor * @throws SQLException if a database access error occurs @@ -865,8 +849,7 @@ public class MonetResultSet extends Mone * ResultSet object as a double in the Java programming language. * * @param columnIndex the first column is 1, the second is 2, ... - * @return the column value; if the value is SQL NULL, the value returned - * is 0 + * @return the column value; if the value is SQL NULL, the value returned is 0 * @throws SQLException if there is no such column */ @Override @@ -888,8 +871,7 @@ public class MonetResultSet extends Mone * ResultSet object as a double in the Java programming language. * * @param columnName the SQL name of the column - * @return the column value; if the value is SQL NULL, the value returned - * is 0 + * @return the column value; if the value is SQL NULL, the value returned is 0 * @throws SQLException if the ResultSet object does not contain columnName */ @Override @@ -900,8 +882,7 @@ public class MonetResultSet extends Mone /** * Retrieves the holdability of this ResultSet object. * - * @return either ResultSet.HOLD_CURSORS_OVER_COMMIT or - * ResultSet.CLOSE_CURSORS_AT_COMMIT + * @return either ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT * @throws SQLException if a database access error occurs */ @Override @@ -933,13 +914,13 @@ public class MonetResultSet extends Mone @Override public void setFetchDirection(int direction) throws SQLException { switch (direction) { - case ResultSet.FETCH_FORWARD: - break; - case ResultSet.FETCH_REVERSE: - case ResultSet.FETCH_UNKNOWN: - throw new SQLException("Not supported direction " + direction, "0A000"); - default: - throw new SQLException("Illegal direction: " + direction, "M1M05"); + case ResultSet.FETCH_FORWARD: + break; + case ResultSet.FETCH_REVERSE: + case ResultSet.FETCH_UNKNOWN: + throw new SQLException("Not supported direction " + direction, "0A000"); + default: + throw new SQLException("Illegal direction: " + direction, "M1M05"); } } @@ -982,8 +963,7 @@ public class MonetResultSet extends Mone * ResultSet object as a float in the Java programming language. * * @param columnIndex the first column is 1, the second is 2, ... - * @return the column value; if the value is SQL NULL, the value returned - * is 0 + * @return the column value; if the value is SQL NULL, the value returned is 0 * @throws SQLException if there is no such column */ @Override @@ -1060,7 +1040,7 @@ public class MonetResultSet extends Mone public long getLong(int columnIndex) throws SQLException { try { if(setLastNullValue(columnIndex - 1)) { - return 0; + return 0L; } return currentBlock.getLongValue(columnIndex - 1); } catch (ClassCastException ex) { @@ -1196,20 +1176,14 @@ public class MonetResultSet extends Mone @Override public boolean isCaseSensitive(int column) throws SQLException { switch (getColumnType(column)) { + case Types.CLOB: case Types.CHAR: - case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness - case Types.CLOB: - return true; case Types.VARCHAR: - String monettype = getColumnTypeName(column); - if (monettype != null && monettype.length() == 4) { - // data of type inet or uuid is not case sensitive - if ("inet".equals(monettype) || "uuid".equals(monettype)) - return false; - } + case Types.LONGVARCHAR: return true; + default: + return false; } - return false; } /** @@ -1245,8 +1219,7 @@ public class MonetResultSet extends Mone } /** - * Indicates whether values in the designated column are signed - * numbers. + * Indicates whether values in the designated column are signed numbers. * Within MonetDB all numeric types (except oid and ptr) are signed. * * @param column the first column is 1, the second is 2, ... @@ -1254,23 +1227,16 @@ public class MonetResultSet extends Mone */ @Override public boolean isSigned(int column) throws SQLException { - // we can hardcode this, based on the colum type switch (getColumnType(column)) { - case Types.NUMERIC: - case Types.DECIMAL: case Types.TINYINT: case Types.SMALLINT: case Types.INTEGER: case Types.REAL: - case Types.FLOAT: case Types.DOUBLE: case Types.BIGINT: + case Types.NUMERIC: + case Types.DECIMAL: return true; - case Types.BIT: // we don't use type BIT, it's here for completeness - case Types.BOOLEAN: - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: default: return false; } @@ -1280,8 +1246,7 @@ public class MonetResultSet extends Mone * Indicates the designated column's normal maximum width in characters. * * @param column the first column is 1, the second is 2, ... - * @return the normal maximum number of characters allowed as the - * width of the designated column + * @return the normal maximum number of characters allowed as the width of the designated column * @throws SQLException if there is no such column */ @Override @@ -1345,10 +1310,8 @@ public class MonetResultSet extends Mone } /** - * Get the designated column's number of decimal digits. - * This method is currently very expensive as it needs to - * retrieve the information from the database using an SQL - * query. + * Get the designated column's number of decimal digits. This method is currently very expensive as it needs + * to retrieve the information from the database using an SQL query. * * @param column the first column is 1, the second is 2, ... * @return precision @@ -1361,13 +1324,14 @@ public class MonetResultSet extends Mone fetchColumnInfo(column); } if (_precision[column] == 0) { - // apparently no precision could be fetched - // use columnDisplaySize() value for variable length data types + // apparently no precision could be fetched use columnDisplaySize() value for variable + // length data types switch (getColumnType(column)) { case Types.CHAR: case Types.VARCHAR: - case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness + case Types.LONGVARCHAR: case Types.CLOB: + case Types.LONGVARBINARY: case Types.BLOB: case Types.NUMERIC: case Types.DECIMAL: @@ -1388,13 +1352,9 @@ public class MonetResultSet extends Mone case Types.REAL: _precision[column] = 7; break; - case Types.FLOAT: case Types.DOUBLE: _precision[column] = 15; break; - case Types.BIT: // MonetDB doesn't use type BIT, it's here for completeness - _precision[column] = 1; - break; case Types.BOOLEAN: _precision[column] = 5; break; @@ -1489,8 +1449,7 @@ public class MonetResultSet extends Mone } /** - * Indicates whether it is possible for a write on the - * designated column to succeed. + * Indicates whether it is possible for a write on the designated column to succeed. * * @param column the first column is 1, the second is 2, ... * @return true if so; false otherwise @@ -1501,8 +1460,7 @@ public class MonetResultSet extends Mone } /** - * Indicates whether a write on the designated column will - * definitely succeed. + * Indicates whether a write on the designated column will definitely succeed. * * @param column the first column is 1, the second is 2, ... * @return true if so; false otherwise @@ -1650,92 +1608,85 @@ public class MonetResultSet extends Mone return null; } JdbcType = JdbcSQLTypes[columnIndex - 1]; + switch(JdbcType) { + case Types.BOOLEAN: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.REAL: + case Types.DOUBLE: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.CLOB: + case Types.LONGVARBINARY: + case Types.BLOB: + return currentBlock.getValueAsObject(columnIndex - 1); + case Types.DATE: + return getDate(columnIndex); + case Types.TIME: + return getTime(columnIndex); + case Types.TIMESTAMP: + return getTimestamp(columnIndex); + case Types.OTHER: { + // The MonetDB types: inet, json, url and uuid are all mapped to Types.OTHER in MonetDriver.typeMap + // For these MonetDB types (except json, see comments below) we try to create objects of the corresponding class. + String MonetDBType = types[columnIndex - 1]; + String val = currentBlock.getValueAsString(columnIndex - 1); + switch (MonetDBType.length()) { + case 3: + if ("url".equals(MonetDBType)) { + try { + MonetURL url_obj = new MonetURL(); + url_obj.fromString(val); + return url_obj; + } catch (Exception exc) { + // ignore exception and just return the val String object + return val; + } + } + break; + case 4: + if ("inet".equals(MonetDBType)) { + try { + MonetINET inet_obj = new MonetINET(); + inet_obj.fromString(val); + return inet_obj; + } catch (Exception exc) { + // ignore exception and just return the val String object + return val; + } + } else + if ("uuid".equals(MonetDBType)) { + try { + return UUID.fromString(val); + } catch (IllegalArgumentException exc) { + // ignore exception and just return the val String object + return val; + } +// } else if ("json".equals(MonetDBType)) { //the same happens for geometry + // There is no support for JSON in standard java class libraries. + // Possibly we could use org.json.simple.JSONObject or other/faster libs + // javax.json.Json is not released yet (see https://json-processing-spec.java.net/) + // see also https://github.com/fabienrenaud/java-json-benchmark + // Note that it would make our JDBC driver dependent of an external jar + // and we don't want that so simply return it as String object + } + break; + } + return val; + } + default: + // When we get here the column type is a non-standard JDBC SQL type, possibly a User Defined Type. + // Just call getObject(int, Map) for those rare cases. + return getObject(columnIndex, this.getStatement().getConnection().getTypeMap()); + } } catch (IndexOutOfBoundsException e) { throw newSQLInvalidColumnIndexException(columnIndex); } - - switch(JdbcType) { - case Types.BIT: // MonetDB doesn't use type BInary digiT, it's here for completeness - case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness - case Types.BOOLEAN: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.DOUBLE: - case Types.FLOAT: - case Types.REAL: - case Types.DECIMAL: - case Types.NUMERIC: - case Types.CHAR: - case Types.VARCHAR: - case Types.BLOB: - case Types.CLOB: - return currentBlock.getValueAsObject(columnIndex - 1); - case Types.DATE: - return getDate(columnIndex); - case Types.TIME: - return getTime(columnIndex); - case Types.TIMESTAMP: - return getTimestamp(columnIndex); - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY, it's here for completeness - return getBytes(columnIndex); - case Types.OTHER: { - // The MonetDB types: inet, json, url and uuid are all mapped to Types.VARCHAR in MonetDriver.typeMap - // For these MonetDB types (except json, see comments below) we try to create objects of the corresponding class. - String MonetDBType = types[columnIndex - 1]; - String val = currentBlock.getValueAsString(columnIndex - 1); - switch (MonetDBType.length()) { - case 3: - if ("url".equals(MonetDBType)) { - try { - URL url_obj = new URL(); - url_obj.fromString(val); - return url_obj; - } catch (Exception exc) { - // ignore exception and just return the val String object - return val; - } - } - break; - case 4: - if ("inet".equals(MonetDBType)) { - try { - INET inet_obj = new INET(); - inet_obj.fromString(val); - return inet_obj; - } catch (Exception exc) { - // ignore exception and just return the val String object - return val; - } - } else - if ("uuid".equals(MonetDBType)) { - try { - return UUID.fromString(val); - } catch (IllegalArgumentException exc) { - // ignore exception and just return the val String object - return val; - } -// } else if ("json".equals(MonetDBType)) { - // There is no support for JSON in standard java class libraries. - // Possibly we could use org.json.simple.JSONObject or other/faster libs - // javax.json.Json is not released yet (see https://json-processing-spec.java.net/) - // see also https://github.com/fabienrenaud/java-json-benchmark - // Note that it would make our JDBC driver dependent of an external jar - // and we don't want that so simply return it as String object -// return val; - } - break; - } - return val; - } - default: - // When we get here the column type is a non-standard JDBC SQL type, possibly a User Defined Type. - // Just call getObject(int, Map) for those rare cases. - return getObject(columnIndex, this.getStatement().getConnection().getTypeMap()); - } } private boolean classImplementsSQLData(Class<?> cl) { @@ -1747,63 +1698,25 @@ public class MonetResultSet extends Mone return false; } - /** - * Gets the value of the designated column in the current row of this - * ResultSet object as an Object in the Java programming language. - * - * This method will return the value of the given column as a Java object. - * The type of the Java object will be the default Java object type corresponding - * to the column's SQL type, following the mapping for built-in types specified - * in the JDBC specification. - * If the value is an SQL NULL, the driver returns a Java null. - * - * This method may also be used to read database-specific abstract data types. - * In the JDBC 2.0 API, the behavior of method getObject is extended to - * materialize data of SQL user-defined types. - * - * If Connection.getTypeMap does not throw a SQLFeatureNotSupportedException, then - * when a column contains a structured or distinct value, the behavior of this - * method is as if it were a call to: getObject(columnIndex, - * this.getStatement().getInternalConnection().getTypeMap()). - * If Connection.getTypeMap does throw a SQLFeatureNotSupportedException, then - * structured values are not supported, and distinct values are mapped to the - * default Java class as determined by the underlying SQL type of the DISTINCT type. - * - * @param columnIndex the first column is 1, the second is 2, ... - * @param map a java.util.Map object that contains the mapping from SQL - * type names to classes in the Java programming language - * @return an Object in the Java programming language representing the SQL - * value - * @throws SQLException if a database access error occurs - */ - @Override @SuppressWarnings("unchecked") - public Object getObject(int columnIndex, Map<String,Class<?>> map) throws SQLException { - final String MonetDBtype; - try { - if(setLastNullValue(columnIndex - 1)) { - return null; - } - MonetDBtype = types[columnIndex - 1]; - } catch (IndexOutOfBoundsException e) { - throw newSQLInvalidColumnIndexException(columnIndex); - } - - Class<?> type = null; - if (map != null && map.containsKey(MonetDBtype)) { - type = map.get(MonetDBtype); + private Object getObjectFromClass(int columnIndex, Class<?> type) throws SQLException { + if(setLastNullValue(columnIndex - 1)) { + return null; } if (type == null) { // fallback to the standard Class mappings type = getClassForType(JdbcSQLTypes[columnIndex - 1]); } - if (type == null || type == String.class) { return currentBlock.getValueAsString(columnIndex - 1); + } else if (type == BigInteger.class) { + return getObject(columnIndex); } else if (type == BigDecimal.class) { return getBigDecimal(columnIndex); } else if (type == Boolean.class) { return getBoolean(columnIndex); + } else if (type == Byte.class) { + return getByte(columnIndex); } else if (type == Short.class) { return getShort(columnIndex); } else if (type == Integer.class) { @@ -1889,12 +1802,12 @@ public class MonetResultSet extends Mone } @Override - public java.sql.Date readDate() throws SQLException { + public Date readDate() throws SQLException { return getDate(colnum); } @Override - public java.sql.Time readTime() throws SQLException { + public Time readTime() throws SQLException { return getTime(colnum); } @@ -1949,7 +1862,7 @@ public class MonetResultSet extends Mone } @Override - public java.net.URL readURL() throws SQLException { + public URL readURL() throws SQLException { return getURL(colnum); } @@ -1973,7 +1886,7 @@ public class MonetResultSet extends Mone return getRowId(colnum); } }; - x.readSQL(input, MonetDBtype); + x.readSQL(input, types[columnIndex - 1]); return x; } else { return currentBlock.getObjectValue(columnIndex - 1); @@ -1981,6 +1894,48 @@ public class MonetResultSet extends Mone } /** + * Gets the value of the designated column in the current row of this + * ResultSet object as an Object in the Java programming language. + * + * This method will return the value of the given column as a Java object. + * The type of the Java object will be the default Java object type corresponding + * to the column's SQL type, following the mapping for built-in types specified + * in the JDBC specification. + * If the value is an SQL NULL, the driver returns a Java null. + * + * This method may also be used to read database-specific abstract data types. + * In the JDBC 2.0 API, the behavior of method getObject is extended to + * materialize data of SQL user-defined types. + * + * If Connection.getTypeMap does not throw a SQLFeatureNotSupportedException, then + * when a column contains a structured or distinct value, the behavior of this + * method is as if it were a call to: getObject(columnIndex, + * this.getStatement().getInternalConnection().getTypeMap()). + * If Connection.getTypeMap does throw a SQLFeatureNotSupportedException, then + * structured values are not supported, and distinct values are mapped to the + * default Java class as determined by the underlying SQL type of the DISTINCT type. + * + * @param columnIndex the first column is 1, the second is 2, ... + * @param map a java.util.Map object that contains the mapping from SQL + * type names to classes in the Java programming language + * @return an Object in the Java programming language representing the SQL value + * @throws SQLException if a database access error occurs + */ + @Override + public Object getObject(int columnIndex, Map<String, Class<?>> map) throws SQLException { + try { + String MonetDBtype = types[columnIndex - 1]; + Class<?> type = null; + if (map != null && map.containsKey(MonetDBtype)) { + type = map.get(MonetDBtype); + } + return getObjectFromClass(columnIndex, type); + } catch (IndexOutOfBoundsException e) { + throw newSQLInvalidColumnIndexException(columnIndex); + } + } + + /** * Retrieves the value of the designated column in the current row * of this ResultSet object and will convert from the SQL type of * the column to the requested Java data type, if the conversion is @@ -1992,22 +1947,20 @@ public class MonetResultSet extends Mone * SQL types to a Java type which implements SQLData, or Struct. * Additional conversions may be supported and are vendor defined. * - * @param i the first column is 1, the second is 2, ... - * @param type Class representing the Java data type to convert the - * designated column to + * @param columnIndex the first column is 1, the second is 2, ... + * @param type Class representing the Java data type to convert the designated column to * @return an instance of type holding the column value - * @throws SQLException if conversion is not supported, type is - * null or another error occurs. The getCause() method of - * the exception may provide a more detailed exception, for - * example, if a conversion error occurs + * @throws SQLException if conversion is not supported, type is null or another error occurs. The getCause() method + * of the exception may provide a more detailed exception, for example, if a conversion error occurs */ @Override - public <T> T getObject(int i, Class<T> type) throws SQLException { - if (type == null) { - throw new SQLException("type is null", "M1M05"); + @SuppressWarnings("unchecked") + public <T> T getObject(int columnIndex, Class<T> type) throws SQLException { + try { + return (T) getObjectFromClass(columnIndex, type); + } catch (IndexOutOfBoundsException e) { + throw newSQLInvalidColumnIndexException(columnIndex); } - throw new SQLFeatureNotSupportedException("cannot return a Java generic type based on static " + - "types from getXXX methods", "0AM34"); } /** @@ -2017,16 +1970,12 @@ public class MonetResultSet extends Mone * supported. If the conversion is not supported or null is * specified for the type, a SQLException is thrown. * - * @param columnLabel the label for the column specified with the - * SQL AS clause. If the SQL AS clause was not specified, - * then the label is the name of the column - * @param type Class representing the Java data type to convert the - * designated column to + * @param columnLabel the label for the column specified with the SQL AS clause. If the SQL AS clause was not + * specified, then the label is the name of the column + * @param type Class representing the Java data type to convert the designated column to * @return an instance of type holding the column value - * @throws SQLException if conversion is not supported, type is - * null or another error occurs. The getCause() method of - * the exception may provide a more detailed exception, for - * example, if a conversion error occurs + * @throws SQLException if conversion is not supported, type is null or another error occurs. The getCause() method + * of the exception may provide a more detailed exception, for example, if a conversion error occurs */ @Override public <T> T getObject(String columnLabel, Class<T> type) throws SQLException { @@ -2034,30 +1983,28 @@ public class MonetResultSet extends Mone } /** - * Helper method to support the getObject and - * ResultsetMetaData.getColumnClassName JDBC methods. + * Helper method to support the getObject and ResultsetMetaData.getColumnClassName JDBC methods. * * @param type a value from java.sql.Types * @return a Class object from which an instance would be returned */ static Class<?> getClassForType(int type) { /** - * This switch returns the types as objects according to table B-3 from - * Oracle's JDBC specification 4.1 + * This switch returns the types as objects according to table B-3 from Oracle's JDBC specification 4.1 */ - // keep this switch regarding the returned classes aligned with getObject(int, Map) ! - switch(type) { + switch(type) { // keep this switch regarding the returned classes aligned with getObject(int, Map) ! case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: return String.class; case Types.NUMERIC: + return BigInteger.class; case Types.DECIMAL: return BigDecimal.class; case Types.BOOLEAN: return Boolean.class; - case Types.BIT: // MonetDB doesn't support type BIT, it's here for completeness case Types.TINYINT: + return Byte.class; case Types.SMALLINT: return Short.class; case Types.INTEGER: @@ -2066,11 +2013,8 @@ public class MonetResultSet extends Mone return Long.class; case Types.REAL: return Float.class; - case Types.FLOAT: case Types.DOUBLE: return Double.class; - case Types.BINARY: // MonetDB currently does not support these - case Types.VARBINARY: // see treat_blob_as_binary property case Types.LONGVARBINARY: return byte[].class; case Types.DATE: @@ -2083,8 +2027,7 @@ public class MonetResultSet extends Mone return Clob.class; case Types.BLOB: return Blob.class; - // all the rest are currently not implemented and used - default: + default: // all the rest are currently not implemented and used return String.class; } } @@ -2163,9 +2106,8 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row - * of this ResultSet object as a java.sql.RowId object in the Java - * programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.RowId + * object in the Java programming language. * * @param columnName the SQL name of the column * @return the column value; if the value is SQL NULL, the value returned is null @@ -2178,8 +2120,8 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a short in the Java programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a short in the Java + * programming language. * * @param columnIndex the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is 0 @@ -2200,8 +2142,8 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a short in the Java programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a short in the Java + * programming language. * * @param columnName the SQL name of the column * @return the column value; if the value is SQL NULL, the value returned is 0 @@ -2213,12 +2155,11 @@ public class MonetResultSet extends Mone } /** - * Retrieves the Statement object that produced this ResultSet object. If - * the result set was generated some other way, such as by a - * DatabaseMetaData method, this method returns null. + * Retrieves the Statement object that produced this ResultSet object. If the result set was generated some other + * way, such as by a DatabaseMetaData method, this method returns null. * - * @return the Statement object that produced this ResultSet object or null - * if the result set was produced some other way + * @return the Statement object that produced this ResultSet object or null if the result set was produced some + * other way */ @Override public Statement getStatement() { @@ -2226,8 +2167,8 @@ public class MonetResultSet extends Mone } /** - * Retrieves the value of the designated column in the current row of this - * ResultSet object as a String in the Java programming language. + * Retrieves the value of the designated column in the current row of this ResultSet object as a String in the Java + * programming language. * * @param columnIndex the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null @@ -2354,12 +2295,31 @@ public class MonetResultSet extends Mone if(setLastNullValue(columnIndex - 1)) { return null; } - return (Date) currentBlock.getObjectValue(columnIndex - 1); - } catch (ClassCastException ex) { + Calendar res; + switch (JdbcSQLTypes[columnIndex - 1]) { + case Types.CHAR : + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.CLOB: + String value = currentBlock.getValueAsString(columnIndex - 1); + res = GregorianCalendarParser.ParseDate(value, new ParsePosition(0)); + break; + case Types.DATE: + res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1); + break; + default: + throw new SQLException("Conversion from " + types[columnIndex - 1] + + " to Date not supported", "M1M05"); + } + res.setTimeZone(cal.getTimeZone()); + return new Date(res.getTimeInMillis()); + } catch (ClassCastException ex) { throw new SQLException(ex.getMessage()); } catch (IndexOutOfBoundsException e) { throw newSQLInvalidColumnIndexException(columnIndex); - } + } catch (ProtocolException ep) { + throw new SQLException(ep.getMessage(), "M1M05"); + } } /** @@ -2421,18 +2381,39 @@ public class MonetResultSet extends Mone */ @Override public Time getTime(int columnIndex, Calendar cal) throws SQLException { - if (cal == null) - throw new IllegalArgumentException("No Calendar object given!"); - try { - if(setLastNullValue(columnIndex - 1)) { - return null; - } - return (Time) currentBlock.getObjectValue(columnIndex - 1); - } catch (ClassCastException ex) { - throw new SQLException(ex.getMessage()); - } catch (IndexOutOfBoundsException e) { - throw newSQLInvalidColumnIndexException(columnIndex); - } + try { + if(setLastNullValue(columnIndex - 1)) { + return null; + } + Calendar res; + switch (JdbcSQLTypes[columnIndex - 1]) { + case Types.CHAR : + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.CLOB: + String value = currentBlock.getValueAsString(columnIndex - 1); + res = GregorianCalendarParser.ParseTime(value, new ParsePosition(0), false); + res.setTimeZone(cal.getTimeZone()); + break; + case Types.TIME: + res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1); + res.setTimeZone(cal.getTimeZone()); + break; + case Types.TIME_WITH_TIMEZONE: + res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1); + break; + default: + throw new SQLException("Conversion from " + types[columnIndex - 1] + + " to Time not supported", "M1M05"); + } + return new Time(res.getTimeInMillis()); + } catch (ClassCastException ex) { + throw new SQLException(ex.getMessage()); + } catch (IndexOutOfBoundsException e) { + throw newSQLInvalidColumnIndexException(columnIndex); + } catch (ProtocolException ep) { + throw new SQLException(ep.getMessage(), "M1M05"); + } } /** @@ -2494,18 +2475,39 @@ public class MonetResultSet extends Mone */ @Override public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { - if (cal == null) - throw new IllegalArgumentException("No Calendar object given!"); - try { - if(setLastNullValue(columnIndex - 1)) { - return null; - } - return (Timestamp) currentBlock.getObjectValue(columnIndex - 1); - } catch (ClassCastException ex) { - throw new SQLException(ex.getMessage()); - } catch (IndexOutOfBoundsException e) { - throw newSQLInvalidColumnIndexException(columnIndex); - } + try { + if(setLastNullValue(columnIndex - 1)) { + return null; + } + Calendar res; + switch (JdbcSQLTypes[columnIndex - 1]) { + case Types.CHAR : + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.CLOB: + String value = currentBlock.getValueAsString(columnIndex - 1); + res = GregorianCalendarParser.ParseTimestamp(value, new ParsePosition(0), false); + res.setTimeZone(cal.getTimeZone()); + break; + case Types.TIMESTAMP: + res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1); + res.setTimeZone(cal.getTimeZone()); + break; + case Types.TIMESTAMP_WITH_TIMEZONE: + res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1); + break; + default: + throw new SQLException("Conversion from " + types[columnIndex - 1] + + " to Timestamp not supported", "M1M05"); + } + return new Timestamp(res.getTimeInMillis()); + } catch (ClassCastException ex) { + throw new SQLException(ex.getMessage()); + } catch (IndexOutOfBoundsException e) { + throw newSQLInvalidColumnIndexException(columnIndex); + } catch (ProtocolException ep) { + throw new SQLException(ep.getMessage(), "M1M05"); + } } /** @@ -2543,8 +2545,7 @@ public class MonetResultSet extends Mone * Retrieves the type of this ResultSet object. The type is determined by * the Statement object that created the result set. * - * @return ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, - * or ResultSet.TYPE_SCROLL_SENSITIVE + * @return ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE or ResultSet.TYPE_SCROLL_SENSITIVE */ @Override public int getType() { @@ -2561,18 +2562,27 @@ public class MonetResultSet extends Mone * @throws SQLException if a database access error occurs, or if a URL is malformed */ @Override - public java.net.URL getURL(int columnIndex) throws SQLException { + public URL getURL(int columnIndex) throws SQLException { try { if(setLastNullValue(columnIndex - 1)) { return null; } - try { - return new java.net.URL(currentBlock.getValueAsString(columnIndex - 1)); - } catch (MalformedURLException e) { - throw new SQLException(e.getMessage(), "M1M05"); + switch(JdbcSQLTypes[columnIndex - 1]) { //if it's a string type, will attempt the conversion + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.CLOB: + return new URL(currentBlock.getValueAsString(columnIndex - 1)); + } + if(JdbcSQLTypes[columnIndex - 1] == Types.OTHER && "url".equals(types[columnIndex - 1])) { + return new URL(currentBlock.getValueAsString(columnIndex - 1)); + } else { + throw new SQLException("Cannot convert " + types[columnIndex - 1] + " to an url", "M1M05"); } } catch (IndexOutOfBoundsException e) { throw newSQLInvalidColumnIndexException(columnIndex); + } catch (MalformedURLException e) { + throw new SQLException(e.getMessage(), "M1M05"); } } @@ -2587,7 +2597,7 @@ public class MonetResultSet extends Mone * @throws SQLException if a database access error occurs, or if a URL is malformed */ @Override - public java.net.URL getURL(String columnName) throws SQLException { + public URL getURL(String columnName) throws SQLException { return getURL(findColumn(columnName)); } @@ -2619,8 +2629,8 @@ public class MonetResultSet extends Mone /** * Retrieves whether the cursor is after the last row in this ResultSet object. * - * @return true if the cursor is after the last row; false if the cursor is - * at any other position or the result set contains no rows + * @return true if the cursor is after the last row; false if the cursor is at any other position or the result set + * contains no rows */ @Override public boolean isAfterLast() { @@ -2630,8 +2640,8 @@ public class MonetResultSet extends Mone /** * Retrieves whether the cursor is before the first row in this ResultSet object. * - * @return true if the cursor is before the first row; false if the cursor - * is at any other position or the result set contains no rows + * @return true if the cursor is before the first row; false if the cursor is at any other position or the result + * set contains no rows */ @Override public boolean isBeforeFirst() { @@ -3291,4 +3301,3 @@ public class MonetResultSet extends Mone return new SQLFeatureNotSupportedException("Method " + name + " not implemented", "0A000"); } } -
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetSavepoint.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetSavepoint.java @@ -41,8 +41,8 @@ public class MonetSavepoint implements S private final int id; public MonetSavepoint(String name) throws IllegalArgumentException { - if (name == null) throw new IllegalArgumentException("null not allowed"); - + if (name == null) + throw new IllegalArgumentException("Null name not allowed"); this.id = getNextId(); this.name = name; } @@ -60,9 +60,8 @@ public class MonetSavepoint implements S */ @Override public int getSavepointId() throws SQLException { - if (name != null) throw - new SQLException("Cannot getID for named savepoint", "3B000"); - + if (name != null) + throw new SQLException("Cannot getID for named savepoint", "3B000"); return getId(); } @@ -74,9 +73,8 @@ public class MonetSavepoint implements S */ @Override public String getSavepointName() throws SQLException { - if (name == null) throw - new SQLException("Unable to retrieve name of unnamed savepoint", "3B000"); - + if (name == null) + throw new SQLException("Unable to retrieve name of unnamed savepoint", "3B000"); return name; }
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java @@ -234,7 +234,8 @@ public class MonetStatement extends Mone } } - private boolean internalBatch(String batch, int[] counts, int offset, int max, BatchUpdateException e) throws BatchUpdateException { + private boolean internalBatch(String batch, int[] counts, int offset, int max, BatchUpdateException e) + throws BatchUpdateException { try { boolean type = internalExecute(batch); int count = -1; @@ -950,8 +951,7 @@ public class MonetStatement extends Mone @Override public void setEscapeProcessing(boolean enable) throws SQLException { if (enable) { - addWarning("setEscapeProcessing: JDBC escape syntax is not supported by this driver", - "01M22"); + addWarning("setEscapeProcessing: JDBC escape syntax is not supported by this driver", "01M22"); } }
rename from src/main/java/nl/cwi/monetdb/jdbc/types/INET.java rename to src/main/java/nl/cwi/monetdb/jdbc/types/MonetINET.java --- a/src/main/java/nl/cwi/monetdb/jdbc/types/INET.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/types/MonetINET.java @@ -25,7 +25,8 @@ import java.net.*; * This is probably meaningful only and only if the netmask is 32. The * getNetmaskBits() method can be used to retrieve the subnet bits. */ -public class INET implements SQLData { +public class MonetINET implements SQLData { + private String inet; @Override
rename from src/main/java/nl/cwi/monetdb/jdbc/types/URL.java rename to src/main/java/nl/cwi/monetdb/jdbc/types/MonetURL.java --- a/src/main/java/nl/cwi/monetdb/jdbc/types/URL.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/types/MonetURL.java @@ -16,7 +16,8 @@ import java.net.*; * represents an URL, that is, a well-formed string conforming to * RFC2396. */ -public class URL implements SQLData { +public class MonetURL implements SQLData { + private String url; @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/ControlCommands.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/ControlCommands.java @@ -1,8 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection; -/** - * Created by ferreira on 12/9/16. - */ public enum ControlCommands { /** Send autocommit statement */
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/IMonetDBLanguage.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/IMonetDBLanguage.java @@ -1,8 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection; -/** - * Created by ferreira on 12/9/16. - */ public interface IMonetDBLanguage { String getQueryTemplateIndex(int index);
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/SenderThread.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/SenderThread.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol;
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/BufferReallocator.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/BufferReallocator.java @@ -1,11 +1,16 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection.helpers; import java.nio.CharBuffer; -/** - * Created by ferreira on 12/14/16. - */ -public class BufferReallocator { +public final class BufferReallocator { private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/ChannelSecurity.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/ChannelSecurity.java @@ -1,12 +1,17 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection.helpers; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -/** - * Created by ferreira on 12/1/16. - */ -public class ChannelSecurity { +public final class ChannelSecurity { private static char HexChar(int n) { return (n > 9) ? (char) ('a' + (n - 10)) : (char) ('0' + n); }
new file mode 100644 --- /dev/null +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/GregorianCalendarParser.java @@ -0,0 +1,106 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + +package nl.cwi.monetdb.mcl.connection.helpers; + +import nl.cwi.monetdb.mcl.protocol.ProtocolException; + +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +public final class GregorianCalendarParser { + + private static final SimpleDateFormat DateParser = new SimpleDateFormat("yyyy-MM-dd"); + + private static final SimpleDateFormat TimeParser = new SimpleDateFormat("HH:mm:ss"); + + private static final SimpleDateFormat TimestampParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /** + * Small helper method that returns the intrinsic value of a char if it represents a digit. If a non-digit character + * is encountered an MCLParseException is thrown. + * + * @param c the char + * @param pos the position + * @return the intrinsic value of the char + * @throws ProtocolException if c is not a digit + */ + private static int getIntrinsicValue(char c, int pos) throws ProtocolException { + // note: don't use Character.isDigit() here, because we only want ISO-LATIN-1 digits + if (c >= '0' && c <= '9') { + return (int)c - (int)'0'; + } else { + throw new ProtocolException("Expected a digit", pos); + } + } + + public static Calendar ParseDate(String toParse, ParsePosition pos) throws ProtocolException { + pos.setIndex(0); + Calendar res = new GregorianCalendar(); + Date util = DateParser.parse(toParse, pos); + if(util == null) { + res.clear(); + } else { + res.setTime(util); + } + return res; + } + + private static Calendar ParseTimeIn(String toParse, ParsePosition pos, boolean hasTimeZone, + SimpleDateFormat parser) throws ProtocolException { + pos.setIndex(0); + Calendar res = new GregorianCalendar(); + Date util = parser.parse(toParse, pos); + if(util == null) { + res.clear(); + } else { + res.setTime(util); + } + + // parse additional nanos (if any) + int pos1 = pos.getIndex(), nanos; + if (pos1 < toParse.length() && toParse.charAt(pos1) == '.') { + pos1++; + int ctr; + + nanos = getIntrinsicValue(toParse.charAt(pos1), pos1++); + for (ctr = 1; pos1 < toParse.length() && toParse.charAt(pos1) >= '0' && toParse.charAt(pos1) <= '9'; ctr++) { + if (ctr < 9) { + nanos *= 10; + nanos += (getIntrinsicValue(toParse.charAt(pos1), pos1)); + } + if (ctr == 2) // we have three at this point + res.set(Calendar.MILLISECOND, nanos); + pos1++; + } + while (ctr++ < 9) + nanos *= 10; + } + + if(hasTimeZone) { + int vallen = toParse.length(); + if (vallen >= 6) { // MonetDB/SQL99: Sign TwoDigitHours : Minutes + res.setTimeZone(TimeZone.getTimeZone("GMT" + toParse.substring(vallen - 6, vallen))); + } + } + return res; + } + + public static Calendar ParseTime(String toParse, ParsePosition pos, boolean hasTimeZone) throws ProtocolException { + return ParseTimeIn(toParse, pos, hasTimeZone, TimeParser); + } + + public static Calendar ParseTimestamp(String toParse, ParsePosition pos, boolean hasTimeZone) + throws ProtocolException { + return ParseTimeIn(toParse, pos, hasTimeZone, TimestampParser); + } +}
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection.mapi; import nl.cwi.monetdb.mcl.connection.helpers.BufferReallocator; @@ -13,9 +21,6 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; -/** - * Created by ferreira on 12/9/16. - */ public abstract class AbstractSocket implements Closeable { protected final Socket socket;
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiConnection.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiConnection.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection.mapi; import nl.cwi.monetdb.jdbc.MonetConnection; @@ -40,8 +48,8 @@ public class MapiConnection extends Mone private ByteOrder serverEndianness; public MapiConnection(Properties props, String database, String hash, String language, boolean blobIsBinary, - String hostname, int port) throws IOException { - super(props, database, hash, MapiLanguage.GetLanguageFromString(language), blobIsBinary); + boolean clobIsLongChar, String hostname, int port) throws IOException { + super(props, database, hash, MapiLanguage.GetLanguageFromString(language), blobIsBinary, clobIsLongChar); this.hostname = hostname; this.port = port; }
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiLanguage.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiLanguage.java @@ -1,10 +1,15 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection.mapi; import nl.cwi.monetdb.mcl.connection.IMonetDBLanguage; -/** - * Created by ferreira on 11/30/16. - */ public enum MapiLanguage implements IMonetDBLanguage { /** the SQL language */
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/OldMapiSocket.java +++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/OldMapiSocket.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.connection.mapi; import java.io.IOException; @@ -5,9 +13,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; -/** - * Created by ferreira on 12/9/16. - */ public class OldMapiSocket extends AbstractSocket { /** The blocksize (hardcoded in compliance with stream.mx) */
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol; import nl.cwi.monetdb.jdbc.MonetConnection; @@ -10,9 +18,6 @@ import nl.cwi.monetdb.mcl.responses.Resu import java.io.IOException; import java.util.Map; -/** - * Created by ferreira on 11/30/16. - */ public abstract class AbstractProtocol { public abstract void waitUntilPrompt() throws IOException;
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/ServerResponses.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/ServerResponses.java @@ -1,8 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol; -/** - * Created by ferreira on 11/30/16. - */ public enum ServerResponses { /* Please don't change the order */
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/StarterHeaders.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/StarterHeaders.java @@ -1,8 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol; -/** - * Created by ferreira on 11/30/16. - */ public enum StarterHeaders { /* Please don't change the order */
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/TableResultHeaders.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/TableResultHeaders.java @@ -1,8 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol; -/** - * Created by ferreira on 11/30/16. - */ public enum TableResultHeaders { /* Please don't change the order */
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol.newmapi; import nl.cwi.monetdb.jdbc.MonetConnection; @@ -10,9 +18,6 @@ import nl.cwi.monetdb.mcl.responses.Upda import java.io.IOException; import java.util.Map; -/** - * Created by ferreira on 11/30/16. - */ public class NewMapiProtocol extends AbstractProtocol { @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol.oldmapi; import nl.cwi.monetdb.jdbc.MonetConnection; @@ -16,9 +24,6 @@ import java.io.IOException; import java.nio.CharBuffer; import java.util.Map; -/** - * Created by ferreira on 11/30/16. - */ public class OldMapiProtocol extends AbstractProtocol { private ServerResponses currentServerResponseHeader = ServerResponses.UNKNOWN;
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiServerResponseParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiServerResponseParser.java @@ -1,10 +1,15 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol.oldmapi; import nl.cwi.monetdb.mcl.protocol.ServerResponses; -/** - * Created by ferreira on 11/30/16. - */ final class OldMapiServerResponseParser { static ServerResponses ParseOldMapiServerResponse(OldMapiProtocol protocol) {
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiStartOfHeaderParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiStartOfHeaderParser.java @@ -1,11 +1,16 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol.oldmapi; import nl.cwi.monetdb.mcl.protocol.ProtocolException; import nl.cwi.monetdb.mcl.protocol.StarterHeaders; -/** - * Created by ferreira on 12/6/16. - */ final class OldMapiStartOfHeaderParser { static StarterHeaders GetNextStartHeaderOnOldMapi(OldMapiProtocol protocol) {
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol.oldmapi; import nl.cwi.monetdb.mcl.protocol.ProtocolException; @@ -5,9 +13,6 @@ import nl.cwi.monetdb.mcl.protocol.Table import java.nio.CharBuffer; -/** - * Created by ferreira on 12/6/16. - */ final class OldMapiTableHeaderParser { static TableResultHeaders GetNextTableHeader(CharBuffer lineBuffer, String[] columnNames, int[] columnLengths,
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java +++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java @@ -1,19 +1,24 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.protocol.oldmapi; import nl.cwi.monetdb.jdbc.MonetBlob; import nl.cwi.monetdb.jdbc.MonetClob; +import nl.cwi.monetdb.mcl.connection.helpers.GregorianCalendarParser; import nl.cwi.monetdb.mcl.protocol.ProtocolException; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.CharBuffer; import java.sql.Types; -import java.text.ParseException; -import java.text.SimpleDateFormat; - -/** - * Created by ferreira on 12/6/16. - */ +import java.text.ParsePosition; +import java.util.Calendar; final class OldMapiTupleLineParser { private static final char[] NULL_STRING = "NULL".toCharArray(); @@ -167,12 +172,6 @@ final class OldMapiTupleLineParser { return column; } - private static final SimpleDateFormat DateParser = new SimpleDateFormat("yyyy-MM-dd"); - - private static final SimpleDateFormat TimeParser = new SimpleDateFormat("HH:mm:ss"); - - private static final SimpleDateFormat TimestampParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - private static byte[] BinaryBlobConverter(String toParse) { int len = toParse.length() / 2; byte[] res = new byte[len]; @@ -182,6 +181,8 @@ final class OldMapiTupleLineParser { return res; } + private static final ParsePosition Ppos = new ParsePosition(0); + private static void OldMapiStringToJavaObjectConverter(String toParse, int lineNumber, Object columnArray, int jDBCMapping) throws ProtocolException { switch (jDBCMapping) { @@ -207,45 +208,40 @@ final class OldMapiTupleLineParser { ((double[]) columnArray)[lineNumber] = Double.parseDouble(toParse); break; case Types.DECIMAL: - ((Object[]) columnArray)[lineNumber] = new BigDecimal(toParse); + ((BigDecimal[]) columnArray)[lineNumber] = new BigDecimal(toParse); break; case Types.NUMERIC: - ((Object[]) columnArray)[lineNumber] = new BigInteger(toParse); + ((BigInteger[]) columnArray)[lineNumber] = new BigInteger(toParse); break; case Types.CHAR: case Types.VARCHAR: + case Types.LONGVARCHAR: case Types.OTHER: - ((Object[]) columnArray)[lineNumber] = toParse; + ((String[]) columnArray)[lineNumber] = toParse; break; case Types.DATE: - try { - ((Object[]) columnArray)[lineNumber] = DateParser.parse(toParse); - } catch (ParseException e) { - throw new ProtocolException(e.getMessage()); - } + ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseDate(toParse, Ppos); break; case Types.TIME: - try { - ((Object[]) columnArray)[lineNumber] = TimeParser.parse(toParse); - } catch (ParseException e) { - throw new ProtocolException(e.getMessage()); - } + ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTime(toParse, Ppos, false); + break; + case Types.TIME_WITH_TIMEZONE: + ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTime(toParse, Ppos, true); break; case Types.TIMESTAMP: - try { - ((Object[]) columnArray)[lineNumber] = TimestampParser.parse(toParse); - } catch (ParseException e) { - throw new ProtocolException(e.getMessage()); - } + ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTimestamp(toParse, Ppos, false); + break; + case Types.TIMESTAMP_WITH_TIMEZONE: + ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTimestamp(toParse, Ppos, true); break; case Types.CLOB: - ((Object[]) columnArray)[lineNumber] = new MonetClob(toParse); + ((MonetClob[]) columnArray)[lineNumber] = new MonetClob(toParse); break; case Types.BLOB: - ((Object[]) columnArray)[lineNumber] = new MonetBlob(BinaryBlobConverter(toParse)); + ((MonetBlob[]) columnArray)[lineNumber] = new MonetBlob(BinaryBlobConverter(toParse)); break; - case Types.BINARY: - ((Object[]) columnArray)[lineNumber] = BinaryBlobConverter(toParse); + case Types.LONGVARBINARY: + ((byte[][]) columnArray)[lineNumber] = BinaryBlobConverter(toParse); break; default: throw new ProtocolException("Unknown type!");
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/AutoCommitResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/AutoCommitResponse.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; /**
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java @@ -1,10 +1,24 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; +import nl.cwi.monetdb.jdbc.MonetBlob; +import nl.cwi.monetdb.jdbc.MonetClob; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.ProtocolException; import nl.cwi.monetdb.mcl.protocol.ServerResponses; +import java.math.BigDecimal; +import java.math.BigInteger; import java.sql.Types; +import java.util.Arrays; +import java.util.Calendar; /** * The DataBlockResponse is tabular data belonging to a @@ -91,8 +105,30 @@ public class DataBlockResponse implement case Types.DOUBLE: this.data[i] = new double[numberOfRows]; break; - default: - this.data[i] = new Object[numberOfRows]; + case Types.DECIMAL: + this.data[i] = new BigDecimal[numberOfRows]; + break; + case Types.NUMERIC: + this.data[i] = new BigInteger[numberOfRows]; + break; + case Types.BLOB: + this.data[i] = new MonetBlob[numberOfRows]; + break; + case Types.CLOB: + this.data[i] = new MonetClob[numberOfRows]; + break; + case Types.TIME: + case Types.TIME_WITH_TIMEZONE: + case Types.DATE: + case Types.TIMESTAMP: + case Types.TIMESTAMP_WITH_TIMEZONE: + this.data[i] = new Calendar[numberOfRows]; + break; + case Types.LONGVARBINARY: + this.data[i] = new byte[numberOfRows][]; + break; + default: //CHAR, VARCHAR, OTHER + this.data[i] = new String[numberOfRows]; } } } @@ -194,12 +230,9 @@ public class DataBlockResponse implement return Float.toString(((float[]) this.data[column])[this.blockLine]); case Types.DOUBLE: return Double.toString(((double[]) this.data[column])[this.blockLine]); - case Types.CHAR: - case Types.VARCHAR: - case Types.CLOB: - case Types.OTHER: - return (String) ((Object[]) this.data[column])[this.blockLine]; - default: + case Types.LONGVARBINARY: + return Arrays.toString(((byte[][]) this.data[column])[this.blockLine]); + default: //CHAR, VARCHAR, LONGVARCHAR, OTHER, BLOB, CLOB and others return ((Object[]) this.data[column])[this.blockLine].toString(); } } @@ -209,17 +242,17 @@ public class DataBlockResponse implement case Types.BOOLEAN: return ((boolean[]) this.data[column])[this.blockLine]; case Types.TINYINT: - return (((byte[]) this.data[column])[this.blockLine]); + return ((byte[]) this.data[column])[this.blockLine]; case Types.SMALLINT: - return (((short[]) this.data[column])[this.blockLine]); + return ((short[]) this.data[column])[this.blockLine]; case Types.INTEGER: - return (((int[]) this.data[column])[this.blockLine]); + return ((int[]) this.data[column])[this.blockLine]; case Types.BIGINT: - return (((long[]) this.data[column])[this.blockLine]); + return ((long[]) this.data[column])[this.blockLine]; case Types.REAL: - return (((float[]) this.data[column])[this.blockLine]); + return ((float[]) this.data[column])[this.blockLine]; case Types.DOUBLE: - return (((double[]) this.data[column])[this.blockLine]); + return ((double[]) this.data[column])[this.blockLine]; default: return ((Object[]) this.data[column])[this.blockLine]; }
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java @@ -1,11 +1,16 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.ProtocolException; -/** - * Created by ferreira on 12/15/16. - */ public interface IIncompleteResponse extends IResponse { /** * Returns whether this Response expects more lines to be added to it.
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/IResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/IResponse.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; /**
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; import nl.cwi.monetdb.jdbc.MonetConnection; @@ -126,7 +134,10 @@ public class ResultSetResponse implement for (int i = 0; i < this.type.length; i++) { int javaSQLtype = MonetDriver.getJavaType(this.type[i]); if (javaSQLtype == Types.BLOB && con.getBlobAsBinary()) { - javaSQLtype = Types.BINARY; + javaSQLtype = Types.LONGVARBINARY; + } + if (javaSQLtype == Types.CLOB && con.getClobAsLongChar()) { + javaSQLtype = Types.LONGVARCHAR; } this.JdbcSQLTypes[i] = javaSQLtype; }
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/SchemaResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/SchemaResponse.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; import java.sql.Statement;
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/UpdateResponse.java +++ b/src/main/java/nl/cwi/monetdb/mcl/responses/UpdateResponse.java @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. + */ + package nl.cwi.monetdb.mcl.responses; /**
--- a/src/main/java/nl/cwi/monetdb/merovingian/Control.java +++ b/src/main/java/nl/cwi/monetdb/merovingian/Control.java @@ -98,7 +98,7 @@ public class Control { private List<String> sendCommand(String database, String command, boolean hasOutput) throws MerovingianException, IOException { - MapiConnection server = new MapiConnection(null, "merovingian",null, "control", true, host, port ); + MapiConnection server = new MapiConnection(null, "merovingian",null, "control", false, true, host, port ); AbstractProtocol protocol = server.getProtocol(); try { server.connect("monetdb", passphrase);
--- a/src/main/java/nl/cwi/monetdb/util/SQLRestore.java +++ b/src/main/java/nl/cwi/monetdb/util/SQLRestore.java @@ -102,7 +102,7 @@ public class SQLRestore { * @throws IOException */ public void restore(File source) throws IOException { - MapiConnection server = new MapiConnection(null, _dbName,null, "sql", true,_host, _port ); + MapiConnection server = new MapiConnection(null, _dbName,null, "sql", false, true, _host, _port ); try { server.connect(_user, _password);
--- a/tests/Test_PSsqldata.java +++ b/tests/Test_PSsqldata.java @@ -37,8 +37,8 @@ public class Test_PSsqldata { System.out.println("\tclassname " + pmd.getParameterClassName(col)); } - INET tinet = new INET(); - URL turl = new URL(); + MonetINET tinet = new MonetINET(); + MonetURL turl = new MonetURL(); tinet.fromString("172.5.5.5/24"); turl.fromString("http://www.monetdb.org/"); @@ -59,12 +59,12 @@ public class Test_PSsqldata { System.out.println("" + i + ".\t<null>"); } else { System.out.println("" + i + ".\t" + x.toString()); - if (x instanceof INET) { - INET inet = (INET)x; + if (x instanceof MonetINET) { + MonetINET inet = (MonetINET)x; System.out.println("\t" + inet.getAddress() + "/" + inet.getNetmaskBits()); System.out.println("\t" + inet.getInetAddress().toString()); - } else if (x instanceof URL) { - URL url = (URL)x; + } else if (x instanceof MonetURL) { + MonetURL url = (MonetURL)x; System.out.println("\t" + url.getURL().toString()); } }
--- a/tests/Test_Rsqldata.java +++ b/tests/Test_Rsqldata.java @@ -51,12 +51,12 @@ public class Test_Rsqldata { System.out.println("" + i + ".\t<null>"); } else { System.out.println("" + i + ".\t" + x.toString()); - if (x instanceof INET) { - INET inet = (INET)x; + if (x instanceof MonetINET) { + MonetINET inet = (MonetINET)x; System.out.println("\t" + inet.getAddress() + "/" + inet.getNetmaskBits()); System.out.println("\t" + inet.getInetAddress().toString()); - } else if (x instanceof URL) { - URL url = (URL)x; + } else if (x instanceof MonetURL) { + MonetURL url = (MonetURL)x; System.out.println("\t" + url.getURL().toString()); } }