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,
3838CmdType event ,
3939bool instead_flag );
4040static List * adjustJoinTreeList (Query * parsetree ,int rt_index ,bool * found );
41+ static void markQueryForUpdate (Query * qry ,bool skipOldNew );
4142static List * matchLocks (CmdType event ,RuleLock * rulelocks ,
4243int varno ,Query * parsetree );
4344static Query * fireRIRrules (Query * parsetree );
@@ -263,7 +264,6 @@ ApplyRetrieveRule(Query *parsetree,
263264Query * rule_action ;
264265RangeTblEntry * rte ,
265266* subrte ;
266- List * l ;
267267
268268if (length (rule -> actions )!= 1 )
269269elog (ERROR ,"ApplyRetrieveRule: expected just one rule action" );
@@ -308,8 +308,6 @@ ApplyRetrieveRule(Query *parsetree,
308308 */
309309if (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
343324return 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 -