1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-09 17:03:00 +03:00

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.
This commit is contained in:
Tom Lane
2007-03-01 18:51:03 +00:00
parent 2c47aaa0b6
commit 4edaffa1d1

View 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.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));
}