Commit 2a06b3bd authored by Tom Lane's avatar Tom Lane

Repair problem with multi-action rules in combination with any nontrivial

manipulation of rtable/jointree by planner.  Rewriter was generating
actions that shared rtable/jointree substructure, which caused havoc
when planner got to the later actions that it'd already mucked up.
parent c1db506a
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.93 2001/05/03 17:47:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.94 2001/06/12 18:54:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -82,7 +82,7 @@ gatherRewriteMeta(Query *parsetree, ...@@ -82,7 +82,7 @@ gatherRewriteMeta(Query *parsetree,
/* /*
* Adjust rule action and qual to offset its varnos, so that we can * Adjust rule action and qual to offset its varnos, so that we can
* merge its rtable into the main parsetree's rtable. * merge its rtable with the main parsetree's rtable.
* *
* If the rule action is an INSERT...SELECT, the OLD/NEW rtable entries * 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 * will be in the SELECT part, and we have to modify that rather than
...@@ -99,23 +99,19 @@ gatherRewriteMeta(Query *parsetree, ...@@ -99,23 +99,19 @@ gatherRewriteMeta(Query *parsetree,
PRS2_OLD_VARNO + rt_length, rt_index, 0); PRS2_OLD_VARNO + rt_length, rt_index, 0);
/* /*
* We want the main parsetree's rtable to end up as the concatenation * Generate expanded rtable consisting of main parsetree's rtable
* of its original contents plus those of all the relevant rule * plus rule action's rtable; this becomes the complete rtable for the
* actions. Also store same into all the rule_action rtables. Some of * rule action. Some of the entries may be unused after we finish
* the entries may be unused after we finish rewriting, but if we * rewriting, but if we tried to clean those out we'd have a much harder
* tried to clean those out we'd have a much harder job to adjust RT * job to adjust RT indexes in the query's Vars. It's OK to have unused
* indexes in the query's Vars. It's OK to have unused RT entries, * RT entries, since planner will ignore them.
* since planner will ignore them.
* *
* NOTE KLUGY HACK: we assume the parsetree rtable had at least one entry * NOTE: because planner will destructively alter rtable, we must ensure
* to begin with (OK enough, else where'd the rule come from?). * that rule action's rtable is separate and shares no substructure with
* Because of this, if multiple rules nconc() their rtable additions * the main rtable. Hence do a deep copy here.
* 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 = nconc((List *) copyObject(parsetree->rtable),
sub_action->rtable); sub_action->rtable);
sub_action->rtable = parsetree->rtable;
/* /*
* Each rule action's jointree should be the main parsetree's jointree * Each rule action's jointree should be the main parsetree's jointree
...@@ -128,6 +124,9 @@ gatherRewriteMeta(Query *parsetree, ...@@ -128,6 +124,9 @@ gatherRewriteMeta(Query *parsetree,
* data for the quals. We don't want the original rtindex to be * data for the quals. We don't want the original rtindex to be
* joined twice, however, so avoid keeping it if the rule action * joined twice, however, so avoid keeping it if the rule action
* mentions it. * mentions it.
*
* As above, the action's jointree must not share substructure with
* the main parsetree's.
*/ */
if (sub_action->jointree != NULL) if (sub_action->jointree != NULL)
{ {
...@@ -193,13 +192,13 @@ gatherRewriteMeta(Query *parsetree, ...@@ -193,13 +192,13 @@ gatherRewriteMeta(Query *parsetree,
* occurrence of the given rt_index as a top-level join item (we do not look * occurrence of the given rt_index as a top-level join item (we do not look
* for it within join items; this is OK because we are only expecting to find * for it within join items; this is OK because we are only expecting to find
* it as an UPDATE or DELETE target relation, which will be at the top level * it as an UPDATE or DELETE target relation, which will be at the top level
* of the join). Returns modified jointree list --- original list is not * of the join). Returns modified jointree list --- this is a separate copy
* changed. * sharing no nodes with the original.
*/ */
static List * static List *
adjustJoinTreeList(Query *parsetree, bool removert, int rt_index) adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
{ {
List *newjointree = listCopy(parsetree->jointree->fromlist); List *newjointree = copyObject(parsetree->jointree->fromlist);
List *jjt; List *jjt;
if (removert) if (removert)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment