1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-03 01:21:48 +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:50:42 +00:00
parent e9a97570fa
commit 3b14809f92

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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, TargetEntry *prior_tle,
const char *attrName); const char *attrName);
static Node *get_assignment_input(Node *node); static Node *get_assignment_input(Node *node);
static void markQueryForLocking(Query *qry, bool forUpdate, bool noWait, static void markQueryForLocking(Query *qry, Node *jtnode,
bool skipOldNew); bool forUpdate, bool noWait);
static List *matchLocks(CmdType event, RuleLock *rulelocks, static List *matchLocks(CmdType event, RuleLock *rulelocks,
int varno, Query *parsetree); int varno, Query *parsetree);
static Query *fireRIRrules(Query *parsetree, List *activeRIRs); 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. * Set up the view's referenced tables as if FOR UPDATE/SHARE.
*/ */
markQueryForLocking(rule_action, parsetree->forUpdate, markQueryForLocking(rule_action, (Node *) rule_action->jointree,
parsetree->rowNoWait, true); parsetree->forUpdate, parsetree->rowNoWait);
} }
return parsetree; return parsetree;
@ -979,14 +979,15 @@ ApplyRetrieveRule(Query *parsetree,
* This may generate an invalid query, eg if some sub-query uses an * This may generate an invalid query, eg if some sub-query uses an
* aggregate. We leave it to the planner to detect that. * 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 static void
markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew) markQueryForLocking(Query *qry, Node *jtnode, bool forUpdate, bool noWait)
{ {
Index rti = 0; /* when recursing, this check is redundant; cheap enough not to worry */
ListCell *l;
if (qry->rowMarks) if (qry->rowMarks)
{ {
if (forUpdate != qry->forUpdate) if (forUpdate != qry->forUpdate)
@ -1001,16 +1002,12 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
qry->forUpdate = forUpdate; qry->forUpdate = forUpdate;
qry->rowNoWait = noWait; qry->rowNoWait = noWait;
foreach(l, qry->rtable) if (jtnode == NULL)
return;
if (IsA(jtnode, RangeTblRef))
{ {
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); int rti = ((RangeTblRef *) jtnode)->rtindex;
RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
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;
if (rte->rtekind == RTE_RELATION) if (rte->rtekind == RTE_RELATION)
{ {
@ -1020,9 +1017,28 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
else if (rte->rtekind == RTE_SUBQUERY) else if (rte->rtekind == RTE_SUBQUERY)
{ {
/* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */ /* 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));
} }