Skip to content

Commit 6a850b7

Browse files
guofengrichardCommitfest Bot
authored and
Commitfest Bot
committed
Expand virtual generated columns before sublink pull-up
Currently, we expand virtual generated columns after we have pulled up any SubLinks within the query's quals. This ensures that the virtual generated column references within SubLinks that should be transformed into joins are correctly expanded. This approach works well and has posed no issues. In an upcoming patch, we plan to centralize the collection of catalog information needed early in the planner. This will help avoid repeated table_open/table_close calls for relations in the rangetable. Since this information is required during sublink pull-up, we are moving the expansion of virtual generated columns to occur beforehand. To achieve this, if any EXISTS SubLinks can be pulled up, their rangetables are processed just before pulling them up.
1 parent 06c4f3a commit 6a850b7

File tree

6 files changed

+65
-21
lines changed

6 files changed

+65
-21
lines changed

src/backend/optimizer/plan/planner.c

+9-8
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,15 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
717717
*/
718718
transform_MERGE_to_join(parse);
719719

720+
/*
721+
* Scan the rangetable for relations with virtual generated columns, and
722+
* replace all Var nodes in the query that reference these columns with
723+
* the generation expressions. Note that this step does not descend into
724+
* sublinks and subqueries; if we pull up any sublinks or subqueries
725+
* below, their rangetables are processed just before pulling them up.
726+
*/
727+
parse = root->parse = expand_virtual_generated_columns(root);
728+
720729
/*
721730
* If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
722731
* that we don't need so many special cases to deal with that situation.
@@ -740,14 +749,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
740749
*/
741750
preprocess_function_rtes(root);
742751

743-
/*
744-
* Scan the rangetable for relations with virtual generated columns, and
745-
* replace all Var nodes in the query that reference these columns with
746-
* the generation expressions. Recursion issues here are handled in the
747-
* same way as for SubLinks.
748-
*/
749-
parse = root->parse = expand_virtual_generated_columns(root);
750-
751752
/*
752753
* Check to see if any subqueries in the jointree can be merged into this
753754
* query.

src/backend/optimizer/plan/subselect.c

+16
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
14581458
int varno;
14591459
Relids clause_varnos;
14601460
Relids upper_varnos;
1461+
PlannerInfo subroot;
14611462

14621463
Assert(sublink->subLinkType == EXISTS_SUBLINK);
14631464

@@ -1487,6 +1488,21 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
14871488
if (!simplify_EXISTS_query(root, subselect))
14881489
return NULL;
14891490

1491+
/*
1492+
* Scan the rangetable for relations with virtual generated columns, and
1493+
* replace all Var nodes in the subquery that reference these columns with
1494+
* the generation expressions.
1495+
*
1496+
* Note: we construct up an entirely dummy PlannerInfo for use here. This
1497+
* is fine because only the "glob" and "parse" links will be used in this
1498+
* case.
1499+
*/
1500+
MemSet(&subroot, 0, sizeof(subroot));
1501+
subroot.type = T_PlannerInfo;
1502+
subroot.glob = root->glob;
1503+
subroot.parse = subselect;
1504+
subselect = expand_virtual_generated_columns(&subroot);
1505+
14901506
/*
14911507
* Separate out the WHERE clause. (We could theoretically also remove
14921508
* top-level plain JOIN/ON clauses, but it's probably not worth the

src/backend/optimizer/prep/prepjointree.c

+8-12
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
* Planner preprocessing for subqueries and join tree manipulation.
55
*
66
* NOTE: the intended sequence for invoking these operations is
7+
* expand_virtual_generated_columns
78
* replace_empty_jointree
89
* pull_up_sublinks
910
* preprocess_function_rtes
10-
* expand_virtual_generated_columns
1111
* pull_up_subqueries
1212
* flatten_simple_union_all
1313
* do expression preprocessing (including flattening JOIN alias vars)
@@ -958,10 +958,6 @@ preprocess_function_rtes(PlannerInfo *root)
958958
* generation expressions. Note that we do not descend into subqueries; that
959959
* is taken care of when the subqueries are planned.
960960
*
961-
* This has to be done after we have pulled up any SubLinks within the query's
962-
* quals; otherwise any virtual generated column references within the SubLinks
963-
* that should be transformed into joins wouldn't get expanded.
964-
*
965961
* Returns a modified copy of the query tree, if any relations with virtual
966962
* generated columns are present.
967963
*/
@@ -1333,6 +1329,13 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
13331329
/* No CTEs to worry about */
13341330
Assert(subquery->cteList == NIL);
13351331

1332+
/*
1333+
* Scan the rangetable for relations with virtual generated columns, and
1334+
* replace all Var nodes in the subquery that reference these columns with
1335+
* the generation expressions.
1336+
*/
1337+
subquery = subroot->parse = expand_virtual_generated_columns(subroot);
1338+
13361339
/*
13371340
* If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
13381341
* that we don't need so many special cases to deal with that situation.
@@ -1352,13 +1355,6 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
13521355
*/
13531356
preprocess_function_rtes(subroot);
13541357

1355-
/*
1356-
* Scan the rangetable for relations with virtual generated columns, and
1357-
* replace all Var nodes in the query that reference these columns with
1358-
* the generation expressions.
1359-
*/
1360-
subquery = subroot->parse = expand_virtual_generated_columns(subroot);
1361-
13621358
/*
13631359
* Recursively pull up the subquery's subqueries, so that
13641360
* pull_up_subqueries' processing is complete for its jointree and

src/include/optimizer/prep.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
* prototypes for prepjointree.c
2323
*/
2424
extern void transform_MERGE_to_join(Query *parse);
25+
extern Query *expand_virtual_generated_columns(PlannerInfo *root);
2526
extern void replace_empty_jointree(Query *parse);
2627
extern void pull_up_sublinks(PlannerInfo *root);
2728
extern void preprocess_function_rtes(PlannerInfo *root);
28-
extern Query *expand_virtual_generated_columns(PlannerInfo *root);
2929
extern void pull_up_subqueries(PlannerInfo *root);
3030
extern void flatten_simple_union_all(PlannerInfo *root);
3131
extern void reduce_outer_joins(PlannerInfo *root);

src/test/regress/expected/generated_virtual.out

+22
Original file line numberDiff line numberDiff line change
@@ -1591,4 +1591,26 @@ select * from gtest32 t group by grouping sets (a, b, c, d) having c = 20;
15911591
| | 20 |
15921592
(1 row)
15931593

1594+
-- Ensure that virtual generated column references within SubLinks that should
1595+
-- be transformed into joins can get expanded
1596+
explain (costs off)
1597+
select 1 from gtest32 t1 where exists
1598+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
1599+
QUERY PLAN
1600+
-------------------------------------
1601+
Nested Loop Semi Join
1602+
Join Filter: (t1.a > t2.a)
1603+
-> Seq Scan on gtest32 t1
1604+
-> Materialize
1605+
-> Seq Scan on gtest32 t2
1606+
Filter: ((a * 2) = 2)
1607+
(6 rows)
1608+
1609+
select 1 from gtest32 t1 where exists
1610+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
1611+
?column?
1612+
----------
1613+
1
1614+
(1 row)
1615+
15941616
drop table gtest32;

src/test/regress/sql/generated_virtual.sql

+9
Original file line numberDiff line numberDiff line change
@@ -832,4 +832,13 @@ explain (verbose, costs off)
832832
select * from gtest32 t group by grouping sets (a, b, c, d) having c = 20;
833833
select * from gtest32 t group by grouping sets (a, b, c, d) having c = 20;
834834

835+
-- Ensure that virtual generated column references within SubLinks that should
836+
-- be transformed into joins can get expanded
837+
explain (costs off)
838+
select 1 from gtest32 t1 where exists
839+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
840+
841+
select 1 from gtest32 t1 where exists
842+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
843+
835844
drop table gtest32;

0 commit comments

Comments
 (0)