Package org.hsqldb_voltpatches

Source Code of org.hsqldb_voltpatches.ParserRoutine

/* Copyright (c) 2001-2009, 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_voltpatches;

import org.hsqldb_voltpatches.HsqlNameManager.HsqlName;
import org.hsqldb_voltpatches.lib.HsqlArrayList;
import org.hsqldb_voltpatches.lib.HsqlList;
import org.hsqldb_voltpatches.lib.OrderedHashSet;
import org.hsqldb_voltpatches.lib.OrderedIntHashSet;
import org.hsqldb_voltpatches.types.Type;

/**
* Parser for SQL stored procedures and functions - PSM
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.9.0
*/
public class ParserRoutine extends ParserDML {

    ParserRoutine(Session session, Scanner t) {
        super(session, t);
    }

    /**
     *  Reads a DEFAULT clause expression.
     */
    /*
     for datetime, the default must have the same fields
     */
    Expression readDefaultClause(Type dataType) {

        Expression e     = null;
        boolean    minus = false;

        if (dataType.isDateTimeType() || dataType.isIntervalType()) {
            switch (token.tokenType) {

                case Tokens.DATE :
                case Tokens.TIME :
                case Tokens.TIMESTAMP :
                case Tokens.INTERVAL : {
                    e = readDateTimeIntervalLiteral();

                    if (e.dataType.typeCode != dataType.typeCode) {

                        // error message
                        throw unexpectedToken();
                    }

                    Object defaultValue = e.getValue(session, dataType);

                    return new ExpressionValue(defaultValue, dataType);
                }
                case Tokens.X_VALUE :
                    break;

                default :
                    e = XreadDateTimeValueFunctionOrNull();
                    break;
            }
        } else if (dataType.isNumberType()) {
            if (token.tokenType == Tokens.MINUS) {
                read();

                minus = true;
            }
        } else if (dataType.isCharacterType()) {
            switch (token.tokenType) {

                case Tokens.USER :
                case Tokens.CURRENT_USER :
                case Tokens.CURRENT_ROLE :
                case Tokens.SESSION_USER :
                case Tokens.SYSTEM_USER :
                case Tokens.CURRENT_CATALOG :
                case Tokens.CURRENT_SCHEMA :
                case Tokens.CURRENT_PATH :
                    FunctionSQL function =
                        FunctionSQL.newSQLFunction(token.tokenString,
                                                   compileContext);

                    if (function == null) {
                        throw unexpectedToken();
                    }

                    e = readSQLFunction(function);
                    break;

                default :
            }
        } else if (dataType.isBooleanType()) {
            switch (token.tokenType) {

                case Tokens.TRUE :
                    read();

                    return Expression.EXPR_TRUE;

                case Tokens.FALSE :
                    read();

                    return Expression.EXPR_FALSE;
            }
        }

        if (e == null) {
            if (token.tokenType == Tokens.NULL) {
                read();

                return new ExpressionValue(null, dataType);
            }

            if (token.tokenType == Tokens.X_VALUE) {
                e = new ExpressionValue(token.tokenValue, token.dataType);

                if (minus) {
                    e = new ExpressionArithmetic(OpTypes.NEGATE, e);

                    e.resolveTypes(session, null);
                }

                read();

                Object defaultValue = e.getValue(session, dataType);

                return new ExpressionValue(defaultValue, dataType);
            } else {
                throw unexpectedToken();
            }
        }

        e.resolveTypes(session, null);

        // check type and length compatibility of datetime and character functions
        return e;
    }

    /**
     * Creates SET Statement for PSM from this parse context.
     */
    StatementSimple compileSetStatement(RangeVariable rangeVars[]) {

        read();

        OrderedHashSet colNames = new OrderedHashSet();
        HsqlArrayList  exprList = new HsqlArrayList();

        readSetClauseList(rangeVars, colNames, exprList);

        if (exprList.size() > 1) {
            throw Error.error(ErrorCode.X_42602);
        }

        Expression expression = (Expression) exprList.get(0);

        if (expression.getDegree() != colNames.size()) {

//            throw Error.error(ErrorCode.X_42546);
        }

        int[]          indexes   = new int[colNames.size()];
        ColumnSchema[] variables = new ColumnSchema[colNames.size()];

        setVariables(rangeVars, colNames, indexes, variables);

        HsqlList unresolved = expression.resolveColumnReferences(rangeVars,
            rangeVars.length, null, false);

        unresolved = Expression.resolveColumnSet(rangeVars, unresolved, null);

        ExpressionColumn.checkColumnsResolved(unresolved);
        expression.resolveTypes(session, null);

        StatementSimple cs = new StatementSimple(StatementTypes.ASSIGNMENT,
            variables, expression, indexes);

        return cs;
    }

    private static void setVariables(RangeVariable[] rangeVars,
                                     OrderedHashSet colNames, int[] indexes,
                                     ColumnSchema[] variables)
                                     throws IndexOutOfBoundsException {

        int index = -1;

        for (int i = 0; i < variables.length; i++) {
            String colName = (String) colNames.get(i);

            for (int j = 0; j < rangeVars.length; j++) {
                index = rangeVars[j].variables.getIndex(colName);

                if (index > -1) {
                    indexes[i]   = index;
                    variables[i] = rangeVars[j].getColumn(index);

                    break;
                }
            }
        }
    }

    // SQL-invoked routine
    StatementSchema compileCreateProcedureOrFunction() {

        int routineType = token.tokenType == Tokens.PROCEDURE
                          ? SchemaObject.PROCEDURE
                          : SchemaObject.FUNCTION;
        HsqlName name;

        read();

        name = readNewSchemaObjectNameNoCheck(routineType);

        Routine routine = new Routine(routineType);

        routine.setName(name);
        readThis(Tokens.OPENBRACKET);

        if (token.tokenType == Tokens.CLOSEBRACKET) {
            read();
        } else {
            while (true) {
                ColumnSchema newcolumn = readRoutineParameter(routine);

                routine.addParameter(newcolumn);

                if (token.tokenType == Tokens.COMMA) {
                    read();
                } else {
                    readThis(Tokens.CLOSEBRACKET);

                    break;
                }
            }
        }

        if (routineType != SchemaObject.PROCEDURE) {
            readThis(Tokens.RETURNS);

            if (token.tokenType == Tokens.TABLE) {
                read();

                TableDerived table =
                    new TableDerived(database, name, TableBase.FUNCTION_TABLE);

                readThis(Tokens.OPENBRACKET);

                if (token.tokenType == Tokens.CLOSEBRACKET) {
                    read();
                } else {
                    while (true) {
                        ColumnSchema newcolumn = readRoutineParameter(routine);

                        table.addColumn(newcolumn);

                        if (token.tokenType == Tokens.COMMA) {
                            read();
                        } else {
                            readThis(Tokens.CLOSEBRACKET);

                            break;
                        }
                    }
                }

                routine.setReturnTable(table);
            } else {
                Type type = readTypeDefinition(true);

                routine.setReturnType(type);
            }
        }

        readRoutineCharacteristics(routine);

        if (token.tokenType == Tokens.EXTERNAL) {
            if (routine.getLanguage() != Routine.LANGUAGE_JAVA) {
                throw unexpectedToken();
            }

            read();
            readThis(Tokens.NAME);
            checkIsValue(Types.SQL_CHAR);
            routine.setMethodURL((String) token.tokenValue);
            read();

            if (token.tokenType == Tokens.PARAMETER) {
                read();
                readThis(Tokens.STYLE);
                readThis(Tokens.JAVA);
            }
        } else {
            startRecording();

            Statement statement = readSQLProcedureStatementOrNull(routine,
                null);
            Token[] tokenList = getRecordedStatement();
            String  sql       = Token.getSQL(tokenList);

            statement.setSQL(sql);
            routine.setProcedure(statement);
        }

        Object[] args = new Object[]{ routine };
        String   sql  = getLastPart();
        StatementSchema cs = new StatementSchema(sql,
            StatementTypes.CREATE_ROUTINE, args, null, null);

        return cs;
    }

    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 =
                        readNewSchemaObjectNameNoCheck(routine.getType());

                    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();
                    }

                    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);
                    readBigint();

                    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 super.unsupportedFeature(Tokens.T_OLD);

                    // break;
                }
                default :
                    end = true;
                    break;
            }
        }
    }

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


*/
    private Object[] readLocalDeclarationList(Routine routine,
            StatementCompound context) {

        HsqlArrayList list = new HsqlArrayList();

        while (token.tokenType == Tokens.DECLARE) {
            Object var = readLocalVariableDeclarationOrNull();

            if (var == null) {
                var = readLocalHandlerDeclaration(routine, context);
            }

            list.add(var);
        }

        Object[] declarations = new Object[list.size()];

        list.toArray(declarations);

        return declarations;
    }

    ColumnSchema readLocalVariableDeclarationOrNull() {

        int position = super.getPosition();

        readThis(Tokens.DECLARE);

        if (isReservedKey()) {
            rewind(position);

            return null;
        }

        HsqlName name =
            super.readNewSchemaObjectNameNoCheck(SchemaObject.VARIABLE);
        Type       type = readTypeDefinition(true);
        Expression def  = null;

        if (token.tokenType == Tokens.DEFAULT) {
            read();

            def = readDefaultClause(type);
        }

        ColumnSchema variable = new ColumnSchema(name, type, true, false, def);

        variable.setParameterMode(SchemaObject.ParameterModes.PARAM_INOUT);
        readThis(Tokens.SEMICOLON);

        return variable;
    }

    private StatementHandler readLocalHandlerDeclaration(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 = readSQLProcedureStatementOrNull(routine, context);

            if (e == null) {
                throw unexpectedToken();
            }

            readThis(Tokens.SEMICOLON);
            handler.addStatement(e);
        }

        return handler;
    }

    String parseSQLStateValue() {

        readIfThis(Tokens.VALUE);
        checkIsValue(Types.SQL_CHAR);

        String sqlState = token.tokenString;

        if (token.tokenString.length() != 5) {
            throw Error.error(ErrorCode.X_07000);
        }

        read();

        return sqlState;
    }

    private Statement readCompoundStatement(Routine routine,
            StatementCompound context, HsqlName label) {

        final boolean atomic = true;

        readThis(Tokens.BEGIN);
        readThis(Tokens.ATOMIC);

        StatementCompound statement =
            new StatementCompound(StatementTypes.BEGIN_END, label);

        statement.setAtomic(atomic);
        statement.setRoot(routine);
        statement.setParent(context);

        Object[] declarations = readLocalDeclarationList(routine, context);

        statement.setLocalDeclarations(declarations);

        Statement[] statements = readSQLProcedureStatementList(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;
    }

    private Statement[] readSQLProcedureStatementList(Routine routine,
            StatementCompound context) {

        Statement e = readSQLProcedureStatementOrNull(routine, context);

        if (e == null) {
            throw unexpectedToken();
        }

        readThis(Tokens.SEMICOLON);

        HsqlArrayList list = new HsqlArrayList();

        list.add(e);

        while (true) {
            e = readSQLProcedureStatementOrNull(routine, context);

            if (e == null) {
                break;
            }

            readThis(Tokens.SEMICOLON);
            list.add(e);
        }

        Statement[] statements = new Statement[list.size()];

        list.toArray(statements);

        return statements;
    }

    private Statement readSQLProcedureStatementOrNull(Routine routine,
            StatementCompound context) {

        Statement cs    = null;
        HsqlName  label = null;
        RangeVariable[] rangeVariables = context == null
                                         ? routine.getParameterRangeVariables()
                                         : context.getRangeVariables();

        if (isSimpleName() && !isReservedKey()) {
            label = readNewSchemaObjectNameNoCheck(SchemaObject.LABEL);

            readThis(Tokens.COLON);
        }

        switch (token.tokenType) {

            // data
            case Tokens.SELECT : {
                cs = readSelectSingleRowStatement(rangeVariables);

                break;
            }

            // data change
            case Tokens.INSERT :
                cs = compileInsertStatement(rangeVariables);
                break;

            case Tokens.UPDATE :
                cs = compileUpdateStatement(rangeVariables);
                break;

            case Tokens.DELETE :
            case Tokens.TRUNCATE :
                cs = compileDeleteStatement(rangeVariables);
                break;

            case Tokens.MERGE :
                cs = compileMergeStatement(rangeVariables);
                break;

            case Tokens.SET :
                cs = compileSetStatement(rangeVariables);
                break;

            // control
            case Tokens.CALL : {
                if (label != null) {
                    throw unexpectedToken();
                }

                cs = compileCallStatement(rangeVariables, true);

                break;
            }
            case Tokens.RETURN : {
                if (label != null) {
                    throw unexpectedToken();
                }

                read();

                cs = readReturnValue(routine, context);

                break;
            }
            case Tokens.BEGIN : {
                cs = readCompoundStatement(routine, context, label);

                break;
            }
            case Tokens.WHILE : {
                cs = readWhile(routine, context, label);

                break;
            }
            case Tokens.REPEAT : {
                cs = readRepeat(routine, context, label);

                break;
            }
            case Tokens.LOOP : {
                cs = readLoop(routine, context, label);

                break;
            }
            case Tokens.FOR : {
                cs = readFor(routine, context, label);

                break;
            }
            case Tokens.ITERATE : {
                if (label != null) {
                    throw unexpectedToken();
                }

                cs = readIterate();

                break;
            }
            case Tokens.LEAVE : {
                if (label != null) {
                    throw unexpectedToken();
                }

                cs = readLeave(routine, context);

                break;
            }
            case Tokens.IF : {
                if (label != null) {
                    throw unexpectedToken();
                }

                cs = readIf(routine, context);

                break;
            }
            case Tokens.CASE : {
                if (label != null) {
                    throw unexpectedToken();
                }

                cs = readCase(routine, context);

                break;
            }
            case Tokens.SIGNAL : {
                cs = readSignal(routine, context, label);

                break;
            }
            case Tokens.RESIGNAL : {
                cs = readResignal(routine, context, label);

                break;
            }
            default :
                return null;
        }

        cs.setRoot(routine);
        cs.setParent(context);

        return cs;
    }

    private Statement readReturnValue(Routine routine,
                                      StatementCompound context) {

        Expression e = XreadValueExpressionOrNull();

        if (e == null) {
            checkIsValue();

            if (token.tokenValue == null) {
                e = new ExpressionValue(null, null);
            }
        }

        RangeVariable[] rangeVars = routine.getParameterRangeVariables();

        if (context != null) {
            rangeVars = context.getRangeVariables();
        }

        HsqlList list = e.resolveColumnReferences(rangeVars, rangeVars.length,
            null, false);

        ExpressionColumn.checkColumnsResolved(list);
        e.resolveTypes(session, null);

        return new StatementSimple(StatementTypes.RETURN, e);
    }

    private Statement readSelectSingleRowStatement(RangeVariable[] rangeVars) {

        OrderedHashSet     variableNames = new OrderedHashSet();
        QuerySpecification select        = XreadSelect();

        readThis(Tokens.INTO);
        readColumnNamesForSelectInto(variableNames, rangeVars);
        XreadTableExpression(select);
        select.setAsTopLevel();
        select.resolve(session);

        int[]          indexes   = new int[variableNames.size()];
        ColumnSchema[] variables = new ColumnSchema[variableNames.size()];
        Statement statement = new StatementSimple(StatementTypes.ASSIGNMENT,
            variables, null, indexes);

        return statement;
    }

    private Statement readIterate() {

        readThis(Tokens.ITERATE);

        HsqlName label = readNewSchemaObjectNameNoCheck(SchemaObject.LABEL);

        return new StatementSimple(StatementTypes.ITERATE, label);
    }

    private Statement readLeave(Routine routine, StatementCompound context) {

        readThis(Tokens.LEAVE);

        HsqlName label = readNewSchemaObjectNameNoCheck(SchemaObject.LABEL);

        return new StatementSimple(StatementTypes.LEAVE, label);
    }

    private Statement readWhile(Routine routine, StatementCompound context,
                                HsqlName label) {

        readThis(Tokens.WHILE);

        StatementSimple condition =
            new StatementSimple(StatementTypes.CONDITION,
                                XreadBooleanValueExpression());

        readThis(Tokens.DO);

        Statement[] statements = readSQLProcedureStatementList(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);

        statement.setStatements(statements);
        statement.setCondition(condition);

        return statement;
    }

    private Statement readRepeat(Routine routine, StatementCompound context,
                                 HsqlName label) {

        readThis(Tokens.REPEAT);

        Statement[] statements = readSQLProcedureStatementList(routine,
            context);

        readThis(Tokens.UNTIL);

        StatementSimple condition =
            new StatementSimple(StatementTypes.CONDITION,
                                XreadBooleanValueExpression());

        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);

        statement.setStatements(statements);
        statement.setCondition(condition);

        return statement;
    }

    private Statement readLoop(Routine routine, StatementCompound context,
                               HsqlName label) {

        readThis(Tokens.LOOP);

        Statement[] statements = readSQLProcedureStatementList(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);

        result.setStatements(statements);

        return result;
    }

    private Statement readFor(Routine routine, StatementCompound context,
                              HsqlName label) {

        readThis(Tokens.FOR);

        Statement cursorStatement = compileCursorSpecification();

        readThis(Tokens.DO);

        Statement[] statements = readSQLProcedureStatementList(routine,
            context);

        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();
        }

        StatementCompound result = new StatementCompound(StatementTypes.FOR,
            label);

        result.setLoopStatement(cursorStatement);
        result.setStatements(statements);

        return result;
    }

    private Statement readIf(Routine routine, StatementCompound context) {

        HsqlArrayList list = new HsqlArrayList();
        RangeVariable[] rangeVariables = context == null
                                         ? routine.getParameterRangeVariables()
                                         : context.getRangeVariables();
        HsqlList unresolved = null;

        readThis(Tokens.IF);

        Expression condition = XreadBooleanValueExpression();

        unresolved = condition.resolveColumnReferences(rangeVariables,
                rangeVariables.length, unresolved, false);

        ExpressionColumn.checkColumnsResolved(unresolved);

        unresolved = null;

        condition.resolveTypes(session, null);

        Statement statement = new StatementSimple(StatementTypes.CONDITION,
            condition);

        list.add(statement);
        readThis(Tokens.THEN);

        Statement[] statements = readSQLProcedureStatementList(routine,
            context);

        for (int i = 0; i < statements.length; i++) {
            list.add(statements[i]);
        }

        while (token.tokenType == Tokens.ELSEIF) {
            read();

            condition = XreadBooleanValueExpression();
            unresolved = condition.resolveColumnReferences(rangeVariables,
                    rangeVariables.length, unresolved, false);

            ExpressionColumn.checkColumnsResolved(unresolved);

            unresolved = null;

            condition.resolveTypes(session, null);

            statement = new StatementSimple(StatementTypes.CONDITION,
                                            condition);

            list.add(statement);
            readThis(Tokens.THEN);

            statements = readSQLProcedureStatementList(routine, context);

            for (int i = 0; i < statements.length; i++) {
                list.add(statements[i]);
            }
        }

        if (token.tokenType == Tokens.ELSE) {
            read();

            condition = Expression.EXPR_TRUE;
            statement = new StatementSimple(StatementTypes.CONDITION,
                                            condition);

            list.add(statement);

            statements = readSQLProcedureStatementList(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);

        result.setStatements(statements);

        return result;
    }

    private Statement readCase(Routine routine, StatementCompound context) {

        HsqlArrayList list      = new HsqlArrayList();
        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 StatementSimple(StatementTypes.CONDITION,
                                            condition);

            list.add(statement);

            statements = readSQLProcedureStatementList(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);

        result.setStatements(statements);

        return result;
    }

    private HsqlArrayList readSimpleCaseWhen(Routine routine,
            StatementCompound context) {

        HsqlArrayList list = new HsqlArrayList();
        RangeVariable[] rangeVariables = context == null
                                         ? routine.getParameterRangeVariables()
                                         : context.getRangeVariables();
        HsqlList    unresolved = null;
        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());
                }

                unresolved =
                    newCondition.resolveColumnReferences(rangeVariables,
                        rangeVariables.length, unresolved, false);

                ExpressionColumn.checkColumnsResolved(unresolved);

                unresolved = null;

                newCondition.resolveTypes(session, null);

                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 StatementSimple(StatementTypes.CONDITION,
                                            condition);

            list.add(statement);
            readThis(Tokens.THEN);

            statements = readSQLProcedureStatementList(routine, context);

            for (int i = 0; i < statements.length; i++) {
                list.add(statements[i]);
            }

            if (token.tokenType != Tokens.WHEN) {
                break;
            }
        } while (true);

        return list;
    }

    private HsqlArrayList readCaseWhen(Routine routine,
                                       StatementCompound context) {

        HsqlArrayList list = new HsqlArrayList();
        RangeVariable[] rangeVariables = context == null
                                         ? routine.getParameterRangeVariables()
                                         : context.getRangeVariables();
        HsqlList    unresolved = null;
        Expression  condition  = null;
        Statement   statement;
        Statement[] statements;

        do {
            readThis(Tokens.WHEN);

            condition = XreadBooleanValueExpression();
            unresolved = condition.resolveColumnReferences(rangeVariables,
                    rangeVariables.length, unresolved, false);

            ExpressionColumn.checkColumnsResolved(unresolved);

            unresolved = null;

            condition.resolveTypes(session, null);

            statement = new StatementSimple(StatementTypes.CONDITION,
                                            condition);

            list.add(statement);
            readThis(Tokens.THEN);

            statements = readSQLProcedureStatementList(routine, context);

            for (int i = 0; i < statements.length; i++) {
                list.add(statements[i]);
            }

            if (token.tokenType != Tokens.WHEN) {
                break;
            }
        } while (true);

        return list;
    }

    private Statement readSignal(Routine routine, StatementCompound context,
                                 HsqlName label) {

        readThis(Tokens.SIGNAL);
        readThis(Tokens.SQLSTATE);

        String sqlState = parseSQLStateValue();
        StatementSimple cs = new StatementSimple(StatementTypes.SIGNAL,
            sqlState);

        return cs;
    }

    private Statement readResignal(Routine routine, StatementCompound context,
                                   HsqlName label) {

        String sqlState = null;

        readThis(Tokens.RESIGNAL);

        if (readIfThis(Tokens.SQLSTATE)) {
            sqlState = parseSQLStateValue();
        }

        StatementSimple cs = new StatementSimple(StatementTypes.RESIGNAL,
            sqlState);

        return cs;
    }

    private ColumnSchema readRoutineParameter(Routine routine) {

        HsqlName hsqlName      = null;
        byte     parameterMode = SchemaObject.ParameterModes.PARAM_IN;

        switch (token.tokenType) {

            case Tokens.IN :
                read();
                break;

            case Tokens.OUT :
                if (routine.getType() != SchemaObject.PROCEDURE) {
                    throw unexpectedToken();
                }

                read();

                parameterMode = SchemaObject.ParameterModes.PARAM_OUT;
                break;

            case Tokens.INOUT :
                if (routine.getType() != SchemaObject.PROCEDURE) {
                    throw unexpectedToken();
                }

                read();

                parameterMode = SchemaObject.ParameterModes.PARAM_INOUT;
                break;

            default :
        }

        if (!isReservedKey()) {
            hsqlName = readNewDependentSchemaObjectName(routine.getName(),
                    SchemaObject.PARAMETER);
        }

        Type typeObject = readTypeDefinition(true);
        ColumnSchema column = new ColumnSchema(hsqlName, typeObject, false,
                                               false, null);

        column.setParameterMode(parameterMode);

        return column;
    }
}
TOP

Related Classes of org.hsqldb_voltpatches.ParserRoutine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.