Commit da3df998 authored by Tom Lane's avatar Tom Lane

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() ...
parent f789909b
...@@ -49,13 +49,15 @@ planner_hook_type planner_hook = NULL; ...@@ -49,13 +49,15 @@ planner_hook_type planner_hook = NULL;
/* Expression kind codes for preprocess_expression */ /* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0 #define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1 #define EXPRKIND_TARGET 1
#define EXPRKIND_RTFUNC 2 #define EXPRKIND_RTFUNC 2
#define EXPRKIND_VALUES 3 #define EXPRKIND_RTFUNC_LATERAL 3
#define EXPRKIND_LIMIT 4 #define EXPRKIND_VALUES 4
#define EXPRKIND_APPINFO 5 #define EXPRKIND_VALUES_LATERAL 5
#define EXPRKIND_PHV 6 #define EXPRKIND_LIMIT 6
#define EXPRKIND_APPINFO 7
#define EXPRKIND_PHV 8
static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind); static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
...@@ -438,18 +440,38 @@ subquery_planner(PlannerGlobal *glob, Query *parse, ...@@ -438,18 +440,38 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
preprocess_expression(root, (Node *) root->append_rel_list, preprocess_expression(root, (Node *) root->append_rel_list,
EXPRKIND_APPINFO); EXPRKIND_APPINFO);
/* Also need to preprocess expressions for function and values RTEs */ /* Also need to preprocess expressions within RTEs */
foreach(l, parse->rtable) foreach(l, parse->rtable)
{ {
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
int kind;
if (rte->rtekind == RTE_FUNCTION) if (rte->rtekind == RTE_SUBQUERY)
rte->funcexpr = preprocess_expression(root, rte->funcexpr, {
EXPRKIND_RTFUNC); /*
* We don't want to do all preprocessing yet on the subquery's
* expressions, since that will happen when we plan it. But if it
* contains any join aliases of our level, those have to get
* expanded now, because planning of the subquery won't do it.
* That's only possible if the subquery is LATERAL.
*/
if (rte->lateral && root->hasJoinRTEs)
rte->subquery = (Query *)
flatten_join_alias_vars(root, (Node *) rte->subquery);
}
else if (rte->rtekind == RTE_FUNCTION)
{
/* Preprocess the function expression fully */
kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
rte->funcexpr = preprocess_expression(root, rte->funcexpr, kind);
}
else if (rte->rtekind == RTE_VALUES) else if (rte->rtekind == RTE_VALUES)
{
/* Preprocess the values lists fully */
kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
rte->values_lists = (List *) rte->values_lists = (List *)
preprocess_expression(root, (Node *) rte->values_lists, preprocess_expression(root, (Node *) rte->values_lists, kind);
EXPRKIND_VALUES); }
} }
/* /*
...@@ -593,12 +615,13 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind) ...@@ -593,12 +615,13 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
/* /*
* If the query has any join RTEs, replace join alias variables with * If the query has any join RTEs, replace join alias variables with
* base-relation variables. We must do this before sublink processing, * base-relation variables. We must do this before sublink processing,
* else sublinks expanded out from join aliases wouldn't get processed. We * else sublinks expanded out from join aliases would not get processed.
* can skip it in VALUES lists, however, since they can't contain any Vars * We can skip it in non-lateral RTE functions and VALUES lists, however,
* at all. * since they can't contain any Vars of the current query level.
*/ */
if (root->hasJoinRTEs && kind != EXPRKIND_VALUES) if (root->hasJoinRTEs &&
!(kind == EXPRKIND_RTFUNC || kind == EXPRKIND_VALUES))
expr = flatten_join_alias_vars(root, expr); expr = flatten_join_alias_vars(root, expr);
/* /*
......
...@@ -600,7 +600,9 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context) ...@@ -600,7 +600,9 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
* hasSubLinks = TRUE, so this is only relevant to un-flattened subqueries. * hasSubLinks = TRUE, so this is only relevant to un-flattened subqueries.
* *
* NOTE: this is used on not-yet-planned expressions. We do not expect it * NOTE: this is used on not-yet-planned expressions. We do not expect it
* to be applied directly to a Query node. * to be applied directly to the whole Query, so if we see a Query to start
* with, we do want to increment sublevels_up (this occurs for LATERAL
* subqueries).
*/ */
Node * Node *
flatten_join_alias_vars(PlannerInfo *root, Node *node) flatten_join_alias_vars(PlannerInfo *root, Node *node)
......
...@@ -3242,6 +3242,32 @@ select * from int8_tbl a, ...@@ -3242,6 +3242,32 @@ select * from int8_tbl a,
4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 |
(57 rows) (57 rows)
-- lateral reference to a join alias variable
select * from (select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
lateral (select x) ss2(y);
x | f1 | y
---+----+---
0 | 0 | 0
(1 row)
select * from (select f1 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
lateral (values(x)) ss2(y);
x | f1 | y
-------------+-------------+-------------
0 | 0 | 0
123456 | 123456 | 123456
-123456 | -123456 | -123456
2147483647 | 2147483647 | 2147483647
-2147483647 | -2147483647 | -2147483647
(5 rows)
select * from ((select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1) j,
lateral (select x) ss2(y);
x | f1 | y
---+----+---
0 | 0 | 0
(1 row)
-- lateral references requiring pullup -- lateral references requiring pullup
select * from (values(1)) x(lb), select * from (values(1)) x(lb),
lateral generate_series(lb,4) x4; lateral generate_series(lb,4) x4;
......
...@@ -901,6 +901,14 @@ select * from int8_tbl a, ...@@ -901,6 +901,14 @@ select * from int8_tbl a,
int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z) int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z)
on x.q2 = ss.z; on x.q2 = ss.z;
-- lateral reference to a join alias variable
select * from (select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
lateral (select x) ss2(y);
select * from (select f1 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
lateral (values(x)) ss2(y);
select * from ((select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1) j,
lateral (select x) ss2(y);
-- lateral references requiring pullup -- lateral references requiring pullup
select * from (values(1)) x(lb), select * from (values(1)) x(lb),
lateral generate_series(lb,4) x4; lateral generate_series(lb,4) x4;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment