/* 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;

import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.ParserDQL.CompileContext;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.HsqlList;
import org.hsqldb.result.Result;
import org.hsqldb.rights.Grantee;
import org.hsqldb.rights.User;
import org.hsqldb.types.DTIType;
import org.hsqldb.types.IntervalSecondData;
import org.hsqldb.types.Type;
import org.hsqldb.types.Types;

Implementation of Statement for SQL session statements.

Author:Fred Toussi (fredt@users dot sourceforge.net)
Version:2.3.5
Since:1.9.0
/** * Implementation of Statement for SQL session statements.<p> * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 2.3.5 * @since 1.9.0 */
public class StatementSession extends Statement { public static final StatementSession commitNoChainStatement = new StatementSession(StatementTypes.COMMIT_WORK, new Object[]{ Boolean.FALSE }); public static final StatementSession rollbackNoChainStatement = new StatementSession(StatementTypes.ROLLBACK_WORK, new Object[]{ Boolean.FALSE }); public static final StatementSession commitAndChainStatement = new StatementSession(StatementTypes.COMMIT_WORK, new Object[]{ Boolean.TRUE }); public static final StatementSession rollbackAndChainStatement = new StatementSession(StatementTypes.ROLLBACK_WORK, new Object[]{ Boolean.TRUE }); static { commitNoChainStatement.sql = Tokens.T_COMMIT; commitAndChainStatement.sql = Tokens.T_COMMIT + ' ' + Tokens.T_CHAIN; rollbackNoChainStatement.sql = Tokens.T_ROLLBACK; rollbackAndChainStatement.sql = Tokens.T_ROLLBACK + ' ' + Tokens.T_CHAIN; commitNoChainStatement.compileTimestamp = Long.MAX_VALUE; commitAndChainStatement.compileTimestamp = Long.MAX_VALUE; rollbackNoChainStatement.compileTimestamp = Long.MAX_VALUE; rollbackAndChainStatement.compileTimestamp = Long.MAX_VALUE; } Expression[] expressions; Object[] arguments; StatementSession(Session session, CompileContext context, int type, Expression[] args) { super(type); expressions = args; isTransactionStatement = false; isLogged = false; Expression e = expressions[0]; switch (type) { case StatementTypes.SET_TIME_ZONE : HsqlList unresolved = e.resolveColumnReferences(session, RangeGroup.emptyGroup, RangeGroup.emptyArray, null); ExpressionColumn.checkColumnsResolved(unresolved); e.resolveTypes(session, null); if (e.dataType == null) { e.setDataType(session, Type.SQL_INTERVAL_HOUR_TO_MINUTE); } if (e.dataType.isCharacterType()) { e = new ExpressionOp(e, Type.SQL_INTERVAL_HOUR_TO_MINUTE); expressions[0] = e; } if (e.dataType.typeCode != Types.SQL_INTERVAL_HOUR_TO_MINUTE) { throw Error.error(ErrorCode.X_42563); } group = StatementTypes.X_SQL_SESSION; return; case StatementTypes.SET_PATH : case StatementTypes.SET_NAMES : case StatementTypes.SET_ROLE : case StatementTypes.SET_SCHEMA : case StatementTypes.SET_CATALOG : case StatementTypes.SET_SESSION_AUTHORIZATION : case StatementTypes.SET_COLLATION : group = StatementTypes.X_SQL_SESSION; break; default : throw Error.runtimeError(ErrorCode.U_S0500, "StatementSession"); } e.resolveTypes(session, null); switch (e.getType()) { case OpTypes.VALUE : break; case OpTypes.DYNAMIC_PARAM : e.setDataType(session, Type.SQL_VARCHAR_DEFAULT); break; case OpTypes.SQL_FUNCTION : if (((FunctionSQL) e).isValueFunction()) { break; } throw Error.error(ErrorCode.X_0P000); default : throw Error.error(ErrorCode.X_0P000); } if (!e.getDataType().isCharacterType()) { throw Error.error(ErrorCode.X_0P000); } setDatabaseObjects(session, context); } StatementSession(int type, Object[] args) { super(type); this.arguments = args; isTransactionStatement = false; isLogged = false; switch (type) { // logged by statement case StatementTypes.SET_SCHEMA : group = StatementTypes.X_SQL_SESSION; isLogged = true; break; case StatementTypes.DECLARE_VARIABLE : group = StatementTypes.X_HSQLDB_SESSION; isLogged = true; break; // cursor case StatementTypes.ALLOCATE_CURSOR : group = StatementTypes.X_SQL_DATA; break; case StatementTypes.ALLOCATE_DESCRIPTOR : case StatementTypes.DEALLOCATE_DESCRIPTOR : case StatementTypes.DEALLOCATE_PREPARE : group = StatementTypes.X_SQL_DYNAMIC; break; // case StatementTypes.DYNAMIC_DELETE_CURSOR : group = StatementTypes.X_SQL_DATA_CHANGE; break; case StatementTypes.DYNAMIC_CLOSE : case StatementTypes.DYNAMIC_FETCH : case StatementTypes.DYNAMIC_OPEN : group = StatementTypes.X_SQL_DATA; break; // case StatementTypes.OPEN : case StatementTypes.FETCH : case StatementTypes.FREE_LOCATOR : case StatementTypes.GET_DESCRIPTOR : case StatementTypes.HOLD_LOCATOR : group = StatementTypes.X_SQL_DATA; break; // case StatementTypes.PREPARABLE_DYNAMIC_DELETE_CURSOR : case StatementTypes.PREPARABLE_DYNAMIC_UPDATE_CURSOR : case StatementTypes.PREPARE : group = StatementTypes.X_SQL_DYNAMIC; break; // logged by session case StatementTypes.DISCONNECT : group = StatementTypes.X_SQL_CONNECTION; break; // case StatementTypes.SET_COLLATION : case StatementTypes.SET_CONNECTION : case StatementTypes.SET_CONSTRAINT : case StatementTypes.SET_DESCRIPTOR : case StatementTypes.SET_SESSION_AUTOCOMMIT : case StatementTypes.SET_SESSION_CHARACTERISTICS : case StatementTypes.SET_SESSION_FEATURE : case StatementTypes.SET_SESSION_RESULT_MAX_ROWS : case StatementTypes.SET_SESSION_RESULT_MEMORY_ROWS : case StatementTypes.SET_TRANSFORM_GROUP : group = StatementTypes.X_HSQLDB_SESSION; break; case StatementTypes.SET_SESSION_SQL_IGNORECASE : isLogged = true; group = StatementTypes.X_HSQLDB_SESSION; break; // logged by session if necessary case StatementTypes.COMMIT_WORK : case StatementTypes.RELEASE_SAVEPOINT : case StatementTypes.ROLLBACK_SAVEPOINT : case StatementTypes.ROLLBACK_WORK : case StatementTypes.SAVEPOINT : case StatementTypes.SET_TRANSACTION : case StatementTypes.START_TRANSACTION : group = StatementTypes.X_SQL_TRANSACTION; break; case StatementTypes.DECLARE_SESSION_TABLE : case StatementTypes.DROP_TABLE : group = StatementTypes.X_SQL_SESSION; break; default : throw Error.runtimeError(ErrorCode.U_S0500, "StatementSession"); } } StatementSession(int type, HsqlName[] readNames, HsqlName[] writeNames) { super(type); isTransactionStatement = true; isLogged = false; readTableNames = readNames; writeTableNames = writeNames; switch (type) { case StatementTypes.TRANSACTION_LOCK_CATALOG : case StatementTypes.TRANSACTION_UNLOCK_CATALOG : case StatementTypes.TRANSACTION_LOCK_TABLE : group = StatementTypes.X_HSQLDB_TRANSACTION; break; default : throw Error.runtimeError(ErrorCode.U_S0500, "StatementSession"); } } public Result execute(Session session) { Result result; try { result = getResult(session); } catch (Throwable t) { result = Result.newErrorResult(t, null); } if (result.isError()) { result.getException().setStatementType(group, type); return result; } try { if (isLogged) { session.database.logger.writeOtherStatement(session, sql); } } catch (Throwable e) { return Result.newErrorResult(e, sql); } return result; } Result getResult(Session session) { boolean startTransaction = false; if (this.isExplain) { return Result.newSingleColumnStringResult("OPERATION", describe(session)); } switch (type) { // cursor case StatementTypes.ALLOCATE_CURSOR : case StatementTypes.ALLOCATE_DESCRIPTOR : return Result.updateZeroResult; // case StatementTypes.COMMIT_WORK : { try { boolean chain = ((Boolean) arguments[0]).booleanValue(); session.commit(chain); return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.DEALLOCATE_DESCRIPTOR : case StatementTypes.DEALLOCATE_PREPARE : return Result.updateZeroResult; case StatementTypes.DISCONNECT : session.close(); return Result.updateZeroResult; // case StatementTypes.DYNAMIC_CLOSE : case StatementTypes.DYNAMIC_DELETE_CURSOR : case StatementTypes.DYNAMIC_FETCH : case StatementTypes.DYNAMIC_OPEN : // case StatementTypes.FETCH : case StatementTypes.FREE_LOCATOR : case StatementTypes.GET_DESCRIPTOR : case StatementTypes.HOLD_LOCATOR : // case StatementTypes.OPEN : case StatementTypes.PREPARABLE_DYNAMIC_DELETE_CURSOR : case StatementTypes.PREPARABLE_DYNAMIC_UPDATE_CURSOR : case StatementTypes.PREPARE : return Result.updateZeroResult; case StatementTypes.TRANSACTION_LOCK_CATALOG : case StatementTypes.TRANSACTION_UNLOCK_CATALOG : case StatementTypes.TRANSACTION_LOCK_TABLE : { return Result.updateZeroResult; } case StatementTypes.RELEASE_SAVEPOINT : { String savepoint = (String) arguments[0]; try { session.releaseSavepoint(savepoint); return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.ROLLBACK_WORK : { boolean chain = ((Boolean) arguments[0]).booleanValue(); session.rollback(chain); return Result.updateZeroResult; } case StatementTypes.ROLLBACK_SAVEPOINT : { String savepoint = (String) arguments[0]; try { session.rollbackToSavepoint(savepoint); return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.SAVEPOINT : { String savepoint = (String) arguments[0]; session.savepoint(savepoint); return Result.updateZeroResult; } case StatementTypes.SET_CATALOG : { String name; try { name = (String) expressions[0].getValue(session); name = (String) Type.SQL_VARCHAR.trim(session, name, ' ', true, true); if (session.database.getCatalogName().name.equals(name)) { return Result.updateZeroResult; } return Result.newErrorResult( Error.error(ErrorCode.X_3D000), sql); } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.SET_CONNECTION : case StatementTypes.SET_CONSTRAINT : case StatementTypes.SET_DESCRIPTOR : return Result.updateZeroResult; case StatementTypes.SET_TIME_ZONE : { Object value = null; if (expressions[0].getType() == OpTypes.VALUE && expressions[0].getConstantValueNoCheck(session) == null) { session.setZoneSeconds(session.sessionTimeZoneSeconds); return Result.updateZeroResult; } try { value = expressions[0].getValue(session); } catch (HsqlException e) {} if (value instanceof Result) { Result result = (Result) value; if (result.isData()) { Object[] data = null; boolean single = false; if (result.getNavigator().next()) { data = result.getNavigator().getCurrent(); single = !result.getNavigator().next(); } if (single && data != null && data[0] != null) { value = data[0]; result.getNavigator().release(); } else { result.getNavigator().release(); return Result.newErrorResult( Error.error(ErrorCode.X_22009), sql); } } else { return Result.newErrorResult( Error.error(ErrorCode.X_22009), sql); } } else { if (value == null) { return Result.newErrorResult( Error.error(ErrorCode.X_22009), sql); } } long seconds = ((IntervalSecondData) value).getSeconds(); if (-DTIType.timezoneSecondsLimit <= seconds && seconds <= DTIType.timezoneSecondsLimit) { session.setZoneSeconds((int) seconds); return Result.updateZeroResult; } return Result.newErrorResult(Error.error(ErrorCode.X_22009), sql); } case StatementTypes.SET_NAMES : return Result.updateZeroResult; case StatementTypes.SET_PATH : return Result.updateZeroResult; case StatementTypes.SET_ROLE : { String name; Grantee role = null; try { name = (String) expressions[0].getValue(session); if (name != null) { name = (String) Type.SQL_VARCHAR.trim(session, name, ' ', true, true); role = session.database.granteeManager.getRole(name); } } catch (HsqlException e) { return Result.newErrorResult( Error.error(ErrorCode.X_0P000), sql); } if (session.isInMidTransaction()) { return Result.newErrorResult( Error.error(ErrorCode.X_25001), sql); } if (role == null) { session.setRole(null); } if (session.getGrantee().hasRole(role)) { session.setRole(role); return Result.updateZeroResult; } else { return Result.newErrorResult( Error.error(ErrorCode.X_0P000), sql); } } case StatementTypes.SET_SCHEMA : { String name; HsqlName schema; try { if (expressions == null) { name = ((HsqlName) arguments[0]).name; } else { name = (String) expressions[0].getValue(session); } name = (String) Type.SQL_VARCHAR.trim(session, name, ' ', true, true); schema = session.database.schemaManager.getSchemaHsqlName(name); session.setCurrentSchemaHsqlName(schema); return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.SET_SESSION_AUTHORIZATION : { if (session.isInMidTransaction()) { return Result.newErrorResult( Error.error(ErrorCode.X_25001), sql); } try { String user; String password = null; user = (String) expressions[0].getValue(session); user = (String) Type.SQL_VARCHAR.trim(session, user, ' ', true, true); if (expressions[1] != null) { password = (String) expressions[1].getValue(session); } User userObject; if (password == null) { userObject = session.database.userManager.get(user); } else { userObject = session.database.getUserManager().getUser(user, password); } if (userObject == null) { throw Error.error(ErrorCode.X_28501); } // override the actual SQL at runtime sql = userObject.getConnectUserSQL(); if (userObject == session.getGrantee()) { return Result.updateZeroResult; } if (password == null && !session.isProcessingLog() && userObject.isAdmin() && !session.getGrantee().isAdmin()) { throw Error.error(ErrorCode.X_28000); } if (session.getGrantee().canChangeAuthorisation()) { session.setUser(userObject); session.setRole(null); session.resetSchema(); return Result.updateZeroResult; } /** @todo may need different error code */ throw Error.error(ErrorCode.X_28000); } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.SET_SESSION_CHARACTERISTICS : { try { if (arguments[0] != null) { boolean readonly = ((Boolean) arguments[0]).booleanValue(); session.setReadOnlyDefault(readonly); } if (arguments[1] != null) { int level = ((Integer) arguments[1]).intValue(); session.setIsolationDefault(level); } return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.SET_COLLATION : return Result.updateZeroResult; case StatementTypes.SET_TRANSFORM_GROUP : return Result.updateZeroResult; case StatementTypes.START_TRANSACTION : startTransaction = true; // fall through case StatementTypes.SET_TRANSACTION : { try { if (arguments[0] != null) { boolean readonly = ((Boolean) arguments[0]).booleanValue(); session.setReadOnly(readonly); } if (arguments[1] != null) { int level = ((Integer) arguments[1]).intValue(); session.setIsolation(level); } if (startTransaction) { session.startTransaction(); } return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } // case StatementTypes.SET_SESSION_AUTOCOMMIT : { boolean mode = ((Boolean) arguments[0]).booleanValue(); try { session.setAutoCommit(mode); return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.DECLARE_VARIABLE : { ColumnSchema[] variables = (ColumnSchema[]) arguments[0]; try { for (int i = 0; i < variables.length; i++) { session.sessionContext.addSessionVariable( variables[i]); } return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.SET_SESSION_FEATURE : { String feature = (String) arguments[0]; Boolean value = (Boolean) arguments[1]; session.setFeature(feature, value.booleanValue()); return Result.updateZeroResult; } case StatementTypes.SET_SESSION_RESULT_MAX_ROWS : { int size = ((Integer) arguments[0]).intValue(); session.setSQLMaxRows(size); return Result.updateZeroResult; } case StatementTypes.SET_SESSION_RESULT_MEMORY_ROWS : { int size = ((Integer) arguments[0]).intValue(); session.setResultMemoryRowCount(size); return Result.updateZeroResult; } case StatementTypes.SET_SESSION_SQL_IGNORECASE : { try { boolean mode = ((Boolean) arguments[0]).booleanValue(); session.setIgnoreCase(mode); return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.DECLARE_SESSION_TABLE : { Table table = (Table) arguments[0]; HsqlArrayList tempConstraints = (HsqlArrayList) arguments[1]; StatementDMQL statement = (StatementDMQL) arguments[3]; Boolean ifNotExists = (Boolean) arguments[4]; try { if (tempConstraints.size() != 0) { table = ParserDDL.addTableConstraintDefinitions(session, table, tempConstraints, null, false); } table.compile(session, null); try { session.sessionContext.addSessionTable(table); } catch (HsqlException e) { if (ifNotExists != null && ifNotExists.booleanValue()) { return Result.updateZeroResult; } else { return Result.newErrorResult(e, sql); } } if (table.hasLobColumn) { throw Error.error(ErrorCode.X_42534); } if (statement != null) { Result result = statement.execute(session); table.insertIntoTable(session, result); } return Result.updateZeroResult; } catch (HsqlException e) { return Result.newErrorResult(e, sql); } } case StatementTypes.DROP_TABLE : { HsqlName name = (HsqlName) arguments[0]; Boolean ifExists = (Boolean) arguments[1]; Table table = session.sessionContext.findSessionTable(name.name); if (table == null) { if (ifExists.booleanValue()) { return Result.updateZeroResult; } else { throw Error.error(ErrorCode.X_42501, name.name); } } session.sessionData.persistentStoreCollection.removeStore( table); session.sessionContext.dropSessionTable(name.name); return Result.updateZeroResult; } default : throw Error.runtimeError(ErrorCode.U_S0500, "StatementSession"); } } public boolean isAutoCommitStatement() { return false; } public String describe(Session session) { return sql; } public boolean isCatalogLock(int model) { return false; } public boolean isCatalogChange() { return false; } }