PostgreSQL Source Code  git master
policy.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * policy.c
4  * Commands for manipulating policies.
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * src/backend/commands/policy.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "access/genam.h"
16 #include "access/htup.h"
17 #include "access/htup_details.h"
18 #include "access/relation.h"
19 #include "access/table.h"
20 #include "access/sysattr.h"
21 #include "catalog/catalog.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.h"
25 #include "catalog/objectaccess.h"
26 #include "catalog/pg_authid.h"
27 #include "catalog/pg_policy.h"
28 #include "catalog/pg_type.h"
29 #include "commands/policy.h"
30 #include "miscadmin.h"
31 #include "nodes/makefuncs.h"
32 #include "nodes/pg_list.h"
33 #include "parser/parse_clause.h"
34 #include "parser/parse_collate.h"
35 #include "parser/parse_node.h"
36 #include "parser/parse_relation.h"
37 #include "rewrite/rewriteManip.h"
38 #include "rewrite/rowsecurity.h"
39 #include "storage/lock.h"
40 #include "utils/acl.h"
41 #include "utils/array.h"
42 #include "utils/builtins.h"
43 #include "utils/fmgroids.h"
44 #include "utils/inval.h"
45 #include "utils/lsyscache.h"
46 #include "utils/memutils.h"
47 #include "utils/rel.h"
48 #include "utils/syscache.h"
49 
50 static void RangeVarCallbackForPolicy(const RangeVar *rv,
51  Oid relid, Oid oldrelid, void *arg);
52 static char parse_policy_command(const char *cmd_name);
53 static Datum *policy_role_list_to_array(List *roles, int *num_roles);
54 
55 /*
56  * Callback to RangeVarGetRelidExtended().
57  *
58  * Checks the following:
59  * - the relation specified is a table.
60  * - current user owns the table.
61  * - the table is not a system table.
62  *
63  * If any of these checks fails then an error is raised.
64  */
65 static void
66 RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid,
67  void *arg)
68 {
69  HeapTuple tuple;
70  Form_pg_class classform;
71  char relkind;
72 
73  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
74  if (!HeapTupleIsValid(tuple))
75  return;
76 
77  classform = (Form_pg_class) GETSTRUCT(tuple);
78  relkind = classform->relkind;
79 
80  /* Must own relation. */
81  if (!pg_class_ownercheck(relid, GetUserId()))
83 
84  /* No system table modifications unless explicitly allowed. */
85  if (!allowSystemTableMods && IsSystemClass(relid, classform))
86  ereport(ERROR,
87  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
88  errmsg("permission denied: \"%s\" is a system catalog",
89  rv->relname)));
90 
91  /* Relation type MUST be a table. */
92  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
93  ereport(ERROR,
94  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
95  errmsg("\"%s\" is not a table", rv->relname)));
96 
97  ReleaseSysCache(tuple);
98 }
99 
100 /*
101  * parse_policy_command -
102  * helper function to convert full command strings to their char
103  * representation.
104  *
105  * cmd_name - full string command name. Valid values are 'all', 'select',
106  * 'insert', 'update' and 'delete'.
107  *
108  */
109 static char
110 parse_policy_command(const char *cmd_name)
111 {
112  char polcmd;
113 
114  if (!cmd_name)
115  elog(ERROR, "unrecognized policy command");
116 
117  if (strcmp(cmd_name, "all") == 0)
118  polcmd = '*';
119  else if (strcmp(cmd_name, "select") == 0)
120  polcmd = ACL_SELECT_CHR;
121  else if (strcmp(cmd_name, "insert") == 0)
122  polcmd = ACL_INSERT_CHR;
123  else if (strcmp(cmd_name, "update") == 0)
124  polcmd = ACL_UPDATE_CHR;
125  else if (strcmp(cmd_name, "delete") == 0)
126  polcmd = ACL_DELETE_CHR;
127  else
128  elog(ERROR, "unrecognized policy command");
129 
130  return polcmd;
131 }
132 
133 /*
134  * policy_role_list_to_array
135  * helper function to convert a list of RoleSpecs to an array of
136  * role id Datums.
137  */
138 static Datum *
139 policy_role_list_to_array(List *roles, int *num_roles)
140 {
141  Datum *role_oids;
142  ListCell *cell;
143  int i = 0;
144 
145  /* Handle no roles being passed in as being for public */
146  if (roles == NIL)
147  {
148  *num_roles = 1;
149  role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
150  role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
151 
152  return role_oids;
153  }
154 
155  *num_roles = list_length(roles);
156  role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
157 
158  foreach(cell, roles)
159  {
160  RoleSpec *spec = lfirst(cell);
161 
162  /*
163  * PUBLIC covers all roles, so it only makes sense alone.
164  */
165  if (spec->roletype == ROLESPEC_PUBLIC)
166  {
167  if (*num_roles != 1)
168  {
170  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
171  errmsg("ignoring specified roles other than PUBLIC"),
172  errhint("All roles are members of the PUBLIC role.")));
173  *num_roles = 1;
174  }
175  role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
176 
177  return role_oids;
178  }
179  else
180  role_oids[i++] =
181  ObjectIdGetDatum(get_rolespec_oid(spec, false));
182  }
183 
184  return role_oids;
185 }
186 
187 /*
188  * Load row security policy from the catalog, and store it in
189  * the relation's relcache entry.
190  */
191 void
193 {
194  MemoryContext rscxt;
196  RowSecurityDesc *volatile rsdesc = NULL;
197 
198  /*
199  * Create a memory context to hold everything associated with this
200  * relation's row security policy. This makes it easy to clean up during
201  * a relcache flush.
202  */
204  "row security descriptor",
206 
207  /*
208  * Since rscxt lives under CacheMemoryContext, it is long-lived. Use a
209  * PG_TRY block to ensure it'll get freed if we fail partway through.
210  */
211  PG_TRY();
212  {
213  Relation catalog;
214  ScanKeyData skey;
215  SysScanDesc sscan;
216  HeapTuple tuple;
217 
219  RelationGetRelationName(relation));
220 
221  rsdesc = MemoryContextAllocZero(rscxt, sizeof(RowSecurityDesc));
222  rsdesc->rscxt = rscxt;
223 
224  catalog = table_open(PolicyRelationId, AccessShareLock);
225 
226  ScanKeyInit(&skey,
227  Anum_pg_policy_polrelid,
228  BTEqualStrategyNumber, F_OIDEQ,
230 
231  sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
232  NULL, 1, &skey);
233 
234  /*
235  * Loop through the row level security policies for this relation, if
236  * any.
237  */
238  while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
239  {
240  Datum value_datum;
241  char cmd_value;
242  bool permissive_value;
243  Datum roles_datum;
244  char *qual_value;
245  Expr *qual_expr;
246  char *with_check_value;
247  Expr *with_check_qual;
248  char *policy_name_value;
249  bool isnull;
250  RowSecurityPolicy *policy;
251 
252  /*
253  * Note: all the pass-by-reference data we collect here is either
254  * still stored in the tuple, or constructed in the caller's
255  * short-lived memory context. We must copy it into rscxt
256  * explicitly below.
257  */
258 
259  /* Get policy command */
260  value_datum = heap_getattr(tuple, Anum_pg_policy_polcmd,
261  RelationGetDescr(catalog), &isnull);
262  Assert(!isnull);
263  cmd_value = DatumGetChar(value_datum);
264 
265  /* Get policy permissive or restrictive */
266  value_datum = heap_getattr(tuple, Anum_pg_policy_polpermissive,
267  RelationGetDescr(catalog), &isnull);
268  Assert(!isnull);
269  permissive_value = DatumGetBool(value_datum);
270 
271  /* Get policy name */
272  value_datum = heap_getattr(tuple, Anum_pg_policy_polname,
273  RelationGetDescr(catalog), &isnull);
274  Assert(!isnull);
275  policy_name_value = NameStr(*(DatumGetName(value_datum)));
276 
277  /* Get policy roles */
278  roles_datum = heap_getattr(tuple, Anum_pg_policy_polroles,
279  RelationGetDescr(catalog), &isnull);
280  /* shouldn't be null, but initdb doesn't mark it so, so check */
281  if (isnull)
282  elog(ERROR, "unexpected null value in pg_policy.polroles");
283 
284  /* Get policy qual */
285  value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
286  RelationGetDescr(catalog), &isnull);
287  if (!isnull)
288  {
289  qual_value = TextDatumGetCString(value_datum);
290  qual_expr = (Expr *) stringToNode(qual_value);
291  }
292  else
293  qual_expr = NULL;
294 
295  /* Get WITH CHECK qual */
296  value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
297  RelationGetDescr(catalog), &isnull);
298  if (!isnull)
299  {
300  with_check_value = TextDatumGetCString(value_datum);
301  with_check_qual = (Expr *) stringToNode(with_check_value);
302  }
303  else
304  with_check_qual = NULL;
305 
306  /* Now copy everything into the cache context */
307  MemoryContextSwitchTo(rscxt);
308 
309  policy = palloc0(sizeof(RowSecurityPolicy));
310  policy->policy_name = pstrdup(policy_name_value);
311  policy->polcmd = cmd_value;
312  policy->permissive = permissive_value;
313  policy->roles = DatumGetArrayTypePCopy(roles_datum);
314  policy->qual = copyObject(qual_expr);
315  policy->with_check_qual = copyObject(with_check_qual);
316  policy->hassublinks = checkExprHasSubLink((Node *) qual_expr) ||
317  checkExprHasSubLink((Node *) with_check_qual);
318 
319  rsdesc->policies = lcons(policy, rsdesc->policies);
320 
321  MemoryContextSwitchTo(oldcxt);
322 
323  /* clean up some (not all) of the junk ... */
324  if (qual_expr != NULL)
325  pfree(qual_expr);
326  if (with_check_qual != NULL)
327  pfree(with_check_qual);
328  }
329 
330  systable_endscan(sscan);
331  table_close(catalog, AccessShareLock);
332  }
333  PG_CATCH();
334  {
335  /* Delete rscxt, first making sure it isn't active */
336  MemoryContextSwitchTo(oldcxt);
337  MemoryContextDelete(rscxt);
338  PG_RE_THROW();
339  }
340  PG_END_TRY();
341 
342  /* Success --- attach the policy descriptor to the relcache entry */
343  relation->rd_rsdesc = rsdesc;
344 }
345 
346 /*
347  * RemovePolicyById -
348  * remove a policy by its OID. If a policy does not exist with the provided
349  * oid, then an error is raised.
350  *
351  * policy_id - the oid of the policy.
352  */
353 void
355 {
356  Relation pg_policy_rel;
357  SysScanDesc sscan;
358  ScanKeyData skey[1];
359  HeapTuple tuple;
360  Oid relid;
361  Relation rel;
362 
363  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
364 
365  /*
366  * Find the policy to delete.
367  */
368  ScanKeyInit(&skey[0],
369  Anum_pg_policy_oid,
370  BTEqualStrategyNumber, F_OIDEQ,
371  ObjectIdGetDatum(policy_id));
372 
373  sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
374  NULL, 1, skey);
375 
376  tuple = systable_getnext(sscan);
377 
378  /* If the policy exists, then remove it, otherwise raise an error. */
379  if (!HeapTupleIsValid(tuple))
380  elog(ERROR, "could not find tuple for policy %u", policy_id);
381 
382  /*
383  * Open and exclusive-lock the relation the policy belongs to. (We need
384  * exclusive lock to lock out queries that might otherwise depend on the
385  * set of policies the rel has; furthermore we've got to hold the lock
386  * till commit.)
387  */
388  relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
389 
390  rel = table_open(relid, AccessExclusiveLock);
391  if (rel->rd_rel->relkind != RELKIND_RELATION &&
392  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
393  ereport(ERROR,
394  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
395  errmsg("\"%s\" is not a table",
396  RelationGetRelationName(rel))));
397 
399  ereport(ERROR,
400  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
401  errmsg("permission denied: \"%s\" is a system catalog",
402  RelationGetRelationName(rel))));
403 
404  CatalogTupleDelete(pg_policy_rel, &tuple->t_self);
405 
406  systable_endscan(sscan);
407 
408  /*
409  * Note that, unlike some of the other flags in pg_class, relrowsecurity
410  * is not just an indication of if policies exist. When relrowsecurity is
411  * set by a user, then all access to the relation must be through a
412  * policy. If no policy is defined for the relation then a default-deny
413  * policy is created and all records are filtered (except for queries from
414  * the owner).
415  */
417 
418  table_close(rel, NoLock);
419 
420  /* Clean up */
421  table_close(pg_policy_rel, RowExclusiveLock);
422 }
423 
424 /*
425  * RemoveRoleFromObjectPolicy -
426  * remove a role from a policy by its OID. If the role is not a member of
427  * the policy then an error is raised. False is returned to indicate that
428  * the role could not be removed due to being the only role on the policy
429  * and therefore the entire policy should be removed.
430  *
431  * Note that a warning will be thrown and true will be returned on a
432  * permission error, as the policy should not be removed in that case.
433  *
434  * roleid - the oid of the role to remove
435  * classid - should always be PolicyRelationId
436  * policy_id - the oid of the policy.
437  */
438 bool
439 RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
440 {
441  Relation pg_policy_rel;
442  SysScanDesc sscan;
443  ScanKeyData skey[1];
444  HeapTuple tuple;
445  Oid relid;
446  Relation rel;
447  ArrayType *policy_roles;
448  int num_roles;
449  Datum roles_datum;
450  bool attr_isnull;
451  bool noperm = true;
452 
453  Assert(classid == PolicyRelationId);
454 
455  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
456 
457  /*
458  * Find the policy to update.
459  */
460  ScanKeyInit(&skey[0],
461  Anum_pg_policy_oid,
462  BTEqualStrategyNumber, F_OIDEQ,
463  ObjectIdGetDatum(policy_id));
464 
465  sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
466  NULL, 1, skey);
467 
468  tuple = systable_getnext(sscan);
469 
470  /* Raise an error if we don't find the policy. */
471  if (!HeapTupleIsValid(tuple))
472  elog(ERROR, "could not find tuple for policy %u", policy_id);
473 
474  /*
475  * Open and exclusive-lock the relation the policy belongs to.
476  */
477  relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
478 
479  rel = relation_open(relid, AccessExclusiveLock);
480 
481  if (rel->rd_rel->relkind != RELKIND_RELATION &&
482  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
483  ereport(ERROR,
484  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
485  errmsg("\"%s\" is not a table",
486  RelationGetRelationName(rel))));
487 
489  ereport(ERROR,
490  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
491  errmsg("permission denied: \"%s\" is a system catalog",
492  RelationGetRelationName(rel))));
493 
494  /* Get the current set of roles */
495  roles_datum = heap_getattr(tuple,
496  Anum_pg_policy_polroles,
497  RelationGetDescr(pg_policy_rel),
498  &attr_isnull);
499 
500  Assert(!attr_isnull);
501 
502  policy_roles = DatumGetArrayTypePCopy(roles_datum);
503 
504  /* We should be removing exactly one entry from the roles array */
505  num_roles = ARR_DIMS(policy_roles)[0] - 1;
506 
507  Assert(num_roles >= 0);
508 
509  /* Must own relation. */
510  if (pg_class_ownercheck(relid, GetUserId()))
511  noperm = false; /* user is allowed to modify this policy */
512  else
514  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
515  errmsg("role \"%s\" could not be removed from policy \"%s\" on \"%s\"",
516  GetUserNameFromId(roleid, false),
517  NameStr(((Form_pg_policy) GETSTRUCT(tuple))->polname),
518  RelationGetRelationName(rel))));
519 
520  /*
521  * If multiple roles exist on this policy, then remove the one we were
522  * asked to and leave the rest.
523  */
524  if (!noperm && num_roles > 0)
525  {
526  int i,
527  j;
528  Oid *roles = (Oid *) ARR_DATA_PTR(policy_roles);
529  Datum *role_oids;
530  char *qual_value;
531  Node *qual_expr;
532  List *qual_parse_rtable = NIL;
533  char *with_check_value;
534  Node *with_check_qual;
535  List *with_check_parse_rtable = NIL;
536  Datum values[Natts_pg_policy];
537  bool isnull[Natts_pg_policy];
538  bool replaces[Natts_pg_policy];
539  Datum value_datum;
540  ArrayType *role_ids;
541  HeapTuple new_tuple;
542  ObjectAddress target;
543  ObjectAddress myself;
544 
545  /* zero-clear */
546  memset(values, 0, sizeof(values));
547  memset(replaces, 0, sizeof(replaces));
548  memset(isnull, 0, sizeof(isnull));
549 
550  /*
551  * All of the dependencies will be removed from the policy and then
552  * re-added. In order to get them correct, we need to extract out the
553  * expressions in the policy and construct a parsestate just enough to
554  * build the range table(s) to then pass to recordDependencyOnExpr().
555  */
556 
557  /* Get policy qual, to update dependencies */
558  value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
559  RelationGetDescr(pg_policy_rel), &attr_isnull);
560  if (!attr_isnull)
561  {
562  ParseState *qual_pstate;
563 
564  /* parsestate is built just to build the range table */
565  qual_pstate = make_parsestate(NULL);
566 
567  qual_value = TextDatumGetCString(value_datum);
568  qual_expr = stringToNode(qual_value);
569 
570  /* Add this rel to the parsestate's rangetable, for dependencies */
571  addRangeTableEntryForRelation(qual_pstate, rel,
573  NULL, false, false);
574 
575  qual_parse_rtable = qual_pstate->p_rtable;
576  free_parsestate(qual_pstate);
577  }
578  else
579  qual_expr = NULL;
580 
581  /* Get WITH CHECK qual, to update dependencies */
582  value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
583  RelationGetDescr(pg_policy_rel), &attr_isnull);
584  if (!attr_isnull)
585  {
586  ParseState *with_check_pstate;
587 
588  /* parsestate is built just to build the range table */
589  with_check_pstate = make_parsestate(NULL);
590 
591  with_check_value = TextDatumGetCString(value_datum);
592  with_check_qual = stringToNode(with_check_value);
593 
594  /* Add this rel to the parsestate's rangetable, for dependencies */
595  addRangeTableEntryForRelation(with_check_pstate, rel,
597  NULL, false, false);
598 
599  with_check_parse_rtable = with_check_pstate->p_rtable;
600  free_parsestate(with_check_pstate);
601  }
602  else
603  with_check_qual = NULL;
604 
605  /* Rebuild the roles array to then update the pg_policy tuple with */
606  role_oids = (Datum *) palloc(num_roles * sizeof(Datum));
607  for (i = 0, j = 0; i < ARR_DIMS(policy_roles)[0]; i++)
608  /* Copy over all of the roles which are not the one being removed */
609  if (roles[i] != roleid)
610  role_oids[j++] = ObjectIdGetDatum(roles[i]);
611 
612  /* We should have only removed the one role */
613  Assert(j == num_roles);
614 
615  /* This is the array for the new tuple */
616  role_ids = construct_array(role_oids, num_roles, OIDOID,
617  sizeof(Oid), true, 'i');
618 
619  replaces[Anum_pg_policy_polroles - 1] = true;
620  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
621 
622  new_tuple = heap_modify_tuple(tuple,
623  RelationGetDescr(pg_policy_rel),
624  values, isnull, replaces);
625  CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
626 
627  /* Remove all old dependencies. */
628  deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
629 
630  /* Record the new set of dependencies */
631  target.classId = RelationRelationId;
632  target.objectId = relid;
633  target.objectSubId = 0;
634 
635  myself.classId = PolicyRelationId;
636  myself.objectId = policy_id;
637  myself.objectSubId = 0;
638 
639  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
640 
641  if (qual_expr)
642  recordDependencyOnExpr(&myself, qual_expr, qual_parse_rtable,
644 
645  if (with_check_qual)
646  recordDependencyOnExpr(&myself, with_check_qual,
647  with_check_parse_rtable,
649 
650  /* Remove all the old shared dependencies (roles) */
651  deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
652 
653  /* Record the new shared dependencies (roles) */
654  target.classId = AuthIdRelationId;
655  target.objectSubId = 0;
656  for (i = 0; i < num_roles; i++)
657  {
658  target.objectId = DatumGetObjectId(role_oids[i]);
659  /* no need for dependency on the public role */
660  if (target.objectId != ACL_ID_PUBLIC)
661  recordSharedDependencyOn(&myself, &target,
663  }
664 
665  InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
666 
667  heap_freetuple(new_tuple);
668 
669  /* Invalidate Relation Cache */
671  }
672 
673  /* Clean up. */
674  systable_endscan(sscan);
675 
676  relation_close(rel, NoLock);
677 
678  table_close(pg_policy_rel, RowExclusiveLock);
679 
680  return (noperm || num_roles > 0);
681 }
682 
683 /*
684  * CreatePolicy -
685  * handles the execution of the CREATE POLICY command.
686  *
687  * stmt - the CreatePolicyStmt that describes the policy to create.
688  */
691 {
692  Relation pg_policy_rel;
693  Oid policy_id;
694  Relation target_table;
695  Oid table_id;
696  char polcmd;
697  Datum *role_oids;
698  int nitems = 0;
699  ArrayType *role_ids;
700  ParseState *qual_pstate;
701  ParseState *with_check_pstate;
702  RangeTblEntry *rte;
703  Node *qual;
704  Node *with_check_qual;
705  ScanKeyData skey[2];
706  SysScanDesc sscan;
707  HeapTuple policy_tuple;
708  Datum values[Natts_pg_policy];
709  bool isnull[Natts_pg_policy];
710  ObjectAddress target;
711  ObjectAddress myself;
712  int i;
713 
714  /* Parse command */
715  polcmd = parse_policy_command(stmt->cmd_name);
716 
717  /*
718  * If the command is SELECT or DELETE then WITH CHECK should be NULL.
719  */
720  if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
721  && stmt->with_check != NULL)
722  ereport(ERROR,
723  (errcode(ERRCODE_SYNTAX_ERROR),
724  errmsg("WITH CHECK cannot be applied to SELECT or DELETE")));
725 
726  /*
727  * If the command is INSERT then WITH CHECK should be the only expression
728  * provided.
729  */
730  if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL)
731  ereport(ERROR,
732  (errcode(ERRCODE_SYNTAX_ERROR),
733  errmsg("only WITH CHECK expression allowed for INSERT")));
734 
735  /* Collect role ids */
736  role_oids = policy_role_list_to_array(stmt->roles, &nitems);
737  role_ids = construct_array(role_oids, nitems, OIDOID,
738  sizeof(Oid), true, 'i');
739 
740  /* Parse the supplied clause */
741  qual_pstate = make_parsestate(NULL);
742  with_check_pstate = make_parsestate(NULL);
743 
744  /* zero-clear */
745  memset(values, 0, sizeof(values));
746  memset(isnull, 0, sizeof(isnull));
747 
748  /* Get id of table. Also handles permissions checks. */
750  0,
752  (void *) stmt);
753 
754  /* Open target_table to build quals. No additional lock is necessary. */
755  target_table = relation_open(table_id, NoLock);
756 
757  /* Add for the regular security quals */
758  rte = addRangeTableEntryForRelation(qual_pstate, target_table,
760  NULL, false, false);
761  addRTEtoQuery(qual_pstate, rte, false, true, true);
762 
763  /* Add for the with-check quals */
764  rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
766  NULL, false, false);
767  addRTEtoQuery(with_check_pstate, rte, false, true, true);
768 
769  qual = transformWhereClause(qual_pstate,
770  copyObject(stmt->qual),
772  "POLICY");
773 
774  with_check_qual = transformWhereClause(with_check_pstate,
775  copyObject(stmt->with_check),
777  "POLICY");
778 
779  /* Fix up collation information */
780  assign_expr_collations(qual_pstate, qual);
781  assign_expr_collations(with_check_pstate, with_check_qual);
782 
783  /* Open pg_policy catalog */
784  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
785 
786  /* Set key - policy's relation id. */
787  ScanKeyInit(&skey[0],
788  Anum_pg_policy_polrelid,
789  BTEqualStrategyNumber, F_OIDEQ,
790  ObjectIdGetDatum(table_id));
791 
792  /* Set key - policy's name. */
793  ScanKeyInit(&skey[1],
794  Anum_pg_policy_polname,
795  BTEqualStrategyNumber, F_NAMEEQ,
796  CStringGetDatum(stmt->policy_name));
797 
798  sscan = systable_beginscan(pg_policy_rel,
799  PolicyPolrelidPolnameIndexId, true, NULL, 2,
800  skey);
801 
802  policy_tuple = systable_getnext(sscan);
803 
804  /* Complain if the policy name already exists for the table */
805  if (HeapTupleIsValid(policy_tuple))
806  ereport(ERROR,
808  errmsg("policy \"%s\" for table \"%s\" already exists",
809  stmt->policy_name, RelationGetRelationName(target_table))));
810 
811  policy_id = GetNewOidWithIndex(pg_policy_rel, PolicyOidIndexId,
812  Anum_pg_policy_oid);
813  values[Anum_pg_policy_oid - 1] = ObjectIdGetDatum(policy_id);
814  values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
815  values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein,
816  CStringGetDatum(stmt->policy_name));
817  values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
818  values[Anum_pg_policy_polpermissive - 1] = BoolGetDatum(stmt->permissive);
819  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
820 
821  /* Add qual if present. */
822  if (qual)
823  values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual));
824  else
825  isnull[Anum_pg_policy_polqual - 1] = true;
826 
827  /* Add WITH CHECK qual if present */
828  if (with_check_qual)
829  values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual));
830  else
831  isnull[Anum_pg_policy_polwithcheck - 1] = true;
832 
833  policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values,
834  isnull);
835 
836  CatalogTupleInsert(pg_policy_rel, policy_tuple);
837 
838  /* Record Dependencies */
839  target.classId = RelationRelationId;
840  target.objectId = table_id;
841  target.objectSubId = 0;
842 
843  myself.classId = PolicyRelationId;
844  myself.objectId = policy_id;
845  myself.objectSubId = 0;
846 
847  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
848 
849  recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable,
851 
852  recordDependencyOnExpr(&myself, with_check_qual,
853  with_check_pstate->p_rtable, DEPENDENCY_NORMAL);
854 
855  /* Register role dependencies */
856  target.classId = AuthIdRelationId;
857  target.objectSubId = 0;
858  for (i = 0; i < nitems; i++)
859  {
860  target.objectId = DatumGetObjectId(role_oids[i]);
861  /* no dependency if public */
862  if (target.objectId != ACL_ID_PUBLIC)
863  recordSharedDependencyOn(&myself, &target,
865  }
866 
867  InvokeObjectPostCreateHook(PolicyRelationId, policy_id, 0);
868 
869  /* Invalidate Relation Cache */
870  CacheInvalidateRelcache(target_table);
871 
872  /* Clean up. */
873  heap_freetuple(policy_tuple);
874  free_parsestate(qual_pstate);
875  free_parsestate(with_check_pstate);
876  systable_endscan(sscan);
877  relation_close(target_table, NoLock);
878  table_close(pg_policy_rel, RowExclusiveLock);
879 
880  return myself;
881 }
882 
883 /*
884  * AlterPolicy -
885  * handles the execution of the ALTER POLICY command.
886  *
887  * stmt - the AlterPolicyStmt that describes the policy and how to alter it.
888  */
891 {
892  Relation pg_policy_rel;
893  Oid policy_id;
894  Relation target_table;
895  Oid table_id;
896  Datum *role_oids = NULL;
897  int nitems = 0;
898  ArrayType *role_ids = NULL;
899  List *qual_parse_rtable = NIL;
900  List *with_check_parse_rtable = NIL;
901  Node *qual = NULL;
902  Node *with_check_qual = NULL;
903  ScanKeyData skey[2];
904  SysScanDesc sscan;
905  HeapTuple policy_tuple;
906  HeapTuple new_tuple;
907  Datum values[Natts_pg_policy];
908  bool isnull[Natts_pg_policy];
909  bool replaces[Natts_pg_policy];
910  ObjectAddress target;
911  ObjectAddress myself;
912  Datum polcmd_datum;
913  char polcmd;
914  bool polcmd_isnull;
915  int i;
916 
917  /* Parse role_ids */
918  if (stmt->roles != NULL)
919  {
920  role_oids = policy_role_list_to_array(stmt->roles, &nitems);
921  role_ids = construct_array(role_oids, nitems, OIDOID,
922  sizeof(Oid), true, 'i');
923  }
924 
925  /* Get id of table. Also handles permissions checks. */
927  0,
929  (void *) stmt);
930 
931  target_table = relation_open(table_id, NoLock);
932 
933  /* Parse the using policy clause */
934  if (stmt->qual)
935  {
936  RangeTblEntry *rte;
937  ParseState *qual_pstate = make_parsestate(NULL);
938 
939  rte = addRangeTableEntryForRelation(qual_pstate, target_table,
941  NULL, false, false);
942 
943  addRTEtoQuery(qual_pstate, rte, false, true, true);
944 
945  qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
947  "POLICY");
948 
949  /* Fix up collation information */
950  assign_expr_collations(qual_pstate, qual);
951 
952  qual_parse_rtable = qual_pstate->p_rtable;
953  free_parsestate(qual_pstate);
954  }
955 
956  /* Parse the with-check policy clause */
957  if (stmt->with_check)
958  {
959  RangeTblEntry *rte;
960  ParseState *with_check_pstate = make_parsestate(NULL);
961 
962  rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
964  NULL, false, false);
965 
966  addRTEtoQuery(with_check_pstate, rte, false, true, true);
967 
968  with_check_qual = transformWhereClause(with_check_pstate,
969  copyObject(stmt->with_check),
971  "POLICY");
972 
973  /* Fix up collation information */
974  assign_expr_collations(with_check_pstate, with_check_qual);
975 
976  with_check_parse_rtable = with_check_pstate->p_rtable;
977  free_parsestate(with_check_pstate);
978  }
979 
980  /* zero-clear */
981  memset(values, 0, sizeof(values));
982  memset(replaces, 0, sizeof(replaces));
983  memset(isnull, 0, sizeof(isnull));
984 
985  /* Find policy to update. */
986  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
987 
988  /* Set key - policy's relation id. */
989  ScanKeyInit(&skey[0],
990  Anum_pg_policy_polrelid,
991  BTEqualStrategyNumber, F_OIDEQ,
992  ObjectIdGetDatum(table_id));
993 
994  /* Set key - policy's name. */
995  ScanKeyInit(&skey[1],
996  Anum_pg_policy_polname,
997  BTEqualStrategyNumber, F_NAMEEQ,
998  CStringGetDatum(stmt->policy_name));
999 
1000  sscan = systable_beginscan(pg_policy_rel,
1001  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1002  skey);
1003 
1004  policy_tuple = systable_getnext(sscan);
1005 
1006  /* Check that the policy is found, raise an error if not. */
1007  if (!HeapTupleIsValid(policy_tuple))
1008  ereport(ERROR,
1009  (errcode(ERRCODE_UNDEFINED_OBJECT),
1010  errmsg("policy \"%s\" for table \"%s\" does not exist",
1011  stmt->policy_name,
1012  RelationGetRelationName(target_table))));
1013 
1014  /* Get policy command */
1015  polcmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
1016  RelationGetDescr(pg_policy_rel),
1017  &polcmd_isnull);
1018  Assert(!polcmd_isnull);
1019  polcmd = DatumGetChar(polcmd_datum);
1020 
1021  /*
1022  * If the command is SELECT or DELETE then WITH CHECK should be NULL.
1023  */
1024  if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
1025  && stmt->with_check != NULL)
1026  ereport(ERROR,
1027  (errcode(ERRCODE_SYNTAX_ERROR),
1028  errmsg("only USING expression allowed for SELECT, DELETE")));
1029 
1030  /*
1031  * If the command is INSERT then WITH CHECK should be the only expression
1032  * provided.
1033  */
1034  if ((polcmd == ACL_INSERT_CHR)
1035  && stmt->qual != NULL)
1036  ereport(ERROR,
1037  (errcode(ERRCODE_SYNTAX_ERROR),
1038  errmsg("only WITH CHECK expression allowed for INSERT")));
1039 
1040  policy_id = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
1041 
1042  if (role_ids != NULL)
1043  {
1044  replaces[Anum_pg_policy_polroles - 1] = true;
1045  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
1046  }
1047  else
1048  {
1049  Oid *roles;
1050  Datum roles_datum;
1051  bool attr_isnull;
1052  ArrayType *policy_roles;
1053 
1054  /*
1055  * We need to pull the set of roles this policy applies to from what's
1056  * in the catalog, so that we can recreate the dependencies correctly
1057  * for the policy.
1058  */
1059 
1060  roles_datum = heap_getattr(policy_tuple, Anum_pg_policy_polroles,
1061  RelationGetDescr(pg_policy_rel),
1062  &attr_isnull);
1063  Assert(!attr_isnull);
1064 
1065  policy_roles = DatumGetArrayTypePCopy(roles_datum);
1066 
1067  roles = (Oid *) ARR_DATA_PTR(policy_roles);
1068 
1069  nitems = ARR_DIMS(policy_roles)[0];
1070 
1071  role_oids = (Datum *) palloc(nitems * sizeof(Datum));
1072 
1073  for (i = 0; i < nitems; i++)
1074  role_oids[i] = ObjectIdGetDatum(roles[i]);
1075  }
1076 
1077  if (qual != NULL)
1078  {
1079  replaces[Anum_pg_policy_polqual - 1] = true;
1080  values[Anum_pg_policy_polqual - 1]
1082  }
1083  else
1084  {
1085  Datum value_datum;
1086  bool attr_isnull;
1087 
1088  /*
1089  * We need to pull the USING expression and build the range table for
1090  * the policy from what's in the catalog, so that we can recreate the
1091  * dependencies correctly for the policy.
1092  */
1093 
1094  /* Check if the policy has a USING expr */
1095  value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polqual,
1096  RelationGetDescr(pg_policy_rel),
1097  &attr_isnull);
1098  if (!attr_isnull)
1099  {
1100  char *qual_value;
1101  ParseState *qual_pstate;
1102 
1103  /* parsestate is built just to build the range table */
1104  qual_pstate = make_parsestate(NULL);
1105 
1106  qual_value = TextDatumGetCString(value_datum);
1107  qual = stringToNode(qual_value);
1108 
1109  /* Add this rel to the parsestate's rangetable, for dependencies */
1110  addRangeTableEntryForRelation(qual_pstate, target_table,
1112  NULL, false, false);
1113 
1114  qual_parse_rtable = qual_pstate->p_rtable;
1115  free_parsestate(qual_pstate);
1116  }
1117  }
1118 
1119  if (with_check_qual != NULL)
1120  {
1121  replaces[Anum_pg_policy_polwithcheck - 1] = true;
1122  values[Anum_pg_policy_polwithcheck - 1]
1123  = CStringGetTextDatum(nodeToString(with_check_qual));
1124  }
1125  else
1126  {
1127  Datum value_datum;
1128  bool attr_isnull;
1129 
1130  /*
1131  * We need to pull the WITH CHECK expression and build the range table
1132  * for the policy from what's in the catalog, so that we can recreate
1133  * the dependencies correctly for the policy.
1134  */
1135 
1136  /* Check if the policy has a WITH CHECK expr */
1137  value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polwithcheck,
1138  RelationGetDescr(pg_policy_rel),
1139  &attr_isnull);
1140  if (!attr_isnull)
1141  {
1142  char *with_check_value;
1143  ParseState *with_check_pstate;
1144 
1145  /* parsestate is built just to build the range table */
1146  with_check_pstate = make_parsestate(NULL);
1147 
1148  with_check_value = TextDatumGetCString(value_datum);
1149  with_check_qual = stringToNode(with_check_value);
1150 
1151  /* Add this rel to the parsestate's rangetable, for dependencies */
1152  addRangeTableEntryForRelation(with_check_pstate, target_table,
1154  NULL, false, false);
1155 
1156  with_check_parse_rtable = with_check_pstate->p_rtable;
1157  free_parsestate(with_check_pstate);
1158  }
1159  }
1160 
1161  new_tuple = heap_modify_tuple(policy_tuple,
1162  RelationGetDescr(pg_policy_rel),
1163  values, isnull, replaces);
1164  CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
1165 
1166  /* Update Dependencies. */
1167  deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
1168 
1169  /* Record Dependencies */
1170  target.classId = RelationRelationId;
1171  target.objectId = table_id;
1172  target.objectSubId = 0;
1173 
1174  myself.classId = PolicyRelationId;
1175  myself.objectId = policy_id;
1176  myself.objectSubId = 0;
1177 
1178  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
1179 
1180  recordDependencyOnExpr(&myself, qual, qual_parse_rtable, DEPENDENCY_NORMAL);
1181 
1182  recordDependencyOnExpr(&myself, with_check_qual, with_check_parse_rtable,
1184 
1185  /* Register role dependencies */
1186  deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
1187  target.classId = AuthIdRelationId;
1188  target.objectSubId = 0;
1189  for (i = 0; i < nitems; i++)
1190  {
1191  target.objectId = DatumGetObjectId(role_oids[i]);
1192  /* no dependency if public */
1193  if (target.objectId != ACL_ID_PUBLIC)
1194  recordSharedDependencyOn(&myself, &target,
1196  }
1197 
1198  InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
1199 
1200  heap_freetuple(new_tuple);
1201 
1202  /* Invalidate Relation Cache */
1203  CacheInvalidateRelcache(target_table);
1204 
1205  /* Clean up. */
1206  systable_endscan(sscan);
1207  relation_close(target_table, NoLock);
1208  table_close(pg_policy_rel, RowExclusiveLock);
1209 
1210  return myself;
1211 }
1212 
1213 /*
1214  * rename_policy -
1215  * change the name of a policy on a relation
1216  */
1219 {
1220  Relation pg_policy_rel;
1221  Relation target_table;
1222  Oid table_id;
1223  Oid opoloid;
1224  ScanKeyData skey[2];
1225  SysScanDesc sscan;
1226  HeapTuple policy_tuple;
1227  ObjectAddress address;
1228 
1229  /* Get id of table. Also handles permissions checks. */
1231  0,
1233  (void *) stmt);
1234 
1235  target_table = relation_open(table_id, NoLock);
1236 
1237  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
1238 
1239  /* First pass -- check for conflict */
1240 
1241  /* Add key - policy's relation id. */
1242  ScanKeyInit(&skey[0],
1243  Anum_pg_policy_polrelid,
1244  BTEqualStrategyNumber, F_OIDEQ,
1245  ObjectIdGetDatum(table_id));
1246 
1247  /* Add key - policy's name. */
1248  ScanKeyInit(&skey[1],
1249  Anum_pg_policy_polname,
1250  BTEqualStrategyNumber, F_NAMEEQ,
1251  CStringGetDatum(stmt->newname));
1252 
1253  sscan = systable_beginscan(pg_policy_rel,
1254  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1255  skey);
1256 
1257  if (HeapTupleIsValid(systable_getnext(sscan)))
1258  ereport(ERROR,
1260  errmsg("policy \"%s\" for table \"%s\" already exists",
1261  stmt->newname, RelationGetRelationName(target_table))));
1262 
1263  systable_endscan(sscan);
1264 
1265  /* Second pass -- find existing policy and update */
1266  /* Add key - policy's relation id. */
1267  ScanKeyInit(&skey[0],
1268  Anum_pg_policy_polrelid,
1269  BTEqualStrategyNumber, F_OIDEQ,
1270  ObjectIdGetDatum(table_id));
1271 
1272  /* Add key - policy's name. */
1273  ScanKeyInit(&skey[1],
1274  Anum_pg_policy_polname,
1275  BTEqualStrategyNumber, F_NAMEEQ,
1276  CStringGetDatum(stmt->subname));
1277 
1278  sscan = systable_beginscan(pg_policy_rel,
1279  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1280  skey);
1281 
1282  policy_tuple = systable_getnext(sscan);
1283 
1284  /* Complain if we did not find the policy */
1285  if (!HeapTupleIsValid(policy_tuple))
1286  ereport(ERROR,
1287  (errcode(ERRCODE_UNDEFINED_OBJECT),
1288  errmsg("policy \"%s\" for table \"%s\" does not exist",
1289  stmt->subname, RelationGetRelationName(target_table))));
1290 
1291  opoloid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
1292 
1293  policy_tuple = heap_copytuple(policy_tuple);
1294 
1295  namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname,
1296  stmt->newname);
1297 
1298  CatalogTupleUpdate(pg_policy_rel, &policy_tuple->t_self, policy_tuple);
1299 
1300  InvokeObjectPostAlterHook(PolicyRelationId, opoloid, 0);
1301 
1302  ObjectAddressSet(address, PolicyRelationId, opoloid);
1303 
1304  /*
1305  * Invalidate relation's relcache entry so that other backends (and this
1306  * one too!) are sent SI message to make them rebuild relcache entries.
1307  * (Ideally this should happen automatically...)
1308  */
1309  CacheInvalidateRelcache(target_table);
1310 
1311  /* Clean up. */
1312  systable_endscan(sscan);
1313  table_close(pg_policy_rel, RowExclusiveLock);
1314  relation_close(target_table, NoLock);
1315 
1316  return address;
1317 }
1318 
1319 /*
1320  * get_relation_policy_oid - Look up a policy by name to find its OID
1321  *
1322  * If missing_ok is false, throw an error if policy not found. If
1323  * true, just return InvalidOid.
1324  */
1325 Oid
1326 get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
1327 {
1328  Relation pg_policy_rel;
1329  ScanKeyData skey[2];
1330  SysScanDesc sscan;
1331  HeapTuple policy_tuple;
1332  Oid policy_oid;
1333 
1334  pg_policy_rel = table_open(PolicyRelationId, AccessShareLock);
1335 
1336  /* Add key - policy's relation id. */
1337  ScanKeyInit(&skey[0],
1338  Anum_pg_policy_polrelid,
1339  BTEqualStrategyNumber, F_OIDEQ,
1340  ObjectIdGetDatum(relid));
1341 
1342  /* Add key - policy's name. */
1343  ScanKeyInit(&skey[1],
1344  Anum_pg_policy_polname,
1345  BTEqualStrategyNumber, F_NAMEEQ,
1346  CStringGetDatum(policy_name));
1347 
1348  sscan = systable_beginscan(pg_policy_rel,
1349  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1350  skey);
1351 
1352  policy_tuple = systable_getnext(sscan);
1353 
1354  if (!HeapTupleIsValid(policy_tuple))
1355  {
1356  if (!missing_ok)
1357  ereport(ERROR,
1358  (errcode(ERRCODE_UNDEFINED_OBJECT),
1359  errmsg("policy \"%s\" for table \"%s\" does not exist",
1360  policy_name, get_rel_name(relid))));
1361 
1362  policy_oid = InvalidOid;
1363  }
1364  else
1365  policy_oid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
1366 
1367  /* Clean up. */
1368  systable_endscan(sscan);
1369  table_close(pg_policy_rel, AccessShareLock);
1370 
1371  return policy_oid;
1372 }
1373 
1374 /*
1375  * relation_has_policies - Determine if relation has any policies
1376  */
1377 bool
1379 {
1380  Relation catalog;
1381  ScanKeyData skey;
1382  SysScanDesc sscan;
1383  HeapTuple policy_tuple;
1384  bool ret = false;
1385 
1386  catalog = table_open(PolicyRelationId, AccessShareLock);
1387  ScanKeyInit(&skey,
1388  Anum_pg_policy_polrelid,
1389  BTEqualStrategyNumber, F_OIDEQ,
1391  sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
1392  NULL, 1, &skey);
1393  policy_tuple = systable_getnext(sscan);
1394  if (HeapTupleIsValid(policy_tuple))
1395  ret = true;
1396 
1397  systable_endscan(sscan);
1398  table_close(catalog, AccessShareLock);
1399 
1400  return ret;
1401 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define NIL
Definition: pg_list.h:65
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
#define ACL_INSERT_CHR
Definition: acl.h:137
void recordSharedDependencyOn(ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype)
Definition: pg_shdepend.c:121
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:169
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:974
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
bool IsSystemRelation(Relation relation)
Definition: catalog.c:70
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
#define RelationGetDescr(relation)
Definition: rel.h:442
Oid GetUserId(void)
Definition: miscinit.c:380
void RelationBuildRowSecurity(Relation relation)
Definition: policy.c:192
#define PolicyOidIndexId
Definition: indexing.h:334
#define PointerGetDatum(X)
Definition: postgres.h:556
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define DatumGetObjectId(X)
Definition: postgres.h:500
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:201
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:190
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define ACL_DELETE_CHR
Definition: acl.h:140
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
void * stringToNode(const char *str)
Definition: read.c:89
static char parse_policy_command(const char *cmd_name)
Definition: policy.c:110
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:616
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
RangeVar * table
Definition: parsenodes.h:2382
char relkind
Definition: pg_class.h:81
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:82
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
bool RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
Definition: policy.c:439
void assign_expr_collations(ParseState *pstate, Node *expr)
#define DatumGetName(X)
Definition: postgres.h:585
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
ObjectAddress AlterPolicy(AlterPolicyStmt *stmt)
Definition: policy.c:890
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ObjectAddress rename_policy(RenameStmt *stmt)
Definition: policy.c:1218
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define ARR_DIMS(a)
Definition: array.h:282
ObjectAddress CreatePolicy(CreatePolicyStmt *stmt)
Definition: policy.c:690
ItemPointerData t_self
Definition: htup.h:65
void RemovePolicyById(Oid policy_id)
Definition: policy.c:354
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:96
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
#define CStringGetDatum(X)
Definition: postgres.h:578
Expr * with_check_qual
Definition: rowsecurity.h:27
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1586
#define DatumGetBool(X)
Definition: postgres.h:393
#define RelationGetRelationName(relation)
Definition: rel.h:450
ArrayType * roles
Definition: rowsecurity.h:24
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define PolicyPolrelidPolnameIndexId
Definition: indexing.h:337
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:91
#define ereport(elevel, rest)
Definition: elog.h:141
MemoryContext rscxt
Definition: rowsecurity.h:33
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:908
#define WARNING
Definition: elog.h:40
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
#define ACL_SELECT_CHR
Definition: acl.h:138
#define TextDatumGetCString(d)
Definition: builtins.h:84
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
RoleSpecType roletype
Definition: parsenodes.h:328
#define DatumGetChar(X)
Definition: postgres.h:409
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5225
#define DatumGetArrayTypePCopy(X)
Definition: array.h:250
RangeVar * relation
Definition: parsenodes.h:2881
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
#define BoolGetDatum(X)
Definition: postgres.h:402
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
FormData_pg_policy * Form_pg_policy
Definition: pg_policy.h:50
List * lcons(void *datum, List *list)
Definition: list.c:453
#define PG_CATCH()
Definition: elog.h:310
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:795
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
Oid get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
Definition: policy.c:1326
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4755
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
static Datum * policy_role_list_to_array(List *roles, int *num_roles)
Definition: policy.c:139
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static int list_length(const List *l)
Definition: pg_list.h:169
#define ACL_UPDATE_CHR
Definition: acl.h:139
#define PG_RE_THROW()
Definition: elog.h:331
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
RangeVar * table
Definition: parsenodes.h:2366
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1270
static Datum values[MAXATTR]
Definition: bootstrap.c:167
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#define AccessExclusiveLock
Definition: lockdefs.h:45
bool relation_has_policies(Relation rel)
Definition: policy.c:1378
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
static void RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: policy.c:66
#define elog(elevel,...)
Definition: elog.h:226
int i
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:609
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:83
char * nodeToString(const void *obj)
Definition: outfuncs.c:4303
#define ACL_ID_PUBLIC
Definition: acl.h:46
void * arg
#define copyObject(obj)
Definition: nodes.h:640
#define PG_TRY()
Definition: elog.h:301
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define RelationGetRelid(relation)
Definition: rel.h:416
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define PG_END_TRY()
Definition: elog.h:317
#define BTEqualStrategyNumber
Definition: stratnum.h:31
MemoryContext CacheMemoryContext
Definition: mcxt.c:47
List * p_rtable
Definition: parse_node.h:177