Thursday, August 14, 2008

Re: [BUGS] BUG #4350: 'select' acess given to views containing "union all" even though user has no grants

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);
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

No comments: