Repair bug reported by Huxton, 1/24/01. We need to include a rule's

original table ('OLD' table) in its join tree if OLD is referenced by
either the rule action, the rule qual, or the original query qual that
will be added to the rule action.  However, we only want one instance
of the original table to be included; so beware of the possibility that
the rule action already has a jointree entry for OLD.
This commit is contained in:
Tom Lane 2001-01-27 04:40:59 +00:00
parent a60537240f
commit 352871ac93
1 changed files with 32 additions and 24 deletions

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.88 2001/01/24 19:43:05 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.89 2001/01/27 04:40:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -37,7 +37,7 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree,
int rt_index,
CmdType event,
bool instead_flag);
static List *adjustJoinTreeList(Query *parsetree, int rt_index, bool *found);
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static void markQueryForUpdate(Query *qry, bool skipOldNew);
static List *matchLocks(CmdType event, RuleLock *rulelocks,
int varno, Query *parsetree);
@ -119,18 +119,25 @@ gatherRewriteMeta(Query *parsetree,
/*
* Each rule action's jointree should be the main parsetree's jointree
* plus that rule's jointree, but *without* the original rtindex
* plus that rule's jointree, but usually *without* the original rtindex
* that we're replacing (if present, which it won't be for INSERT).
* Note that if the rule refers to OLD, its jointree will add back
* a reference to rt_index.
* Note that if the rule action refers to OLD, its jointree will add
* a reference to rt_index. If the rule action doesn't refer to OLD,
* but either the rule_qual or the user query quals do, then we need to
* keep the original rtindex in the jointree to provide data for the
* quals. We don't want the original rtindex to be joined twice,
* however, so avoid keeping it if the rule action mentions it.
*/
if (sub_action->jointree != NULL)
{
bool found;
List *newjointree = adjustJoinTreeList(parsetree,
rt_index,
&found);
bool keeporig;
List *newjointree;
keeporig = (! rangeTableEntry_used((Node *) sub_action->jointree,
rt_index, 0)) &&
(rangeTableEntry_used(info->rule_qual, rt_index, 0) ||
rangeTableEntry_used(parsetree->jointree->quals, rt_index, 0));
newjointree = adjustJoinTreeList(parsetree, !keeporig, rt_index);
sub_action->jointree->fromlist =
nconc(newjointree, sub_action->jointree->fromlist);
}
@ -181,29 +188,30 @@ gatherRewriteMeta(Query *parsetree,
}
/*
* Copy the query's jointree list, and attempt to remove any occurrence
* of the given rt_index as a top-level join item (we do not look for it
* within join items; this is OK because we are only expecting to find it
* as an UPDATE or DELETE target relation, which will be at the top level
* of the join). Returns modified jointree list --- original list
* is not changed. *found is set to indicate if we found the rt_index.
* Copy the query's jointree list, and optionally attempt to remove any
* occurrence of the given rt_index as a top-level join item (we do not look
* for it within join items; this is OK because we are only expecting to find
* it as an UPDATE or DELETE target relation, which will be at the top level
* of the join). Returns modified jointree list --- original list is not
* changed.
*/
static List *
adjustJoinTreeList(Query *parsetree, int rt_index, bool *found)
adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
{
List *newjointree = listCopy(parsetree->jointree->fromlist);
List *jjt;
*found = false;
foreach(jjt, newjointree)
if (removert)
{
RangeTblRef *rtr = lfirst(jjt);
if (IsA(rtr, RangeTblRef) && rtr->rtindex == rt_index)
foreach(jjt, newjointree)
{
newjointree = lremove(rtr, newjointree);
*found = true;
break;
RangeTblRef *rtr = lfirst(jjt);
if (IsA(rtr, RangeTblRef) && rtr->rtindex == rt_index)
{
newjointree = lremove(rtr, newjointree);
break;
}
}
}
return newjointree;