Package com.alibaba.druid.sql.dialect.oracle.parser

Source Code of com.alibaba.druid.sql.dialect.oracle.parser.OracleSelectParser

/*
* Copyright 1999-2011 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.druid.sql.dialect.oracle.parser;

import com.alibaba.druid.sql.ast.SQLSetQuantifier;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUnionOperator;
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.CycleClause;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.AsOfFlashbackQueryClause;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.VersionsFlashbackQueryClause;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.GroupingSetExpr;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.SampleClause;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.SearchClause;
import com.alibaba.druid.sql.dialect.oracle.ast.clause.SubqueryFactoringClause;
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectForUpdate;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectHierachicalQueryClause;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectJoin;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectPivot;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectRestriction;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectSubqueryTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectUnPivot;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLParseException;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.Token;

public class OracleSelectParser extends SQLSelectParser {

    public OracleSelectParser(String sql){
        super(sql);
    }

    public OracleSelectParser(Lexer lexer){
        super(lexer);
    }

    protected OracleExprParser createExprParser() {
        return new OracleExprParser(lexer);
    }

    public OracleSelect select() {
        OracleSelect select = new OracleSelect();

        if (lexer.token() == Token.WITH) {
            lexer.nextToken();

            SubqueryFactoringClause subqueryFactoringClause = new SubqueryFactoringClause();
            for (;;) {
                SubqueryFactoringClause.Entry entry = new SubqueryFactoringClause.Entry();
                entry.setName((SQLIdentifierExpr) createExprParser().name());

                if (lexer.token() == Token.LPAREN) {
                    lexer.nextToken();
                    createExprParser().names(entry.getColumns());
                    accept(Token.RPAREN);
                }

                accept(Token.AS);
                accept(Token.LPAREN);
                entry.setSubQuery(query());
                accept(Token.RPAREN);

                if (identifierEquals("SEARCH")) {
                    lexer.nextToken();
                    SearchClause searchClause = new SearchClause();

                    if (lexer.token() != Token.IDENTIFIER) {
                        throw new SQLParseException("syntax erorr : " + lexer.token());
                    }

                    searchClause.setType(SearchClause.Type.valueOf(lexer.stringVal()));
                    lexer.nextToken();

                    acceptIdentifier("FIRST");
                    accept(Token.BY);

                    searchClause.getItems().add((OracleOrderByItem) createExprParser().parseSelectOrderByItem());

                    while (lexer.token() == (Token.COMMA)) {
                        lexer.nextToken();
                        searchClause.getItems().add((OracleOrderByItem) createExprParser().parseSelectOrderByItem());
                    }

                    accept(Token.SET);

                    searchClause.setOrderingColumn((SQLIdentifierExpr) createExprParser().name());

                    entry.setSearchClause(searchClause);
                }

                if (identifierEquals("CYCLE")) {
                    lexer.nextToken();
                    CycleClause cycleClause = new CycleClause();
                    createExprParser().exprList(cycleClause.getAliases());
                    accept(Token.SET);
                    cycleClause.setMark(createExprParser().expr());
                    acceptIdentifier("TO");
                    cycleClause.setValue(createExprParser().expr());
                    accept(Token.DEFAULT);
                    cycleClause.setDefaultValue(createExprParser().expr());
                    entry.setCycleClause(cycleClause);
                }

                subqueryFactoringClause.getEntries().add(entry);

                if (lexer.token() == Token.COMMA) {
                    lexer.nextToken();
                    continue;
                }

                break;
            }

            select.setFactoring(subqueryFactoringClause);
        }

        select.setQuery(query());
        select.setOrderBy(this.parseOrderBy());

        if (lexer.token() == (Token.FOR)) {
            lexer.nextToken();
            accept(Token.UPDATE);

            OracleSelectForUpdate forUpdate = new OracleSelectForUpdate();

            if (identifierEquals("OF")) {
                lexer.nextToken();
                this.createExprParser().exprList(forUpdate.getOf());

                if (identifierEquals("WAIT")) throw new ParserException("TODO");
                if (identifierEquals("NOWAIT")) throw new ParserException("TODO");
                if (identifierEquals("SKIP")) {
                    throw new ParserException("TODO");
                }
            }

            select.setForUpdate(forUpdate);
        }

        if (select.getOrderBy() == null) {
            select.setOrderBy(this.createExprParser().parseOrderBy());
        }

        if (lexer.token() == Token.WITH) {
            lexer.nextToken();

            if (identifierEquals("READ")) {
                lexer.nextToken();

                if (identifierEquals("ONLY")) lexer.nextToken();
                else {
                    throw new ParserException("syntax error");
                }

                select.setRestriction(new OracleSelectRestriction.ReadOnly());
            } else if (lexer.token() == (Token.CHECK)) {
                lexer.nextToken();

                if (identifierEquals("OPTION")) lexer.nextToken();
                else {
                    throw new ParserException("syntax error");
                }

                OracleSelectRestriction.CheckOption checkOption = new OracleSelectRestriction.CheckOption();

                if (lexer.token() == Token.CONSTRAINT) {
                    lexer.nextToken();
                    throw new ParserException("TODO");
                }

                select.setRestriction(checkOption);
            } else {
                throw new ParserException("syntax error");
            }
        }

        return select;
    }

    protected SQLSelectQuery query() {
        if (lexer.token() == (Token.LPAREN)) {
            lexer.nextToken();

            SQLSelectQuery select = query();
            accept(Token.RPAREN);

            return queryRest(select);
        }

        accept(Token.SELECT);

        OracleSelectQueryBlock queryBlock = new OracleSelectQueryBlock();
        parseHints(queryBlock);

        if (lexer.token() == (Token.DISTINCT)) {
            queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
            lexer.nextToken();
        } else if (lexer.token() == (Token.UNIQUE)) {
            queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE);
            lexer.nextToken();
        } else if (lexer.token() == (Token.ALL)) {
            queryBlock.setDistionOption(SQLSetQuantifier.ALL);
            lexer.nextToken();
        }

        parseSelectList(queryBlock);

        parseFrom(queryBlock);

        parseWhere(queryBlock);

        parseHierachical(queryBlock);

        parseGroupBy(queryBlock);

        return queryRest(queryBlock);
    }

    public SQLSelectQuery queryRest(SQLSelectQuery selectQuery) {
        if (lexer.token() == (Token.UNION)) {
            SQLUnionQuery union = new SQLUnionQuery();
            union.setLeft(selectQuery);

            lexer.nextToken();

            if (lexer.token() == (Token.ALL)) {
                union.setOperator(SQLUnionOperator.UNION_ALL);
                lexer.nextToken();
            }

            SQLSelectQuery right = query();

            union.setRight(right);

            return queryRest(union);
        }

        if (lexer.token() == Token.INTERSECT) {
            lexer.nextToken();

            SQLUnionQuery union = new SQLUnionQuery();
            union.setLeft(selectQuery);

            union.setOperator(SQLUnionOperator.INTERSECT);

            SQLSelectQuery right = this.query();
            union.setRight(right);

            return union;
        }

        if (lexer.token() == Token.MINUS) {
            lexer.nextToken();

            SQLUnionQuery union = new SQLUnionQuery();
            union.setLeft(selectQuery);

            union.setOperator(SQLUnionOperator.MINUS);

            SQLSelectQuery right = this.query();
            union.setRight(right);

            return union;
        }

        return selectQuery;
    }

    private void parseGroupBy(OracleSelectQueryBlock queryBlock) {
        if (lexer.token() == (Token.GROUP)) {
            lexer.nextToken();
            accept(Token.BY);

            SQLSelectGroupByClause groupBy = new SQLSelectGroupByClause();
            for (;;) {
                if (identifierEquals("GROUPING")) {
                    GroupingSetExpr groupingSet = new GroupingSetExpr();
                    lexer.nextToken();
                    acceptIdentifier("SETS");
                    accept(Token.LPAREN);
                    createExprParser().exprList(groupingSet.getParameters());
                    accept(Token.RPAREN);
                    groupBy.getItems().add(groupingSet);
                } else {
                    groupBy.getItems().add(this.createExprParser().expr());
                }

                if (!(lexer.token() == (Token.COMMA))) {
                    break;
                }

                lexer.nextToken();
            }

            if (lexer.token() == (Token.HAVING)) {
                lexer.nextToken();

                groupBy.setHaving(this.createExprParser().expr());
            }

            queryBlock.setGroupBy(groupBy);
        }
    }

    private void parseHierachical(OracleSelectQueryBlock queryBlock) {
        OracleSelectHierachicalQueryClause hierachical = null;

        if (lexer.token() == Token.CONNECT) {
            hierachical = new OracleSelectHierachicalQueryClause();
            lexer.nextToken();
            accept(Token.BY);

            if (lexer.token() == Token.PRIOR) {
                lexer.nextToken();
                hierachical.setPrior(true);
            }

            if (identifierEquals("NOCYCLE")) {
                hierachical.setNoCycle(true);
            }
            hierachical.setConnectBy(this.createExprParser().expr());
        }

        if (lexer.token() == Token.START) {
            lexer.nextToken();
            if (hierachical == null) {
                hierachical = new OracleSelectHierachicalQueryClause();
            }
            accept(Token.WITH);

            hierachical.setStartWith(this.createExprParser().expr());
        }

        if (lexer.token() == Token.CONNECT) {
            if (hierachical == null) {
                hierachical = new OracleSelectHierachicalQueryClause();
            }

            lexer.nextToken();
            accept(Token.BY);

            if (lexer.token() == Token.PRIOR) {
                lexer.nextToken();
                hierachical.setPrior(true);
            }

            if (identifierEquals("NOCYCLE")) {
                hierachical.setNoCycle(true);
            }
            hierachical.setConnectBy(this.createExprParser().expr());
        }

        if (hierachical != null) {
            queryBlock.setHierachicalQueryClause(hierachical);
        }
    }

    @Override
    public SQLTableSource parseTableSource() {
        if (lexer.token() == (Token.LPAREN)) {
            lexer.nextToken();
            OracleSelectSubqueryTableSource tableSource;
            if (lexer.token() == Token.SELECT) {
                tableSource = new OracleSelectSubqueryTableSource(select());
            } else if (lexer.token() == (Token.LPAREN)) {
                tableSource = new OracleSelectSubqueryTableSource(select());
            } else {
                throw new ParserException("TODO :" + lexer.token());
            }
            accept(Token.RPAREN);

            parsePivot((OracleSelectTableSource) tableSource);

            return parseTableSourceRest(tableSource);
        }

        if (lexer.token() == (Token.SELECT)) {
            throw new ParserException("TODO");
        }

        OracleSelectTableReference tableReference = new OracleSelectTableReference();

        if (identifierEquals("ONLY")) {
            lexer.nextToken();
            accept(Token.LPAREN);
            parseTableSourceQueryTableExpr(tableReference);
            accept(Token.RPAREN);
        } else {
            parseTableSourceQueryTableExpr(tableReference);
            parsePivot(tableReference);
        }

        return parseTableSourceRest(tableReference);
    }

    private void parseTableSourceQueryTableExpr(OracleSelectTableReference tableReference) {
        tableReference.setExpr(this.createExprParser().expr());

        if (identifierEquals("SAMPLE")) {
            lexer.nextToken();

            SampleClause sample = new SampleClause();

            if (identifierEquals("BLOCK")) {
                sample.setBlock(true);
            }

            accept(Token.LPAREN);

            if (lexer.token() != Token.LITERAL_INT) {
                throw new ParserException("syntax error : " + lexer.token());
            }
            sample.setPercent(lexer.integerValue().intValue());
            lexer.nextToken();

            accept(Token.RPAREN);

            if (identifierEquals("SEED")) {
                lexer.nextToken();
                accept(Token.LPAREN);
                sample.setSeedValue(expr());
                accept(Token.RPAREN);
            }

            tableReference.setSampleClause(sample);
        }

        if (identifierEquals("PARTITION")) {
            lexer.nextToken();
            PartitionExtensionClause partition = new PartitionExtensionClause();

            if (lexer.token() == Token.LPAREN) {
                lexer.nextToken();
                partition.setPartition(createExprParser().name());
                accept(Token.RPAREN);
            } else {
                accept(Token.FOR);
                accept(Token.LPAREN);
                createExprParser().names(partition.getFor());
                accept(Token.RPAREN);
            }

            tableReference.setPartition(partition);
        }

        if (identifierEquals("SUBPARTITION")) {
            lexer.nextToken();
            PartitionExtensionClause partition = new PartitionExtensionClause();
            partition.setSubPartition(true);

            if (lexer.token() == Token.LPAREN) {
                lexer.nextToken();
                partition.setPartition(createExprParser().name());
                accept(Token.RPAREN);
            } else {
                accept(Token.FOR);
                accept(Token.LPAREN);
                createExprParser().names(partition.getFor());
                accept(Token.RPAREN);
            }

            tableReference.setPartition(partition);
        }

        if (lexer.token() == Token.AS) {
            lexer.nextToken();

            if (identifierEquals("OF")) {
                lexer.nextToken();

                AsOfFlashbackQueryClause clause = new AsOfFlashbackQueryClause();
                if (identifierEquals("SCN")) {
                    clause.setType(AsOfFlashbackQueryClause.Type.SCN);
                    lexer.nextToken();
                } else {
                    accept(Token.TIMESTAMP);
                    clause.setType(AsOfFlashbackQueryClause.Type.TIMESTAMP);
                }
                clause.setExpr(createExprParser().primary());

                tableReference.setFlashback(clause);
            } else {
                throw new SQLParseException("TODO");
            }
        } else if (identifierEquals("VERSIONS")) {
            lexer.nextToken();

            if (lexer.token() == Token.BETWEEN) {
                lexer.nextToken();

                VersionsFlashbackQueryClause clause = new VersionsFlashbackQueryClause();
                if (identifierEquals("SCN")) {
                    clause.setType(AsOfFlashbackQueryClause.Type.SCN);
                    lexer.nextToken();
                } else {
                   accept(Token.TIMESTAMP);
                    clause.setType(AsOfFlashbackQueryClause.Type.TIMESTAMP);
                }

                SQLBinaryOpExpr binaryExpr = (SQLBinaryOpExpr) createExprParser().expr();
                if (binaryExpr.getOperator() != SQLBinaryOperator.BooleanAnd) {
                    throw new SQLParseException("syntax error : " + binaryExpr.getOperator());
                }

                clause.setBegin(binaryExpr.getLeft());
                clause.setEnd(binaryExpr.getRight());

                tableReference.setFlashback(clause);
            } else {
                throw new SQLParseException("TODO");
            }
        }

    }

    protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
        if ((tableSource.getAlias() == null) || (tableSource.getAlias().length() == 0)) {
            if (lexer.token() != Token.LEFT && lexer.token() != Token.RIGHT && lexer.token() != Token.FULL) {
                tableSource.setAlias(as());
            }
        }

        OracleSelectJoin.JoinType joinType = null;

        if (lexer.token() == Token.LEFT) {
            lexer.nextToken();
            if (identifierEquals("OUTER")) {
                lexer.nextToken();
            }
            accept(Token.JOIN);
            joinType = OracleSelectJoin.JoinType.LEFT_OUTER_JOIN;
        }

        if (lexer.token() == Token.RIGHT) {
            lexer.nextToken();
            if (identifierEquals("OUTER")) {
                lexer.nextToken();
            }
            accept(Token.JOIN);
            joinType = OracleSelectJoin.JoinType.RIGHT_OUTER_JOIN;
        }

        if (identifierEquals("FULL")) {
            lexer.nextToken();
            if (identifierEquals("OUTER")) {
                lexer.nextToken();
            }
            accept(Token.JOIN);
            joinType = OracleSelectJoin.JoinType.FULL_OUTER_JOIN;
        }
       
        if (lexer.token() == Token.INNER) {
            lexer.nextToken();
            accept(Token.JOIN);
            joinType = OracleSelectJoin.JoinType.INNER_JOIN;
        }

        if (lexer.token() == Token.JOIN) {
            lexer.nextToken();
            joinType = OracleSelectJoin.JoinType.JOIN;
        }

        if (lexer.token() == (Token.COMMA)) {
            lexer.nextToken();
            joinType = OracleSelectJoin.JoinType.COMMA;
        }

        if (joinType != null) {
            OracleSelectJoin join = new OracleSelectJoin();
            join.setLeft(tableSource);
            join.setJoinType(joinType);
            join.setRight(parseTableSource());

            if (lexer.token() == Token.ON) {
                lexer.nextToken();
                join.setCondition(this.createExprParser().expr());
            } else if (identifierEquals("USING")) {
                lexer.nextToken();
                accept(Token.LPAREN);
                this.createExprParser().exprList(join.getUsing());
                accept(Token.RPAREN);
            }

            return join;
        }

        return tableSource;
    }

    private void parsePivot(OracleSelectTableSource tableSource) {
        OracleSelectPivot.Item item;
        if (identifierEquals("PIVOT")) {
            lexer.nextToken();

            OracleSelectPivot pivot = new OracleSelectPivot();

            if (identifierEquals("XML")) {
                lexer.nextToken();
                pivot.setXml(true);
            }

            accept(Token.LPAREN);
            while (true) {
                item = new OracleSelectPivot.Item();
                item.setExpr((OracleAggregateExpr) this.createExprParser().expr());
                item.setAlias(as());
                pivot.getItems().add(item);

                if (!(lexer.token() == (Token.COMMA))) break;
                lexer.nextToken();
            }

            accept(Token.FOR);

            if (lexer.token() == (Token.LPAREN)) {
                lexer.nextToken();
                while (true) {
                    pivot.getPivotFor().add(new SQLIdentifierExpr(lexer.stringVal()));
                    lexer.nextToken();

                    if (!(lexer.token() == (Token.COMMA))) break;
                    lexer.nextToken();
                }

                accept(Token.RPAREN);
            } else {
                pivot.getPivotFor().add(new SQLIdentifierExpr(lexer.stringVal()));
                lexer.nextToken();
            }

            accept(Token.IN);
            accept(Token.LPAREN);
            if (lexer.token() == (Token.LPAREN)) {
                throw new ParserException("TODO");
            }

            if (lexer.token() == (Token.SELECT)) {
                throw new ParserException("TODO");
            }

            for (;;) {
                item = new OracleSelectPivot.Item();
                item.setExpr(this.createExprParser().expr());
                item.setAlias(as());
                pivot.getPivotIn().add(item);

                if (lexer.token() != Token.COMMA) {
                    break;
                }

                lexer.nextToken();
            }

            accept(Token.RPAREN);

            accept(Token.RPAREN);

            tableSource.setPivot(pivot);
        } else if (identifierEquals("UNPIVOT")) {
            lexer.nextToken();

            OracleSelectUnPivot unPivot = new OracleSelectUnPivot();
            if (identifierEquals("INCLUDE")) {
                lexer.nextToken();
                acceptIdentifier("NULLS");
                unPivot.setNullsIncludeType(OracleSelectUnPivot.NullsIncludeType.INCLUDE_NULLS);
            } else if (identifierEquals("EXCLUDE")) {
                lexer.nextToken();
                acceptIdentifier("NULLS");
                unPivot.setNullsIncludeType(OracleSelectUnPivot.NullsIncludeType.EXCLUDE_NULLS);
            }

            accept(Token.LPAREN);

            if (lexer.token() == (Token.LPAREN)) {
                lexer.nextToken();
                this.createExprParser().exprList(unPivot.getItems());
                accept(Token.RPAREN);
            } else {
                unPivot.getItems().add(this.createExprParser().expr());
            }

            accept(Token.FOR);

            if (lexer.token() == (Token.LPAREN)) {
                lexer.nextToken();
                while (true) {
                    unPivot.getPivotFor().add(new SQLIdentifierExpr(lexer.stringVal()));
                    lexer.nextToken();

                    if (!(lexer.token() == (Token.COMMA))) break;
                    lexer.nextToken();
                }

                accept(Token.RPAREN);
            } else {
                unPivot.getPivotFor().add(new SQLIdentifierExpr(lexer.stringVal()));
                lexer.nextToken();
            }

            accept(Token.IN);
            accept(Token.LPAREN);
            if (lexer.token() == (Token.LPAREN)) {
                throw new ParserException("TODO");
            }

            if (lexer.token() == (Token.SELECT)) {
                throw new ParserException("TODO");
            }

            for (;;) {
                item = new OracleSelectPivot.Item();
                item.setExpr(this.createExprParser().expr());
                item.setAlias(as());
                unPivot.getPivotIn().add(item);

                if (lexer.token() != Token.COMMA) {
                    break;
                }

                lexer.nextToken();
            }

            accept(Token.RPAREN);

            accept(Token.RPAREN);

            tableSource.setPivot(unPivot);
        }
    }

    private void parseHints(OracleSelectQueryBlock queryBlock) {
        if (lexer.token() == Token.HINT) {
            queryBlock.getHints().add(new OracleHint(lexer.stringVal()));
            lexer.nextToken();
        }
    }
}
TOP

Related Classes of com.alibaba.druid.sql.dialect.oracle.parser.OracleSelectParser

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.