1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-25 01:02:05 +03:00

First cut at full support for OUTER JOINs. There are still a few loose

ends to clean up (see my message of same date to pghackers), but mostly
it works.  INITDB REQUIRED!
This commit is contained in:
Tom Lane
2000-09-12 21:07:18 +00:00
parent b5c0ab278b
commit ed5003c584
93 changed files with 6386 additions and 4262 deletions

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.31 2000/09/06 14:15:20 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.32 2000/09/12 21:07:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -56,38 +56,16 @@ thisLockWasTriggered_walker(Node *node,
return true;
return false;
}
if (IsA(node, SubLink))
{
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (thisLockWasTriggered_walker((Node *) (sub->lefthand), context))
return true;
context->sublevels_up++;
if (thisLockWasTriggered_walker((Node *) (sub->subselect), context))
{
context->sublevels_up--; /* not really necessary */
return true;
}
context->sublevels_up--;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
/* Recurse into subselects */
bool result;
if (thisLockWasTriggered_walker((Node *) (qry->targetList), context))
return true;
if (thisLockWasTriggered_walker((Node *) (qry->qual), context))
return true;
if (thisLockWasTriggered_walker((Node *) (qry->havingQual), context))
return true;
return false;
context->sublevels_up++;
result = query_tree_walker((Query *) node, thisLockWasTriggered_walker,
(void *) context);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, thisLockWasTriggered_walker,
(void *) context);
@ -175,7 +153,7 @@ matchLocks(CmdType event,
typedef struct
{
Oid evowner;
Oid evowner;
} checkLockPerms_context;
static bool
@ -184,23 +162,8 @@ checkLockPerms_walker(Node *node,
{
if (node == NULL)
return false;
if (IsA(node, SubLink))
{
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (checkLockPerms_walker((Node *) (sub->lefthand), context))
return true;
if (checkLockPerms_walker((Node *) (sub->subselect), context))
return true;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
int rtablength = length(qry->rtable);
int i;
@ -212,13 +175,10 @@ checkLockPerms_walker(Node *node,
int32 reqperm;
int32 aclcheck_res;
if (rte->ref != NULL)
{
if (strcmp(rte->ref->relname, "*NEW*") == 0)
continue;
if (strcmp(rte->ref->relname, "*OLD*") == 0)
continue;
}
if (strcmp(rte->eref->relname, "*NEW*") == 0)
continue;
if (strcmp(rte->eref->relname, "*OLD*") == 0)
continue;
if (i == qry->resultRelation)
switch (qry->commandType)
@ -250,14 +210,8 @@ checkLockPerms_walker(Node *node,
/* If there are sublinks, search for them and check their RTEs */
if (qry->hasSubLinks)
{
if (checkLockPerms_walker((Node *) (qry->targetList), context))
return true;
if (checkLockPerms_walker((Node *) (qry->qual), context))
return true;
if (checkLockPerms_walker((Node *) (qry->havingQual), context))
return true;
}
return query_tree_walker(qry, checkLockPerms_walker,
(void *) context);
return false;
}
return expression_tree_walker(node, checkLockPerms_walker,
@ -278,7 +232,7 @@ checkLockPerms(List *locks, Query *parsetree, int rt_index)
return; /* nothing to check */
/*
* Get the usename of the rule's event relation owner
* Get the userid of the rule's event relation owner
*/
rte = rt_fetch(rt_index, parsetree->rtable);
ev_rel = heap_openr(rte->relname, AccessShareLock);

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.79 2000/09/06 14:15:20 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.80 2000/09/12 21:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -51,12 +51,11 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree,
Node *rule_qual,
int rt_index,
CmdType event,
bool *instead_flag);
static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up);
static bool attribute_used(Node *node, int rt_index, int attno,
int sublevels_up);
static bool modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index,
int sublevels_up, int new_sublevels_up);
bool instead_flag);
static List *adjustJoinTree(Query *parsetree, int rt_index, bool *found);
static bool modifyAggrefChangeVarnodes(Query *query,
int rt_index, int new_index,
int sublevels_up, int new_sublevels_up);
static Node *modifyAggrefDropQual(Node *node, Node *targetNode);
static SubLink *modifyAggrefMakeSublink(Aggref *aggref, Query *parsetree);
static Node *modifyAggrefQual(Node *node, Query *parsetree);
@ -80,16 +79,15 @@ gatherRewriteMeta(Query *parsetree,
Node *rule_qual,
int rt_index,
CmdType event,
bool *instead_flag)
bool instead_flag)
{
RewriteInfo *info;
int rt_length;
int result_reln;
info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
info->rt_index = rt_index;
info->event = event;
info->instead_flag = *instead_flag;
info->instead_flag = instead_flag;
info->rule_action = (Query *) copyObject(rule_action);
info->rule_qual = (Node *) copyObject(rule_qual);
if (info->rule_action == NULL)
@ -99,21 +97,54 @@ gatherRewriteMeta(Query *parsetree,
info->nothing = FALSE;
info->action = info->rule_action->commandType;
info->current_varno = rt_index;
info->rt = parsetree->rtable;
rt_length = length(info->rt);
info->rt = nconc(info->rt, copyObject(info->rule_action->rtable));
rt_length = length(parsetree->rtable);
/* Adjust rule action and qual to offset its varnos */
info->new_varno = PRS2_NEW_VARNO + rt_length;
OffsetVarNodes(info->rule_action->qual, rt_length, 0);
OffsetVarNodes((Node *) info->rule_action->targetList, rt_length, 0);
OffsetVarNodes((Node *) info->rule_action, rt_length, 0);
OffsetVarNodes(info->rule_qual, rt_length, 0);
ChangeVarNodes((Node *) info->rule_action->qual,
PRS2_OLD_VARNO + rt_length, rt_index, 0);
ChangeVarNodes((Node *) info->rule_action->targetList,
/* but its references to *OLD* should point at original rt_index */
ChangeVarNodes((Node *) info->rule_action,
PRS2_OLD_VARNO + rt_length, rt_index, 0);
ChangeVarNodes(info->rule_qual,
PRS2_OLD_VARNO + rt_length, rt_index, 0);
/*
* We want the main parsetree's rtable to end up as the concatenation
* of its original contents plus those of all the relevant rule
* actions. Also store same into all the rule_action rtables.
* Some of the entries may be unused after we finish rewriting, but
* if we tried to clean those out we'd have a much harder job to
* adjust RT indexes in the query's Vars. It's OK to have unused
* RT entries, since planner will ignore them.
*
* NOTE KLUGY HACK: we assume the parsetree rtable had at least one
* entry to begin with (OK enough, else where'd the rule come from?).
* Because of this, if multiple rules nconc() their rtable additions
* onto parsetree->rtable, they'll all see the same rtable because
* they all have the same list head pointer.
*/
parsetree->rtable = nconc(parsetree->rtable,
info->rule_action->rtable);
info->rule_action->rtable = parsetree->rtable;
/*
* Each rule action's jointree should be the main parsetree's jointree
* plus that rule's jointree, but *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.
*
* XXX This might be wrong for subselect-in-FROM?
*/
{
bool found;
List *newjointree = adjustJoinTree(parsetree, rt_index, &found);
info->rule_action->jointree = nconc(newjointree,
info->rule_action->jointree);
}
/*
* bug here about replace CURRENT -- sort of replace current is
* deprecated now so this code shouldn't really need to be so
@ -121,7 +152,8 @@ gatherRewriteMeta(Query *parsetree,
*/
if (info->action != CMD_SELECT)
{ /* i.e update XXXXX */
int new_result_reln = 0;
int result_reln;
int new_result_reln;
result_reln = info->rule_action->resultRelation;
switch (result_reln)
@ -140,152 +172,31 @@ gatherRewriteMeta(Query *parsetree,
return info;
}
/*
* rangeTableEntry_used -
* we need to process a RTE for RIR rules only if it is
* referenced somewhere in var nodes of the query.
* 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 JoinExprs). Returns modified jointree list --- original list
* is not changed. *found is set to indicate if we found the rt_index.
*/
typedef struct
static List *
adjustJoinTree(Query *parsetree, int rt_index, bool *found)
{
int rt_index;
int sublevels_up;
} rangeTableEntry_used_context;
List *newjointree = listCopy(parsetree->jointree);
List *jjt;
static bool
rangeTableEntry_used_walker(Node *node,
rangeTableEntry_used_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
*found = false;
foreach(jjt, newjointree)
{
Var *var = (Var *) node;
RangeTblRef *rtr = lfirst(jjt);
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index)
return true;
return false;
if (IsA(rtr, RangeTblRef) && rtr->rtindex == rt_index)
{
newjointree = lremove(rtr, newjointree);
*found = true;
break;
}
}
if (IsA(node, SubLink))
{
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (rangeTableEntry_used_walker((Node *) (sub->lefthand), context))
return true;
if (rangeTableEntry_used((Node *) (sub->subselect),
context->rt_index,
context->sublevels_up + 1))
return true;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
if (rangeTableEntry_used_walker((Node *) (qry->targetList), context))
return true;
if (rangeTableEntry_used_walker((Node *) (qry->qual), context))
return true;
if (rangeTableEntry_used_walker((Node *) (qry->havingQual), context))
return true;
return false;
}
return expression_tree_walker(node, rangeTableEntry_used_walker,
(void *) context);
}
static bool
rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
{
rangeTableEntry_used_context context;
context.rt_index = rt_index;
context.sublevels_up = sublevels_up;
return rangeTableEntry_used_walker(node, &context);
}
/*
* attribute_used -
* Check if a specific attribute number of a RTE is used
* somewhere in the query
*/
typedef struct
{
int rt_index;
int attno;
int sublevels_up;
} attribute_used_context;
static bool
attribute_used_walker(Node *node,
attribute_used_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index &&
var->varattno == context->attno)
return true;
return false;
}
if (IsA(node, SubLink))
{
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (attribute_used_walker((Node *) (sub->lefthand), context))
return true;
if (attribute_used((Node *) (sub->subselect),
context->rt_index,
context->attno,
context->sublevels_up + 1))
return true;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
if (attribute_used_walker((Node *) (qry->targetList), context))
return true;
if (attribute_used_walker((Node *) (qry->qual), context))
return true;
if (attribute_used_walker((Node *) (qry->havingQual), context))
return true;
return false;
}
return expression_tree_walker(node, attribute_used_walker,
(void *) context);
}
static bool
attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
{
attribute_used_context context;
context.rt_index = rt_index;
context.attno = attno;
context.sublevels_up = sublevels_up;
return attribute_used_walker(node, &context);
return newjointree;
}
@ -330,48 +241,26 @@ modifyAggrefChangeVarnodes_walker(Node *node,
}
return false;
}
if (IsA(node, SubLink))
{
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (modifyAggrefChangeVarnodes_walker((Node *) (sub->lefthand),
context))
return true;
if (modifyAggrefChangeVarnodes((Node *) (sub->subselect),
context->rt_index,
context->new_index,
context->sublevels_up + 1,
context->new_sublevels_up + 1))
return true;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
/* Recurse into subselects */
bool result;
if (modifyAggrefChangeVarnodes_walker((Node *) (qry->targetList),
context))
return true;
if (modifyAggrefChangeVarnodes_walker((Node *) (qry->qual),
context))
return true;
if (modifyAggrefChangeVarnodes_walker((Node *) (qry->havingQual),
context))
return true;
return false;
context->sublevels_up++;
context->new_sublevels_up++;
result = query_tree_walker((Query *) node,
modifyAggrefChangeVarnodes_walker,
(void *) context);
context->sublevels_up--;
context->new_sublevels_up--;
return result;
}
return expression_tree_walker(node, modifyAggrefChangeVarnodes_walker,
(void *) context);
}
static bool
modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index,
modifyAggrefChangeVarnodes(Query *query, int rt_index, int new_index,
int sublevels_up, int new_sublevels_up)
{
modifyAggrefChangeVarnodes_context context;
@ -380,7 +269,8 @@ modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index,
context.new_index = new_index;
context.sublevels_up = sublevels_up;
context.new_sublevels_up = new_sublevels_up;
return modifyAggrefChangeVarnodes_walker(node, &context);
return query_tree_walker(query, modifyAggrefChangeVarnodes_walker,
(void *) &context);
}
@ -453,6 +343,7 @@ modifyAggrefMakeSublink(Aggref *aggref, Query *parsetree)
SubLink *sublink;
TargetEntry *tle;
Resdom *resdom;
RangeTblRef *rtr;
aggVarNos = pull_varnos(aggref->target);
if (length(aggVarNos) != 1)
@ -492,6 +383,9 @@ modifyAggrefMakeSublink(Aggref *aggref, Query *parsetree)
subquery->distinctClause = NIL;
subquery->sortClause = NIL;
subquery->rtable = lcons(copyObject(rte), NIL);
rtr = makeNode(RangeTblRef);
rtr->rtindex = 1;
subquery->jointree = lcons(rtr, NIL);
subquery->targetList = lcons(tle, NIL);
subquery->qual = modifyAggrefDropQual((Node *) parsetree->qual,
(Node *) aggref);
@ -517,7 +411,7 @@ modifyAggrefMakeSublink(Aggref *aggref, Query *parsetree)
* Note that because of previous line, these references have
* varlevelsup = 1, which must be changed to 0.
*/
modifyAggrefChangeVarnodes((Node *) subquery,
modifyAggrefChangeVarnodes(subquery,
lfirsti(aggVarNos), 1,
1, 0);
@ -675,6 +569,8 @@ apply_RIR_view_mutator(Node *node,
apply_RIR_view_mutator, context);
MUTATE(newnode->havingQual, query->havingQual, Node *,
apply_RIR_view_mutator, context);
MUTATE(newnode->jointree, query->jointree, List *,
apply_RIR_view_mutator, context);
return (Node *) newnode;
}
return expression_tree_mutator(node, apply_RIR_view_mutator,
@ -703,7 +599,7 @@ ApplyRetrieveRule(Query *parsetree,
int rt_index,
int relation_level,
Relation relation,
bool relWasInJoinSet)
bool relIsUsed)
{
Query *rule_action = NULL;
Node *rule_qual;
@ -735,17 +631,34 @@ ApplyRetrieveRule(Query *parsetree,
addedrtable = copyObject(rule_action->rtable);
/*
* If the original rel wasn't in the join set, none of its spawn is.
* If it was, then leave the spawn's flags as they are.
* If the original rel wasn't in the join set (which'd be the case
* for the target of an INSERT, for example), none of its spawn is.
* If it was, then the spawn has to be added to the join set.
*/
if (!relWasInJoinSet)
if (relIsUsed)
{
foreach(l, addedrtable)
{
RangeTblEntry *rte = lfirst(l);
/*
* QUICK HACK: this all needs to be replaced, but for now, find
* the original rel in the jointree, remove it, and add the rule
* action's jointree. This will not work for views referenced
* in JoinExprs!!
*
* Note: it is possible that the old rel is referenced in the query
* but isn't present in the jointree; this should only happen for
* *OLD* and *NEW*. We must not fail if so, but add the rule's
* jointree anyway. (This is a major crock ... should fix rule
* representation ...)
*/
bool found;
List *newjointree = adjustJoinTree(parsetree, rt_index, &found);
List *addedjointree = (List *) copyObject(rule_action->jointree);
rte->inJoinSet = false;
}
if (!found)
elog(DEBUG, "ApplyRetrieveRule: can't find old rel %s (%d) in jointree",
rt_fetch(rt_index, rtable)->eref->relname, rt_index);
OffsetVarNodes((Node *) addedjointree, rt_length, 0);
newjointree = nconc(newjointree, addedjointree);
parsetree->jointree = newjointree;
}
rtable = nconc(rtable, addedrtable);
@ -845,6 +758,10 @@ ApplyRetrieveRule(Query *parsetree,
* NOTE: although this has the form of a walker, we cheat and modify the
* SubLink nodes in-place. It is caller's responsibility to ensure that
* no unwanted side-effects occur!
*
* This is unlike most of the other routines that recurse into subselects,
* because we must take control at the SubLink node in order to replace
* the SubLink's subselect link with the possibly-rewritten subquery.
*/
static bool
fireRIRonSubselect(Node *node, void *context)
@ -854,30 +771,15 @@ fireRIRonSubselect(Node *node, void *context)
if (IsA(node, SubLink))
{
SubLink *sub = (SubLink *) node;
Query *qry;
/* Process lefthand args */
if (fireRIRonSubselect((Node *) (sub->lefthand), context))
return true;
/* Do what we came for */
qry = fireRIRrules((Query *) (sub->subselect));
sub->subselect = (Node *) qry;
/* Need not recurse into subselect, because fireRIRrules did it */
return false;
}
if (IsA(node, Query))
{
/* Reach here when called from fireRIRrules */
Query *qry = (Query *) node;
if (fireRIRonSubselect((Node *) (qry->targetList), context))
return true;
if (fireRIRonSubselect((Node *) (qry->qual), context))
return true;
if (fireRIRonSubselect((Node *) (qry->havingQual), context))
return true;
return false;
sub->subselect = (Node *) fireRIRrules((Query *) (sub->subselect));
/* Fall through to process lefthand args of SubLink */
}
/*
* Do NOT recurse into Query nodes, because fireRIRrules already
* processed subselects for us.
*/
return expression_tree_walker(node, fireRIRonSubselect,
(void *) context);
}
@ -897,7 +799,7 @@ fireRIRrules(Query *parsetree)
RuleLock *rules;
RewriteRule *rule;
RewriteRule RIRonly;
bool relWasInJoinSet;
bool relIsUsed;
int i;
List *l;
@ -916,11 +818,12 @@ fireRIRrules(Query *parsetree)
* If the table is not referenced in the query, then we ignore it.
* This prevents infinite expansion loop due to new rtable entries
* inserted by expansion of a rule. A table is referenced if it is
* part of the join set (a source table), or is the result table,
* or is referenced by any Var nodes.
* part of the join set (a source table), or is referenced by any
* Var nodes, or is the result table.
*/
if (!rte->inJoinSet && rt_index != parsetree->resultRelation &&
!rangeTableEntry_used((Node *) parsetree, rt_index, 0))
relIsUsed = rangeTableEntry_used((Node *) parsetree, rt_index, 0);
if (!relIsUsed && rt_index != parsetree->resultRelation)
continue;
rel = heap_openr(rte->relname, AccessShareLock);
@ -931,9 +834,6 @@ fireRIRrules(Query *parsetree)
continue;
}
relWasInJoinSet = rte->inJoinSet; /* save before possibly
* clearing */
/*
* Collect the RIR rules that we must apply
*/
@ -947,22 +847,10 @@ fireRIRrules(Query *parsetree)
if (rule->attrno > 0)
{
/* per-attr rule; do we need it? */
if (!attribute_used((Node *) parsetree,
rt_index,
if (!attribute_used((Node *) parsetree, rt_index,
rule->attrno, 0))
continue;
}
else
{
/*
* Rel-wide ON SELECT DO INSTEAD means this is a view.
* Remove the view from the planner's join target set, or
* we'll get no rows out because view itself is empty!
*/
if (rule->isInstead)
rte->inJoinSet = false;
}
locks = lappend(locks, rule);
}
@ -989,7 +877,7 @@ fireRIRrules(Query *parsetree)
rt_index,
RIRonly.attrno == -1,
rel,
relWasInJoinSet);
relIsUsed);
}
heap_close(rel, AccessShareLock);
@ -999,7 +887,7 @@ fireRIRrules(Query *parsetree)
parsetree->qual = modifyAggrefQual(parsetree->qual, parsetree);
if (parsetree->hasSubLinks)
fireRIRonSubselect((Node *) parsetree, NULL);
query_tree_walker(parsetree, fireRIRonSubselect, NULL);
return parsetree;
}
@ -1056,13 +944,20 @@ CopyAndAddQual(Query *parsetree,
{
List *rtable;
int rt_length;
List *jointree;
rtable = new_tree->rtable;
rt_length = length(rtable);
rtable = nconc(rtable, copyObject(rule_action->rtable));
/* XXX above possibly wrong for subselect-in-FROM */
new_tree->rtable = rtable;
OffsetVarNodes(new_qual, rt_length, 0);
ChangeVarNodes(new_qual, PRS2_OLD_VARNO + rt_length, rt_index, 0);
jointree = copyObject(rule_action->jointree);
OffsetVarNodes((Node *) jointree, rt_length, 0);
ChangeVarNodes((Node *) jointree, PRS2_OLD_VARNO + rt_length,
rt_index, 0);
new_tree->jointree = nconc(new_tree->jointree, jointree);
}
/* XXX -- where current doesn't work for instead nothing.... yet */
AddNotQual(new_tree, new_qual);
@ -1103,8 +998,7 @@ fireRules(Query *parsetree,
foreach(i, locks)
{
RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
Node *qual,
*event_qual;
Node *event_qual;
List *actions;
List *r;
@ -1227,7 +1121,7 @@ fireRules(Query *parsetree,
*--------------------------------------------------
*/
info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
rt_index, event, instead_flag);
rt_index, event, *instead_flag);
/* handle escapable cases, or those handled by other code */
if (info->nothing)
@ -1247,11 +1141,9 @@ fireRules(Query *parsetree,
* splitting into two queries one w/rule_qual, one w/NOT
* rule_qual. Also add user query qual onto rule action
*/
qual = parsetree->qual;
AddQual(info->rule_action, qual);
AddQual(info->rule_action, parsetree->qual);
if (info->rule_qual != NULL)
AddQual(info->rule_action, info->rule_qual);
AddQual(info->rule_action, info->rule_qual);
/*--------------------------------------------------
* Step 2:
@ -1264,18 +1156,6 @@ fireRules(Query *parsetree,
/*--------------------------------------------------
* Step 3:
* rewriting due to retrieve rules
*--------------------------------------------------
*/
info->rule_action->rtable = info->rt;
/*
* ProcessRetrieveQuery(info->rule_action, info->rt,
* &orig_instead_flag, TRUE);
*/
/*--------------------------------------------------
* Step 4
* Simplify? hey, no algorithm for simplification... let
* the planner do it.
*--------------------------------------------------
@ -1403,7 +1283,7 @@ deepRewriteQuery(Query *parsetree)
rewritten = nconc(rewritten, qual_products);
/* ----------
* The original query is appended last if not instead
* The original query is appended last (if no "instead" rule)
* because update and delete rule actions might not do
* anything if they are invoked after the update or
* delete is performed. The command counter increment
@ -1471,17 +1351,15 @@ BasicQueryRewrite(Query *parsetree)
*/
if (query->hasAggs)
{
query->hasAggs =
checkExprHasAggs((Node *) (query->targetList)) ||
checkExprHasAggs((Node *) (query->havingQual));
if (checkExprHasAggs((Node *) (query->qual)))
elog(ERROR, "BasicQueryRewrite: failed to remove aggs from qual");
query->hasAggs = checkExprHasAggs((Node *) query);
if (query->hasAggs)
if (checkExprHasAggs(query->qual))
elog(ERROR, "BasicQueryRewrite: failed to remove aggs from qual");
}
if (query->hasSubLinks)
query->hasSubLinks =
checkExprHasSubLink((Node *) (query->targetList)) ||
checkExprHasSubLink((Node *) (query->qual)) ||
checkExprHasSubLink((Node *) (query->havingQual));
{
query->hasSubLinks = checkExprHasSubLink((Node *) query);
}
results = lappend(results, query);
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.47 2000/05/30 00:49:51 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.48 2000/09/12 21:07:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -42,7 +42,15 @@ static bool checkExprHasSubLink_walker(Node *node, void *context);
bool
checkExprHasAggs(Node *node)
{
return checkExprHasAggs_walker(node, NULL);
/*
* If a Query is passed, examine it --- but we will not recurse
* into sub-Queries.
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, checkExprHasAggs_walker,
NULL);
else
return checkExprHasAggs_walker(node, NULL);
}
static bool
@ -64,7 +72,15 @@ checkExprHasAggs_walker(Node *node, void *context)
bool
checkExprHasSubLink(Node *node)
{
return checkExprHasSubLink_walker(node, NULL);
/*
* If a Query is passed, examine it --- but we will not recurse
* into sub-Queries.
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, checkExprHasSubLink_walker,
NULL);
else
return checkExprHasSubLink_walker(node, NULL);
}
static bool
@ -84,10 +100,11 @@ checkExprHasSubLink_walker(Node *node, void *context)
*
* Find all Var nodes in the given tree with varlevelsup == sublevels_up,
* and increment their varno fields (rangetable indexes) by 'offset'.
* The varnoold fields are adjusted similarly.
* The varnoold fields are adjusted similarly. Also, RangeTblRef nodes
* in join trees are adjusted.
*
* NOTE: although this has the form of a walker, we cheat and modify the
* Var nodes in-place. The given expression tree should have been copied
* nodes in-place. The given expression tree should have been copied
* earlier to ensure that no unwanted side-effects occur!
*/
@ -113,38 +130,24 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
}
return false;
}
if (IsA(node, SubLink))
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (OffsetVarNodes_walker((Node *) (sub->lefthand),
context))
return true;
OffsetVarNodes((Node *) (sub->subselect),
context->offset,
context->sublevels_up + 1);
if (context->sublevels_up == 0)
rtr->rtindex += context->offset;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
/* Recurse into subselects */
bool result;
if (OffsetVarNodes_walker((Node *) (qry->targetList),
context))
return true;
if (OffsetVarNodes_walker((Node *) (qry->qual),
context))
return true;
if (OffsetVarNodes_walker((Node *) (qry->havingQual),
context))
return true;
return false;
context->sublevels_up++;
result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
(void *) context);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, OffsetVarNodes_walker,
(void *) context);
@ -157,7 +160,17 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
context.offset = offset;
context.sublevels_up = sublevels_up;
OffsetVarNodes_walker(node, &context);
/*
* Must be prepared to start with a Query or a bare expression tree;
* if it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
query_tree_walker((Query *) node, OffsetVarNodes_walker,
(void *) &context);
else
OffsetVarNodes_walker(node, &context);
}
/*
@ -165,10 +178,11 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
*
* Find all Var nodes in the given tree belonging to a specific relation
* (identified by sublevels_up and rt_index), and change their varno fields
* to 'new_index'. The varnoold fields are changed too.
* to 'new_index'. The varnoold fields are changed too. Also, RangeTblRef
* nodes in join trees are adjusted.
*
* NOTE: although this has the form of a walker, we cheat and modify the
* Var nodes in-place. The given expression tree should have been copied
* nodes in-place. The given expression tree should have been copied
* earlier to ensure that no unwanted side-effects occur!
*/
@ -196,39 +210,25 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
}
return false;
}
if (IsA(node, SubLink))
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (ChangeVarNodes_walker((Node *) (sub->lefthand),
context))
return true;
ChangeVarNodes((Node *) (sub->subselect),
context->rt_index,
context->new_index,
context->sublevels_up + 1);
if (context->sublevels_up == 0 &&
rtr->rtindex == context->rt_index)
rtr->rtindex = context->new_index;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
/* Recurse into subselects */
bool result;
if (ChangeVarNodes_walker((Node *) (qry->targetList),
context))
return true;
if (ChangeVarNodes_walker((Node *) (qry->qual),
context))
return true;
if (ChangeVarNodes_walker((Node *) (qry->havingQual),
context))
return true;
return false;
context->sublevels_up++;
result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
(void *) context);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, ChangeVarNodes_walker,
(void *) context);
@ -242,7 +242,17 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
context.rt_index = rt_index;
context.new_index = new_index;
context.sublevels_up = sublevels_up;
ChangeVarNodes_walker(node, &context);
/*
* Must be prepared to start with a Query or a bare expression tree;
* if it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
query_tree_walker((Query *) node, ChangeVarNodes_walker,
(void *) &context);
else
ChangeVarNodes_walker(node, &context);
}
/*
@ -282,38 +292,17 @@ IncrementVarSublevelsUp_walker(Node *node,
var->varlevelsup += context->delta_sublevels_up;
return false;
}
if (IsA(node, SubLink))
{
/*
* Standard expression_tree_walker will not recurse into
* subselect, but here we must do so.
*/
SubLink *sub = (SubLink *) node;
if (IncrementVarSublevelsUp_walker((Node *) (sub->lefthand),
context))
return true;
IncrementVarSublevelsUp((Node *) (sub->subselect),
context->delta_sublevels_up,
context->min_sublevels_up + 1);
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
/* Recurse into subselects */
bool result;
if (IncrementVarSublevelsUp_walker((Node *) (qry->targetList),
context))
return true;
if (IncrementVarSublevelsUp_walker((Node *) (qry->qual),
context))
return true;
if (IncrementVarSublevelsUp_walker((Node *) (qry->havingQual),
context))
return true;
return false;
context->min_sublevels_up++;
result = query_tree_walker((Query *) node,
IncrementVarSublevelsUp_walker,
(void *) context);
context->min_sublevels_up--;
return result;
}
return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
(void *) context);
@ -327,9 +316,157 @@ IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
context.delta_sublevels_up = delta_sublevels_up;
context.min_sublevels_up = min_sublevels_up;
IncrementVarSublevelsUp_walker(node, &context);
/*
* Must be prepared to start with a Query or a bare expression tree;
* if it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
query_tree_walker((Query *) node, IncrementVarSublevelsUp_walker,
(void *) &context);
else
IncrementVarSublevelsUp_walker(node, &context);
}
/*
* rangeTableEntry_used - detect whether an RTE is referenced somewhere
* in var nodes or jointree nodes of a query or expression.
*/
typedef struct
{
int rt_index;
int sublevels_up;
} rangeTableEntry_used_context;
static bool
rangeTableEntry_used_walker(Node *node,
rangeTableEntry_used_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index)
return true;
return false;
}
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
if (rtr->rtindex == context->rt_index &&
context->sublevels_up == 0)
return true;
return false;
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
(void *) context);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, rangeTableEntry_used_walker,
(void *) context);
}
bool
rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
{
rangeTableEntry_used_context context;
context.rt_index = rt_index;
context.sublevels_up = sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree;
* if it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, rangeTableEntry_used_walker,
(void *) &context);
else
return rangeTableEntry_used_walker(node, &context);
}
/*
* attribute_used -
* Check if a specific attribute number of a RTE is used
* somewhere in the query or expression.
*/
typedef struct
{
int rt_index;
int attno;
int sublevels_up;
} attribute_used_context;
static bool
attribute_used_walker(Node *node,
attribute_used_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index &&
var->varattno == context->attno)
return true;
return false;
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node, attribute_used_walker,
(void *) context);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, attribute_used_walker,
(void *) context);
}
bool
attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
{
attribute_used_context context;
context.rt_index = rt_index;
context.attno = attno;
context.sublevels_up = sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree;
* if it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, attribute_used_walker,
(void *) &context);
else
return attribute_used_walker(node, &context);
}
/*
* Add the given qualifier condition to the query's WHERE clause
*/
@ -615,11 +752,6 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
Query *query = (Query *) node;
Query *newnode;
/*
* XXX original code for ResolveNew only recursed into qual field
* of subquery. I'm assuming that was an oversight ... tgl 9/99
*/
FLATCOPY(newnode, query, Query);
MUTATE(newnode->targetList, query->targetList, List *,
ResolveNew_mutator, context);
@ -627,6 +759,8 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
ResolveNew_mutator, context);
MUTATE(newnode->havingQual, query->havingQual, Node *,
ResolveNew_mutator, context);
MUTATE(newnode->jointree, query->jointree, List *,
ResolveNew_mutator, context);
return (Node *) newnode;
}
return expression_tree_mutator(node, ResolveNew_mutator,
@ -650,13 +784,15 @@ void
FixNew(RewriteInfo *info, Query *parsetree)
{
info->rule_action->targetList = (List *)
ResolveNew((Node *) info->rule_action->targetList,
info, parsetree->targetList, 0);
ResolveNew((Node *) info->rule_action->targetList,
info, parsetree->targetList, 0);
info->rule_action->qual = ResolveNew(info->rule_action->qual,
info, parsetree->targetList, 0);
/* XXX original code didn't fix havingQual; presumably an oversight? */
info->rule_action->havingQual = ResolveNew(info->rule_action->havingQual,
info, parsetree->targetList, 0);
info, parsetree->targetList, 0);
info->rule_action->jointree = (List *)
ResolveNew((Node *) info->rule_action->jointree,
info, parsetree->targetList, 0);
}
/*
@ -758,11 +894,6 @@ HandleRIRAttributeRule_mutator(Node *node,
Query *query = (Query *) node;
Query *newnode;
/*
* XXX original code for HandleRIRAttributeRule only recursed into
* qual field of subquery. I'm assuming that was an oversight ...
*/
FLATCOPY(newnode, query, Query);
MUTATE(newnode->targetList, query->targetList, List *,
HandleRIRAttributeRule_mutator, context);
@ -770,6 +901,8 @@ HandleRIRAttributeRule_mutator(Node *node,
HandleRIRAttributeRule_mutator, context);
MUTATE(newnode->havingQual, query->havingQual, Node *,
HandleRIRAttributeRule_mutator, context);
MUTATE(newnode->jointree, query->jointree, List *,
HandleRIRAttributeRule_mutator, context);
return (Node *) newnode;
}
return expression_tree_mutator(node, HandleRIRAttributeRule_mutator,
@ -798,9 +931,13 @@ HandleRIRAttributeRule(Query *parsetree,
parsetree->targetList = (List *)
HandleRIRAttributeRule_mutator((Node *) parsetree->targetList,
&context);
parsetree->qual = HandleRIRAttributeRule_mutator(parsetree->qual,
&context);
/* XXX original code did not fix havingQual ... oversight? */
parsetree->havingQual = HandleRIRAttributeRule_mutator(parsetree->havingQual,
&context);
parsetree->qual =
HandleRIRAttributeRule_mutator(parsetree->qual,
&context);
parsetree->havingQual =
HandleRIRAttributeRule_mutator(parsetree->havingQual,
&context);
parsetree->jointree = (List *)
HandleRIRAttributeRule_mutator((Node *) parsetree->jointree,
&context);
}