Repair problem with multi-action rules in combination with any nontrivial
authorTom Lane
Tue, 12 Jun 2001 18:54:22 +0000 (18:54 +0000)
committerTom Lane
Tue, 12 Jun 2001 18:54:22 +0000 (18:54 +0000)
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.

src/backend/rewrite/rewriteHandler.c

index 2787b9ce553e9a51f72a59c4f2dac687d882632e..d78334d83d3cfa7f47997d0eb9a4686eefa8a84b 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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,
 
    /*
     * 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
     * will be in the SELECT part, and we have to modify that rather than
@@ -99,23 +99,19 @@ gatherRewriteMeta(Query *parsetree,
                   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.
+    * Generate expanded rtable consisting of main parsetree's rtable
+    * plus rule action's rtable; this becomes the complete rtable for the
+    * rule action.  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.
+    * NOTE: because planner will destructively alter rtable, we must ensure
+    * that rule action's rtable is separate and shares no substructure with
+    * the main rtable.  Hence do a deep copy here.
     */
-   parsetree->rtable = nconc(parsetree->rtable,
-                             sub_action->rtable);
-   sub_action->rtable = parsetree->rtable;
+   sub_action->rtable = nconc((List *) copyObject(parsetree->rtable),
+                              sub_action->rtable);
 
    /*
     * Each rule action's jointree should be the main parsetree's jointree
@@ -128,6 +124,9 @@ gatherRewriteMeta(Query *parsetree,
     * data for the quals.  We don't want the original rtindex to be
     * joined twice, however, so avoid keeping it if the rule action
     * mentions it.
+    *
+    * As above, the action's jointree must not share substructure with
+    * the main parsetree's.
     */
    if (sub_action->jointree != NULL)
    {
@@ -193,13 +192,13 @@ gatherRewriteMeta(Query *parsetree,
  * 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
  * 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
- * changed.
+ * of the join).  Returns modified jointree list --- this is a separate copy
+ * sharing no nodes with the original.
  */
 static List *
 adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
 {
-   List       *newjointree = listCopy(parsetree->jointree->fromlist);
+   List       *newjointree = copyObject(parsetree->jointree->fromlist);
    List       *jjt;
 
    if (removert)