package org.postgresql.jdbc;
import org.postgresql.Driver;
import org.postgresql.core.BaseConnection;
import org.postgresql.core.BaseStatement;
import org.postgresql.core.CachedQuery;
import org.postgresql.core.Field;
import org.postgresql.core.ParameterList;
import org.postgresql.core.Query;
import org.postgresql.core.QueryExecutor;
import org.postgresql.core.ResultCursor;
import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.SqlCommand;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
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 java.util.List;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
public class PgStatement implements Statement, BaseStatement {
private static final String[] NO_RETURNING_COLUMNS = new String[0];
private static final boolean DEFAULT_FORCE_BINARY_TRANSFERS =
Boolean.getBoolean("org.postgresql.forceBinary");
private boolean forceBinaryTransfers = DEFAULT_FORCE_BINARY_TRANSFERS;
protected ArrayList<Query> batchStatements = null;
protected ArrayList<ParameterList> batchParameters = null;
protected final int resultsettype;
protected final int concurrency;
private final int rsHoldability;
private boolean poolable;
private boolean closeOnCompletion = false;
protected int fetchdirection = ResultSet.FETCH_FORWARD;
private volatile TimerTask cancelTimerTask = null;
private static final AtomicReferenceFieldUpdater<PgStatement, TimerTask> CANCEL_TIMER_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(PgStatement.class, TimerTask.class, "cancelTimerTask");
private volatile StatementCancelState statementState = StatementCancelState.IDLE;
private static final AtomicReferenceFieldUpdater<PgStatement, StatementCancelState> STATE_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(PgStatement.class, StatementCancelState.class, "statementState");
protected boolean wantsGeneratedKeysOnce = false;
public boolean wantsGeneratedKeysAlways = false;
protected final BaseConnection connection;
protected volatile PSQLWarningWrapper warnings = null;
protected int maxrows = 0;
protected int fetchSize = 0;
protected long timeout = 0;
protected boolean replaceProcessingEnabled = true;
protected ResultWrapper result = null;
protected ResultWrapper firstUnclosedResult = null;
protected ResultWrapper generatedKeys = null;
protected int mPrepareThreshold;
protected int maxFieldSize = 0;
PgStatement(PgConnection c, int rsType, int rsConcurrency, int rsHoldability)
throws SQLException {
this.connection = c;
forceBinaryTransfers |= c.getForceBinary();
resultsettype = rsType;
concurrency = rsConcurrency;
setFetchSize(c.getDefaultFetchSize());
setPrepareThreshold(c.getPrepareThreshold());
this.rsHoldability = rsHoldability;
}
public ResultSet createResultSet(Query originalQuery, Field[] fields, List<byte[][]> tuples,
ResultCursor cursor) throws SQLException {
PgResultSet newResult = new PgResultSet(originalQuery, this, fields, tuples, cursor,
getMaxRows(), getMaxFieldSize(), getResultSetType(), getResultSetConcurrency(),
getResultSetHoldability());
newResult.setFetchSize(getFetchSize());
newResult.setFetchDirection(getFetchDirection());
return newResult;
}
public BaseConnection getPGConnection() {
return connection;
}
public String getFetchingCursorName() {
return null;
}
public int getFetchSize() {
return fetchSize;
}
protected boolean wantsScrollableResultSet() {
return resultsettype != ResultSet.TYPE_FORWARD_ONLY;
}
protected boolean wantsHoldableResultSet() {
return rsHoldability == ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
public class StatementResultHandler extends ResultHandlerBase {
private ResultWrapper results;
private ResultWrapper lastResult;
ResultWrapper getResults() {
return results;
}
private void append(ResultWrapper newResult) {
if (results == null) {
lastResult = results = newResult;
} else {
lastResult.append(newResult);
}
}
@Override
public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
ResultCursor cursor) {
try {
ResultSet rs = PgStatement.this.createResultSet(fromQuery, fields, tuples, cursor);
append(new ResultWrapper(rs));
} catch (SQLException e) {
handleError(e);
}
}
@Override
public void handleCommandStatus(String status, int updateCount, long insertOID) {
append(new ResultWrapper(updateCount, insertOID));
}
@Override
public void handleWarning(SQLWarning warning) {
PgStatement.this.addWarning(warning);
}
}
@Override
public ResultSet executeQuery(String sql) throws SQLException {
if (!executeWithFlags(sql, 0)) {
throw new PSQLException(GT.tr("No results were returned by the query."), PSQLState.NO_DATA);
}
return getSingleResultSet();
}
protected ResultSet getSingleResultSet() throws SQLException {
synchronized (this) {
checkClosed();
if (result.getNext() != null) {
throw new PSQLException(GT.tr("Multiple ResultSets were returned by the query."),
PSQLState.TOO_MANY_RESULTS);
}
return result.getResultSet();
}
}
@Override
public int executeUpdate(String sql) throws SQLException {
executeWithFlags(sql, QueryExecutor.QUERY_NO_RESULTS);
return getNoResultUpdateCount();
}
protected int getNoResultUpdateCount() throws SQLException {
synchronized (this) {
checkClosed();
ResultWrapper iter = result;
while (iter != null) {
if (iter.getResultSet() != null) {
throw new PSQLException(GT.tr("A result was returned when none was expected."),
PSQLState.TOO_MANY_RESULTS);
}
iter = iter.getNext();
}
return getUpdateCount();
}
}
@Override
public boolean execute(String sql) throws SQLException {
return executeWithFlags(sql, 0);
}
@Override
public boolean executeWithFlags(String sql, int flags) throws SQLException {
return executeCachedSql(sql, flags, NO_RETURNING_COLUMNS);
}
private boolean executeCachedSql(String sql, int flags, String[] columnNames) throws SQLException {
PreferQueryMode preferQueryMode = connection.getPreferQueryMode();
boolean shouldUseParameterized = false;
QueryExecutor queryExecutor = connection.getQueryExecutor();
Object key = queryExecutor
.createQueryKey(sql, replaceProcessingEnabled, shouldUseParameterized, columnNames);
CachedQuery cachedQuery;
boolean shouldCache = preferQueryMode == PreferQueryMode.EXTENDED_CACHE_EVERYTHING;
if (shouldCache) {
cachedQuery = queryExecutor.borrowQueryByKey(key);
} else {
cachedQuery = queryExecutor.createQueryByKey(key);
}
if (wantsGeneratedKeysOnce) {
SqlCommand sqlCommand = cachedQuery.query.getSqlCommand();
wantsGeneratedKeysOnce = sqlCommand != null && sqlCommand.isReturningKeywordPresent();
}
boolean res;
try {
res = executeWithFlags(cachedQuery, flags);
} finally {
if (shouldCache) {
queryExecutor.releaseQuery(cachedQuery);
}
}
return res;
}
public boolean executeWithFlags(CachedQuery simpleQuery, int flags) throws SQLException {
checkClosed();
if (connection.getPreferQueryMode().compareTo(PreferQueryMode.EXTENDED) < 0) {
flags |= QueryExecutor.QUERY_EXECUTE_AS_SIMPLE;
}
execute(simpleQuery, null, flags);
synchronized (this) {
checkClosed();
return (result != null && result.getResultSet() != null);
}
}
public boolean executeWithFlags(int flags) throws SQLException {
checkClosed();
throw new PSQLException(GT.tr("Can''t use executeWithFlags(int) on a Statement."),
PSQLState.WRONG_OBJECT_TYPE);
}
protected void closeForNextExecution() throws SQLException {
clearWarnings();
synchronized (this) {
while (firstUnclosedResult != null) {
ResultSet rs = firstUnclosedResult.getResultSet();
if (rs != null) {
rs.close();
}
firstUnclosedResult = firstUnclosedResult.getNext();
}
result = null;
if (generatedKeys != null) {
if (generatedKeys.getResultSet() != null) {
generatedKeys.getResultSet().close();
}
generatedKeys = null;
}
}
}
protected boolean isOneShotQuery(CachedQuery cachedQuery) {
if (cachedQuery == null) {
return true;
}
cachedQuery.increaseExecuteCount();
if ((mPrepareThreshold == 0 || cachedQuery.getExecuteCount() < mPrepareThreshold)
&& !getForceBinaryTransfer()) {
return true;
}
return false;
}
protected final void execute(CachedQuery cachedQuery, ParameterList queryParameters, int flags)
throws SQLException {
try {
executeInternal(cachedQuery, queryParameters, flags);
} catch (SQLException e) {
if (cachedQuery.query.getSubqueries() != null
|| !connection.getQueryExecutor().willHealOnRetry(e)) {
throw e;
}
cachedQuery.query.close();
executeInternal(cachedQuery, queryParameters, flags);
}
}
private void executeInternal(CachedQuery cachedQuery, ParameterList queryParameters, int flags)
throws SQLException {
closeForNextExecution();
if (fetchSize > 0 && !wantsScrollableResultSet() && !connection.getAutoCommit()
&& !wantsHoldableResultSet()) {
flags |= QueryExecutor.QUERY_FORWARD_CURSOR;
}
if (wantsGeneratedKeysOnce || wantsGeneratedKeysAlways) {
flags |= QueryExecutor.QUERY_BOTH_ROWS_AND_STATUS;
if ((flags & QueryExecutor.QUERY_NO_RESULTS) != 0) {
flags &= ~(QueryExecutor.QUERY_NO_RESULTS);
}
}
if (isOneShotQuery(cachedQuery)) {
flags |= QueryExecutor.QUERY_ONESHOT;
}
if (connection.getAutoCommit()) {
flags |= QueryExecutor.QUERY_SUPPRESS_BEGIN;
}
if (concurrency != ResultSet.CONCUR_READ_ONLY) {
flags |= QueryExecutor.QUERY_NO_BINARY_TRANSFER;
}
Query queryToExecute = cachedQuery.query;
if (queryToExecute.isEmpty()) {
flags |= QueryExecutor.QUERY_SUPPRESS_BEGIN;
}
if (!queryToExecute.isStatementDescribed() && forceBinaryTransfers
&& (flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) == 0) {
int flags2 = flags | QueryExecutor.QUERY_DESCRIBE_ONLY;
StatementResultHandler handler2 = new StatementResultHandler();
connection.getQueryExecutor().execute(queryToExecute, queryParameters, handler2, 0, 0,
flags2);
ResultWrapper result2 = handler2.getResults();
if (result2 != null) {
result2.getResultSet().close();
}
}
StatementResultHandler handler = new StatementResultHandler();
synchronized (this) {
result = null;
}
try {
startTimer();
connection.getQueryExecutor().execute(queryToExecute, queryParameters, handler, maxrows,
fetchSize, flags);
} finally {
killTimerTask();
}
synchronized (this) {
checkClosed();
result = firstUnclosedResult = handler.getResults();
if (wantsGeneratedKeysOnce || wantsGeneratedKeysAlways) {
generatedKeys = result;
result = result.getNext();
if (wantsGeneratedKeysOnce) {
wantsGeneratedKeysOnce = false;
}
}
}
}
public void setCursorName(String name) throws SQLException {
checkClosed();
}
private volatile boolean isClosed = false;
public int getUpdateCount() throws SQLException {
synchronized (this) {
checkClosed();
if (result == null || result.getResultSet() != null) {
return -1;
}
return result.getUpdateCount();
}
}
public boolean getMoreResults() throws SQLException {
synchronized (this) {
checkClosed();
if (result == null) {
return false;
}
result = result.getNext();
while (firstUnclosedResult != result) {
if (firstUnclosedResult.getResultSet() != null) {
firstUnclosedResult.getResultSet().close();
}
firstUnclosedResult = firstUnclosedResult.getNext();
}
return (result != null && result.getResultSet() != null);
}
}
public int getMaxRows() throws SQLException {
checkClosed();
return maxrows;
}
public void setMaxRows(int max) throws SQLException {
checkClosed();
if (max < 0) {
throw new PSQLException(
GT.tr("Maximum number of rows must be a value grater than or equal to 0."),
PSQLState.INVALID_PARAMETER_VALUE);
}
maxrows = max;
}
public void setEscapeProcessing(boolean enable) throws SQLException {
checkClosed();
replaceProcessingEnabled = enable;
}
public int getQueryTimeout() throws SQLException {
checkClosed();
long seconds = timeout / 1000;
if (seconds >= Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
return (int) seconds;
}
public void setQueryTimeout(int seconds) throws SQLException {
setQueryTimeoutMs(seconds * 1000L);
}
public long getQueryTimeoutMs() throws SQLException {
checkClosed();
return timeout;
}
public void setQueryTimeoutMs(long millis) throws SQLException {
checkClosed();
if (millis < 0) {
throw new PSQLException(GT.tr("Query timeout must be a value greater than or equals to 0."),
PSQLState.INVALID_PARAMETER_VALUE);
}
timeout = millis;
}
public void addWarning(SQLWarning warn) {
final PSQLWarningWrapper warnWrap = this.warnings;
if (warnWrap == null) {
this.warnings = new PSQLWarningWrapper(warn);
} else {
warnWrap.addWarning(warn);
}
}
public SQLWarning getWarnings() throws SQLException {
checkClosed();
final PSQLWarningWrapper warnWrap = this.warnings;
return warnWrap != null ? warnWrap.getFirstWarning() : null;
}
@Override
public int getMaxFieldSize() throws SQLException {
return maxFieldSize;
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
checkClosed();
if (max < 0) {
throw new PSQLException(
GT.tr("The maximum field size must be a value greater than or equal to 0."),
PSQLState.INVALID_PARAMETER_VALUE);
}
maxFieldSize = max;
}
public void clearWarnings() throws SQLException {
warnings = null;
}
public ResultSet getResultSet() throws SQLException {
synchronized (this) {
checkClosed();
if (result == null) {
return null;
}
return result.getResultSet();
}
}
public final void close() throws SQLException {
synchronized (this) {
if (isClosed) {
return;
}
isClosed = true;
}
cancel();
closeForNextExecution();
closeImpl();
}
protected void closeImpl() throws SQLException {
}
public long getLastOID() throws SQLException {
synchronized (this) {
checkClosed();
if (result == null) {
return 0;
}
return result.getInsertOID();
}
}
@Override
public void setPrepareThreshold(int newThreshold) throws SQLException {
checkClosed();
if (newThreshold < 0) {
forceBinaryTransfers = true;
newThreshold = 1;
}
this.mPrepareThreshold = newThreshold;
}
@Override
public int getPrepareThreshold() {
return mPrepareThreshold;
}
@Override
public void setUseServerPrepare(boolean flag) throws SQLException {
setPrepareThreshold(flag ? 1 : 0);
}
@Override
public boolean isUseServerPrepare() {
return false;
}
protected void checkClosed() throws SQLException {
if (isClosed()) {
throw new PSQLException(GT.tr("This statement has been closed."),
PSQLState.OBJECT_NOT_IN_STATE);
}
}
@Override
public void addBatch(String sql) throws SQLException {
checkClosed();
if (batchStatements == null) {
batchStatements = new ArrayList<Query>();
batchParameters = new ArrayList<ParameterList>();
}
boolean shouldUseParameterized = false;
CachedQuery cachedQuery = connection.createQuery(sql, replaceProcessingEnabled, shouldUseParameterized);
batchStatements.add(cachedQuery.query);
batchParameters.add(null);
}
@Override
public void clearBatch() throws SQLException {
if (batchStatements != null) {
batchStatements.clear();
batchParameters.clear();
}
}
protected BatchResultHandler createBatchHandler(Query[] queries,
ParameterList[] parameterLists) {
return new BatchResultHandler(this, queries, parameterLists,
wantsGeneratedKeysAlways);
}
public int[] executeBatch() throws SQLException {
checkClosed();
closeForNextExecution();
if (batchStatements == null || batchStatements.isEmpty()) {
return new int[0];
}
transformQueriesAndParameters();
Query[] queries = batchStatements.toArray(new Query[0]);
ParameterList[] parameterLists =
batchParameters.toArray(new ParameterList[0]);
batchStatements.clear();
batchParameters.clear();
int flags = 0;
boolean preDescribe = false;
if (wantsGeneratedKeysAlways) {
flags = QueryExecutor.QUERY_BOTH_ROWS_AND_STATUS | QueryExecutor.QUERY_NO_BINARY_TRANSFER;
} else {
flags = QueryExecutor.QUERY_NO_RESULTS;
}
PreferQueryMode preferQueryMode = connection.getPreferQueryMode();
if (preferQueryMode == PreferQueryMode.SIMPLE
|| (preferQueryMode == PreferQueryMode.EXTENDED_FOR_PREPARED
&& parameterLists[0] == null)) {
flags |= QueryExecutor.QUERY_EXECUTE_AS_SIMPLE;
}
boolean sameQueryAhead = queries.length > 1 && queries[0] == queries[1];
if (!sameQueryAhead
|| isOneShotQuery(null)) {
flags |= QueryExecutor.QUERY_ONESHOT;
} else {
preDescribe = (wantsGeneratedKeysAlways || sameQueryAhead)
&& !queries[0].isStatementDescribed();
flags |= QueryExecutor.QUERY_FORCE_DESCRIBE_PORTAL;
}
if (connection.getAutoCommit()) {
flags |= QueryExecutor.QUERY_SUPPRESS_BEGIN;
}
BatchResultHandler handler;
handler = createBatchHandler(queries, parameterLists);
if ((preDescribe || forceBinaryTransfers)
&& (flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) == 0) {
int flags2 = flags | QueryExecutor.QUERY_DESCRIBE_ONLY;
StatementResultHandler handler2 = new StatementResultHandler();
try {
connection.getQueryExecutor().execute(queries[0], parameterLists[0], handler2, 0, 0, flags2);
} catch (SQLException e) {
handler.handleError(e);
handler.handleCompletion();
}
ResultWrapper result2 = handler2.getResults();
if (result2 != null) {
result2.getResultSet().close();
}
}
synchronized (this) {
result = null;
}
try {
startTimer();
connection.getQueryExecutor().execute(queries, parameterLists, handler, maxrows, fetchSize,
flags);
} finally {
killTimerTask();
synchronized (this) {
checkClosed();
if (wantsGeneratedKeysAlways) {
generatedKeys = new ResultWrapper(handler.getGeneratedKeys());
}
}
}
return handler.getUpdateCount();
}
public void cancel() throws SQLException {
if (statementState == StatementCancelState.IDLE) {
return;
}
if (!STATE_UPDATER.compareAndSet(this, StatementCancelState.IN_QUERY,
StatementCancelState.CANCELING)) {
return;
}
synchronized (connection) {
try {
connection.cancelQuery();
} finally {
STATE_UPDATER.set(this, StatementCancelState.CANCELLED);
connection.notifyAll();
}
}
}
public Connection getConnection() throws SQLException {
return connection;
}
public int getFetchDirection() {
return fetchdirection;
}
public int getResultSetConcurrency() {
return concurrency;
}
public int getResultSetType() {
return resultsettype;
}
public void setFetchDirection(int direction) throws SQLException {
switch (direction) {
case ResultSet.FETCH_FORWARD:
case ResultSet.FETCH_REVERSE:
case ResultSet.FETCH_UNKNOWN:
fetchdirection = direction;
break;
default:
throw new PSQLException(GT.tr("Invalid fetch direction constant: {0}.", direction),
PSQLState.INVALID_PARAMETER_VALUE);
}
}
public void setFetchSize(int rows) throws SQLException {
checkClosed();
if (rows < 0) {
throw new PSQLException(GT.tr("Fetch size must be a value greater to or equal to 0."),
PSQLState.INVALID_PARAMETER_VALUE);
}
fetchSize = rows;
}
private void startTimer() {
cleanupTimer();
STATE_UPDATER.set(this, StatementCancelState.IN_QUERY);
if (timeout == 0) {
return;
}
TimerTask cancelTask = new TimerTask() {
public void run() {
try {
if (!CANCEL_TIMER_UPDATER.compareAndSet(PgStatement.this, this, null)) {
return;
}
PgStatement.this.cancel();
} catch (SQLException e) {
}
}
};
CANCEL_TIMER_UPDATER.set(this, cancelTask);
connection.addTimerTask(cancelTask, timeout);
}
private boolean cleanupTimer() {
TimerTask timerTask = CANCEL_TIMER_UPDATER.get(this);
if (timerTask == null) {
return timeout == 0;
}
if (!CANCEL_TIMER_UPDATER.compareAndSet(this, timerTask, null)) {
return false;
}
timerTask.cancel();
connection.purgeTimerTasks();
return true;
}
private void killTimerTask() {
boolean timerTaskIsClear = cleanupTimer();
if (timerTaskIsClear && STATE_UPDATER.compareAndSet(this, StatementCancelState.IN_QUERY, StatementCancelState.IDLE)) {
return;
}
boolean interrupted = false;
synchronized (connection) {
while (!STATE_UPDATER.compareAndSet(this, StatementCancelState.CANCELLED, StatementCancelState.IDLE)) {
try {
connection.wait(10);
} catch (InterruptedException e) {
interrupted = true;
}
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
protected boolean getForceBinaryTransfer() {
return forceBinaryTransfers;
}
public long getLargeUpdateCount() throws SQLException {
throw Driver.notImplemented(this.getClass(), "getLargeUpdateCount");
}
public void setLargeMaxRows(long max) throws SQLException {
throw Driver.notImplemented(this.getClass(), "setLargeMaxRows");
}
public long getLargeMaxRows() throws SQLException {
throw Driver.notImplemented(this.getClass(), "getLargeMaxRows");
}
public long[] executeLargeBatch() throws SQLException {
throw Driver.notImplemented(this.getClass(), "executeLargeBatch");
}
public long executeLargeUpdate(String sql) throws SQLException {
throw Driver.notImplemented(this.getClass(), "executeLargeUpdate");
}
public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
throw Driver.notImplemented(this.getClass(), "executeLargeUpdate");
}
public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException {
throw Driver.notImplemented(this.getClass(), "executeLargeUpdate");
}
public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException {
throw Driver.notImplemented(this.getClass(), "executeLargeUpdate");
}
public long executeLargeUpdate() throws SQLException {
throw Driver.notImplemented(this.getClass(), "executeLargeUpdate");
}
public boolean isClosed() throws SQLException {
return isClosed;
}
public void setPoolable(boolean poolable) throws SQLException {
checkClosed();
this.poolable = poolable;
}
public boolean isPoolable() throws SQLException {
checkClosed();
return poolable;
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isAssignableFrom(getClass());
}
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return iface.cast(this);
}
throw new SQLException("Cannot unwrap to " + iface.getName());
}
public void closeOnCompletion() throws SQLException {
closeOnCompletion = true;
}
public boolean isCloseOnCompletion() throws SQLException {
return closeOnCompletion;
}
protected void checkCompletion() throws SQLException {
if (!closeOnCompletion) {
return;
}
synchronized (this) {
ResultWrapper result = firstUnclosedResult;
while (result != null) {
if (result.getResultSet() != null && !result.getResultSet().isClosed()) {
return;
}
result = result.getNext();
}
}
closeOnCompletion = false;
try {
close();
} finally {
closeOnCompletion = true;
}
}
public boolean getMoreResults(int current) throws SQLException {
synchronized (this) {
checkClosed();
if (current == Statement.CLOSE_CURRENT_RESULT && result != null
&& result.getResultSet() != null) {
result.getResultSet().close();
}
if (result != null) {
result = result.getNext();
}
if (current == Statement.CLOSE_ALL_RESULTS) {
while (firstUnclosedResult != result) {
if (firstUnclosedResult.getResultSet() != null) {
firstUnclosedResult.getResultSet().close();
}
firstUnclosedResult = firstUnclosedResult.getNext();
}
}
return (result != null && result.getResultSet() != null);
}
}
public ResultSet getGeneratedKeys() throws SQLException {
synchronized (this) {
checkClosed();
if (generatedKeys == null || generatedKeys.getResultSet() == null) {
return createDriverResultSet(new Field[0], new ArrayList<byte[][]>());
}
return generatedKeys.getResultSet();
}
}
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
if (autoGeneratedKeys == Statement.NO_GENERATED_KEYS) {
return executeUpdate(sql);
}
return executeUpdate(sql, (String[]) null);
}
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
if (columnIndexes == null || columnIndexes.length == 0) {
return executeUpdate(sql);
}
throw new PSQLException(GT.tr("Returning autogenerated keys by column index is not supported."),
PSQLState.NOT_IMPLEMENTED);
}
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
if (columnNames != null && columnNames.length == 0) {
return executeUpdate(sql);
}
wantsGeneratedKeysOnce = true;
if (!executeCachedSql(sql, 0, columnNames)) {
}
return getUpdateCount();
}
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
if (autoGeneratedKeys == Statement.NO_GENERATED_KEYS) {
return execute(sql);
}
return execute(sql, (String[]) null);
}
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
if (columnIndexes != null && columnIndexes.length == 0) {
return execute(sql);
}
throw new PSQLException(GT.tr("Returning autogenerated keys by column index is not supported."),
PSQLState.NOT_IMPLEMENTED);
}
public boolean execute(String sql, String[] columnNames) throws SQLException {
if (columnNames != null && columnNames.length == 0) {
return execute(sql);
}
wantsGeneratedKeysOnce = true;
return executeCachedSql(sql, 0, columnNames);
}
public int getResultSetHoldability() throws SQLException {
return rsHoldability;
}
public ResultSet createDriverResultSet(Field[] fields, List<byte[][]> tuples)
throws SQLException {
return createResultSet(null, fields, tuples, null);
}
protected void transformQueriesAndParameters() throws SQLException {
}
}