/* Copyright (c) 2001-2019, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;

import org.hsqldb.StatementTypes;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.result.Result;
import org.hsqldb.result.ResultConstants;

/**
 * Base class for HSQLDB's implementations of java.sql.Statement and
 * java.sql.PreparedStatement. Contains common members and methods.
 *
 * @author fredt@usrs
 * @version 2.3.5
 * @since 1.9.0
 * @revised JDK 1.7, HSQLDB 2.0.1
 */

/**
 * JDBC specification.
 *
 * Closing the Statement closes the ResultSet instance returned. But:
 *
 * Statement can be executed multiple times and return several results. With
 * normal Statement objects, each execution can be for a completely different
 * query. PreparedStatement instances are specifically for multiple use over
 * multiple transactions.
 *
 * ResultSets may be held over commits and span several transactions.
 *
 * There is no real relation between the current state fo an Statement instance
 * and the various ResultSets that it may have returned for different queries.
 */

review the following issues: Does not always close ResultSet object directly when closed. Although RS objects will eventually be closed when accessed, the change is not reflected to the server, impacting ResultSets that are held.
/** * review the following issues: * * Does not always close ResultSet object directly when closed. Although RS * objects will eventually be closed when accessed, the change is not reflected * to the server, impacting ResultSets that are held. */
class JDBCStatementBase {
Whether this Statement has been explicitly closed. A JDBCConnection object now explicitly closes all of its open JDBC Statement objects when it is closed.
/** * Whether this Statement has been explicitly closed. A JDBCConnection * object now explicitly closes all of its open JDBC Statement objects * when it is closed. */
volatile boolean isClosed;
Is escape processing enabled?
/** Is escape processing enabled? */
protected boolean isEscapeProcessing = true;
The connection used to execute this statement.
/** The connection used to execute this statement. */
protected JDBCConnection connection;
The maximum number of rows to generate when executing this statement.
/** The maximum number of rows to generate when executing this statement. */
protected int maxRows;
The number of rows returned in a chunk.
/** The number of rows returned in a chunk. */
protected int fetchSize = 0;
Direction of results fetched.
/** Direction of results fetched. */
protected int fetchDirection = JDBCResultSet.FETCH_FORWARD;
The result of executing this statement.
/** The result of executing this statement. */
protected Result resultIn;
Any error returned from a batch execute.
/** Any error returned from a batch execute. */
protected Result errorResult;
The currently existing generated key Result
/** The currently existing generated key Result */
protected Result generatedResult;
The combined result set properties obtained by executing this statement.
/** The combined result set properties obtained by executing this statement. */
protected int rsProperties;
Used by this statement to communicate non-batched requests.
/** Used by this statement to communicate non-batched requests. */
protected Result resultOut;
Used by this statement to communicate batched execution requests
/** Used by this statement to communicate batched execution requests */
protected Result batchResultOut;
The currently existing ResultSet object
/** The currently existing ResultSet object */
protected JDBCResultSet currentResultSet;
The currently existing ResultSet object for generated keys
/** The currently existing ResultSet object for generated keys */
protected JDBCResultSet generatedResultSet;
The first warning in the chain. Null if there are no warnings.
/** The first warning in the chain. Null if there are no warnings. */
protected SQLWarning rootWarning;
Query timeout in seconds
/** Query timeout in seconds */
protected int queryTimeout;
connection generation
/** connection generation */
int connectionIncarnation;
Implementation in subclasses
Throws:
  • SQLException – on access error
/** Implementation in subclasses * @throws SQLException on access error */
void close() throws SQLException {}
An internal check for closed statements.
Throws:
  • SQLException – when the connection is closed
/** * An internal check for closed statements. * * @throws SQLException when the connection is closed */
void checkClosed() throws SQLException { if (isClosed) { throw JDBCUtil.sqlException(ErrorCode.X_07501); } if (connection.isClosed) { close(); throw JDBCUtil.sqlException(ErrorCode.X_08503); } if (connectionIncarnation != connection.incarnation) { throw JDBCUtil.sqlException(ErrorCode.X_08503); } }
processes chained warnings and any generated columns result set
/** * processes chained warnings and any generated columns result set */
void performPostExecute() throws SQLException { resultOut.clearLobResults(); generatedResult = null; if (resultIn == null) { return; } rootWarning = null; Result current = resultIn; while (current.getChainedResult() != null) { current = current.getUnlinkChainedResult(); if (current.getType() == ResultConstants.WARNING) { SQLWarning w = JDBCUtil.sqlWarning(current); if (rootWarning == null) { rootWarning = w; } else { rootWarning.setNextWarning(w); } } else if (current.getType() == ResultConstants.ERROR) { errorResult = current; } else if (current.getType() == ResultConstants.GENERATED) { generatedResult = current; } else if (current.getType() == ResultConstants.DATA) { resultIn.addChainedResult(current); } } if (rootWarning != null) { connection.setWarnings(rootWarning); } } int getUpdateCount() throws SQLException { checkClosed(); return (resultIn == null || resultIn.isData()) ? -1 : resultIn .getUpdateCount(); } ResultSet getResultSet() throws SQLException { checkClosed(); ResultSet result = currentResultSet; if(!connection.isCloseResultSet) { currentResultSet = null; } if (result == null) { // if statement has been used with executeQuery and the result is update count // return an empty result for 1.8 compatibility if (resultOut.getStatementType() == StatementTypes.RETURN_RESULT) { return JDBCResultSet.newEmptyResultSet(); } } return result; } boolean getMoreResults() throws SQLException { return getMoreResults(CLOSE_CURRENT_RESULT); }
Not yet correct for multiple ResultSets. Should keep track of all previous ResultSet objects to be able to close them
/** * Not yet correct for multiple ResultSets. Should keep track of all * previous ResultSet objects to be able to close them */
boolean getMoreResults(int current) throws SQLException { checkClosed(); if (resultIn == null) { return false; } resultIn = resultIn.getChainedResult(); if (currentResultSet != null) { if( current != KEEP_CURRENT_RESULT) { currentResultSet.close(); } } currentResultSet = null; if (resultIn != null) { currentResultSet = new JDBCResultSet(connection, this, resultIn, resultIn.metaData); return true; } return false; } ResultSet getGeneratedResultSet() throws SQLException { checkClosed(); if (generatedResultSet != null) { generatedResultSet.close(); } if (generatedResult == null) { generatedResult = Result.emptyGeneratedResult; } generatedResultSet = new JDBCResultSet(connection, null, generatedResult, generatedResult.metaData); return generatedResultSet; }
See comment for getMoreResults.
/** * See comment for getMoreResults. */
void closeResultData() throws SQLException { if (currentResultSet != null) { currentResultSet.close(); } if (generatedResultSet != null) { generatedResultSet.close(); } generatedResultSet = null; generatedResult = null; resultIn = null; currentResultSet = null; }
JDBC 3 constants
/** * JDBC 3 constants */
static final int CLOSE_CURRENT_RESULT = 1; static final int KEEP_CURRENT_RESULT = 2; static final int CLOSE_ALL_RESULTS = 3; static final int SUCCESS_NO_INFO = -2; static final int EXECUTE_FAILED = -3; static final int RETURN_GENERATED_KEYS = 1; static final int NO_GENERATED_KEYS = 2; //--------------------------JDBC 4.1 -----------------------------
Specifies that this Statement will be closed when all its dependent result sets are closed. If execution of the Statement does not produce any result sets, this method has no effect.

Note: Multiple calls to closeOnCompletion do not toggle the effect on this Statement. However, a call to closeOnCompletion does effect both the subsequent execution of statements, and statements that currently have open, dependent, result sets.

Throws:
  • SQLException – if this method is called on a closed Statement
Since:JDK 1.7 M11 2010/09/10 (b123), HSQLDB 2.0.1
/** * Specifies that this {@code Statement} will be closed when all its * dependent result sets are closed. If execution of the {@code Statement} * does not produce any result sets, this method has no effect. * <p> * <strong>Note:</strong> Multiple calls to {@code closeOnCompletion} do * not toggle the effect on this {@code Statement}. However, a call to * {@code closeOnCompletion} does effect both the subsequent execution of * statements, and statements that currently have open, dependent, * result sets. * * @throws SQLException if this method is called on a closed * {@code Statement} * @since JDK 1.7 M11 2010/09/10 (b123), HSQLDB 2.0.1 */
public void closeOnCompletion() throws SQLException { checkClosed(); }
Returns a value indicating whether this Statement will be closed when all its dependent result sets are closed.
Throws:
  • SQLException – if this method is called on a closed Statement
Returns:true if the Statement will be closed when all of its dependent result sets are closed; false otherwise
Since:JDK 1.7 M11 2010/09/10 (b123), HSQLDB 2.0.1
/** * Returns a value indicating whether this {@code Statement} will be * closed when all its dependent result sets are closed. * @return {@code true} if the {@code Statement} will be closed when all * of its dependent result sets are closed; {@code false} otherwise * @throws SQLException if this method is called on a closed * {@code Statement} * @since JDK 1.7 M11 2010/09/10 (b123), HSQLDB 2.0.1 */
public boolean isCloseOnCompletion() throws SQLException { checkClosed(); return false; } }