提交 66e55075 编写于 作者: T terrymanu

for #2084, add pagination for oracle with 3rd generation parse engine

上级 cf424400
......@@ -18,15 +18,20 @@
package org.apache.shardingsphere.core.parse.antlr.extractor.impl.dml.select;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import org.antlr.v4.runtime.ParserRuleContext;
import org.apache.shardingsphere.core.parse.antlr.extractor.api.OptionalSQLSegmentExtractor;
import org.apache.shardingsphere.core.parse.antlr.extractor.impl.dml.select.item.SelectItemExtractor;
import org.apache.shardingsphere.core.parse.antlr.extractor.util.ExtractorUtils;
import org.apache.shardingsphere.core.parse.antlr.extractor.util.RuleName;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.SelectItemsSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.item.ColumnSelectItemSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.item.SelectItemSegment;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeSet;
/**
* Select items extractor.
......@@ -36,8 +41,17 @@ import java.util.Map;
*/
public final class SelectItemsExtractor implements OptionalSQLSegmentExtractor {
// TODO recognize database type, only oracle and sqlserver can use row number
private final Collection<String> rowNumberIdentifiers;
private final SelectItemExtractor selectItemExtractor = new SelectItemExtractor();
public SelectItemsExtractor() {
rowNumberIdentifiers = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
rowNumberIdentifiers.add("rownum");
rowNumberIdentifiers.add("ROW_NUMBER");
}
@Override
public Optional<SelectItemsSegment> extract(final ParserRuleContext ancestorNode, final Map<ParserRuleContext, Integer> parameterMarkerIndexes) {
ParserRuleContext selectItemsNode = ExtractorUtils.getFirstChildNode(findMainQueryNode(ancestorNode), RuleName.SELECT_ITEMS);
......@@ -47,6 +61,7 @@ public final class SelectItemsExtractor implements OptionalSQLSegmentExtractor {
setUnqualifiedShorthandSelectItemSegment(unqualifiedShorthandNode.get(), result, parameterMarkerIndexes);
}
setSelectItemSegment(selectItemsNode, result, parameterMarkerIndexes);
result.getSelectItems().addAll(extractRowNumberSelectItem(ancestorNode, parameterMarkerIndexes));
return Optional.of(result);
}
......@@ -84,4 +99,17 @@ public final class SelectItemsExtractor implements OptionalSQLSegmentExtractor {
}
return ancestorNode;
}
private Collection<SelectItemSegment> extractRowNumberSelectItem(final ParserRuleContext ancestorNode, final Map<ParserRuleContext, Integer> parameterMarkerIndexes) {
Collection<SelectItemSegment> result = new LinkedList<>();
Collection<ParserRuleContext> selectItemNodes = ExtractorUtils.getAllDescendantNodes(ancestorNode, RuleName.SELECT_ITEM);
for (ParserRuleContext each : selectItemNodes) {
Optional<? extends SelectItemSegment> selectItemSegment = selectItemExtractor.extract(each, parameterMarkerIndexes);
Preconditions.checkState(selectItemSegment.isPresent());
if (selectItemSegment.get() instanceof ColumnSelectItemSegment && rowNumberIdentifiers.contains(((ColumnSelectItemSegment) selectItemSegment.get()).getName())) {
result.add(selectItemSegment.get());
}
}
return result;
}
}
......@@ -25,6 +25,7 @@ import org.apache.shardingsphere.core.parse.antlr.filler.api.ShardingRuleAwareFi
import org.apache.shardingsphere.core.parse.antlr.filler.api.ShardingTableMetaDataAwareFiller;
import org.apache.shardingsphere.core.parse.antlr.filler.common.dml.PredicateUtils;
import org.apache.shardingsphere.core.parse.antlr.filler.encrypt.dml.EncryptOrPredicateFiller;
import org.apache.shardingsphere.core.parse.antlr.filler.sharding.dml.select.ShardingRowNumberPredicateFiller;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.AndPredicateSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.OrPredicateSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.PredicateSegment;
......@@ -32,6 +33,7 @@ import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.valu
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.value.PredicateCompareRightValue;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.value.PredicateInRightValue;
import org.apache.shardingsphere.core.parse.antlr.sql.statement.SQLStatement;
import org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.SelectStatement;
import org.apache.shardingsphere.core.parse.old.parser.context.condition.AndCondition;
import org.apache.shardingsphere.core.parse.old.parser.context.condition.Column;
import org.apache.shardingsphere.core.parse.old.parser.context.condition.Condition;
......@@ -47,6 +49,8 @@ import org.apache.shardingsphere.core.rule.ShardingRule;
@Setter
public final class ShardingOrPredicateFiller implements SQLSegmentFiller<OrPredicateSegment>, ShardingRuleAwareFiller, ShardingTableMetaDataAwareFiller {
private final ShardingRowNumberPredicateFiller shardingRowNumberPredicateFiller = new ShardingRowNumberPredicateFiller();
private ShardingRule shardingRule;
private ShardingTableMetaData shardingTableMetaData;
......@@ -54,6 +58,9 @@ public final class ShardingOrPredicateFiller implements SQLSegmentFiller<OrPredi
@Override
public void fill(final OrPredicateSegment sqlSegment, final SQLStatement sqlStatement) {
sqlStatement.getRouteConditions().getOrCondition().getAndConditions().addAll(buildCondition(sqlSegment, sqlStatement).getAndConditions());
if (sqlStatement instanceof SelectStatement) {
shardingRowNumberPredicateFiller.fill(sqlSegment, sqlStatement);
}
}
/**
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.shardingsphere.core.parse.antlr.filler.sharding.dml.select;
import com.google.common.base.Optional;
import org.apache.shardingsphere.core.parse.antlr.filler.api.SQLSegmentFiller;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.expr.ExpressionSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.expr.simple.LiteralExpressionSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.AndPredicateSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.OrPredicateSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.PredicateSegment;
import org.apache.shardingsphere.core.parse.antlr.sql.segment.dml.predicate.value.PredicateCompareRightValue;
import org.apache.shardingsphere.core.parse.antlr.sql.statement.SQLStatement;
import org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.SelectStatement;
import org.apache.shardingsphere.core.parse.antlr.sql.token.OffsetToken;
import org.apache.shardingsphere.core.parse.antlr.sql.token.RowCountToken;
import org.apache.shardingsphere.core.parse.old.parser.context.limit.Limit;
import org.apache.shardingsphere.core.parse.old.parser.context.limit.LimitValue;
import org.apache.shardingsphere.core.parse.old.parser.context.selectitem.SelectItem;
import java.util.Collection;
import java.util.LinkedList;
import java.util.TreeSet;
/**
* Row number predicate filler for sharding.
*
* @author zhangliang
*/
public final class ShardingRowNumberPredicateFiller implements SQLSegmentFiller<OrPredicateSegment> {
// TODO recognize database type, only oracle and sqlserver can use row number
private final Collection<String> rowNumberIdentifiers;
public ShardingRowNumberPredicateFiller() {
rowNumberIdentifiers = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
rowNumberIdentifiers.add("rownum");
rowNumberIdentifiers.add("ROW_NUMBER");
}
@Override
public void fill(final OrPredicateSegment sqlSegment, final SQLStatement sqlStatement) {
SelectStatement selectStatement = (SelectStatement) sqlStatement;
Optional<String> rowNumberAlias = findRowNumberAlias(selectStatement);
Collection<PredicateSegment> rowNumberPredicates = getRowNumberPredicates(sqlSegment, rowNumberAlias.orNull());
if (!rowNumberPredicates.isEmpty()) {
fillLimit(selectStatement, rowNumberPredicates);
}
}
private Optional<String> findRowNumberAlias(final SelectStatement selectStatement) {
for (SelectItem each : selectStatement.getItems()) {
if (rowNumberIdentifiers.contains(each.getExpression())) {
return each.getAlias();
}
}
return Optional.absent();
}
private Collection<PredicateSegment> getRowNumberPredicates(final OrPredicateSegment sqlSegment, final String rowNumberAlias) {
Collection<PredicateSegment> result = new LinkedList<>();
for (AndPredicateSegment each : sqlSegment.getAndPredicates()) {
for (PredicateSegment predicate : each.getPredicates()) {
if (isRowNumberColumn(predicate, rowNumberAlias) && isCompareCondition(predicate)) {
result.add(predicate);
}
}
}
return result;
}
private boolean isRowNumberColumn(final PredicateSegment predicate, final String rowNumberAlias) {
return rowNumberIdentifiers.contains(predicate.getColumn().getName()) || predicate.getColumn().getName().equalsIgnoreCase(rowNumberAlias);
}
private boolean isCompareCondition(final PredicateSegment predicate) {
if (!(predicate.getRightValue() instanceof PredicateCompareRightValue)) {
return false;
}
String operator = ((PredicateCompareRightValue) predicate.getRightValue()).getOperator();
return "<".equals(operator) || "<=".equals(operator) || ">".equals(operator) || ">=".equals(operator);
}
private void fillLimit(final SelectStatement selectStatement, final Collection<PredicateSegment> rowNumberPredicates) {
Limit limit = new Limit();
for (PredicateSegment each : rowNumberPredicates) {
ExpressionSegment expression = ((PredicateCompareRightValue) each.getRightValue()).getExpression();
switch (((PredicateCompareRightValue) each.getRightValue()).getOperator()) {
case "<":
limit.setRowCount(createLimitValue(expression, false));
if (-1 != limit.getRowCount().getValue()) {
selectStatement.addSQLToken(new RowCountToken(expression.getStartIndex(), expression.getStopIndex(), limit.getRowCount().getValue()));
}
break;
case "<=":
limit.setRowCount(createLimitValue(expression, true));
if (-1 != limit.getRowCount().getValue()) {
selectStatement.addSQLToken(new RowCountToken(expression.getStartIndex(), expression.getStopIndex(), limit.getRowCount().getValue()));
}
break;
case ">":
limit.setOffset(createLimitValue(expression, false));
if (-1 != limit.getOffset().getValue()) {
selectStatement.addSQLToken(new OffsetToken(expression.getStartIndex(), expression.getStopIndex(), limit.getOffset().getValue()));
}
break;
case ">=":
limit.setOffset(createLimitValue(expression, true));
if (-1 != limit.getOffset().getValue()) {
selectStatement.addSQLToken(new OffsetToken(expression.getStartIndex(), expression.getStopIndex(), limit.getOffset().getValue()));
}
break;
default:
break;
}
}
selectStatement.setLimit(limit);
}
private LimitValue createLimitValue(final ExpressionSegment expression, final boolean boundOpened) {
return expression instanceof ParameterMarkerExpressionSegment ? new LimitValue(-1, ((ParameterMarkerExpressionSegment) expression).getParameterMarkerIndex(), boundOpened)
: new LimitValue(((Number) ((LiteralExpressionSegment) expression).getLiterals()).intValue(), -1, boundOpened);
}
}
......@@ -37,6 +37,8 @@ import org.apache.shardingsphere.core.rule.ShardingRule;
@Setter
public final class ShardingSubqueryPredicateFiller implements SQLSegmentFiller<SubqueryPredicateSegment>, ShardingRuleAwareFiller, ShardingTableMetaDataAwareFiller {
private final ShardingRowNumberPredicateFiller shardingRowNumberPredicateFiller = new ShardingRowNumberPredicateFiller();
private ShardingRule shardingRule;
private ShardingTableMetaData shardingTableMetaData;
......@@ -47,6 +49,7 @@ public final class ShardingSubqueryPredicateFiller implements SQLSegmentFiller<S
ShardingOrPredicateFiller shardingOrPredicateFiller = getShardingOrPredicateFiller();
for (OrPredicateSegment each : sqlSegment.getOrPredicates()) {
selectStatement.getSubqueryConditions().add(shardingOrPredicateFiller.buildCondition(each, sqlStatement));
shardingRowNumberPredicateFiller.fill(each, sqlStatement);
}
}
......
......@@ -57,7 +57,7 @@ public final class SQLParserFactory {
*/
public static SQLParser newInstance(
final DatabaseType dbType, final ShardingRule shardingRule, final LexerEngine lexerEngine, final ShardingTableMetaData shardingTableMetaData, final String sql) {
if (DatabaseType.MySQL == dbType || DatabaseType.H2 == dbType || DatabaseType.PostgreSQL == dbType) {
if (DatabaseType.MySQL == dbType || DatabaseType.H2 == dbType || DatabaseType.PostgreSQL == dbType || DatabaseType.Oracle == dbType) {
return new AntlrParsingEngine(dbType, sql, shardingRule, shardingTableMetaData);
}
lexerEngine.nextToken();
......@@ -81,7 +81,7 @@ public final class SQLParserFactory {
* @return sql parser
*/
public static SQLParser newInstance(final DatabaseType dbType, final EncryptRule encryptRule, final ShardingTableMetaData shardingTableMetaData, final String sql) {
if (DatabaseType.MySQL == dbType || DatabaseType.H2 == dbType || DatabaseType.PostgreSQL == dbType) {
if (DatabaseType.MySQL == dbType || DatabaseType.H2 == dbType || DatabaseType.PostgreSQL == dbType || DatabaseType.Oracle == dbType) {
return new AntlrParsingEngine(dbType, sql, encryptRule, shardingTableMetaData);
}
throw new SQLParsingUnsupportedException(String.format("Can not support %s", dbType));
......
......@@ -29,7 +29,7 @@
<sql-statement-rule context="insert" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.InsertStatement" extractor-rule-refs="table, columns, insertColumns, insertValues" />
<sql-statement-rule context="update" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.UpdateStatement" extractor-rule-refs="tableReferences, columns, setAssignments, where, predicate" />
<sql-statement-rule context="delete" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.DeleteStatement" extractor-rule-refs="tables, columns, where, predicate" />
<sql-statement-rule context="select" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.SelectStatement" extractor-rule-refs="tableReferences, columns, selectItems, where, predicate, groupBy, orderBy, subqueryPredicate" optimizer-class="org.apache.shardingsphere.core.parse.antlr.optimizer.select.SelectOptimizer" />
<sql-statement-rule context="select" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.dml.SelectStatement" extractor-rule-refs="tableReferences, columns, selectItems, subqueryPredicate, where, predicate, groupBy, orderBy" optimizer-class="org.apache.shardingsphere.core.parse.antlr.optimizer.select.SelectOptimizer" />
<sql-statement-rule context="setTransaction" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.tcl.SetTransactionStatement" />
<sql-statement-rule context="commit" sql-statement-class="org.apache.shardingsphere.core.parse.antlr.sql.statement.tcl.CommitStatement" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册