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.c320
1 files changed, 150 insertions, 170 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index a0a9d5671e5..6b842582b43 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.83 2000/11/08 22:09:59 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.84 2000/12/05 19:15:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,6 +61,8 @@ gatherRewriteMeta(Query *parsetree,
bool instead_flag)
{
RewriteInfo *info;
+ Query *sub_action;
+ Query **sub_action_ptr;
int rt_length;
info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
@@ -70,85 +72,135 @@ gatherRewriteMeta(Query *parsetree,
info->rule_action = (Query *) copyObject(rule_action);
info->rule_qual = (Node *) copyObject(rule_qual);
if (info->rule_action == NULL)
- info->nothing = TRUE;
- else
{
- info->nothing = FALSE;
- info->action = info->rule_action->commandType;
- info->current_varno = rt_index;
- rt_length = length(parsetree->rtable);
-
- /* Adjust rule action and qual to offset its varnos */
- info->new_varno = PRS2_NEW_VARNO + rt_length;
- OffsetVarNodes((Node *) info->rule_action, rt_length, 0);
- OffsetVarNodes(info->rule_qual, rt_length, 0);
- /* 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);
+ info->nothing = TRUE;
+ return info;
+ }
+ info->nothing = FALSE;
+ info->action = info->rule_action->commandType;
+ info->current_varno = rt_index;
+ rt_length = length(parsetree->rtable);
+ info->new_varno = PRS2_NEW_VARNO + rt_length;
- /*
- * 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;
+ /*
+ * Adjust rule action and qual to offset its varnos, so that we can
+ * merge its rtable into the main parsetree's rtable.
+ *
+ * If the rule action is an INSERT...SELECT, the OLD/NEW rtable
+ * entries will be in the SELECT part, and we have to modify that
+ * rather than the top-level INSERT (kluge!).
+ */
+ sub_action = getInsertSelectQuery(info->rule_action, &sub_action_ptr);
- /*
- * 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.
- */
+ OffsetVarNodes((Node *) sub_action, rt_length, 0);
+ OffsetVarNodes(info->rule_qual, rt_length, 0);
+ /* but references to *OLD* should point at original rt_index */
+ ChangeVarNodes((Node *) sub_action,
+ PRS2_OLD_VARNO + rt_length, rt_index, 0);
+ ChangeVarNodes(info->rule_qual,
+ PRS2_OLD_VARNO + rt_length, rt_index, 0);
+
+ /*
+ * Update resultRelation too ... perhaps this should be done by
+ * Offset/ChangeVarNodes?
+ */
+ if (sub_action->resultRelation)
+ {
+ int result_reln;
+ int new_result_reln;
+
+ result_reln = sub_action->resultRelation;
+ switch (result_reln)
{
- bool found;
- List *newjointree = adjustJoinTreeList(parsetree,
- rt_index,
- &found);
-
- info->rule_action->jointree->fromlist =
- nconc(newjointree,
- info->rule_action->jointree->fromlist);
+ case PRS2_OLD_VARNO:
+ new_result_reln = rt_index;
+ break;
+ case PRS2_NEW_VARNO:
+ default:
+ new_result_reln = result_reln + rt_length;
+ break;
}
+ sub_action->resultRelation = new_result_reln;
+ }
- /*
- * 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 result_reln;
- int new_result_reln;
+ /*
+ * 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,
+ sub_action->rtable);
+ sub_action->rtable = parsetree->rtable;
- result_reln = info->rule_action->resultRelation;
- switch (result_reln)
- {
- case PRS2_OLD_VARNO:
- new_result_reln = rt_index;
- break;
- case PRS2_NEW_VARNO: /* XXX */
- default:
- new_result_reln = result_reln + rt_length;
- break;
- }
- info->rule_action->resultRelation = new_result_reln;
- }
+ /*
+ * 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.
+ */
+ {
+ bool found;
+ List *newjointree = adjustJoinTreeList(parsetree,
+ rt_index,
+ &found);
+
+ sub_action->jointree->fromlist =
+ nconc(newjointree, sub_action->jointree->fromlist);
}
+
+ /*
+ * We copy the qualifications of the parsetree to the action and vice
+ * versa. So force hasSubLinks if one of them has it. If this is not
+ * right, the flag will get cleared later, but we mustn't risk having
+ * it not set when it needs to be.
+ */
+ if (parsetree->hasSubLinks)
+ sub_action->hasSubLinks = TRUE;
+ else if (sub_action->hasSubLinks)
+ parsetree->hasSubLinks = TRUE;
+
+ /*
+ * Event Qualification forces copying of parsetree and
+ * splitting into two queries one w/rule_qual, one w/NOT
+ * rule_qual. Also add user query qual onto rule action
+ */
+ AddQual(sub_action, info->rule_qual);
+
+ AddQual(sub_action, parsetree->jointree->quals);
+
+ /*
+ * Rewrite new.attribute w/ right hand side of target-list
+ * entry for appropriate field name in insert/update.
+ *
+ * KLUGE ALERT: since ResolveNew returns a mutated copy, we can't just
+ * apply it to sub_action; we have to remember to update the sublink
+ * inside info->rule_action, too.
+ */
+ if (info->event == CMD_INSERT || info->event == CMD_UPDATE)
+ {
+ sub_action = (Query *) ResolveNew((Node *) sub_action,
+ info->new_varno,
+ 0,
+ parsetree->targetList,
+ info->event,
+ info->current_varno);
+ if (sub_action_ptr)
+ *sub_action_ptr = sub_action;
+ else
+ info->rule_action = sub_action;
+ }
+
return info;
}
@@ -536,42 +588,37 @@ orderRules(List *locks)
}
-
+/*
+ * Modify the given query by adding 'AND NOT rule_qual' to its qualification.
+ * This is used to generate suitable "else clauses" for conditional INSTEAD
+ * rules.
+ *
+ * The rule_qual may contain references to OLD or NEW. OLD references are
+ * replaced by references to the specified rt_index (the relation that the
+ * rule applies to). NEW references are only possible for INSERT and UPDATE
+ * queries on the relation itself, and so they should be replaced by copies
+ * of the related entries in the query's own targetlist.
+ */
static Query *
CopyAndAddQual(Query *parsetree,
- List *actions,
Node *rule_qual,
int rt_index,
CmdType event)
{
Query *new_tree = (Query *) copyObject(parsetree);
- Node *new_qual = NULL;
- Query *rule_action = NULL;
-
- if (actions)
- rule_action = lfirst(actions);
- if (rule_qual != NULL)
- new_qual = (Node *) copyObject(rule_qual);
- if (rule_action != NULL)
- {
- List *rtable;
- int rt_length;
- List *jointreelist;
-
- rtable = new_tree->rtable;
- rt_length = length(rtable);
- rtable = nconc(rtable, copyObject(rule_action->rtable));
- new_tree->rtable = rtable;
- OffsetVarNodes(new_qual, rt_length, 0);
- ChangeVarNodes(new_qual, PRS2_OLD_VARNO + rt_length, rt_index, 0);
- jointreelist = copyObject(rule_action->jointree->fromlist);
- OffsetVarNodes((Node *) jointreelist, rt_length, 0);
- ChangeVarNodes((Node *) jointreelist, PRS2_OLD_VARNO + rt_length,
- rt_index, 0);
- new_tree->jointree->fromlist = nconc(new_tree->jointree->fromlist,
- jointreelist);
- }
- /* XXX -- where current doesn't work for instead nothing.... yet */
+ Node *new_qual = (Node *) copyObject(rule_qual);
+
+ /* Fix references to OLD */
+ ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
+ /* Fix references to NEW */
+ if (event == CMD_INSERT || event == CMD_UPDATE)
+ new_qual = ResolveNew(new_qual,
+ PRS2_NEW_VARNO,
+ 0,
+ parsetree->targetList,
+ event,
+ rt_index);
+ /* And attach the fixed qual */
AddNotQual(new_tree, new_qual);
return new_tree;
@@ -598,7 +645,6 @@ fireRules(Query *parsetree,
List *locks,
List **qual_products)
{
- RewriteInfo *info;
List *results = NIL;
List *i;
@@ -623,7 +669,6 @@ fireRules(Query *parsetree,
if (event_qual != NULL && *instead_flag)
{
Query *qual_product;
- RewriteInfo qual_info;
/* ----------
* If there are instead rules with qualifications,
@@ -642,60 +687,23 @@ fireRules(Query *parsetree,
else
qual_product = (Query *) lfirst(*qual_products);
- MemSet(&qual_info, 0, sizeof(qual_info));
- qual_info.event = qual_product->commandType;
- qual_info.current_varno = rt_index;
- qual_info.new_varno = length(qual_product->rtable) + 2;
-
qual_product = CopyAndAddQual(qual_product,
- actions,
event_qual,
rt_index,
event);
- qual_info.rule_action = qual_product;
-
- if (event == CMD_INSERT || event == CMD_UPDATE)
- FixNew(&qual_info, qual_product);
-
*qual_products = makeList1(qual_product);
}
foreach(r, actions)
{
Query *rule_action = lfirst(r);
- Node *rule_qual = copyObject(event_qual);
+ RewriteInfo *info;
if (rule_action->commandType == CMD_NOTHING)
continue;
- /*--------------------------------------------------
- * We copy the qualifications of the parsetree
- * to the action and vice versa. So force
- * hasSubLinks if one of them has it.
- *
- * As of 6.4 only parsetree qualifications can
- * have sublinks. If this changes, we must make
- * this a node lookup at the end of rewriting.
- *
- * Jan
- *--------------------------------------------------
- */
- if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
- {
- rule_action = copyObject(rule_action);
- rule_action->hasSubLinks = TRUE;
- }
- if (!parsetree->hasSubLinks && rule_action->hasSubLinks)
- parsetree->hasSubLinks = TRUE;
-
- /*--------------------------------------------------
- * Step 1:
- * Rewrite current.attribute or current to tuple variable
- * this appears to be done in parser?
- *--------------------------------------------------
- */
- info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
+ info = gatherRewriteMeta(parsetree, rule_action, event_qual,
rt_index, event, *instead_flag);
/* handle escapable cases, or those handled by other code */
@@ -707,34 +715,6 @@ fireRules(Query *parsetree,
continue;
}
- if (info->action == info->event &&
- info->event == CMD_SELECT)
- continue;
-
- /*
- * Event Qualification forces copying of parsetree and
- * splitting into two queries one w/rule_qual, one w/NOT
- * rule_qual. Also add user query qual onto rule action
- */
- AddQual(info->rule_action, info->rule_qual);
-
- AddQual(info->rule_action, parsetree->jointree->quals);
-
- /*--------------------------------------------------
- * Step 2:
- * Rewrite new.attribute w/ right hand side of target-list
- * entry for appropriate field name in insert/update
- *--------------------------------------------------
- */
- if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE))
- FixNew(info, parsetree);
-
- /*--------------------------------------------------
- * Step 3:
- * Simplify? hey, no algorithm for simplification... let
- * the planner do it.
- *--------------------------------------------------
- */
results = lappend(results, info->rule_action);
pfree(info);