]> granicus.if.org Git - postgresql/commitdiff
Make application of FOR UPDATE to a view work exactly like the parser's
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Dec 2000 01:22:25 +0000 (01:22 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 7 Dec 2000 01:22:25 +0000 (01:22 +0000)
transformForUpdate does: it should recurse into subqueries.

src/backend/rewrite/rewriteHandler.c

index 21372e0794df0c407728b8552e9c2811668184fa..753475aa820889eb877d16b16a2f2cb13b4f58cb 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.85 2000/12/06 23:55:18 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.86 2000/12/07 01:22:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,7 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree,
                                  CmdType event,
                                  bool instead_flag);
 static List *adjustJoinTreeList(Query *parsetree, int rt_index, bool *found);
+static void markQueryForUpdate(Query *qry, bool skipOldNew);
 static List *matchLocks(CmdType event, RuleLock *rulelocks,
                                                int varno, Query *parsetree);
 static Query *fireRIRrules(Query *parsetree);
@@ -263,7 +264,6 @@ ApplyRetrieveRule(Query *parsetree,
        Query      *rule_action;
        RangeTblEntry *rte,
                           *subrte;
-       List       *l;
 
        if (length(rule->actions) != 1)
                elog(ERROR, "ApplyRetrieveRule: expected just one rule action");
@@ -308,8 +308,6 @@ ApplyRetrieveRule(Query *parsetree,
         */
        if (intMember(rt_index, parsetree->rowMarks))
        {
-               Index           innerrti = 1;
-
                /*
                 * Remove the view from the list of rels that will actually be
                 * marked FOR UPDATE by the executor.  It will still be access-
@@ -320,29 +318,51 @@ ApplyRetrieveRule(Query *parsetree,
                /*
                 * Set up the view's referenced tables as if FOR UPDATE.
                 */
-               foreach(l, rule_action->rtable)
-               {
-                       subrte = (RangeTblEntry *) lfirst(l);
-
-                       /*
-                        * RTable of VIEW has two entries of VIEW itself - skip them!
-                        * Also keep hands off of sub-subqueries.
-                        */
-                       if (innerrti != PRS2_OLD_VARNO && innerrti != PRS2_NEW_VARNO &&
-                               subrte->relid != InvalidOid)
-                       {
-                               if (!intMember(innerrti, rule_action->rowMarks))
-                                       rule_action->rowMarks = lappendi(rule_action->rowMarks,
-                                                                                                        innerrti);
-                               subrte->checkForWrite = true;
-                       }
-                       innerrti++;
-               }
+               markQueryForUpdate(rule_action, true);
        }
 
        return parsetree;
 }
 
+/*
+ * Recursively mark all relations used by a view as FOR UPDATE.
+ *
+ * This may generate an invalid query, eg if some sub-query uses an
+ * aggregate.  We leave it to the planner to detect that.
+ *
+ * NB: this must agree with the parser's transformForUpdate() routine.
+ */
+static void
+markQueryForUpdate(Query *qry, bool skipOldNew)
+{
+       Index           rti = 0;
+       List       *l;
+
+       foreach(l, qry->rtable)
+       {
+               RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+
+               rti++;
+
+               /* Ignore OLD and NEW entries if we are at top level of view */
+               if (skipOldNew &&
+                       (rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO))
+                       continue;
+
+               if (rte->subquery)
+               {
+                       /* FOR UPDATE of subquery is propagated to subquery's rels */
+                       markQueryForUpdate(rte->subquery, false);
+               }
+               else
+               {
+                       if (!intMember(rti, qry->rowMarks))
+                               qry->rowMarks = lappendi(qry->rowMarks, rti);
+                       rte->checkForWrite = true;
+               }
+       }
+}
+
 
 /*
  * fireRIRonSubLink -