@@ -186,150 +186,136 @@ policy_role_list_to_array(List *roles, int *num_roles)
186
186
/*
187
187
* Load row security policy from the catalog, and store it in
188
188
* the relation's relcache entry.
189
+ *
190
+ * Note that caller should have verified that pg_class.relrowsecurity
191
+ * is true for this relation.
189
192
*/
190
193
void
191
194
RelationBuildRowSecurity (Relation relation )
192
195
{
193
196
MemoryContext rscxt ;
194
197
MemoryContext oldcxt = CurrentMemoryContext ;
195
- RowSecurityDesc * volatile rsdesc = NULL ;
198
+ RowSecurityDesc * rsdesc ;
199
+ Relation catalog ;
200
+ ScanKeyData skey ;
201
+ SysScanDesc sscan ;
202
+ HeapTuple tuple ;
196
203
197
204
/*
198
205
* Create a memory context to hold everything associated with this
199
206
* relation's row security policy. This makes it easy to clean up during
200
- * a relcache flush.
207
+ * a relcache flush. However, to cover the possibility of an error
208
+ * partway through, we don't make the context long-lived till we're done.
201
209
*/
202
- rscxt = AllocSetContextCreate (CacheMemoryContext ,
210
+ rscxt = AllocSetContextCreate (CurrentMemoryContext ,
203
211
"row security descriptor" ,
204
212
ALLOCSET_SMALL_MINSIZE ,
205
213
ALLOCSET_SMALL_INITSIZE ,
206
214
ALLOCSET_SMALL_MAXSIZE );
207
215
216
+ rsdesc = MemoryContextAllocZero (rscxt , sizeof (RowSecurityDesc ));
217
+ rsdesc -> rscxt = rscxt ;
218
+
208
219
/*
209
- * Since rscxt lives under CacheMemoryContext, it is long-lived. Use a
210
- * PG_TRY block to ensure it'll get freed if we fail partway through.
220
+ * Now scan pg_policy for RLS policies associated with this relation.
221
+ * Because we use the index on (polrelid, polname), we should consistently
222
+ * visit the rel's policies in name order, at least when system indexes
223
+ * aren't disabled. This simplifies equalRSDesc().
211
224
*/
212
- PG_TRY ();
213
- {
214
- Relation catalog ;
215
- ScanKeyData skey ;
216
- SysScanDesc sscan ;
217
- HeapTuple tuple ;
225
+ catalog = heap_open (PolicyRelationId , AccessShareLock );
218
226
219
- rsdesc = MemoryContextAllocZero (rscxt , sizeof (RowSecurityDesc ));
220
- rsdesc -> rscxt = rscxt ;
227
+ ScanKeyInit (& skey ,
228
+ Anum_pg_policy_polrelid ,
229
+ BTEqualStrategyNumber , F_OIDEQ ,
230
+ ObjectIdGetDatum (RelationGetRelid (relation )));
221
231
222
- catalog = heap_open (PolicyRelationId , AccessShareLock );
232
+ sscan = systable_beginscan (catalog , PolicyPolrelidPolnameIndexId , true,
233
+ NULL , 1 , & skey );
223
234
224
- ScanKeyInit (& skey ,
225
- Anum_pg_policy_polrelid ,
226
- BTEqualStrategyNumber , F_OIDEQ ,
227
- ObjectIdGetDatum (RelationGetRelid (relation )));
235
+ while (HeapTupleIsValid (tuple = systable_getnext (sscan )))
236
+ {
237
+ Form_pg_policy policy_form = (Form_pg_policy ) GETSTRUCT (tuple );
238
+ RowSecurityPolicy * policy ;
239
+ Datum datum ;
240
+ bool isnull ;
241
+ char * str_value ;
228
242
229
- sscan = systable_beginscan (catalog , PolicyPolrelidPolnameIndexId , true,
230
- NULL , 1 , & skey );
243
+ policy = MemoryContextAllocZero (rscxt , sizeof (RowSecurityPolicy ));
231
244
232
245
/*
233
- * Loop through the row level security policies for this relation, if
234
- * any.
246
+ * Note: we must be sure that pass-by-reference data gets copied into
247
+ * rscxt. We avoid making that context current over wider spans than
248
+ * we have to, though.
235
249
*/
236
- while (HeapTupleIsValid (tuple = systable_getnext (sscan )))
237
- {
238
- Datum value_datum ;
239
- char cmd_value ;
240
- Datum roles_datum ;
241
- char * qual_value ;
242
- Expr * qual_expr ;
243
- char * with_check_value ;
244
- Expr * with_check_qual ;
245
- char * policy_name_value ;
246
- bool isnull ;
247
- RowSecurityPolicy * policy ;
248
-
249
- /*
250
- * Note: all the pass-by-reference data we collect here is either
251
- * still stored in the tuple, or constructed in the caller's
252
- * short-lived memory context. We must copy it into rscxt
253
- * explicitly below.
254
- */
255
-
256
- /* Get policy command */
257
- value_datum = heap_getattr (tuple , Anum_pg_policy_polcmd ,
258
- RelationGetDescr (catalog ), & isnull );
259
- Assert (!isnull );
260
- cmd_value = DatumGetChar (value_datum );
261
-
262
- /* Get policy name */
263
- value_datum = heap_getattr (tuple , Anum_pg_policy_polname ,
264
- RelationGetDescr (catalog ), & isnull );
265
- Assert (!isnull );
266
- policy_name_value = NameStr (* (DatumGetName (value_datum )));
267
-
268
- /* Get policy roles */
269
- roles_datum = heap_getattr (tuple , Anum_pg_policy_polroles ,
270
- RelationGetDescr (catalog ), & isnull );
271
- /* shouldn't be null, but initdb doesn't mark it so, so check */
272
- if (isnull )
273
- elog (ERROR , "unexpected null value in pg_policy.polroles" );
274
-
275
- /* Get policy qual */
276
- value_datum = heap_getattr (tuple , Anum_pg_policy_polqual ,
277
- RelationGetDescr (catalog ), & isnull );
278
- if (!isnull )
279
- {
280
- qual_value = TextDatumGetCString (value_datum );
281
- qual_expr = (Expr * ) stringToNode (qual_value );
282
- }
283
- else
284
- qual_expr = NULL ;
285
250
286
- /* Get WITH CHECK qual */
287
- value_datum = heap_getattr (tuple , Anum_pg_policy_polwithcheck ,
288
- RelationGetDescr (catalog ), & isnull );
289
- if (!isnull )
290
- {
291
- with_check_value = TextDatumGetCString (value_datum );
292
- with_check_qual = (Expr * ) stringToNode (with_check_value );
293
- }
294
- else
295
- with_check_qual = NULL ;
251
+ /* Get policy command */
252
+ policy -> polcmd = policy_form -> polcmd ;
253
+
254
+ /* Get policy name */
255
+ policy -> policy_name =
256
+ MemoryContextStrdup (rscxt , NameStr (policy_form -> polname ));
257
+
258
+ /* Get policy roles */
259
+ datum = heap_getattr (tuple , Anum_pg_policy_polroles ,
260
+ RelationGetDescr (catalog ), & isnull );
261
+ /* shouldn't be null, but let's check for luck */
262
+ if (isnull )
263
+ elog (ERROR , "unexpected null value in pg_policy.polroles" );
264
+ MemoryContextSwitchTo (rscxt );
265
+ policy -> roles = DatumGetArrayTypePCopy (datum );
266
+ MemoryContextSwitchTo (oldcxt );
296
267
297
- /* Now copy everything into the cache context */
268
+ /* Get policy qual */
269
+ datum = heap_getattr (tuple , Anum_pg_policy_polqual ,
270
+ RelationGetDescr (catalog ), & isnull );
271
+ if (!isnull )
272
+ {
273
+ str_value = TextDatumGetCString (datum );
298
274
MemoryContextSwitchTo (rscxt );
299
-
300
- policy = palloc0 (sizeof (RowSecurityPolicy ));
301
- policy -> policy_name = pstrdup (policy_name_value );
302
- policy -> polcmd = cmd_value ;
303
- policy -> roles = DatumGetArrayTypePCopy (roles_datum );
304
- policy -> qual = copyObject (qual_expr );
305
- policy -> with_check_qual = copyObject (with_check_qual );
306
- policy -> hassublinks = checkExprHasSubLink ((Node * ) qual_expr ) ||
307
- checkExprHasSubLink ((Node * ) with_check_qual );
308
-
309
- rsdesc -> policies = lcons (policy , rsdesc -> policies );
310
-
275
+ policy -> qual = (Expr * ) stringToNode (str_value );
311
276
MemoryContextSwitchTo (oldcxt );
277
+ pfree (str_value );
278
+ }
279
+ else
280
+ policy -> qual = NULL ;
312
281
313
- /* clean up some (not all) of the junk ... */
314
- if (qual_expr != NULL )
315
- pfree (qual_expr );
316
- if (with_check_qual != NULL )
317
- pfree (with_check_qual );
282
+ /* Get WITH CHECK qual */
283
+ datum = heap_getattr (tuple , Anum_pg_policy_polwithcheck ,
284
+ RelationGetDescr (catalog ), & isnull );
285
+ if (!isnull )
286
+ {
287
+ str_value = TextDatumGetCString (datum );
288
+ MemoryContextSwitchTo (rscxt );
289
+ policy -> with_check_qual = (Expr * ) stringToNode (str_value );
290
+ MemoryContextSwitchTo (oldcxt );
291
+ pfree (str_value );
318
292
}
293
+ else
294
+ policy -> with_check_qual = NULL ;
319
295
320
- systable_endscan (sscan );
321
- heap_close (catalog , AccessShareLock );
322
- }
323
- PG_CATCH ();
324
- {
325
- /* Delete rscxt, first making sure it isn't active */
296
+ /* We want to cache whether there are SubLinks in these expressions */
297
+ policy -> hassublinks = checkExprHasSubLink ((Node * ) policy -> qual ) ||
298
+ checkExprHasSubLink ((Node * ) policy -> with_check_qual );
299
+
300
+ /*
301
+ * Add this object to list. For historical reasons, the list is built
302
+ * in reverse order.
303
+ */
304
+ MemoryContextSwitchTo (rscxt );
305
+ rsdesc -> policies = lcons (policy , rsdesc -> policies );
326
306
MemoryContextSwitchTo (oldcxt );
327
- MemoryContextDelete (rscxt );
328
- PG_RE_THROW ();
329
307
}
330
- PG_END_TRY ();
331
308
332
- /* Success --- attach the policy descriptor to the relcache entry */
309
+ systable_endscan (sscan );
310
+ heap_close (catalog , AccessShareLock );
311
+
312
+ /*
313
+ * Success. Reparent the descriptor's memory context under
314
+ * CacheMemoryContext so that it will live indefinitely, then attach the
315
+ * policy descriptor to the relcache entry.
316
+ */
317
+ MemoryContextSetParent (rscxt , CacheMemoryContext );
318
+
333
319
relation -> rd_rsdesc = rsdesc ;
334
320
}
335
321
0 commit comments