@@ -38,7 +38,13 @@ typedef struct rewrite_event
3838CmdType event ;/* type of rule being fired */
3939}rewrite_event ;
4040
41- static bool acquireLocksOnSubLinks (Node * node ,void * context );
41+ typedef struct acquireLocksOnSubLinks_context
42+ {
43+ bool for_execute ;/* AcquireRewriteLocks' forExecute param */
44+ }acquireLocksOnSubLinks_context ;
45+
46+ static bool acquireLocksOnSubLinks (Node * node ,
47+ acquireLocksOnSubLinks_context * context );
4248static Query * rewriteRuleAction (Query * parsetree ,
4349Query * rule_action ,
4450Node * rule_qual ,
@@ -70,9 +76,19 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
7076 * These locks will ensure that the relation schemas don't change under us
7177 * while we are rewriting and planning the query.
7278 *
73- * forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE applies
74- * to the current subquery, requiring all rels to be opened with RowShareLock.
75- * This should always be false at the start of the recursion.
79+ * forExecute indicates that the query is about to be executed.
80+ * If so, we'll acquire RowExclusiveLock on the query's resultRelation,
81+ * RowShareLock on any relation accessed FOR [KEY] UPDATE/SHARE, and
82+ * AccessShareLock on all other relations mentioned.
83+ *
84+ * If forExecute is false, AccessShareLock is acquired on all relations.
85+ * This case is suitable for ruleutils.c, for example, where we only need
86+ * schema stability and we don't intend to actually modify any relations.
87+ *
88+ * forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE
89+ * applies to the current subquery, requiring all rels to be opened with at
90+ * least RowShareLock. This should always be false at the top of the
91+ * recursion. This flag is ignored if forExecute is false.
7692 *
7793 * A secondary purpose of this routine is to fix up JOIN RTE references to
7894 * dropped columns (see details below). Because the RTEs are modified in
@@ -100,10 +116,15 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
100116 * construction of a nested join was O(N^2) in the nesting depth.)
101117 */
102118void
103- AcquireRewriteLocks (Query * parsetree ,bool forUpdatePushedDown )
119+ AcquireRewriteLocks (Query * parsetree ,
120+ bool forExecute ,
121+ bool forUpdatePushedDown )
104122{
105123ListCell * l ;
106124int rt_index ;
125+ acquireLocksOnSubLinks_context context ;
126+
127+ context .for_execute = forExecute ;
107128
108129/*
109130 * First, process RTEs of the current query level.
@@ -129,14 +150,12 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
129150 * release it until end of transaction. This protects the
130151 * rewriter and planner against schema changes mid-query.
131152 *
132- * If the relation is the query's result relation, then we
133- * need RowExclusiveLock. Otherwise, check to see if the
134- * relation is accessed FOR [KEY] UPDATE/SHARE or not.We
135- * can't just grab AccessShareLock because then the executor
136- * would be trying to upgrade the lock, leading to possible
137- * deadlocks.
153+ * Assuming forExecute is true, this logic must match what the
154+ * executor will do, else we risk lock-upgrade deadlocks.
138155 */
139- if (rt_index == parsetree -> resultRelation )
156+ if (!forExecute )
157+ lockmode = AccessShareLock ;
158+ else if (rt_index == parsetree -> resultRelation )
140159lockmode = RowExclusiveLock ;
141160else if (forUpdatePushedDown ||
142161get_parse_rowmark (parsetree ,rt_index )!= NULL )
@@ -224,6 +243,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
224243 * recurse to process the represented subquery.
225244 */
226245AcquireRewriteLocks (rte -> subquery ,
246+ forExecute ,
227247(forUpdatePushedDown ||
228248get_parse_rowmark (parsetree ,rt_index )!= NULL ));
229249break ;
@@ -239,23 +259,23 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
239259{
240260CommonTableExpr * cte = (CommonTableExpr * )lfirst (l );
241261
242- AcquireRewriteLocks ((Query * )cte -> ctequery , false);
262+ AcquireRewriteLocks ((Query * )cte -> ctequery ,forExecute , false);
243263}
244264
245265/*
246266 * Recurse into sublink subqueries, too. But we already did the ones in
247267 * the rtable and cteList.
248268 */
249269if (parsetree -> hasSubLinks )
250- query_tree_walker (parsetree ,acquireLocksOnSubLinks ,NULL ,
270+ query_tree_walker (parsetree ,acquireLocksOnSubLinks ,& context ,
251271QTW_IGNORE_RC_SUBQUERIES );
252272}
253273
254274/*
255275 * Walker to find sublink subqueries for AcquireRewriteLocks
256276 */
257277static bool
258- acquireLocksOnSubLinks (Node * node ,void * context )
278+ acquireLocksOnSubLinks (Node * node ,acquireLocksOnSubLinks_context * context )
259279{
260280if (node == NULL )
261281return false;
@@ -264,7 +284,9 @@ acquireLocksOnSubLinks(Node *node, void *context)
264284SubLink * sub = (SubLink * )node ;
265285
266286/* Do what we came for */
267- AcquireRewriteLocks ((Query * )sub -> subselect , false);
287+ AcquireRewriteLocks ((Query * )sub -> subselect ,
288+ context -> for_execute ,
289+ false);
268290/* Fall through to process lefthand args of SubLink */
269291}
270292
@@ -306,6 +328,9 @@ rewriteRuleAction(Query *parsetree,
306328int rt_length ;
307329Query * sub_action ;
308330Query * * sub_action_ptr ;
331+ acquireLocksOnSubLinks_context context ;
332+
333+ context .for_execute = true;
309334
310335/*
311336 * Make modifiable copies of rule action and qual (what we're passed are
@@ -317,8 +342,8 @@ rewriteRuleAction(Query *parsetree,
317342/*
318343 * Acquire necessary locks and fix any deleted JOIN RTE entries.
319344 */
320- AcquireRewriteLocks (rule_action , false);
321- (void )acquireLocksOnSubLinks (rule_qual ,NULL );
345+ AcquireRewriteLocks (rule_action ,true, false);
346+ (void )acquireLocksOnSubLinks (rule_qual ,& context );
322347
323348current_varno = rt_index ;
324349rt_length = list_length (parsetree -> rtable );
@@ -1387,7 +1412,7 @@ ApplyRetrieveRule(Query *parsetree,
13871412 */
13881413rule_action = copyObject (linitial (rule -> actions ));
13891414
1390- AcquireRewriteLocks (rule_action ,forUpdatePushedDown );
1415+ AcquireRewriteLocks (rule_action ,true, forUpdatePushedDown );
13911416
13921417/*
13931418 * Recursively expand any view references inside the view.
@@ -1719,14 +1744,17 @@ CopyAndAddInvertedQual(Query *parsetree,
17191744{
17201745/* Don't scribble on the passed qual (it's in the relcache!) */
17211746Node * new_qual = (Node * )copyObject (rule_qual );
1747+ acquireLocksOnSubLinks_context context ;
1748+
1749+ context .for_execute = true;
17221750
17231751/*
17241752 * In case there are subqueries in the qual, acquire necessary locks and
17251753 * fix any deleted JOIN RTE entries. (This is somewhat redundant with
17261754 * rewriteRuleAction, but not entirely ... consider restructuring so that
17271755 * we only need to process the qual this way once.)
17281756 */
1729- (void )acquireLocksOnSubLinks (new_qual ,NULL );
1757+ (void )acquireLocksOnSubLinks (new_qual ,& context );
17301758
17311759/* Fix references to OLD */
17321760ChangeVarNodes (new_qual ,PRS2_OLD_VARNO ,rt_index ,0 );