Fix pull_up_simple_union_all to copy all rtable entries from child subquery to
authorHeikki Linnakangas <[email protected]>
Thu, 14 Aug 2008 20:32:11 +0000 (20:32 +0000)
committerHeikki Linnakangas <[email protected]>
Thu, 14 Aug 2008 20:32:11 +0000 (20:32 +0000)
parent, not only those with RangeTblRefs. We need them in ExecCheckRTPerms.

Report by Brendan O'Shea. Back-patch to 8.2, where pull_up_simple_union_all
was introduced.

src/backend/optimizer/prep/prepjointree.c
src/backend/rewrite/rewriteManip.c
src/include/rewrite/rewriteManip.h

index 97ca69dc3b8f6e6ae8bce602a1a694a4ad140329..bda6cdb471e5ad61d039dedbcd2524472d7d538f 100644 (file)
@@ -46,7 +46,8 @@ static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode,
 static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode,
                                                 RangeTblEntry *rte);
 static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
-                                                  int parentRTindex, Query *setOpQuery);
+                                                 int parentRTindex, Query *setOpQuery,
+                                                 int childRToffset);
 static void make_setop_translation_lists(Query *query,
                                                         Index newvarno,
                                                         List **col_mappings, List **translated_vars);
@@ -477,14 +478,34 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
 {
        int                     varno = ((RangeTblRef *) jtnode)->rtindex;
        Query      *subquery = rte->subquery;
+       int                     rtoffset;
+       List       *rtable;
 
        /*
-        * Recursively scan the subquery's setOperations tree and copy the leaf
-        * subqueries into the parent rangetable.  Add AppendRelInfo nodes for
-        * them to the parent's append_rel_list, too.
+        * Append the subquery rtable entries to upper query.
+        */
+       rtoffset = list_length(root->parse->rtable);
+
+       /*
+        * Append child RTEs to parent rtable.
+        *
+        * Upper-level vars in subquery are now one level closer to their
+        * parent than before.  We don't have to worry about offsetting
+        * varnos, though, because any such vars must refer to stuff above the
+        * level of the query we are pulling into.
+        */
+       rtable = copyObject(subquery->rtable);
+       IncrementVarSublevelsUp_rtable(rtable, -1, 1);
+       root->parse->rtable = list_concat(root->parse->rtable, rtable);
+
+       /*
+        * Recursively scan the subquery's setOperations tree and add
+        * AppendRelInfo nodes for leaf subqueries to the parent's
+        * append_rel_list.
         */
        Assert(subquery->setOperations);
-       pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery);
+       pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery,
+                                                          rtoffset);
 
        /*
         * Mark the parent as an append relation.
@@ -500,41 +521,26 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
  * Note that setOpQuery is the Query containing the setOp node, whose rtable
  * is where to look up the RTE if setOp is a RangeTblRef.  This is *not* the
  * same as root->parse, which is the top-level Query we are pulling up into.
+ *
  * parentRTindex is the appendrel parent's index in root->parse->rtable.
+ *
+ * The child RTEs have already been copied to the parent. childRToffset
+ * tells us where in the parent's range table they were copied.
  */
 static void
 pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
-                                                  Query *setOpQuery)
+                                                  Query *setOpQuery, int childRToffset)
 {
        if (IsA(setOp, RangeTblRef))
        {
                RangeTblRef *rtr = (RangeTblRef *) setOp;
-               RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
-               Query      *subquery;
                int                     childRTindex;
                AppendRelInfo *appinfo;
-               Query      *parse = root->parse;
-
-               /*
-                * Make a modifiable copy of the child RTE and contained query.
-                */
-               rte = copyObject(rte);
-               subquery = rte->subquery;
-               Assert(subquery != NULL);
-
-               /*
-                * Upper-level vars in subquery are now one level closer to their
-                * parent than before.  We don't have to worry about offsetting
-                * varnos, though, because any such vars must refer to stuff above the
-                * level of the query we are pulling into.
-                */
-               IncrementVarSublevelsUp((Node *) subquery, -1, 1);
 
                /*
-                * Attach child RTE to parent rtable.
+                * Calculate the index in the parent's range table
                 */
-               parse->rtable = lappend(parse->rtable, rte);
-               childRTindex = list_length(parse->rtable);
+               childRTindex = childRToffset + rtr->rtindex;
 
                /*
                 * Build a suitable AppendRelInfo, and attach to parent's list.
@@ -566,8 +572,10 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
                SetOperationStmt *op = (SetOperationStmt *) setOp;
 
                /* Recurse to reach leaf queries */
-               pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery);
-               pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery);
+               pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
+                                                                  childRToffset);
+               pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
+                                                                  childRToffset);
        }
        else
        {
index 1984c0adeaf1d51e94b5e96bada4319e9e52a669..5be9d040fe1a1a2af2191e2ac82f4d8c9bbbee87 100644 (file)
@@ -509,6 +509,25 @@ IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
                                                                        0);
 }
 
+/*
+ * IncrementVarSublevelsUp_rtable -
+ *     Same as IncrementVarSublevelsUp, but to be invoked on a range table.
+ */
+void
+IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
+                                                          int min_sublevels_up)
+{
+       IncrementVarSublevelsUp_context context;
+
+       context.delta_sublevels_up = delta_sublevels_up;
+       context.min_sublevels_up = min_sublevels_up;
+
+       range_table_walker(rtable,
+                                          IncrementVarSublevelsUp_walker,
+                                          (void *) &context,
+                                          0);
+}
+
 
 /*
  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
index 9a05947478c6e232300d35509d4002a8e15f424b..0bae85c7c3b724155bdf83d5740a9437dfb021a6 100644 (file)
@@ -22,6 +22,8 @@ extern void ChangeVarNodes(Node *node, int old_varno, int new_varno,
                           int sublevels_up);
 extern void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
                                                int min_sublevels_up);
+extern void IncrementVarSublevelsUp_rtable(List *rtable,
+                                                          int delta_sublevels_up,      int min_sublevels_up);
 
 extern bool rangeTableEntry_used(Node *node, int rt_index,
                                         int sublevels_up);