@@ -36,7 +36,13 @@ typedef struct rewrite_event
3636CmdType event ;/* type of rule being fired */
3737}rewrite_event ;
3838
39- static bool acquireLocksOnSubLinks (Node * node ,void * context );
39+ typedef struct acquireLocksOnSubLinks_context
40+ {
41+ bool for_execute ;/* AcquireRewriteLocks' forExecute param */
42+ }acquireLocksOnSubLinks_context ;
43+
44+ static bool acquireLocksOnSubLinks (Node * node ,
45+ acquireLocksOnSubLinks_context * context );
4046static Query * rewriteRuleAction (Query * parsetree ,
4147Query * rule_action ,
4248Node * rule_qual ,
@@ -66,9 +72,19 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
6672 * These locks will ensure that the relation schemas don't change under us
6773 * while we are rewriting and planning the query.
6874 *
69- * forUpdatePushedDown indicates that a pushed-down FOR UPDATE/SHARE applies
70- * to the current subquery, requiring all rels to be opened with RowShareLock.
71- * This should always be false at the start of the recursion.
75+ * forExecute indicates that the query is about to be executed.
76+ * If so, we'll acquire RowExclusiveLock on the query's resultRelation,
77+ * RowShareLock on any relation accessed FOR UPDATE/SHARE, and
78+ * AccessShareLock on all other relations mentioned.
79+ *
80+ * If forExecute is false, AccessShareLock is acquired on all relations.
81+ * This case is suitable for ruleutils.c, for example, where we only need
82+ * schema stability and we don't intend to actually modify any relations.
83+ *
84+ * forUpdatePushedDown indicates that a pushed-down FOR UPDATE/SHARE
85+ * applies to the current subquery, requiring all rels to be opened with at
86+ * least RowShareLock. This should always be false at the top of the
87+ * recursion. This flag is ignored if forExecute is false.
7288 *
7389 * A secondary purpose of this routine is to fix up JOIN RTE references to
7490 * dropped columns (see details below). Because the RTEs are modified in
@@ -96,10 +112,15 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
96112 * construction of a nested join was O(N^2) in the nesting depth.)
97113 */
98114void
99- AcquireRewriteLocks (Query * parsetree ,bool forUpdatePushedDown )
115+ AcquireRewriteLocks (Query * parsetree ,
116+ bool forExecute ,
117+ bool forUpdatePushedDown )
100118{
101119ListCell * l ;
102120int rt_index ;
121+ acquireLocksOnSubLinks_context context ;
122+
123+ context .for_execute = forExecute ;
103124
104125/*
105126 * First, process RTEs of the current query level.
@@ -125,14 +146,12 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
125146 * release it until end of transaction. This protects the
126147 * rewriter and planner against schema changes mid-query.
127148 *
128- * If the relation is the query's result relation, then we
129- * need RowExclusiveLock. Otherwise, check to see if the
130- * relation is accessed FOR UPDATE/SHARE or not. We can't
131- * just grab AccessShareLock because then the executor would
132- * be trying to upgrade the lock, leading to possible
133- * deadlocks.
149+ * Assuming forExecute is true, this logic must match what the
150+ * executor will do, else we risk lock-upgrade deadlocks.
134151 */
135- if (rt_index == parsetree -> resultRelation )
152+ if (!forExecute )
153+ lockmode = AccessShareLock ;
154+ else if (rt_index == parsetree -> resultRelation )
136155lockmode = RowExclusiveLock ;
137156else if (forUpdatePushedDown ||
138157get_parse_rowmark (parsetree ,rt_index )!= NULL )
@@ -213,6 +232,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
213232 * recurse to process the represented subquery.
214233 */
215234AcquireRewriteLocks (rte -> subquery ,
235+ forExecute ,
216236(forUpdatePushedDown ||
217237get_parse_rowmark (parsetree ,rt_index )!= NULL ));
218238break ;
@@ -228,23 +248,23 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
228248{
229249CommonTableExpr * cte = (CommonTableExpr * )lfirst (l );
230250
231- AcquireRewriteLocks ((Query * )cte -> ctequery , false);
251+ AcquireRewriteLocks ((Query * )cte -> ctequery ,forExecute , false);
232252}
233253
234254/*
235255 * Recurse into sublink subqueries, too. But we already did the ones in
236256 * the rtable and cteList.
237257 */
238258if (parsetree -> hasSubLinks )
239- query_tree_walker (parsetree ,acquireLocksOnSubLinks ,NULL ,
259+ query_tree_walker (parsetree ,acquireLocksOnSubLinks ,& context ,
240260QTW_IGNORE_RC_SUBQUERIES );
241261}
242262
243263/*
244264 * Walker to find sublink subqueries for AcquireRewriteLocks
245265 */
246266static bool
247- acquireLocksOnSubLinks (Node * node ,void * context )
267+ acquireLocksOnSubLinks (Node * node ,acquireLocksOnSubLinks_context * context )
248268{
249269if (node == NULL )
250270return false;
@@ -253,7 +273,9 @@ acquireLocksOnSubLinks(Node *node, void *context)
253273SubLink * sub = (SubLink * )node ;
254274
255275/* Do what we came for */
256- AcquireRewriteLocks ((Query * )sub -> subselect , false);
276+ AcquireRewriteLocks ((Query * )sub -> subselect ,
277+ context -> for_execute ,
278+ false);
257279/* Fall through to process lefthand args of SubLink */
258280}
259281
@@ -295,6 +317,9 @@ rewriteRuleAction(Query *parsetree,
295317int rt_length ;
296318Query * sub_action ;
297319Query * * sub_action_ptr ;
320+ acquireLocksOnSubLinks_context context ;
321+
322+ context .for_execute = true;
298323
299324/*
300325 * Make modifiable copies of rule action and qual (what we're passed are
@@ -306,8 +331,8 @@ rewriteRuleAction(Query *parsetree,
306331/*
307332 * Acquire necessary locks and fix any deleted JOIN RTE entries.
308333 */
309- AcquireRewriteLocks (rule_action , false);
310- (void )acquireLocksOnSubLinks (rule_qual ,NULL );
334+ AcquireRewriteLocks (rule_action ,true, false);
335+ (void )acquireLocksOnSubLinks (rule_qual ,& context );
311336
312337current_varno = rt_index ;
313338rt_length = list_length (parsetree -> rtable );
@@ -1170,7 +1195,7 @@ ApplyRetrieveRule(Query *parsetree,
11701195 */
11711196rule_action = copyObject (linitial (rule -> actions ));
11721197
1173- AcquireRewriteLocks (rule_action ,forUpdatePushedDown );
1198+ AcquireRewriteLocks (rule_action ,true, forUpdatePushedDown );
11741199
11751200/*
11761201 * Recursively expand any view references inside the view.
@@ -1479,14 +1504,17 @@ CopyAndAddInvertedQual(Query *parsetree,
14791504{
14801505/* Don't scribble on the passed qual (it's in the relcache!) */
14811506Node * new_qual = (Node * )copyObject (rule_qual );
1507+ acquireLocksOnSubLinks_context context ;
1508+
1509+ context .for_execute = true;
14821510
14831511/*
14841512 * In case there are subqueries in the qual, acquire necessary locks and
14851513 * fix any deleted JOIN RTE entries. (This is somewhat redundant with
14861514 * rewriteRuleAction, but not entirely ... consider restructuring so that
14871515 * we only need to process the qual this way once.)
14881516 */
1489- (void )acquireLocksOnSubLinks (new_qual ,NULL );
1517+ (void )acquireLocksOnSubLinks (new_qual ,& context );
14901518
14911519/* Fix references to OLD */
14921520ChangeVarNodes (new_qual ,PRS2_OLD_VARNO ,rt_index ,0 );