summaryrefslogtreecommitdiff
path: root/src/backend/rewrite
diff options
context:
space:
mode:
authorTom Lane2000-09-12 21:07:18 +0000
committerTom Lane2000-09-12 21:07:18 +0000
commited5003c58401e5727fcdd970505972394c95febb (patch)
tree53c25d5c65d6f7275f110503f51ab370e55af6ea /src/backend/rewrite
parentb5c0ab278bc67bc7f363da7d828a08ce7c4d28c2 (diff)
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!
Diffstat (limited to 'src/backend/rewrite')
-rw-r--r--src/backend/rewrite/locks.c76
-rw-r--r--src/backend/rewrite/rewriteHandler.c432
-rw-r--r--src/backend/rewrite/rewriteManip.c353
3 files changed, 415 insertions, 446 deletions
diff --git a/src/backend/rewrite/locks.c b/src/backend/rewrite/locks.c
index a14e1b48684..78fdad8960a 100644
--- a/src/backend/rewrite/locks.c
+++ b/src/backend/rewrite/locks.c
@@ -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))
+ if (IsA(node, Query))
{
+ /* Recurse into subselects */
+ bool result;
- /*
- * 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;
- }
+ result = query_tree_walker((Query *) node, thisLockWasTriggered_walker,
+ (void *) context);
context->sublevels_up--;
- return false;
- }
- if (IsA(node, Query))
- {
- /* Reach here after recursing down into subselect above... */
- Query *qry = (Query *) node;
-
- 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;
+ 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);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 4362687f8b8..49dfae5b905 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -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,29 +97,63 @@ 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
* clutzy but.....
*/
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.
- */
-
-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, 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
+ * 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
-{
- int rt_index;
- int attno;
- int sublevels_up;
-} attribute_used_context;
-
-static bool
-attribute_used_walker(Node *node,
- attribute_used_context *context)
+static List *
+adjustJoinTree(Query *parsetree, int rt_index, bool *found)
{
- if (node == NULL)
- return false;
- if (IsA(node, Var))
- {
- Var *var = (Var *) node;
+ List *newjointree = listCopy(parsetree->jointree);
+ List *jjt;
- if (var->varlevelsup == context->sublevels_up &&
- var->varno == context->rt_index &&
- var->varattno == context->attno)
- return true;
- return false;
- }
- if (IsA(node, SubLink))
+ *found = false;
+ foreach(jjt, newjointree)
{
+ RangeTblRef *rtr = lfirst(jjt);
- /*
- * 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;
+ if (IsA(rtr, RangeTblRef) && rtr->rtindex == rt_index)
+ {
+ newjointree = lremove(rtr, newjointree);
+ *found = true;
+ break;
+ }
}
- 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;
-
- 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;
+ /* Recurse into subselects */
+ bool result;
+
+ 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);
-
- rte->inJoinSet = false;
- }
+ /*
+ * 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);
+
+ 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);
}
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index a8ec560c741..e83ac054853 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -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,54 +292,181 @@ IncrementVarSublevelsUp_walker(Node *node,
var->varlevelsup += context->delta_sublevels_up;
return false;
}
- if (IsA(node, SubLink))
+ if (IsA(node, Query))
{
+ /* Recurse into subselects */
+ bool result;
- /*
- * Standard expression_tree_walker will not recurse into
- * subselect, but here we must do so.
- */
- SubLink *sub = (SubLink *) node;
+ 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);
+}
+
+void
+IncrementVarSublevelsUp(Node *node, 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;
+
+ /*
+ * 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 (IncrementVarSublevelsUp_walker((Node *) (sub->lefthand),
- context))
+ if (var->varlevelsup == context->sublevels_up &&
+ var->varno == context->rt_index)
return true;
- IncrementVarSublevelsUp((Node *) (sub->subselect),
- context->delta_sublevels_up,
- context->min_sublevels_up + 1);
return false;
}
- if (IsA(node, Query))
+ if (IsA(node, RangeTblRef))
{
- /* Reach here after recursing down into subselect above... */
- Query *qry = (Query *) node;
+ RangeTblRef *rtr = (RangeTblRef *) node;
- if (IncrementVarSublevelsUp_walker((Node *) (qry->targetList),
- context))
+ if (rtr->rtindex == context->rt_index &&
+ context->sublevels_up == 0)
return true;
- if (IncrementVarSublevelsUp_walker((Node *) (qry->qual),
- context))
- return true;
- if (IncrementVarSublevelsUp_walker((Node *) (qry->havingQual),
- context))
+ 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;
}
- return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
+ 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);
}
-void
-IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
- int min_sublevels_up)
+bool
+attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
{
- IncrementVarSublevelsUp_context context;
+ attribute_used_context context;
- context.delta_sublevels_up = delta_sublevels_up;
- context.min_sublevels_up = min_sublevels_up;
- IncrementVarSublevelsUp_walker(node, &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);
}