summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-03-01 18:51:03 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-03-01 18:51:03 +0000
commit4edaffa1d13057427eaec95d8eadb4a5c375debd (patch)
treea4bd59ec457d9c2d451a55c14c67844eaa81f25b
parent2c47aaa0b6775bed84e12cc69948817e31f79db5 (diff)
Fix markQueryForLocking() to work correctly in the presence of nested views.
It has been wrong for this case since it was first written for 7.1 :-( Per report from Pavel HanĂ¡k.
-rw-r--r--src/backend/rewrite/rewriteHandler.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index eed72700776..0ec803230e7 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -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.113.2.2 2004/01/14 03:39:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.113.2.3 2007/03/01 18:51:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,7 +42,7 @@ static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static void rewriteTargetList(Query *parsetree, Relation target_relation);
static TargetEntry *process_matched_tle(TargetEntry *src_tle,
TargetEntry *prior_tle);
-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);
@@ -604,7 +604,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;
@@ -617,23 +617,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)
{
@@ -644,9 +640,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));
}