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