Commit cba2d271 authored by Tom Lane's avatar Tom Lane

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.
parent 7b76bfbe
...@@ -7,7 +7,7 @@ ...@@ -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.170 2007/02/01 19:10:27 momjian Exp $ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.171 2007/03/01 18:50:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -50,8 +50,8 @@ static TargetEntry *process_matched_tle(TargetEntry *src_tle, ...@@ -50,8 +50,8 @@ static TargetEntry *process_matched_tle(TargetEntry *src_tle,
static Node *get_assignment_input(Node *node); static Node *get_assignment_input(Node *node);
static void rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, static void rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation,
List *attrnos); List *attrnos);
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);
...@@ -1122,8 +1122,8 @@ ApplyRetrieveRule(Query *parsetree, ...@@ -1122,8 +1122,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, rc->forUpdate, markQueryForLocking(rule_action, (Node *) rule_action->jointree,
rc->noWait, true); rc->forUpdate, rc->noWait);
} }
return parsetree; return parsetree;
...@@ -1135,24 +1135,20 @@ ApplyRetrieveRule(Query *parsetree, ...@@ -1135,24 +1135,20 @@ 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; if (jtnode == NULL)
ListCell *l; return;
if (IsA(jtnode, RangeTblRef))
foreach(l, qry->rtable)
{ {
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)
{ {
...@@ -1162,9 +1158,28 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew) ...@@ -1162,9 +1158,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));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment