diff src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java @ 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 253363a2ae28
children 8a813f5cef1b
line wrap: on
line diff
--- 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