@@ -38,7 +38,13 @@ typedef struct rewrite_event
38
38
CmdType event ;/* type of rule being fired */
39
39
}rewrite_event ;
40
40
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 );
42
48
static Query * rewriteRuleAction (Query * parsetree ,
43
49
Query * rule_action ,
44
50
Node * rule_qual ,
@@ -70,9 +76,19 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
70
76
* These locks will ensure that the relation schemas don't change under us
71
77
* while we are rewriting and planning the query.
72
78
*
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.
76
92
*
77
93
* A secondary purpose of this routine is to fix up JOIN RTE references to
78
94
* dropped columns (see details below). Because the RTEs are modified in
@@ -100,10 +116,15 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
100
116
* construction of a nested join was O(N^2) in the nesting depth.)
101
117
*/
102
118
void
103
- AcquireRewriteLocks (Query * parsetree ,bool forUpdatePushedDown )
119
+ AcquireRewriteLocks (Query * parsetree ,
120
+ bool forExecute ,
121
+ bool forUpdatePushedDown )
104
122
{
105
123
ListCell * l ;
106
124
int rt_index ;
125
+ acquireLocksOnSubLinks_context context ;
126
+
127
+ context .for_execute = forExecute ;
107
128
108
129
/*
109
130
* First, process RTEs of the current query level.
@@ -129,14 +150,12 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
129
150
* release it until end of transaction. This protects the
130
151
* rewriter and planner against schema changes mid-query.
131
152
*
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.
138
155
*/
139
- if (rt_index == parsetree -> resultRelation )
156
+ if (!forExecute )
157
+ lockmode = AccessShareLock ;
158
+ else if (rt_index == parsetree -> resultRelation )
140
159
lockmode = RowExclusiveLock ;
141
160
else if (forUpdatePushedDown ||
142
161
get_parse_rowmark (parsetree ,rt_index )!= NULL )
@@ -224,6 +243,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
224
243
* recurse to process the represented subquery.
225
244
*/
226
245
AcquireRewriteLocks (rte -> subquery ,
246
+ forExecute ,
227
247
(forUpdatePushedDown ||
228
248
get_parse_rowmark (parsetree ,rt_index )!= NULL ));
229
249
break ;
@@ -239,23 +259,23 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
239
259
{
240
260
CommonTableExpr * cte = (CommonTableExpr * )lfirst (l );
241
261
242
- AcquireRewriteLocks ((Query * )cte -> ctequery , false);
262
+ AcquireRewriteLocks ((Query * )cte -> ctequery ,forExecute , false);
243
263
}
244
264
245
265
/*
246
266
* Recurse into sublink subqueries, too. But we already did the ones in
247
267
* the rtable and cteList.
248
268
*/
249
269
if (parsetree -> hasSubLinks )
250
- query_tree_walker (parsetree ,acquireLocksOnSubLinks ,NULL ,
270
+ query_tree_walker (parsetree ,acquireLocksOnSubLinks ,& context ,
251
271
QTW_IGNORE_RC_SUBQUERIES );
252
272
}
253
273
254
274
/*
255
275
* Walker to find sublink subqueries for AcquireRewriteLocks
256
276
*/
257
277
static bool
258
- acquireLocksOnSubLinks (Node * node ,void * context )
278
+ acquireLocksOnSubLinks (Node * node ,acquireLocksOnSubLinks_context * context )
259
279
{
260
280
if (node == NULL )
261
281
return false;
@@ -264,7 +284,9 @@ acquireLocksOnSubLinks(Node *node, void *context)
264
284
SubLink * sub = (SubLink * )node ;
265
285
266
286
/* Do what we came for */
267
- AcquireRewriteLocks ((Query * )sub -> subselect , false);
287
+ AcquireRewriteLocks ((Query * )sub -> subselect ,
288
+ context -> for_execute ,
289
+ false);
268
290
/* Fall through to process lefthand args of SubLink */
269
291
}
270
292
@@ -306,6 +328,9 @@ rewriteRuleAction(Query *parsetree,
306
328
int rt_length ;
307
329
Query * sub_action ;
308
330
Query * * sub_action_ptr ;
331
+ acquireLocksOnSubLinks_context context ;
332
+
333
+ context .for_execute = true;
309
334
310
335
/*
311
336
* Make modifiable copies of rule action and qual (what we're passed are
@@ -317,8 +342,8 @@ rewriteRuleAction(Query *parsetree,
317
342
/*
318
343
* Acquire necessary locks and fix any deleted JOIN RTE entries.
319
344
*/
320
- AcquireRewriteLocks (rule_action , false);
321
- (void )acquireLocksOnSubLinks (rule_qual ,NULL );
345
+ AcquireRewriteLocks (rule_action ,true, false);
346
+ (void )acquireLocksOnSubLinks (rule_qual ,& context );
322
347
323
348
current_varno = rt_index ;
324
349
rt_length = list_length (parsetree -> rtable );
@@ -1387,7 +1412,7 @@ ApplyRetrieveRule(Query *parsetree,
1387
1412
*/
1388
1413
rule_action = copyObject (linitial (rule -> actions ));
1389
1414
1390
- AcquireRewriteLocks (rule_action ,forUpdatePushedDown );
1415
+ AcquireRewriteLocks (rule_action ,true, forUpdatePushedDown );
1391
1416
1392
1417
/*
1393
1418
* Recursively expand any view references inside the view.
@@ -1719,14 +1744,17 @@ CopyAndAddInvertedQual(Query *parsetree,
1719
1744
{
1720
1745
/* Don't scribble on the passed qual (it's in the relcache!) */
1721
1746
Node * new_qual = (Node * )copyObject (rule_qual );
1747
+ acquireLocksOnSubLinks_context context ;
1748
+
1749
+ context .for_execute = true;
1722
1750
1723
1751
/*
1724
1752
* In case there are subqueries in the qual, acquire necessary locks and
1725
1753
* fix any deleted JOIN RTE entries. (This is somewhat redundant with
1726
1754
* rewriteRuleAction, but not entirely ... consider restructuring so that
1727
1755
* we only need to process the qual this way once.)
1728
1756
*/
1729
- (void )acquireLocksOnSubLinks (new_qual ,NULL );
1757
+ (void )acquireLocksOnSubLinks (new_qual ,& context );
1730
1758
1731
1759
/* Fix references to OLD */
1732
1760
ChangeVarNodes (new_qual ,PRS2_OLD_VARNO ,rt_index ,0 );