org.hsqldb.jdbc.JDBCStatementBase Maven / Gradle / Ivy
Show all versions of sqltool Show documentation
/* Copyright (c) 2001-2021, 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.4.0
* @since 1.9.0
*/
/*
* 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.
*/
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.
*/
volatile boolean isClosed;
/** Is escape processing enabled? */
protected boolean isEscapeProcessing = true;
/** The connection used to execute this statement. */
protected JDBCConnection connection;
/** The maximum number of rows to generate when executing this statement. */
protected int maxRows;
/** The number of rows returned in a chunk. */
protected int fetchSize = 0;
/** Direction of results fetched. */
protected int fetchDirection = JDBCResultSet.FETCH_FORWARD;
/** The result of executing this statement. */
protected Result resultIn;
/** Any error returned from a batch execute. */
protected Result errorResult;
/** The currently existing generated key Result */
protected Result generatedResult;
/** The combined result set properties obtained by executing this statement. */
protected int rsProperties;
/** Used by this statement to communicate non-batched requests. */
protected Result resultOut;
/** Used by this statement to communicate batched execution requests */
protected Result batchResultOut;
/** The currently existing ResultSet object */
protected JDBCResultSet currentResultSet;
/** The currently existing ResultSet object for generated keys */
protected JDBCResultSet generatedResultSet;
/** The first warning in the chain. Null if there are no warnings. */
protected SQLWarning rootWarning;
/** Query timeout in seconds */
protected int queryTimeout;
/** connection generation */
int connectionIncarnation;
/** 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
*/
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
*/
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
*/
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.
*/
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
*/
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 {@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.
*
* Note: 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 {@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;
}
}