]> granicus.if.org Git - postgresql/commitdiff
Fix LATERAL references to join alias variables.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 31 Aug 2012 21:44:01 +0000 (17:44 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 31 Aug 2012 21:44:31 +0000 (17:44 -0400)
I had thought this case worked already, but perhaps I didn't re-test it
after adding extract_lateral_references() ...

src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/var.c
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 0540afaced00ce5807e6d8fe56ed5a15397e2272..4284eed47b929f7c9cca8c75bcde3487fc13c65f 100644 (file)
@@ -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);
 
        /*
index a0668c9615be7dccdc39c3acb53ccad1d3204127..db9a1164ad31ab6a9aa9f6b8c63025f9aeced646 100644 (file)
@@ -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)
index c2e83d7f8bbb1663714b459539349d9f22855662..7c1ab4486151fe5ed96656c0c23fd3f0fae8f14d 100644 (file)
@@ -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;
index 24553045da1d5c1812c2ca408ebfbe28e427505a..2213a446a3ddd7136d802fe016e4156eca02b17c 100644 (file)
@@ -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;