Skip to content

Commit da3df99

Browse files
committed
Fix LATERAL references to join alias variables.
I had thought this case worked already, but perhaps I didn't re-test it after adding extract_lateral_references() ...
1 parent f789909 commit da3df99

File tree

4 files changed

+78
-19
lines changed

4 files changed

+78
-19
lines changed

src/backend/optimizer/plan/planner.c

+41-18
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,15 @@ planner_hook_type planner_hook = NULL;
4949

5050

5151
/* Expression kind codes for preprocess_expression */
52-
#define EXPRKIND_QUAL 0
53-
#define EXPRKIND_TARGET 1
54-
#define EXPRKIND_RTFUNC 2
55-
#define EXPRKIND_VALUES 3
56-
#define EXPRKIND_LIMIT 4
57-
#define EXPRKIND_APPINFO 5
58-
#define EXPRKIND_PHV 6
52+
#define EXPRKIND_QUAL 0
53+
#define EXPRKIND_TARGET 1
54+
#define EXPRKIND_RTFUNC 2
55+
#define EXPRKIND_RTFUNC_LATERAL 3
56+
#define EXPRKIND_VALUES 4
57+
#define EXPRKIND_VALUES_LATERAL 5
58+
#define EXPRKIND_LIMIT 6
59+
#define EXPRKIND_APPINFO 7
60+
#define EXPRKIND_PHV 8
5961

6062

6163
static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
@@ -438,18 +440,38 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
438440
preprocess_expression(root, (Node *) root->append_rel_list,
439441
EXPRKIND_APPINFO);
440442

441-
/* Also need to preprocess expressions for function and values RTEs */
443+
/* Also need to preprocess expressions within RTEs */
442444
foreach(l, parse->rtable)
443445
{
444446
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
447+
int kind;
445448

446-
if (rte->rtekind == RTE_FUNCTION)
447-
rte->funcexpr = preprocess_expression(root, rte->funcexpr,
448-
EXPRKIND_RTFUNC);
449+
if (rte->rtekind == RTE_SUBQUERY)
450+
{
451+
/*
452+
* We don't want to do all preprocessing yet on the subquery's
453+
* expressions, since that will happen when we plan it. But if it
454+
* contains any join aliases of our level, those have to get
455+
* expanded now, because planning of the subquery won't do it.
456+
* That's only possible if the subquery is LATERAL.
457+
*/
458+
if (rte->lateral && root->hasJoinRTEs)
459+
rte->subquery = (Query *)
460+
flatten_join_alias_vars(root, (Node *) rte->subquery);
461+
}
462+
else if (rte->rtekind == RTE_FUNCTION)
463+
{
464+
/* Preprocess the function expression fully */
465+
kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
466+
rte->funcexpr = preprocess_expression(root, rte->funcexpr, kind);
467+
}
449468
else if (rte->rtekind == RTE_VALUES)
469+
{
470+
/* Preprocess the values lists fully */
471+
kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
450472
rte->values_lists = (List *)
451-
preprocess_expression(root, (Node *) rte->values_lists,
452-
EXPRKIND_VALUES);
473+
preprocess_expression(root, (Node *) rte->values_lists, kind);
474+
}
453475
}
454476

455477
/*
@@ -593,12 +615,13 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
593615

594616
/*
595617
* If the query has any join RTEs, replace join alias variables with
596-
* base-relation variables. We must do this before sublink processing,
597-
* else sublinks expanded out from join aliases wouldn't get processed. We
598-
* can skip it in VALUES lists, however, since they can't contain any Vars
599-
* at all.
618+
* base-relation variables. We must do this before sublink processing,
619+
* else sublinks expanded out from join aliases would not get processed.
620+
* We can skip it in non-lateral RTE functions and VALUES lists, however,
621+
* since they can't contain any Vars of the current query level.
600622
*/
601-
if (root->hasJoinRTEs && kind != EXPRKIND_VALUES)
623+
if (root->hasJoinRTEs &&
624+
!(kind == EXPRKIND_RTFUNC || kind == EXPRKIND_VALUES))
602625
expr = flatten_join_alias_vars(root, expr);
603626

604627
/*

src/backend/optimizer/util/var.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,9 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
600600
* hasSubLinks = TRUE, so this is only relevant to un-flattened subqueries.
601601
*
602602
* NOTE: this is used on not-yet-planned expressions. We do not expect it
603-
* to be applied directly to a Query node.
603+
* to be applied directly to the whole Query, so if we see a Query to start
604+
* with, we do want to increment sublevels_up (this occurs for LATERAL
605+
* subqueries).
604606
*/
605607
Node *
606608
flatten_join_alias_vars(PlannerInfo *root, Node *node)

src/test/regress/expected/join.out

+26
Original file line numberDiff line numberDiff line change
@@ -3242,6 +3242,32 @@ select * from int8_tbl a,
32423242
4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 |
32433243
(57 rows)
32443244

3245+
-- lateral reference to a join alias variable
3246+
select * from (select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
3247+
lateral (select x) ss2(y);
3248+
x | f1 | y
3249+
---+----+---
3250+
0 | 0 | 0
3251+
(1 row)
3252+
3253+
select * from (select f1 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
3254+
lateral (values(x)) ss2(y);
3255+
x | f1 | y
3256+
-------------+-------------+-------------
3257+
0 | 0 | 0
3258+
123456 | 123456 | 123456
3259+
-123456 | -123456 | -123456
3260+
2147483647 | 2147483647 | 2147483647
3261+
-2147483647 | -2147483647 | -2147483647
3262+
(5 rows)
3263+
3264+
select * from ((select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1) j,
3265+
lateral (select x) ss2(y);
3266+
x | f1 | y
3267+
---+----+---
3268+
0 | 0 | 0
3269+
(1 row)
3270+
32453271
-- lateral references requiring pullup
32463272
select * from (values(1)) x(lb),
32473273
lateral generate_series(lb,4) x4;

src/test/regress/sql/join.sql

+8
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,14 @@ select * from int8_tbl a,
901901
int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z)
902902
on x.q2 = ss.z;
903903

904+
-- lateral reference to a join alias variable
905+
select * from (select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
906+
lateral (select x) ss2(y);
907+
select * from (select f1 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
908+
lateral (values(x)) ss2(y);
909+
select * from ((select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1) j,
910+
lateral (select x) ss2(y);
911+
904912
-- lateral references requiring pullup
905913
select * from (values(1)) x(lb),
906914
lateral generate_series(lb,4) x4;

0 commit comments

Comments
 (0)