diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-01 18:50:42 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-01 18:50:42 +0000 |
commit | 3b14809f9281bf258c281f6ebcc8b6b7b408a467 (patch) | |
tree | 31066cb4b6797a331231437b5cd25b23e6a94d5c | |
parent | e9a97570fadeb79d5a21086399bdf5b48d924b17 (diff) | |
download | postgresql-3b14809f9281bf258c281f6ebcc8b6b7b408a467.tar.gz postgresql-3b14809f9281bf258c281f6ebcc8b6b7b408a467.zip |
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.c | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 969188acdb7..bf244b7e63a 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 - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.158.2.2 2005/11/23 17:21:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.158.2.3 2007/03/01 18:50:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,8 +52,8 @@ static TargetEntry *process_matched_tle(TargetEntry *src_tle, TargetEntry *prior_tle, const char *attrName); static Node *get_assignment_input(Node *node); -static void markQueryForLocking(Query *qry, bool forUpdate, bool noWait, - bool skipOldNew); +static void markQueryForLocking(Query *qry, Node *jtnode, + bool forUpdate, bool noWait); static List *matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree); static Query *fireRIRrules(Query *parsetree, List *activeRIRs); @@ -966,8 +966,8 @@ ApplyRetrieveRule(Query *parsetree, /* * Set up the view's referenced tables as if FOR UPDATE/SHARE. */ - markQueryForLocking(rule_action, parsetree->forUpdate, - parsetree->rowNoWait, true); + markQueryForLocking(rule_action, (Node *) rule_action->jointree, + parsetree->forUpdate, parsetree->rowNoWait); } return parsetree; @@ -979,14 +979,15 @@ ApplyRetrieveRule(Query *parsetree, * 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 transformLocking() routine. + * NB: this must agree with the parser's transformLockingClause() 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 -markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew) +markQueryForLocking(Query *qry, Node *jtnode, bool forUpdate, bool noWait) { - Index rti = 0; - ListCell *l; - + /* when recursing, this check is redundant; cheap enough not to worry */ if (qry->rowMarks) { if (forUpdate != qry->forUpdate) @@ -1001,16 +1002,12 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew) qry->forUpdate = forUpdate; qry->rowNoWait = noWait; - 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) { @@ -1020,9 +1017,28 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew) else if (rte->rtekind == RTE_SUBQUERY) { /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */ - markQueryForLocking(rte->subquery, forUpdate, noWait, false); + markQueryForLocking(rte->subquery, (Node *) rte->subquery->jointree, + forUpdate, noWait); } } + else if (IsA(jtnode, FromExpr)) + { + FromExpr *f = (FromExpr *) jtnode; + ListCell *l; + + foreach(l, f->fromlist) + markQueryForLocking(qry, lfirst(l), forUpdate, noWait); + } + else if (IsA(jtnode, JoinExpr)) + { + JoinExpr *j = (JoinExpr *) jtnode; + + markQueryForLocking(qry, j->larg, forUpdate, noWait); + markQueryForLocking(qry, j->rarg, forUpdate, noWait); + } + else + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(jtnode)); } |