You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2023/10/25 10:52:22 UTC

[doris] branch master updated: [fix](Nereids) cte should support nested name reuse (#25858)

This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 01d5901356c [fix](Nereids) cte should support nested name reuse (#25858)
01d5901356c is described below

commit 01d5901356ce5306841e752d21387779605bb44d
Author: morrySnow <10...@users.noreply.github.com>
AuthorDate: Wed Oct 25 18:52:14 2023 +0800

    [fix](Nereids) cte should support nested name reuse (#25858)
    
    for example:
    ```sql
    with a as (with a as (select * from t) select * from a) select * from a;
    
    with a as (select * from t1), b as (with a as (select * from a) select * from a) select * from b;
    ```
---
 .../java/org/apache/doris/nereids/CTEContext.java  | 10 +---
 .../doris/nereids/rules/analysis/AnalyzeCTE.java   | 23 ++++++---
 .../data/nereids_p0/cte/test_cte_name_reuse.out    | 10 ++++
 .../nereids_p0/cte/test_cte_name_reuse.groovy      | 60 ++++++++++++++++++++++
 4 files changed, 87 insertions(+), 16 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/CTEContext.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/CTEContext.java
index 6bc67870708..9653811492e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/CTEContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/CTEContext.java
@@ -60,7 +60,8 @@ public class CTEContext {
                 : ImmutableMap.<String, CTEContext>builder()
                         .putAll(previousCteContext.cteContextMap)
                         .put(name, this)
-                        .build();
+                        // if inner name same with outer name, use inner name in this scope.
+                        .buildKeepingLast();
         this.cteId = cteId;
     }
 
@@ -68,13 +69,6 @@ public class CTEContext {
         this.analyzedPlan = analyzedPlan;
     }
 
-    /**
-     * check if cteName can be found in current order
-     */
-    public boolean containsCTE(String cteName) {
-        return findCTEContext(cteName).isPresent();
-    }
-
     /**
      * Get for CTE reuse.
      */
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeCTE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeCTE.java
index a465df6da13..0fe083c1e93 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeCTE.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeCTE.java
@@ -34,11 +34,13 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Register CTE, includes checking columnAliases, checking CTE name, analyzing each CTE and store the
@@ -53,6 +55,18 @@ public class AnalyzeCTE extends OneAnalysisRuleFactory {
         return logicalCTE().thenApply(ctx -> {
             LogicalCTE<Plan> logicalCTE = ctx.root;
 
+            // step 0. check duplicate cte name
+            Set<String> uniqueAlias = Sets.newHashSet();
+            List<String> aliases = logicalCTE.getAliasQueries().stream()
+                    .map(LogicalSubQueryAlias::getAlias)
+                    .collect(Collectors.toList());
+            for (String alias : aliases) {
+                if (uniqueAlias.contains(alias)) {
+                    throw new AnalysisException("CTE name [" + alias + "] cannot be used more than once.");
+                }
+                uniqueAlias.add(alias);
+            }
+
             // step 1. analyzed all cte plan
             Pair<CTEContext, List<LogicalCTEProducer<Plan>>> result = analyzeCte(logicalCTE, ctx.cascadesContext);
             CascadesContext outerCascadesCtx = CascadesContext.newContextWithCteContext(
@@ -76,17 +90,10 @@ public class AnalyzeCTE extends OneAnalysisRuleFactory {
         List<LogicalSubQueryAlias<Plan>> aliasQueries = logicalCTE.getAliasQueries();
         List<LogicalCTEProducer<Plan>> cteProducerPlans = new ArrayList<>();
         for (LogicalSubQueryAlias<Plan> aliasQuery : aliasQueries) {
-            String cteName = aliasQuery.getAlias();
-            if (outerCteCtx.containsCTE(cteName)) {
-                throw new AnalysisException("CTE name [" + cteName + "] cannot be used more than once.");
-            }
-
             // we should use a chain to ensure visible of cte
-            CTEContext innerCteCtx = outerCteCtx;
-
             LogicalPlan parsedCtePlan = (LogicalPlan) aliasQuery.child();
             CascadesContext innerCascadesCtx = CascadesContext.newContextWithCteContext(
-                    cascadesContext, parsedCtePlan, innerCteCtx);
+                    cascadesContext, parsedCtePlan, outerCteCtx);
             innerCascadesCtx.newAnalyzer().analyze();
             LogicalPlan analyzedCtePlan = (LogicalPlan) innerCascadesCtx.getRewritePlan();
             checkColumnAlias(aliasQuery, analyzedCtePlan.getOutput());
diff --git a/regression-test/data/nereids_p0/cte/test_cte_name_reuse.out b/regression-test/data/nereids_p0/cte/test_cte_name_reuse.out
new file mode 100644
index 00000000000..52966eaa688
--- /dev/null
+++ b/regression-test/data/nereids_p0/cte/test_cte_name_reuse.out
@@ -0,0 +1,10 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !reuse_name_with_other_outer_cte --
+1	1	1	1
+
+-- !reuse_name_with_other_outer_cte_and_use_outer_same_name_cte --
+1	1
+
+-- !reuse_name_with_self_outer_cte --
+1	1
+
diff --git a/regression-test/suites/nereids_p0/cte/test_cte_name_reuse.groovy b/regression-test/suites/nereids_p0/cte/test_cte_name_reuse.groovy
new file mode 100644
index 00000000000..5d472716f00
--- /dev/null
+++ b/regression-test/suites/nereids_p0/cte/test_cte_name_reuse.groovy
@@ -0,0 +1,60 @@
+// 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("test_cte_name_reuse)") {
+    sql "SET enable_nereids_planner=true"
+    sql "SET enable_pipeline_engine=true"
+    sql "SET enable_fallback_to_original_planner=false"
+
+    sql """
+        drop table if exists test_cte_name_reuse;
+    """
+
+    sql """
+        CREATE TABLE `test_cte_name_reuse` (
+          `id` int(11) NULL,
+          `msg` text NULL
+        ) ENGINE=OLAP
+        DUPLICATE KEY(`id`)
+        COMMENT 'OLAP'
+        DISTRIBUTED BY HASH(`id`) BUCKETS 10
+        PROPERTIES (
+        "replication_allocation" = "tag.location.default: 1",
+        "min_load_replica_num" = "-1",
+        "is_being_synced" = "false",
+        "storage_format" = "V2",
+        "light_schema_change" = "true",
+        "disable_auto_compaction" = "false",
+        "enable_single_replica_compaction" = "false"
+        );
+    """
+
+    sql """
+        insert into test_cte_name_reuse values(1, "1");
+    """
+
+    qt_reuse_name_with_other_outer_cte """
+        with a as (select * from test_cte_name_reuse), b as (with a as (select * from test_cte_name_reuse) select * from a) select * from a, b;
+    """
+
+    qt_reuse_name_with_other_outer_cte_and_use_outer_same_name_cte """
+        with a as (select * from test_cte_name_reuse), b as (with a as (select * from a) select * from a) select * from b;
+    """
+
+    qt_reuse_name_with_self_outer_cte """
+        with a as (with a as (select * from test_cte_name_reuse) select * from a) select * from a;
+    """
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org