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