@@ -37,7 +37,13 @@ typedef struct rewrite_event
3737 CmdType 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 ,
4248 Query * rule_action ,
4349 Node * rule_qual ,
@@ -71,9 +77,19 @@ static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
7177 * These locks will ensure that the relation schemas don't change under us
7278 * while we are rewriting and planning the query.
7379 *
74- * forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE applies
75- * to the current subquery, requiring all rels to be opened with RowShareLock.
76- * This should always be false at the start of the recursion.
80+ * forExecute indicates that the query is about to be executed.
81+ * If so, we'll acquire RowExclusiveLock on the query's resultRelation,
82+ * RowShareLock on any relation accessed FOR [KEY] UPDATE/SHARE, and
83+ * AccessShareLock on all other relations mentioned.
84+ *
85+ * If forExecute is false, AccessShareLock is acquired on all relations.
86+ * This case is suitable for ruleutils.c, for example, where we only need
87+ * schema stability and we don't intend to actually modify any relations.
88+ *
89+ * forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE
90+ * applies to the current subquery, requiring all rels to be opened with at
91+ * least RowShareLock. This should always be false at the top of the
92+ * recursion. This flag is ignored if forExecute is false.
7793 *
7894 * A secondary purpose of this routine is to fix up JOIN RTE references to
7995 * dropped columns (see details below). Because the RTEs are modified in
@@ -101,10 +117,15 @@ static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
101117 * construction of a nested join was O(N^2) in the nesting depth.)
102118 */
103119void
104- AcquireRewriteLocks (Query * parsetree , bool forUpdatePushedDown )
120+ AcquireRewriteLocks (Query * parsetree ,
121+ bool forExecute ,
122+ bool forUpdatePushedDown )
105123{
106124 ListCell * l ;
107125 int rt_index ;
126+ acquireLocksOnSubLinks_context context ;
127+
128+ context .for_execute = forExecute ;
108129
109130 /*
110131 * First, process RTEs of the current query level.
@@ -130,14 +151,12 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
130151 * release it until end of transaction. This protects the
131152 * rewriter and planner against schema changes mid-query.
132153 *
133- * If the relation is the query's result relation, then we
134- * need RowExclusiveLock. Otherwise, check to see if the
135- * relation is accessed FOR [KEY] UPDATE/SHARE or not. We
136- * can't just grab AccessShareLock because then the executor
137- * would be trying to upgrade the lock, leading to possible
138- * deadlocks.
154+ * Assuming forExecute is true, this logic must match what the
155+ * executor will do, else we risk lock-upgrade deadlocks.
139156 */
140- if (rt_index == parsetree -> resultRelation )
157+ if (!forExecute )
158+ lockmode = AccessShareLock ;
159+ else if (rt_index == parsetree -> resultRelation )
141160 lockmode = RowExclusiveLock ;
142161 else if (forUpdatePushedDown ||
143162 get_parse_rowmark (parsetree , rt_index ) != NULL )
@@ -225,6 +244,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
225244 * recurse to process the represented subquery.
226245 */
227246 AcquireRewriteLocks (rte -> subquery ,
247+ forExecute ,
228248 (forUpdatePushedDown ||
229249 get_parse_rowmark (parsetree , rt_index ) != NULL ));
230250 break ;
@@ -240,23 +260,23 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
240260 {
241261 CommonTableExpr * cte = (CommonTableExpr * ) lfirst (l );
242262
243- AcquireRewriteLocks ((Query * ) cte -> ctequery , false);
263+ AcquireRewriteLocks ((Query * ) cte -> ctequery , forExecute , false);
244264 }
245265
246266 /*
247267 * Recurse into sublink subqueries, too. But we already did the ones in
248268 * the rtable and cteList.
249269 */
250270 if (parsetree -> hasSubLinks )
251- query_tree_walker (parsetree , acquireLocksOnSubLinks , NULL ,
271+ query_tree_walker (parsetree , acquireLocksOnSubLinks , & context ,
252272 QTW_IGNORE_RC_SUBQUERIES );
253273}
254274
255275/*
256276 * Walker to find sublink subqueries for AcquireRewriteLocks
257277 */
258278static bool
259- acquireLocksOnSubLinks (Node * node , void * context )
279+ acquireLocksOnSubLinks (Node * node , acquireLocksOnSubLinks_context * context )
260280{
261281 if (node == NULL )
262282 return false;
@@ -265,7 +285,9 @@ acquireLocksOnSubLinks(Node *node, void *context)
265285 SubLink * sub = (SubLink * ) node ;
266286
267287 /* Do what we came for */
268- AcquireRewriteLocks ((Query * ) sub -> subselect , false);
288+ AcquireRewriteLocks ((Query * ) sub -> subselect ,
289+ context -> for_execute ,
290+ false);
269291 /* Fall through to process lefthand args of SubLink */
270292 }
271293
@@ -307,6 +329,9 @@ rewriteRuleAction(Query *parsetree,
307329 int rt_length ;
308330 Query * sub_action ;
309331 Query * * sub_action_ptr ;
332+ acquireLocksOnSubLinks_context context ;
333+
334+ context .for_execute = true;
310335
311336 /*
312337 * Make modifiable copies of rule action and qual (what we're passed are
@@ -318,8 +343,8 @@ rewriteRuleAction(Query *parsetree,
318343 /*
319344 * Acquire necessary locks and fix any deleted JOIN RTE entries.
320345 */
321- AcquireRewriteLocks (rule_action , false);
322- (void ) acquireLocksOnSubLinks (rule_qual , NULL );
346+ AcquireRewriteLocks (rule_action , true, false);
347+ (void ) acquireLocksOnSubLinks (rule_qual , & context );
323348
324349 current_varno = rt_index ;
325350 rt_length = list_length (parsetree -> rtable );
@@ -1389,7 +1414,7 @@ ApplyRetrieveRule(Query *parsetree,
13891414 */
13901415 rule_action = copyObject (linitial (rule -> actions ));
13911416
1392- AcquireRewriteLocks (rule_action , forUpdatePushedDown );
1417+ AcquireRewriteLocks (rule_action , true, forUpdatePushedDown );
13931418
13941419 /*
13951420 * Recursively expand any view references inside the view.
@@ -1712,14 +1737,17 @@ CopyAndAddInvertedQual(Query *parsetree,
17121737{
17131738 /* Don't scribble on the passed qual (it's in the relcache!) */
17141739 Node * new_qual = (Node * ) copyObject (rule_qual );
1740+ acquireLocksOnSubLinks_context context ;
1741+
1742+ context .for_execute = true;
17151743
17161744 /*
17171745 * In case there are subqueries in the qual, acquire necessary locks and
17181746 * fix any deleted JOIN RTE entries. (This is somewhat redundant with
17191747 * rewriteRuleAction, but not entirely ... consider restructuring so that
17201748 * we only need to process the qual this way once.)
17211749 */
1722- (void ) acquireLocksOnSubLinks (new_qual , NULL );
1750+ (void ) acquireLocksOnSubLinks (new_qual , & context );
17231751
17241752 /* Fix references to OLD */
17251753 ChangeVarNodes (new_qual , PRS2_OLD_VARNO , rt_index , 0 );
0 commit comments