aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteHandler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r--src/backend/rewrite/rewriteHandler.c91
1 files changed, 56 insertions, 35 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 4ad87f16ba4..ca9a2c27d8d 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.59 1999/10/02 04:42:04 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.60 1999/10/07 04:23:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -818,12 +818,13 @@ ApplyRetrieveRule(Query *parsetree,
int rt_index,
int relation_level,
Relation relation,
+ bool relWasInJoinSet,
int *modified)
{
Query *rule_action = NULL;
Node *rule_qual;
List *rtable,
- *rt,
+ *addedrtable,
*l;
int nothing,
rt_length;
@@ -844,19 +845,23 @@ ApplyRetrieveRule(Query *parsetree,
nothing = TRUE;
rtable = copyObject(parsetree->rtable);
- foreach(rt, rtable)
- {
- RangeTblEntry *rte = lfirst(rt);
+ rt_length = length(rtable); /* original length, not counting rule */
- /*
- * this is to prevent add_missing_vars_to_base_rels() from adding
- * a bogus entry to the new target list.
- */
- rte->inFromCl = false;
+ 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 (! relWasInJoinSet)
+ {
+ foreach(l, addedrtable)
+ {
+ RangeTblEntry *rte = lfirst(l);
+ rte->inJoinSet = false;
+ }
}
- rt_length = length(rtable);
- rtable = nconc(rtable, copyObject(rule_action->rtable));
+ rtable = nconc(rtable, addedrtable);
parsetree->rtable = rtable;
/* FOR UPDATE of view... */
@@ -1006,10 +1011,14 @@ fireRIRrules(Query *parsetree)
RuleLock *rules;
RewriteRule *rule;
RewriteRule RIRonly;
+ bool relWasInJoinSet;
int modified = false;
int i;
List *l;
+ /* don't try to convert this into a foreach loop, because
+ * rtable list can get changed each time through...
+ */
rt_index = 0;
while (rt_index < length(parsetree->rtable))
{
@@ -1017,46 +1026,57 @@ fireRIRrules(Query *parsetree)
rte = nth(rt_index - 1, parsetree->rtable);
- if (!rangeTableEntry_used((Node *) parsetree, rt_index, 0))
+ /*
+ * If the table is not one named in the original FROM clause
+ * then it must be referenced in the query, or we ignore it.
+ * This prevents infinite expansion loop due to new rtable
+ * entries inserted by expansion of a rule.
+ */
+ if (! rte->inFromCl && rt_index != parsetree->resultRelation &&
+ ! rangeTableEntry_used((Node *) parsetree, rt_index, 0))
{
-
- /*
- * Unused range table entries must not be marked as coming
- * from a clause. Otherwise the planner will generate joins
- * over relations that in fact shouldn't be scanned at all and
- * the result will contain duplicates
- *
- * Jan
- *
- */
- rte->inFromCl = FALSE;
+ /* Make sure the planner ignores it too... */
+ rte->inJoinSet = false;
continue;
}
rel = heap_openr(rte->relname, AccessShareLock);
- if (rel->rd_rules == NULL)
+ rules = rel->rd_rules;
+ if (rules == NULL)
{
heap_close(rel, AccessShareLock);
continue;
}
- rules = rel->rd_rules;
- locks = NIL;
+ relWasInJoinSet = rte->inJoinSet; /* save before possibly clearing */
/*
* Collect the RIR rules that we must apply
*/
+ locks = NIL;
for (i = 0; i < rules->numLocks; i++)
{
rule = rules->rules[i];
if (rule->event != CMD_SELECT)
continue;
- if (rule->attrno > 0 &&
- !attribute_used((Node *) parsetree,
- rt_index,
- rule->attrno, 0))
- continue;
+ if (rule->attrno > 0)
+ {
+ /* per-attr rule; do we need it? */
+ 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);
}
@@ -1083,6 +1103,7 @@ fireRIRrules(Query *parsetree)
rt_index,
RIRonly.attrno == -1,
rel,
+ relWasInJoinSet,
&modified);
}
@@ -2012,10 +2033,10 @@ Except_Intersect_Rewrite(Query *parsetree)
* If the Select Query node has aggregates in use add all the
* subselects to the HAVING qual else to the WHERE qual
*/
- if (intersect_node->hasAggs == false)
- AddQual(intersect_node, (Node *) n);
- else
+ if (intersect_node->hasAggs)
AddHavingQual(intersect_node, (Node *) n);
+ else
+ AddQual(intersect_node, (Node *) n);
/* Now we got sublinks */
intersect_node->hasSubLinks = true;