From 180cc35815ed1023cbbd22d0c5a4b6016ef11495 Mon Sep 17 00:00:00 2001 From: mch_ucchi <41606806+sohardforaname@users.noreply.github.com> Date: Thu, 11 Aug 2022 12:42:19 +0800 Subject: [PATCH] [Feature](nereids) support sub-query and alias in FromClause (#11035) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support sub-query and alias for TPC-H,for example: select * from (select * from (T1) A join T2 as B on T1.id = T2.id) T; --- .../apache/doris/nereids/NereidsPlanner.java | 6 + .../translator/PhysicalPlanTranslator.java | 1 + .../jobs/batch/FinalizeAnalyzeJob.java | 40 ++++ .../cascades/OptimizeGroupExpressionJob.java | 1 - .../doris/nereids/memo/GroupExpression.java | 10 +- .../nereids/parser/LogicalPlanBuilder.java | 58 +++++- .../doris/nereids/properties/OrderKey.java | 2 +- .../apache/doris/nereids/rules/RuleType.java | 9 + .../nereids/rules/analysis/BindRelation.java | 42 ++++- .../rules/analysis/BindSlotReference.java | 4 + .../rules/analysis/EliminateAliasNode.java | 66 +++++++ .../expressions/NamedExpressionUtil.java | 18 ++ .../doris/nereids/trees/expressions/Slot.java | 6 + .../trees/expressions/SlotReference.java | 5 + .../doris/nereids/trees/plans/PlanType.java | 1 + .../trees/plans/logical/LogicalProject.java | 1 + .../plans/logical/LogicalSubQueryAlias.java | 113 +++++++++++ .../trees/plans/visitor/PlanVisitor.java | 5 + .../nereids/util/AnalyzeSubQueryTest.java | 178 ++++++++++++++++++ .../doris/nereids/util/FieldChecker.java | 56 ++++++ .../doris/utframe/TestWithFeService.java | 9 + .../nereids_syntax_p0/sub_query_alias.out | 26 +++ .../nereids_syntax_p0/sub_query_alias.groovy | 72 +++++++ 23 files changed, 711 insertions(+), 18 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java create mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/util/AnalyzeSubQueryTest.java create mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java create mode 100644 regression-test/data/nereids_syntax_p0/sub_query_alias.out create mode 100644 regression-test/suites/nereids_syntax_p0/sub_query_alias.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java index 3a486c1898..173b68a69f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java @@ -26,6 +26,7 @@ import org.apache.doris.nereids.glue.LogicalPlanAdapter; import org.apache.doris.nereids.glue.translator.PhysicalPlanTranslator; import org.apache.doris.nereids.glue.translator.PlanTranslatorContext; import org.apache.doris.nereids.jobs.batch.DisassembleRulesJob; +import org.apache.doris.nereids.jobs.batch.FinalizeAnalyzeJob; import org.apache.doris.nereids.jobs.batch.JoinReorderRulesJob; import org.apache.doris.nereids.jobs.batch.NormalizeExpressionRulesJob; import org.apache.doris.nereids.jobs.batch.OptimizeRulesJob; @@ -106,6 +107,7 @@ public class NereidsPlanner extends Planner { // cascades style optimize phase. .setJobContext(outputProperties); + finalizeAnalyze(); rewrite(); // TODO: remove this condition, when stats collector is fully developed. if (ConnectContext.get().getSessionVariable().isEnableNereidsCBO()) { @@ -116,6 +118,10 @@ public class NereidsPlanner extends Planner { return getRoot().extractPlan(); } + private void finalizeAnalyze() { + new FinalizeAnalyzeJob(plannerContext).execute(); + } + /** * Logical plan rewrite based on a series of heuristic rules. */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java index 9270d51a41..1799c70123 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java @@ -402,6 +402,7 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor ExpressionTranslator.translate(e, context)) .collect(Collectors.toList()); + // TODO: fix the project alias of an aliased relation. PlanNode inputPlanNode = inputFragment.getPlanRoot(); List predicateList = inputPlanNode.getConjuncts(); Set requiredSlotIdList = new HashSet<>(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java new file mode 100644 index 0000000000..ef0a8e5da4 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java @@ -0,0 +1,40 @@ +// 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.doris.nereids.jobs.batch; + +import org.apache.doris.nereids.PlannerContext; +import org.apache.doris.nereids.rules.analysis.EliminateAliasNode; + +import com.google.common.collect.ImmutableList; + +/** + * Job to eliminate the logical node of sub query and alias + */ +public class FinalizeAnalyzeJob extends BatchRulesJob { + + /** + * constructor + * @param plannerContext ctx + */ + public FinalizeAnalyzeJob(PlannerContext plannerContext) { + super(plannerContext); + rulesJob.addAll(ImmutableList.of( + bottomUpBatch(ImmutableList.of(new EliminateAliasNode())) + )); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java index d43c8a7c68..4a2a876452 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupExpressionJob.java @@ -63,6 +63,5 @@ public class OptimizeGroupExpressionJob extends Job { } } } - } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java index 44f8d0f86c..587051d618 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java @@ -22,6 +22,8 @@ import org.apache.doris.nereids.properties.PhysicalProperties; import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; +import org.apache.doris.nereids.trees.plans.physical.PhysicalRelation; import org.apache.doris.statistics.StatsDeriveResult; import com.google.common.base.Preconditions; @@ -168,7 +170,13 @@ public class GroupExpression { return false; } GroupExpression that = (GroupExpression) o; - return plan.equals(that.plan) && children.equals(that.children); + // if the plan is LogicalRelation or PhysicalRelation, this == that should be true, + // when if one relation appear in plan more than once, + // we cannot distinguish them throw equals function, since equals function cannot use output info. + if (plan instanceof LogicalRelation || plan instanceof PhysicalRelation) { + return false; + } + return children.equals(that.children) && plan.equals(that.plan); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 2453759199..5ea7202629 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -21,6 +21,8 @@ package org.apache.doris.nereids.parser; import org.apache.doris.analysis.ArithmeticExpr.Operator; import org.apache.doris.nereids.DorisParser; import org.apache.doris.nereids.DorisParser.AggClauseContext; +import org.apache.doris.nereids.DorisParser.AliasedQueryContext; +import org.apache.doris.nereids.DorisParser.AliasedRelationContext; import org.apache.doris.nereids.DorisParser.ArithmeticBinaryContext; import org.apache.doris.nereids.DorisParser.ArithmeticUnaryContext; import org.apache.doris.nereids.DorisParser.BooleanLiteralContext; @@ -59,6 +61,7 @@ import org.apache.doris.nereids.DorisParser.SortItemContext; import org.apache.doris.nereids.DorisParser.StarContext; import org.apache.doris.nereids.DorisParser.StringLiteralContext; import org.apache.doris.nereids.DorisParser.SubqueryExpressionContext; +import org.apache.doris.nereids.DorisParser.TableAliasContext; import org.apache.doris.nereids.DorisParser.TableNameContext; import org.apache.doris.nereids.DorisParser.TypeConstructorContext; import org.apache.doris.nereids.DorisParser.UnitIdentifierContext; @@ -69,6 +72,8 @@ import org.apache.doris.nereids.analyzer.UnboundFunction; import org.apache.doris.nereids.analyzer.UnboundRelation; import org.apache.doris.nereids.analyzer.UnboundSlot; import org.apache.doris.nereids.analyzer.UnboundStar; +import org.apache.doris.nereids.annotation.Developing; +import org.apache.doris.nereids.exceptions.ParseException; import org.apache.doris.nereids.properties.OrderKey; import org.apache.doris.nereids.trees.expressions.Add; import org.apache.doris.nereids.trees.expressions.Alias; @@ -118,6 +123,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalSort; +import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; @@ -212,11 +218,33 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor { /** * Create an aliased table reference. This is typically used in FROM clauses. */ + @Developing + private LogicalPlan withTableAlias(LogicalPlan plan, TableAliasContext ctx) { + String alias = ctx.strictIdentifier().getText(); + if (null != ctx.identifierList()) { + throw new ParseException("Do not implemented", ctx); + // TODO: multi-colName + } + return new LogicalSubQueryAlias<>(alias, plan); + } + @Override public LogicalPlan visitTableName(TableNameContext ctx) { List tableId = visitMultipartIdentifier(ctx.multipartIdentifier()); - // TODO: sample and time travel, alias, sub query - return new UnboundRelation(tableId); + if (null == ctx.tableAlias().strictIdentifier()) { + return new UnboundRelation(tableId); + } + return withTableAlias(new UnboundRelation(tableId), ctx.tableAlias()); + } + + @Override + public LogicalPlan visitAliasedQuery(AliasedQueryContext ctx) { + return withTableAlias(visitQuery(ctx.query()), ctx.tableAlias()); + } + + @Override + public LogicalPlan visitAliasedRelation(AliasedRelationContext ctx) { + return withTableAlias(visitRelation(ctx.relation()), ctx.tableAlias()); } /** @@ -568,19 +596,33 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor { return visit(namedCtx.namedExpression(), Expression.class); } + @Override + public LogicalPlan visitRelation(RelationContext ctx) { + LogicalPlan right = plan(ctx.relationPrimary()); + if (ctx.LATERAL() != null) { + if (!(right instanceof LogicalSubQueryAlias)) { + throw new IllegalStateException("lateral join right table should be sub-query"); + } + } + return right; + } + @Override public LogicalPlan visitFromClause(FromClauseContext ctx) { return ParserUtils.withOrigin(ctx, () -> { LogicalPlan left = null; - // build left deep join tree for (RelationContext relation : ctx.relation()) { - LogicalPlan right = plan(relation.relationPrimary()); - left = (left == null) - ? right - : new LogicalJoin<>(JoinType.CROSS_JOIN, Optional.empty(), left, right); + // build left deep join tree + LogicalPlan right = visitRelation(relation); + left = (left == null) ? right : + new LogicalJoin<>( + JoinType.CROSS_JOIN, + Optional.empty(), + left, + right); left = withJoinRelations(left, relation); + // TODO: pivot and lateral view } - // TODO: pivot and lateral view return left; }); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/OrderKey.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/OrderKey.java index 8059b2ddfa..7ed9e8955f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/OrderKey.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/OrderKey.java @@ -67,7 +67,7 @@ public class OrderKey { @Override public String toString() { - return expr.toSql(); + return expr.toString(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index 18b077fd2b..92c306b2fd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -33,6 +33,7 @@ public enum RuleType { BINDING_SORT_SLOT(RuleTypeClass.REWRITE), BINDING_PROJECT_FUNCTION(RuleTypeClass.REWRITE), BINDING_AGGREGATE_FUNCTION(RuleTypeClass.REWRITE), + BINDING_SUBQUERY_ALIAS_SLOT(RuleTypeClass.REWRITE), BINDING_FILTER_FUNCTION(RuleTypeClass.REWRITE), RESOLVE_PROJECT_ALIAS(RuleTypeClass.REWRITE), @@ -41,6 +42,14 @@ public enum RuleType { // rewrite rules AGGREGATE_DISASSEMBLE(RuleTypeClass.REWRITE), COLUMN_PRUNE_PROJECTION(RuleTypeClass.REWRITE), + ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), + + PROJECT_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), + FILTER_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), + JOIN_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), + JOIN_LEFT_CHILD_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), + JOIN_RIGHT_CHILD_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), + AGGREGATE_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE), // predicate push down rules PUSH_DOWN_PREDICATE_THROUGH_JOIN(RuleTypeClass.REWRITE), PUSH_DOWN_PREDICATE_THROUGH_AGGREGATION(RuleTypeClass.REWRITE), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java index f68e3bdc40..88ca9598b1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java @@ -20,9 +20,13 @@ package org.apache.doris.nereids.rules.analysis; import org.apache.doris.catalog.Database; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.Table; +import org.apache.doris.catalog.TableIf.TableType; +import org.apache.doris.nereids.analyzer.NereidsAnalyzer; import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; +import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; +import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import org.apache.doris.qe.ConnectContext; import com.google.common.collect.ImmutableList; @@ -41,16 +45,11 @@ public class BindRelation extends OneAnalysisRuleFactory { switch (nameParts.size()) { case 1: { // Use current database name from catalog. - String dbName = connectContext.getDatabase(); - Table table = getTable(dbName, nameParts.get(0), connectContext.getEnv()); - // TODO: should generate different Scan sub class according to table's type - return new LogicalOlapScan(table, ImmutableList.of(dbName)); + return bindWithCurrentDb(connectContext, nameParts); } case 2: { // Use database name from table name parts. - String dbName = connectContext.getClusterName() + ":" + nameParts.get(0); - Table table = getTable(dbName, nameParts.get(1), connectContext.getEnv()); - return new LogicalOlapScan(table, ImmutableList.of(dbName)); + return bindWithDbNameFromNamePart(connectContext, nameParts); } default: throw new IllegalStateException("Table name [" + ctx.root.getTableName() + "] is invalid."); @@ -69,4 +68,33 @@ public class BindRelation extends OneAnalysisRuleFactory { db.readUnlock(); } } + + private LogicalPlan bindWithCurrentDb(ConnectContext ctx, List nameParts) { + String dbName = ctx.getDatabase(); + Table table = getTable(dbName, nameParts.get(0), ctx.getEnv()); + // TODO: should generate different Scan sub class according to table's type + if (table.getType() == TableType.OLAP) { + return new LogicalOlapScan(table, ImmutableList.of(dbName)); + } else if (table.getType() == TableType.VIEW) { + LogicalPlan viewPlan = new NereidsAnalyzer(ctx).analyze(table.getDdlSql()); + return new LogicalSubQueryAlias<>(table.getName(), viewPlan); + } + throw new RuntimeException("Unsupported tableType:" + table.getType()); + } + + private LogicalPlan bindWithDbNameFromNamePart(ConnectContext ctx, List nameParts) { + // if the relation is view, nameParts.get(0) is dbName. + String dbName = nameParts.get(0); + if (!dbName.equals(ctx.getDatabase())) { + dbName = ctx.getClusterName() + ":" + nameParts.get(0); + } + Table table = getTable(dbName, nameParts.get(1), ctx.getEnv()); + if (table.getType() == TableType.OLAP) { + return new LogicalOlapScan(table, ImmutableList.of(dbName)); + } else if (table.getType() == TableType.VIEW) { + LogicalPlan viewPlan = new NereidsAnalyzer(ctx).analyze(table.getDdlSql()); + return new LogicalSubQueryAlias<>(table.getName(), viewPlan); + } + throw new RuntimeException("Unsupported tableType:" + table.getType()); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java index 182a0c55b3..e38702f101 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java @@ -34,6 +34,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalSort; +import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -103,6 +104,9 @@ public class BindSlotReference implements AnalysisRuleFactory { return new LogicalSort<>(sortItemList, sort.child()); }) + ), + RuleType.BINDING_SUBQUERY_ALIAS_SLOT.build( + logicalSubQueryAlias().then(alias -> new LogicalSubQueryAlias<>(alias.getAlias(), alias.child())) ) ); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java new file mode 100644 index 0000000000..38b294a72a --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java @@ -0,0 +1,66 @@ +// 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.doris.nereids.rules.analysis; + +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * Eliminate the logical sub query and alias node after analyze and before rewrite + * If we match the alias node and return its child node, in the execute() of the job + *

+ * TODO: refactor group merge strategy to support the feature above + */ +public class EliminateAliasNode implements AnalysisRuleFactory { + @Override + public List buildRules() { + return ImmutableList.of( + RuleType.PROJECT_ELIMINATE_ALIAS_NODE.build( + logicalProject(logicalSubQueryAlias()) + .then(project -> project.withChildren(ImmutableList.of(project.child().child()))) + ), + RuleType.FILTER_ELIMINATE_ALIAS_NODE.build( + logicalFilter(logicalSubQueryAlias()) + .then(filter -> filter.withChildren(ImmutableList.of(filter.child().child()))) + ), + RuleType.AGGREGATE_ELIMINATE_ALIAS_NODE.build( + logicalAggregate(logicalSubQueryAlias()) + .then(agg -> agg.withChildren(ImmutableList.of(agg.child().child()))) + ), + RuleType.JOIN_ELIMINATE_ALIAS_NODE.build( + logicalJoin(logicalSubQueryAlias(), logicalSubQueryAlias()) + .then(join -> join.withChildren( + ImmutableList.of(join.left().child(), join.right().child()))) + ), + RuleType.JOIN_LEFT_CHILD_ELIMINATE_ALIAS_NODE.build( + logicalJoin(logicalSubQueryAlias(), group()) + .then(join -> join.withChildren( + ImmutableList.of(join.left().child(), join.right()))) + ), + RuleType.JOIN_RIGHT_CHILD_ELIMINATE_ALIAS_NODE.build( + logicalJoin(group(), logicalSubQueryAlias()) + .then(join -> join.withChildren( + ImmutableList.of(join.left(), join.right().child()))) + ) + ); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpressionUtil.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpressionUtil.java index bbbc839ea3..9e5fa24062 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpressionUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpressionUtil.java @@ -19,6 +19,11 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.common.IdGenerator; +import com.google.common.annotations.VisibleForTesting; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + /** * The util of named expression. */ @@ -31,4 +36,17 @@ public class NamedExpressionUtil { public static ExprId newExprId() { return ID_GENERATOR.getNextId(); } + + /** + * Reset Id Generator + */ + @VisibleForTesting + public static void clear() throws Exception { + Field f = NamedExpressionUtil.class.getDeclaredField("ID_GENERATOR"); + f.setAccessible(true); + Field mf = Field.class.getDeclaredField("modifiers"); + mf.setAccessible(true); + mf.setInt(f, f.getModifiers() & ~Modifier.FINAL); + f.set(NamedExpressionUtil.class, ExprId.createGenerator()); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java index ccc3f4b5fc..232164b1f9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java @@ -17,6 +17,8 @@ package org.apache.doris.nereids.trees.expressions; +import java.util.List; + /** * Abstract class for all slot in expression. */ @@ -30,4 +32,8 @@ public abstract class Slot extends NamedExpression implements LeafExpression { public Slot withNullable(boolean newNullable) { throw new RuntimeException("Do not implement"); } + + public Slot withQualifier(List qualifiers) { + throw new RuntimeException("Do not implement"); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java index 310dcb6d9a..aa0a15631d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java @@ -149,4 +149,9 @@ public class SlotReference extends Slot { } return new SlotReference(exprId, name, dataType, newNullable, qualifier); } + + @Override + public Slot withQualifier(List qualifiers) { + return new SlotReference(exprId, name, dataType, nullable, qualifiers); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index 53f45a7ab1..b920589f80 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -24,6 +24,7 @@ public enum PlanType { UNKNOWN, // logical plan + LOGICAL_SUBQUERY_ALIAS, LOGICAL_UNBOUND_RELATION, LOGICAL_BOUND_RELATION, LOGICAL_PROJECT, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java index 1b3f57949c..e1aaca270c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java @@ -62,6 +62,7 @@ public class LogicalProject extends LogicalUnary getProjects() { return projects; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java new file mode 100644 index 0000000000..5bb98cf41f --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java @@ -0,0 +1,113 @@ +// 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.doris.nereids.trees.plans.logical; + +import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * The node of logical plan for sub query and alias + * + * @param param + */ +public class LogicalSubQueryAlias extends LogicalUnary { + private final String alias; + + public LogicalSubQueryAlias(String tableAlias, CHILD_TYPE child) { + this(tableAlias, Optional.empty(), Optional.empty(), child); + } + + public LogicalSubQueryAlias(String tableAlias, Optional groupExpression, + Optional logicalProperties, CHILD_TYPE child) { + super(PlanType.LOGICAL_SUBQUERY_ALIAS, groupExpression, logicalProperties, child); + this.alias = tableAlias; + } + + @Override + public List computeOutput(Plan input) { + return input.getOutput().stream() + .map(slot -> slot.withQualifier(ImmutableList.of(alias))) + .collect(Collectors.toList()); + } + + public String getAlias() { + return alias; + } + + @Override + public String toString() { + return "LogicalSubQueryAlias (" + alias + ")"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LogicalSubQueryAlias that = (LogicalSubQueryAlias) o; + return alias.equals(that.alias); + } + + @Override + public int hashCode() { + return Objects.hash(alias); + } + + @Override + public Plan withChildren(List children) { + Preconditions.checkArgument(children.size() == 1); + return new LogicalSubQueryAlias<>(alias, children.get(0)); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitSubQueryAlias((LogicalSubQueryAlias) this, context); + } + + @Override + public List getExpressions() { + return Collections.emptyList(); + } + + @Override + public Plan withGroupExpression(Optional groupExpression) { + return new LogicalSubQueryAlias<>(alias, groupExpression, Optional.of(logicalProperties), child()); + } + + @Override + public Plan withLogicalProperties(Optional logicalProperties) { + return new LogicalSubQueryAlias<>(alias, Optional.empty(), logicalProperties, child()); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java index 2f91e1f7f3..523ba554ee 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java @@ -31,6 +31,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalSort; +import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalDistribution; import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter; @@ -56,6 +57,10 @@ public abstract class PlanVisitor { // Logical plans // ******************************* + public R visitSubQueryAlias(LogicalSubQueryAlias alias, C context) { + return visit(alias, context); + } + public R visitUnboundRelation(UnboundRelation relation, C context) { return visit(relation, context); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/AnalyzeSubQueryTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/AnalyzeSubQueryTest.java new file mode 100644 index 0000000000..c1413d974a --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/AnalyzeSubQueryTest.java @@ -0,0 +1,178 @@ +// 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.doris.nereids.util; + +import org.apache.doris.nereids.NereidsPlanner; +import org.apache.doris.nereids.analyzer.NereidsAnalyzer; +import org.apache.doris.nereids.glue.translator.PhysicalPlanTranslator; +import org.apache.doris.nereids.glue.translator.PlanTranslatorContext; +import org.apache.doris.nereids.parser.NereidsParser; +import org.apache.doris.nereids.properties.PhysicalProperties; +import org.apache.doris.nereids.rules.analysis.EliminateAliasNode; +import org.apache.doris.nereids.trees.expressions.EqualTo; +import org.apache.doris.nereids.trees.expressions.ExprId; +import org.apache.doris.nereids.trees.expressions.NamedExpressionUtil; +import org.apache.doris.nereids.trees.expressions.SlotReference; +import org.apache.doris.nereids.trees.plans.JoinType; +import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan; +import org.apache.doris.nereids.types.BigIntType; +import org.apache.doris.utframe.TestWithFeService; + +import com.google.common.collect.ImmutableList; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Optional; + +public class AnalyzeSubQueryTest extends TestWithFeService implements PatternMatchSupported { + private final NereidsParser parser = new NereidsParser(); + + private final List testSql = ImmutableList.of( + "SELECT * FROM (SELECT * FROM T1 T) T2", + "SELECT * FROM T1 TT1 JOIN (SELECT * FROM T2 TT2) T ON TT1.ID = T.ID", + "SELECT * FROM T1 TT1 JOIN (SELECT TT2.ID FROM T2 TT2) T ON TT1.ID = T.ID", + "SELECT T.ID FROM T1 T", + "SELECT A.ID FROM T1 A, T2 B WHERE A.ID = B.ID", + "SELECT * FROM T1 JOIN T1 T2 ON T1.ID = T2.ID" + ); + + @Override + protected void runBeforeAll() throws Exception { + createDatabase("test"); + connectContext.setDatabase("default_cluster:test"); + + createTables( + "CREATE TABLE IF NOT EXISTS T1 (\n" + + " id bigint,\n" + + " score bigint\n" + + ")\n" + + "DUPLICATE KEY(id)\n" + + "DISTRIBUTED BY HASH(id) BUCKETS 1\n" + + "PROPERTIES (\n" + + " \"replication_num\" = \"1\"\n" + + ")\n", + "CREATE TABLE IF NOT EXISTS T2 (\n" + + " id bigint,\n" + + " score bigint\n" + + ")\n" + + "DUPLICATE KEY(id)\n" + + "DISTRIBUTED BY HASH(id) BUCKETS 1\n" + + "PROPERTIES (\n" + + " \"replication_num\" = \"1\"\n" + + ")\n" + ); + } + + @Override + protected void runBeforeEach() throws Exception { + NamedExpressionUtil.clear(); + } + + @Test + public void testTranslateCase() throws Exception { + for (String sql : testSql) { + NamedExpressionUtil.clear(); + System.out.println("\n\n***** " + sql + " *****\n\n"); + PhysicalPlan plan = new NereidsPlanner(connectContext).plan( + parser.parseSingle(sql), + PhysicalProperties.ANY, + connectContext + ); + // Just to check whether translate will throw exception + new PhysicalPlanTranslator().translatePlan(plan, new PlanTranslatorContext()); + } + } + + @Test + public void testCaseSubQuery() { + FieldChecker projectChecker = new FieldChecker(ImmutableList.of("projects")); + new PlanChecker().plan(new NereidsAnalyzer(connectContext).analyze(testSql.get(0))) + .applyTopDown(new EliminateAliasNode()) + .matches( + logicalProject( + logicalProject( + logicalOlapScan().when(o -> true) + ).when(projectChecker.check(ImmutableList.of(ImmutableList.of( + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("T")), + new SlotReference(new ExprId(1), "score", new BigIntType(), true, ImmutableList.of("T"))))) + ) + ).when(projectChecker.check(ImmutableList.of(ImmutableList.of( + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("T2")), + new SlotReference(new ExprId(1), "score", new BigIntType(), true, ImmutableList.of("T2"))))) + ) + ); + } + + @Test + public void testCaseMixed() { + FieldChecker projectChecker = new FieldChecker(ImmutableList.of("projects")); + FieldChecker joinChecker = new FieldChecker(ImmutableList.of("joinType", "condition")); + new PlanChecker().plan(new NereidsAnalyzer(connectContext).analyze(testSql.get(1))) + .applyTopDown(new EliminateAliasNode()) + .matches( + logicalProject( + logicalJoin( + logicalOlapScan(), + logicalProject( + logicalOlapScan() + ).when(projectChecker.check(ImmutableList.of(ImmutableList.of( + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("TT2")), + new SlotReference(new ExprId(1), "score", new BigIntType(), true, ImmutableList.of("TT2"))))) + ) + ).when(joinChecker.check(ImmutableList.of( + JoinType.INNER_JOIN, + Optional.of(new EqualTo( + new SlotReference(new ExprId(2), "id", new BigIntType(), true, ImmutableList.of("TT1")), + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("T")))))) + ) + ).when(projectChecker.check(ImmutableList.of(ImmutableList.of( + new SlotReference(new ExprId(2), "id", new BigIntType(), true, ImmutableList.of("TT1")), + new SlotReference(new ExprId(3), "score", new BigIntType(), true, ImmutableList.of("TT1")), + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("T")), + new SlotReference(new ExprId(1), "score", new BigIntType(), true, ImmutableList.of("T"))))) + ) + ); + } + + @Test + public void testCaseJoinSameTable() { + FieldChecker projectChecker = new FieldChecker(ImmutableList.of("projects")); + FieldChecker joinChecker = new FieldChecker(ImmutableList.of("joinType", "condition")); + new PlanChecker().plan(new NereidsAnalyzer(connectContext).analyze(testSql.get(5))) + .applyTopDown(new EliminateAliasNode()) + .matches( + logicalProject( + logicalJoin( + logicalOlapScan(), + logicalOlapScan() + ).when(joinChecker.check(ImmutableList.of( + JoinType.INNER_JOIN, + Optional.of(new EqualTo( + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("default_cluster:test", "T1")), + new SlotReference(new ExprId(2), "id", new BigIntType(), true, ImmutableList.of("T2")))))) + ) + ).when(projectChecker.check(ImmutableList.of(ImmutableList.of( + new SlotReference(new ExprId(0), "id", new BigIntType(), true, ImmutableList.of("default_cluster:test", "T1")), + new SlotReference(new ExprId(1), "score", new BigIntType(), true, ImmutableList.of("default_cluster:test", "T1")), + new SlotReference(new ExprId(2), "id", new BigIntType(), true, ImmutableList.of("T2")), + new SlotReference(new ExprId(3), "score", new BigIntType(), true, ImmutableList.of("T2"))))) + ) + ); + } +} + diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java new file mode 100644 index 0000000000..da55e9ebeb --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java @@ -0,0 +1,56 @@ +// 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.doris.nereids.util; + +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.IntStream; + +public class FieldChecker { + + public final List fields; + + public FieldChecker(List fields) { + this.fields = fields; + } + + public Predicate check(List valueList) { + return (o) -> { + Assertions.assertEquals(fields.size(), valueList.size()); + Class classInfo = o.getClass(); + IntStream.range(0, valueList.size()).forEach(i -> { + Field field; + try { + field = classInfo.getDeclaredField(this.fields.get(i)); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + field.setAccessible(true); + try { + Assertions.assertEquals(valueList.get(i), field.get(o)); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + return true; + }; + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java index 823bc4f776..a441eab88d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java +++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java @@ -66,6 +66,7 @@ import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInstance; import java.io.File; @@ -112,12 +113,20 @@ public abstract class TestWithFeService { cleanDorisFeDir(runningDir); } + @BeforeEach + public final void beforeEach() throws Exception { + runBeforeEach(); + } + protected void runBeforeAll() throws Exception { } protected void runAfterAll() throws Exception { } + protected void runBeforeEach() throws Exception { + } + // Help to create a mocked ConnectContext. protected ConnectContext createDefaultCtx() throws IOException { return createCtx(UserIdentity.ROOT, "127.0.0.1"); diff --git a/regression-test/data/nereids_syntax_p0/sub_query_alias.out b/regression-test/data/nereids_syntax_p0/sub_query_alias.out new file mode 100644 index 0000000000..bd9b380b01 --- /dev/null +++ b/regression-test/data/nereids_syntax_p0/sub_query_alias.out @@ -0,0 +1,26 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_1 -- +1303 1303 +1303 1303 +1312 1312 + +-- !select_2 -- +1303 1303 +1303 1303 +1312 1312 + +-- !select_3 -- +1303 1303 +1303 1303 +1312 1312 + +-- !select_4 -- +1303 Customer#000001303 fQ Lp,FoozZe1 ETHIOPIA 3 ETHIOPIA AFRICA 15-658-234-7985 MACHINERY 1303 Customer#000001303 fQ Lp,FoozZe1 ETHIOPIA 3 ETHIOPIA AFRICA 15-658-234-7985 MACHINERY +1309 Customer#000001309 vQcJGUXPHMH2 5OWs1XUP0kx IRAN 2 IRAN MIDDLE EAST 20-821-905-5952 AUTOMOBILE 1309 Customer#000001309 vQcJGUXPHMH2 5OWs1XUP0kx IRAN 2 IRAN MIDDLE EAST 20-821-905-5952 AUTOMOBILE +1312 Customer#000001312 MVsKeqWejff8jQ30 CANADA 9 CANADA AMERICA 13-153-492-9898 BUILDING 1312 Customer#000001312 MVsKeqWejff8jQ30 CANADA 9 CANADA AMERICA 13-153-492-9898 BUILDING + +-- !select_5 -- +1303 Customer#000001303 fQ Lp,FoozZe1 ETHIOPIA 3 ETHIOPIA AFRICA 15-658-234-7985 MACHINERY 1309892 1 1303 1432 15 19920517 3-MEDIUM 0 24 2959704 5119906 7 2752524 73992 0 19920619 TRUCK +1303 Customer#000001303 fQ Lp,FoozZe1 ETHIOPIA 3 ETHIOPIA AFRICA 15-658-234-7985 MACHINERY 1309892 2 1303 1165 9 19920517 3-MEDIUM 0 21 2404899 5119906 8 2212507 68711 7 19920616 RAIL +1312 Customer#000001312 MVsKeqWejff8jQ30 CANADA 9 CANADA AMERICA 13-153-492-9898 BUILDING 1310179 6 1312 1455 29 19921110 3-MEDIUM 0 15 1705830 20506457 10 1535247 68233 8 19930114 FOB + diff --git a/regression-test/suites/nereids_syntax_p0/sub_query_alias.groovy b/regression-test/suites/nereids_syntax_p0/sub_query_alias.groovy new file mode 100644 index 0000000000..8a50987089 --- /dev/null +++ b/regression-test/suites/nereids_syntax_p0/sub_query_alias.groovy @@ -0,0 +1,72 @@ +// 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. + +suite("sub_query_alias") { + sql """ + SET enable_vectorized_engine=true + """ + + sql """ + SET enable_nereids_planner=true + """ + + qt_select_1 """ + select t.c_custkey, t.lo_custkey + from ( + select * + from customer, lineorder + where customer.c_custkey = lineorder.lo_custkey + ) t + order by t.c_custkey + """ + + qt_select_2 """ + select c.c_custkey, l.lo_custkey + from customer c, lineorder l + where c.c_custkey = l.lo_custkey + order by c.c_custkey + """ + + qt_select_3 """ + select t.c_custkey, t.lo_custkey + from ( + select * + from customer c, lineorder l + where c.c_custkey = l.lo_custkey + ) t + order by t.c_custkey + """ + + qt_select_4 """ + select * + from customer c + join customer c1 + on c.c_custkey = c1.c_custkey + order by c.c_custkey + """ + + qt_select_5 """ + select * + from customer c + join ( + select * + from lineorder l + ) t on c.c_custkey = t.lo_custkey + order by c.c_custkey + """ +} +