/*
* Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface;
import org.h2.engine.SessionInterface;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
import org.h2.result.ResultWithGeneratedKeys;
import org.h2.result.SimpleResult;
import org.h2.util.ParserUtil;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
Represents a statement.
/**
* Represents a statement.
*/
public class JdbcStatement extends TraceObject implements Statement, JdbcStatementBackwardsCompat {
protected JdbcConnection conn;
protected SessionInterface session;
protected JdbcResultSet resultSet;
protected int maxRows;
protected int fetchSize = SysProperties.SERVER_RESULT_SET_FETCH_SIZE;
protected int updateCount;
protected JdbcResultSet generatedKeys;
protected final int resultSetType;
protected final int resultSetConcurrency;
protected final boolean closedByResultSet;
private volatile CommandInterface executingCommand;
private int lastExecutedCommandType;
private ArrayList<String> batchCommands;
private boolean escapeProcessing = true;
private volatile boolean cancelled;
JdbcStatement(JdbcConnection conn, int id, int resultSetType,
int resultSetConcurrency, boolean closeWithResultSet) {
this.conn = conn;
this.session = conn.getSession();
setTrace(session.getTrace(), TraceObject.STATEMENT, id);
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.closedByResultSet = closeWithResultSet;
}
Executes a query (select statement) and returns the result set.
If another result set exists for this statement, this will be closed
(even if this statement fails).
Params: - sql – the SQL statement to execute
Returns: the result set
/**
* Executes a query (select statement) and returns the result set.
* If another result set exists for this statement, this will be closed
* (even if this statement fails).
*
* @param sql the SQL statement to execute
* @return the result set
*/
@Override
public ResultSet executeQuery(String sql) throws SQLException {
try {
int id = getNextId(TraceObject.RESULT_SET);
if (isDebugEnabled()) {
debugCodeAssign("ResultSet", TraceObject.RESULT_SET, id,
"executeQuery(" + quote(sql) + ")");
}
synchronized (session) {
checkClosed();
closeOldResultSet();
sql = JdbcConnection.translateSQL(sql, escapeProcessing);
CommandInterface command = conn.prepareCommand(sql, fetchSize);
ResultInterface result;
boolean lazy = false;
boolean scrollable = resultSetType != ResultSet.TYPE_FORWARD_ONLY;
boolean updatable = resultSetConcurrency == ResultSet.CONCUR_UPDATABLE;
setExecutingStatement(command);
try {
result = command.executeQuery(maxRows, scrollable);
lazy = result.isLazy();
} finally {
if (!lazy) {
setExecutingStatement(null);
}
}
if (!lazy) {
command.close();
}
resultSet = new JdbcResultSet(conn, this, command, result, id,
closedByResultSet, scrollable, updatable);
}
return resultSet;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement (insert, update, delete, create, drop)
and returns the update count.
If another result set exists for this statement, this will be closed
(even if this statement fails).
If auto commit is on, this statement will be committed.
If the statement is a DDL statement (create, drop, alter) and does not
throw an exception, the current transaction (if any) is committed after
executing the statement.
Params: - sql – the SQL statement
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement (insert, update, delete, create, drop)
* and returns the update count.
* If another result set exists for this statement, this will be closed
* (even if this statement fails).
*
* If auto commit is on, this statement will be committed.
* If the statement is a DDL statement (create, drop, alter) and does not
* throw an exception, the current transaction (if any) is committed after
* executing the statement.
*
* @param sql the SQL statement
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public int executeUpdate(String sql) throws SQLException {
try {
debugCodeCall("executeUpdate", sql);
return executeUpdateInternal(sql, false);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement (insert, update, delete, create, drop)
and returns the update count.
If another result set exists for this statement, this will be closed
(even if this statement fails).
If auto commit is on, this statement will be committed.
If the statement is a DDL statement (create, drop, alter) and does not
throw an exception, the current transaction (if any) is committed after
executing the statement.
Params: - sql – the SQL statement
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement (insert, update, delete, create, drop)
* and returns the update count.
* If another result set exists for this statement, this will be closed
* (even if this statement fails).
*
* If auto commit is on, this statement will be committed.
* If the statement is a DDL statement (create, drop, alter) and does not
* throw an exception, the current transaction (if any) is committed after
* executing the statement.
*
* @param sql the SQL statement
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public long executeLargeUpdate(String sql) throws SQLException {
try {
debugCodeCall("executeLargeUpdate", sql);
return executeUpdateInternal(sql, false);
} catch (Exception e) {
throw logAndConvert(e);
}
}
private int executeUpdateInternal(String sql, Object generatedKeysRequest) throws SQLException {
checkClosedForWrite();
try {
closeOldResultSet();
sql = JdbcConnection.translateSQL(sql, escapeProcessing);
CommandInterface command = conn.prepareCommand(sql, fetchSize);
synchronized (session) {
setExecutingStatement(command);
try {
ResultWithGeneratedKeys result = command.executeUpdate(
conn.scopeGeneratedKeys() ? false : generatedKeysRequest);
updateCount = result.getUpdateCount();
ResultInterface gk = result.getGeneratedKeys();
if (gk != null) {
int id = getNextId(TraceObject.RESULT_SET);
generatedKeys = new JdbcResultSet(conn, this, command, gk, id,
false, true, false);
}
} finally {
setExecutingStatement(null);
}
}
command.close();
return updateCount;
} finally {
afterWriting();
}
}
Executes an arbitrary statement. If another result set exists for this
statement, this will be closed (even if this statement fails).
If the statement is a create or drop and does not throw an exception, the
current transaction (if any) is committed after executing the statement.
If auto commit is on, and the statement is not a select, this statement
will be committed.
Params: - sql – the SQL statement to execute
Returns: true if a result set is available, false if not
/**
* Executes an arbitrary statement. If another result set exists for this
* statement, this will be closed (even if this statement fails).
*
* If the statement is a create or drop and does not throw an exception, the
* current transaction (if any) is committed after executing the statement.
* If auto commit is on, and the statement is not a select, this statement
* will be committed.
*
* @param sql the SQL statement to execute
* @return true if a result set is available, false if not
*/
@Override
public boolean execute(String sql) throws SQLException {
try {
debugCodeCall("execute", sql);
return executeInternal(sql, false);
} catch (Exception e) {
throw logAndConvert(e);
}
}
private boolean executeInternal(String sql, Object generatedKeysRequest) throws SQLException {
int id = getNextId(TraceObject.RESULT_SET);
checkClosedForWrite();
try {
closeOldResultSet();
sql = JdbcConnection.translateSQL(sql, escapeProcessing);
CommandInterface command = conn.prepareCommand(sql, fetchSize);
boolean lazy = false;
boolean returnsResultSet;
synchronized (session) {
setExecutingStatement(command);
try {
if (command.isQuery()) {
returnsResultSet = true;
boolean scrollable = resultSetType != ResultSet.TYPE_FORWARD_ONLY;
boolean updatable = resultSetConcurrency == ResultSet.CONCUR_UPDATABLE;
ResultInterface result = command.executeQuery(maxRows, scrollable);
lazy = result.isLazy();
resultSet = new JdbcResultSet(conn, this, command, result, id,
closedByResultSet, scrollable, updatable);
} else {
returnsResultSet = false;
ResultWithGeneratedKeys result = command.executeUpdate(
conn.scopeGeneratedKeys() ? false : generatedKeysRequest);
updateCount = result.getUpdateCount();
ResultInterface gk = result.getGeneratedKeys();
if (gk != null) {
generatedKeys = new JdbcResultSet(conn, this, command, gk, id,
false, true, false);
}
}
} finally {
if (!lazy) {
setExecutingStatement(null);
}
}
}
if (!lazy) {
command.close();
}
return returnsResultSet;
} finally {
afterWriting();
}
}
Returns the last result set produces by this statement.
Returns: the result set
/**
* Returns the last result set produces by this statement.
*
* @return the result set
*/
@Override
public ResultSet getResultSet() throws SQLException {
try {
checkClosed();
if (resultSet != null) {
int id = resultSet.getTraceId();
debugCodeAssign("ResultSet", TraceObject.RESULT_SET, id, "getResultSet()");
} else {
debugCodeCall("getResultSet");
}
return resultSet;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Returns the last update count of this statement.
Throws: - SQLException – if this object is closed or invalid
Returns: the update count (number of row affected by an insert, update or
delete, or 0 if no rows or the statement was a create, drop,
commit or rollback; -1 if the statement was a select).
/**
* Returns the last update count of this statement.
*
* @return the update count (number of row affected by an insert, update or
* delete, or 0 if no rows or the statement was a create, drop,
* commit or rollback; -1 if the statement was a select).
* @throws SQLException if this object is closed or invalid
*/
@Override
public int getUpdateCount() throws SQLException {
try {
debugCodeCall("getUpdateCount");
checkClosed();
return updateCount;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Returns the last update count of this statement.
Throws: - SQLException – if this object is closed or invalid
Returns: the update count (number of row affected by an insert, update or
delete, or 0 if no rows or the statement was a create, drop,
commit or rollback; -1 if the statement was a select).
/**
* Returns the last update count of this statement.
*
* @return the update count (number of row affected by an insert, update or
* delete, or 0 if no rows or the statement was a create, drop,
* commit or rollback; -1 if the statement was a select).
* @throws SQLException if this object is closed or invalid
*/
@Override
public long getLargeUpdateCount() throws SQLException {
try {
debugCodeCall("getLargeUpdateCount");
checkClosed();
return updateCount;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Closes this statement.
All result sets that where created by this statement
become invalid after calling this method.
/**
* Closes this statement.
* All result sets that where created by this statement
* become invalid after calling this method.
*/
@Override
public void close() throws SQLException {
try {
debugCodeCall("close");
synchronized (session) {
closeOldResultSet();
if (conn != null) {
conn = null;
}
}
} catch (Exception e) {
throw logAndConvert(e);
}
}
Returns the connection that created this object.
Returns: the connection
/**
* Returns the connection that created this object.
*
* @return the connection
*/
@Override
public Connection getConnection() {
debugCodeCall("getConnection");
return conn;
}
Gets the first warning reported by calls on this object.
This driver does not support warnings, and will always return null.
Returns: null
/**
* Gets the first warning reported by calls on this object.
* This driver does not support warnings, and will always return null.
*
* @return null
*/
@Override
public SQLWarning getWarnings() throws SQLException {
try {
debugCodeCall("getWarnings");
checkClosed();
return null;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Clears all warnings. As this driver does not support warnings,
this call is ignored.
/**
* Clears all warnings. As this driver does not support warnings,
* this call is ignored.
*/
@Override
public void clearWarnings() throws SQLException {
try {
debugCodeCall("clearWarnings");
checkClosed();
} catch (Exception e) {
throw logAndConvert(e);
}
}
Sets the name of the cursor. This call is ignored.
Params: - name – ignored
Throws: - SQLException – if this object is closed
/**
* Sets the name of the cursor. This call is ignored.
*
* @param name ignored
* @throws SQLException if this object is closed
*/
@Override
public void setCursorName(String name) throws SQLException {
try {
debugCodeCall("setCursorName", name);
checkClosed();
} catch (Exception e) {
throw logAndConvert(e);
}
}
Sets the fetch direction.
This call is ignored by this driver.
Params: - direction – ignored
Throws: - SQLException – if this object is closed
/**
* Sets the fetch direction.
* This call is ignored by this driver.
*
* @param direction ignored
* @throws SQLException if this object is closed
*/
@Override
public void setFetchDirection(int direction) throws SQLException {
try {
debugCodeCall("setFetchDirection", direction);
checkClosed();
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the fetch direction.
Throws: - SQLException – if this object is closed
Returns: FETCH_FORWARD
/**
* Gets the fetch direction.
*
* @return FETCH_FORWARD
* @throws SQLException if this object is closed
*/
@Override
public int getFetchDirection() throws SQLException {
try {
debugCodeCall("getFetchDirection");
checkClosed();
return ResultSet.FETCH_FORWARD;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the maximum number of rows for a ResultSet.
Throws: - SQLException – if this object is closed
Returns: the number of rows where 0 means no limit
/**
* Gets the maximum number of rows for a ResultSet.
*
* @return the number of rows where 0 means no limit
* @throws SQLException if this object is closed
*/
@Override
public int getMaxRows() throws SQLException {
try {
debugCodeCall("getMaxRows");
checkClosed();
return maxRows;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the maximum number of rows for a ResultSet.
Throws: - SQLException – if this object is closed
Returns: the number of rows where 0 means no limit
/**
* Gets the maximum number of rows for a ResultSet.
*
* @return the number of rows where 0 means no limit
* @throws SQLException if this object is closed
*/
@Override
public long getLargeMaxRows() throws SQLException {
try {
debugCodeCall("getLargeMaxRows");
checkClosed();
return maxRows;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the maximum number of rows for a ResultSet.
Params: - maxRows – the number of rows where 0 means no limit
Throws: - SQLException – if this object is closed
/**
* Gets the maximum number of rows for a ResultSet.
*
* @param maxRows the number of rows where 0 means no limit
* @throws SQLException if this object is closed
*/
@Override
public void setMaxRows(int maxRows) throws SQLException {
try {
debugCodeCall("setMaxRows", maxRows);
checkClosed();
if (maxRows < 0) {
throw DbException.getInvalidValueException("maxRows", maxRows);
}
this.maxRows = maxRows;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the maximum number of rows for a ResultSet.
Params: - maxRows – the number of rows where 0 means no limit
Throws: - SQLException – if this object is closed
/**
* Gets the maximum number of rows for a ResultSet.
*
* @param maxRows the number of rows where 0 means no limit
* @throws SQLException if this object is closed
*/
@Override
public void setLargeMaxRows(long maxRows) throws SQLException {
try {
debugCodeCall("setLargeMaxRows", maxRows);
checkClosed();
if (maxRows < 0) {
throw DbException.getInvalidValueException("maxRows", maxRows);
}
this.maxRows = maxRows <= Integer.MAX_VALUE ? (int) maxRows : 0;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Sets the number of rows suggested to read in one step.
This value cannot be higher than the maximum rows (setMaxRows)
set by the statement or prepared statement, otherwise an exception
is throws. Setting the value to 0 will set the default value.
The default value can be changed using the system property
h2.serverResultSetFetchSize.
Params: - rows – the number of rows
Throws: - SQLException – if this object is closed
/**
* Sets the number of rows suggested to read in one step.
* This value cannot be higher than the maximum rows (setMaxRows)
* set by the statement or prepared statement, otherwise an exception
* is throws. Setting the value to 0 will set the default value.
* The default value can be changed using the system property
* h2.serverResultSetFetchSize.
*
* @param rows the number of rows
* @throws SQLException if this object is closed
*/
@Override
public void setFetchSize(int rows) throws SQLException {
try {
debugCodeCall("setFetchSize", rows);
checkClosed();
if (rows < 0 || (rows > 0 && maxRows > 0 && rows > maxRows)) {
throw DbException.getInvalidValueException("rows", rows);
}
if (rows == 0) {
rows = SysProperties.SERVER_RESULT_SET_FETCH_SIZE;
}
fetchSize = rows;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the number of rows suggested to read in one step.
Throws: - SQLException – if this object is closed
Returns: the current fetch size
/**
* Gets the number of rows suggested to read in one step.
*
* @return the current fetch size
* @throws SQLException if this object is closed
*/
@Override
public int getFetchSize() throws SQLException {
try {
debugCodeCall("getFetchSize");
checkClosed();
return fetchSize;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the result set concurrency created by this object.
Returns: the concurrency
/**
* Gets the result set concurrency created by this object.
*
* @return the concurrency
*/
@Override
public int getResultSetConcurrency() throws SQLException {
try {
debugCodeCall("getResultSetConcurrency");
checkClosed();
return resultSetConcurrency;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the result set type.
Throws: - SQLException – if this object is closed
Returns: the type
/**
* Gets the result set type.
*
* @return the type
* @throws SQLException if this object is closed
*/
@Override
public int getResultSetType() throws SQLException {
try {
debugCodeCall("getResultSetType");
checkClosed();
return resultSetType;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the maximum number of bytes for a result set column.
Throws: - SQLException – if this object is closed
Returns: always 0 for no limit
/**
* Gets the maximum number of bytes for a result set column.
*
* @return always 0 for no limit
* @throws SQLException if this object is closed
*/
@Override
public int getMaxFieldSize() throws SQLException {
try {
debugCodeCall("getMaxFieldSize");
checkClosed();
return 0;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Sets the maximum number of bytes for a result set column.
This method does currently do nothing for this driver.
Params: - max – the maximum size - ignored
Throws: - SQLException – if this object is closed
/**
* Sets the maximum number of bytes for a result set column.
* This method does currently do nothing for this driver.
*
* @param max the maximum size - ignored
* @throws SQLException if this object is closed
*/
@Override
public void setMaxFieldSize(int max) throws SQLException {
try {
debugCodeCall("setMaxFieldSize", max);
checkClosed();
} catch (Exception e) {
throw logAndConvert(e);
}
}
Enables or disables processing or JDBC escape syntax.
See also Connection.nativeSQL.
Params: - enable – - true (default) or false (no conversion is attempted)
Throws: - SQLException – if this object is closed
/**
* Enables or disables processing or JDBC escape syntax.
* See also Connection.nativeSQL.
*
* @param enable - true (default) or false (no conversion is attempted)
* @throws SQLException if this object is closed
*/
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("setEscapeProcessing("+enable+");");
}
checkClosed();
escapeProcessing = enable;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Cancels a currently running statement.
This method must be called from within another
thread than the execute method.
Operations on large objects are not interrupted,
only operations that process many rows.
Throws: - SQLException – if this object is closed
/**
* Cancels a currently running statement.
* This method must be called from within another
* thread than the execute method.
* Operations on large objects are not interrupted,
* only operations that process many rows.
*
* @throws SQLException if this object is closed
*/
@Override
public void cancel() throws SQLException {
try {
debugCodeCall("cancel");
checkClosed();
// executingCommand can be reset by another thread
CommandInterface c = executingCommand;
try {
if (c != null) {
c.cancel();
cancelled = true;
}
} finally {
setExecutingStatement(null);
}
} catch (Exception e) {
throw logAndConvert(e);
}
}
Check whether the statement was cancelled.
Returns: true if yes
/**
* Check whether the statement was cancelled.
*
* @return true if yes
*/
public boolean isCancelled() {
return cancelled;
}
Gets the current query timeout in seconds.
This method will return 0 if no query timeout is set.
The result is rounded to the next second.
For performance reasons, only the first call to this method
will query the database. If the query timeout was changed in another
way than calling setQueryTimeout, this method will always return
the last value.
Throws: - SQLException – if this object is closed
Returns: the timeout in seconds
/**
* Gets the current query timeout in seconds.
* This method will return 0 if no query timeout is set.
* The result is rounded to the next second.
* For performance reasons, only the first call to this method
* will query the database. If the query timeout was changed in another
* way than calling setQueryTimeout, this method will always return
* the last value.
*
* @return the timeout in seconds
* @throws SQLException if this object is closed
*/
@Override
public int getQueryTimeout() throws SQLException {
try {
debugCodeCall("getQueryTimeout");
checkClosed();
return conn.getQueryTimeout();
} catch (Exception e) {
throw logAndConvert(e);
}
}
Sets the current query timeout in seconds.
Changing the value will affect all statements of this connection.
This method does not commit a transaction,
and rolling back a transaction does not affect this setting.
Params: - seconds – the timeout in seconds - 0 means no timeout, values
smaller 0 will throw an exception
Throws: - SQLException – if this object is closed
/**
* Sets the current query timeout in seconds.
* Changing the value will affect all statements of this connection.
* This method does not commit a transaction,
* and rolling back a transaction does not affect this setting.
*
* @param seconds the timeout in seconds - 0 means no timeout, values
* smaller 0 will throw an exception
* @throws SQLException if this object is closed
*/
@Override
public void setQueryTimeout(int seconds) throws SQLException {
try {
debugCodeCall("setQueryTimeout", seconds);
checkClosed();
if (seconds < 0) {
throw DbException.getInvalidValueException("seconds", seconds);
}
conn.setQueryTimeout(seconds);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Adds a statement to the batch.
Params: - sql – the SQL statement
/**
* Adds a statement to the batch.
*
* @param sql the SQL statement
*/
@Override
public void addBatch(String sql) throws SQLException {
try {
debugCodeCall("addBatch", sql);
checkClosed();
sql = JdbcConnection.translateSQL(sql, escapeProcessing);
if (batchCommands == null) {
batchCommands = Utils.newSmallArrayList();
}
batchCommands.add(sql);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Clears the batch.
/**
* Clears the batch.
*/
@Override
public void clearBatch() throws SQLException {
try {
debugCodeCall("clearBatch");
checkClosed();
batchCommands = null;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes the batch.
If one of the batched statements fails, this database will continue.
Returns: the array of update counts
/**
* Executes the batch.
* If one of the batched statements fails, this database will continue.
*
* @return the array of update counts
*/
@Override
public int[] executeBatch() throws SQLException {
try {
debugCodeCall("executeBatch");
checkClosedForWrite();
try {
if (batchCommands == null) {
// TODO batch: check what other database do if no commands
// are set
batchCommands = Utils.newSmallArrayList();
}
int size = batchCommands.size();
int[] result = new int[size];
boolean error = false;
SQLException next = null;
for (int i = 0; i < size; i++) {
String sql = batchCommands.get(i);
try {
result[i] = executeUpdateInternal(sql, false);
} catch (Exception re) {
SQLException e = logAndConvert(re);
if (next == null) {
next = e;
} else {
e.setNextException(next);
next = e;
}
result[i] = Statement.EXECUTE_FAILED;
error = true;
}
}
batchCommands = null;
if (error) {
throw new JdbcBatchUpdateException(next, result);
}
return result;
} finally {
afterWriting();
}
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes the batch.
If one of the batched statements fails, this database will continue.
Returns: the array of update counts
/**
* Executes the batch.
* If one of the batched statements fails, this database will continue.
*
* @return the array of update counts
*/
@Override
public long[] executeLargeBatch() throws SQLException {
int[] intResult = executeBatch();
int count = intResult.length;
long[] longResult = new long[count];
for (int i = 0; i < count; i++) {
longResult[i] = intResult[i];
}
return longResult;
}
Return a result set with generated keys from the latest executed command or an empty result set if keys were not generated or were not requested with Statement.RETURN_GENERATED_KEYS
, column indexes, or column names. Generated keys are only returned from inserted rows from INSERT
, MERGE INTO
, and MERGE INTO ... USING
commands. Generated keys are not returned if exact values of generated columns were specified explicitly in SQL command. All columns with inserted generated values are included in the result if command was executed with Statement.RETURN_GENERATED_KEYS
parameter.
If SQL command inserts multiple rows with generated keys each such inserted row is returned. Batch methods are also supported. When multiple rows are returned each row contains only generated values for this row. It's possible to insert several rows with generated values in different columns with some specific commands, in this special case the returned result set contains all used columns, but each row will contain only generated values, columns that were not generated for this row will contain null
values.
H2 treats inserted value as generated in the following cases:
- Columns with sequences including
IDENTITY
columns and columns with AUTO_INCREMENT
if value was generated automatically (not specified in command).
- Columns with other default values that are not evaluated into constant expressions (like
DEFAULT RANDOM_UUID()
) also only if default value was inserted.
- Columns that were set by triggers.
- Columns with values specified in command with invocation of some sequence (like
INSERT INTO ... VALUES (NEXT VALUE FOR ...)
).
Exact required columns for the returning result set may be specified on
execution of command with names or indexes of columns to limit output or
reorder columns in result set. Specifying of some column has no effect on
treatment of inserted values as generated or not. If some value is not
determined to be generated it will not be returned even on explicit request.
Throws: - SQLException – if this object is closed
Returns: the possibly empty result set with generated keys
/**
* Return a result set with generated keys from the latest executed command or
* an empty result set if keys were not generated or were not requested with
* {@link Statement#RETURN_GENERATED_KEYS}, column indexes, or column names.
* <p>
* Generated keys are only returned from inserted rows from {@code INSERT},
* {@code MERGE INTO}, and {@code MERGE INTO ... USING} commands. Generated keys
* are not returned if exact values of generated columns were specified
* explicitly in SQL command. All columns with inserted generated values are
* included in the result if command was executed with
* {@link Statement#RETURN_GENERATED_KEYS} parameter.
* </p>
* <p>
* If SQL command inserts multiple rows with generated keys each such inserted
* row is returned. Batch methods are also supported. When multiple rows are
* returned each row contains only generated values for this row. It's possible
* to insert several rows with generated values in different columns with some
* specific commands, in this special case the returned result set contains all
* used columns, but each row will contain only generated values, columns that
* were not generated for this row will contain {@code null} values.
* </p>
* <p>
* H2 treats inserted value as generated in the following cases:
* </p>
* <ul>
* <li>Columns with sequences including {@code IDENTITY} columns and columns
* with {@code AUTO_INCREMENT} if value was generated automatically (not
* specified in command).</li>
* <li>Columns with other default values that are not evaluated into constant
* expressions (like {@code DEFAULT RANDOM_UUID()}) also only if default value
* was inserted.</li>
* <li>Columns that were set by triggers.</li>
* <li>Columns with values specified in command with invocation of some sequence
* (like {@code INSERT INTO ... VALUES (NEXT VALUE FOR ...)}).</li>
* </ul>
* <p>
* Exact required columns for the returning result set may be specified on
* execution of command with names or indexes of columns to limit output or
* reorder columns in result set. Specifying of some column has no effect on
* treatment of inserted values as generated or not. If some value is not
* determined to be generated it will not be returned even on explicit request.
* </p>
*
* @return the possibly empty result set with generated keys
* @throws SQLException if this object is closed
*/
@Override
public ResultSet getGeneratedKeys() throws SQLException {
try {
int id = generatedKeys != null ? generatedKeys.getTraceId() : getNextId(TraceObject.RESULT_SET);
if (isDebugEnabled()) {
debugCodeAssign("ResultSet", TraceObject.RESULT_SET, id, "getGeneratedKeys()");
}
checkClosed();
if (generatedKeys == null) {
if (!conn.scopeGeneratedKeys() && session.isSupportsGeneratedKeys()) {
generatedKeys = new JdbcResultSet(conn, this, null, new SimpleResult(), id, false, true, false);
} else {
// Compatibility mode or an old server, so use SCOPE_IDENTITY()
generatedKeys = conn.getGeneratedKeys(this, id);
}
}
return generatedKeys;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Moves to the next result set - however there is always only one result
set. This call also closes the current result set (if there is one).
Returns true if there is a next result set (that means - it always
returns false).
Throws: - SQLException – if this object is closed.
Returns: false
/**
* Moves to the next result set - however there is always only one result
* set. This call also closes the current result set (if there is one).
* Returns true if there is a next result set (that means - it always
* returns false).
*
* @return false
* @throws SQLException if this object is closed.
*/
@Override
public boolean getMoreResults() throws SQLException {
try {
debugCodeCall("getMoreResults");
checkClosed();
closeOldResultSet();
return false;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Move to the next result set.
This method always returns false.
Params: - current – Statement.CLOSE_CURRENT_RESULT,
Statement.KEEP_CURRENT_RESULT,
or Statement.CLOSE_ALL_RESULTS
Returns: false
/**
* Move to the next result set.
* This method always returns false.
*
* @param current Statement.CLOSE_CURRENT_RESULT,
* Statement.KEEP_CURRENT_RESULT,
* or Statement.CLOSE_ALL_RESULTS
* @return false
*/
@Override
public boolean getMoreResults(int current) throws SQLException {
try {
debugCodeCall("getMoreResults", current);
switch (current) {
case Statement.CLOSE_CURRENT_RESULT:
case Statement.CLOSE_ALL_RESULTS:
checkClosed();
closeOldResultSet();
break;
case Statement.KEEP_CURRENT_RESULT:
// nothing to do
break;
default:
throw DbException.getInvalidValueException("current", current);
}
return false;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- autoGeneratedKeys –
Statement.RETURN_GENERATED_KEYS
if generated keys should be available for retrieval, Statement.NO_GENERATED_KEYS
if generated keys should not be available
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param autoGeneratedKeys
* {@link Statement#RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement#NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public int executeUpdate(String sql, int autoGeneratedKeys)
throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("executeUpdate("+quote(sql)+", "+autoGeneratedKeys+");");
}
return executeUpdateInternal(sql, autoGeneratedKeys == RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- autoGeneratedKeys –
Statement.RETURN_GENERATED_KEYS
if generated keys should be available for retrieval, Statement.NO_GENERATED_KEYS
if generated keys should not be available
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param autoGeneratedKeys
* {@link Statement#RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement#NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("executeLargeUpdate("+quote(sql)+", "+autoGeneratedKeys+");");
}
return executeUpdateInternal(sql, autoGeneratedKeys == RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- columnIndexes –
an array of column indexes indicating the columns with generated
keys that should be returned from the inserted row
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("executeUpdate("+quote(sql)+", "+quoteIntArray(columnIndexes)+");");
}
return executeUpdateInternal(sql, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- columnIndexes –
an array of column indexes indicating the columns with generated
keys that should be returned from the inserted row
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public long executeLargeUpdate(String sql, int columnIndexes[]) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("executeLargeUpdate("+quote(sql)+", "+quoteIntArray(columnIndexes)+");");
}
return executeUpdateInternal(sql, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- columnNames –
an array of column names indicating the columns with generated
keys that should be returned from the inserted row
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("executeUpdate("+quote(sql)+", "+quoteArray(columnNames)+");");
}
return executeUpdateInternal(sql, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- columnNames –
an array of column names indicating the columns with generated
keys that should be returned from the inserted row
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public long executeLargeUpdate(String sql, String columnNames[]) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("executeLargeUpdate("+quote(sql)+", "+quoteArray(columnNames)+");");
}
return executeUpdateInternal(sql, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- autoGeneratedKeys –
Statement.RETURN_GENERATED_KEYS
if generated keys should be available for retrieval, Statement.NO_GENERATED_KEYS
if generated keys should not be available
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param autoGeneratedKeys
* {@link Statement#RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement#NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("execute("+quote(sql)+", "+autoGeneratedKeys+");");
}
return executeInternal(sql, autoGeneratedKeys == RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- columnIndexes –
an array of column indexes indicating the columns with generated
keys that should be returned from the inserted row
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("execute("+quote(sql)+", "+quoteIntArray(columnIndexes)+");");
}
return executeInternal(sql, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Executes a statement and returns the update count.
Params: - sql – the SQL statement
- columnNames –
an array of column names indicating the columns with generated
keys that should be returned from the inserted row
Throws: - SQLException – if a database error occurred or a
select statement was executed
Returns: the update count (number of row affected by an insert,
update or delete, or 0 if no rows or the statement was a
create, drop, commit or rollback)
/**
* Executes a statement and returns the update count.
*
* @param sql the SQL statement
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
* @throws SQLException if a database error occurred or a
* select statement was executed
*/
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
try {
if (isDebugEnabled()) {
debugCode("execute("+quote(sql)+", "+quoteArray(columnNames)+");");
}
return executeInternal(sql, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Gets the result set holdability.
Returns: the holdability
/**
* Gets the result set holdability.
*
* @return the holdability
*/
@Override
public int getResultSetHoldability() throws SQLException {
try {
debugCodeCall("getResultSetHoldability");
checkClosed();
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
} catch (Exception e) {
throw logAndConvert(e);
}
}
[Not supported]
/**
* [Not supported]
*/
@Override
public void closeOnCompletion() {
// not supported
}
[Not supported]
/**
* [Not supported]
*/
@Override
public boolean isCloseOnCompletion() {
return true;
}
// =============================================================
Check if this connection is closed.
The next operation is a read request.
Throws: - DbException – if the connection or session is closed
Returns: true if the session was re-connected
/**
* Check if this connection is closed.
* The next operation is a read request.
*
* @return true if the session was re-connected
* @throws DbException if the connection or session is closed
*/
boolean checkClosed() {
return checkClosed(false);
}
Check if this connection is closed.
The next operation may be a write request.
Throws: - DbException – if the connection or session is closed
Returns: true if the session was re-connected
/**
* Check if this connection is closed.
* The next operation may be a write request.
*
* @return true if the session was re-connected
* @throws DbException if the connection or session is closed
*/
boolean checkClosedForWrite() {
return checkClosed(true);
}
INTERNAL.
Check if the statement is closed.
Params: - write – if the next operation is possibly writing
Throws: - DbException – if it is closed
Returns: true if a reconnect was required
/**
* INTERNAL.
* Check if the statement is closed.
*
* @param write if the next operation is possibly writing
* @return true if a reconnect was required
* @throws DbException if it is closed
*/
protected boolean checkClosed(boolean write) {
if (conn == null) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
conn.checkClosed(write);
SessionInterface s = conn.getSession();
if (s != session) {
session = s;
trace = session.getTrace();
return true;
}
return false;
}
Called after each write operation.
/**
* Called after each write operation.
*/
void afterWriting() {
if (conn != null) {
conn.afterWriting();
}
}
INTERNAL.
Close and old result set if there is still one open.
/**
* INTERNAL.
* Close and old result set if there is still one open.
*/
protected void closeOldResultSet() throws SQLException {
try {
if (!closedByResultSet) {
if (resultSet != null) {
resultSet.closeInternal();
}
if (generatedKeys != null) {
generatedKeys.closeInternal();
}
}
} finally {
cancelled = false;
resultSet = null;
updateCount = -1;
generatedKeys = null;
}
}
INTERNAL.
Set the statement that is currently running.
Params: - c – the command
/**
* INTERNAL.
* Set the statement that is currently running.
*
* @param c the command
*/
protected void setExecutingStatement(CommandInterface c) {
if (c == null) {
conn.setExecutingStatement(null);
} else {
conn.setExecutingStatement(this);
lastExecutedCommandType = c.getCommandType();
}
executingCommand = c;
}
Called when the result set is closed.
Params: - command – the command
- closeCommand – whether to close the command
/**
* Called when the result set is closed.
*
* @param command the command
* @param closeCommand whether to close the command
*/
void onLazyResultSetClose(CommandInterface command, boolean closeCommand) {
setExecutingStatement(null);
command.stop();
if (closeCommand) {
command.close();
}
}
INTERNAL.
Get the command type of the last executed command.
/**
* INTERNAL.
* Get the command type of the last executed command.
*/
public int getLastExecutedCommandType() {
return lastExecutedCommandType;
}
Returns whether this statement is closed.
Returns: true if the statement is closed
/**
* Returns whether this statement is closed.
*
* @return true if the statement is closed
*/
@Override
public boolean isClosed() throws SQLException {
try {
debugCodeCall("isClosed");
return conn == null;
} catch (Exception e) {
throw logAndConvert(e);
}
}
Return an object of this class if possible.
Params: - iface – the class
Returns: this
/**
* Return an object of this class if possible.
*
* @param iface the class
* @return this
*/
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
if (isWrapperFor(iface)) {
return (T) this;
}
throw DbException.getInvalidValueException("iface", iface);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Checks if unwrap can return an object of this class.
Params: - iface – the class
Returns: whether or not the interface is assignable from this class
/**
* Checks if unwrap can return an object of this class.
*
* @param iface the class
* @return whether or not the interface is assignable from this class
*/
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface != null && iface.isAssignableFrom(getClass());
}
Returns whether this object is poolable.
Returns: false
/**
* Returns whether this object is poolable.
* @return false
*/
@Override
public boolean isPoolable() {
debugCodeCall("isPoolable");
return false;
}
Requests that this object should be pooled or not.
This call is ignored.
Params: - poolable – the requested value
/**
* Requests that this object should be pooled or not.
* This call is ignored.
*
* @param poolable the requested value
*/
@Override
public void setPoolable(boolean poolable) {
if (isDebugEnabled()) {
debugCode("setPoolable("+poolable+");");
}
}
Params: - identifier –
identifier to quote if required, may be quoted or unquoted
- alwaysQuote – if
true
identifier will be quoted unconditionally
Throws: - SQLException –
if identifier is not a valid identifier
Returns: specified identifier quoted if required, explicitly requested, or
if it was already quoted
/**
* @param identifier
* identifier to quote if required, may be quoted or unquoted
* @param alwaysQuote
* if {@code true} identifier will be quoted unconditionally
* @return specified identifier quoted if required, explicitly requested, or
* if it was already quoted
* @throws SQLException
* if identifier is not a valid identifier
*/
@Override
public String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException {
if (isSimpleIdentifier(identifier)) {
return alwaysQuote ? '"' + identifier + '"': identifier;
}
int length = identifier.length();
if (length > 0 && identifier.charAt(0) == '"') {
boolean quoted = true;
for (int i = 1; i < length; i++) {
if (identifier.charAt(i) == '"') {
quoted = !quoted;
} else if (!quoted) {
throw new SQLException();
}
}
if (quoted) {
throw new SQLException();
}
return identifier;
}
return StringUtils.quoteIdentifier(identifier);
}
Params: - identifier –
identifier to check
Returns: is specified identifier may be used without quotes
/**
* @param identifier
* identifier to check
* @return is specified identifier may be used without quotes
*/
@Override
public boolean isSimpleIdentifier(String identifier) throws SQLException {
JdbcConnection.Settings settings = conn.getSettings();
return ParserUtil.isSimpleIdentifier(identifier, settings.databaseToUpper, settings.databaseToLower);
}
INTERNAL
/**
* INTERNAL
*/
@Override
public String toString() {
return getTraceObjectName();
}
}