mirror of
https://github.com/postgres/postgres.git
synced 2025-05-17 06:41:24 +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:
parent
b128f53343
commit
88d482cf86
@ -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.130.2.1 2004/01/14 03:39:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.130.2.2 2007/03/01 18:50:56 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -50,7 +50,7 @@ static void rewriteTargetList(Query *parsetree, Relation target_relation);
|
||||
static TargetEntry *process_matched_tle(TargetEntry *src_tle,
|
||||
TargetEntry *prior_tle,
|
||||
const char *attrName);
|
||||
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, List *activeRIRs);
|
||||
@ -678,7 +678,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;
|
||||
@ -691,23 +691,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)
|
||||
{
|
||||
@ -718,9 +714,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));
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user