Fix more problems with rewriter failing to set Query.hasSubLinks when inserting
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 24 Sep 2008 16:52:46 +0000 (16:52 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 24 Sep 2008 16:52:46 +0000 (16:52 +0000)
a SubLink expression into a rule query.  We missed cases where the original
query contained a sub-SELECT in a function in FROM, a multi-row VALUES list,
or a RETURNING list.  Per bug #4434 from Dean Rasheed and subsequent
investigation.

Back-patch to 8.1; older releases don't have the issue because they didn't
try to be smart about setting hasSubLinks only when needed.

src/backend/rewrite/rewriteHandler.c

index a6e01a8b1c2403eee9238772799df596f6cf19c6..305b91202ad14138398ad157491def7ec8eb8091 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.179 2008/08/28 23:09:48 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.180 2008/09/24 16:52:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -346,6 +346,37 @@ rewriteRuleAction(Query *parsetree,
    sub_action->rtable = list_concat((List *) copyObject(parsetree->rtable),
                                     sub_action->rtable);
 
+   /*
+    * There could have been some SubLinks in parsetree's rtable, in which
+    * case we'd better mark the sub_action correctly.
+    */
+   if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
+   {
+       ListCell   *lc;
+
+       foreach(lc, parsetree->rtable)
+       {
+           RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+
+           switch (rte->rtekind)
+           {
+               case RTE_FUNCTION:
+                   sub_action->hasSubLinks =
+                       checkExprHasSubLink(rte->funcexpr);
+                   break;
+               case RTE_VALUES:
+                   sub_action->hasSubLinks =
+                       checkExprHasSubLink((Node *) rte->values_lists);
+                   break;
+               default:
+                   /* other RTE types don't contain bare expressions */
+                   break;
+           }
+           if (sub_action->hasSubLinks)
+               break;      /* no need to keep scanning rtable */
+       }
+   }
+
    /*
     * Each rule action's jointree should be the main parsetree's jointree
     * plus that rule's jointree, but usually *without* the original rtindex
@@ -455,6 +486,14 @@ rewriteRuleAction(Query *parsetree,
                       rule_action->returningList,
                       CMD_SELECT,
                       0);
+
+       /*
+        * There could have been some SubLinks in parsetree's returningList,
+        * in which case we'd better mark the rule_action correctly.
+        */
+       if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
+           rule_action->hasSubLinks =
+                   checkExprHasSubLink((Node *) rule_action->returningList);
    }
 
    return rule_action;