changeset 376:ffdc7b0e102d

Updated JDBC driver to comply with JDBC 4.2 interface now we compile for Java 8. This includes: - adding 8 methods to MonetCallableStatement - adding 2 methods to MonetDatabaseMetaData - adding 3 methods to MonetPreparedStatement - adding 4 methods to MonetResultSet - adding 8 methods to MonetStatement Some methods needs some more work, for instance getLargeUpdateCount(). This will be done in a separate checkin.
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Wed, 23 Sep 2020 18:55:33 +0200 (2020-09-23)
parents a229ac4e275c
children 8a813f5cef1b
files ChangeLog release.txt src/main/java/nl/cwi/monetdb/jdbc/MonetCallableStatement.java src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
diffstat 8 files changed, 464 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,10 +2,20 @@
 # This file is updated with Maddlog
 
 * Wed Sep 23 2020 Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
+- Updated JDBC driver to comply with JDBC 4.2 interface now we compile
+  for Java 8. This includes:
+  - adding 8 methods to MonetCallableStatement
+  - adding 2 methods to MonetDatabaseMetaData
+  - adding 3 methods to MonetPreparedStatement
+  - adding 4 methods to MonetResultSet
+  - adding 8 methods to MonetStatement
 - Corrected MonetDatabaseMetaData.getTypeInfo()
-  - The LITERAL_PREFIX column now includes the required casting name for types: clob, inet, json, url, uuid and blob.
-  - The SEARCHABLE column now returns typePredBasic instead of typeSearchable for type: blob.
-  - The AUTO_INCREMENT column now returns false for types: hugeint, decimal, oid and wrd.
+  - The LITERAL_PREFIX column now includes the required casting name for
+    types: clob, inet, json, url, uuid and blob.
+  - The SEARCHABLE column now returns typePredBasic instead of typeSearchable
+    for type: blob.
+  - The AUTO_INCREMENT column now returns false for types: hugeint, decimal,
+    oid and wrd.
 
 * Thu Sep 10 2020 Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
 - Removed support for deprecated MD5 encryption algorithm in MapiSocket.
--- a/release.txt
+++ b/release.txt
@@ -43,8 +43,8 @@ See also: https://www.monetdb.org/Docume
 
 JDBC COMPLIANCE
 The MonetDB JDBC driver is a type 4 driver (100% pure Java) and
-complies to JDBC 4.1 definition, see
- http://docs.oracle.com/javase/7/docs/technotes/guides/jdbc/index.html
+complies to JDBC 4.2 definition, see
+ http://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/index.html
 and
  https://en.wikipedia.org/wiki/Java_Database_Connectivity
 
@@ -60,7 +60,7 @@ If you feel some features are missing or
 please let us know at our bugtracker:
   https://www.monetdb.org/bugzilla/
 
-Currently implemented JDBC 4.1 interfaces include:
+Currently implemented JDBC 4.2 interfaces include:
   * java.sql.Driver
 
   * java.sql.Connection
@@ -138,11 +138,13 @@ Currently implemented JDBC 4.1 interface
 
 The following java.sql.* interfaces are NOT implemented:
   * java.sql.Array
+  * java.sql.DriverAction
   * java.sql.NClob
   * java.sql.Ref
   * java.sql.Rowid
   * java.sql.SQLInput
   * java.sql.SQLOutput
+  * java.sql.SQLType
   * java.sql.SQLXML
   * java.sql.Struct
 
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetCallableStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetCallableStatement.java
@@ -23,6 +23,7 @@ import java.sql.Ref;
 import java.sql.RowId;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLType;	// new as of Java 1.8
 import java.sql.SQLXML;
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -63,7 +64,7 @@ import java.util.Map;
  * because output parameters in stored procedures are not supported by MonetDB.
  *
  * @author Martin van Dinther
- * @version 1.0
+ * @version 1.1
  */
 
 public class MonetCallableStatement
@@ -631,5 +632,44 @@ public class MonetCallableStatement
 		throw newSQLFeatureNotSupportedException("wasNull");
 	}
 
+	//== Java 1.8 methods (JDBC 4.2)
+
+	@Override
+	public void setObject(String parameterName, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException {
+		// setObject(nameToIndex(parameterName), x, convertSQLType(targetSqlType), scaleOrLength);	// TODO implement convertSQLType(targetSqlType)
+		throw newSQLFeatureNotSupportedException("setObject");
+	}
+
+	@Override
+	public void setObject(String parameterName, Object x, SQLType targetSqlType) throws SQLException {
+		// setObject(nameToIndex(parameterName), x, convertSQLType(targetSqlType));	// TODO implement convertSQLType(targetSqlType)
+		throw newSQLFeatureNotSupportedException("setObject");
+	}
+
+	@Override
+	public void registerOutParameter(int parameterIndex, SQLType sqlType) throws SQLException {
+		throw newSQLFeatureNotSupportedException("registerOutParameter");
+	}
+	@Override
+	public void registerOutParameter(int parameterIndex, SQLType sqlType, int scale) throws SQLException {
+		throw newSQLFeatureNotSupportedException("registerOutParameter");
+	}
+	@Override
+	public void registerOutParameter(int parameterIndex, SQLType sqlType, String typeName) throws SQLException {
+		throw newSQLFeatureNotSupportedException("registerOutParameter");
+	}
+	@Override
+	public void registerOutParameter(String parameterName, SQLType sqlType) throws SQLException {
+		throw newSQLFeatureNotSupportedException("registerOutParameter");
+	}
+	@Override
+	public void registerOutParameter(String parameterName, SQLType sqlType, int scale) throws SQLException {
+		throw newSQLFeatureNotSupportedException("registerOutParameter");
+	}
+	@Override
+	public void registerOutParameter(String parameterName, SQLType sqlType, String typeName) throws SQLException {
+		throw newSQLFeatureNotSupportedException("registerOutParameter");
+	}
+
 	// end methods interface CallableStatement
 }
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
@@ -2697,7 +2697,7 @@ public class MonetConnection
 		/** The cache size (number of rows in a DataBlockResponse object) */
 		private final int cachesize;
 		/** The maximum number of results for this query */
-		private final int maxrows;
+		private final long maxrows;
 		/** The ResultSet type to produce */
 		private final int rstype;
 		/** The ResultSet concurrency to produce */
@@ -2726,7 +2726,7 @@ public class MonetConnection
 		 */
 		ResponseList(
 			final int cachesize,
-			final int maxrows,
+			final long maxrows,
 			final int rstype,
 			final int rsconcur
 		) throws SQLException {
@@ -2858,7 +2858,7 @@ public class MonetConnection
 					 */
 					int size = (cachesize == 0 ? DEF_FETCHSIZE : cachesize);
 					if (maxrows > 0 && maxrows < size)
-						size = maxrows;
+						size = (int)maxrows;
 					// don't do work if it's not needed
 					if (lang == LANG_SQL && size != curReplySize && templ != commandTempl) {
 						sendControlCommand("reply_size " + size);
@@ -2887,12 +2887,12 @@ public class MonetConnection
 								case StartOfHeaderParser.Q_TABLE:
 								case StartOfHeaderParser.Q_PREPARE: {
 									final int id = sohp.getNextAsInt();
-									int tuplecount = sohp.getNextAsInt();
+									int tuplecount = sohp.getNextAsInt();	// TODO implement StartOfHeaderParser.getNextAsLong() and change tuplecount to long
 									final int columncount = sohp.getNextAsInt();
 									final int rowcount = sohp.getNextAsInt();
 									// enforce the maxrows setting
 									if (maxrows != 0 && tuplecount > maxrows)
-										tuplecount = maxrows;
+										tuplecount = (int)maxrows;
 									res = new ResultSetResponse(id, tuplecount, columncount, rowcount, this, seqnr);
 									// only add this resultset to the hashmap if it can possibly have an additional datablock
 									if (rowcount < tuplecount) {
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDatabaseMetaData.java
@@ -22,7 +22,7 @@ import java.sql.Types;
  *
  * @author Fabian Groffen
  * @author Martin van Dinther
- * @version 0.9
+ * @version 1.0
  */
 public class MonetDatabaseMetaData
 	extends MonetWrapper
@@ -4023,12 +4023,12 @@ public class MonetDatabaseMetaData
 		return true;
 	}
 
-	//== 1.8 methods (JDBC 4.2)
+	//== Java 1.8 methods (JDBC 4.2)
 
 	/**
 	 * Retrieves the maximum number of bytes this database allows for the logical size for a LOB.
 	 * The default implementation will return 0
-	 * @return the maximum number of bytes
+	 * @return the maximum number of bytes allowed; a result of zero means that there is no limit or the limit is not known
 	 */
 	@Override
 	public long getMaxLogicalLobSize() {
@@ -4038,7 +4038,7 @@ public class MonetDatabaseMetaData
 	/**
 	 * Retrieves whether this database supports REF CURSOR.
 	 * The default implementation will return false
-	 * @return true if so, false otherwise
+	 * @return true if this database supports REF CURSOR; false otherwise
 	 */
 	@Override
 	public boolean supportsRefCursors() {
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
@@ -30,6 +30,7 @@ import java.sql.SQLDataException;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.SQLOutput;
+import java.sql.SQLType;	// new as of Java 1.8
 import java.sql.SQLXML;
 import java.sql.Struct;
 import java.sql.Time;
@@ -61,7 +62,7 @@ import java.util.Map;
  *
  * @author Fabian Groffen
  * @author Martin van Dinther
- * @version 0.5
+ * @version 0.6
  */
 public class MonetPreparedStatement
 	extends MonetStatement
@@ -2613,8 +2614,46 @@ public class MonetPreparedStatement
 		close();
 	}
 
+	//== Java 1.8 methods (JDBC 4.2)
+
+	@Override
+	public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException {
+		// setObject(parameterIndex, x, convertSQLType(targetSqlType), scaleOrLength);	// TODO implement convertSQLType(targetSqlType)
+		throw newSQLFeatureNotSupportedException("setObject");
+	}
+
+	@Override
+	public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType) throws SQLException {
+		// setObject(parameterIndex, x, convertSQLType(targetSqlType));	// TODO implement convertSQLType(targetSqlType)
+		throw newSQLFeatureNotSupportedException("setObject");
+	}
+
+	/**
+	 * Executes the SQL statement in this PreparedStatement object, which must be
+	 * an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or DELETE statement;
+	 * or an SQL statement that returns nothing, such as a DDL statement.
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * The default implementation will throw UnsupportedOperationException
+	 *
+	 * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+	 *         or (2) 0 for SQL statements that return nothing
+	 * @throws SQLException if a database access error occurs; this method is called on a closed PreparedStatement
+	 *		or the SQL statement returns a ResultSet object
+	 */
+	@Override
+	public long executeLargeUpdate() throws SQLException {
+		if (execute() != false)
+			throw new SQLException("Query produced a result set", "M1M17");
+
+		return getLargeUpdateCount();
+	}
+
 	//== end methods interface PreparedStatement
 
+
+	//== internal helper methods which do not belong to the JDBC interface
+
 	/**
 	 * Sets the given index with the supplied value. If the given index is
 	 * out of bounds, and SQLException is thrown.  The given value should
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
@@ -29,6 +29,7 @@ import java.sql.SQLDataException;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.SQLInput;
+import java.sql.SQLType;	// new as of Java 1.8
 import java.sql.SQLWarning;
 import java.sql.SQLXML;
 import java.sql.Statement;
@@ -58,8 +59,9 @@ import java.util.TimeZone;
  * for FORWARD_ONLY result sets the memory usage will be likely lower for large
  * result sets.
  *
- * @author Fabian Groffen, Martin van Dinther
- * @version 0.8
+ * @author Fabian Groffen
+ * @author Martin van Dinther
+ * @version 0.9
  */
 public class MonetResultSet
 	extends MonetWrapper
@@ -2213,63 +2215,6 @@ public class MonetResultSet
 	}
 
 	/**
-	 * 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
-	 * supported.  If the conversion is not supported or null is
-	 * specified for the type, a SQLException is thrown.
-	 *
-	 * At a minimum, an implementation must support the conversions defined
-	 * in Appendix B, Table B-3 and conversion of appropriate user defined
-	 * SQL types to a Java type which implements SQLData, or Struct.
-	 * Additional conversions may be supported and are vendor defined.
-	 *
-	 * @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 SQLFeatureNotSupportedException the JDBC driver does
-	 *         not support this method
-	 */
-	@Override
-	public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException {
-		checkNotClosed();
-		if (type == null)
-			throw new SQLException("type is null", "M1M05");
-
-		throw newSQLFeatureNotSupportedException("getObject(column, Class<T> type)");
-	}
-
-	/**
-	 * 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
-	 * 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
-	 * @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 SQLFeatureNotSupportedException the JDBC driver does
-	 *         not support this method
-	 */
-	@Override
-	public <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException {
-		return getObject(findColumn(columnLabel), type);
-	}
-
-	/**
 	 * Helper method to support the getObject and
 	 * ResultsetMetaData.getColumnClassName JDBC methods.
 	 *
@@ -3785,8 +3730,92 @@ public class MonetResultSet
 		return lastReadWasNull;
 	}
 
+	//== Java 1.7 methods (JDBC 4.1)
+
+	/**
+	 * 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
+	 * supported.  If the conversion is not supported or null is
+	 * specified for the type, a SQLException is thrown.
+	 *
+	 * At a minimum, an implementation must support the conversions defined
+	 * in Appendix B, Table B-3 and conversion of appropriate user defined
+	 * SQL types to a Java type which implements SQLData, or Struct.
+	 * Additional conversions may be supported and are vendor defined.
+	 *
+	 * @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 SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support this method
+	 */
+	@Override
+	public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException {
+		checkNotClosed();
+		if (type == null)
+			throw new SQLException("type is null", "M1M05");
+
+		throw newSQLFeatureNotSupportedException("getObject(column, Class<T> type)");
+	}
+
+	/**
+	 * 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
+	 * 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
+	 * @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 SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support this method
+	 */
+	@Override
+	public <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException {
+		return getObject(findColumn(columnLabel), type);
+	}
+
+	//== Java 1.8 methods (JDBC 4.2)
+
+	@Override
+	public void updateObject(int columnIndex, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException {
+		throw newSQLFeatureNotSupportedException("updateObject");
+	}
+
+	@Override
+	public void updateObject(String columnLabel, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException {
+		throw newSQLFeatureNotSupportedException("updateObject");
+	}
+
+	@Override
+	public void updateObject(int columnIndex, Object x, SQLType targetSqlType) throws SQLException {
+		throw newSQLFeatureNotSupportedException("updateObject");
+	}
+
+	@Override
+	public void updateObject(String columnLabel, Object x, SQLType targetSqlType) throws SQLException {
+		throw newSQLFeatureNotSupportedException("updateObject");
+	}
+
 	//== end methods of interface ResultSet
 
+
+	//== internal helper methods which do not belong to the JDBC interface
+
 	/**
 	 * Adds a warning to the pile of warnings this ResultSet object has. If
 	 * there were no warnings (or clearWarnings was called) this warning will
@@ -3837,4 +3866,3 @@ public class MonetResultSet
 		return new SQLDataException("Could not convert value to a number. " + error.getMessage(), "22003");
 	}
 }
-
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
@@ -41,15 +41,12 @@ import java.util.concurrent.locks.Reentr
  *
  * @author Fabian Groffen
  * @author Martin van Dinther
- * @version 0.8
+ * @version 0.9
  */
 public class MonetStatement
 	extends MonetWrapper
 	implements Statement, AutoCloseable
 {
-	/** the default value of maxRows, 0 indicates unlimited */
-	static final int DEF_MAXROWS = 0;
-
 	/** The parental Connection object */
 	protected final MonetConnection connection;
 	/** The last ResponseList object this Statement produced */
@@ -68,8 +65,8 @@ public class MonetStatement
 	private int queryTimeout = 0;
 	/** The size of the blocks of results to ask for at the server */
 	private int fetchSize = 0;
-	/** The maximum number of rows to return in a ResultSet */
-	private int maxRows = DEF_MAXROWS;
+	/** The maximum number of rows to return in a ResultSet, 0 indicates unlimited */
+	private long maxRows = 0;
 	/** The type of ResultSet to produce; i.e. forward only, random access */
 	private int resultSetType = MonetResultSet.DEF_RESULTSETTYPE;
 	/** The suggested direction of fetching data (implemented but not used) */
@@ -797,7 +794,9 @@ public class MonetStatement
 	 */
 	@Override
 	public int getMaxRows() {
-		return maxRows;
+		if (maxRows >= Integer.MAX_VALUE)
+			return Integer.MAX_VALUE;
+		return (int)maxRows;
 	}
 
 	/**
@@ -1203,8 +1202,270 @@ public class MonetStatement
 		return closeOnCompletion;
 	}
 
+	//== Java 1.8 methods (JDBC 4.2)
+
+	/**
+	 * Retrieves the current result as an update count;
+	 * if the result is a ResultSet object or there are no more results, -1 is returned.
+	 * This method should be called only once per result.
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * The default implementation will throw UnsupportedOperationException
+	 *
+	 * @return the current result as an update count; -1 if the current
+	 *	result is a ResultSet object or there are no more results
+	 * @throws SQLException if a database access error occurs or this
+	 *	method is called on a closed Statement
+	 */
+	public long getLargeUpdateCount() throws SQLException {
+		return getUpdateCount();
+	}
+
+	/**
+	 * Sets the limit for the maximum number of rows that any ResultSet object
+	 * generated by this Statement object can contain to the given number.
+	 * If the limit is exceeded, the excess rows are silently dropped.
+	 *
+	 * This method should be used when the row limit may exceed Integer.MAX_VALUE.
+	 * The default implementation will throw UnsupportedOperationException
+	 *
+	 * @param max the new max rows limit; zero means there is no limit
+	 * @throws SQLException if a database access error occurs,
+	 *	this method is called on a closed Statement or
+	 *	the condition max &gt;= 0 is not satisfied
+	 * @see #getLargeMaxRows()
+	 */
+	@Override
+	public void setLargeMaxRows(final long max) throws SQLException {
+		if (max < 0)
+			throw new SQLException("Illegal max value: " + max, "M1M05");
+		maxRows = max;
+	}
+
+	/**
+	 * Retrieves the maximum number of rows that a ResultSet object produced by
+	 * this Statement object can contain. If this limit is exceeded, the excess
+	 * rows are silently dropped.
+	 *
+	 * This method should be used when the returned row limit may exceed Integer.MAX_VALUE.
+	 * The default implementation will return 0
+	 *
+	 * @return the current maximum number of rows for a ResultSet object
+	 *	produced by this Statement object; zero means there is no limit
+	 * @see #setLargeMaxRows(long max)
+	 */
+	@Override
+	public long getLargeMaxRows() {
+		return maxRows;
+	}
+
+	/**
+	 * Submits a batch of commands to the database for execution and if
+	 * all commands execute successfully, returns an array of update counts.
+	 * The long elements of the array that is returned are ordered to
+	 * correspond to the commands in the batch, which are ordered according
+	 * to the order in which they were added to the batch.
+	 * The elements in the array returned by the method executeLargeBatch
+	 * may be one of the following:
+	 * <ol>
+	 * <li>A number greater than or equal to zero -- indicates that the command
+	 * was processed successfully and is an update count giving the number of
+	 * rows in the database that were affected by the command's execution</li>
+	 * <li>A value of SUCCESS_NO_INFO -- indicates that the command was
+	 * processed successfully but that the number of rows affected is unknown</li>
+	 * If one of the commands in a batch update fails to execute properly,
+	 * this method throws a BatchUpdateException, and a JDBC driver may or
+	 * may not continue to process the remaining commands in the batch.
+	 * However, the driver's behavior must be consistent with a particular DBMS,
+	 * either always continuing to process commands or never continuing to process
+	 * commands. If the driver continues processing after a failure, the array
+	 * returned by the method BatchUpdateException.getLargeUpdateCounts will
+	 * contain as many elements as there are commands in the batch, and at
+	 * least one of the elements will be the following:
+	 * <li>A value of EXECUTE_FAILED -- indicates that the command failed to
+	 * execute successfully and occurs only if a driver continues to process
+	 * commands after a command fails</li>
+	 * </ol>
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * The default implementation will throw UnsupportedOperationException
+	 *
+	 * MonetDB does continues after an error has occurred in the batch.
+	 * If one of the commands attempts to return a result set, an
+	 * SQLException is added to the SQLException list and thrown
+	 * afterwards execution.  Failing queries result in SQLExceptions
+	 * too and may cause subparts of the batch to fail as well.
+	 *
+	 * @return an array of update counts containing one element for each
+	 *	command in the batch. The elements of the array are ordered
+	 *	according to the order in which commands were added to the batch.
+	 * @throws SQLException if a database access error occurs, this method is called
+	 *	on a closed Statement or the driver does not support batch statements.
+	 *	Throws BatchUpdateException (a subclass of SQLException) if one of the
+	 *	commands sent to the database fails to execute properly or attempts to return a result set.
+	 */
+	@Override
+	public long[] executeLargeBatch() throws SQLException {
+		if (batch == null || batch.isEmpty()) {
+			return new long[0];
+		}
+
+		final int[] ret = executeBatch();
+		// copy contents of int[] into new long[]
+		final long[] counts = new long[ret.length];
+		for (int i = 0; i < ret.length; i++) {
+			counts[i] = ret[i];
+		}
+		return counts;
+	}
+
+	/**
+	 * Executes the given SQL statement, which may be an INSERT, UPDATE, or
+	 * DELETE statement or an SQL statement that returns nothing, such as an
+	 * SQL DDL statement.
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * Note: This method cannot be called on a PreparedStatement or CallableStatement.
+	 * The default implementation will throw SQLFeatureNotSupportedException
+	 *
+	 * @param sql an SQL Data Manipulation Language (DML) statement, such as
+	 *	INSERT, UPDATE or DELETE; or an SQL statement that returns nothing,
+	 *	such as a DDL statement.
+	 * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+	 *	or (2) 0 for SQL statements that return nothing
+	 * @throws SQLException if a database access error occurs, this method is
+	 *	called on a closed Statement, the given SQL statement produces a
+	 *	ResultSet object, the method is called on a PreparedStatement or CallableStatement
+	 */
+	@Override
+	public long executeLargeUpdate(final String sql) throws SQLException {
+		if (execute(sql) != false)
+			throw new SQLException("Query produced a result set", "M1M17");
+
+		return getLargeUpdateCount();
+	}
+
+	/**
+	 * Executes the given SQL statement and signals the driver with the
+	 * given flag about whether the auto-generated keys produced by this
+	 * Statement object should be made available for retrieval.
+	 * The driver will ignore the flag if the SQL statement is not an INSERT
+	 * statement, or an SQL statement able to return auto-generated keys
+	 * (the list of such statements is vendor-specific).
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * Note: This method cannot be called on a PreparedStatement or CallableStatement.
+	 * The default implementation will throw SQLFeatureNotSupportedException
+	 *
+	 * @param sql an SQL Data Manipulation Language (DML) statement, such as
+	 *	INSERT, UPDATE or DELETE; or an SQL statement that returns nothing,
+	 *	such as a DDL statement.
+	 * @param autoGeneratedKeys - a flag indicating whether
+	 *        auto-generated keys should be made available for
+	 *        retrieval; one of the following constants:
+	 *        Statement.RETURN_GENERATED_KEYS
+	 *        Statement.NO_GENERATED_KEYS
+	 * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+	 *	or (2) 0 for SQL statements that return nothing
+	 * @throws SQLException if a database access error occurs, this method is
+	 *	called on a closed Statement, the given SQL statement produces a
+	 *	ResultSet object, the given constant is not one of those allowed,
+	 *	the method is called on a PreparedStatement or CallableStatement
+	 */
+	@Override
+	public long executeLargeUpdate(final String sql, final int autoGeneratedKeys)
+		throws SQLException
+	{
+		if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS &&
+		    autoGeneratedKeys != Statement.NO_GENERATED_KEYS)
+			throw new SQLException("Invalid argument, expected RETURN_GENERATED_KEYS or NO_GENERATED_KEYS", "M1M05");
+
+		/* MonetDB has no way to disable this, so just do the normal thing ;) */
+		if (execute(sql) != false)
+			throw new SQLException("Query produced a result set", "M1M17");
+
+		return getLargeUpdateCount();
+	}
+
+	/**
+	 * Executes the given SQL statement and signals the driver that the
+	 * auto-generated keys indicated in the given array should be made
+	 * available for retrieval. The driver will ignore the array if the
+	 * SQL statement is not an INSERT statement.
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * Note: This method cannot be called on a PreparedStatement or CallableStatement.
+	 * The default implementation will throw SQLFeatureNotSupportedException
+	 *
+	 * MonetDB only supports returing the generated key for one column,
+	 * which will be the first column that has a serial.  Hence, this
+	 * method cannot work as required and the driver will fall back to
+	 * executing with request to the database to return the generated
+	 * key, if any.
+	 *
+	 * @param sql an SQL Data Manipulation Language (DML) statement, such as
+	 *	INSERT, UPDATE or DELETE; or an SQL statement that returns nothing,
+	 *	such as a DDL statement.
+	 * @param columnIndexes an array of column indexes indicating the
+	 *        columns that should be returned from the inserted row
+	 * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+	 *	or (2) 0 for SQL statements that return nothing
+	 * @throws SQLException if a database access error occurs, this method is
+	 *	called on a closed Statement, the given SQL statement produces a
+	 *	ResultSet object, the second argument supplied to this method is
+	 *	not an int array whose elements are valid column indexes,
+	 *	the method is called on a PreparedStatement or CallableStatement
+	 */
+	@Override
+	public long executeLargeUpdate(final String sql, final int[] columnIndexes)
+		throws SQLException
+	{
+		addWarning("executeLargeUpdate: generated keys for fixed set of columns not supported", "01M18");
+		return executeLargeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
+	}
+
+	/**
+	 * Executes the given SQL statement and signals the driver that the
+	 * auto-generated keys indicated in the given array should be made
+	 * available for retrieval. The driver will ignore the array if the
+	 * SQL statement is not an INSERT statement.
+	 *
+	 * This method should be used when the returned row count may exceed Integer.MAX_VALUE.
+	 * Note: This method cannot be called on a PreparedStatement or CallableStatement.
+	 * The default implementation will throw SQLFeatureNotSupportedException
+	 *
+	 * MonetDB only supports returing the generated key for one column,
+	 * which will be the first column that has a serial.  Hence, this
+	 * method cannot work as required and the driver will fall back to
+	 * executing with request to the database to return the generated
+	 * key, if any.
+	 *
+	 * @param sql an SQL Data Manipulation Language (DML) statement, such as
+	 *	INSERT, UPDATE or DELETE; or an SQL statement that returns nothing,
+	 *	such as a DDL statement.
+	 * @param columnNames an array of the names of the columns that
+	 *        should be returned from the inserted row
+	 * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+	 *	or (2) 0 for SQL statements that return nothing
+	 * @throws SQLException if a database access error occurs, this method is
+	 *	called on a closed Statement, the given SQL statement produces a
+	 *	ResultSet object, the second argument supplied to this method is
+	 *	not a String array whose elements are valid column names,
+	 *	the method is called on a PreparedStatement or CallableStatement
+	 */
+	@Override
+	public long executeLargeUpdate(final String sql, final String[] columnNames)
+		throws SQLException
+	{
+		addWarning("executeLargeUpdate: generated keys for fixed set of columns not supported", "01M18");
+		return executeLargeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
+	}
+
 	//== end methods of interface Statement
 
+
+	//== internal helper methods which do not belong to the JDBC interface
+
 	/**
 	 * Adds a warning to the pile of warnings this Statement object has. If
 	 * there were no warnings (or clearWarnings was called) this warning will