aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-08-31 17:44:01 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-08-31 17:44:31 -0400
commitda3df998702061b4b63d83d5354b148e812f21f8 (patch)
tree6a622788d29e9cdf3b7ee9db6d25832684cc26e7
parentf789909b59c59a33e34feac3bed2c86f18159122 (diff)
downloadpostgresql-da3df998702061b4b63d83d5354b148e812f21f8.tar.gz
postgresql-da3df998702061b4b63d83d5354b148e812f21f8.zip
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() ...
-rw-r--r--src/backend/optimizer/plan/planner.c59
-rw-r--r--src/backend/optimizer/util/var.c4
-rw-r--r--src/test/regress/expected/join.out26
-rw-r--r--src/test/regress/sql/join.sql8
4 files changed, 78 insertions, 19 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 0540afaced0..4284eed47b9 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 a0668c9615b..db9a1164ad3 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 c2e83d7f8bb..7c1ab448615 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 24553045da1..2213a446a3d 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;