Select parseSelect()

in HSQL/src/org/hsqldb1/Parser.java [392:729]


    Select parseSelect(int brackets, boolean canHaveOrder,
                       boolean canHaveLimit, boolean limitWithOrder,
                       boolean isMain) throws HsqlException {

        Select select = new Select();
        String token  = tokenizer.getString();

        if (canHaveLimit || limitWithOrder) {
            if (tokenizer.wasThis(Token.T_LIMIT)
                    || tokenizer.wasThis(Token.T_TOP)) {
                parseLimit(token, select, false);

                token = tokenizer.getString();
            }
        }

        if (tokenizer.wasThis(Token.T_DISTINCT)) {
            select.isDistinctSelect = true;
        } else if (tokenizer.wasThis(Token.T_ALL)) {}
        else {
            tokenizer.back();
        }

        // parse column list
        HsqlArrayList vcolumn = new HsqlArrayList();

        do {
            int        expPos = tokenizer.getPosition();
            Expression e      = parseExpression();

            if (isCompilingView()) {
                if (e.getType() == Expression.ASTERISK) {
                    if (select.asteriskPositions == null) {
                        select.asteriskPositions = new IntKeyHashMap();
                    }

                    // remember the position of the asterisk. For the moment, just
                    // remember the expression, so it can later be found and replaced
                    // with the concrete column list
                    select.asteriskPositions.put(expPos, e);
                }
            }

            token = tokenizer.getString();

            if (tokenizer.wasThis(Token.T_AS)) {
                e.setAlias(tokenizer.getSimpleName(),
                           tokenizer.wasQuotedIdentifier());

                token = tokenizer.getString();
            } else if (tokenizer.wasSimpleName()) {
                e.setAlias(token, tokenizer.wasQuotedIdentifier());

                token = tokenizer.getString();
            }

            vcolumn.add(e);
        } while (tokenizer.wasThis(Token.T_COMMA));

        if (token.equals(Token.T_INTO)) {
            boolean getname = true;

            token           = tokenizer.getString();
            select.intoType = database.getDefaultTableType();

            if (tokenizer.wasSimpleToken()) {
                switch (Token.get(token)) {

                    case Token.CACHED :
                        select.intoType = Table.CACHED_TABLE;
                        break;

                    case Token.TEMP :
                        select.intoType = Table.TEMP_TABLE;
                        break;

                    case Token.TEXT :
                        select.intoType = Table.TEXT_TABLE;
                        break;

                    case Token.MEMORY :
                        select.intoType = Table.MEMORY_TABLE;
                        break;

                    default :
                        getname = false;
                        break;
                }

                if (getname) {
                    token = tokenizer.getName();
                }
            }

            if (!tokenizer.wasName()) {
                tokenizer.throwUnexpected();
            }

            select.sIntoTable = database.nameManager.newHsqlName(token,
                    tokenizer.wasQuotedIdentifier());
            select.sIntoTable.schema =
                session.getSchemaHsqlName(tokenizer.getLongNameFirst());
            token = tokenizer.getString();
        }

        tokenizer.matchThis(Token.T_FROM);

        Expression condition = null;

        // parse table list
        HsqlArrayList vfilter = new HsqlArrayList();

        vfilter.add(parseTableFilter(false));

        while (true) {
            token = tokenizer.getString();

            boolean cross = false;

            if (tokenizer.wasThis(Token.T_INNER)) {
                tokenizer.getThis(Token.T_JOIN);

                token = Token.T_JOIN;
            } else if (tokenizer.wasThis(Token.T_CROSS)) {
                tokenizer.getThis(Token.T_JOIN);

                token = Token.T_JOIN;
                cross = true;
            }

            if (token.equals(Token.T_LEFT)
                    && !tokenizer.wasQuotedIdentifier()) {
                tokenizer.isGetThis(Token.T_OUTER);
                tokenizer.getThis(Token.T_JOIN);

                TableFilter tf = parseTableFilter(true);

                vfilter.add(tf);
                tokenizer.getThis(Token.T_ON);

                Expression newcondition = parseExpression();

                newcondition.checkTables(vfilter);

                condition = addJoinCondition(condition, newcondition, tf,
                                             true);

                // MarcH HuugO RIGHT JOIN SUPPORT
            } else if (token.equals(Token.T_RIGHT)
                       && !tokenizer.wasQuotedIdentifier()) {
                tokenizer.isGetThis(Token.T_OUTER);
                tokenizer.getThis(Token.T_JOIN);

                // this object is not an outerjoin, the next object is an outerjoin
                TableFilter tf = parseTableFilter(false);

                // insert new condition as first element in a new vfilter (nvfilter), copy the content of vfilter and rename nvfilter back to vfilter.
                HsqlArrayList nvfilter = new HsqlArrayList();

                nvfilter.add(tf);
                nvfilter.addAll(vfilter);

                vfilter = nvfilter;

                // set isOuterJoin correct
                ((TableFilter) vfilter.get(1)).isOuterJoin = true;

                tokenizer.getThis(Token.T_ON);

                Expression newcondition = parseExpression();

                newcondition.checkTables(vfilter);

                condition = addJoinCondition(condition, newcondition,
                                             ((TableFilter) vfilter.get(1)),
                                             true);
            } else if (tokenizer.wasThis(Token.T_JOIN)) {
                vfilter.add(parseTableFilter(false));

                if (!cross) {
                    tokenizer.getThis(Token.T_ON);

                    Expression newcondition = parseExpression();

                    newcondition.checkTables(vfilter);

                    condition = addJoinCondition(condition, newcondition,
                                                 null, false);
                }
            } else if (tokenizer.wasThis(Token.T_COMMA)) {
                vfilter.add(parseTableFilter(false));
            } else {
                tokenizer.back();

                break;
            }
        }

        resolveSelectTableFilter(select, vcolumn, vfilter);

        // where
        token = tokenizer.getString();

        if (tokenizer.wasThis(Token.T_WHERE)) {
            Expression newcondition = parseExpression();

            condition = addCondition(condition, newcondition);
            token     = tokenizer.getString();
        }

        select.queryCondition = condition;

        // group by
        if (tokenizer.wasThis(Token.T_GROUP)) {
            tokenizer.getThis(Token.T_BY);

            int len = 0;

            do {
                Expression e = parseExpression();

                vcolumn.add(e);

                token = tokenizer.getString();

                len++;
            } while (tokenizer.wasThis(Token.T_COMMA));

            select.iGroupLen = len;
        }

        // having
        if (tokenizer.wasThis(Token.T_HAVING)) {
            select.iHavingLen      = 1;
            select.havingCondition = parseExpression();
            token                  = tokenizer.getString();

            vcolumn.add(select.havingCondition);
        }

        if (isMain || limitWithOrder) {
            if (tokenizer.wasThis(Token.T_ORDER)) {
                tokenizer.getThis(Token.T_BY);
                parseOrderBy(select, vcolumn);

                token = tokenizer.getString();
            }

            if (tokenizer.wasThis(Token.T_LIMIT)) {
                parseLimit(token, select, true);

                token = tokenizer.getString();
            }
        }

        boolean closebrackets = false;

        if (brackets > 0 && token.equals(Token.T_CLOSEBRACKET)) {
            closebrackets = true;
            brackets      -= parseCloseBrackets(brackets - 1) + 1;
            token         = tokenizer.getString();
        }

        select.unionDepth = brackets;

        // checks for ORDER and LIMIT
        if (!(isMain || closebrackets)) {
            limitWithOrder = false;
        }

        boolean hasOrder = select.iOrderLen != 0;
        boolean hasLimit = select.limitCondition != null;

        if (limitWithOrder) {
            if (hasLimit && !hasOrder) {
                throw Trace.error(Trace.ORDER_LIMIT_REQUIRED);
            }
        } else {
            if (hasOrder && !canHaveOrder) {
                throw Trace.error(Trace.INVALID_ORDER_BY);
            }

            if (hasLimit && !canHaveLimit) {
                throw Trace.error(Trace.INVALID_LIMIT);
            }
        }

        int unionType = parseUnion(token);

        if (unionType != Select.NOUNION) {
            boolean openbracket = false;

            select.unionType = unionType;

            if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
                openbracket = true;
                brackets    += parseOpenBrackets() + 1;
            }

            tokenizer.getThis(Token.T_SELECT);

            // accept ORDRY BY with LIMIT when in brackets
            select.unionSelect = parseSelect(brackets, false, false,
                                             openbracket, false);
            token = tokenizer.getString();
        }

        if (isMain && (canHaveOrder || limitWithOrder)
                && select.iOrderLen == 0) {
            if (tokenizer.wasThis(Token.T_ORDER)) {
                tokenizer.getThis(Token.T_BY);
                parseOrderBy(select, vcolumn);

                token            = tokenizer.getString();
                select.sortUnion = true;
            }

            if (tokenizer.wasThis(Token.T_LIMIT)) {
                parseLimit(token, select, true);

                token = tokenizer.getString();
            }
        }

        tokenizer.back();

        if (isMain) {
            select.prepareUnions();
        }

        int len = vcolumn.size();

        select.exprColumns = new Expression[len];

        vcolumn.toArray(select.exprColumns);

        return select;
    }