]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix markQueryForLocking() to work correctly in the presence of nested views.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 1 Mar 2007 18:50:56 +0000 (18:50 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 1 Mar 2007 18:50:56 +0000 (18:50 +0000)
It has been wrong for this case since it was first written for 7.1 :-(
Per report from Pavel HanĂ¡k.

src/backend/rewrite/rewriteHandler.c

index df8d8b0ed5731c7fd62a3d26a7c475adde979aac..6aa27dbc306be0d016c2e1cecc8e733f06daab23 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.130.2.1 2004/01/14 03:39:29 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.130.2.2 2007/03/01 18:50:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ static void rewriteTargetList(Query *parsetree, Relation target_relation);
 static TargetEntry *process_matched_tle(TargetEntry *src_tle,
                                                                                TargetEntry *prior_tle,
                                                                                const char *attrName);
-static void markQueryForUpdate(Query *qry, bool skipOldNew);
+static void markQueryForUpdate(Query *qry, Node *jtnode);
 static List *matchLocks(CmdType event, RuleLock *rulelocks,
                   int varno, Query *parsetree);
 static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
@@ -678,7 +678,7 @@ ApplyRetrieveRule(Query *parsetree,
                /*
                 * Set up the view's referenced tables as if FOR UPDATE.
                 */
-               markQueryForUpdate(rule_action, true);
+               markQueryForUpdate(rule_action, (Node *) rule_action->jointree);
        }
 
        return parsetree;
@@ -691,23 +691,19 @@ ApplyRetrieveRule(Query *parsetree,
  * aggregate.  We leave it to the planner to detect that.
  *
  * NB: this must agree with the parser's transformForUpdate() routine.
+ * However, unlike the parser we have to be careful not to mark a view's
+ * OLD and NEW rels for updating.  The best way to handle that seems to be
+ * to scan the jointree to determine which rels are used.
  */
 static void
-markQueryForUpdate(Query *qry, bool skipOldNew)
+markQueryForUpdate(Query *qry, Node *jtnode)
 {
-       Index           rti = 0;
-       List       *l;
-
-       foreach(l, qry->rtable)
+       if (jtnode == NULL)
+               return;
+       if (IsA(jtnode, RangeTblRef))
        {
-               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;
+               int                     rti = ((RangeTblRef *) jtnode)->rtindex;
+               RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
 
                if (rte->rtekind == RTE_RELATION)
                {
@@ -718,9 +714,27 @@ markQueryForUpdate(Query *qry, bool skipOldNew)
                else if (rte->rtekind == RTE_SUBQUERY)
                {
                        /* FOR UPDATE of subquery is propagated to subquery's rels */
-                       markQueryForUpdate(rte->subquery, false);
+                       markQueryForUpdate(rte->subquery, (Node *) rte->subquery->jointree);
                }
        }
+       else if (IsA(jtnode, FromExpr))
+       {
+               FromExpr   *f = (FromExpr *) jtnode;
+               List       *l;
+
+               foreach(l, f->fromlist)
+                       markQueryForUpdate(qry, lfirst(l));
+       }
+       else if (IsA(jtnode, JoinExpr))
+       {
+               JoinExpr   *j = (JoinExpr *) jtnode;
+
+               markQueryForUpdate(qry, j->larg);
+               markQueryForUpdate(qry, j->rarg);
+       }
+       else
+               elog(ERROR, "unrecognized node type: %d",
+                        (int) nodeTag(jtnode));
 }