diff --git a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/window/WindowConverter.java b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/window/WindowConverter.java index a8a454d3e365f..f5e19be101ded 100644 --- a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/window/WindowConverter.java +++ b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/window/WindowConverter.java @@ -21,13 +21,16 @@ import lombok.NoArgsConstructor; import org.apache.calcite.sql.SqlIdentifier; import org.apache.calcite.sql.SqlLiteral; +import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlNodeList; import org.apache.calcite.sql.SqlWindow; import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowItemSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowSegment; import org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.expression.ExpressionConverter; -import java.util.Collections; +import java.util.Collection; +import java.util.LinkedList; import java.util.Optional; /** @@ -43,11 +46,17 @@ public final class WindowConverter { * @return sql node list */ public static Optional convert(final WindowSegment segment) { - SqlIdentifier sqlIdentifier = new SqlIdentifier(segment.getIdentifierValue().getValue(), SqlParserPos.ZERO); - SqlNodeList partitionList = new SqlNodeList(Collections.singletonList(ExpressionConverter.convert(segment.getPartitionListSegments().iterator().next()).get()), SqlParserPos.ZERO); - SqlNodeList orderList = new SqlNodeList(SqlParserPos.ZERO); - SqlWindow sqlWindow = new SqlWindow(SqlParserPos.ZERO, sqlIdentifier, null, partitionList, orderList, SqlLiteral.createBoolean(false, SqlParserPos.ZERO), null, null, null); - SqlNodeList result = new SqlNodeList(Collections.singletonList(sqlWindow), SqlParserPos.ZERO); + Collection sqlWindows = new LinkedList<>(); + for (WindowItemSegment each : segment.getItemSegments()) { + SqlIdentifier sqlIdentifier = null == each.getWindowName() ? new SqlIdentifier("", SqlParserPos.ZERO) : new SqlIdentifier(each.getWindowName().getValue(), SqlParserPos.ZERO); + Collection partitionNodes = new LinkedList<>(); + each.getPartitionListSegments().forEach(expressionSegment -> ExpressionConverter.convert(expressionSegment).ifPresent(partitionNodes::add)); + SqlNodeList partitionList = new SqlNodeList(partitionNodes, SqlParserPos.ZERO); + SqlNodeList orderList = new SqlNodeList(SqlParserPos.ZERO); + SqlWindow sqlWindow = new SqlWindow(SqlParserPos.ZERO, sqlIdentifier, null, partitionList, orderList, SqlLiteral.createBoolean(false, SqlParserPos.ZERO), null, null, null); + sqlWindows.add(sqlWindow); + } + SqlNodeList result = new SqlNodeList(sqlWindows, SqlParserPos.ZERO); return Optional.of(result); } } diff --git a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java index c38ccaca6473b..e66945f729433 100644 --- a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java +++ b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java @@ -145,9 +145,7 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ViewNamesContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WeightStringFunctionContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WhereClauseContext; -import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowClauseContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowFunctionContext; -import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowItemContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WithClauseContext; import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType; import org.apache.shardingsphere.sql.parser.sql.common.enums.CombineType; @@ -863,19 +861,6 @@ public ASTNode visitTableStatement(final TableStatementContext ctx) { return result; } - @Override - public ASTNode visitWindowClause(final WindowClauseContext ctx) { - if (null != ctx.windowItem()) { - return new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getWindowItem(ctx.windowItem(0)), - getExpressions(ctx.windowItem(0).windowSpecification().expr())); - } - return new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); - } - - private IdentifierValue getWindowItem(final WindowItemContext ctx) { - return new IdentifierValue(ctx.identifier().getText()); - } - @Override public ASTNode visitHavingClause(final HavingClauseContext ctx) { ExpressionSegment expr = (ExpressionSegment) visit(ctx.expr()); diff --git a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/type/MySQLDMLStatementVisitor.java b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/type/MySQLDMLStatementVisitor.java index 189e2b515ea63..7cd45a730cec0 100644 --- a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/type/MySQLDMLStatementVisitor.java +++ b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/type/MySQLDMLStatementVisitor.java @@ -21,16 +21,24 @@ import org.apache.shardingsphere.sql.parser.api.visitor.statement.type.DMLStatementVisitor; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CallContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DoStatementContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ExprContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.HandlerStatementContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ImportStatementContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.IndexHintContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LoadDataStatementContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LoadStatementContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.LoadXmlStatementContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowClauseContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowItemContext; import org.apache.shardingsphere.sql.parser.mysql.visitor.statement.MySQLStatementVisitor; import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.OrderBySegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowItemSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.IndexHintSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment; +import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue; import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLCallStatement; import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLDoStatement; import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLHandlerStatement; @@ -40,6 +48,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -114,4 +123,41 @@ public ASTNode visitIndexHint(final IndexHintContext ctx) { } return result; } + + @Override + public ASTNode visitWindowClause(final WindowClauseContext ctx) { + WindowSegment result = new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + for (WindowItemContext each : ctx.windowItem()) { + result.getItemSegments().add((WindowItemSegment) visit(each)); + } + return result; + } + + @Override + public ASTNode visitWindowItem(final WindowItemContext ctx) { + WindowItemSegment result = new WindowItemSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + result.setWindowName(new IdentifierValue(ctx.identifier().getText())); + if (null != ctx.windowSpecification().PARTITION()) { + result.setPartitionListSegments(getExpressions(ctx.windowSpecification().expr())); + } + if (null != ctx.windowSpecification().orderByClause()) { + result.setOrderBySegment((OrderBySegment) visit(ctx.windowSpecification().orderByClause())); + } + if (null != ctx.windowSpecification().frameClause()) { + result.setFrameClause(new CommonExpressionSegment(ctx.windowSpecification().frameClause().start.getStartIndex(), ctx.windowSpecification().frameClause().stop.getStopIndex(), + ctx.windowSpecification().frameClause().getText())); + } + return result; + } + + private Collection getExpressions(final List exprList) { + if (null == exprList) { + return Collections.emptyList(); + } + Collection result = new ArrayList<>(exprList.size()); + for (ExprContext each : exprList) { + result.add((ExpressionSegment) visit(each)); + } + return result; + } } diff --git a/parser/sql/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/OpenGaussStatementVisitor.java b/parser/sql/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/OpenGaussStatementVisitor.java index 6b31aa954726a..b3335d9a74197 100644 --- a/parser/sql/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/OpenGaussStatementVisitor.java +++ b/parser/sql/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/OpenGaussStatementVisitor.java @@ -115,7 +115,7 @@ import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.WhereOrCurrentClauseContext; import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.WindowClauseContext; import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.WindowDefinitionContext; -import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.WindowSpecificationContext; +import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.WindowDefinitionListContext; import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.IntoClauseContext; import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType; import org.apache.shardingsphere.sql.parser.sql.common.enums.CombineType; @@ -177,6 +177,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.NameSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.ParameterMarkerSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowItemSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment; @@ -1038,19 +1039,38 @@ public ASTNode visitHavingClause(final HavingClauseContext ctx) { @Override public ASTNode visitWindowClause(final WindowClauseContext ctx) { - if (null != ctx.windowDefinitionList()) { - return new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getWindowItem(ctx.windowDefinitionList().windowDefinition()), - getWindowSpecification(ctx.windowDefinitionList().windowDefinition().windowSpecification())); - } - return new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + WindowSegment result = new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + appendWindowItems(ctx.windowDefinitionList(), result.getItemSegments()); + return result; } - private IdentifierValue getWindowItem(final WindowDefinitionContext ctx) { - return new IdentifierValue(ctx.colId().identifier().getText()); + private void appendWindowItems(final WindowDefinitionListContext ctx, final Collection windowItems) { + if (null != ctx.windowDefinitionList()) { + appendWindowItems(ctx.windowDefinitionList(), windowItems); + windowItems.add((WindowItemSegment) visit(ctx.windowDefinition())); + return; + } + windowItems.add((WindowItemSegment) visit(ctx.windowDefinition())); } - private Collection getWindowSpecification(final WindowSpecificationContext ctx) { - return createInsertValuesSegments(ctx.partitionClause().exprList()); + @SuppressWarnings("unchecked") + @Override + public ASTNode visitWindowDefinition(final WindowDefinitionContext ctx) { + WindowItemSegment result = new WindowItemSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + result.setWindowName(new IdentifierValue(ctx.colId().getText())); + if (null != ctx.windowSpecification().partitionClause()) { + CollectionValue value = (CollectionValue) visit(ctx.windowSpecification().partitionClause().exprList()); + result.setPartitionListSegments(value.getValue()); + } + if (null != ctx.windowSpecification().sortClause()) { + OrderBySegment orderBySegment = (OrderBySegment) visit(ctx.windowSpecification().sortClause()); + result.setOrderBySegment(orderBySegment); + } + if (null != ctx.windowSpecification().frameClause()) { + result.setFrameClause(new CommonExpressionSegment(ctx.windowSpecification().frameClause().start.getStartIndex(), ctx.windowSpecification().frameClause().stop.getStopIndex(), + ctx.windowSpecification().frameClause().getText())); + } + return result; } @Override diff --git a/parser/sql/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/PostgreSQLStatementVisitor.java b/parser/sql/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/PostgreSQLStatementVisitor.java index 549d4c5b67aa9..8d1475eac7fb3 100644 --- a/parser/sql/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/PostgreSQLStatementVisitor.java +++ b/parser/sql/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/PostgreSQLStatementVisitor.java @@ -109,7 +109,7 @@ import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.WhereOrCurrentClauseContext; import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.WindowClauseContext; import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.WindowDefinitionContext; -import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.WindowSpecificationContext; +import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.WindowDefinitionListContext; import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.IntoClauseContext; import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParserBaseVisitor; import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType; @@ -172,6 +172,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.NameSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.ParameterMarkerSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowItemSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment; @@ -1004,19 +1005,38 @@ public ASTNode visitHavingClause(final HavingClauseContext ctx) { @Override public ASTNode visitWindowClause(final WindowClauseContext ctx) { - if (null != ctx.windowDefinitionList()) { - return new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getWindowItem(ctx.windowDefinitionList().windowDefinition()), - getWindowSpecification(ctx.windowDefinitionList().windowDefinition().windowSpecification())); - } - return new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + WindowSegment result = new WindowSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + appendWindowItems(ctx.windowDefinitionList(), result.getItemSegments()); + return result; } - private IdentifierValue getWindowItem(final WindowDefinitionContext ctx) { - return new IdentifierValue(ctx.colId().identifier().getText()); + private void appendWindowItems(final WindowDefinitionListContext ctx, final Collection windowItems) { + if (null != ctx.windowDefinitionList()) { + appendWindowItems(ctx.windowDefinitionList(), windowItems); + windowItems.add((WindowItemSegment) visit(ctx.windowDefinition())); + return; + } + windowItems.add((WindowItemSegment) visit(ctx.windowDefinition())); } - private Collection getWindowSpecification(final WindowSpecificationContext ctx) { - return createInsertValuesSegments(ctx.partitionClause().exprList()); + @SuppressWarnings("unchecked") + @Override + public ASTNode visitWindowDefinition(final WindowDefinitionContext ctx) { + WindowItemSegment result = new WindowItemSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex()); + result.setWindowName(new IdentifierValue(ctx.colId().getText())); + if (null != ctx.windowSpecification().partitionClause()) { + CollectionValue value = (CollectionValue) visit(ctx.windowSpecification().partitionClause().exprList()); + result.setPartitionListSegments(value.getValue()); + } + if (null != ctx.windowSpecification().sortClause()) { + OrderBySegment orderBySegment = (OrderBySegment) visit(ctx.windowSpecification().sortClause()); + result.setOrderBySegment(orderBySegment); + } + if (null != ctx.windowSpecification().frameClause()) { + result.setFrameClause(new CommonExpressionSegment(ctx.windowSpecification().frameClause().start.getStartIndex(), ctx.windowSpecification().frameClause().stop.getStopIndex(), + ctx.windowSpecification().frameClause().getText())); + } + return result; } @Override diff --git a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowItemSegment.java b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowItemSegment.java new file mode 100644 index 0000000000000..710d43fa66e30 --- /dev/null +++ b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowItemSegment.java @@ -0,0 +1,46 @@ +/* + * 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.sql.parser.sql.common.segment.generic; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.apache.shardingsphere.sql.parser.sql.common.segment.SQLSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment; +import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.OrderBySegment; +import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue; + +import java.util.Collection; + +@RequiredArgsConstructor +@Getter +@Setter +public class WindowItemSegment implements SQLSegment { + + private final int startIndex; + + private final int stopIndex; + + private IdentifierValue windowName; + + private Collection partitionListSegments; + + private OrderBySegment orderBySegment; + + private ExpressionSegment frameClause; +} diff --git a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowSegment.java b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowSegment.java index d625d66c1ea42..5f969e795bbbd 100644 --- a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowSegment.java +++ b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/WindowSegment.java @@ -20,10 +20,9 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import org.apache.shardingsphere.sql.parser.sql.common.segment.SQLSegment; -import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment; -import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue; import java.util.Collection; +import java.util.LinkedList; /** * Window segment. @@ -36,14 +35,5 @@ public final class WindowSegment implements SQLSegment { private final int stopIndex; - private IdentifierValue identifierValue; - - private Collection partitionListSegments; - - public WindowSegment(final int startIndex, final int stopIndex, final IdentifierValue identifierValue, final Collection partitionListSegments) { - this.startIndex = startIndex; - this.stopIndex = stopIndex; - this.identifierValue = identifierValue; - this.partitionListSegments = partitionListSegments; - } + private final Collection itemSegments = new LinkedList<>(); }