Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Replace relids in lateral subquery parse tree during SJE
authorAlexander Korotkov <akorotkov@postgresql.org>
Tue, 20 Feb 2024 12:10:10 +0000 (14:10 +0200)
committerAlexander Korotkov <akorotkov@postgresql.org>
Tue, 20 Feb 2024 12:10:10 +0000 (14:10 +0200)
Reported-by: Alexander Lakhin
Discussion: https://postgr.es/m/56ee4520-e9d1-d519-54fe-c8bff880ce9b%40gmail.com
Author: Alexander Korotkov, Andrei Lepikhov

src/backend/optimizer/plan/analyzejoins.c
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index e494acd51a6b485e44c757f0e4ee49d0742fff85..072298f66c640cbaefc4fb05f48a32307f410bf4 100644 (file)
@@ -395,7 +395,34 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
        }
 
        /* Update lateral references. */
-       replace_varno((Node *) otherrel->lateral_vars, relid, subst);
+       if (root->hasLateralRTEs)
+       {
+           RangeTblEntry *rte = root->simple_rte_array[rti];
+           ReplaceVarnoContext ctx = {.from = relid,.to = subst};
+
+           if (rte->lateral)
+           {
+               replace_varno((Node *) otherrel->lateral_vars, relid, subst);
+
+               /*
+                * Although we pass root->parse through cleanup procedure,
+                * but parse->rtable and rte contains refs to different copies
+                * of the subquery.
+                */
+               if (otherrel->rtekind == RTE_SUBQUERY)
+                   query_tree_walker(rte->subquery, replace_varno_walker, &ctx,
+                                     QTW_EXAMINE_SORTGROUP);
+#ifdef USE_ASSERT_CHECKING
+               /* Just check possibly hidden non-replaced relids */
+               Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->tablesample)));
+               Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->functions)));
+               Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->tablefunc)));
+               Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->values_lists)));
+#endif
+           }
+       }
+
+
    }
 
    /*
index 0c2cba892131be92ce0c9f736a4506152676c999..d560a4a6b9e00d3624490088e701760a636ccbf3 100644 (file)
@@ -6349,6 +6349,50 @@ on true;
                ->  Seq Scan on int8_tbl y
 (7 rows)
 
+-- Test processing target lists in lateral subqueries
+explain (verbose, costs off)
+SELECT t3.a FROM sj t1, sj t2,
+LATERAL (SELECT t1.a WHERE t1.a <> 1
+        GROUP BY (t1.a) HAVING t1.a > 0 ORDER BY t1.a LIMIT 1) t3,
+LATERAL (SELECT t1.a,t3.a WHERE t1.a <> t3.a+t2.a
+        GROUP BY (t3.a) HAVING t1.a > t3.a*t3.a+t2.a/t1.a LIMIT 2) t4,
+LATERAL (SELECT * FROM sj TABLESAMPLE bernoulli(t1.a/t2.a)
+        REPEATABLE (t1.a+t2.a)) t5,
+LATERAL generate_series(1, t1.a + t2.a) AS t6
+WHERE t1.a = t2.a;
+                                                          QUERY PLAN                                                           
+-------------------------------------------------------------------------------------------------------------------------------
+ Nested Loop
+   Output: (t2.a)
+   ->  Nested Loop
+         Output: t2.a, (t2.a)
+         ->  Nested Loop
+               Output: t2.a, (t2.a)
+               ->  Nested Loop
+                     Output: t2.a, (t2.a)
+                     ->  Seq Scan on public.sj t2
+                           Output: t2.a, t2.b, t2.c
+                           Filter: (t2.a IS NOT NULL)
+                     ->  Limit
+                           Output: (t2.a)
+                           ->  Group
+                                 Output: t2.a
+                                 ->  Result
+                                       One-Time Filter: ((t2.a <> 1) AND (t2.a > 0))
+               ->  Limit
+                     Output: NULL::integer, ((t2.a))
+                     ->  Group
+                           Output: NULL::integer, (t2.a)
+                           ->  Result
+                                 One-Time Filter: ((t2.a <> ((t2.a) + t2.a)) AND (t2.a > (((t2.a) * (t2.a)) + (t2.a / t2.a))))
+         ->  Sample Scan on public.sj
+               Output: sj.a, sj.b, sj.c
+               Sampling: bernoulli ((t2.a / t2.a)) REPEATABLE ((t2.a + t2.a))
+   ->  Function Scan on pg_catalog.generate_series t6
+         Output: t6.t6
+         Function Call: generate_series(1, (t2.a + t2.a))
+(29 rows)
+
 -- Check updating of Lateral links from top-level query to the removing relation
 explain (COSTS OFF)
 SELECT * FROM pg_am am WHERE am.amname IN (
index 257f727a2be04fe4cd3f93b01d9228bbda4e4959..9341f80bbc4f5ca2f0851893dfa2f6378c1e6fd2 100644 (file)
@@ -2406,6 +2406,18 @@ left join (select coalesce(y.q1, 1) from int8_tbl y
    on true) z
 on true;
 
+-- Test processing target lists in lateral subqueries
+explain (verbose, costs off)
+SELECT t3.a FROM sj t1, sj t2,
+LATERAL (SELECT t1.a WHERE t1.a <> 1
+        GROUP BY (t1.a) HAVING t1.a > 0 ORDER BY t1.a LIMIT 1) t3,
+LATERAL (SELECT t1.a,t3.a WHERE t1.a <> t3.a+t2.a
+        GROUP BY (t3.a) HAVING t1.a > t3.a*t3.a+t2.a/t1.a LIMIT 2) t4,
+LATERAL (SELECT * FROM sj TABLESAMPLE bernoulli(t1.a/t2.a)
+        REPEATABLE (t1.a+t2.a)) t5,
+LATERAL generate_series(1, t1.a + t2.a) AS t6
+WHERE t1.a = t2.a;
+
 -- Check updating of Lateral links from top-level query to the removing relation
 explain (COSTS OFF)
 SELECT * FROM pg_am am WHERE am.amname IN (