Tom Lane wrote:
Probably not. But it strikes me that there's another sin of omission
here: function and values RTEs need to be tweaked too, because they
contain expressions thst could have uplevel Vars in them. I'm not
certain such RTEs could appear at top level in a UNION query, but I'm
not sure they couldn't either.
Hmm. Maybe through a rewrite or something?
We should use range_table_walker, which knows how to descend into all
kinds of RTEs...
--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com
Index: src/backend/optimizer/prep/prepjointree.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/optimizer/prep/prepjointree.c,v
retrieving revision 1.44
diff -c -r1.44 prepjointree.c
*** src/backend/optimizer/prep/prepjointree.c 4 Oct 2006 00:29:54 -0000 1.44
--- src/backend/optimizer/prep/prepjointree.c 14 Aug 2008 11:50:22 -0000
***************
*** 46,52 ****
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);
static void make_setop_translation_lists(Query *query,
Index newvarno,
List **col_mappings, List **translated_vars);
--- 46,53 ----
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 childRToffset);
static void make_setop_translation_lists(Query *query,
Index newvarno,
List **col_mappings, List **translated_vars);
***************
*** 477,490 ****
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
Query *subquery = rte->subquery;
/*
! * 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.
*/
Assert(subquery->setOperations);
! pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery);
/*
* Mark the parent as an append relation.
--- 478,511 ----
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
Query *subquery = rte->subquery;
+ int rtoffset;
+ List *rtable;
/*
! * 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,
! rtoffset);
/*
* Mark the parent as an append relation.
***************
*** 500,540 ****
* 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.
*/
static void
pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
! Query *setOpQuery)
{
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.
*/
! parse->rtable = lappend(parse->rtable, rte);
! childRTindex = list_length(parse->rtable);
/*
* Build a suitable AppendRelInfo, and attach to parent's list.
--- 521,546 ----
* 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, int childRToffset)
{
if (IsA(setOp, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) setOp;
int childRTindex;
AppendRelInfo *appinfo;
/*
! * Calculate the index in the parent's range table
*/
! childRTindex = childRToffset + rtr->rtindex;
/*
* Build a suitable AppendRelInfo, and attach to parent's list.
***************
*** 566,573 ****
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);
}
else
{
--- 572,581 ----
SetOperationStmt *op = (SetOperationStmt *) setOp;
/* Recurse to reach leaf queries */
! pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
! childRToffset);
! pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
! childRToffset);
}
else
{
Index: src/backend/rewrite/rewriteManip.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/rewrite/rewriteManip.c,v
retrieving revision 1.102
diff -c -r1.102 rewriteManip.c
*** src/backend/rewrite/rewriteManip.c 4 Oct 2006 00:29:56 -0000 1.102
--- src/backend/rewrite/rewriteManip.c 14 Aug 2008 11:50:36 -0000
***************
*** 509,514 ****
--- 509,529 ----
0);
}
+ 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: src/include/rewrite/rewriteManip.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/rewrite/rewriteManip.h,v
retrieving revision 1.42
diff -c -r1.42 rewriteManip.h
*** src/include/rewrite/rewriteManip.h 5 Mar 2006 15:58:58 -0000 1.42
--- src/include/rewrite/rewriteManip.h 14 Aug 2008 11:38:08 -0000
***************
*** 22,27 ****
--- 22,29 ----
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);
--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs