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-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  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
479  ereport(ERROR,
480  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
481  errmsg("\"%s\" is not a table",
482  RelationGetRelationName(rel))));
483 
485  ereport(ERROR,
486  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
487  errmsg("permission denied: \"%s\" is a system catalog",
488  RelationGetRelationName(rel))));
489 
490  /* Get the current set of roles */
491  roles_datum = heap_getattr(tuple,
493  RelationGetDescr(pg_policy_rel),
494  &attr_isnull);
495 
496  Assert(!attr_isnull);
497 
498  policy_roles = DatumGetArrayTypePCopy(roles_datum);
499 
500  /* We should be removing exactly one entry from the roles array */
501  num_roles = ARR_DIMS(policy_roles)[0] - 1;
502 
503  Assert(num_roles >= 0);
504 
505  /* Must own relation. */
506  if (pg_class_ownercheck(relid, GetUserId()))
507  noperm = false; /* user is allowed to modify this policy */
508  else
510  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
511  errmsg("role \"%s\" could not be removed from policy \"%s\" on \"%s\"",
512  GetUserNameFromId(roleid, false),
513  NameStr(((Form_pg_policy) GETSTRUCT(tuple))->polname),
514  RelationGetRelationName(rel))));
515 
516  /*
517  * If multiple roles exist on this policy, then remove the one we were
518  * asked to and leave the rest.
519  */
520  if (!noperm && num_roles > 0)
521  {
522  int i,
523  j;
524  Oid *roles = (Oid *) ARR_DATA_PTR(policy_roles);
525  Datum *role_oids;
526  char *qual_value;
527  Node *qual_expr;
528  List *qual_parse_rtable = NIL;
529  char *with_check_value;
530  Node *with_check_qual;
531  List *with_check_parse_rtable = NIL;
533  bool isnull[Natts_pg_policy];
534  bool replaces[Natts_pg_policy];
535  Datum value_datum;
536  ArrayType *role_ids;
537  HeapTuple new_tuple;
538  ObjectAddress target;
539  ObjectAddress myself;
540 
541  /* zero-clear */
542  memset(values, 0, sizeof(values));
543  memset(replaces, 0, sizeof(replaces));
544  memset(isnull, 0, sizeof(isnull));
545 
546  /*
547  * All of the dependencies will be removed from the policy and then
548  * re-added. In order to get them correct, we need to extract out the
549  * expressions in the policy and construct a parsestate just enough to
550  * build the range table(s) to then pass to recordDependencyOnExpr().
551  */
552 
553  /* Get policy qual, to update dependencies */
554  value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
555  RelationGetDescr(pg_policy_rel), &attr_isnull);
556  if (!attr_isnull)
557  {
558  ParseState *qual_pstate;
559 
560  /* parsestate is built just to build the range table */
561  qual_pstate = make_parsestate(NULL);
562 
563  qual_value = TextDatumGetCString(value_datum);
564  qual_expr = stringToNode(qual_value);
565 
566  /* Add this rel to the parsestate's rangetable, for dependencies */
567  addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
568 
569  qual_parse_rtable = qual_pstate->p_rtable;
570  free_parsestate(qual_pstate);
571  }
572  else
573  qual_expr = NULL;
574 
575  /* Get WITH CHECK qual, to update dependencies */
576  value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
577  RelationGetDescr(pg_policy_rel), &attr_isnull);
578  if (!attr_isnull)
579  {
580  ParseState *with_check_pstate;
581 
582  /* parsestate is built just to build the range table */
583  with_check_pstate = make_parsestate(NULL);
584 
585  with_check_value = TextDatumGetCString(value_datum);
586  with_check_qual = stringToNode(with_check_value);
587 
588  /* Add this rel to the parsestate's rangetable, for dependencies */
589  addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
590  false);
591 
592  with_check_parse_rtable = with_check_pstate->p_rtable;
593  free_parsestate(with_check_pstate);
594  }
595  else
596  with_check_qual = NULL;
597 
598  /* Rebuild the roles array to then update the pg_policy tuple with */
599  role_oids = (Datum *) palloc(num_roles * sizeof(Datum));
600  for (i = 0, j = 0; i < ARR_DIMS(policy_roles)[0]; i++)
601  /* Copy over all of the roles which are not the one being removed */
602  if (roles[i] != roleid)
603  role_oids[j++] = ObjectIdGetDatum(roles[i]);
604 
605  /* We should have only removed the one role */
606  Assert(j == num_roles);
607 
608  /* This is the array for the new tuple */
609  role_ids = construct_array(role_oids, num_roles, OIDOID,
610  sizeof(Oid), true, 'i');
611 
612  replaces[Anum_pg_policy_polroles - 1] = true;
613  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
614 
615  new_tuple = heap_modify_tuple(tuple,
616  RelationGetDescr(pg_policy_rel),
617  values, isnull, replaces);
618  CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
619 
620  /* Remove all old dependencies. */
621  deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
622 
623  /* Record the new set of dependencies */
624  target.classId = RelationRelationId;
625  target.objectId = relid;
626  target.objectSubId = 0;
627 
628  myself.classId = PolicyRelationId;
629  myself.objectId = policy_id;
630  myself.objectSubId = 0;
631 
632  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
633 
634  if (qual_expr)
635  recordDependencyOnExpr(&myself, qual_expr, qual_parse_rtable,
637 
638  if (with_check_qual)
639  recordDependencyOnExpr(&myself, with_check_qual,
640  with_check_parse_rtable,
642 
643  /* Remove all the old shared dependencies (roles) */
645 
646  /* Record the new shared dependencies (roles) */
647  target.classId = AuthIdRelationId;
648  target.objectSubId = 0;
649  for (i = 0; i < num_roles; i++)
650  {
651  target.objectId = DatumGetObjectId(role_oids[i]);
652  /* no need for dependency on the public role */
653  if (target.objectId != ACL_ID_PUBLIC)
654  recordSharedDependencyOn(&myself, &target,
656  }
657 
659 
660  heap_freetuple(new_tuple);
661 
662  /* Invalidate Relation Cache */
664  }
665 
666  /* Clean up. */
667  systable_endscan(sscan);
668 
669  relation_close(rel, NoLock);
670 
671  heap_close(pg_policy_rel, RowExclusiveLock);
672 
673  return (noperm || num_roles > 0);
674 }
675 
676 /*
677  * CreatePolicy -
678  * handles the execution of the CREATE POLICY command.
679  *
680  * stmt - the CreatePolicyStmt that describes the policy to create.
681  */
684 {
685  Relation pg_policy_rel;
686  Oid policy_id;
687  Relation target_table;
688  Oid table_id;
689  char polcmd;
690  Datum *role_oids;
691  int nitems = 0;
692  ArrayType *role_ids;
693  ParseState *qual_pstate;
694  ParseState *with_check_pstate;
695  RangeTblEntry *rte;
696  Node *qual;
697  Node *with_check_qual;
698  ScanKeyData skey[2];
699  SysScanDesc sscan;
700  HeapTuple policy_tuple;
702  bool isnull[Natts_pg_policy];
703  ObjectAddress target;
704  ObjectAddress myself;
705  int i;
706 
707  /* Parse command */
708  polcmd = parse_policy_command(stmt->cmd_name);
709 
710  /*
711  * If the command is SELECT or DELETE then WITH CHECK should be NULL.
712  */
713  if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
714  && stmt->with_check != NULL)
715  ereport(ERROR,
716  (errcode(ERRCODE_SYNTAX_ERROR),
717  errmsg("WITH CHECK cannot be applied to SELECT or DELETE")));
718 
719  /*
720  * If the command is INSERT then WITH CHECK should be the only expression
721  * provided.
722  */
723  if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL)
724  ereport(ERROR,
725  (errcode(ERRCODE_SYNTAX_ERROR),
726  errmsg("only WITH CHECK expression allowed for INSERT")));
727 
728  /* Collect role ids */
729  role_oids = policy_role_list_to_array(stmt->roles, &nitems);
730  role_ids = construct_array(role_oids, nitems, OIDOID,
731  sizeof(Oid), true, 'i');
732 
733  /* Parse the supplied clause */
734  qual_pstate = make_parsestate(NULL);
735  with_check_pstate = make_parsestate(NULL);
736 
737  /* zero-clear */
738  memset(values, 0, sizeof(values));
739  memset(isnull, 0, sizeof(isnull));
740 
741  /* Get id of table. Also handles permissions checks. */
743  false, false,
745  (void *) stmt);
746 
747  /* Open target_table to build quals. No additional lock is necessary. */
748  target_table = relation_open(table_id, NoLock);
749 
750  /* Add for the regular security quals */
751  rte = addRangeTableEntryForRelation(qual_pstate, target_table,
752  NULL, false, false);
753  addRTEtoQuery(qual_pstate, rte, false, true, true);
754 
755  /* Add for the with-check quals */
756  rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
757  NULL, false, false);
758  addRTEtoQuery(with_check_pstate, rte, false, true, true);
759 
760  qual = transformWhereClause(qual_pstate,
761  copyObject(stmt->qual),
763  "POLICY");
764 
765  with_check_qual = transformWhereClause(with_check_pstate,
766  copyObject(stmt->with_check),
768  "POLICY");
769 
770  /* Fix up collation information */
771  assign_expr_collations(qual_pstate, qual);
772  assign_expr_collations(with_check_pstate, with_check_qual);
773 
774  /* Open pg_policy catalog */
775  pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
776 
777  /* Set key - policy's relation id. */
778  ScanKeyInit(&skey[0],
780  BTEqualStrategyNumber, F_OIDEQ,
781  ObjectIdGetDatum(table_id));
782 
783  /* Set key - policy's name. */
784  ScanKeyInit(&skey[1],
786  BTEqualStrategyNumber, F_NAMEEQ,
787  CStringGetDatum(stmt->policy_name));
788 
789  sscan = systable_beginscan(pg_policy_rel,
790  PolicyPolrelidPolnameIndexId, true, NULL, 2,
791  skey);
792 
793  policy_tuple = systable_getnext(sscan);
794 
795  /* Complain if the policy name already exists for the table */
796  if (HeapTupleIsValid(policy_tuple))
797  ereport(ERROR,
799  errmsg("policy \"%s\" for table \"%s\" already exists",
800  stmt->policy_name, RelationGetRelationName(target_table))));
801 
802  values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
804  CStringGetDatum(stmt->policy_name));
805  values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
806  values[Anum_pg_policy_polpermissive - 1] = BoolGetDatum(stmt->permissive);
807  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
808 
809  /* Add qual if present. */
810  if (qual)
812  else
813  isnull[Anum_pg_policy_polqual - 1] = true;
814 
815  /* Add WITH CHECK qual if present */
816  if (with_check_qual)
817  values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual));
818  else
819  isnull[Anum_pg_policy_polwithcheck - 1] = true;
820 
821  policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values,
822  isnull);
823 
824  policy_id = CatalogTupleInsert(pg_policy_rel, policy_tuple);
825 
826  /* Record Dependencies */
827  target.classId = RelationRelationId;
828  target.objectId = table_id;
829  target.objectSubId = 0;
830 
831  myself.classId = PolicyRelationId;
832  myself.objectId = policy_id;
833  myself.objectSubId = 0;
834 
835  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
836 
837  recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable,
839 
840  recordDependencyOnExpr(&myself, with_check_qual,
841  with_check_pstate->p_rtable, DEPENDENCY_NORMAL);
842 
843  /* Register role dependencies */
844  target.classId = AuthIdRelationId;
845  target.objectSubId = 0;
846  for (i = 0; i < nitems; i++)
847  {
848  target.objectId = DatumGetObjectId(role_oids[i]);
849  /* no dependency if public */
850  if (target.objectId != ACL_ID_PUBLIC)
851  recordSharedDependencyOn(&myself, &target,
853  }
854 
856 
857  /* Invalidate Relation Cache */
858  CacheInvalidateRelcache(target_table);
859 
860  /* Clean up. */
861  heap_freetuple(policy_tuple);
862  free_parsestate(qual_pstate);
863  free_parsestate(with_check_pstate);
864  systable_endscan(sscan);
865  relation_close(target_table, NoLock);
866  heap_close(pg_policy_rel, RowExclusiveLock);
867 
868  return myself;
869 }
870 
871 /*
872  * AlterPolicy -
873  * handles the execution of the ALTER POLICY command.
874  *
875  * stmt - the AlterPolicyStmt that describes the policy and how to alter it.
876  */
879 {
880  Relation pg_policy_rel;
881  Oid policy_id;
882  Relation target_table;
883  Oid table_id;
884  Datum *role_oids = NULL;
885  int nitems = 0;
886  ArrayType *role_ids = NULL;
887  List *qual_parse_rtable = NIL;
888  List *with_check_parse_rtable = NIL;
889  Node *qual = NULL;
890  Node *with_check_qual = NULL;
891  ScanKeyData skey[2];
892  SysScanDesc sscan;
893  HeapTuple policy_tuple;
894  HeapTuple new_tuple;
896  bool isnull[Natts_pg_policy];
897  bool replaces[Natts_pg_policy];
898  ObjectAddress target;
899  ObjectAddress myself;
900  Datum polcmd_datum;
901  char polcmd;
902  bool polcmd_isnull;
903  int i;
904 
905  /* Parse role_ids */
906  if (stmt->roles != NULL)
907  {
908  role_oids = policy_role_list_to_array(stmt->roles, &nitems);
909  role_ids = construct_array(role_oids, nitems, OIDOID,
910  sizeof(Oid), true, 'i');
911  }
912 
913  /* Get id of table. Also handles permissions checks. */
915  false, false,
917  (void *) stmt);
918 
919  target_table = relation_open(table_id, NoLock);
920 
921  /* Parse the using policy clause */
922  if (stmt->qual)
923  {
924  RangeTblEntry *rte;
925  ParseState *qual_pstate = make_parsestate(NULL);
926 
927  rte = addRangeTableEntryForRelation(qual_pstate, target_table,
928  NULL, false, false);
929 
930  addRTEtoQuery(qual_pstate, rte, false, true, true);
931 
932  qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
934  "POLICY");
935 
936  /* Fix up collation information */
937  assign_expr_collations(qual_pstate, qual);
938 
939  qual_parse_rtable = qual_pstate->p_rtable;
940  free_parsestate(qual_pstate);
941  }
942 
943  /* Parse the with-check policy clause */
944  if (stmt->with_check)
945  {
946  RangeTblEntry *rte;
947  ParseState *with_check_pstate = make_parsestate(NULL);
948 
949  rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
950  NULL, false, false);
951 
952  addRTEtoQuery(with_check_pstate, rte, false, true, true);
953 
954  with_check_qual = transformWhereClause(with_check_pstate,
955  copyObject(stmt->with_check),
957  "POLICY");
958 
959  /* Fix up collation information */
960  assign_expr_collations(with_check_pstate, with_check_qual);
961 
962  with_check_parse_rtable = with_check_pstate->p_rtable;
963  free_parsestate(with_check_pstate);
964  }
965 
966  /* zero-clear */
967  memset(values, 0, sizeof(values));
968  memset(replaces, 0, sizeof(replaces));
969  memset(isnull, 0, sizeof(isnull));
970 
971  /* Find policy to update. */
972  pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
973 
974  /* Set key - policy's relation id. */
975  ScanKeyInit(&skey[0],
977  BTEqualStrategyNumber, F_OIDEQ,
978  ObjectIdGetDatum(table_id));
979 
980  /* Set key - policy's name. */
981  ScanKeyInit(&skey[1],
983  BTEqualStrategyNumber, F_NAMEEQ,
984  CStringGetDatum(stmt->policy_name));
985 
986  sscan = systable_beginscan(pg_policy_rel,
987  PolicyPolrelidPolnameIndexId, true, NULL, 2,
988  skey);
989 
990  policy_tuple = systable_getnext(sscan);
991 
992  /* Check that the policy is found, raise an error if not. */
993  if (!HeapTupleIsValid(policy_tuple))
994  ereport(ERROR,
995  (errcode(ERRCODE_UNDEFINED_OBJECT),
996  errmsg("policy \"%s\" for table \"%s\" does not exist",
997  stmt->policy_name,
998  RelationGetRelationName(target_table))));
999 
1000  /* Get policy command */
1001  polcmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
1002  RelationGetDescr(pg_policy_rel),
1003  &polcmd_isnull);
1004  Assert(!polcmd_isnull);
1005  polcmd = DatumGetChar(polcmd_datum);
1006 
1007  /*
1008  * If the command is SELECT or DELETE then WITH CHECK should be NULL.
1009  */
1010  if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
1011  && stmt->with_check != NULL)
1012  ereport(ERROR,
1013  (errcode(ERRCODE_SYNTAX_ERROR),
1014  errmsg("only USING expression allowed for SELECT, DELETE")));
1015 
1016  /*
1017  * If the command is INSERT then WITH CHECK should be the only expression
1018  * provided.
1019  */
1020  if ((polcmd == ACL_INSERT_CHR)
1021  && stmt->qual != NULL)
1022  ereport(ERROR,
1023  (errcode(ERRCODE_SYNTAX_ERROR),
1024  errmsg("only WITH CHECK expression allowed for INSERT")));
1025 
1026  policy_id = HeapTupleGetOid(policy_tuple);
1027 
1028  if (role_ids != NULL)
1029  {
1030  replaces[Anum_pg_policy_polroles - 1] = true;
1031  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
1032  }
1033  else
1034  {
1035  Oid *roles;
1036  Datum roles_datum;
1037  bool attr_isnull;
1038  ArrayType *policy_roles;
1039 
1040  /*
1041  * We need to pull the set of roles this policy applies to from what's
1042  * in the catalog, so that we can recreate the dependencies correctly
1043  * for the policy.
1044  */
1045 
1046  roles_datum = heap_getattr(policy_tuple, Anum_pg_policy_polroles,
1047  RelationGetDescr(pg_policy_rel),
1048  &attr_isnull);
1049  Assert(!attr_isnull);
1050 
1051  policy_roles = DatumGetArrayTypePCopy(roles_datum);
1052 
1053  roles = (Oid *) ARR_DATA_PTR(policy_roles);
1054 
1055  nitems = ARR_DIMS(policy_roles)[0];
1056 
1057  role_oids = (Datum *) palloc(nitems * sizeof(Datum));
1058 
1059  for (i = 0; i < nitems; i++)
1060  role_oids[i] = ObjectIdGetDatum(roles[i]);
1061  }
1062 
1063  if (qual != NULL)
1064  {
1065  replaces[Anum_pg_policy_polqual - 1] = true;
1066  values[Anum_pg_policy_polqual - 1]
1068  }
1069  else
1070  {
1071  Datum value_datum;
1072  bool attr_isnull;
1073 
1074  /*
1075  * We need to pull the USING expression and build the range table for
1076  * the policy from what's in the catalog, so that we can recreate the
1077  * dependencies correctly for the policy.
1078  */
1079 
1080  /* Check if the policy has a USING expr */
1081  value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polqual,
1082  RelationGetDescr(pg_policy_rel),
1083  &attr_isnull);
1084  if (!attr_isnull)
1085  {
1086  char *qual_value;
1087  ParseState *qual_pstate;
1088 
1089  /* parsestate is built just to build the range table */
1090  qual_pstate = make_parsestate(NULL);
1091 
1092  qual_value = TextDatumGetCString(value_datum);
1093  qual = stringToNode(qual_value);
1094 
1095  /* Add this rel to the parsestate's rangetable, for dependencies */
1096  addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
1097  false, false);
1098 
1099  qual_parse_rtable = qual_pstate->p_rtable;
1100  free_parsestate(qual_pstate);
1101  }
1102  }
1103 
1104  if (with_check_qual != NULL)
1105  {
1106  replaces[Anum_pg_policy_polwithcheck - 1] = true;
1107  values[Anum_pg_policy_polwithcheck - 1]
1108  = CStringGetTextDatum(nodeToString(with_check_qual));
1109  }
1110  else
1111  {
1112  Datum value_datum;
1113  bool attr_isnull;
1114 
1115  /*
1116  * We need to pull the WITH CHECK expression and build the range table
1117  * for the policy from what's in the catalog, so that we can recreate
1118  * the dependencies correctly for the policy.
1119  */
1120 
1121  /* Check if the policy has a WITH CHECK expr */
1122  value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polwithcheck,
1123  RelationGetDescr(pg_policy_rel),
1124  &attr_isnull);
1125  if (!attr_isnull)
1126  {
1127  char *with_check_value;
1128  ParseState *with_check_pstate;
1129 
1130  /* parsestate is built just to build the range table */
1131  with_check_pstate = make_parsestate(NULL);
1132 
1133  with_check_value = TextDatumGetCString(value_datum);
1134  with_check_qual = stringToNode(with_check_value);
1135 
1136  /* Add this rel to the parsestate's rangetable, for dependencies */
1137  addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
1138  false, false);
1139 
1140  with_check_parse_rtable = with_check_pstate->p_rtable;
1141  free_parsestate(with_check_pstate);
1142  }
1143  }
1144 
1145  new_tuple = heap_modify_tuple(policy_tuple,
1146  RelationGetDescr(pg_policy_rel),
1147  values, isnull, replaces);
1148  CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
1149 
1150  /* Update Dependencies. */
1151  deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
1152 
1153  /* Record Dependencies */
1154  target.classId = RelationRelationId;
1155  target.objectId = table_id;
1156  target.objectSubId = 0;
1157 
1158  myself.classId = PolicyRelationId;
1159  myself.objectId = policy_id;
1160  myself.objectSubId = 0;
1161 
1162  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
1163 
1164  recordDependencyOnExpr(&myself, qual, qual_parse_rtable, DEPENDENCY_NORMAL);
1165 
1166  recordDependencyOnExpr(&myself, with_check_qual, with_check_parse_rtable,
1168 
1169  /* Register role dependencies */
1171  target.classId = AuthIdRelationId;
1172  target.objectSubId = 0;
1173  for (i = 0; i < nitems; i++)
1174  {
1175  target.objectId = DatumGetObjectId(role_oids[i]);
1176  /* no dependency if public */
1177  if (target.objectId != ACL_ID_PUBLIC)
1178  recordSharedDependencyOn(&myself, &target,
1180  }
1181 
1183 
1184  heap_freetuple(new_tuple);
1185 
1186  /* Invalidate Relation Cache */
1187  CacheInvalidateRelcache(target_table);
1188 
1189  /* Clean up. */
1190  systable_endscan(sscan);
1191  relation_close(target_table, NoLock);
1192  heap_close(pg_policy_rel, RowExclusiveLock);
1193 
1194  return myself;
1195 }
1196 
1197 /*
1198  * rename_policy -
1199  * change the name of a policy on a relation
1200  */
1203 {
1204  Relation pg_policy_rel;
1205  Relation target_table;
1206  Oid table_id;
1207  Oid opoloid;
1208  ScanKeyData skey[2];
1209  SysScanDesc sscan;
1210  HeapTuple policy_tuple;
1211  ObjectAddress address;
1212 
1213  /* Get id of table. Also handles permissions checks. */
1215  false, false,
1217  (void *) stmt);
1218 
1219  target_table = relation_open(table_id, NoLock);
1220 
1221  pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
1222 
1223  /* First pass -- check for conflict */
1224 
1225  /* Add key - policy's relation id. */
1226  ScanKeyInit(&skey[0],
1228  BTEqualStrategyNumber, F_OIDEQ,
1229  ObjectIdGetDatum(table_id));
1230 
1231  /* Add key - policy's name. */
1232  ScanKeyInit(&skey[1],
1234  BTEqualStrategyNumber, F_NAMEEQ,
1235  CStringGetDatum(stmt->newname));
1236 
1237  sscan = systable_beginscan(pg_policy_rel,
1238  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1239  skey);
1240 
1241  if (HeapTupleIsValid(systable_getnext(sscan)))
1242  ereport(ERROR,
1244  errmsg("policy \"%s\" for table \"%s\" already exists",
1245  stmt->newname, RelationGetRelationName(target_table))));
1246 
1247  systable_endscan(sscan);
1248 
1249  /* Second pass -- find existing policy and update */
1250  /* Add key - policy's relation id. */
1251  ScanKeyInit(&skey[0],
1253  BTEqualStrategyNumber, F_OIDEQ,
1254  ObjectIdGetDatum(table_id));
1255 
1256  /* Add key - policy's name. */
1257  ScanKeyInit(&skey[1],
1259  BTEqualStrategyNumber, F_NAMEEQ,
1260  CStringGetDatum(stmt->subname));
1261 
1262  sscan = systable_beginscan(pg_policy_rel,
1263  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1264  skey);
1265 
1266  policy_tuple = systable_getnext(sscan);
1267 
1268  /* Complain if we did not find the policy */
1269  if (!HeapTupleIsValid(policy_tuple))
1270  ereport(ERROR,
1271  (errcode(ERRCODE_UNDEFINED_OBJECT),
1272  errmsg("policy \"%s\" for table \"%s\" does not exist",
1273  stmt->subname, RelationGetRelationName(target_table))));
1274 
1275  opoloid = HeapTupleGetOid(policy_tuple);
1276 
1277  policy_tuple = heap_copytuple(policy_tuple);
1278 
1279  namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname,
1280  stmt->newname);
1281 
1282  CatalogTupleUpdate(pg_policy_rel, &policy_tuple->t_self, policy_tuple);
1283 
1285  HeapTupleGetOid(policy_tuple), 0);
1286 
1287  ObjectAddressSet(address, PolicyRelationId, opoloid);
1288 
1289  /*
1290  * Invalidate relation's relcache entry so that other backends (and this
1291  * one too!) are sent SI message to make them rebuild relcache entries.
1292  * (Ideally this should happen automatically...)
1293  */
1294  CacheInvalidateRelcache(target_table);
1295 
1296  /* Clean up. */
1297  systable_endscan(sscan);
1298  heap_close(pg_policy_rel, RowExclusiveLock);
1299  relation_close(target_table, NoLock);
1300 
1301  return address;
1302 }
1303 
1304 /*
1305  * get_relation_policy_oid - Look up a policy by name to find its OID
1306  *
1307  * If missing_ok is false, throw an error if policy not found. If
1308  * true, just return InvalidOid.
1309  */
1310 Oid
1311 get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
1312 {
1313  Relation pg_policy_rel;
1314  ScanKeyData skey[2];
1315  SysScanDesc sscan;
1316  HeapTuple policy_tuple;
1317  Oid policy_oid;
1318 
1319  pg_policy_rel = heap_open(PolicyRelationId, AccessShareLock);
1320 
1321  /* Add key - policy's relation id. */
1322  ScanKeyInit(&skey[0],
1324  BTEqualStrategyNumber, F_OIDEQ,
1325  ObjectIdGetDatum(relid));
1326 
1327  /* Add key - policy's name. */
1328  ScanKeyInit(&skey[1],
1330  BTEqualStrategyNumber, F_NAMEEQ,
1331  CStringGetDatum(policy_name));
1332 
1333  sscan = systable_beginscan(pg_policy_rel,
1334  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1335  skey);
1336 
1337  policy_tuple = systable_getnext(sscan);
1338 
1339  if (!HeapTupleIsValid(policy_tuple))
1340  {
1341  if (!missing_ok)
1342  ereport(ERROR,
1343  (errcode(ERRCODE_UNDEFINED_OBJECT),
1344  errmsg("policy \"%s\" for table \"%s\" does not exist",
1345  policy_name, get_rel_name(relid))));
1346 
1347  policy_oid = InvalidOid;
1348  }
1349  else
1350  policy_oid = HeapTupleGetOid(policy_tuple);
1351 
1352  /* Clean up. */
1353  systable_endscan(sscan);
1354  heap_close(pg_policy_rel, AccessShareLock);
1355 
1356  return policy_oid;
1357 }
1358 
1359 /*
1360  * relation_has_policies - Determine if relation has any policies
1361  */
1362 bool
1364 {
1365  Relation catalog;
1366  ScanKeyData skey;
1367  SysScanDesc sscan;
1368  HeapTuple policy_tuple;
1369  bool ret = false;
1370 
1372  ScanKeyInit(&skey,
1374  BTEqualStrategyNumber, F_OIDEQ,
1376  sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
1377  NULL, 1, &skey);
1378  policy_tuple = systable_getnext(sscan);
1379  if (HeapTupleIsValid(policy_tuple))
1380  ret = true;
1381 
1382  systable_endscan(sscan);
1383  heap_close(catalog, AccessShareLock);
1384 
1385  return ret;
1386 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
#define NIL
Definition: pg_list.h:69
#define ACL_INSERT_CHR
Definition: acl.h:138
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:661
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
#define RelationGetDescr(relation)
Definition: rel.h:437
Oid GetUserId(void)
Definition: miscinit.c:284
#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:1076
#define RelationRelationId
Definition: pg_class.h:29
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:180
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:141
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3279
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:512
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
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:695
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
#define Anum_pg_policy_polroles
Definition: pg_policy.h:51
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
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
RangeVar * table
Definition: parsenodes.h:2340
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:75
#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:878
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void pfree(void *pointer)
Definition: mcxt.c:949
#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:1202
#define ARR_DIMS(a)
Definition: array.h:279
ObjectAddress CreatePolicy(CreatePolicyStmt *stmt)
Definition: policy.c:683
ItemPointerData t_self
Definition: htup.h:65
void RemovePolicyById(Oid policy_id)
Definition: policy.c:350
#define ARR_DATA_PTR(a)
Definition: array.h:307
#define NoLock
Definition: lockdefs.h:34
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3457
#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:445
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:774
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define Anum_pg_policy_polname
Definition: pg_policy.h:47
#define ACL_SELECT_CHR
Definition: acl.h:139
#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:342
void * palloc0(Size size)
Definition: mcxt.c:877
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
RoleSpecType roletype
Definition: parsenodes.h:327
#define DatumGetChar(X)
Definition: postgres.h:415
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5149
#define DatumGetArrayTypePCopy(X)
Definition: array.h:247
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
RangeVar * relation
Definition: parsenodes.h:2827
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
#define BoolGetDatum(X)
Definition: postgres.h:408
bool allowSystemTableMods
Definition: globals.c:112
#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
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:692
#define Assert(condition)
Definition: c.h:670
#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:1311
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4604
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:140
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:2324
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1233
static Datum values[MAXATTR]
Definition: bootstrap.c:164
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define AccessExclusiveLock
Definition: lockdefs.h:45
bool relation_has_policies(Relation rel)
Definition: policy.c:1363
void * palloc(Size size)
Definition: mcxt.c:848
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:547
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:4265
#define ACL_ID_PUBLIC
Definition: acl.h:47
void * arg
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
#define copyObject(obj)
Definition: nodes.h:625
#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:794
#define RELKIND_RELATION
Definition: pg_class.h:160
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1745
#define RelationGetRelid(relation)
Definition: rel.h:425
#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:173