From: Tom Lane Date: Fri, 31 Aug 2012 21:44:01 +0000 (-0400) Subject: Fix LATERAL references to join alias variables. X-Git-Tag: REL9_3_BETA1~970 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da3df998702061b4b63d83d5354b148e812f21f8;p=postgresql 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() ... --- diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 0540afaced..4284eed47b 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -49,13 +49,15 @@ planner_hook_type planner_hook = NULL; /* Expression kind codes for preprocess_expression */ -#define EXPRKIND_QUAL 0 -#define EXPRKIND_TARGET 1 -#define EXPRKIND_RTFUNC 2 -#define EXPRKIND_VALUES 3 -#define EXPRKIND_LIMIT 4 -#define EXPRKIND_APPINFO 5 -#define EXPRKIND_PHV 6 +#define EXPRKIND_QUAL 0 +#define EXPRKIND_TARGET 1 +#define EXPRKIND_RTFUNC 2 +#define EXPRKIND_RTFUNC_LATERAL 3 +#define EXPRKIND_VALUES 4 +#define EXPRKIND_VALUES_LATERAL 5 +#define EXPRKIND_LIMIT 6 +#define EXPRKIND_APPINFO 7 +#define EXPRKIND_PHV 8 static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind); @@ -438,18 +440,38 @@ subquery_planner(PlannerGlobal *glob, Query *parse, preprocess_expression(root, (Node *) root->append_rel_list, EXPRKIND_APPINFO); - /* Also need to preprocess expressions for function and values RTEs */ + /* Also need to preprocess expressions within RTEs */ foreach(l, parse->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); + int kind; - if (rte->rtekind == RTE_FUNCTION) - rte->funcexpr = preprocess_expression(root, rte->funcexpr, - EXPRKIND_RTFUNC); + if (rte->rtekind == RTE_SUBQUERY) + { + /* + * 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) + { + /* Preprocess the values lists fully */ + kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES; rte->values_lists = (List *) - preprocess_expression(root, (Node *) rte->values_lists, - EXPRKIND_VALUES); + preprocess_expression(root, (Node *) rte->values_lists, 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 - * base-relation variables. We must do this before sublink processing, - * else sublinks expanded out from join aliases wouldn't get processed. We - * can skip it in VALUES lists, however, since they can't contain any Vars - * at all. + * base-relation variables. We must do this before sublink processing, + * else sublinks expanded out from join aliases would not get processed. + * We can skip it in non-lateral RTE functions and VALUES lists, however, + * 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); /* diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index a0668c9615..db9a1164ad 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -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. * * 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 * flatten_join_alias_vars(PlannerInfo *root, Node *node) diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index c2e83d7f8b..7c1ab44861 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -3242,6 +3242,32 @@ select * from int8_tbl a, 4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 | (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 select * from (values(1)) x(lb), lateral generate_series(lb,4) x4; diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 24553045da..2213a446a3 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -901,6 +901,14 @@ select * from int8_tbl a, int8_tbl x left join lateral (select a.q1 from int4_tbl y) 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 select * from (values(1)) x(lb), lateral generate_series(lb,4) x4;