/*
* 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.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.parser.AbstractSQLParser;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.exception.SQLParsingUnsupportedException;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dql.select.AbstractSelectParser;
import java.util.Collection;
import java.util.Collections;
/**
* Oracle Select语句解析器.
*
* @author zhangliang
*/
public final class OracleSelectParser extends AbstractSelectParser {
public OracleSelectParser(final AbstractSQLParser sqlParser) {
super(sqlParser);
}
@Override
protected Collection getCustomizedDistinctKeywords() {
return Collections.singletonList(DefaultKeyword.UNIQUE);
}
@Override
protected Keyword[] getSkippedKeywordsBeforeSelectItem() {
return new Keyword[] {OracleKeyword.CONNECT_BY_ROOT};
}
@Override
protected void customizedBetweenWhereAndGroupBy() {
skipHierarchicalQueryClause();
}
private void skipHierarchicalQueryClause() {
skipConnect();
skipStart();
skipConnect();
}
private void skipStart() {
if (getSqlParser().skipIfEqual(OracleKeyword.START)) {
getSqlParser().accept(DefaultKeyword.WITH);
getSqlParser().parseComparisonCondition(getSelectStatement());
}
}
private void skipConnect() {
if (getSqlParser().skipIfEqual(OracleKeyword.CONNECT)) {
getSqlParser().accept(DefaultKeyword.BY);
getSqlParser().skipIfEqual(OracleKeyword.PRIOR);
if (getSqlParser().skipIfEqual(OracleKeyword.NOCYCLE)) {
getSqlParser().skipIfEqual(OracleKeyword.PRIOR);
}
getSqlParser().parseComparisonCondition(getSelectStatement());
}
}
@Override
protected void customizedBetweenGroupByAndOrderBy() {
skipModelClause();
}
private void skipModelClause() {
if (!getSqlParser().skipIfEqual(OracleKeyword.MODEL)) {
return;
}
skipCellReferenceOptions();
getSqlParser().skipIfEqual(OracleKeyword.RETURN);
getSqlParser().skipIfEqual(DefaultKeyword.ALL);
getSqlParser().skipIfEqual(OracleKeyword.UPDATED);
getSqlParser().skipIfEqual(OracleKeyword.ROWS);
while (getSqlParser().skipIfEqual(OracleKeyword.REFERENCE)) {
getSqlParser().getLexer().nextToken();
getSqlParser().accept(DefaultKeyword.ON);
getSqlParser().skipParentheses();
skipModelColumnClause();
skipCellReferenceOptions();
}
skipMainModelClause();
}
private void skipCellReferenceOptions() {
if (getSqlParser().skipIfEqual(OracleKeyword.IGNORE)) {
getSqlParser().accept(OracleKeyword.NAV);
} else if (getSqlParser().skipIfEqual(OracleKeyword.KEEP)) {
getSqlParser().accept(OracleKeyword.NAV);
}
if (getSqlParser().skipIfEqual(DefaultKeyword.UNIQUE)) {
getSqlParser().skipIfEqual(OracleKeyword.DIMENSION, OracleKeyword.SINGLE);
getSqlParser().skipIfEqual(OracleKeyword.REFERENCE);
}
}
private void skipMainModelClause() {
if (getSqlParser().skipIfEqual(OracleKeyword.MAIN)) {
getSqlParser().getLexer().nextToken();
}
skipQueryPartitionClause();
getSqlParser().accept(OracleKeyword.DIMENSION);
getSqlParser().accept(DefaultKeyword.BY);
getSqlParser().skipParentheses();
getSqlParser().accept(OracleKeyword.MEASURES);
getSqlParser().skipParentheses();
skipCellReferenceOptions();
skipModelRulesClause();
}
private void skipModelRulesClause() {
if (getSqlParser().skipIfEqual(OracleKeyword.RULES)) {
getSqlParser().skipIfEqual(DefaultKeyword.UPDATE);
getSqlParser().skipIfEqual(OracleKeyword.UPSERT);
if (getSqlParser().skipIfEqual(OracleKeyword.AUTOMATIC)) {
getSqlParser().accept(DefaultKeyword.ORDER);
} else if (getSqlParser().skipIfEqual(OracleKeyword.SEQUENTIAL)) {
getSqlParser().accept(DefaultKeyword.ORDER);
}
}
if (getSqlParser().skipIfEqual(DefaultKeyword.ITERATE)) {
getSqlParser().skipParentheses();
if (getSqlParser().skipIfEqual(DefaultKeyword.UNTIL)) {
getSqlParser().skipParentheses();
}
}
getSqlParser().skipParentheses();
}
private void skipQueryPartitionClause() {
if (getSqlParser().skipIfEqual(OracleKeyword.PARTITION)) {
getSqlParser().accept(DefaultKeyword.BY);
if (getSqlParser().equalAny(Symbol.LEFT_PAREN)) {
getSqlParser().skipParentheses();
} else {
throw new UnsupportedOperationException("Cannot support PARTITION BY without ()");
}
}
}
private void skipModelColumnClause() {
throw new SQLParsingUnsupportedException(getSqlParser().getLexer().getCurrentToken().getType());
}
@Override
protected void customizedSelect() {
if (getSqlParser().equalAny(DefaultKeyword.FOR)) {
skipForUpdate();
}
if (getSelectStatement().getOrderByItems().isEmpty()) {
parseOrderBy();
}
}
@Override
protected void parseGroupBy() {
if (getSqlParser().equalAny(DefaultKeyword.GROUP)) {
getSqlParser().getLexer().nextToken();
getSqlParser().accept(DefaultKeyword.BY);
while (true) {
if (getSqlParser().equalAny(OracleKeyword.ROLLUP, OracleKeyword.CUBE, OracleKeyword.GROUPING)) {
throw new UnsupportedOperationException("Cannot support ROLLUP, CUBE, GROUPING SETS");
}
addGroupByItem(getSqlParser().parseExpression());
if (!getSqlParser().equalAny(Symbol.COMMA)) {
break;
}
getSqlParser().getLexer().nextToken();
}
if (getSqlParser().skipIfEqual(DefaultKeyword.HAVING)) {
throw new UnsupportedOperationException("Cannot support Having");
}
getSelectStatement().setGroupByLastPosition(getSqlParser().getLexer().getCurrentToken().getEndPosition() - getSqlParser().getLexer().getCurrentToken().getLiterals().length());
}
}
@Override
protected void customizedParseTableFactor() {
if (getSqlParser().skipIfEqual(OracleKeyword.ONLY)) {
getSqlParser().skipIfEqual(Symbol.LEFT_PAREN);
parseQueryTableExpression();
getSqlParser().skipIfEqual(Symbol.RIGHT_PAREN);
skipFlashbackQueryClause();
} else {
parseQueryTableExpression();
skipPivotClause();
skipFlashbackQueryClause();
}
}
private void parseQueryTableExpression() {
parseTableFactor();
parseSample();
skipPartition();
}
private void parseSample() {
if (getSqlParser().skipIfEqual(OracleKeyword.SAMPLE)) {
getSqlParser().skipIfEqual(OracleKeyword.BLOCK);
getSqlParser().skipParentheses();
if (getSqlParser().skipIfEqual(OracleKeyword.SEED)) {
getSqlParser().skipParentheses();
}
}
}
private void skipPartition() {
skipPartition(OracleKeyword.PARTITION);
skipPartition(OracleKeyword.SUBPARTITION);
}
private void skipPartition(final OracleKeyword keyword) {
if (getSqlParser().skipIfEqual(keyword)) {
getSqlParser().skipParentheses();
if (getSqlParser().skipIfEqual(DefaultKeyword.FOR)) {
getSqlParser().skipParentheses();
}
}
}
private void skipPivotClause() {
if (getSqlParser().skipIfEqual(OracleKeyword.PIVOT)) {
getSqlParser().skipIfEqual(OracleKeyword.XML);
getSqlParser().skipParentheses();
} else if (getSqlParser().skipIfEqual(OracleKeyword.UNPIVOT)) {
if (getSqlParser().skipIfEqual(OracleKeyword.INCLUDE)) {
getSqlParser().accept(OracleKeyword.NULLS);
} else if (getSqlParser().skipIfEqual(OracleKeyword.EXCLUDE)) {
getSqlParser().accept(OracleKeyword.NULLS);
}
getSqlParser().skipParentheses();
}
}
private void skipFlashbackQueryClause() {
if (isFlashbackQueryClauseForVersions() || isFlashbackQueryClauseForAs()) {
throw new UnsupportedOperationException("Cannot support Flashback Query");
}
}
private boolean isFlashbackQueryClauseForVersions() {
return getSqlParser().skipIfEqual(OracleKeyword.VERSIONS) && getSqlParser().skipIfEqual(DefaultKeyword.BETWEEN);
}
private boolean isFlashbackQueryClauseForAs() {
return getSqlParser().skipIfEqual(DefaultKeyword.AS) && getSqlParser().skipIfEqual(OracleKeyword.OF)
&& (getSqlParser().skipIfEqual(OracleKeyword.SCN) || getSqlParser().skipIfEqual(OracleKeyword.TIMESTAMP));
}
private void skipForUpdate() {
getSqlParser().getLexer().nextToken();
getSqlParser().accept(DefaultKeyword.UPDATE);
if (getSqlParser().skipIfEqual(OracleKeyword.OF)) {
do {
getSqlParser().parseExpression();
} while (getSqlParser().skipIfEqual(Symbol.COMMA));
}
if (getSqlParser().equalAny(OracleKeyword.NOWAIT, OracleKeyword.WAIT)) {
getSqlParser().getLexer().nextToken();
} else if (getSqlParser().skipIfEqual(OracleKeyword.SKIP)) {
getSqlParser().accept(OracleKeyword.LOCKED);
}
}
@Override
protected void skipAfterOrderByItem() {
if (getSqlParser().skipIfEqual(OracleKeyword.NULLS)) {
getSqlParser().getLexer().nextToken();
if (!getSqlParser().skipIfEqual(OracleKeyword.FIRST, OracleKeyword.LAST)) {
throw new SQLParsingUnsupportedException(getSqlParser().getLexer().getCurrentToken().getType());
}
}
}
}