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/28 14:55:43 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.191 2009/10/28 17:36:50 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -55,7 +55,8 @@ static void markQueryForLocking(Query *qry, Node *jtnode,
5555 bool forUpdate , bool noWait , bool pushedDown );
5656static List * matchLocks (CmdType event , RuleLock * rulelocks ,
5757 int 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{
96101 ListCell * l ;
97102 int rt_index ;
@@ -129,7 +134,8 @@ AcquireRewriteLocks(Query *parsetree)
129134 */
130135 if (rt_index == parsetree -> resultRelation )
131136 lockmode = RowExclusiveLock ;
132- else if (get_parse_rowmark (parsetree , rt_index ) != NULL )
137+ else if (forUpdatePushedDown ||
138+ get_parse_rowmark (parsetree , rt_index ) != NULL )
133139 lockmode = RowShareLock ;
134140 else
135141 lockmode = 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 ));
210218 break ;
211219
212220 default :
@@ -220,7 +228,7 @@ AcquireRewriteLocks(Query *parsetree)
220228 {
221229 CommonTableExpr * 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)
245253 SubLink * 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
304312 current_varno = rt_index ;
@@ -1134,7 +1142,8 @@ ApplyRetrieveRule(Query *parsetree,
11341142 int rt_index ,
11351143 bool relation_level ,
11361144 Relation relation ,
1137- List * activeRIRs )
1145+ List * activeRIRs ,
1146+ bool forUpdatePushedDown )
11381147{
11391148 Query * rule_action ;
11401149 RangeTblEntry * rte ,
@@ -1148,18 +1157,25 @@ ApplyRetrieveRule(Query *parsetree,
11481157 if (!relation_level )
11491158 elog (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 */
11551171 rule_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 )
11971216 markQueryForLocking (rule_action , (Node * ) rule_action -> jointree ,
11981217 rc -> forUpdate , rc -> noWait , true);
11991218
@@ -1281,7 +1300,7 @@ fireRIRonSubLink(Node *node, List *activeRIRs)
12811300
12821301 /* Do what we came for */
12831302 sub -> 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{
13041323 int rt_index ;
13051324 ListCell * lc ;
@@ -1329,7 +1348,9 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
13291348 */
13301349 if (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 ));
13331354 continue ;
13341355 }
13351356
@@ -1406,7 +1427,8 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
14061427 rt_index ,
14071428 rule -> attrno == -1 ,
14081429 rel ,
1409- activeRIRs );
1430+ activeRIRs ,
1431+ forUpdatePushedDown );
14101432 }
14111433
14121434 activeRIRs = list_delete_first (activeRIRs );
@@ -1421,7 +1443,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
14211443 CommonTableExpr * cte = (CommonTableExpr * ) lfirst (lc );
14221444
14231445 cte -> 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 {
18511873 Query * 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.
0 commit comments