PostgreSQL Source Code  git master
policy.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_policy.h"
#include "catalog/pg_type.h"
#include "commands/policy.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "parser/parse_clause.h"
#include "parser/parse_collate.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for policy.c:

Go to the source code of this file.

Functions

static void RangeVarCallbackForPolicy (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static char parse_policy_command (const char *cmd_name)
 
static Datumpolicy_role_list_to_array (List *roles, int *num_roles)
 
void RelationBuildRowSecurity (Relation relation)
 
void RemovePolicyById (Oid policy_id)
 
bool RemoveRoleFromObjectPolicy (Oid roleid, Oid classid, Oid policy_id)
 
ObjectAddress CreatePolicy (CreatePolicyStmt *stmt)
 
ObjectAddress AlterPolicy (AlterPolicyStmt *stmt)
 
ObjectAddress rename_policy (RenameStmt *stmt)
 
Oid get_relation_policy_oid (Oid relid, const char *policy_name, bool missing_ok)
 
bool relation_has_policies (Relation rel)
 

Function Documentation

◆ AlterPolicy()

ObjectAddress AlterPolicy ( AlterPolicyStmt stmt)

Definition at line 768 of file policy.c.

769 {
770  Relation pg_policy_rel;
771  Oid policy_id;
772  Relation target_table;
773  Oid table_id;
774  Datum *role_oids = NULL;
775  int nitems = 0;
776  ArrayType *role_ids = NULL;
777  List *qual_parse_rtable = NIL;
778  List *with_check_parse_rtable = NIL;
779  Node *qual = NULL;
780  Node *with_check_qual = NULL;
781  ScanKeyData skey[2];
782  SysScanDesc sscan;
783  HeapTuple policy_tuple;
784  HeapTuple new_tuple;
785  Datum values[Natts_pg_policy];
786  bool isnull[Natts_pg_policy];
787  bool replaces[Natts_pg_policy];
788  ObjectAddress target;
789  ObjectAddress myself;
790  Datum polcmd_datum;
791  char polcmd;
792  bool polcmd_isnull;
793  int i;
794 
795  /* Parse role_ids */
796  if (stmt->roles != NULL)
797  {
798  role_oids = policy_role_list_to_array(stmt->roles, &nitems);
799  role_ids = construct_array_builtin(role_oids, nitems, OIDOID);
800  }
801 
802  /* Get id of table. Also handles permissions checks. */
804  0,
806  (void *) stmt);
807 
808  target_table = relation_open(table_id, NoLock);
809 
810  /* Parse the using policy clause */
811  if (stmt->qual)
812  {
813  ParseNamespaceItem *nsitem;
814  ParseState *qual_pstate = make_parsestate(NULL);
815 
816  nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
818  NULL, false, false);
819 
820  addNSItemToQuery(qual_pstate, nsitem, false, true, true);
821 
822  qual = transformWhereClause(qual_pstate, stmt->qual,
824  "POLICY");
825 
826  /* Fix up collation information */
827  assign_expr_collations(qual_pstate, qual);
828 
829  qual_parse_rtable = qual_pstate->p_rtable;
830  free_parsestate(qual_pstate);
831  }
832 
833  /* Parse the with-check policy clause */
834  if (stmt->with_check)
835  {
836  ParseNamespaceItem *nsitem;
837  ParseState *with_check_pstate = make_parsestate(NULL);
838 
839  nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
841  NULL, false, false);
842 
843  addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
844 
845  with_check_qual = transformWhereClause(with_check_pstate,
846  stmt->with_check,
848  "POLICY");
849 
850  /* Fix up collation information */
851  assign_expr_collations(with_check_pstate, with_check_qual);
852 
853  with_check_parse_rtable = with_check_pstate->p_rtable;
854  free_parsestate(with_check_pstate);
855  }
856 
857  /* zero-clear */
858  memset(values, 0, sizeof(values));
859  memset(replaces, 0, sizeof(replaces));
860  memset(isnull, 0, sizeof(isnull));
861 
862  /* Find policy to update. */
863  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
864 
865  /* Set key - policy's relation id. */
866  ScanKeyInit(&skey[0],
867  Anum_pg_policy_polrelid,
868  BTEqualStrategyNumber, F_OIDEQ,
869  ObjectIdGetDatum(table_id));
870 
871  /* Set key - policy's name. */
872  ScanKeyInit(&skey[1],
873  Anum_pg_policy_polname,
874  BTEqualStrategyNumber, F_NAMEEQ,
875  CStringGetDatum(stmt->policy_name));
876 
877  sscan = systable_beginscan(pg_policy_rel,
878  PolicyPolrelidPolnameIndexId, true, NULL, 2,
879  skey);
880 
881  policy_tuple = systable_getnext(sscan);
882 
883  /* Check that the policy is found, raise an error if not. */
884  if (!HeapTupleIsValid(policy_tuple))
885  ereport(ERROR,
886  (errcode(ERRCODE_UNDEFINED_OBJECT),
887  errmsg("policy \"%s\" for table \"%s\" does not exist",
888  stmt->policy_name,
889  RelationGetRelationName(target_table))));
890 
891  /* Get policy command */
892  polcmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
893  RelationGetDescr(pg_policy_rel),
894  &polcmd_isnull);
895  Assert(!polcmd_isnull);
896  polcmd = DatumGetChar(polcmd_datum);
897 
898  /*
899  * If the command is SELECT or DELETE then WITH CHECK should be NULL.
900  */
901  if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
902  && stmt->with_check != NULL)
903  ereport(ERROR,
904  (errcode(ERRCODE_SYNTAX_ERROR),
905  errmsg("only USING expression allowed for SELECT, DELETE")));
906 
907  /*
908  * If the command is INSERT then WITH CHECK should be the only expression
909  * provided.
910  */
911  if ((polcmd == ACL_INSERT_CHR)
912  && stmt->qual != NULL)
913  ereport(ERROR,
914  (errcode(ERRCODE_SYNTAX_ERROR),
915  errmsg("only WITH CHECK expression allowed for INSERT")));
916 
917  policy_id = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
918 
919  if (role_ids != NULL)
920  {
921  replaces[Anum_pg_policy_polroles - 1] = true;
922  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
923  }
924  else
925  {
926  Oid *roles;
927  Datum roles_datum;
928  bool attr_isnull;
929  ArrayType *policy_roles;
930 
931  /*
932  * We need to pull the set of roles this policy applies to from what's
933  * in the catalog, so that we can recreate the dependencies correctly
934  * for the policy.
935  */
936 
937  roles_datum = heap_getattr(policy_tuple, Anum_pg_policy_polroles,
938  RelationGetDescr(pg_policy_rel),
939  &attr_isnull);
940  Assert(!attr_isnull);
941 
942  policy_roles = DatumGetArrayTypePCopy(roles_datum);
943 
944  roles = (Oid *) ARR_DATA_PTR(policy_roles);
945 
946  nitems = ARR_DIMS(policy_roles)[0];
947 
948  role_oids = (Datum *) palloc(nitems * sizeof(Datum));
949 
950  for (i = 0; i < nitems; i++)
951  role_oids[i] = ObjectIdGetDatum(roles[i]);
952  }
953 
954  if (qual != NULL)
955  {
956  replaces[Anum_pg_policy_polqual - 1] = true;
957  values[Anum_pg_policy_polqual - 1]
959  }
960  else
961  {
962  Datum value_datum;
963  bool attr_isnull;
964 
965  /*
966  * We need to pull the USING expression and build the range table for
967  * the policy from what's in the catalog, so that we can recreate the
968  * dependencies correctly for the policy.
969  */
970 
971  /* Check if the policy has a USING expr */
972  value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polqual,
973  RelationGetDescr(pg_policy_rel),
974  &attr_isnull);
975  if (!attr_isnull)
976  {
977  char *qual_value;
978  ParseState *qual_pstate;
979 
980  /* parsestate is built just to build the range table */
981  qual_pstate = make_parsestate(NULL);
982 
983  qual_value = TextDatumGetCString(value_datum);
984  qual = stringToNode(qual_value);
985 
986  /* Add this rel to the parsestate's rangetable, for dependencies */
987  (void) addRangeTableEntryForRelation(qual_pstate, target_table,
989  NULL, false, false);
990 
991  qual_parse_rtable = qual_pstate->p_rtable;
992  free_parsestate(qual_pstate);
993  }
994  }
995 
996  if (with_check_qual != NULL)
997  {
998  replaces[Anum_pg_policy_polwithcheck - 1] = true;
999  values[Anum_pg_policy_polwithcheck - 1]
1000  = CStringGetTextDatum(nodeToString(with_check_qual));
1001  }
1002  else
1003  {
1004  Datum value_datum;
1005  bool attr_isnull;
1006 
1007  /*
1008  * We need to pull the WITH CHECK expression and build the range table
1009  * for the policy from what's in the catalog, so that we can recreate
1010  * the dependencies correctly for the policy.
1011  */
1012 
1013  /* Check if the policy has a WITH CHECK expr */
1014  value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polwithcheck,
1015  RelationGetDescr(pg_policy_rel),
1016  &attr_isnull);
1017  if (!attr_isnull)
1018  {
1019  char *with_check_value;
1020  ParseState *with_check_pstate;
1021 
1022  /* parsestate is built just to build the range table */
1023  with_check_pstate = make_parsestate(NULL);
1024 
1025  with_check_value = TextDatumGetCString(value_datum);
1026  with_check_qual = stringToNode(with_check_value);
1027 
1028  /* Add this rel to the parsestate's rangetable, for dependencies */
1029  (void) addRangeTableEntryForRelation(with_check_pstate,
1030  target_table,
1032  NULL, false, false);
1033 
1034  with_check_parse_rtable = with_check_pstate->p_rtable;
1035  free_parsestate(with_check_pstate);
1036  }
1037  }
1038 
1039  new_tuple = heap_modify_tuple(policy_tuple,
1040  RelationGetDescr(pg_policy_rel),
1041  values, isnull, replaces);
1042  CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
1043 
1044  /* Update Dependencies. */
1045  deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
1046 
1047  /* Record Dependencies */
1048  target.classId = RelationRelationId;
1049  target.objectId = table_id;
1050  target.objectSubId = 0;
1051 
1052  myself.classId = PolicyRelationId;
1053  myself.objectId = policy_id;
1054  myself.objectSubId = 0;
1055 
1056  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
1057 
1058  recordDependencyOnExpr(&myself, qual, qual_parse_rtable, DEPENDENCY_NORMAL);
1059 
1060  recordDependencyOnExpr(&myself, with_check_qual, with_check_parse_rtable,
1062 
1063  /* Register role dependencies */
1064  deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
1065  target.classId = AuthIdRelationId;
1066  target.objectSubId = 0;
1067  for (i = 0; i < nitems; i++)
1068  {
1069  target.objectId = DatumGetObjectId(role_oids[i]);
1070  /* no dependency if public */
1071  if (target.objectId != ACL_ID_PUBLIC)
1072  recordSharedDependencyOn(&myself, &target,
1074  }
1075 
1076  InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
1077 
1078  heap_freetuple(new_tuple);
1079 
1080  /* Invalidate Relation Cache */
1081  CacheInvalidateRelcache(target_table);
1082 
1083  /* Clean up. */
1084  systable_endscan(sscan);
1085  relation_close(target_table, NoLock);
1086  table_close(pg_policy_rel, RowExclusiveLock);
1087 
1088  return myself;
1089 }
#define ACL_SELECT_CHR
Definition: acl.h:138
#define ACL_DELETE_CHR
Definition: acl.h:140
#define ACL_INSERT_CHR
Definition: acl.h:137
#define ACL_ID_PUBLIC
Definition: acl.h:46
#define DatumGetArrayTypePCopy(X)
Definition: array.h:262
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define ARR_DIMS(a)
Definition: array.h:294
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3374
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1551
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
@ SHARED_DEPENDENCY_POLICY
Definition: dependency.h:76
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define nitems(x)
Definition: indent.h:31
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
void * palloc(Size size)
Definition: mcxt.c:1304
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
char * nodeToString(const void *obj)
Definition: outfuncs.c:791
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:72
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
@ EXPR_KIND_POLICY
Definition: parse_node.h:78
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
#define NIL
Definition: pg_list.h:68
FormData_pg_policy * Form_pg_policy
Definition: pg_policy.h:51
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:997
void recordSharedDependencyOn(ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype)
Definition: pg_shdepend.c:117
static void RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: policy.c:64
static Datum * policy_role_list_to_array(List *roles, int *num_roles)
Definition: policy.c:137
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static char DatumGetChar(Datum X)
Definition: postgres.h:112
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
unsigned int Oid
Definition: postgres_ext.h:31
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetDescr(relation)
Definition: rel.h:533
#define RelationGetRelationName(relation)
Definition: rel.h:541
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Definition: nodes.h:129
List * p_rtable
Definition: parse_node.h:194
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessExclusiveLock, AccessShareLock, ACL_DELETE_CHR, ACL_ID_PUBLIC, ACL_INSERT_CHR, ACL_SELECT_CHR, addNSItemToQuery(), addRangeTableEntryForRelation(), ARR_DATA_PTR, ARR_DIMS, Assert(), assign_expr_collations(), BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), ObjectAddress::classId, construct_array_builtin(), CStringGetDatum(), CStringGetTextDatum, DatumGetArrayTypePCopy, DatumGetChar(), DatumGetObjectId(), deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_POLICY, free_parsestate(), GETSTRUCT, heap_freetuple(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, make_parsestate(), NIL, nitems, nodeToString(), NoLock, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, ParseState::p_rtable, palloc(), PointerGetDatum(), policy_role_list_to_array(), RangeVarCallbackForPolicy(), RangeVarGetRelidExtended(), recordDependencyOn(), recordDependencyOnExpr(), recordSharedDependencyOn(), relation_close(), relation_open(), RelationGetDescr, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_POLICY, stmt, stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), TextDatumGetCString, transformWhereClause(), and values.

Referenced by ProcessUtilitySlow().

◆ CreatePolicy()

ObjectAddress CreatePolicy ( CreatePolicyStmt stmt)

Definition at line 569 of file policy.c.

570 {
571  Relation pg_policy_rel;
572  Oid policy_id;
573  Relation target_table;
574  Oid table_id;
575  char polcmd;
576  Datum *role_oids;
577  int nitems = 0;
578  ArrayType *role_ids;
579  ParseState *qual_pstate;
580  ParseState *with_check_pstate;
581  ParseNamespaceItem *nsitem;
582  Node *qual;
583  Node *with_check_qual;
584  ScanKeyData skey[2];
585  SysScanDesc sscan;
586  HeapTuple policy_tuple;
587  Datum values[Natts_pg_policy];
588  bool isnull[Natts_pg_policy];
589  ObjectAddress target;
590  ObjectAddress myself;
591  int i;
592 
593  /* Parse command */
594  polcmd = parse_policy_command(stmt->cmd_name);
595 
596  /*
597  * If the command is SELECT or DELETE then WITH CHECK should be NULL.
598  */
599  if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
600  && stmt->with_check != NULL)
601  ereport(ERROR,
602  (errcode(ERRCODE_SYNTAX_ERROR),
603  errmsg("WITH CHECK cannot be applied to SELECT or DELETE")));
604 
605  /*
606  * If the command is INSERT then WITH CHECK should be the only expression
607  * provided.
608  */
609  if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL)
610  ereport(ERROR,
611  (errcode(ERRCODE_SYNTAX_ERROR),
612  errmsg("only WITH CHECK expression allowed for INSERT")));
613 
614  /* Collect role ids */
615  role_oids = policy_role_list_to_array(stmt->roles, &nitems);
616  role_ids = construct_array_builtin(role_oids, nitems, OIDOID);
617 
618  /* Parse the supplied clause */
619  qual_pstate = make_parsestate(NULL);
620  with_check_pstate = make_parsestate(NULL);
621 
622  /* zero-clear */
623  memset(values, 0, sizeof(values));
624  memset(isnull, 0, sizeof(isnull));
625 
626  /* Get id of table. Also handles permissions checks. */
628  0,
630  (void *) stmt);
631 
632  /* Open target_table to build quals. No additional lock is necessary. */
633  target_table = relation_open(table_id, NoLock);
634 
635  /* Add for the regular security quals */
636  nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
638  NULL, false, false);
639  addNSItemToQuery(qual_pstate, nsitem, false, true, true);
640 
641  /* Add for the with-check quals */
642  nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
644  NULL, false, false);
645  addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
646 
647  qual = transformWhereClause(qual_pstate,
648  stmt->qual,
650  "POLICY");
651 
652  with_check_qual = transformWhereClause(with_check_pstate,
653  stmt->with_check,
655  "POLICY");
656 
657  /* Fix up collation information */
658  assign_expr_collations(qual_pstate, qual);
659  assign_expr_collations(with_check_pstate, with_check_qual);
660 
661  /* Open pg_policy catalog */
662  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
663 
664  /* Set key - policy's relation id. */
665  ScanKeyInit(&skey[0],
666  Anum_pg_policy_polrelid,
667  BTEqualStrategyNumber, F_OIDEQ,
668  ObjectIdGetDatum(table_id));
669 
670  /* Set key - policy's name. */
671  ScanKeyInit(&skey[1],
672  Anum_pg_policy_polname,
673  BTEqualStrategyNumber, F_NAMEEQ,
674  CStringGetDatum(stmt->policy_name));
675 
676  sscan = systable_beginscan(pg_policy_rel,
677  PolicyPolrelidPolnameIndexId, true, NULL, 2,
678  skey);
679 
680  policy_tuple = systable_getnext(sscan);
681 
682  /* Complain if the policy name already exists for the table */
683  if (HeapTupleIsValid(policy_tuple))
684  ereport(ERROR,
686  errmsg("policy \"%s\" for table \"%s\" already exists",
687  stmt->policy_name, RelationGetRelationName(target_table))));
688 
689  policy_id = GetNewOidWithIndex(pg_policy_rel, PolicyOidIndexId,
690  Anum_pg_policy_oid);
691  values[Anum_pg_policy_oid - 1] = ObjectIdGetDatum(policy_id);
692  values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
693  values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein,
694  CStringGetDatum(stmt->policy_name));
695  values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
696  values[Anum_pg_policy_polpermissive - 1] = BoolGetDatum(stmt->permissive);
697  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
698 
699  /* Add qual if present. */
700  if (qual)
701  values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual));
702  else
703  isnull[Anum_pg_policy_polqual - 1] = true;
704 
705  /* Add WITH CHECK qual if present */
706  if (with_check_qual)
707  values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual));
708  else
709  isnull[Anum_pg_policy_polwithcheck - 1] = true;
710 
711  policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values,
712  isnull);
713 
714  CatalogTupleInsert(pg_policy_rel, policy_tuple);
715 
716  /* Record Dependencies */
717  target.classId = RelationRelationId;
718  target.objectId = table_id;
719  target.objectSubId = 0;
720 
721  myself.classId = PolicyRelationId;
722  myself.objectId = policy_id;
723  myself.objectSubId = 0;
724 
725  recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
726 
727  recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable,
729 
730  recordDependencyOnExpr(&myself, with_check_qual,
731  with_check_pstate->p_rtable, DEPENDENCY_NORMAL);
732 
733  /* Register role dependencies */
734  target.classId = AuthIdRelationId;
735  target.objectSubId = 0;
736  for (i = 0; i < nitems; i++)
737  {
738  target.objectId = DatumGetObjectId(role_oids[i]);
739  /* no dependency if public */
740  if (target.objectId != ACL_ID_PUBLIC)
741  recordSharedDependencyOn(&myself, &target,
743  }
744 
745  InvokeObjectPostCreateHook(PolicyRelationId, policy_id, 0);
746 
747  /* Invalidate Relation Cache */
748  CacheInvalidateRelcache(target_table);
749 
750  /* Clean up. */
751  heap_freetuple(policy_tuple);
752  free_parsestate(qual_pstate);
753  free_parsestate(with_check_pstate);
754  systable_endscan(sscan);
755  relation_close(target_table, NoLock);
756  table_close(pg_policy_rel, RowExclusiveLock);
757 
758  return myself;
759 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
static char parse_policy_command(const char *cmd_name)
Definition: policy.c:108
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

References AccessExclusiveLock, AccessShareLock, ACL_DELETE_CHR, ACL_ID_PUBLIC, ACL_INSERT_CHR, ACL_SELECT_CHR, addNSItemToQuery(), addRangeTableEntryForRelation(), assign_expr_collations(), BoolGetDatum(), BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum(), ObjectAddress::classId, construct_array_builtin(), CStringGetDatum(), CStringGetTextDatum, DatumGetObjectId(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, EXPR_KIND_POLICY, free_parsestate(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, InvokeObjectPostCreateHook, make_parsestate(), namein(), nitems, nodeToString(), NoLock, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, ParseState::p_rtable, parse_policy_command(), PointerGetDatum(), policy_role_list_to_array(), RangeVarCallbackForPolicy(), RangeVarGetRelidExtended(), recordDependencyOn(), recordDependencyOnExpr(), recordSharedDependencyOn(), relation_close(), relation_open(), RelationGetDescr, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), SHARED_DEPENDENCY_POLICY, stmt, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), transformWhereClause(), and values.

Referenced by ProcessUtilitySlow().

◆ get_relation_policy_oid()

Oid get_relation_policy_oid ( Oid  relid,
const char *  policy_name,
bool  missing_ok 
)

Definition at line 1204 of file policy.c.

1205 {
1206  Relation pg_policy_rel;
1207  ScanKeyData skey[2];
1208  SysScanDesc sscan;
1209  HeapTuple policy_tuple;
1210  Oid policy_oid;
1211 
1212  pg_policy_rel = table_open(PolicyRelationId, AccessShareLock);
1213 
1214  /* Add key - policy's relation id. */
1215  ScanKeyInit(&skey[0],
1216  Anum_pg_policy_polrelid,
1217  BTEqualStrategyNumber, F_OIDEQ,
1218  ObjectIdGetDatum(relid));
1219 
1220  /* Add key - policy's name. */
1221  ScanKeyInit(&skey[1],
1222  Anum_pg_policy_polname,
1223  BTEqualStrategyNumber, F_NAMEEQ,
1224  CStringGetDatum(policy_name));
1225 
1226  sscan = systable_beginscan(pg_policy_rel,
1227  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1228  skey);
1229 
1230  policy_tuple = systable_getnext(sscan);
1231 
1232  if (!HeapTupleIsValid(policy_tuple))
1233  {
1234  if (!missing_ok)
1235  ereport(ERROR,
1236  (errcode(ERRCODE_UNDEFINED_OBJECT),
1237  errmsg("policy \"%s\" for table \"%s\" does not exist",
1238  policy_name, get_rel_name(relid))));
1239 
1240  policy_oid = InvalidOid;
1241  }
1242  else
1243  policy_oid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
1244 
1245  /* Clean up. */
1246  systable_endscan(sscan);
1247  table_close(pg_policy_rel, AccessShareLock);
1248 
1249  return policy_oid;
1250 }
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1906
#define InvalidOid
Definition: postgres_ext.h:36

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, get_rel_name(), GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_object_address_relobject().

◆ parse_policy_command()

static char parse_policy_command ( const char *  cmd_name)
static

Definition at line 108 of file policy.c.

109 {
110  char polcmd;
111 
112  if (!cmd_name)
113  elog(ERROR, "unrecognized policy command");
114 
115  if (strcmp(cmd_name, "all") == 0)
116  polcmd = '*';
117  else if (strcmp(cmd_name, "select") == 0)
118  polcmd = ACL_SELECT_CHR;
119  else if (strcmp(cmd_name, "insert") == 0)
120  polcmd = ACL_INSERT_CHR;
121  else if (strcmp(cmd_name, "update") == 0)
122  polcmd = ACL_UPDATE_CHR;
123  else if (strcmp(cmd_name, "delete") == 0)
124  polcmd = ACL_DELETE_CHR;
125  else
126  elog(ERROR, "unrecognized policy command");
127 
128  return polcmd;
129 }
#define ACL_UPDATE_CHR
Definition: acl.h:139
#define elog(elevel,...)
Definition: elog.h:224

References ACL_DELETE_CHR, ACL_INSERT_CHR, ACL_SELECT_CHR, ACL_UPDATE_CHR, elog, and ERROR.

Referenced by CreatePolicy().

◆ policy_role_list_to_array()

static Datum * policy_role_list_to_array ( List roles,
int *  num_roles 
)
static

Definition at line 137 of file policy.c.

138 {
139  Datum *role_oids;
140  ListCell *cell;
141  int i = 0;
142 
143  /* Handle no roles being passed in as being for public */
144  if (roles == NIL)
145  {
146  *num_roles = 1;
147  role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
148  role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
149 
150  return role_oids;
151  }
152 
153  *num_roles = list_length(roles);
154  role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
155 
156  foreach(cell, roles)
157  {
158  RoleSpec *spec = lfirst(cell);
159 
160  /*
161  * PUBLIC covers all roles, so it only makes sense alone.
162  */
163  if (spec->roletype == ROLESPEC_PUBLIC)
164  {
165  if (*num_roles != 1)
166  {
168  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
169  errmsg("ignoring specified roles other than PUBLIC"),
170  errhint("All roles are members of the PUBLIC role.")));
171  *num_roles = 1;
172  }
173  role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
174 
175  return role_oids;
176  }
177  else
178  role_oids[i++] =
179  ObjectIdGetDatum(get_rolespec_oid(spec, false));
180  }
181 
182  return role_oids;
183 }
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5448
int errhint(const char *fmt,...)
Definition: elog.c:1319
#define WARNING
Definition: elog.h:36
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:397
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
RoleSpecType roletype
Definition: parsenodes.h:403

References ACL_ID_PUBLIC, ereport, errcode(), errhint(), errmsg(), get_rolespec_oid(), i, lfirst, list_length(), NIL, ObjectIdGetDatum(), palloc(), ROLESPEC_PUBLIC, RoleSpec::roletype, and WARNING.

Referenced by AlterPolicy(), and CreatePolicy().

◆ RangeVarCallbackForPolicy()

static void RangeVarCallbackForPolicy ( const RangeVar rv,
Oid  relid,
Oid  oldrelid,
void *  arg 
)
static

Definition at line 64 of file policy.c.

66 {
67  HeapTuple tuple;
68  Form_pg_class classform;
69  char relkind;
70 
71  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
72  if (!HeapTupleIsValid(tuple))
73  return;
74 
75  classform = (Form_pg_class) GETSTRUCT(tuple);
76  relkind = classform->relkind;
77 
78  /* Must own relation. */
79  if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
81 
82  /* No system table modifications unless explicitly allowed. */
83  if (!allowSystemTableMods && IsSystemClass(relid, classform))
84  ereport(ERROR,
85  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
86  errmsg("permission denied: \"%s\" is a system catalog",
87  rv->relname)));
88 
89  /* Relation type MUST be a table. */
90  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
91  ereport(ERROR,
92  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
93  errmsg("\"%s\" is not a table", rv->relname)));
94 
95  ReleaseSysCache(tuple);
96 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2688
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4130
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
bool allowSystemTableMods
Definition: globals.c:127
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1981
Oid GetUserId(void)
Definition: miscinit.c:514
ObjectType get_relkind_objtype(char relkind)
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
char * relname
Definition: primnodes.h:82
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), get_relkind_objtype(), GETSTRUCT, GetUserId(), HeapTupleIsValid, IsSystemClass(), object_ownercheck(), ObjectIdGetDatum(), ReleaseSysCache(), RangeVar::relname, and SearchSysCache1().

Referenced by AlterPolicy(), CreatePolicy(), and rename_policy().

◆ relation_has_policies()

bool relation_has_policies ( Relation  rel)

Definition at line 1256 of file policy.c.

1257 {
1258  Relation catalog;
1259  ScanKeyData skey;
1260  SysScanDesc sscan;
1261  HeapTuple policy_tuple;
1262  bool ret = false;
1263 
1264  catalog = table_open(PolicyRelationId, AccessShareLock);
1265  ScanKeyInit(&skey,
1266  Anum_pg_policy_polrelid,
1267  BTEqualStrategyNumber, F_OIDEQ,
1269  sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
1270  NULL, 1, &skey);
1271  policy_tuple = systable_getnext(sscan);
1272  if (HeapTupleIsValid(policy_tuple))
1273  ret = true;
1274 
1275  systable_endscan(sscan);
1276  table_close(catalog, AccessShareLock);
1277 
1278  return ret;
1279 }
#define RelationGetRelid(relation)
Definition: rel.h:507

References AccessShareLock, BTEqualStrategyNumber, HeapTupleIsValid, ObjectIdGetDatum(), RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

◆ RelationBuildRowSecurity()

void RelationBuildRowSecurity ( Relation  relation)

Definition at line 193 of file policy.c.

194 {
195  MemoryContext rscxt;
197  RowSecurityDesc *rsdesc;
198  Relation catalog;
199  ScanKeyData skey;
200  SysScanDesc sscan;
201  HeapTuple tuple;
202 
203  /*
204  * Create a memory context to hold everything associated with this
205  * relation's row security policy. This makes it easy to clean up during
206  * a relcache flush. However, to cover the possibility of an error
207  * partway through, we don't make the context long-lived till we're done.
208  */
210  "row security descriptor",
213  RelationGetRelationName(relation));
214 
215  rsdesc = MemoryContextAllocZero(rscxt, sizeof(RowSecurityDesc));
216  rsdesc->rscxt = rscxt;
217 
218  /*
219  * Now scan pg_policy for RLS policies associated with this relation.
220  * Because we use the index on (polrelid, polname), we should consistently
221  * visit the rel's policies in name order, at least when system indexes
222  * aren't disabled. This simplifies equalRSDesc().
223  */
224  catalog = table_open(PolicyRelationId, AccessShareLock);
225 
226  ScanKeyInit(&skey,
227  Anum_pg_policy_polrelid,
228  BTEqualStrategyNumber, F_OIDEQ,
230 
231  sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
232  NULL, 1, &skey);
233 
234  while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
235  {
236  Form_pg_policy policy_form = (Form_pg_policy) GETSTRUCT(tuple);
237  RowSecurityPolicy *policy;
238  Datum datum;
239  bool isnull;
240  char *str_value;
241 
242  policy = MemoryContextAllocZero(rscxt, sizeof(RowSecurityPolicy));
243 
244  /*
245  * Note: we must be sure that pass-by-reference data gets copied into
246  * rscxt. We avoid making that context current over wider spans than
247  * we have to, though.
248  */
249 
250  /* Get policy command */
251  policy->polcmd = policy_form->polcmd;
252 
253  /* Get policy, permissive or restrictive */
254  policy->permissive = policy_form->polpermissive;
255 
256  /* Get policy name */
257  policy->policy_name =
258  MemoryContextStrdup(rscxt, NameStr(policy_form->polname));
259 
260  /* Get policy roles */
261  datum = heap_getattr(tuple, Anum_pg_policy_polroles,
262  RelationGetDescr(catalog), &isnull);
263  /* shouldn't be null, but let's check for luck */
264  if (isnull)
265  elog(ERROR, "unexpected null value in pg_policy.polroles");
266  MemoryContextSwitchTo(rscxt);
267  policy->roles = DatumGetArrayTypePCopy(datum);
268  MemoryContextSwitchTo(oldcxt);
269 
270  /* Get policy qual */
271  datum = heap_getattr(tuple, Anum_pg_policy_polqual,
272  RelationGetDescr(catalog), &isnull);
273  if (!isnull)
274  {
275  str_value = TextDatumGetCString(datum);
276  MemoryContextSwitchTo(rscxt);
277  policy->qual = (Expr *) stringToNode(str_value);
278  MemoryContextSwitchTo(oldcxt);
279  pfree(str_value);
280  }
281  else
282  policy->qual = NULL;
283 
284  /* Get WITH CHECK qual */
285  datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
286  RelationGetDescr(catalog), &isnull);
287  if (!isnull)
288  {
289  str_value = TextDatumGetCString(datum);
290  MemoryContextSwitchTo(rscxt);
291  policy->with_check_qual = (Expr *) stringToNode(str_value);
292  MemoryContextSwitchTo(oldcxt);
293  pfree(str_value);
294  }
295  else
296  policy->with_check_qual = NULL;
297 
298  /* We want to cache whether there are SubLinks in these expressions */
299  policy->hassublinks = checkExprHasSubLink((Node *) policy->qual) ||
301 
302  /*
303  * Add this object to list. For historical reasons, the list is built
304  * in reverse order.
305  */
306  MemoryContextSwitchTo(rscxt);
307  rsdesc->policies = lcons(policy, rsdesc->policies);
308  MemoryContextSwitchTo(oldcxt);
309  }
310 
311  systable_endscan(sscan);
312  table_close(catalog, AccessShareLock);
313 
314  /*
315  * Success. Reparent the descriptor's memory context under
316  * CacheMemoryContext so that it will live indefinitely, then attach the
317  * policy descriptor to the relcache entry.
318  */
320 
321  relation->rd_rsdesc = rsdesc;
322 }
#define NameStr(name)
Definition: c.h:733
List * lcons(void *datum, List *list)
Definition: list.c:495
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:625
void pfree(void *pointer)
Definition: mcxt.c:1508
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1202
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1670
MemoryContext CacheMemoryContext
Definition: mcxt.c:140
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:101
MemoryContextSwitchTo(old_ctx)
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:295
struct RowSecurityDesc * rd_rsdesc
Definition: rel.h:119
MemoryContext rscxt
Definition: rowsecurity.h:33
ArrayType * roles
Definition: rowsecurity.h:24
Expr * with_check_qual
Definition: rowsecurity.h:27

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, BTEqualStrategyNumber, CacheMemoryContext, checkExprHasSubLink(), CurrentMemoryContext, DatumGetArrayTypePCopy, elog, ERROR, GETSTRUCT, RowSecurityPolicy::hassublinks, heap_getattr(), HeapTupleIsValid, lcons(), MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSetParent(), MemoryContextStrdup(), MemoryContextSwitchTo(), NameStr, ObjectIdGetDatum(), RowSecurityPolicy::permissive, pfree(), RowSecurityPolicy::polcmd, RowSecurityDesc::policies, RowSecurityPolicy::policy_name, RowSecurityPolicy::qual, RelationData::rd_rsdesc, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RowSecurityPolicy::roles, RowSecurityDesc::rscxt, ScanKeyInit(), stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, and RowSecurityPolicy::with_check_qual.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

◆ RemovePolicyById()

void RemovePolicyById ( Oid  policy_id)

Definition at line 332 of file policy.c.

333 {
334  Relation pg_policy_rel;
335  SysScanDesc sscan;
336  ScanKeyData skey[1];
337  HeapTuple tuple;
338  Oid relid;
339  Relation rel;
340 
341  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
342 
343  /*
344  * Find the policy to delete.
345  */
346  ScanKeyInit(&skey[0],
347  Anum_pg_policy_oid,
348  BTEqualStrategyNumber, F_OIDEQ,
349  ObjectIdGetDatum(policy_id));
350 
351  sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
352  NULL, 1, skey);
353 
354  tuple = systable_getnext(sscan);
355 
356  /* If the policy exists, then remove it, otherwise raise an error. */
357  if (!HeapTupleIsValid(tuple))
358  elog(ERROR, "could not find tuple for policy %u", policy_id);
359 
360  /*
361  * Open and exclusive-lock the relation the policy belongs to. (We need
362  * exclusive lock to lock out queries that might otherwise depend on the
363  * set of policies the rel has; furthermore we've got to hold the lock
364  * till commit.)
365  */
366  relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
367 
368  rel = table_open(relid, AccessExclusiveLock);
369  if (rel->rd_rel->relkind != RELKIND_RELATION &&
370  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
371  ereport(ERROR,
372  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
373  errmsg("\"%s\" is not a table",
374  RelationGetRelationName(rel))));
375 
377  ereport(ERROR,
378  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
379  errmsg("permission denied: \"%s\" is a system catalog",
380  RelationGetRelationName(rel))));
381 
382  CatalogTupleDelete(pg_policy_rel, &tuple->t_self);
383 
384  systable_endscan(sscan);
385 
386  /*
387  * Note that, unlike some of the other flags in pg_class, relrowsecurity
388  * is not just an indication of if policies exist. When relrowsecurity is
389  * set by a user, then all access to the relation must be through a
390  * policy. If no policy is defined for the relation then a default-deny
391  * policy is created and all records are filtered (except for queries from
392  * the owner).
393  */
395 
396  table_close(rel, NoLock);
397 
398  /* Clean up */
399  table_close(pg_policy_rel, RowExclusiveLock);
400 }
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
Form_pg_class rd_rel
Definition: rel.h:111

References AccessExclusiveLock, allowSystemTableMods, BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleDelete(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, IsSystemRelation(), NoLock, ObjectIdGetDatum(), RelationData::rd_rel, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveRoleFromObjectPolicy()

bool RemoveRoleFromObjectPolicy ( Oid  roleid,
Oid  classid,
Oid  policy_id 
)

Definition at line 416 of file policy.c.

417 {
418  Relation pg_policy_rel;
419  SysScanDesc sscan;
420  ScanKeyData skey[1];
421  HeapTuple tuple;
422  Oid relid;
423  ArrayType *policy_roles;
424  Datum roles_datum;
425  Oid *roles;
426  int num_roles;
427  Datum *role_oids;
428  bool attr_isnull;
429  bool keep_policy = true;
430  int i,
431  j;
432 
433  Assert(classid == PolicyRelationId);
434 
435  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
436 
437  /*
438  * Find the policy to update.
439  */
440  ScanKeyInit(&skey[0],
441  Anum_pg_policy_oid,
442  BTEqualStrategyNumber, F_OIDEQ,
443  ObjectIdGetDatum(policy_id));
444 
445  sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
446  NULL, 1, skey);
447 
448  tuple = systable_getnext(sscan);
449 
450  /* Raise an error if we don't find the policy. */
451  if (!HeapTupleIsValid(tuple))
452  elog(ERROR, "could not find tuple for policy %u", policy_id);
453 
454  /* Identify rel the policy belongs to */
455  relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
456 
457  /* Get the current set of roles */
458  roles_datum = heap_getattr(tuple,
459  Anum_pg_policy_polroles,
460  RelationGetDescr(pg_policy_rel),
461  &attr_isnull);
462 
463  Assert(!attr_isnull);
464 
465  policy_roles = DatumGetArrayTypePCopy(roles_datum);
466  roles = (Oid *) ARR_DATA_PTR(policy_roles);
467  num_roles = ARR_DIMS(policy_roles)[0];
468 
469  /*
470  * Rebuild the polroles array, without any mentions of the target role.
471  * Ordinarily there'd be exactly one, but we must cope with duplicate
472  * mentions, since CREATE/ALTER POLICY historically have allowed that.
473  */
474  role_oids = (Datum *) palloc(num_roles * sizeof(Datum));
475  for (i = 0, j = 0; i < num_roles; i++)
476  {
477  if (roles[i] != roleid)
478  role_oids[j++] = ObjectIdGetDatum(roles[i]);
479  }
480  num_roles = j;
481 
482  /* If any roles remain, update the policy entry. */
483  if (num_roles > 0)
484  {
485  ArrayType *role_ids;
486  Datum values[Natts_pg_policy];
487  bool isnull[Natts_pg_policy];
488  bool replaces[Natts_pg_policy];
489  HeapTuple new_tuple;
490  HeapTuple reltup;
491  ObjectAddress target;
492  ObjectAddress myself;
493 
494  /* zero-clear */
495  memset(values, 0, sizeof(values));
496  memset(replaces, 0, sizeof(replaces));
497  memset(isnull, 0, sizeof(isnull));
498 
499  /* This is the array for the new tuple */
500  role_ids = construct_array_builtin(role_oids, num_roles, OIDOID);
501 
502  replaces[Anum_pg_policy_polroles - 1] = true;
503  values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
504 
505  new_tuple = heap_modify_tuple(tuple,
506  RelationGetDescr(pg_policy_rel),
507  values, isnull, replaces);
508  CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
509 
510  /* Remove all the old shared dependencies (roles) */
511  deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
512 
513  /* Record the new shared dependencies (roles) */
514  myself.classId = PolicyRelationId;
515  myself.objectId = policy_id;
516  myself.objectSubId = 0;
517 
518  target.classId = AuthIdRelationId;
519  target.objectSubId = 0;
520  for (i = 0; i < num_roles; i++)
521  {
522  target.objectId = DatumGetObjectId(role_oids[i]);
523  /* no need for dependency on the public role */
524  if (target.objectId != ACL_ID_PUBLIC)
525  recordSharedDependencyOn(&myself, &target,
527  }
528 
529  InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
530 
531  heap_freetuple(new_tuple);
532 
533  /* Make updates visible */
535 
536  /*
537  * Invalidate relcache entry for rel the policy belongs to, to force
538  * redoing any dependent plans. In case of a race condition where the
539  * rel was just dropped, we need do nothing.
540  */
541  reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
542  if (HeapTupleIsValid(reltup))
543  {
545  ReleaseSysCache(reltup);
546  }
547  }
548  else
549  {
550  /* No roles would remain, so drop the policy instead. */
551  keep_policy = false;
552  }
553 
554  /* Clean up. */
555  systable_endscan(sscan);
556 
557  table_close(pg_policy_rel, RowExclusiveLock);
558 
559  return keep_policy;
560 }
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1396
int j
Definition: isn.c:74
void CommandCounterIncrement(void)
Definition: xact.c:1097

References ACL_ID_PUBLIC, ARR_DATA_PTR, ARR_DIMS, Assert(), BTEqualStrategyNumber, CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), ObjectAddress::classId, CommandCounterIncrement(), construct_array_builtin(), DatumGetArrayTypePCopy, DatumGetObjectId(), deleteSharedDependencyRecordsFor(), elog, ERROR, GETSTRUCT, heap_freetuple(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, j, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, palloc(), PointerGetDatum(), recordSharedDependencyOn(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SHARED_DEPENDENCY_POLICY, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by shdepDropOwned().

◆ rename_policy()

ObjectAddress rename_policy ( RenameStmt stmt)

Definition at line 1096 of file policy.c.

1097 {
1098  Relation pg_policy_rel;
1099  Relation target_table;
1100  Oid table_id;
1101  Oid opoloid;
1102  ScanKeyData skey[2];
1103  SysScanDesc sscan;
1104  HeapTuple policy_tuple;
1105  ObjectAddress address;
1106 
1107  /* Get id of table. Also handles permissions checks. */
1108  table_id = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
1109  0,
1111  (void *) stmt);
1112 
1113  target_table = relation_open(table_id, NoLock);
1114 
1115  pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
1116 
1117  /* First pass -- check for conflict */
1118 
1119  /* Add key - policy's relation id. */
1120  ScanKeyInit(&skey[0],
1121  Anum_pg_policy_polrelid,
1122  BTEqualStrategyNumber, F_OIDEQ,
1123  ObjectIdGetDatum(table_id));
1124 
1125  /* Add key - policy's name. */
1126  ScanKeyInit(&skey[1],
1127  Anum_pg_policy_polname,
1128  BTEqualStrategyNumber, F_NAMEEQ,
1129  CStringGetDatum(stmt->newname));
1130 
1131  sscan = systable_beginscan(pg_policy_rel,
1132  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1133  skey);
1134 
1135  if (HeapTupleIsValid(systable_getnext(sscan)))
1136  ereport(ERROR,
1138  errmsg("policy \"%s\" for table \"%s\" already exists",
1139  stmt->newname, RelationGetRelationName(target_table))));
1140 
1141  systable_endscan(sscan);
1142 
1143  /* Second pass -- find existing policy and update */
1144  /* Add key - policy's relation id. */
1145  ScanKeyInit(&skey[0],
1146  Anum_pg_policy_polrelid,
1147  BTEqualStrategyNumber, F_OIDEQ,
1148  ObjectIdGetDatum(table_id));
1149 
1150  /* Add key - policy's name. */
1151  ScanKeyInit(&skey[1],
1152  Anum_pg_policy_polname,
1153  BTEqualStrategyNumber, F_NAMEEQ,
1154  CStringGetDatum(stmt->subname));
1155 
1156  sscan = systable_beginscan(pg_policy_rel,
1157  PolicyPolrelidPolnameIndexId, true, NULL, 2,
1158  skey);
1159 
1160  policy_tuple = systable_getnext(sscan);
1161 
1162  /* Complain if we did not find the policy */
1163  if (!HeapTupleIsValid(policy_tuple))
1164  ereport(ERROR,
1165  (errcode(ERRCODE_UNDEFINED_OBJECT),
1166  errmsg("policy \"%s\" for table \"%s\" does not exist",
1167  stmt->subname, RelationGetRelationName(target_table))));
1168 
1169  opoloid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
1170 
1171  policy_tuple = heap_copytuple(policy_tuple);
1172 
1173  namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname,
1174  stmt->newname);
1175 
1176  CatalogTupleUpdate(pg_policy_rel, &policy_tuple->t_self, policy_tuple);
1177 
1178  InvokeObjectPostAlterHook(PolicyRelationId, opoloid, 0);
1179 
1180  ObjectAddressSet(address, PolicyRelationId, opoloid);
1181 
1182  /*
1183  * Invalidate relation's relcache entry so that other backends (and this
1184  * one too!) are sent SI message to make them rebuild relcache entries.
1185  * (Ideally this should happen automatically...)
1186  */
1187  CacheInvalidateRelcache(target_table);
1188 
1189  /* Clean up. */
1190  systable_endscan(sscan);
1191  table_close(pg_policy_rel, RowExclusiveLock);
1192  relation_close(target_table, NoLock);
1193 
1194  return address;
1195 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40

References AccessExclusiveLock, BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, GETSTRUCT, heap_copytuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, namestrcpy(), NoLock, ObjectAddressSet, ObjectIdGetDatum(), RangeVarCallbackForPolicy(), RangeVarGetRelidExtended(), relation_close(), relation_open(), RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), stmt, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ExecRenameStmt().