Skip to content

Commit e0d0529

Browse files
author
Richard Guo
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. Author: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/CAMbWs4-bFJ1At4btk5wqbezdu8PLtQ3zv-aiaY3ry9Ymm=jgFQ@mail.gmail.com
1 parent 0810fbb commit e0d0529

File tree

6 files changed

+76
-21
lines changed

6 files changed

+76
-21
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,15 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
720720
*/
721721
transform_MERGE_to_join(parse);
722722

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

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

src/backend/optimizer/plan/subselect.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
14541454
Query *parse = root->parse;
14551455
Query *subselect = (Query *) sublink->subselect;
14561456
Node *whereClause;
1457+
PlannerInfo subroot;
14571458
int rtoffset;
14581459
int varno;
14591460
Relids clause_varnos;
@@ -1515,6 +1516,32 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
15151516
if (contain_volatile_functions(whereClause))
15161517
return NULL;
15171518

1519+
/*
1520+
* Scan the rangetable for relations with virtual generated columns, and
1521+
* replace all Var nodes in the subquery that reference these columns with
1522+
* the generation expressions.
1523+
*
1524+
* Note: we construct up an entirely dummy PlannerInfo for use here. This
1525+
* is fine because only the "glob" and "parse" links will be used in this
1526+
* case.
1527+
*
1528+
* Note: we temporarily assign back the WHERE clause so that any virtual
1529+
* generated column references within it can be expanded. It should be
1530+
* separated out again afterward.
1531+
*/
1532+
MemSet(&subroot, 0, sizeof(subroot));
1533+
subroot.type = T_PlannerInfo;
1534+
subroot.glob = root->glob;
1535+
subroot.parse = subselect;
1536+
subselect->jointree->quals = whereClause;
1537+
subselect = expand_virtual_generated_columns(&subroot);
1538+
1539+
/*
1540+
* Now separate out the WHERE clause again.
1541+
*/
1542+
whereClause = subselect->jointree->quals;
1543+
subselect->jointree->quals = NULL;
1544+
15181545
/*
15191546
* The subquery must have a nonempty jointree, but we can make it so.
15201547
*/

src/backend/optimizer/prep/prepjointree.c

Lines changed: 8 additions & 12 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,4 +1613,26 @@ select * from gtest32 t group by grouping sets (a, b, c, d, e) having c = 20;
16131613

16141614
-- Ensure that the virtual generated columns in ALTER COLUMN TYPE USING expression are expanded
16151615
alter table gtest32 alter column e type bigint using b;
1616+
-- Ensure that virtual generated column references within SubLinks that should
1617+
-- be transformed into joins can get expanded
1618+
explain (costs off)
1619+
select 1 from gtest32 t1 where exists
1620+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
1621+
QUERY PLAN
1622+
-------------------------------------
1623+
Nested Loop Semi Join
1624+
Join Filter: (t1.a > t2.a)
1625+
-> Seq Scan on gtest32 t1
1626+
-> Materialize
1627+
-> Seq Scan on gtest32 t2
1628+
Filter: ((a * 2) = 2)
1629+
(6 rows)
1630+
1631+
select 1 from gtest32 t1 where exists
1632+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
1633+
?column?
1634+
----------
1635+
1
1636+
(1 row)
1637+
16161638
drop table gtest32;

src/test/regress/sql/generated_virtual.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,4 +858,13 @@ select * from gtest32 t group by grouping sets (a, b, c, d, e) having c = 20;
858858
-- Ensure that the virtual generated columns in ALTER COLUMN TYPE USING expression are expanded
859859
alter table gtest32 alter column e type bigint using b;
860860

861+
-- Ensure that virtual generated column references within SubLinks that should
862+
-- be transformed into joins can get expanded
863+
explain (costs off)
864+
select 1 from gtest32 t1 where exists
865+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
866+
867+
select 1 from gtest32 t1 where exists
868+
(select 1 from gtest32 t2 where t1.a > t2.a and t2.b = 2);
869+
861870
drop table gtest32;

0 commit comments

Comments
 (0)