77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.190 2009/10/2814:55:43 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.191 2009/10/2817:36:50 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -55,7 +55,8 @@ static void markQueryForLocking(Query *qry, Node *jtnode,
5555bool forUpdate ,bool noWait ,bool pushedDown );
5656static List * matchLocks (CmdType event ,RuleLock * rulelocks ,
5757int varno ,Query * parsetree );
58- static Query * fireRIRrules (Query * parsetree ,List * activeRIRs );
58+ static Query * fireRIRrules (Query * parsetree ,List * activeRIRs ,
59+ bool forUpdatePushedDown );
5960
6061
6162/*
@@ -64,6 +65,10 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
6465 * These locks will ensure that the relation schemas don't change under us
6566 * while we are rewriting and planning the query.
6667 *
68+ * forUpdatePushedDown indicates that a pushed-down FOR UPDATE/SHARE applies
69+ * to the current subquery, requiring all rels to be opened with RowShareLock.
70+ * This should always be false at the start of the recursion.
71+ *
6772 * A secondary purpose of this routine is to fix up JOIN RTE references to
6873 * dropped columns (see details below). Because the RTEs are modified in
6974 * place, it is generally appropriate for the caller of this routine to have
@@ -91,7 +96,7 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
9196 * construction of a nested join was O(N^2) in the nesting depth.)
9297 */
9398void
94- AcquireRewriteLocks (Query * parsetree )
99+ AcquireRewriteLocks (Query * parsetree , bool forUpdatePushedDown )
95100{
96101ListCell * l ;
97102int rt_index ;
@@ -129,7 +134,8 @@ AcquireRewriteLocks(Query *parsetree)
129134 */
130135if (rt_index == parsetree -> resultRelation )
131136lockmode = RowExclusiveLock ;
132- else if (get_parse_rowmark (parsetree ,rt_index )!= NULL )
137+ else if (forUpdatePushedDown ||
138+ get_parse_rowmark (parsetree ,rt_index )!= NULL )
133139lockmode = RowShareLock ;
134140else
135141lockmode = AccessShareLock ;
@@ -206,7 +212,9 @@ AcquireRewriteLocks(Query *parsetree)
206212 * The subquery RTE itself is all right, but we have to
207213 * recurse to process the represented subquery.
208214 */
209- AcquireRewriteLocks (rte -> subquery );
215+ AcquireRewriteLocks (rte -> subquery ,
216+ (forUpdatePushedDown ||
217+ get_parse_rowmark (parsetree ,rt_index )!= NULL ));
210218break ;
211219
212220default :
@@ -220,7 +228,7 @@ AcquireRewriteLocks(Query *parsetree)
220228{
221229CommonTableExpr * cte = (CommonTableExpr * )lfirst (l );
222230
223- AcquireRewriteLocks ((Query * )cte -> ctequery );
231+ AcquireRewriteLocks ((Query * )cte -> ctequery , false );
224232}
225233
226234/*
@@ -245,7 +253,7 @@ acquireLocksOnSubLinks(Node *node, void *context)
245253SubLink * sub = (SubLink * )node ;
246254
247255/* Do what we came for */
248- AcquireRewriteLocks ((Query * )sub -> subselect );
256+ AcquireRewriteLocks ((Query * )sub -> subselect , false );
249257/* Fall through to process lefthand args of SubLink */
250258}
251259
@@ -298,7 +306,7 @@ rewriteRuleAction(Query *parsetree,
298306/*
299307 * Acquire necessary locks and fix any deleted JOIN RTE entries.
300308 */
301- AcquireRewriteLocks (rule_action );
309+ AcquireRewriteLocks (rule_action , false );
302310(void )acquireLocksOnSubLinks (rule_qual ,NULL );
303311
304312current_varno = rt_index ;
@@ -1134,7 +1142,8 @@ ApplyRetrieveRule(Query *parsetree,
11341142int rt_index ,
11351143bool relation_level ,
11361144Relation relation ,
1137- List * activeRIRs )
1145+ List * activeRIRs ,
1146+ bool forUpdatePushedDown )
11381147{
11391148Query * rule_action ;
11401149RangeTblEntry * rte ,
@@ -1148,18 +1157,25 @@ ApplyRetrieveRule(Query *parsetree,
11481157if (!relation_level )
11491158elog (ERROR ,"cannot handle per-attribute ON SELECT rule" );
11501159
1160+ /*
1161+ * If FOR UPDATE/SHARE of view, be sure we get right initial lock on the
1162+ * relations it references.
1163+ */
1164+ rc = get_parse_rowmark (parsetree ,rt_index );
1165+ forUpdatePushedDown |= (rc != NULL );
1166+
11511167/*
11521168 * Make a modifiable copy of the view query, and acquire needed locks on
11531169 * the relations it mentions.
11541170 */
11551171rule_action = copyObject (linitial (rule -> actions ));
11561172
1157- AcquireRewriteLocks (rule_action );
1173+ AcquireRewriteLocks (rule_action , forUpdatePushedDown );
11581174
11591175/*
11601176 * Recursively expand any view references inside the view.
11611177 */
1162- rule_action = fireRIRrules (rule_action ,activeRIRs );
1178+ rule_action = fireRIRrules (rule_action ,activeRIRs , forUpdatePushedDown );
11631179
11641180/*
11651181 * VIEWs are really easy --- just plug the view query in as a subselect,
@@ -1192,8 +1208,11 @@ ApplyRetrieveRule(Query *parsetree,
11921208 * If FOR UPDATE/SHARE of view, mark all the contained tables as
11931209 * implicit FOR UPDATE/SHARE, the same as the parser would have done
11941210 * if the view's subquery had been written out explicitly.
1211+ *
1212+ * Note: we don't consider forUpdatePushedDown here; such marks will be
1213+ * made by recursing from the upper level in markQueryForLocking.
11951214 */
1196- if (( rc = get_parse_rowmark ( parsetree , rt_index )) != NULL )
1215+ if (rc != NULL )
11971216markQueryForLocking (rule_action , (Node * )rule_action -> jointree ,
11981217rc -> forUpdate ,rc -> noWait , true);
11991218
@@ -1281,7 +1300,7 @@ fireRIRonSubLink(Node *node, List *activeRIRs)
12811300
12821301/* Do what we came for */
12831302sub -> subselect = (Node * )fireRIRrules ((Query * )sub -> subselect ,
1284- activeRIRs );
1303+ activeRIRs , false );
12851304/* Fall through to process lefthand args of SubLink */
12861305}
12871306
@@ -1299,7 +1318,7 @@ fireRIRonSubLink(Node *node, List *activeRIRs)
12991318 *Apply all RIR rules on each rangetable entry in a query
13001319 */
13011320static Query *
1302- fireRIRrules (Query * parsetree ,List * activeRIRs )
1321+ fireRIRrules (Query * parsetree ,List * activeRIRs , bool forUpdatePushedDown )
13031322{
13041323int rt_index ;
13051324ListCell * lc ;
@@ -1329,7 +1348,9 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
13291348 */
13301349if (rte -> rtekind == RTE_SUBQUERY )
13311350{
1332- rte -> subquery = fireRIRrules (rte -> subquery ,activeRIRs );
1351+ rte -> subquery = fireRIRrules (rte -> subquery ,activeRIRs ,
1352+ (forUpdatePushedDown ||
1353+ get_parse_rowmark (parsetree ,rt_index )!= NULL ));
13331354continue ;
13341355}
13351356
@@ -1406,7 +1427,8 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
14061427rt_index ,
14071428rule -> attrno == -1 ,
14081429rel ,
1409- activeRIRs );
1430+ activeRIRs ,
1431+ forUpdatePushedDown );
14101432}
14111433
14121434activeRIRs = list_delete_first (activeRIRs );
@@ -1421,7 +1443,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
14211443CommonTableExpr * cte = (CommonTableExpr * )lfirst (lc );
14221444
14231445cte -> ctequery = (Node * )
1424- fireRIRrules ((Query * )cte -> ctequery ,activeRIRs );
1446+ fireRIRrules ((Query * )cte -> ctequery ,activeRIRs , false );
14251447}
14261448
14271449/*
@@ -1850,7 +1872,7 @@ QueryRewrite(Query *parsetree)
18501872{
18511873Query * query = (Query * )lfirst (l );
18521874
1853- query = fireRIRrules (query ,NIL );
1875+ query = fireRIRrules (query ,NIL , false );
18541876
18551877/*
18561878 * If the query target was rewritten as a view, complain.