Skip to content

Commit 7711e40

Browse files
committed
Make application of FOR UPDATE to a view work exactly like the parser's
transformForUpdate does: it should recurse into subqueries.
1 parent 0a844e8 commit 7711e40

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

src/backend/rewrite/rewriteHandler.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.85 2000/12/06 23:55:18 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.86 2000/12/07 01:22:25 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -38,6 +38,7 @@ static RewriteInfo *gatherRewriteMeta(Query *parsetree,
3838
CmdType event,
3939
bool instead_flag);
4040
static List *adjustJoinTreeList(Query *parsetree, int rt_index, bool *found);
41+
static void markQueryForUpdate(Query *qry, bool skipOldNew);
4142
static List *matchLocks(CmdType event, RuleLock *rulelocks,
4243
int varno, Query *parsetree);
4344
static Query *fireRIRrules(Query *parsetree);
@@ -263,7 +264,6 @@ ApplyRetrieveRule(Query *parsetree,
263264
Query *rule_action;
264265
RangeTblEntry *rte,
265266
*subrte;
266-
List *l;
267267

268268
if (length(rule->actions) != 1)
269269
elog(ERROR, "ApplyRetrieveRule: expected just one rule action");
@@ -308,8 +308,6 @@ ApplyRetrieveRule(Query *parsetree,
308308
*/
309309
if (intMember(rt_index, parsetree->rowMarks))
310310
{
311-
Index innerrti = 1;
312-
313311
/*
314312
* Remove the view from the list of rels that will actually be
315313
* marked FOR UPDATE by the executor. It will still be access-
@@ -320,29 +318,51 @@ ApplyRetrieveRule(Query *parsetree,
320318
/*
321319
* Set up the view's referenced tables as if FOR UPDATE.
322320
*/
323-
foreach(l, rule_action->rtable)
324-
{
325-
subrte = (RangeTblEntry *) lfirst(l);
326-
327-
/*
328-
* RTable of VIEW has two entries of VIEW itself - skip them!
329-
* Also keep hands off of sub-subqueries.
330-
*/
331-
if (innerrti != PRS2_OLD_VARNO && innerrti != PRS2_NEW_VARNO &&
332-
subrte->relid != InvalidOid)
333-
{
334-
if (!intMember(innerrti, rule_action->rowMarks))
335-
rule_action->rowMarks = lappendi(rule_action->rowMarks,
336-
innerrti);
337-
subrte->checkForWrite = true;
338-
}
339-
innerrti++;
340-
}
321+
markQueryForUpdate(rule_action, true);
341322
}
342323

343324
return parsetree;
344325
}
345326

327+
/*
328+
* Recursively mark all relations used by a view as FOR UPDATE.
329+
*
330+
* This may generate an invalid query, eg if some sub-query uses an
331+
* aggregate. We leave it to the planner to detect that.
332+
*
333+
* NB: this must agree with the parser's transformForUpdate() routine.
334+
*/
335+
static void
336+
markQueryForUpdate(Query *qry, bool skipOldNew)
337+
{
338+
Index rti = 0;
339+
List *l;
340+
341+
foreach(l, qry->rtable)
342+
{
343+
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
344+
345+
rti++;
346+
347+
/* Ignore OLD and NEW entries if we are at top level of view */
348+
if (skipOldNew &&
349+
(rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO))
350+
continue;
351+
352+
if (rte->subquery)
353+
{
354+
/* FOR UPDATE of subquery is propagated to subquery's rels */
355+
markQueryForUpdate(rte->subquery, false);
356+
}
357+
else
358+
{
359+
if (!intMember(rti, qry->rowMarks))
360+
qry->rowMarks = lappendi(qry->rowMarks, rti);
361+
rte->checkForWrite = true;
362+
}
363+
}
364+
}
365+
346366

347367
/*
348368
* fireRIRonSubLink -

0 commit comments

Comments
 (0)