/* 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.HsqlNameManager.SimpleName;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.HsqlList;
import org.hsqldb.lib.LongDeque;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.lib.OrderedIntHashSet;
import org.hsqldb.result.ResultProperties;
import org.hsqldb.types.ArrayType;
import org.hsqldb.types.RowType;
import org.hsqldb.types.Type;

Parser for SQL stored procedures and functions - PSM
Author:Fred Toussi (fredt@users dot sourceforge.net)
Version:2.4.1
Since:1.9.0
/** * Parser for SQL stored procedures and functions - PSM * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 2.4.1 * @since 1.9.0 */
public class ParserRoutine extends ParserTable { ParserRoutine(Session session, Scanner t) { super(session, t); } Statement compileOpenCursorStatement(StatementCompound context) { readThis(Tokens.OPEN); checkIsSimpleName(); String tokenString = token.tokenString; read(); for (int i = 0; i < context.cursors.length; i++) { if (context.cursors[i].getCursorName().name.equals(tokenString)) { return context.cursors[i]; } } throw Error.parseError(ErrorCode.X_34000, null, scanner.getLineNumber()); } Statement compileSelectSingleRowStatement(RangeGroup[] rangeGroups) { OrderedHashSet variableNames = new OrderedHashSet(); Type[] targetTypes; LongDeque colIndexList = new LongDeque(); QuerySpecification select; compileContext.setOuterRanges(rangeGroups); select = XreadSelect(); readThis(Tokens.INTO); RangeVariable[] ranges = rangeGroups[0].getRangeVariables(); readTargetSpecificationList(variableNames, ranges, colIndexList); XreadTableExpression(select); select.setReturningResult(); int[] columnMap = new int[colIndexList.size()]; colIndexList.toArray(columnMap); Expression[] variables = new Expression[variableNames.size()]; variableNames.toArray(variables); targetTypes = new Type[variables.length]; for (int i = 0; i < variables.length; i++) { if (variables[i].getColumn().getParameterMode() == SchemaObject.ParameterModes.PARAM_IN) { // todo - use more specific error message throw Error.parseError(ErrorCode.X_0U000, null, scanner.getLineNumber()); } targetTypes[i] = variables[i].getDataType(); } select.setReturningResult(); select.resolve(session, rangeGroups, targetTypes); if (select.getColumnCount() != variables.length) { throw Error.error(ErrorCode.X_42564, Tokens.T_INTO); } Statement statement = new StatementSet(session, variables, select, columnMap, compileContext); return statement; }
Creates GET DIAGNOSTICS.
/** * Creates GET DIAGNOSTICS. */
Statement compileGetStatement(RangeGroup[] rangeGroups) { read(); readThis(Tokens.DIAGNOSTICS); OrderedHashSet targetSet = new OrderedHashSet(); HsqlArrayList exprList = new HsqlArrayList(); LongDeque colIndexList = new LongDeque(); RangeVariable[] rangeVars = rangeGroups[0].getRangeVariables(); readGetClauseList(rangeVars, targetSet, colIndexList, exprList); if (exprList.size() > 1) { throw Error.parseError(ErrorCode.X_42602, null, scanner.getLineNumber()); } Expression expression = (Expression) exprList.get(0); if (expression.getDegree() != targetSet.size()) { throw Error.error(ErrorCode.X_42546, Tokens.T_SET); } int[] columnMap = new int[colIndexList.size()]; colIndexList.toArray(columnMap); Expression[] targets = new Expression[targetSet.size()]; targetSet.toArray(targets); for (int i = 0; i < targets.length; i++) { resolveOuterReferencesAndTypes(rangeGroups, targets[i]); } resolveOuterReferencesAndTypes(rangeGroups, expression); for (int i = 0; i < targets.length; i++) { if (targets[i].getColumn().getParameterMode() == SchemaObject.ParameterModes.PARAM_IN) { // todo - use more specific error message throw Error.parseError(ErrorCode.X_0U000, null, scanner.getLineNumber()); } if (!targets[i].getDataType().canBeAssignedFrom( expression.getNodeDataType(i))) { throw Error.parseError(ErrorCode.X_42561, null, scanner.getLineNumber()); } } StatementSet cs = new StatementSet(session, targets, expression, columnMap, compileContext); return cs; }
Creates SET Statement for PSM or session variables from this parse context.
/** * Creates SET Statement for PSM or session variables from this parse context. */
StatementSet compileSetStatement(RangeGroup[] rangeGroups, RangeVariable[] rangeVars) { OrderedHashSet targetSet = new OrderedHashSet(); HsqlArrayList exprList = new HsqlArrayList(); LongDeque colIndexList = new LongDeque(); readSetClauseList(rangeVars, targetSet, colIndexList, exprList); if (exprList.size() > 1) { throw Error.parseError(ErrorCode.X_42602, null, scanner.getLineNumber()); } Expression expression = (Expression) exprList.get(0); if (expression.getDegree() != targetSet.size()) { throw Error.error(ErrorCode.X_42546, Tokens.T_SET); } int[] columnMap = new int[colIndexList.size()]; colIndexList.toArray(columnMap); Expression[] targets = new Expression[targetSet.size()]; targetSet.toArray(targets); for (int i = 0; i < targets.length; i++) { resolveOuterReferencesAndTypes(rangeGroups, targets[i]); } resolveOuterReferencesAndTypes(rangeGroups, expression); for (int i = 0; i < targets.length; i++) { ColumnSchema col = targets[i].getColumn(); if (col.getParameterMode() == SchemaObject.ParameterModes.PARAM_IN) { // todo - use more specific error message throw Error.error(ErrorCode.X_0U000, col.getName().statementName); } if (!targets[i].getDataType().canBeAssignedFrom( expression.getNodeDataType(i))) { throw Error.parseError(ErrorCode.X_42561, null, scanner.getLineNumber()); } } StatementSet cs = new StatementSet(session, targets, expression, columnMap, compileContext); return cs; }
Creates SET Statement for a trigger row from this parse context.
/** * Creates SET Statement for a trigger row from this parse context. */
StatementDMQL compileTriggerSetStatement(Table table, RangeGroup[] rangeGroups) { Expression[] updateExpressions; int[] columnMap; OrderedHashSet targetSet = new OrderedHashSet(); HsqlArrayList exprList = new HsqlArrayList(); RangeVariable[] targetRangeVars = new RangeVariable[]{ rangeGroups[0].getRangeVariables()[TriggerDef.NEW_ROW] }; LongDeque colIndexList = new LongDeque(); readSetClauseList(targetRangeVars, targetSet, colIndexList, exprList); columnMap = new int[colIndexList.size()]; colIndexList.toArray(columnMap); Expression[] targets = new Expression[targetSet.size()]; targetSet.toArray(targets); for (int i = 0; i < targets.length; i++) { resolveOuterReferencesAndTypes(RangeGroup.emptyArray, targets[i]); } updateExpressions = new Expression[exprList.size()]; exprList.toArray(updateExpressions); resolveUpdateExpressions(table, RangeGroup.emptyGroup, columnMap, updateExpressions, rangeGroups); StatementDMQL cs = new StatementSet(session, targets, table, rangeGroups[0].getRangeVariables(), columnMap, updateExpressions, compileContext); return cs; } StatementSchema compileAlterSpecificRoutine(Routine routine) { boolean restrict = false; routine = routine.duplicate(); readRoutineCharacteristics(routine); restrict = readIfThis(Tokens.RESTRICT); if (restrict) { OrderedHashSet set = database.schemaManager.getReferencesTo( routine.getSpecificName()); if (!set.isEmpty()) { throw Error.parseError(ErrorCode.X_42502, null, scanner.getLineNumber()); } } if (token.tokenType == Tokens.BODY) { read(); } else if (token.tokenType == Tokens.NAME) { read(); } readRoutineBody(routine); routine.resetAlteredRoutineSettings(); routine.resolve(session); Object[] args = new Object[]{ routine }; String sql = getLastPart(); StatementSchema cs = new StatementSchema(sql, StatementTypes.ALTER_ROUTINE, args, null, database.schemaManager.getCatalogNameArray()); return cs; } // SQL-invoked routine StatementSchema compileCreateProcedureOrFunction(boolean orReplace) { Routine routine = readCreateProcedureOrFunction(); Object[] args = new Object[]{ routine }; String sql = getLastPart(); StatementSchema cs = new StatementSchema(sql, StatementTypes.CREATE_ROUTINE, args, null, database.schemaManager.getCatalogNameArray()); return cs; } Routine readCreateProcedureOrFunction() { Routine routine = readProcedureOrFunctionDeclaration(); readRoutineBody(routine); routine.resolve(session); return routine; } Routine readProcedureOrFunctionDeclaration() { int routineType; boolean isAggregate = false; if (token.tokenType == Tokens.AGGREGATE) { isAggregate = true; read(); if (token.tokenType == Tokens.PROCEDURE) { throw unexpectedToken(); } } routineType = token.tokenType == Tokens.PROCEDURE ? SchemaObject.PROCEDURE : SchemaObject.FUNCTION; HsqlName name; read(); name = readNewSchemaObjectName(routineType, true); name.setSchemaIfNull(session.getCurrentSchemaHsqlName()); Routine routine = new Routine(routineType); routine.setName(name); routine.setAggregate(isAggregate); readRoutineArguments(routine); if (routineType != SchemaObject.PROCEDURE) { readThis(Tokens.RETURNS); if (token.tokenType == Tokens.TABLE) { read(); TableDerived table = new TableDerived(database, SqlInvariants.MODULE_HSQLNAME, TableBase.FUNCTION_TABLE); readTableDefinition(routine, table); routine.setReturnTable(table); } else { Type type = readTypeDefinition(false, true); routine.setReturnType(type); } } readRoutineCharacteristics(routine); return routine; } void readRoutineArguments(Routine routine) { readThis(Tokens.OPENBRACKET); if (token.tokenType == Tokens.CLOSEBRACKET) { read(); } else { while (true) { ColumnSchema newcolumn = readRoutineParameter(routine, true); routine.addParameter(newcolumn); if (token.tokenType == Tokens.COMMA) { read(); } else { readThis(Tokens.CLOSEBRACKET); break; } } } } Routine readCreatePasswordCheckFunction() { Routine routine = new Routine(SchemaObject.FUNCTION); if (token.tokenType == Tokens.NONE) { read(); return null; } else if (token.tokenType == Tokens.EXTERNAL) { routine.setLanguage(Routine.LANGUAGE_JAVA); routine.setDataImpact(Routine.NO_SQL); } else { routine.setLanguage(Routine.LANGUAGE_SQL); routine.setDataImpact(Routine.CONTAINS_SQL); } HsqlName hsqlName = database.nameManager.newHsqlName(Tokens.T_PASSWORD, false, SchemaObject.FUNCTION); hsqlName.setSchemaIfNull(SqlInvariants.SYSTEM_SCHEMA_HSQLNAME); routine.setName(hsqlName); hsqlName = database.nameManager.newHsqlName(Tokens.T_PASSWORD, false, SchemaObject.PARAMETER); ColumnSchema column = new ColumnSchema(hsqlName, Type.SQL_VARCHAR, false, false, null); routine.addParameter(column); routine.setReturnType(Type.SQL_BOOLEAN); readRoutineBody(routine); routine.resolve(session); return routine; } Routine readCreateDatabaseAuthenticationFunction() { Routine routine = new Routine(SchemaObject.FUNCTION); if (token.tokenType == Tokens.NONE) { read(); return null; } checkIsThis(Tokens.EXTERNAL); routine.setLanguage(Routine.LANGUAGE_JAVA); routine.setDataImpact(Routine.NO_SQL); routine.setName( database.nameManager.newHsqlName( Tokens.T_AUTHENTICATION, false, SchemaObject.FUNCTION)); for (int i = 0; i < 3; i++) { ColumnSchema column = new ColumnSchema(null, Type.SQL_VARCHAR, false, false, null); routine.addParameter(column); } routine.setReturnType( new ArrayType( Type.SQL_VARCHAR_DEFAULT, ArrayType.defaultArrayCardinality)); readRoutineBody(routine); routine.resolve(session); return routine; } private void readTableDefinition(Routine routine, Table table) { readThis(Tokens.OPENBRACKET); for (int i = 0; ; i++) { ColumnSchema newcolumn = readRoutineParameter(routine, false); if (newcolumn.getName() == null) { throw unexpectedToken(); } table.addColumn(newcolumn); if (token.tokenType == Tokens.COMMA) { read(); } else { readThis(Tokens.CLOSEBRACKET); break; } } table.createPrimaryKey(); } private void readRoutineCharacteristics(Routine routine) { OrderedIntHashSet set = new OrderedIntHashSet(); boolean end = false; while (!end) { switch (token.tokenType) { case Tokens.LANGUAGE : { if (!set.add(Tokens.LANGUAGE)) { throw unexpectedToken(); } read(); if (token.tokenType == Tokens.JAVA) { read(); routine.setLanguage(Routine.LANGUAGE_JAVA); } else if (token.tokenType == Tokens.SQL) { read(); routine.setLanguage(Routine.LANGUAGE_SQL); } else { throw unexpectedToken(); } break; } case Tokens.PARAMETER : { if (!set.add(Tokens.PARAMETER)) { throw unexpectedToken(); } read(); readThis(Tokens.STYLE); if (token.tokenType == Tokens.JAVA) { read(); routine.setParameterStyle(Routine.PARAM_STYLE_JAVA); } else { readThis(Tokens.SQL); routine.setParameterStyle(Routine.PARAM_STYLE_SQL); } break; } case Tokens.SPECIFIC : { if (!set.add(Tokens.SPECIFIC)) { throw unexpectedToken(); } read(); HsqlName name = readNewSchemaObjectName(SchemaObject.SPECIFIC_ROUTINE, false); routine.setSpecificName(name); break; } case Tokens.DETERMINISTIC : { if (!set.add(Tokens.DETERMINISTIC)) { throw unexpectedToken(); } read(); routine.setDeterministic(true); break; } case Tokens.NOT : { if (!set.add(Tokens.DETERMINISTIC)) { throw unexpectedToken(); } read(); readThis(Tokens.DETERMINISTIC); routine.setDeterministic(false); break; } case Tokens.MODIFIES : { if (!set.add(Tokens.SQL)) { throw unexpectedToken(); } if (routine.getType() == SchemaObject.FUNCTION) { throw unexpectedToken(); } read(); readThis(Tokens.SQL); readThis(Tokens.DATA); routine.setDataImpact(Routine.MODIFIES_SQL); break; } case Tokens.NO : { if (!set.add(Tokens.SQL)) { throw unexpectedToken(); } read(); readThis(Tokens.SQL); routine.setDataImpact(Routine.NO_SQL); break; } case Tokens.READS : { if (!set.add(Tokens.SQL)) { throw unexpectedToken(); } read(); readThis(Tokens.SQL); readThis(Tokens.DATA); routine.setDataImpact(Routine.READS_SQL); break; } case Tokens.CONTAINS : { if (!set.add(Tokens.SQL)) { throw unexpectedToken(); } read(); readThis(Tokens.SQL); routine.setDataImpact(Routine.CONTAINS_SQL); break; } case Tokens.RETURNS : { if (!set.add(Tokens.NULL) || routine.isProcedure()) { throw unexpectedToken(); } if (routine.isAggregate()) { throw Error.error(ErrorCode.X_42604, token.tokenString); } read(); readThis(Tokens.NULL); readThis(Tokens.ON); readThis(Tokens.NULL); readThis(Tokens.INPUT); routine.setNullInputOutput(true); break; } case Tokens.CALLED : { if (!set.add(Tokens.NULL) || routine.isProcedure()) { throw unexpectedToken(); } read(); readThis(Tokens.ON); readThis(Tokens.NULL); readThis(Tokens.INPUT); routine.setNullInputOutput(false); break; } case Tokens.DYNAMIC : { if (!set.add(Tokens.RESULT) || routine.isFunction()) { throw unexpectedToken(); } read(); readThis(Tokens.RESULT); readThis(Tokens.SETS); int results = readInteger(); if (results < 0 || results > 16) { throw Error.error(ErrorCode.X_42604, String.valueOf(results)); } routine.setMaxDynamicResults(results); break; } case Tokens.NEW : { if (routine.getType() == SchemaObject.FUNCTION || !set.add(Tokens.SAVEPOINT)) { throw unexpectedToken(); } read(); readThis(Tokens.SAVEPOINT); readThis(Tokens.LEVEL); routine.setNewSavepointLevel(true); break; } case Tokens.OLD : { if (routine.getType() == SchemaObject.FUNCTION || !set.add(Tokens.SAVEPOINT)) { throw unexpectedToken(); } read(); readThis(Tokens.SAVEPOINT); readThis(Tokens.LEVEL); routine.setNewSavepointLevel(false); throw unsupportedFeature(Tokens.T_OLD); // break; } default : end = true; break; } } } void readRoutineBody(Routine routine) { if (token.tokenType == Tokens.EXTERNAL) { readRoutineJavaBody(routine); } else { readRoutineSQLBody(routine); } } void readRoutineSQLBody(Routine routine) { startRecording(); session.sessionContext.pushRoutineTables(); try { Statement statement = compileSQLProcedureStatementOrNull(routine, null); if (statement == null) { throw unexpectedToken(); } Token[] tokenisedStatement = getRecordedStatement(); String sql = Token.getSQL(tokenisedStatement); statement.setSQL(sql); routine.setProcedure(statement); } finally { session.sessionContext.popRoutineTables(); } } void readRoutineJavaBody(Routine routine) { if (routine.getLanguage() != Routine.LANGUAGE_JAVA) { throw unexpectedToken(); } read(); readThis(Tokens.NAME); checkIsQuotedString(); routine.setMethodURL((String) token.tokenValue); read(); if (token.tokenType == Tokens.PARAMETER) { read(); readThis(Tokens.STYLE); readThis(Tokens.JAVA); } } /* <SQL control statement> ::= <call statement> | <return statement> <compound statement> <case statement> <if statement> <iterate statement> <leave statement> <loop statement> <while statement> <repeat statement> <for statement> <assignment statement> SET (,,,) = (,,,) or SET a = b */ Object[] readLocalDeclarationList(Routine routine, StatementCompound context) { HsqlArrayList list = new HsqlArrayList(); final int table = 0; final int variableOrCondition = 1; final int cursor = 2; final int handler = 3; int objectType = table; RangeGroup[] rangeGroups = new RangeGroup[1]; rangeGroups[0] = context == null ? routine : context; compileContext.setOuterRanges(rangeGroups); while (token.tokenType == Tokens.DECLARE) { Object var = null; if (objectType == table) { var = readLocalTableVariableDeclarationOrNull(routine); if (var == null) { objectType = variableOrCondition; } else { list.add(var); readThis(Tokens.SEMICOLON); } } else if (objectType == variableOrCondition) { var = readLocalVariableDeclarationOrNull(); if (var == null) { objectType = cursor; } else { list.addAll((Object[]) var); } } else if (objectType == cursor) { var = compileDeclareCursorOrNull(rangeGroups, true); if (var == null) { objectType = handler; } else { list.add(var); readThis(Tokens.SEMICOLON); } } else if (objectType == handler) { var = compileLocalHandlerDeclaration(routine, context); list.add(var); } } Object[] declarations = new Object[list.size()]; list.toArray(declarations); return declarations; } Table readLocalTableVariableDeclarationOrNull(Routine routine) { int position = getPosition(); readThis(Tokens.DECLARE); if (token.tokenType == Tokens.TABLE) { read(); HsqlName name = readNewSchemaObjectName(SchemaObject.TABLE, false); name.schema = SqlInvariants.MODULE_HSQLNAME; Table table = new Table(database, name, TableBase.TEMP_TABLE); table.persistenceScope = TableBase.SCOPE_ROUTINE; readTableDefinition(routine, table); session.sessionContext.addSessionTable(table); return table; } else { rewind(position); return null; } } ColumnSchema[] readLocalVariableDeclarationOrNull() { int position = getPosition(); Type type; HsqlArrayList names = new HsqlArrayList(); try { readThis(Tokens.DECLARE); if (isReservedKey()) { rewind(position); return null; } while (true) { HsqlName name = readNewSchemaObjectName(SchemaObject.VARIABLE, false); if (token.tokenType == Tokens.CONDITION) { rewind(position); return null; } names.add(name); if (token.tokenType == Tokens.COMMA) { read(); } else { break; } } type = readTypeDefinition(false, true); } catch (HsqlException e) { // may be cursor rewind(position); return null; } Expression def = null; if (token.tokenType == Tokens.DEFAULT) { read(); def = readDefaultClause(type); } ColumnSchema[] variable = new ColumnSchema[names.size()]; for (int i = 0; i < names.size(); i++) { variable[i] = new ColumnSchema((HsqlName) names.get(i), type, true, false, def); variable[i].setParameterMode( SchemaObject.ParameterModes.PARAM_INOUT); } readThis(Tokens.SEMICOLON); return variable; } private StatementHandler compileLocalHandlerDeclaration(Routine routine, StatementCompound context) { int handlerType; readThis(Tokens.DECLARE); switch (token.tokenType) { case Tokens.CONTINUE : read(); handlerType = StatementHandler.CONTINUE; break; case Tokens.EXIT : read(); handlerType = StatementHandler.EXIT; break; case Tokens.UNDO : read(); handlerType = StatementHandler.UNDO; break; default : throw unexpectedToken(); } readThis(Tokens.HANDLER); readThis(Tokens.FOR); StatementHandler handler = new StatementHandler(handlerType); boolean end = false; boolean start = true; while (!end) { int conditionType = StatementHandler.NONE; switch (token.tokenType) { case Tokens.COMMA : if (start) { throw unexpectedToken(); } read(); start = true; break; case Tokens.SQLSTATE : conditionType = StatementHandler.SQL_STATE; // fall through case Tokens.SQLEXCEPTION : if (conditionType == StatementHandler.NONE) { conditionType = StatementHandler.SQL_EXCEPTION; } // fall through case Tokens.SQLWARNING : if (conditionType == StatementHandler.NONE) { conditionType = StatementHandler.SQL_WARNING; } // fall through case Tokens.NOT : if (conditionType == StatementHandler.NONE) { conditionType = StatementHandler.SQL_NOT_FOUND; } if (!start) { throw unexpectedToken(); } start = false; read(); if (conditionType == StatementHandler.SQL_NOT_FOUND) { readThis(Tokens.FOUND); } else if (conditionType == StatementHandler.SQL_STATE) { String sqlState = parseSQLStateValue(); handler.addConditionState(sqlState); break; } handler.addConditionType(conditionType); break; default : if (start) { throw unexpectedToken(); } end = true; break; } } if (token.tokenType == Tokens.SEMICOLON) { read(); } else { Statement e = compileSQLProcedureStatementOrNull(routine, context); if (e == null) { throw unexpectedToken(); } readThis(Tokens.SEMICOLON); handler.addStatement(e); } return handler; } String parseSQLStateValue() { readIfThis(Tokens.VALUE); checkIsQuotedString(); String sqlState = token.tokenString; if (sqlState.length() != 5) { throw Error.parseError(ErrorCode.X_42607, null, scanner.getLineNumber()); } read(); return sqlState; } static String[] featureStrings = new String[]{ "H901_03" }; String parseSQLFeatureValue() { if (!isUndelimitedSimpleName()) { throw Error.parseError(ErrorCode.X_42555, token.tokenString, scanner.getLineNumber()); } String sqlFeature = token.tokenString; int index = ArrayUtil.find(featureStrings, sqlFeature); if (index < 0) { throw Error.parseError(ErrorCode.X_42555, token.tokenString, scanner.getLineNumber()); } read(); return sqlFeature; } Statement compileCompoundStatement(Routine routine, StatementCompound context, HsqlName label) { final boolean atomic = true; readThis(Tokens.BEGIN); readThis(Tokens.ATOMIC); label = createLabelIfNull(context, label); StatementCompound statement = new StatementCompound(StatementTypes.BEGIN_END, label, context); statement.setAtomic(atomic); statement.setRoot(routine); Object[] declarations = readLocalDeclarationList(routine, context); statement.setLocalDeclarations(declarations); Statement[] statements = compileSQLProcedureStatementList(routine, statement); statement.setStatements(statements); readThis(Tokens.END); if (isSimpleName() && !isReservedKey()) { if (label == null) { throw unexpectedToken(); } if (!label.name.equals(token.tokenString)) { throw Error.error(ErrorCode.X_42508, token.tokenString); } read(); } return statement; } HsqlName createLabelIfNull(StatementCompound context, HsqlName label) { if (label != null) { return label; } String labelString; StatementCompound parent = context; int level = 0; while (parent != null) { level++; parent = parent.parent; } labelString = "_" + level; label = session.database.nameManager.newHsqlName(labelString, false, SchemaObject.LABEL); return label; } Statement[] compileSQLProcedureStatementList(Routine routine, StatementCompound context) { Statement e; HsqlArrayList list = new HsqlArrayList(); while (true) { e = compileSQLProcedureStatementOrNull(routine, context); if (e == null) { break; } readThis(Tokens.SEMICOLON); list.add(e); } if (list.size() == 0) { throw unexpectedToken(); } Statement[] statements = new Statement[list.size()]; list.toArray(statements); return statements; } Statement compileSQLProcedureStatementOrNull(Routine routine, StatementCompound context) { Statement cs = null; HsqlName label = null; RangeGroup rangeGroup = context == null ? routine : context; RangeGroup[] rangeGroups = new RangeGroup[]{ rangeGroup }; if (!routine.isTrigger() && isSimpleName() && !isReservedKey()) { label = readLabel(); } compileContext.reset(); HsqlName oldSchema = session.getCurrentSchemaHsqlName(); session.setCurrentSchemaHsqlName(routine.getSchemaName()); try { switch (token.tokenType) { // data case Tokens.OPEN : { if (routine.dataImpact == Routine.CONTAINS_SQL) { throw Error.error(ErrorCode.X_42602, routine.getDataImpactString()); } if (label != null) { throw unexpectedToken(); } cs = compileOpenCursorStatement(context); break; } case Tokens.SELECT : { if (label != null) { throw unexpectedToken(); } cs = compileSelectSingleRowStatement(rangeGroups); break; } // data change case Tokens.INSERT : if (label != null) { throw unexpectedToken(); } cs = compileInsertStatement(rangeGroups); break; case Tokens.UPDATE : if (label != null) { throw unexpectedToken(); } cs = compileUpdateStatement(rangeGroups); break; case Tokens.DELETE : if (label != null) { throw unexpectedToken(); } cs = compileDeleteStatement(rangeGroups); break; case Tokens.TRUNCATE : if (label != null) { throw unexpectedToken(); } cs = compileTruncateStatement(); break; case Tokens.MERGE : if (label != null) { throw unexpectedToken(); } cs = compileMergeStatement(rangeGroups); break; case Tokens.SET : if (label != null) { throw unexpectedToken(); } read(); if (routine.isTrigger()) { if (routine.triggerType == TriggerDef.BEFORE && routine.triggerOperation != StatementTypes.DELETE_WHERE) { int position = getPosition(); try { cs = compileTriggerSetStatement( routine.triggerTable, rangeGroups); break; } catch (HsqlException e) { rewind(position); cs = compileSetStatement( rangeGroups, rangeGroup.getRangeVariables()); } } else { cs = compileSetStatement( rangeGroups, rangeGroup.getRangeVariables()); } ((StatementSet) cs).checkIsNotColumnTarget(); } else { cs = compileSetStatement( rangeGroups, rangeGroup.getRangeVariables()); } break; case Tokens.GET : if (label != null) { throw unexpectedToken(); } cs = compileGetStatement(rangeGroups); break; // control case Tokens.CALL : { if (label != null) { throw unexpectedToken(); } cs = compileCallStatement(rangeGroups, true); Routine proc = ((StatementProcedure) cs).procedure; if (proc != null) { switch (routine.dataImpact) { case Routine.CONTAINS_SQL : { if (proc.dataImpact == Routine.READS_SQL || proc.dataImpact == Routine.MODIFIES_SQL) { throw Error.error( ErrorCode.X_42602, routine.getDataImpactString()); } break; } case Routine.READS_SQL : { if (proc.dataImpact == Routine.MODIFIES_SQL) { throw Error.error( ErrorCode.X_42602, routine.getDataImpactString()); } break; } } } break; } case Tokens.RETURN : { if (routine.isTrigger() || label != null) { throw unexpectedToken(); } read(); cs = compileReturnValue(routine, context); break; } case Tokens.BEGIN : { cs = compileCompoundStatement(routine, context, label); break; } case Tokens.WHILE : { if (routine.isTrigger()) { throw unexpectedToken(); } cs = compileWhile(routine, context, label); break; } case Tokens.REPEAT : { cs = compileRepeat(routine, context, label); break; } case Tokens.LOOP : { cs = compileLoop(routine, context, label); break; } case Tokens.FOR : { cs = compileFor(routine, context, label); break; } case Tokens.ITERATE : { if (label != null) { throw unexpectedToken(); } cs = compileIterate(); break; } case Tokens.LEAVE : { if (label != null) { throw unexpectedToken(); } cs = compileLeave(routine, context); break; } case Tokens.IF : { cs = compileIf(routine, context); break; } case Tokens.CASE : { cs = compileCase(routine, context); break; } case Tokens.SIGNAL : { cs = compileSignal(routine, context, label); break; } case Tokens.RESIGNAL : { cs = compileResignal(routine, context, label); break; } default : return null; } cs.setRoot(routine); cs.setParent(context); return cs; } finally { session.setCurrentSchemaHsqlName(oldSchema); } } HsqlName readLabel() { HsqlName label = readNewSchemaObjectName(SchemaObject.LABEL, false); if (token.tokenType != Tokens.COLON) { throw unexpectedToken(label.getNameString()); } readThis(Tokens.COLON); return label; } Statement compileReturnValue(Routine routine, StatementCompound context) { RangeGroup[] rangeGroups = new RangeGroup[1]; rangeGroups[0] = context == null ? routine : context; compileContext.setOuterRanges(rangeGroups); Expression e = XreadValueExpression(); if (e == null) { throw unexpectedToken(); } resolveOuterReferencesAndTypes(routine, context, e); if (routine.isProcedure()) { throw Error.parseError(ErrorCode.X_42602, null, scanner.getLineNumber()); } if (routine.returnsTable()) { if (e.getType() != OpTypes.TABLE_SUBQUERY) { throw Error.parseError(ErrorCode.X_42611, null, scanner.getLineNumber()); } } Type returnType = new RowType(e.getNodeDataTypes()); Type declaredType = routine.getReturnType(); if (!declaredType.isRowType()) { declaredType = new RowType(new Type[]{ routine.getReturnType() }); } if (declaredType.getDegree() != returnType.getDegree()) { throw Error.parseError(ErrorCode.X_42564, null, scanner.getLineNumber()); } if (!declaredType.canBeAssignedFrom(returnType)) { throw Error.parseError(ErrorCode.X_42611, null, scanner.getLineNumber()); } return new StatementExpression(session, compileContext, StatementTypes.RETURN, e); } Statement compileIterate() { readThis(Tokens.ITERATE); HsqlName label = readNewSchemaObjectName(SchemaObject.LABEL, false); return new StatementSimple(StatementTypes.ITERATE, label); } Statement compileLeave(Routine routine, StatementCompound context) { readThis(Tokens.LEAVE); HsqlName label = readNewSchemaObjectName(SchemaObject.LABEL, false); return new StatementSimple(StatementTypes.LEAVE, label); } Statement compileWhile(Routine routine, StatementCompound context, HsqlName label) { readThis(Tokens.WHILE); Expression e = XreadBooleanValueExpression(); resolveOuterReferencesAndTypes(routine, context, e); StatementExpression condition = new StatementExpression(session, compileContext, StatementTypes.CONDITION, e); readThis(Tokens.DO); Statement[] statements = compileSQLProcedureStatementList(routine, context); readThis(Tokens.END); readThis(Tokens.WHILE); if (isSimpleName() && !isReservedKey()) { if (label == null) { throw unexpectedToken(); } if (!label.name.equals(token.tokenString)) { throw Error.error(ErrorCode.X_42508, token.tokenString); } read(); } StatementCompound statement = new StatementCompound(StatementTypes.WHILE, label, context); statement.setStatements(statements); statement.setCondition(condition); return statement; } Statement compileRepeat(Routine routine, StatementCompound context, HsqlName label) { readThis(Tokens.REPEAT); Statement[] statements = compileSQLProcedureStatementList(routine, context); readThis(Tokens.UNTIL); Expression e = XreadBooleanValueExpression(); resolveOuterReferencesAndTypes(routine, context, e); StatementExpression condition = new StatementExpression(session, compileContext, StatementTypes.CONDITION, e); readThis(Tokens.END); readThis(Tokens.REPEAT); if (isSimpleName() && !isReservedKey()) { if (label == null) { throw unexpectedToken(); } if (!label.name.equals(token.tokenString)) { throw Error.error(ErrorCode.X_42508, token.tokenString); } read(); } StatementCompound statement = new StatementCompound(StatementTypes.REPEAT, label, context); statement.setStatements(statements); statement.setCondition(condition); return statement; } Statement compileLoop(Routine routine, StatementCompound context, HsqlName label) { readThis(Tokens.LOOP); Statement[] statements = compileSQLProcedureStatementList(routine, context); readThis(Tokens.END); readThis(Tokens.LOOP); if (isSimpleName() && !isReservedKey()) { if (label == null) { throw unexpectedToken(); } if (!label.name.equals(token.tokenString)) { throw Error.error(ErrorCode.X_42508, token.tokenString); } read(); } StatementCompound result = new StatementCompound(StatementTypes.LOOP, label, context); result.setStatements(statements); return result; } Statement compileFor(Routine routine, StatementCompound context, HsqlName label) { RangeGroup[] rangeGroups = new RangeGroup[1]; rangeGroups[0] = context == null ? routine : context; compileContext.setOuterRanges(rangeGroups); readThis(Tokens.FOR); StatementQuery cursorStatement = compileCursorSpecification(rangeGroups, ResultProperties.defaultPropsValue, false); readThis(Tokens.DO); StatementCompound forStatement = new StatementCompound(StatementTypes.FOR, label, context); forStatement.setAtomic(true); forStatement.setRoot(routine); forStatement.setLoopStatement(null, cursorStatement); Statement[] statements = compileSQLProcedureStatementList(routine, forStatement); readThis(Tokens.END); readThis(Tokens.FOR); if (isSimpleName() && !isReservedKey()) { if (label == null) { throw unexpectedToken(); } if (!label.name.equals(token.tokenString)) { throw Error.error(ErrorCode.X_42508, token.tokenString); } read(); } forStatement.setStatements(statements); return forStatement; } Statement compileIf(Routine routine, StatementCompound context) { HsqlArrayList list = new HsqlArrayList(); readThis(Tokens.IF); Expression e = XreadBooleanValueExpression(); resolveOuterReferencesAndTypes(routine, context, e); Statement statement = new StatementExpression(session, compileContext, StatementTypes.CONDITION, e); list.add(statement); readThis(Tokens.THEN); Statement[] statements = compileSQLProcedureStatementList(routine, context); for (int i = 0; i < statements.length; i++) { list.add(statements[i]); } while (token.tokenType == Tokens.ELSEIF) { read(); e = XreadBooleanValueExpression(); resolveOuterReferencesAndTypes(routine, context, e); statement = new StatementExpression(session, compileContext, StatementTypes.CONDITION, e); list.add(statement); readThis(Tokens.THEN); statements = compileSQLProcedureStatementList(routine, context); for (int i = 0; i < statements.length; i++) { list.add(statements[i]); } } if (token.tokenType == Tokens.ELSE) { read(); e = Expression.EXPR_TRUE; statement = new StatementExpression(session, compileContext, StatementTypes.CONDITION, e); list.add(statement); statements = compileSQLProcedureStatementList(routine, context); for (int i = 0; i < statements.length; i++) { list.add(statements[i]); } } readThis(Tokens.END); readThis(Tokens.IF); statements = new Statement[list.size()]; list.toArray(statements); StatementCompound result = new StatementCompound(StatementTypes.IF, null, context); result.setStatements(statements); return result; } Statement compileCase(Routine routine, StatementCompound context) { HsqlArrayList list; Expression condition = null; Statement statement; Statement[] statements; readThis(Tokens.CASE); if (token.tokenType == Tokens.WHEN) { list = readCaseWhen(routine, context); } else { list = readSimpleCaseWhen(routine, context); } if (token.tokenType == Tokens.ELSE) { read(); condition = Expression.EXPR_TRUE; statement = new StatementExpression(session, compileContext, StatementTypes.CONDITION, condition); list.add(statement); statements = compileSQLProcedureStatementList(routine, context); for (int i = 0; i < statements.length; i++) { list.add(statements[i]); } } readThis(Tokens.END); readThis(Tokens.CASE); statements = new Statement[list.size()]; list.toArray(statements); StatementCompound result = new StatementCompound(StatementTypes.IF, null, context); result.setStatements(statements); return result; } HsqlArrayList readSimpleCaseWhen(Routine routine, StatementCompound context) { HsqlArrayList list = new HsqlArrayList(); Expression condition = null; Statement statement; Statement[] statements; Expression predicand = XreadRowValuePredicand(); do { readThis(Tokens.WHEN); do { Expression newCondition = XreadPredicateRightPart(predicand); if (predicand == newCondition) { newCondition = new ExpressionLogical(predicand, XreadRowValuePredicand()); } resolveOuterReferencesAndTypes(routine, context, newCondition); if (condition == null) { condition = newCondition; } else { condition = new ExpressionLogical(OpTypes.OR, condition, newCondition); } if (token.tokenType == Tokens.COMMA) { read(); } else { break; } } while (true); statement = new StatementExpression(session, compileContext, StatementTypes.CONDITION, condition); list.add(statement); readThis(Tokens.THEN); statements = compileSQLProcedureStatementList(routine, context); for (int i = 0; i < statements.length; i++) { list.add(statements[i]); } if (token.tokenType != Tokens.WHEN) { break; } } while (true); return list; } HsqlArrayList readCaseWhen(Routine routine, StatementCompound context) { HsqlArrayList list = new HsqlArrayList(); Expression condition = null; Statement statement; Statement[] statements; do { readThis(Tokens.WHEN); condition = XreadBooleanValueExpression(); resolveOuterReferencesAndTypes(routine, context, condition); statement = new StatementExpression(session, compileContext, StatementTypes.CONDITION, condition); list.add(statement); readThis(Tokens.THEN); statements = compileSQLProcedureStatementList(routine, context); for (int i = 0; i < statements.length; i++) { list.add(statements[i]); } if (token.tokenType != Tokens.WHEN) { break; } } while (true); return list; } Statement compileSignal(Routine routine, StatementCompound context, HsqlName label) { String sqlState; Expression message = null; readThis(Tokens.SIGNAL); readThis(Tokens.SQLSTATE); sqlState = parseSQLStateValue(); if (readIfThis(Tokens.SET)) { readThis(Tokens.MESSAGE_TEXT); readThis(Tokens.EQUALS_OP); message = XreadSimpleValueSpecificationOrNull(); if (message == null) { throw unexpectedToken(); } resolveOuterReferencesAndTypes(routine, context, message); } StatementSignal cs = new StatementSignal(StatementTypes.SIGNAL, sqlState, message); return cs; } private Statement compileResignal(Routine routine, StatementCompound context, HsqlName label) { String sqlState = null; Expression message = null; readThis(Tokens.RESIGNAL); if (readIfThis(Tokens.SQLSTATE)) { sqlState = parseSQLStateValue(); if (readIfThis(Tokens.SET)) { readThis(Tokens.MESSAGE_TEXT); readThis(Tokens.EQUALS_OP); message = XreadSimpleValueSpecificationOrNull(); if (message == null) { throw unexpectedToken(); } resolveOuterReferencesAndTypes(routine, context, message); } } StatementSignal cs = new StatementSignal(StatementTypes.RESIGNAL, sqlState, message); return cs; } ColumnSchema readRoutineParameter(Routine routine, boolean isParam) { HsqlName hsqlName = null; int parameterMode = readRoutineParameterMode(routine.routineType, routine.isAggregate); if (!isReservedKey()) { hsqlName = readNewDependentSchemaObjectName(routine.getName(), SchemaObject.PARAMETER); } Type typeObject = readTypeDefinition(false, true); ColumnSchema column = new ColumnSchema(hsqlName, typeObject, true, false, null); if (isParam) { column.setParameterMode((byte) parameterMode); } return column; } int readRoutineParameterMode(int routineType, boolean isAggregate) { int parameterMode = SchemaObject.ParameterModes.PARAM_IN; switch (token.tokenType) { case Tokens.IN : read(); break; case Tokens.OUT : if (routineType != SchemaObject.PROCEDURE) { throw unexpectedToken(); } read(); parameterMode = SchemaObject.ParameterModes.PARAM_OUT; break; case Tokens.INOUT : if (routineType != SchemaObject.PROCEDURE) { if (!isAggregate) { throw unexpectedToken(); } } read(); parameterMode = SchemaObject.ParameterModes.PARAM_INOUT; break; default : } return parameterMode; } void resolveOuterReferencesAndTypes(Routine routine, StatementCompound context, Expression e) { RangeGroup rangeGroup = context == null ? routine : context; resolveOuterReferencesAndTypes(new RangeGroup[]{ rangeGroup }, e); } StatementSchema compileCreateTrigger(boolean orReplace) { Table table; Boolean isForEachRow = null; boolean isNowait = false; boolean hasQueueSize = false; int queueSize = 0; int beforeOrAfterType; int operationType; String className; TriggerDef td; HsqlName name; HsqlName otherName = null; OrderedHashSet columns = null; int[] updateColumnIndexes = null; read(); Boolean ifNotExists = readIfNotExists(); name = readNewSchemaObjectName(SchemaObject.TRIGGER, true); switch (token.tokenType) { case Tokens.INSTEAD : beforeOrAfterType = TriggerDef.getTiming(Tokens.INSTEAD); read(); readThis(Tokens.OF); break; case Tokens.BEFORE : case Tokens.AFTER : beforeOrAfterType = TriggerDef.getTiming(token.tokenType); read(); break; default : throw unexpectedToken(); } switch (token.tokenType) { case Tokens.INSERT : case Tokens.DELETE : operationType = TriggerDef.getOperationType(token.tokenType); read(); break; case Tokens.UPDATE : operationType = TriggerDef.getOperationType(token.tokenType); read(); if (token.tokenType == Tokens.OF && beforeOrAfterType != TriggerDef.INSTEAD) { read(); columns = new OrderedHashSet(); readColumnNameList(columns, null, false); } break; default : throw unexpectedToken(); } readThis(Tokens.ON); table = readTableName(); if (token.tokenType == Tokens.BEFORE) { read(); checkIsSimpleName(); otherName = readNewSchemaObjectName(SchemaObject.TRIGGER, true); } name.setSchemaIfNull(table.getSchemaName()); checkSchemaUpdateAuthorisation(name.schema); if (beforeOrAfterType == TriggerDef.INSTEAD) { if (!table.isView() || ((View) table).getCheckOption() == SchemaObject.ViewCheckModes.CHECK_CASCADE) { throw Error.error(ErrorCode.X_42538, name.schema.name); } } else { if (table.isView()) { throw Error.error(ErrorCode.X_42538, name.schema.name); } } if (name.schema != table.getSchemaName()) { throw Error.error(ErrorCode.X_42505, name.schema.name); } name.parent = table.getName(); database.schemaManager.checkSchemaObjectNotExists(name); if (columns != null) { updateColumnIndexes = table.getColumnIndexes(columns); for (int i = 0; i < updateColumnIndexes.length; i++) { if (updateColumnIndexes[i] == -1) { throw Error.error(ErrorCode.X_42544, (String) columns.get(i)); } } } Expression condition = null; SimpleName oldTableName = null; SimpleName newTableName = null; SimpleName oldRowName = null; SimpleName newRowName = null; Table[] transitions = new Table[4]; RangeVariable[] rangeVars = new RangeVariable[4]; String conditionSQL = null; RangeGroup[] rangeGroups = new RangeGroup[]{ new RangeGroup.RangeGroupSimple(rangeVars, false) }; if (token.tokenType == Tokens.REFERENCING) { read(); if (token.tokenType != Tokens.OLD && token.tokenType != Tokens.NEW) { throw unexpectedToken(); } while (true) { if (token.tokenType == Tokens.OLD) { if (operationType == StatementTypes.INSERT) { throw unexpectedToken(); } read(); if (token.tokenType == Tokens.TABLE) { if (Boolean.TRUE.equals(isForEachRow) || oldTableName != null || beforeOrAfterType == TriggerDef.BEFORE) { throw unexpectedToken(); } read(); readIfThis(Tokens.AS); checkIsSimpleName(); read(); oldTableName = HsqlNameManager.getSimpleName( token.tokenString, token.isDelimitedIdentifier); SimpleName n = oldTableName; if (n.equals(newTableName) || n.equals(oldRowName) || n.equals(newRowName)) { throw unexpectedToken(); } isForEachRow = Boolean.FALSE; HsqlName hsqlName = database.nameManager.newHsqlName( table.getSchemaName(), n.name, isDelimitedIdentifier(), SchemaObject.TRANSITION); Table transition = new Table(table, hsqlName); RangeVariable range = new RangeVariable(transition, null, null, null, compileContext); transitions[TriggerDef.OLD_TABLE] = transition; rangeVars[TriggerDef.OLD_TABLE] = range; } else { if (Boolean.FALSE.equals(isForEachRow) || oldRowName != null) { throw unexpectedToken(); } readIfThis(Tokens.ROW); readIfThis(Tokens.AS); checkIsSimpleName(); oldRowName = HsqlNameManager.getSimpleName( token.tokenString, token.isDelimitedIdentifier); read(); SimpleName n = oldRowName; if (n.equals(newTableName) || n.equals(oldTableName) || n.equals(newRowName)) { throw unexpectedToken(); } isForEachRow = Boolean.TRUE; RangeVariable range = new RangeVariable(table.columnList, oldRowName, false, RangeVariable.TRANSITION_RANGE); range.rangePosition = TriggerDef.OLD_ROW; transitions[TriggerDef.OLD_ROW] = null; rangeVars[TriggerDef.OLD_ROW] = range; } } else if (token.tokenType == Tokens.NEW) { if (operationType == StatementTypes.DELETE_WHERE) { throw unexpectedToken(); } read(); if (token.tokenType == Tokens.TABLE) { if (Boolean.TRUE.equals(isForEachRow) || newTableName != null || beforeOrAfterType == TriggerDef.BEFORE) { throw unexpectedToken(); } read(); readIfThis(Tokens.AS); checkIsSimpleName(); newTableName = HsqlNameManager.getSimpleName( token.tokenString, token.isDelimitedIdentifier); read(); isForEachRow = Boolean.FALSE; SimpleName n = newTableName; if (n.equals(oldTableName) || n.equals(oldRowName) || n.equals(newRowName)) { throw unexpectedToken(); } HsqlName hsqlName = database.nameManager.newHsqlName( table.getSchemaName(), n.name, isDelimitedIdentifier(), SchemaObject.TRANSITION); Table transition = new Table(table, hsqlName); RangeVariable range = new RangeVariable(transition, null, null, null, compileContext); transitions[TriggerDef.NEW_TABLE] = transition; rangeVars[TriggerDef.NEW_TABLE] = range; } else { if (Boolean.FALSE.equals(isForEachRow) || newRowName != null) { throw unexpectedToken(); } readIfThis(Tokens.ROW); readIfThis(Tokens.AS); checkIsSimpleName(); newRowName = HsqlNameManager.getSimpleName( token.tokenString, token.isDelimitedIdentifier); read(); SimpleName n = newRowName; if (n.equals(oldTableName) || n.equals(newTableName) || n.equals(oldRowName)) { throw unexpectedToken(); } isForEachRow = Boolean.TRUE; RangeVariable range = new RangeVariable(table.columnList, newRowName, false, RangeVariable.TRANSITION_RANGE); range.rangePosition = TriggerDef.NEW_ROW; transitions[TriggerDef.NEW_ROW] = null; rangeVars[TriggerDef.NEW_ROW] = range; } } else { break; } } } if (Boolean.TRUE.equals(isForEachRow) && token.tokenType != Tokens.FOR) { throw unexpectedTokenRequire(Tokens.T_FOR); } if (token.tokenType == Tokens.FOR) { read(); readThis(Tokens.EACH); if (token.tokenType == Tokens.ROW) { if (Boolean.FALSE.equals(isForEachRow)) { throw unexpectedToken(); } isForEachRow = Boolean.TRUE; } else if (token.tokenType == Tokens.STATEMENT) { if (Boolean.TRUE.equals(isForEachRow) || beforeOrAfterType == TriggerDef.BEFORE) { throw unexpectedToken(); } isForEachRow = Boolean.FALSE; } else { throw unexpectedToken(); } read(); } // if (rangeVars[TriggerDef.OLD_TABLE] != null) {} if (rangeVars[TriggerDef.NEW_TABLE] != null) {} // if (Tokens.T_QUEUE.equals(token.tokenString)) { read(); queueSize = readInteger(); hasQueueSize = true; } if (Tokens.T_NOWAIT.equals(token.tokenString)) { read(); isNowait = true; } if (token.tokenType == Tokens.WHEN && beforeOrAfterType != TriggerDef.INSTEAD) { read(); readThis(Tokens.OPENBRACKET); int position = getPosition(); isCheckOrTriggerCondition = true; condition = XreadBooleanValueExpression(); conditionSQL = getLastPart(position); isCheckOrTriggerCondition = false; readThis(Tokens.CLOSEBRACKET); HsqlList unresolved = condition.resolveColumnReferences(session, rangeGroups[0], rangeGroups, null); ExpressionColumn.checkColumnsResolved(unresolved); condition.resolveTypes(session, null); if (condition.getDataType() != Type.SQL_BOOLEAN) { throw Error.error(ErrorCode.X_42568); } } if (isForEachRow == null) { isForEachRow = Boolean.FALSE; } if (token.tokenType == Tokens.CALL) { int position = getPosition(); try { read(); checkIsSimpleName(); checkIsDelimitedIdentifier(); className = token.tokenString; read(); if (token.tokenType == Tokens.OPENBRACKET) { throw unexpectedToken(); } td = new TriggerDef(name, beforeOrAfterType, operationType, isForEachRow.booleanValue(), table, transitions, rangeVars, condition, conditionSQL, updateColumnIndexes, className, isNowait, queueSize); String sql = getLastPart(); Object[] args = new Object[] { td, otherName, ifNotExists }; HsqlName[] writeLockNames = new HsqlName[] { database.getCatalogName(), table.getName() }; return new StatementSchema(sql, StatementTypes.CREATE_TRIGGER, args, null, writeLockNames); } catch (HsqlException e) { rewind(position); } } // if (hasQueueSize) { throw unexpectedToken(Tokens.T_QUEUE); } if (isNowait) { throw unexpectedToken(Tokens.T_NOWAIT); } Routine routine = compileTriggerRoutine(table, rangeVars, beforeOrAfterType, operationType); td = new TriggerDefSQL(name, beforeOrAfterType, operationType, isForEachRow.booleanValue(), table, transitions, rangeVars, condition, conditionSQL, updateColumnIndexes, routine); String sql = getLastPart(); Object[] args = new Object[] { td, otherName, ifNotExists }; return new StatementSchema(sql, StatementTypes.CREATE_TRIGGER, args, null, new HsqlName[] { database.getCatalogName(), table.getName() }); } Routine compileTriggerRoutine(Table table, RangeVariable[] ranges, int beforeOrAfter, int operation) { int impact = (beforeOrAfter == TriggerDef.BEFORE) ? Routine.READS_SQL : Routine .MODIFIES_SQL; Routine routine = new Routine(table, ranges, impact, beforeOrAfter, operation); session.sessionContext.pushRoutineTables(); try { startRecording(); StatementCompound parent = new StatementCompound(StatementTypes.BEGIN_END, null, null); parent.rangeVariables = ranges; Statement statement = compileSQLProcedureStatementOrNull(routine, null); if (statement == null) { throw unexpectedToken(); } Token[] tokenisedStatement = getRecordedStatement(); String sql = Token.getSQL(tokenisedStatement); statement.setSQL(sql); routine.setProcedure(statement); routine.resolve(session); } finally { session.sessionContext.popRoutineTables(); } return routine; } void checkSchemaUpdateAuthorisation(HsqlName schema) { if (session.isProcessingLog()) { return; } SqlInvariants.checkSchemaNameNotSystem(schema.name); if (isSchemaDefinition) { if (schema != session.getCurrentSchemaHsqlName()) { throw Error.error(ErrorCode.X_42505); } } else { session.getGrantee().checkSchemaUpdateOrGrantRights(schema.name); } session.checkDDLWrite(); } }