/*
* Copyright 1999-2015 dangdang.com.
*
* 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.dangdang.ddframe.rdb.sharding.parsing.parser.dialect.oracle;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.constant.OrderType;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.dialect.oracle.OracleKeyword;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.DefaultKeyword;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.Keyword;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.Symbol;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.LexerEngine;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.selectitem.SelectItem;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.exception.SQLParsingException;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.exception.SQLParsingUnsupportedException;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dql.select.AbstractSelectParser;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dql.select.SelectStatement;
import java.util.Collections;
/**
* Oracle Select语句解析器.
*
* @author zhangliang
*/
public final class OracleSelectParser extends AbstractSelectParser {
public OracleSelectParser(final ShardingRule shardingRule, final LexerEngine lexerEngine) {
super(shardingRule, lexerEngine, new OracleWhereSQLParser(lexerEngine));
}
@Override
protected void parseInternal(final SelectStatement selectStatement) {
parseDistinct();
parseSelectList(selectStatement);
parseFrom(selectStatement);
parseWhere(selectStatement);
skipHierarchicalQueryClause(selectStatement);
parseGroupBy(selectStatement);
parseHaving();
skipModelClause(selectStatement);
parseOrderBy(selectStatement);
skipFor(selectStatement);
parseRest();
}
private void skipHierarchicalQueryClause(final SelectStatement selectStatement) {
skipConnect(selectStatement);
skipStart(selectStatement);
skipConnect(selectStatement);
}
private void skipStart(final SelectStatement selectStatement) {
if (!getLexerEngine().skipIfEqual(OracleKeyword.START)) {
return;
}
getLexerEngine().accept(DefaultKeyword.WITH);
getWhereSQLParser().parseComparisonCondition(getShardingRule(), selectStatement, Collections.emptyList());
}
private void skipConnect(final SelectStatement selectStatement) {
if (!getLexerEngine().skipIfEqual(OracleKeyword.CONNECT)) {
return;
}
getLexerEngine().accept(DefaultKeyword.BY);
getLexerEngine().skipIfEqual(OracleKeyword.PRIOR);
if (getLexerEngine().skipIfEqual(OracleKeyword.NOCYCLE)) {
getLexerEngine().skipIfEqual(OracleKeyword.PRIOR);
}
getWhereSQLParser().parseComparisonCondition(getShardingRule(), selectStatement, Collections.emptyList());
}
private void skipModelClause(final SelectStatement selectStatement) {
if (!getLexerEngine().skipIfEqual(OracleKeyword.MODEL)) {
return;
}
skipCellReferenceOptions();
getLexerEngine().skipIfEqual(OracleKeyword.RETURN);
getLexerEngine().skipIfEqual(DefaultKeyword.ALL);
getLexerEngine().skipIfEqual(OracleKeyword.UPDATED);
getLexerEngine().skipIfEqual(OracleKeyword.ROWS);
while (getLexerEngine().skipIfEqual(OracleKeyword.REFERENCE)) {
getLexerEngine().nextToken();
getLexerEngine().accept(DefaultKeyword.ON);
getLexerEngine().skipParentheses(selectStatement);
skipModelColumnClause();
skipCellReferenceOptions();
}
skipMainModelClause(selectStatement);
}
private void skipCellReferenceOptions() {
if (getLexerEngine().skipIfEqual(OracleKeyword.IGNORE)) {
getLexerEngine().accept(OracleKeyword.NAV);
} else if (getLexerEngine().skipIfEqual(OracleKeyword.KEEP)) {
getLexerEngine().accept(OracleKeyword.NAV);
}
if (getLexerEngine().skipIfEqual(DefaultKeyword.UNIQUE)) {
getLexerEngine().skipIfEqual(OracleKeyword.DIMENSION, OracleKeyword.SINGLE);
getLexerEngine().skipIfEqual(OracleKeyword.REFERENCE);
}
}
private void skipMainModelClause(final SelectStatement selectStatement) {
if (getLexerEngine().skipIfEqual(OracleKeyword.MAIN)) {
getLexerEngine().nextToken();
}
skipQueryPartitionClause(selectStatement);
getLexerEngine().accept(OracleKeyword.DIMENSION);
getLexerEngine().accept(DefaultKeyword.BY);
getLexerEngine().skipParentheses(selectStatement);
getLexerEngine().accept(OracleKeyword.MEASURES);
getLexerEngine().skipParentheses(selectStatement);
skipCellReferenceOptions();
skipModelRulesClause(selectStatement);
}
private void skipModelRulesClause(final SelectStatement selectStatement) {
if (getLexerEngine().skipIfEqual(OracleKeyword.RULES)) {
getLexerEngine().skipIfEqual(DefaultKeyword.UPDATE);
getLexerEngine().skipIfEqual(OracleKeyword.UPSERT);
if (getLexerEngine().skipIfEqual(OracleKeyword.AUTOMATIC)) {
getLexerEngine().accept(DefaultKeyword.ORDER);
} else if (getLexerEngine().skipIfEqual(OracleKeyword.SEQUENTIAL)) {
getLexerEngine().accept(DefaultKeyword.ORDER);
}
}
if (getLexerEngine().skipIfEqual(DefaultKeyword.ITERATE)) {
getLexerEngine().skipParentheses(selectStatement);
if (getLexerEngine().skipIfEqual(DefaultKeyword.UNTIL)) {
getLexerEngine().skipParentheses(selectStatement);
}
}
getLexerEngine().skipParentheses(selectStatement);
}
private void skipQueryPartitionClause(final SelectStatement selectStatement) {
if (!getLexerEngine().skipIfEqual(OracleKeyword.PARTITION)) {
return;
}
getLexerEngine().accept(DefaultKeyword.BY);
if (!getLexerEngine().equalAny(Symbol.LEFT_PAREN)) {
throw new UnsupportedOperationException("Cannot support PARTITION BY without ()");
}
getLexerEngine().skipParentheses(selectStatement);
}
private void skipModelColumnClause() {
throw new SQLParsingUnsupportedException(getLexerEngine().getCurrentToken().getType());
}
private void skipFor(final SelectStatement selectStatement) {
if (!getLexerEngine().skipIfEqual(DefaultKeyword.FOR)) {
return;
}
getLexerEngine().accept(DefaultKeyword.UPDATE);
if (getLexerEngine().skipIfEqual(DefaultKeyword.OF)) {
do {
getExpressionSQLParser().parse(selectStatement);
} while (getLexerEngine().skipIfEqual(Symbol.COMMA));
}
if (getLexerEngine().equalAny(OracleKeyword.NOWAIT, OracleKeyword.WAIT)) {
getLexerEngine().nextToken();
} else if (getLexerEngine().skipIfEqual(OracleKeyword.SKIP)) {
getLexerEngine().accept(OracleKeyword.LOCKED);
}
}
@Override
protected void parseTableFactor(final SelectStatement selectStatement) {
if (getLexerEngine().skipIfEqual(OracleKeyword.ONLY)) {
getLexerEngine().skipIfEqual(Symbol.LEFT_PAREN);
parseQueryTableExpression(selectStatement);
getLexerEngine().skipIfEqual(Symbol.RIGHT_PAREN);
skipFlashbackQueryClause();
} else {
parseQueryTableExpression(selectStatement);
skipPivotClause(selectStatement);
skipFlashbackQueryClause();
}
}
private void parseQueryTableExpression(final SelectStatement selectStatement) {
parseTableFactorInternal(selectStatement);
parseSample(selectStatement);
skipPartition(selectStatement);
}
private void parseSample(final SelectStatement selectStatement) {
if (!getLexerEngine().skipIfEqual(OracleKeyword.SAMPLE)) {
return;
}
getLexerEngine().skipIfEqual(OracleKeyword.BLOCK);
getLexerEngine().skipParentheses(selectStatement);
if (getLexerEngine().skipIfEqual(OracleKeyword.SEED)) {
getLexerEngine().skipParentheses(selectStatement);
}
}
private void skipPartition(final SelectStatement selectStatement) {
skipPartition(selectStatement, OracleKeyword.PARTITION);
skipPartition(selectStatement, OracleKeyword.SUBPARTITION);
}
private void skipPartition(final SelectStatement selectStatement, final OracleKeyword keyword) {
if (!getLexerEngine().skipIfEqual(keyword)) {
return;
}
getLexerEngine().skipParentheses(selectStatement);
if (getLexerEngine().skipIfEqual(DefaultKeyword.FOR)) {
getLexerEngine().skipParentheses(selectStatement);
}
}
private void skipFlashbackQueryClause() {
if (isFlashbackQueryClauseForVersions() || isFlashbackQueryClauseForAs()) {
throw new UnsupportedOperationException("Cannot support Flashback Query");
}
}
private boolean isFlashbackQueryClauseForVersions() {
return getLexerEngine().skipIfEqual(OracleKeyword.VERSIONS) && getLexerEngine().skipIfEqual(DefaultKeyword.BETWEEN);
}
private boolean isFlashbackQueryClauseForAs() {
return getLexerEngine().skipIfEqual(DefaultKeyword.AS) && getLexerEngine().skipIfEqual(DefaultKeyword.OF)
&& (getLexerEngine().skipIfEqual(OracleKeyword.SCN) || getLexerEngine().skipIfEqual(OracleKeyword.TIMESTAMP));
}
private void skipPivotClause(final SelectStatement selectStatement) {
if (getLexerEngine().skipIfEqual(OracleKeyword.PIVOT)) {
getLexerEngine().skipIfEqual(OracleKeyword.XML);
getLexerEngine().skipParentheses(selectStatement);
} else if (getLexerEngine().skipIfEqual(OracleKeyword.UNPIVOT)) {
if (getLexerEngine().skipIfEqual(OracleKeyword.INCLUDE)) {
getLexerEngine().accept(OracleKeyword.NULLS);
} else if (getLexerEngine().skipIfEqual(OracleKeyword.EXCLUDE)) {
getLexerEngine().accept(OracleKeyword.NULLS);
}
getLexerEngine().skipParentheses(selectStatement);
}
}
@Override
protected Keyword[] getSynonymousKeywordsForDistinct() {
return new Keyword[] {DefaultKeyword.UNIQUE};
}
@Override
protected Keyword[] getSkippedKeywordsBeforeSelectItem() {
return new Keyword[] {OracleKeyword.CONNECT_BY_ROOT};
}
@Override
protected Keyword[] getUnsupportedKeywordBeforeGroupByItem() {
return new Keyword[] {OracleKeyword.ROLLUP, OracleKeyword.CUBE, OracleKeyword.GROUPING};
}
@Override
protected OrderType getNullOrderType() {
if (!getLexerEngine().skipIfEqual(OracleKeyword.NULLS)) {
return OrderType.ASC;
}
if (getLexerEngine().skipIfEqual(OracleKeyword.FIRST)) {
return OrderType.ASC;
}
if (getLexerEngine().skipIfEqual(OracleKeyword.LAST)) {
return OrderType.DESC;
}
throw new SQLParsingException(getLexerEngine());
}
}