From f24f233f6a9fb3af211c2fc658c5068e63593a8c Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 14 Aug 2008 20:31:29 +0000 Subject: [PATCH] Fix pull_up_simple_union_all to copy all rtable entries from child subquery to 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 | 68 +++++++++++++---------- src/backend/rewrite/rewriteManip.c | 21 ++++++- src/include/rewrite/rewriteManip.h | 4 +- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index b4be3d8d0c..241ad66807 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.51 2008/08/14 18:47:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.52 2008/08/14 20:31:29 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -47,7 +47,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); @@ -560,14 +561,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. @@ -583,41 +604,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. + * Calculate the index in the parent's range table */ - 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. - */ - 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. @@ -649,8 +655,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 { diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 60492fe3d0..1202c31314 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.108 2008/08/14 18:47:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.109 2008/08/14 20:31:29 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -533,6 +533,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 diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h index 05da127ffa..110d8ac0d1 100644 --- a/src/include/rewrite/rewriteManip.h +++ b/src/include/rewrite/rewriteManip.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/rewrite/rewriteManip.h,v 1.44 2008/01/01 19:45:58 momjian Exp $ + * $PostgreSQL: pgsql/src/include/rewrite/rewriteManip.h,v 1.45 2008/08/14 20:31:29 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -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);