From: Tom Lane Date: Thu, 1 Mar 2007 18:51:03 +0000 (+0000) Subject: Fix markQueryForLocking() to work correctly in the presence of nested views. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=5e67cf4513848df45173313fec296fd5c4d96248;p=users%2Fbernd%2Fpostgres.git 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. --- diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 0cc4fc99c2..2bc345abde 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -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)); }