@@ -37,7 +37,13 @@ typedef struct rewrite_event
3737CmdType event ;/* type of rule being fired */
3838}rewrite_event ;
3939
40- static bool acquireLocksOnSubLinks (Node * node ,void * context );
40+ typedef struct acquireLocksOnSubLinks_context
41+ {
42+ bool for_execute ;/* AcquireRewriteLocks' forExecute param */
43+ }acquireLocksOnSubLinks_context ;
44+
45+ static bool acquireLocksOnSubLinks (Node * node ,
46+ acquireLocksOnSubLinks_context * context );
4147static Query * rewriteRuleAction (Query * parsetree ,
4248Query * rule_action ,
4349Node * rule_qual ,
@@ -69,9 +75,19 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
6975 * These locks will ensure that the relation schemas don't change under us
7076 * while we are rewriting and planning the query.
7177 *
72- * forUpdatePushedDown indicates that a pushed-down FOR UPDATE/SHARE applies
73- * to the current subquery, requiring all rels to be opened with RowShareLock.
74- * This should always be false at the start of the recursion.
78+ * forExecute indicates that the query is about to be executed.
79+ * If so, we'll acquire RowExclusiveLock on the query's resultRelation,
80+ * RowShareLock on any relation accessed FOR UPDATE/SHARE, and
81+ * AccessShareLock on all other relations mentioned.
82+ *
83+ * If forExecute is false, AccessShareLock is acquired on all relations.
84+ * This case is suitable for ruleutils.c, for example, where we only need
85+ * schema stability and we don't intend to actually modify any relations.
86+ *
87+ * forUpdatePushedDown indicates that a pushed-down FOR UPDATE/SHARE
88+ * applies to the current subquery, requiring all rels to be opened with at
89+ * least RowShareLock. This should always be false at the top of the
90+ * recursion. This flag is ignored if forExecute is false.
7591 *
7692 * A secondary purpose of this routine is to fix up JOIN RTE references to
7793 * dropped columns (see details below). Because the RTEs are modified in
@@ -99,10 +115,15 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
99115 * construction of a nested join was O(N^2) in the nesting depth.)
100116 */
101117void
102- AcquireRewriteLocks (Query * parsetree ,bool forUpdatePushedDown )
118+ AcquireRewriteLocks (Query * parsetree ,
119+ bool forExecute ,
120+ bool forUpdatePushedDown )
103121{
104122ListCell * l ;
105123int rt_index ;
124+ acquireLocksOnSubLinks_context context ;
125+
126+ context .for_execute = forExecute ;
106127
107128/*
108129 * First, process RTEs of the current query level.
@@ -128,14 +149,12 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
128149 * release it until end of transaction. This protects the
129150 * rewriter and planner against schema changes mid-query.
130151 *
131- * If the relation is the query's result relation, then we
132- * need RowExclusiveLock. Otherwise, check to see if the
133- * relation is accessed FOR UPDATE/SHARE or not. We can't
134- * just grab AccessShareLock because then the executor would
135- * be trying to upgrade the lock, leading to possible
136- * deadlocks.
152+ * Assuming forExecute is true, this logic must match what the
153+ * executor will do, else we risk lock-upgrade deadlocks.
137154 */
138- if (rt_index == parsetree -> resultRelation )
155+ if (!forExecute )
156+ lockmode = AccessShareLock ;
157+ else if (rt_index == parsetree -> resultRelation )
139158lockmode = RowExclusiveLock ;
140159else if (forUpdatePushedDown ||
141160get_parse_rowmark (parsetree ,rt_index )!= NULL )
@@ -223,6 +242,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
223242 * recurse to process the represented subquery.
224243 */
225244AcquireRewriteLocks (rte -> subquery ,
245+ forExecute ,
226246(forUpdatePushedDown ||
227247get_parse_rowmark (parsetree ,rt_index )!= NULL ));
228248break ;
@@ -238,23 +258,23 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
238258{
239259CommonTableExpr * cte = (CommonTableExpr * )lfirst (l );
240260
241- AcquireRewriteLocks ((Query * )cte -> ctequery , false);
261+ AcquireRewriteLocks ((Query * )cte -> ctequery ,forExecute , false);
242262}
243263
244264/*
245265 * Recurse into sublink subqueries, too. But we already did the ones in
246266 * the rtable and cteList.
247267 */
248268if (parsetree -> hasSubLinks )
249- query_tree_walker (parsetree ,acquireLocksOnSubLinks ,NULL ,
269+ query_tree_walker (parsetree ,acquireLocksOnSubLinks ,& context ,
250270QTW_IGNORE_RC_SUBQUERIES );
251271}
252272
253273/*
254274 * Walker to find sublink subqueries for AcquireRewriteLocks
255275 */
256276static bool
257- acquireLocksOnSubLinks (Node * node ,void * context )
277+ acquireLocksOnSubLinks (Node * node ,acquireLocksOnSubLinks_context * context )
258278{
259279if (node == NULL )
260280return false;
@@ -263,7 +283,9 @@ acquireLocksOnSubLinks(Node *node, void *context)
263283SubLink * sub = (SubLink * )node ;
264284
265285/* Do what we came for */
266- AcquireRewriteLocks ((Query * )sub -> subselect , false);
286+ AcquireRewriteLocks ((Query * )sub -> subselect ,
287+ context -> for_execute ,
288+ false);
267289/* Fall through to process lefthand args of SubLink */
268290}
269291
@@ -305,6 +327,9 @@ rewriteRuleAction(Query *parsetree,
305327int rt_length ;
306328Query * sub_action ;
307329Query * * sub_action_ptr ;
330+ acquireLocksOnSubLinks_context context ;
331+
332+ context .for_execute = true;
308333
309334/*
310335 * Make modifiable copies of rule action and qual (what we're passed are
@@ -316,8 +341,8 @@ rewriteRuleAction(Query *parsetree,
316341/*
317342 * Acquire necessary locks and fix any deleted JOIN RTE entries.
318343 */
319- AcquireRewriteLocks (rule_action , false);
320- (void )acquireLocksOnSubLinks (rule_qual ,NULL );
344+ AcquireRewriteLocks (rule_action ,true, false);
345+ (void )acquireLocksOnSubLinks (rule_qual ,& context );
321346
322347current_varno = rt_index ;
323348rt_length = list_length (parsetree -> rtable );
@@ -1367,7 +1392,7 @@ ApplyRetrieveRule(Query *parsetree,
13671392 */
13681393rule_action = copyObject (linitial (rule -> actions ));
13691394
1370- AcquireRewriteLocks (rule_action ,forUpdatePushedDown );
1395+ AcquireRewriteLocks (rule_action ,true, forUpdatePushedDown );
13711396
13721397/*
13731398 * Recursively expand any view references inside the view.
@@ -1690,14 +1715,17 @@ CopyAndAddInvertedQual(Query *parsetree,
16901715{
16911716/* Don't scribble on the passed qual (it's in the relcache!) */
16921717Node * new_qual = (Node * )copyObject (rule_qual );
1718+ acquireLocksOnSubLinks_context context ;
1719+
1720+ context .for_execute = true;
16931721
16941722/*
16951723 * In case there are subqueries in the qual, acquire necessary locks and
16961724 * fix any deleted JOIN RTE entries. (This is somewhat redundant with
16971725 * rewriteRuleAction, but not entirely ... consider restructuring so that
16981726 * we only need to process the qual this way once.)
16991727 */
1700- (void )acquireLocksOnSubLinks (new_qual ,NULL );
1728+ (void )acquireLocksOnSubLinks (new_qual ,& context );
17011729
17021730/* Fix references to OLD */
17031731ChangeVarNodes (new_qual ,PRS2_OLD_VARNO ,rt_index ,0 );