@@ -37,7 +37,7 @@ typedef struct
37
37
}security_barrier_replace_vars_context ;
38
38
39
39
static void expand_security_qual (PlannerInfo * root ,List * tlist ,int rt_index ,
40
- RangeTblEntry * rte ,Node * qual );
40
+ RangeTblEntry * rte ,Node * qual , bool targetRelation );
41
41
42
42
static void security_barrier_replace_vars (Node * node ,
43
43
security_barrier_replace_vars_context * context );
@@ -63,6 +63,7 @@ expand_security_quals(PlannerInfo *root, List *tlist)
63
63
Query * parse = root -> parse ;
64
64
int rt_index ;
65
65
ListCell * cell ;
66
+ bool targetRelation = false;
66
67
67
68
/*
68
69
* Process each RTE in the rtable list.
@@ -98,6 +99,15 @@ expand_security_quals(PlannerInfo *root, List *tlist)
98
99
{
99
100
RangeTblEntry * newrte = copyObject (rte );
100
101
102
+ /*
103
+ * We need to let expand_security_qual know if this is the target
104
+ * relation, as it has additional work to do in that case.
105
+ *
106
+ * Capture that information here as we're about to replace
107
+ * parse->resultRelation.
108
+ */
109
+ targetRelation = true;
110
+
101
111
parse -> rtable = lappend (parse -> rtable ,newrte );
102
112
parse -> resultRelation = list_length (parse -> rtable );
103
113
@@ -147,7 +157,8 @@ expand_security_quals(PlannerInfo *root, List *tlist)
147
157
rte -> securityQuals = list_delete_first (rte -> securityQuals );
148
158
149
159
ChangeVarNodes (qual ,rt_index ,1 ,0 );
150
- expand_security_qual (root ,tlist ,rt_index ,rte ,qual );
160
+ expand_security_qual (root ,tlist ,rt_index ,rte ,qual ,
161
+ targetRelation );
151
162
}
152
163
}
153
164
}
@@ -160,7 +171,7 @@ expand_security_quals(PlannerInfo *root, List *tlist)
160
171
*/
161
172
static void
162
173
expand_security_qual (PlannerInfo * root ,List * tlist ,int rt_index ,
163
- RangeTblEntry * rte ,Node * qual )
174
+ RangeTblEntry * rte ,Node * qual , bool targetRelation )
164
175
{
165
176
Query * parse = root -> parse ;
166
177
Oid relid = rte -> relid ;
@@ -219,10 +230,11 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
219
230
* Now deal with any PlanRowMark on this RTE by requesting a lock
220
231
* of the same strength on the RTE copied down to the subquery.
221
232
*
222
- * Note that we can't push the user-defined quals down since they
223
- * may included untrusted functions and that means that we will
224
- * end up locking all rows which pass the securityQuals, even if
225
- * those rows don't pass the user-defined quals. This is
233
+ * Note that we can only push down user-defined quals if they are
234
+ * only using leakproof (and therefore trusted) functions and
235
+ * operators. As a result, we may end up locking more rows than
236
+ * strictly necessary (and, in the worst case, we could end up
237
+ * locking all rows which pass the securityQuals). This is
226
238
* currently documented behavior, but it'd be nice to come up with
227
239
* a better solution some day.
228
240
*/
@@ -255,6 +267,15 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
255
267
root -> rowMarks = list_delete (root -> rowMarks ,rc );
256
268
}
257
269
270
+ /*
271
+ * When we are replacing the target relation with a subquery, we
272
+ * need to make sure to add a locking clause explicitly to the
273
+ * generated subquery since there won't be any row marks against
274
+ * the target relation itself.
275
+ */
276
+ if (targetRelation )
277
+ applyLockingClause (subquery ,1 ,LCS_FORUPDATE ,
278
+ false, false);
258
279
/*
259
280
* Replace any variables in the outer query that refer to the
260
281
* original relation RTE with references to columns that we will