@@ -36,7 +36,13 @@ typedef struct rewrite_event
36
36
CmdType event ; /* type of rule being fired */
37
37
} rewrite_event ;
38
38
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 );
40
46
static Query * rewriteRuleAction (Query * parsetree ,
41
47
Query * rule_action ,
42
48
Node * rule_qual ,
@@ -65,6 +71,15 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
65
71
* These locks will ensure that the relation schemas don't change under us
66
72
* while we are rewriting and planning the query.
67
73
*
74
+ * forExecute indicates that the query is about to be executed.
75
+ * If so, we'll acquire RowExclusiveLock on the query's resultRelation,
76
+ * RowShareLock on any relation accessed FOR UPDATE/SHARE, and
77
+ * AccessShareLock on all other relations mentioned.
78
+ *
79
+ * If forExecute is false, AccessShareLock is acquired on all relations.
80
+ * This case is suitable for ruleutils.c, for example, where we only need
81
+ * schema stability and we don't intend to actually modify any relations.
82
+ *
68
83
* A secondary purpose of this routine is to fix up JOIN RTE references to
69
84
* dropped columns (see details below). Because the RTEs are modified in
70
85
* place, it is generally appropriate for the caller of this routine to have
@@ -91,10 +106,13 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
91
106
* construction of a nested join was O(N^2) in the nesting depth.)
92
107
*/
93
108
void
94
- AcquireRewriteLocks (Query * parsetree )
109
+ AcquireRewriteLocks (Query * parsetree , bool forExecute )
95
110
{
96
111
ListCell * l ;
97
112
int rt_index ;
113
+ acquireLocksOnSubLinks_context context ;
114
+
115
+ context .for_execute = forExecute ;
98
116
99
117
/*
100
118
* First, process RTEs of the current query level.
@@ -120,14 +138,12 @@ AcquireRewriteLocks(Query *parsetree)
120
138
* release it until end of transaction. This protects the
121
139
* rewriter and planner against schema changes mid-query.
122
140
*
123
- * If the relation is the query's result relation, then we
124
- * need RowExclusiveLock. Otherwise, check to see if the
125
- * relation is accessed FOR UPDATE/SHARE or not. We can't
126
- * just grab AccessShareLock because then the executor would
127
- * be trying to upgrade the lock, leading to possible
128
- * deadlocks.
141
+ * Assuming forExecute is true, this logic must match what the
142
+ * executor will do, else we risk lock-upgrade deadlocks.
129
143
*/
130
- if (rt_index == parsetree -> resultRelation )
144
+ if (!forExecute )
145
+ lockmode = AccessShareLock ;
146
+ else if (rt_index == parsetree -> resultRelation )
131
147
lockmode = RowExclusiveLock ;
132
148
else if (get_rowmark (parsetree , rt_index ))
133
149
lockmode = RowShareLock ;
@@ -206,7 +222,7 @@ AcquireRewriteLocks(Query *parsetree)
206
222
* The subquery RTE itself is all right, but we have to
207
223
* recurse to process the represented subquery.
208
224
*/
209
- AcquireRewriteLocks (rte -> subquery );
225
+ AcquireRewriteLocks (rte -> subquery , forExecute );
210
226
break ;
211
227
212
228
default :
@@ -220,23 +236,23 @@ AcquireRewriteLocks(Query *parsetree)
220
236
{
221
237
CommonTableExpr * cte = (CommonTableExpr * ) lfirst (l );
222
238
223
- AcquireRewriteLocks ((Query * ) cte -> ctequery );
239
+ AcquireRewriteLocks ((Query * ) cte -> ctequery , forExecute );
224
240
}
225
241
226
242
/*
227
243
* Recurse into sublink subqueries, too. But we already did the ones in
228
244
* the rtable and cteList.
229
245
*/
230
246
if (parsetree -> hasSubLinks )
231
- query_tree_walker (parsetree , acquireLocksOnSubLinks , NULL ,
247
+ query_tree_walker (parsetree , acquireLocksOnSubLinks , & context ,
232
248
QTW_IGNORE_RC_SUBQUERIES );
233
249
}
234
250
235
251
/*
236
252
* Walker to find sublink subqueries for AcquireRewriteLocks
237
253
*/
238
254
static bool
239
- acquireLocksOnSubLinks (Node * node , void * context )
255
+ acquireLocksOnSubLinks (Node * node , acquireLocksOnSubLinks_context * context )
240
256
{
241
257
if (node == NULL )
242
258
return false;
@@ -245,7 +261,7 @@ acquireLocksOnSubLinks(Node *node, void *context)
245
261
SubLink * sub = (SubLink * ) node ;
246
262
247
263
/* Do what we came for */
248
- AcquireRewriteLocks ((Query * ) sub -> subselect );
264
+ AcquireRewriteLocks ((Query * ) sub -> subselect , context -> for_execute );
249
265
/* Fall through to process lefthand args of SubLink */
250
266
}
251
267
@@ -287,6 +303,9 @@ rewriteRuleAction(Query *parsetree,
287
303
int rt_length ;
288
304
Query * sub_action ;
289
305
Query * * sub_action_ptr ;
306
+ acquireLocksOnSubLinks_context context ;
307
+
308
+ context .for_execute = true;
290
309
291
310
/*
292
311
* Make modifiable copies of rule action and qual (what we're passed are
@@ -298,8 +317,8 @@ rewriteRuleAction(Query *parsetree,
298
317
/*
299
318
* Acquire necessary locks and fix any deleted JOIN RTE entries.
300
319
*/
301
- AcquireRewriteLocks (rule_action );
302
- (void ) acquireLocksOnSubLinks (rule_qual , NULL );
320
+ AcquireRewriteLocks (rule_action , true );
321
+ (void ) acquireLocksOnSubLinks (rule_qual , & context );
303
322
304
323
current_varno = rt_index ;
305
324
rt_length = list_length (parsetree -> rtable );
@@ -1154,7 +1173,7 @@ ApplyRetrieveRule(Query *parsetree,
1154
1173
*/
1155
1174
rule_action = copyObject (linitial (rule -> actions ));
1156
1175
1157
- AcquireRewriteLocks (rule_action );
1176
+ AcquireRewriteLocks (rule_action , true );
1158
1177
1159
1178
/*
1160
1179
* Recursively expand any view references inside the view.
@@ -1465,14 +1484,17 @@ CopyAndAddInvertedQual(Query *parsetree,
1465
1484
{
1466
1485
/* Don't scribble on the passed qual (it's in the relcache!) */
1467
1486
Node * new_qual = (Node * ) copyObject (rule_qual );
1487
+ acquireLocksOnSubLinks_context context ;
1488
+
1489
+ context .for_execute = true;
1468
1490
1469
1491
/*
1470
1492
* In case there are subqueries in the qual, acquire necessary locks and
1471
1493
* fix any deleted JOIN RTE entries. (This is somewhat redundant with
1472
1494
* rewriteRuleAction, but not entirely ... consider restructuring so that
1473
1495
* we only need to process the qual this way once.)
1474
1496
*/
1475
- (void ) acquireLocksOnSubLinks (new_qual , NULL );
1497
+ (void ) acquireLocksOnSubLinks (new_qual , & context );
1476
1498
1477
1499
/* Fix references to OLD */
1478
1500
ChangeVarNodes (new_qual , PRS2_OLD_VARNO , rt_index , 0 );
0 commit comments