LCOV - differential code coverage report
Current view: top level - src/backend/commands - policy.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 87.5 % 401 351 1 26 23 3 143 4 201 24 147 2
Current Date: 2023-04-08 17:13:01 Functions: 90.9 % 11 10 1 4 2 4 1 4
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (240..) days: 87.5 % 400 350 1 26 23 3 143 3 201 24 147
Function coverage date bins:
(240..) days: 62.5 % 16 10 1 4 2 4 1 4

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * policy.c
                                  4                 :  *    Commands for manipulating policies.
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  * src/backend/commands/policy.c
                                 10                 :  *
                                 11                 :  *-------------------------------------------------------------------------
                                 12                 :  */
                                 13                 : #include "postgres.h"
                                 14                 : 
                                 15                 : #include "access/genam.h"
                                 16                 : #include "access/htup.h"
                                 17                 : #include "access/htup_details.h"
                                 18                 : #include "access/relation.h"
                                 19                 : #include "access/sysattr.h"
                                 20                 : #include "access/table.h"
                                 21                 : #include "access/xact.h"
                                 22                 : #include "catalog/catalog.h"
                                 23                 : #include "catalog/dependency.h"
                                 24                 : #include "catalog/indexing.h"
                                 25                 : #include "catalog/namespace.h"
                                 26                 : #include "catalog/objectaccess.h"
                                 27                 : #include "catalog/pg_authid.h"
                                 28                 : #include "catalog/pg_policy.h"
                                 29                 : #include "catalog/pg_type.h"
                                 30                 : #include "commands/policy.h"
                                 31                 : #include "miscadmin.h"
                                 32                 : #include "nodes/makefuncs.h"
                                 33                 : #include "nodes/pg_list.h"
                                 34                 : #include "parser/parse_clause.h"
                                 35                 : #include "parser/parse_collate.h"
                                 36                 : #include "parser/parse_node.h"
                                 37                 : #include "parser/parse_relation.h"
                                 38                 : #include "rewrite/rewriteManip.h"
                                 39                 : #include "rewrite/rowsecurity.h"
                                 40                 : #include "storage/lock.h"
                                 41                 : #include "utils/acl.h"
                                 42                 : #include "utils/array.h"
                                 43                 : #include "utils/builtins.h"
                                 44                 : #include "utils/fmgroids.h"
                                 45                 : #include "utils/inval.h"
                                 46                 : #include "utils/lsyscache.h"
                                 47                 : #include "utils/memutils.h"
                                 48                 : #include "utils/rel.h"
                                 49                 : #include "utils/syscache.h"
                                 50                 : 
                                 51                 : static void RangeVarCallbackForPolicy(const RangeVar *rv,
                                 52                 :                                       Oid relid, Oid oldrelid, void *arg);
                                 53                 : static char parse_policy_command(const char *cmd_name);
                                 54                 : static Datum *policy_role_list_to_array(List *roles, int *num_roles);
                                 55                 : 
                                 56                 : /*
                                 57                 :  * Callback to RangeVarGetRelidExtended().
                                 58                 :  *
                                 59                 :  * Checks the following:
                                 60                 :  *  - the relation specified is a table.
                                 61                 :  *  - current user owns the table.
                                 62                 :  *  - the table is not a system table.
                                 63                 :  *
                                 64                 :  * If any of these checks fails then an error is raised.
                                 65                 :  */
                                 66                 : static void
 3124 sfrost                     67 CBC         382 : RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid,
                                 68                 :                           void *arg)
                                 69                 : {
                                 70                 :     HeapTuple   tuple;
                                 71                 :     Form_pg_class classform;
                                 72                 :     char        relkind;
                                 73                 : 
                                 74             382 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                                 75             382 :     if (!HeapTupleIsValid(tuple))
 3124 sfrost                     76 UBC           0 :         return;
                                 77                 : 
 3124 sfrost                     78 CBC         382 :     classform = (Form_pg_class) GETSTRUCT(tuple);
                                 79             382 :     relkind = classform->relkind;
                                 80                 : 
                                 81                 :     /* Must own relation. */
  147 peter                      82 GNC         382 :     if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
 1954 peter_e                    83 CBC           6 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
                                 84                 : 
                                 85                 :     /* No system table modifications unless explicitly allowed. */
 3124 sfrost                     86             376 :     if (!allowSystemTableMods && IsSystemClass(relid, classform))
                                 87               1 :         ereport(ERROR,
                                 88                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 89                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                                 90                 :                         rv->relname)));
                                 91                 : 
                                 92                 :     /* Relation type MUST be a table. */
 2314 rhaas                      93             375 :     if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
 3124 sfrost                     94 UBC           0 :         ereport(ERROR,
                                 95                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 96                 :                  errmsg("\"%s\" is not a table", rv->relname)));
                                 97                 : 
 3124 sfrost                     98 CBC         375 :     ReleaseSysCache(tuple);
                                 99                 : }
                                100                 : 
                                101                 : /*
                                102                 :  * parse_policy_command -
                                103                 :  *   helper function to convert full command strings to their char
                                104                 :  *   representation.
                                105                 :  *
                                106                 :  * cmd_name - full string command name. Valid values are 'all', 'select',
                                107                 :  *            'insert', 'update' and 'delete'.
                                108                 :  *
                                109                 :  */
                                110                 : static char
 3055                           111             314 : parse_policy_command(const char *cmd_name)
                                112                 : {
                                113                 :     char        polcmd;
                                114                 : 
 3124                           115             314 :     if (!cmd_name)
 2997 tgl                       116 UBC           0 :         elog(ERROR, "unrecognized policy command");
                                117                 : 
 3124 sfrost                    118 CBC         314 :     if (strcmp(cmd_name, "all") == 0)
 2788                           119             185 :         polcmd = '*';
 3124                           120             129 :     else if (strcmp(cmd_name, "select") == 0)
 2788                           121              47 :         polcmd = ACL_SELECT_CHR;
 3124                           122              82 :     else if (strcmp(cmd_name, "insert") == 0)
 2788                           123              22 :         polcmd = ACL_INSERT_CHR;
 3124                           124              60 :     else if (strcmp(cmd_name, "update") == 0)
 2788                           125              39 :         polcmd = ACL_UPDATE_CHR;
 3124                           126              21 :     else if (strcmp(cmd_name, "delete") == 0)
 2788                           127              21 :         polcmd = ACL_DELETE_CHR;
                                128                 :     else
 2997 tgl                       129 UBC           0 :         elog(ERROR, "unrecognized policy command");
                                130                 : 
 2788 sfrost                    131 CBC         314 :     return polcmd;
                                132                 : }
                                133                 : 
                                134                 : /*
                                135                 :  * policy_role_list_to_array
                                136                 :  *   helper function to convert a list of RoleSpecs to an array of
                                137                 :  *   role id Datums.
                                138                 :  */
                                139                 : static Datum *
 2812 mail                      140             320 : policy_role_list_to_array(List *roles, int *num_roles)
                                141                 : {
                                142                 :     Datum      *role_oids;
                                143                 :     ListCell   *cell;
 3124 sfrost                    144             320 :     int         i = 0;
                                145                 : 
                                146                 :     /* Handle no roles being passed in as being for public */
                                147             320 :     if (roles == NIL)
                                148                 :     {
 2812 tgl                       149 UBC           0 :         *num_roles = 1;
      mail                      150               0 :         role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
                                151               0 :         role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
                                152                 : 
                                153               0 :         return role_oids;
                                154                 :     }
                                155                 : 
 2812 tgl                       156 CBC         320 :     *num_roles = list_length(roles);
      mail                      157             320 :     role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
                                158                 : 
 3124 sfrost                    159             394 :     foreach(cell, roles)
                                160                 :     {
 2878 bruce                     161             341 :         RoleSpec   *spec = lfirst(cell);
                                162                 : 
                                163                 :         /*
                                164                 :          * PUBLIC covers all roles, so it only makes sense alone.
                                165                 :          */
 2953 alvherre                  166             341 :         if (spec->roletype == ROLESPEC_PUBLIC)
                                167                 :         {
 2812 mail                      168             267 :             if (*num_roles != 1)
                                169                 :             {
 3124 sfrost                    170 UBC           0 :                 ereport(WARNING,
                                171                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                172                 :                          errmsg("ignoring specified roles other than PUBLIC"),
                                173                 :                          errhint("All roles are members of the PUBLIC role.")));
 2812 tgl                       174               0 :                 *num_roles = 1;
                                175                 :             }
 2812 mail                      176 CBC         267 :             role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
                                177                 : 
                                178             267 :             return role_oids;
                                179                 :         }
                                180                 :         else
                                181              74 :             role_oids[i++] =
 2293 peter_e                   182              74 :                 ObjectIdGetDatum(get_rolespec_oid(spec, false));
                                183                 :     }
                                184                 : 
 2812 mail                      185              53 :     return role_oids;
                                186                 : }
                                187                 : 
                                188                 : /*
                                189                 :  * Load row security policy from the catalog, and store it in
                                190                 :  * the relation's relcache entry.
                                191                 :  *
                                192                 :  * Note that caller should have verified that pg_class.relrowsecurity
                                193                 :  * is true for this relation.
                                194                 :  */
                                195                 : void
 3124 sfrost                    196             944 : RelationBuildRowSecurity(Relation relation)
                                197                 : {
                                198                 :     MemoryContext rscxt;
 2878 bruce                     199             944 :     MemoryContext oldcxt = CurrentMemoryContext;
                                200                 :     RowSecurityDesc *rsdesc;
                                201                 :     Relation    catalog;
                                202                 :     ScanKeyData skey;
                                203                 :     SysScanDesc sscan;
                                204                 :     HeapTuple   tuple;
                                205                 : 
                                206                 :     /*
                                207                 :      * Create a memory context to hold everything associated with this
                                208                 :      * relation's row security policy.  This makes it easy to clean up during
                                209                 :      * a relcache flush.  However, to cover the possibility of an error
                                210                 :      * partway through, we don't make the context long-lived till we're done.
                                211                 :      */
  925 tgl                       212             944 :     rscxt = AllocSetContextCreate(CurrentMemoryContext,
                                213                 :                                   "row security descriptor",
                                214                 :                                   ALLOCSET_SMALL_SIZES);
                                215             944 :     MemoryContextCopyAndSetIdentifier(rscxt,
                                216                 :                                       RelationGetRelationName(relation));
                                217                 : 
                                218             944 :     rsdesc = MemoryContextAllocZero(rscxt, sizeof(RowSecurityDesc));
                                219             944 :     rsdesc->rscxt = rscxt;
                                220                 : 
                                221                 :     /*
                                222                 :      * Now scan pg_policy for RLS policies associated with this relation.
                                223                 :      * Because we use the index on (polrelid, polname), we should consistently
                                224                 :      * visit the rel's policies in name order, at least when system indexes
                                225                 :      * aren't disabled.  This simplifies equalRSDesc().
                                226                 :      */
                                227             944 :     catalog = table_open(PolicyRelationId, AccessShareLock);
                                228                 : 
                                229             944 :     ScanKeyInit(&skey,
                                230                 :                 Anum_pg_policy_polrelid,
                                231                 :                 BTEqualStrategyNumber, F_OIDEQ,
                                232                 :                 ObjectIdGetDatum(RelationGetRelid(relation)));
                                233                 : 
                                234             944 :     sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
                                235                 :                                NULL, 1, &skey);
                                236                 : 
                                237            2358 :     while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
                                238                 :     {
                                239            1414 :         Form_pg_policy policy_form = (Form_pg_policy) GETSTRUCT(tuple);
                                240                 :         RowSecurityPolicy *policy;
                                241                 :         Datum       datum;
                                242                 :         bool        isnull;
                                243                 :         char       *str_value;
                                244                 : 
                                245            1414 :         policy = MemoryContextAllocZero(rscxt, sizeof(RowSecurityPolicy));
                                246                 : 
                                247                 :         /*
                                248                 :          * Note: we must be sure that pass-by-reference data gets copied into
                                249                 :          * rscxt.  We avoid making that context current over wider spans than
                                250                 :          * we have to, though.
                                251                 :          */
                                252                 : 
                                253                 :         /* Get policy command */
                                254            1414 :         policy->polcmd = policy_form->polcmd;
                                255                 : 
                                256                 :         /* Get policy, permissive or restrictive */
                                257            1414 :         policy->permissive = policy_form->polpermissive;
                                258                 : 
                                259                 :         /* Get policy name */
                                260            1414 :         policy->policy_name =
                                261            1414 :             MemoryContextStrdup(rscxt, NameStr(policy_form->polname));
                                262                 : 
                                263                 :         /* Get policy roles */
                                264            1414 :         datum = heap_getattr(tuple, Anum_pg_policy_polroles,
                                265                 :                              RelationGetDescr(catalog), &isnull);
                                266                 :         /* shouldn't be null, but let's check for luck */
                                267            1414 :         if (isnull)
  925 tgl                       268 UBC           0 :             elog(ERROR, "unexpected null value in pg_policy.polroles");
  925 tgl                       269 CBC        1414 :         MemoryContextSwitchTo(rscxt);
                                270            1414 :         policy->roles = DatumGetArrayTypePCopy(datum);
                                271            1414 :         MemoryContextSwitchTo(oldcxt);
                                272                 : 
                                273                 :         /* Get policy qual */
                                274            1414 :         datum = heap_getattr(tuple, Anum_pg_policy_polqual,
                                275                 :                              RelationGetDescr(catalog), &isnull);
                                276            1414 :         if (!isnull)
                                277                 :         {
                                278            1249 :             str_value = TextDatumGetCString(datum);
                                279            1249 :             MemoryContextSwitchTo(rscxt);
                                280            1249 :             policy->qual = (Expr *) stringToNode(str_value);
 3124 sfrost                    281            1249 :             MemoryContextSwitchTo(oldcxt);
  925 tgl                       282            1249 :             pfree(str_value);
                                283                 :         }
                                284                 :         else
                                285             165 :             policy->qual = NULL;
                                286                 : 
                                287                 :         /* Get WITH CHECK qual */
                                288            1414 :         datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
                                289                 :                              RelationGetDescr(catalog), &isnull);
                                290            1414 :         if (!isnull)
                                291                 :         {
                                292             425 :             str_value = TextDatumGetCString(datum);
                                293             425 :             MemoryContextSwitchTo(rscxt);
                                294             425 :             policy->with_check_qual = (Expr *) stringToNode(str_value);
                                295             425 :             MemoryContextSwitchTo(oldcxt);
                                296             425 :             pfree(str_value);
                                297                 :         }
                                298                 :         else
                                299             989 :             policy->with_check_qual = NULL;
                                300                 : 
                                301                 :         /* We want to cache whether there are SubLinks in these expressions */
                                302            2702 :         policy->hassublinks = checkExprHasSubLink((Node *) policy->qual) ||
                                303            1288 :             checkExprHasSubLink((Node *) policy->with_check_qual);
                                304                 : 
                                305                 :         /*
                                306                 :          * Add this object to list.  For historical reasons, the list is built
                                307                 :          * in reverse order.
                                308                 :          */
                                309            1414 :         MemoryContextSwitchTo(rscxt);
                                310            1414 :         rsdesc->policies = lcons(policy, rsdesc->policies);
 2997                           311            1414 :         MemoryContextSwitchTo(oldcxt);
                                312                 :     }
                                313                 : 
  925                           314             944 :     systable_endscan(sscan);
                                315             944 :     table_close(catalog, AccessShareLock);
                                316                 : 
                                317                 :     /*
                                318                 :      * Success.  Reparent the descriptor's memory context under
                                319                 :      * CacheMemoryContext so that it will live indefinitely, then attach the
                                320                 :      * policy descriptor to the relcache entry.
                                321                 :      */
                                322             944 :     MemoryContextSetParent(rscxt, CacheMemoryContext);
                                323                 : 
 3068 sfrost                    324             944 :     relation->rd_rsdesc = rsdesc;
 3124                           325             944 : }
                                326                 : 
                                327                 : /*
                                328                 :  * RemovePolicyById -
                                329                 :  *   remove a policy by its OID.  If a policy does not exist with the provided
                                330                 :  *   oid, then an error is raised.
                                331                 :  *
                                332                 :  * policy_id - the oid of the policy.
                                333                 :  */
                                334                 : void
                                335             257 : RemovePolicyById(Oid policy_id)
                                336                 : {
                                337                 :     Relation    pg_policy_rel;
                                338                 :     SysScanDesc sscan;
                                339                 :     ScanKeyData skey[1];
                                340                 :     HeapTuple   tuple;
                                341                 :     Oid         relid;
                                342                 :     Relation    rel;
                                343                 : 
 1539 andres                    344             257 :     pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
                                345                 : 
                                346                 :     /*
                                347                 :      * Find the policy to delete.
                                348                 :      */
 3124 sfrost                    349             257 :     ScanKeyInit(&skey[0],
                                350                 :                 Anum_pg_policy_oid,
                                351                 :                 BTEqualStrategyNumber, F_OIDEQ,
                                352                 :                 ObjectIdGetDatum(policy_id));
                                353                 : 
 3055                           354             257 :     sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
                                355                 :                                NULL, 1, skey);
                                356                 : 
 3124                           357             257 :     tuple = systable_getnext(sscan);
                                358                 : 
                                359                 :     /* If the policy exists, then remove it, otherwise raise an error. */
                                360             257 :     if (!HeapTupleIsValid(tuple))
 3055 sfrost                    361 UBC           0 :         elog(ERROR, "could not find tuple for policy %u", policy_id);
                                362                 : 
                                363                 :     /*
                                364                 :      * Open and exclusive-lock the relation the policy belongs to.  (We need
                                365                 :      * exclusive lock to lock out queries that might otherwise depend on the
                                366                 :      * set of policies the rel has; furthermore we've got to hold the lock
                                367                 :      * till commit.)
                                368                 :      */
 3055 sfrost                    369 CBC         257 :     relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
                                370                 : 
 1539 andres                    371             257 :     rel = table_open(relid, AccessExclusiveLock);
 2314 rhaas                     372             257 :     if (rel->rd_rel->relkind != RELKIND_RELATION &&
                                373              24 :         rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 3124 sfrost                    374 UBC           0 :         ereport(ERROR,
                                375                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                376                 :                  errmsg("\"%s\" is not a table",
                                377                 :                         RelationGetRelationName(rel))));
                                378                 : 
 3124 sfrost                    379 CBC         257 :     if (!allowSystemTableMods && IsSystemRelation(rel))
 3124 sfrost                    380 UBC           0 :         ereport(ERROR,
                                381                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                382                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                                383                 :                         RelationGetRelationName(rel))));
                                384                 : 
 2258 tgl                       385 CBC         257 :     CatalogTupleDelete(pg_policy_rel, &tuple->t_self);
                                386                 : 
 3124 sfrost                    387             257 :     systable_endscan(sscan);
                                388                 : 
                                389                 :     /*
                                390                 :      * Note that, unlike some of the other flags in pg_class, relrowsecurity
                                391                 :      * is not just an indication of if policies exist.  When relrowsecurity is
                                392                 :      * set by a user, then all access to the relation must be through a
                                393                 :      * policy.  If no policy is defined for the relation then a default-deny
                                394                 :      * policy is created and all records are filtered (except for queries from
                                395                 :      * the owner).
                                396                 :      */
                                397             257 :     CacheInvalidateRelcache(rel);
                                398                 : 
 1539 andres                    399             257 :     table_close(rel, NoLock);
                                400                 : 
                                401                 :     /* Clean up */
                                402             257 :     table_close(pg_policy_rel, RowExclusiveLock);
 3124 sfrost                    403             257 : }
                                404                 : 
                                405                 : /*
                                406                 :  * RemoveRoleFromObjectPolicy -
                                407                 :  *   remove a role from a policy's applicable-roles list.
                                408                 :  *
                                409                 :  * Returns true if the role was successfully removed from the policy.
                                410                 :  * Returns false if the role was not removed because it would have left
                                411                 :  * polroles empty (which is disallowed, though perhaps it should not be).
                                412                 :  * On false return, the caller should instead drop the policy altogether.
                                413                 :  *
                                414                 :  * roleid - the oid of the role to remove
                                415                 :  * classid - should always be PolicyRelationId
                                416                 :  * policy_id - the oid of the policy.
                                417                 :  */
                                418                 : bool
 2676                           419              21 : RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
                                420                 : {
                                421                 :     Relation    pg_policy_rel;
                                422                 :     SysScanDesc sscan;
                                423                 :     ScanKeyData skey[1];
                                424                 :     HeapTuple   tuple;
                                425                 :     Oid         relid;
                                426                 :     ArrayType  *policy_roles;
                                427                 :     Datum       roles_datum;
                                428                 :     Oid        *roles;
                                429                 :     int         num_roles;
                                430                 :     Datum      *role_oids;
                                431                 :     bool        attr_isnull;
  660 tgl                       432              21 :     bool        keep_policy = true;
                                433                 :     int         i,
                                434                 :                 j;
                                435                 : 
 2676 sfrost                    436              21 :     Assert(classid == PolicyRelationId);
                                437                 : 
 1539 andres                    438              21 :     pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
                                439                 : 
                                440                 :     /*
                                441                 :      * Find the policy to update.
                                442                 :      */
 2676 sfrost                    443              21 :     ScanKeyInit(&skey[0],
                                444                 :                 Anum_pg_policy_oid,
                                445                 :                 BTEqualStrategyNumber, F_OIDEQ,
                                446                 :                 ObjectIdGetDatum(policy_id));
                                447                 : 
                                448              21 :     sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
                                449                 :                                NULL, 1, skey);
                                450                 : 
                                451              21 :     tuple = systable_getnext(sscan);
                                452                 : 
                                453                 :     /* Raise an error if we don't find the policy. */
                                454              21 :     if (!HeapTupleIsValid(tuple))
 2676 sfrost                    455 UBC           0 :         elog(ERROR, "could not find tuple for policy %u", policy_id);
                                456                 : 
                                457                 :     /* Identify rel the policy belongs to */
 2676 sfrost                    458 CBC          21 :     relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
                                459                 : 
                                460                 :     /* Get the current set of roles */
                                461              21 :     roles_datum = heap_getattr(tuple,
                                462                 :                                Anum_pg_policy_polroles,
                                463                 :                                RelationGetDescr(pg_policy_rel),
                                464                 :                                &attr_isnull);
                                465                 : 
                                466              21 :     Assert(!attr_isnull);
                                467                 : 
                                468              21 :     policy_roles = DatumGetArrayTypePCopy(roles_datum);
  653 tgl                       469              21 :     roles = (Oid *) ARR_DATA_PTR(policy_roles);
                                470              21 :     num_roles = ARR_DIMS(policy_roles)[0];
                                471                 : 
                                472                 :     /*
                                473                 :      * Rebuild the polroles array, without any mentions of the target role.
                                474                 :      * Ordinarily there'd be exactly one, but we must cope with duplicate
                                475                 :      * mentions, since CREATE/ALTER POLICY historically have allowed that.
                                476                 :      */
                                477              21 :     role_oids = (Datum *) palloc(num_roles * sizeof(Datum));
                                478              60 :     for (i = 0, j = 0; i < num_roles; i++)
                                479                 :     {
                                480              39 :         if (roles[i] != roleid)
                                481              12 :             role_oids[j++] = ObjectIdGetDatum(roles[i]);
                                482                 :     }
                                483              21 :     num_roles = j;
                                484                 : 
                                485                 :     /* If any roles remain, update the policy entry. */
                                486              21 :     if (num_roles > 0)
                                487                 :     {
                                488                 :         ArrayType  *role_ids;
                                489                 :         Datum       values[Natts_pg_policy];
                                490                 :         bool        isnull[Natts_pg_policy];
                                491                 :         bool        replaces[Natts_pg_policy];
                                492                 :         HeapTuple   new_tuple;
                                493                 :         HeapTuple   reltup;
                                494                 :         ObjectAddress target;
                                495                 :         ObjectAddress myself;
                                496                 : 
                                497                 :         /* zero-clear */
 2676 sfrost                    498              12 :         memset(values, 0, sizeof(values));
                                499              12 :         memset(replaces, 0, sizeof(replaces));
                                500              12 :         memset(isnull, 0, sizeof(isnull));
                                501                 : 
                                502                 :         /* This is the array for the new tuple */
  282 peter                     503 GNC          12 :         role_ids = construct_array_builtin(role_oids, num_roles, OIDOID);
 2676 sfrost                    504 ECB             : 
 2676 sfrost                    505 CBC          12 :         replaces[Anum_pg_policy_polroles - 1] = true;
 2676 sfrost                    506 GIC          12 :         values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
 2676 sfrost                    507 ECB             : 
 2676 sfrost                    508 GIC          12 :         new_tuple = heap_modify_tuple(tuple,
                                509                 :                                       RelationGetDescr(pg_policy_rel),
 2676 sfrost                    510 ECB             :                                       values, isnull, replaces);
 2259 alvherre                  511 GIC          12 :         CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
                                512                 : 
  653 tgl                       513 ECB             :         /* Remove all the old shared dependencies (roles) */
  653 tgl                       514 GIC          12 :         deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
                                515                 : 
  653 tgl                       516 ECB             :         /* Record the new shared dependencies (roles) */
 2676 sfrost                    517 CBC          12 :         myself.classId = PolicyRelationId;
                                518              12 :         myself.objectId = policy_id;
 2676 sfrost                    519 GIC          12 :         myself.objectSubId = 0;
 2676 sfrost                    520 ECB             : 
 2676 sfrost                    521 CBC          12 :         target.classId = AuthIdRelationId;
                                522              12 :         target.objectSubId = 0;
 2676 sfrost                    523 GIC          24 :         for (i = 0; i < num_roles; i++)
 2676 sfrost                    524 ECB             :         {
 2676 sfrost                    525 GIC          12 :             target.objectId = DatumGetObjectId(role_oids[i]);
 2676 sfrost                    526 ECB             :             /* no need for dependency on the public role */
 2676 sfrost                    527 CBC          12 :             if (target.objectId != ACL_ID_PUBLIC)
 2676 sfrost                    528 GIC          12 :                 recordSharedDependencyOn(&myself, &target,
                                529                 :                                          SHARED_DEPENDENCY_POLICY);
                                530                 :         }
 2676 sfrost                    531 ECB             : 
 2676 sfrost                    532 GIC          12 :         InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
 2676 sfrost                    533 ECB             : 
 2676 sfrost                    534 GIC          12 :         heap_freetuple(new_tuple);
                                535                 : 
  660 tgl                       536 ECB             :         /* Make updates visible */
  660 tgl                       537 GIC          12 :         CommandCounterIncrement();
                                538                 : 
                                539                 :         /*
                                540                 :          * Invalidate relcache entry for rel the policy belongs to, to force
                                541                 :          * redoing any dependent plans.  In case of a race condition where the
                                542                 :          * rel was just dropped, we need do nothing.
  653 tgl                       543 ECB             :          */
  653 tgl                       544 CBC          12 :         reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
  653 tgl                       545 GIC          12 :         if (HeapTupleIsValid(reltup))
  660 tgl                       546 ECB             :         {
  653 tgl                       547 CBC          12 :             CacheInvalidateRelcacheByTuple(reltup);
  653 tgl                       548 GIC          12 :             ReleaseSysCache(reltup);
                                549                 :         }
                                550                 :     }
                                551                 :     else
                                552                 :     {
  653 tgl                       553 ECB             :         /* No roles would remain, so drop the policy instead. */
  653 tgl                       554 GIC           9 :         keep_policy = false;
                                555                 :     }
                                556                 : 
 2676 sfrost                    557 ECB             :     /* Clean up. */
 2676 sfrost                    558 GIC          21 :     systable_endscan(sscan);
 2653 tgl                       559 ECB             : 
 1539 andres                    560 GIC          21 :     table_close(pg_policy_rel, RowExclusiveLock);
 2676 sfrost                    561 ECB             : 
  660 tgl                       562 GIC          21 :     return keep_policy;
                                563                 : }
                                564                 : 
                                565                 : /*
                                566                 :  * CreatePolicy -
                                567                 :  *   handles the execution of the CREATE POLICY command.
                                568                 :  *
                                569                 :  * stmt - the CreatePolicyStmt that describes the policy to create.
                                570                 :  */
 2959 alvherre                  571 ECB             : ObjectAddress
 3124 sfrost                    572 GIC         314 : CreatePolicy(CreatePolicyStmt *stmt)
                                573                 : {
                                574                 :     Relation    pg_policy_rel;
                                575                 :     Oid         policy_id;
                                576                 :     Relation    target_table;
                                577                 :     Oid         table_id;
                                578                 :     char        polcmd;
 2812 mail                      579 ECB             :     Datum      *role_oids;
 2812 mail                      580 GIC         314 :     int         nitems = 0;
                                581                 :     ArrayType  *role_ids;
                                582                 :     ParseState *qual_pstate;
                                583                 :     ParseState *with_check_pstate;
                                584                 :     ParseNamespaceItem *nsitem;
                                585                 :     Node       *qual;
                                586                 :     Node       *with_check_qual;
                                587                 :     ScanKeyData skey[2];
                                588                 :     SysScanDesc sscan;
                                589                 :     HeapTuple   policy_tuple;
                                590                 :     Datum       values[Natts_pg_policy];
                                591                 :     bool        isnull[Natts_pg_policy];
                                592                 :     ObjectAddress target;
                                593                 :     ObjectAddress myself;
                                594                 :     int         i;
                                595                 : 
 3124 sfrost                    596 ECB             :     /* Parse command */
 2788 sfrost                    597 GIC         314 :     polcmd = parse_policy_command(stmt->cmd_name);
                                598                 : 
                                599                 :     /*
                                600                 :      * If the command is SELECT or DELETE then WITH CHECK should be NULL.
 3124 sfrost                    601 ECB             :      */
 3055 sfrost                    602 CBC         314 :     if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
 3124 sfrost                    603 GBC          68 :         && stmt->with_check != NULL)
 3124 sfrost                    604 UIC           0 :         ereport(ERROR,
                                605                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                606                 :                  errmsg("WITH CHECK cannot be applied to SELECT or DELETE")));
                                607                 : 
                                608                 :     /*
                                609                 :      * If the command is INSERT then WITH CHECK should be the only expression
                                610                 :      * provided.
 3124 sfrost                    611 ECB             :      */
 3055 sfrost                    612 GBC         314 :     if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL)
 3124 sfrost                    613 UIC           0 :         ereport(ERROR,
                                614                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                615                 :                  errmsg("only WITH CHECK expression allowed for INSERT")));
                                616                 : 
 3124 sfrost                    617 ECB             :     /* Collect role ids */
 2812 mail                      618 CBC         314 :     role_oids = policy_role_list_to_array(stmt->roles, &nitems);
  282 peter                     619 GNC         314 :     role_ids = construct_array_builtin(role_oids, nitems, OIDOID);
 3124 sfrost                    620 ECB             : 
                                621                 :     /* Parse the supplied clause */
 3124 sfrost                    622 GIC         314 :     qual_pstate = make_parsestate(NULL);
                                623             314 :     with_check_pstate = make_parsestate(NULL);
 3124 sfrost                    624 ECB             : 
                                625                 :     /* zero-clear */
 2878 bruce                     626 GIC         314 :     memset(values, 0, sizeof(values));
                                627             314 :     memset(isnull, 0, sizeof(isnull));
 3124 sfrost                    628 ECB             : 
                                629                 :     /* Get id of table.  Also handles permissions checks. */
 3124 sfrost                    630 GIC         314 :     table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
                                631                 :                                         0,
                                632                 :                                         RangeVarCallbackForPolicy,
                                633                 :                                         (void *) stmt);
 3124 sfrost                    634 ECB             : 
                                635                 :     /* Open target_table to build quals. No additional lock is necessary. */
 3124 sfrost                    636 GIC         313 :     target_table = relation_open(table_id, NoLock);
 3124 sfrost                    637 ECB             : 
                                638                 :     /* Add for the regular security quals */
 1193 tgl                       639 GIC         313 :     nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
 1193 tgl                       640 ECB             :                                            AccessShareLock,
                                641                 :                                            NULL, false, false);
 1193 tgl                       642 GIC         313 :     addNSItemToQuery(qual_pstate, nsitem, false, true, true);
 3124 sfrost                    643 ECB             : 
                                644                 :     /* Add for the with-check quals */
 1193 tgl                       645 GIC         313 :     nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
 1193 tgl                       646 ECB             :                                            AccessShareLock,
                                647                 :                                            NULL, false, false);
 1193 tgl                       648 CBC         313 :     addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
                                649                 : 
 3124 sfrost                    650 GIC         313 :     qual = transformWhereClause(qual_pstate,
                                651                 :                                 stmt->qual,
                                652                 :                                 EXPR_KIND_POLICY,
 3124 sfrost                    653 ECB             :                                 "POLICY");
                                654                 : 
 3124 sfrost                    655 GIC         310 :     with_check_qual = transformWhereClause(with_check_pstate,
                                656                 :                                            stmt->with_check,
                                657                 :                                            EXPR_KIND_POLICY,
                                658                 :                                            "POLICY");
 3124 sfrost                    659 ECB             : 
 2829 mail                      660                 :     /* Fix up collation information */
 2829 mail                      661 GIC         310 :     assign_expr_collations(qual_pstate, qual);
                                662             310 :     assign_expr_collations(with_check_pstate, with_check_qual);
 2829 mail                      663 ECB             : 
                                664                 :     /* Open pg_policy catalog */
 1539 andres                    665 GIC         310 :     pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
 3124 sfrost                    666 ECB             : 
                                667                 :     /* Set key - policy's relation id. */
 3124 sfrost                    668 GIC         310 :     ScanKeyInit(&skey[0],
                                669                 :                 Anum_pg_policy_polrelid,
                                670                 :                 BTEqualStrategyNumber, F_OIDEQ,
                                671                 :                 ObjectIdGetDatum(table_id));
 3124 sfrost                    672 ECB             : 
                                673                 :     /* Set key - policy's name. */
 3124 sfrost                    674 GIC         310 :     ScanKeyInit(&skey[1],
 3055 sfrost                    675 ECB             :                 Anum_pg_policy_polname,
                                676                 :                 BTEqualStrategyNumber, F_NAMEEQ,
 3124 sfrost                    677 CBC         310 :                 CStringGetDatum(stmt->policy_name));
                                678                 : 
 3055 sfrost                    679 GIC         310 :     sscan = systable_beginscan(pg_policy_rel,
                                680                 :                                PolicyPolrelidPolnameIndexId, true, NULL, 2,
 3124 sfrost                    681 ECB             :                                skey);
                                682                 : 
 3055 sfrost                    683 GIC         310 :     policy_tuple = systable_getnext(sscan);
 3124 sfrost                    684 ECB             : 
                                685                 :     /* Complain if the policy name already exists for the table */
 3055 sfrost                    686 GIC         310 :     if (HeapTupleIsValid(policy_tuple))
 3124                           687               3 :         ereport(ERROR,
                                688                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
                                689                 :                  errmsg("policy \"%s\" for table \"%s\" already exists",
 2118 tgl                       690 ECB             :                         stmt->policy_name, RelationGetRelationName(target_table))));
                                691                 : 
 1601 andres                    692 CBC         307 :     policy_id = GetNewOidWithIndex(pg_policy_rel, PolicyOidIndexId,
 1601 andres                    693 ECB             :                                    Anum_pg_policy_oid);
 1601 andres                    694 CBC         307 :     values[Anum_pg_policy_oid - 1] = ObjectIdGetDatum(policy_id);
 3055 sfrost                    695 GIC         307 :     values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
 2997 tgl                       696 CBC         307 :     values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein,
 2118 tgl                       697 ECB             :                                                              CStringGetDatum(stmt->policy_name));
 2997 tgl                       698 CBC         307 :     values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
 2316 sfrost                    699 GIC         307 :     values[Anum_pg_policy_polpermissive - 1] = BoolGetDatum(stmt->permissive);
 3055                           700             307 :     values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
 3124 sfrost                    701 ECB             : 
                                702                 :     /* Add qual if present. */
 3124 sfrost                    703 GIC         307 :     if (qual)
 2997 tgl                       704 CBC         281 :         values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual));
                                705                 :     else
 3055 sfrost                    706 GIC          26 :         isnull[Anum_pg_policy_polqual - 1] = true;
 3124 sfrost                    707 ECB             : 
                                708                 :     /* Add WITH CHECK qual if present */
 3124 sfrost                    709 GIC         307 :     if (with_check_qual)
 2997 tgl                       710 CBC          61 :         values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual));
                                711                 :     else
 3055 sfrost                    712             246 :         isnull[Anum_pg_policy_polwithcheck - 1] = true;
                                713                 : 
 3055 sfrost                    714 GIC         307 :     policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values,
 3055 sfrost                    715 ECB             :                                    isnull);
                                716                 : 
 1601 andres                    717 GIC         307 :     CatalogTupleInsert(pg_policy_rel, policy_tuple);
 3124 sfrost                    718 ECB             : 
                                719                 :     /* Record Dependencies */
 3124 sfrost                    720 CBC         307 :     target.classId = RelationRelationId;
 3124 sfrost                    721 GIC         307 :     target.objectId = table_id;
 3124 sfrost                    722 CBC         307 :     target.objectSubId = 0;
 3124 sfrost                    723 ECB             : 
 3055 sfrost                    724 CBC         307 :     myself.classId = PolicyRelationId;
 3055 sfrost                    725 GIC         307 :     myself.objectId = policy_id;
 3124 sfrost                    726 CBC         307 :     myself.objectSubId = 0;
                                727                 : 
                                728             307 :     recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
                                729                 : 
 3124 sfrost                    730 GIC         307 :     recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable,
 3124 sfrost                    731 ECB             :                            DEPENDENCY_NORMAL);
                                732                 : 
 3124 sfrost                    733 GIC         307 :     recordDependencyOnExpr(&myself, with_check_qual,
                                734                 :                            with_check_pstate->p_rtable, DEPENDENCY_NORMAL);
 3124 sfrost                    735 ECB             : 
 2812 mail                      736                 :     /* Register role dependencies */
 2812 mail                      737 CBC         307 :     target.classId = AuthIdRelationId;
 2812 mail                      738 GIC         307 :     target.objectSubId = 0;
 2812 mail                      739 CBC         632 :     for (i = 0; i < nitems; i++)
                                740                 :     {
                                741             325 :         target.objectId = DatumGetObjectId(role_oids[i]);
 2812 mail                      742 ECB             :         /* no dependency if public */
 2812 mail                      743 GIC         325 :         if (target.objectId != ACL_ID_PUBLIC)
                                744              65 :             recordSharedDependencyOn(&myself, &target,
                                745                 :                                      SHARED_DEPENDENCY_POLICY);
 2812 mail                      746 ECB             :     }
                                747                 : 
 2811 mail                      748 GIC         307 :     InvokeObjectPostCreateHook(PolicyRelationId, policy_id, 0);
 2811 mail                      749 ECB             : 
                                750                 :     /* Invalidate Relation Cache */
 3124 sfrost                    751 GIC         307 :     CacheInvalidateRelcache(target_table);
 3124 sfrost                    752 ECB             : 
                                753                 :     /* Clean up. */
 3055 sfrost                    754 CBC         307 :     heap_freetuple(policy_tuple);
 3124                           755             307 :     free_parsestate(qual_pstate);
                                756             307 :     free_parsestate(with_check_pstate);
                                757             307 :     systable_endscan(sscan);
 3124 sfrost                    758 GIC         307 :     relation_close(target_table, NoLock);
 1539 andres                    759 CBC         307 :     table_close(pg_policy_rel, RowExclusiveLock);
                                760                 : 
 2959 alvherre                  761 GIC         307 :     return myself;
                                762                 : }
                                763                 : 
                                764                 : /*
                                765                 :  * AlterPolicy -
                                766                 :  *   handles the execution of the ALTER POLICY command.
                                767                 :  *
                                768                 :  * stmt - the AlterPolicyStmt that describes the policy and how to alter it.
 3124 sfrost                    769 ECB             :  */
                                770                 : ObjectAddress
 3124 sfrost                    771 GIC          42 : AlterPolicy(AlterPolicyStmt *stmt)
                                772                 : {
                                773                 :     Relation    pg_policy_rel;
                                774                 :     Oid         policy_id;
 2878 bruce                     775 ECB             :     Relation    target_table;
                                776                 :     Oid         table_id;
 2812 tgl                       777 CBC          42 :     Datum      *role_oids = NULL;
      mail                      778              42 :     int         nitems = 0;
 2878 bruce                     779              42 :     ArrayType  *role_ids = NULL;
                                780              42 :     List       *qual_parse_rtable = NIL;
                                781              42 :     List       *with_check_parse_rtable = NIL;
 2878 bruce                     782 GIC          42 :     Node       *qual = NULL;
                                783              42 :     Node       *with_check_qual = NULL;
                                784                 :     ScanKeyData skey[2];
                                785                 :     SysScanDesc sscan;
                                786                 :     HeapTuple   policy_tuple;
                                787                 :     HeapTuple   new_tuple;
                                788                 :     Datum       values[Natts_pg_policy];
                                789                 :     bool        isnull[Natts_pg_policy];
                                790                 :     bool        replaces[Natts_pg_policy];
                                791                 :     ObjectAddress target;
                                792                 :     ObjectAddress myself;
                                793                 :     Datum       polcmd_datum;
                                794                 :     char        polcmd;
                                795                 :     bool        polcmd_isnull;
                                796                 :     int         i;
 3124 sfrost                    797 ECB             : 
                                798                 :     /* Parse role_ids */
 3124 sfrost                    799 CBC          42 :     if (stmt->roles != NULL)
 2812 mail                      800 ECB             :     {
 2812 mail                      801 GIC           6 :         role_oids = policy_role_list_to_array(stmt->roles, &nitems);
  282 peter                     802 GNC           6 :         role_ids = construct_array_builtin(role_oids, nitems, OIDOID);
 2812 mail                      803 ECB             :     }
                                804                 : 
                                805                 :     /* Get id of table.  Also handles permissions checks. */
 3124 sfrost                    806 GIC          42 :     table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
                                807                 :                                         0,
 3124 sfrost                    808 ECB             :                                         RangeVarCallbackForPolicy,
                                809                 :                                         (void *) stmt);
                                810                 : 
 3124 sfrost                    811 CBC          36 :     target_table = relation_open(table_id, NoLock);
                                812                 : 
                                813                 :     /* Parse the using policy clause */
                                814              36 :     if (stmt->qual)
                                815                 :     {
 1193 tgl                       816 ECB             :         ParseNamespaceItem *nsitem;
 2878 bruce                     817 GIC          33 :         ParseState *qual_pstate = make_parsestate(NULL);
                                818                 : 
 1193 tgl                       819              33 :         nsitem = addRangeTableEntryForRelation(qual_pstate, target_table,
 1193 tgl                       820 ECB             :                                                AccessShareLock,
                                821                 :                                                NULL, false, false);
 3124 sfrost                    822                 : 
 1193 tgl                       823 GIC          33 :         addNSItemToQuery(qual_pstate, nsitem, false, true, true);
                                824                 : 
  660                           825              33 :         qual = transformWhereClause(qual_pstate, stmt->qual,
                                826                 :                                     EXPR_KIND_POLICY,
 3055 sfrost                    827 ECB             :                                     "POLICY");
                                828                 : 
 2829 mail                      829                 :         /* Fix up collation information */
 2829 mail                      830 CBC          33 :         assign_expr_collations(qual_pstate, qual);
                                831                 : 
 3124 sfrost                    832 GIC          33 :         qual_parse_rtable = qual_pstate->p_rtable;
                                833              33 :         free_parsestate(qual_pstate);
 3124 sfrost                    834 ECB             :     }
                                835                 : 
                                836                 :     /* Parse the with-check policy clause */
 3124 sfrost                    837 GBC          36 :     if (stmt->with_check)
                                838                 :     {
 1193 tgl                       839 EUB             :         ParseNamespaceItem *nsitem;
 2878 bruce                     840 UIC           0 :         ParseState *with_check_pstate = make_parsestate(NULL);
                                841                 : 
 1193 tgl                       842               0 :         nsitem = addRangeTableEntryForRelation(with_check_pstate, target_table,
 1193 tgl                       843 EUB             :                                                AccessShareLock,
                                844                 :                                                NULL, false, false);
 3124 sfrost                    845                 : 
 1193 tgl                       846 UIC           0 :         addNSItemToQuery(with_check_pstate, nsitem, false, true, true);
                                847                 : 
 3124 sfrost                    848               0 :         with_check_qual = transformWhereClause(with_check_pstate,
                                849                 :                                                stmt->with_check,
                                850                 :                                                EXPR_KIND_POLICY,
 3055 sfrost                    851 EUB             :                                                "POLICY");
                                852                 : 
 2829 mail                      853                 :         /* Fix up collation information */
 2829 mail                      854 UBC           0 :         assign_expr_collations(with_check_pstate, with_check_qual);
                                855                 : 
 3124 sfrost                    856 UIC           0 :         with_check_parse_rtable = with_check_pstate->p_rtable;
                                857               0 :         free_parsestate(with_check_pstate);
 3124 sfrost                    858 ECB             :     }
                                859                 : 
                                860                 :     /* zero-clear */
 2878 bruce                     861 GIC          36 :     memset(values, 0, sizeof(values));
 3124 sfrost                    862              36 :     memset(replaces, 0, sizeof(replaces));
 2878 bruce                     863 CBC          36 :     memset(isnull, 0, sizeof(isnull));
                                864                 : 
                                865                 :     /* Find policy to update. */
 1539 andres                    866              36 :     pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
                                867                 : 
                                868                 :     /* Set key - policy's relation id. */
 3124 sfrost                    869 GIC          36 :     ScanKeyInit(&skey[0],
                                870                 :                 Anum_pg_policy_polrelid,
                                871                 :                 BTEqualStrategyNumber, F_OIDEQ,
 3124 sfrost                    872 ECB             :                 ObjectIdGetDatum(table_id));
                                873                 : 
                                874                 :     /* Set key - policy's name. */
 3124 sfrost                    875 CBC          36 :     ScanKeyInit(&skey[1],
                                876                 :                 Anum_pg_policy_polname,
 3124 sfrost                    877 ECB             :                 BTEqualStrategyNumber, F_NAMEEQ,
 3124 sfrost                    878 GIC          36 :                 CStringGetDatum(stmt->policy_name));
                                879                 : 
 3055                           880              36 :     sscan = systable_beginscan(pg_policy_rel,
 3055 sfrost                    881 ECB             :                                PolicyPolrelidPolnameIndexId, true, NULL, 2,
                                882                 :                                skey);
                                883                 : 
 3055 sfrost                    884 CBC          36 :     policy_tuple = systable_getnext(sscan);
 3124 sfrost                    885 EUB             : 
                                886                 :     /* Check that the policy is found, raise an error if not. */
 3055 sfrost                    887 GIC          36 :     if (!HeapTupleIsValid(policy_tuple))
 3124 sfrost                    888 UIC           0 :         ereport(ERROR,
                                889                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                                890                 :                  errmsg("policy \"%s\" for table \"%s\" does not exist",
                                891                 :                         stmt->policy_name,
 3124 sfrost                    892 ECB             :                         RelationGetRelationName(target_table))));
                                893                 : 
                                894                 :     /* Get policy command */
 2788 sfrost                    895 CBC          36 :     polcmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
 2495 rhaas                     896 ECB             :                                 RelationGetDescr(pg_policy_rel),
                                897                 :                                 &polcmd_isnull);
 2997 tgl                       898 GIC          36 :     Assert(!polcmd_isnull);
 2788 sfrost                    899              36 :     polcmd = DatumGetChar(polcmd_datum);
                                900                 : 
 3124 sfrost                    901 ECB             :     /*
 3124 sfrost                    902 EUB             :      * If the command is SELECT or DELETE then WITH CHECK should be NULL.
                                903                 :      */
 3055 sfrost                    904 GIC          36 :     if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
 3124 sfrost                    905 UIC           0 :         && stmt->with_check != NULL)
                                906               0 :         ereport(ERROR,
                                907                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                908                 :                  errmsg("only USING expression allowed for SELECT, DELETE")));
                                909                 : 
                                910                 :     /*
 2878 bruce                     911 ECB             :      * If the command is INSERT then WITH CHECK should be the only expression
 2878 bruce                     912 EUB             :      * provided.
 3124 sfrost                    913                 :      */
 3055 sfrost                    914 GIC          36 :     if ((polcmd == ACL_INSERT_CHR)
 3124 sfrost                    915 UIC           0 :         && stmt->qual != NULL)
                                916               0 :         ereport(ERROR,
 3124 sfrost                    917 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                918                 :                  errmsg("only WITH CHECK expression allowed for INSERT")));
                                919                 : 
 1601 andres                    920 GIC          36 :     policy_id = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
 3124 sfrost                    921 ECB             : 
 3124 sfrost                    922 CBC          36 :     if (role_ids != NULL)
                                923                 :     {
 3055 sfrost                    924 GIC           6 :         replaces[Anum_pg_policy_polroles - 1] = true;
                                925               6 :         values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
                                926                 :     }
                                927                 :     else
                                928                 :     {
                                929                 :         Oid        *roles;
                                930                 :         Datum       roles_datum;
                                931                 :         bool        attr_isnull;
                                932                 :         ArrayType  *policy_roles;
                                933                 : 
                                934                 :         /*
                                935                 :          * We need to pull the set of roles this policy applies to from what's
                                936                 :          * in the catalog, so that we can recreate the dependencies correctly
 2495 rhaas                     937 ECB             :          * for the policy.
                                938                 :          */
                                939                 : 
 2676 sfrost                    940 CBC          30 :         roles_datum = heap_getattr(policy_tuple, Anum_pg_policy_polroles,
                                941                 :                                    RelationGetDescr(pg_policy_rel),
 2676 sfrost                    942 ECB             :                                    &attr_isnull);
 2676 sfrost                    943 GIC          30 :         Assert(!attr_isnull);
 2676 sfrost                    944 ECB             : 
 2676 sfrost                    945 GIC          30 :         policy_roles = DatumGetArrayTypePCopy(roles_datum);
 2676 sfrost                    946 ECB             : 
 2676 sfrost                    947 GIC          30 :         roles = (Oid *) ARR_DATA_PTR(policy_roles);
 2676 sfrost                    948 ECB             : 
 2676 sfrost                    949 GIC          30 :         nitems = ARR_DIMS(policy_roles)[0];
 2676 sfrost                    950 ECB             : 
 2676 sfrost                    951 CBC          30 :         role_oids = (Datum *) palloc(nitems * sizeof(Datum));
                                952                 : 
 2676 sfrost                    953 GIC          63 :         for (i = 0; i < nitems; i++)
 2676 sfrost                    954 CBC          33 :             role_oids[i] = ObjectIdGetDatum(roles[i]);
                                955                 :     }
 3124 sfrost                    956 ECB             : 
 3124 sfrost                    957 GIC          36 :     if (qual != NULL)
 3124 sfrost                    958 ECB             :     {
 3055 sfrost                    959 GIC          33 :         replaces[Anum_pg_policy_polqual - 1] = true;
                                960                 :         values[Anum_pg_policy_polqual - 1]
 3124                           961              33 :             = CStringGetTextDatum(nodeToString(qual));
                                962                 :     }
                                963                 :     else
                                964                 :     {
                                965                 :         Datum       value_datum;
                                966                 :         bool        attr_isnull;
                                967                 : 
                                968                 :         /*
                                969                 :          * We need to pull the USING expression and build the range table for
                                970                 :          * the policy from what's in the catalog, so that we can recreate the
                                971                 :          * dependencies correctly for the policy.
 2676 sfrost                    972 ECB             :          */
                                973                 : 
                                974                 :         /* Check if the policy has a USING expr */
 2676 sfrost                    975 CBC           3 :         value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polqual,
                                976                 :                                    RelationGetDescr(pg_policy_rel),
                                977                 :                                    &attr_isnull);
 2676 sfrost                    978 GIC           3 :         if (!attr_isnull)
                                979                 :         {
                                980                 :             char       *qual_value;
 2579 tgl                       981 ECB             :             ParseState *qual_pstate;
                                982                 : 
 2676 sfrost                    983                 :             /* parsestate is built just to build the range table */
 2676 sfrost                    984 CBC           3 :             qual_pstate = make_parsestate(NULL);
                                985                 : 
 2676 sfrost                    986 GIC           3 :             qual_value = TextDatumGetCString(value_datum);
 2676 sfrost                    987 CBC           3 :             qual = stringToNode(qual_value);
                                988                 : 
                                989                 :             /* Add this rel to the parsestate's rangetable, for dependencies */
 1193 tgl                       990 GIC           3 :             (void) addRangeTableEntryForRelation(qual_pstate, target_table,
 1193 tgl                       991 ECB             :                                                  AccessShareLock,
                                992                 :                                                  NULL, false, false);
                                993                 : 
 2676 sfrost                    994 GIC           3 :             qual_parse_rtable = qual_pstate->p_rtable;
                                995               3 :             free_parsestate(qual_pstate);
 2676 sfrost                    996 ECB             :         }
                                997                 :     }
 3124 sfrost                    998 EUB             : 
 3124 sfrost                    999 GIC          36 :     if (with_check_qual != NULL)
 3124 sfrost                   1000 EUB             :     {
 3055 sfrost                   1001 UIC           0 :         replaces[Anum_pg_policy_polwithcheck - 1] = true;
                               1002                 :         values[Anum_pg_policy_polwithcheck - 1]
 3124                          1003               0 :             = CStringGetTextDatum(nodeToString(with_check_qual));
                               1004                 :     }
                               1005                 :     else
                               1006                 :     {
                               1007                 :         Datum       value_datum;
                               1008                 :         bool        attr_isnull;
                               1009                 : 
                               1010                 :         /*
                               1011                 :          * We need to pull the WITH CHECK expression and build the range table
                               1012                 :          * for the policy from what's in the catalog, so that we can recreate
                               1013                 :          * the dependencies correctly for the policy.
 2676 sfrost                   1014 ECB             :          */
                               1015                 : 
                               1016                 :         /* Check if the policy has a WITH CHECK expr */
 2676 sfrost                   1017 CBC          36 :         value_datum = heap_getattr(policy_tuple, Anum_pg_policy_polwithcheck,
                               1018                 :                                    RelationGetDescr(pg_policy_rel),
                               1019                 :                                    &attr_isnull);
 2676 sfrost                   1020 GIC          36 :         if (!attr_isnull)
                               1021                 :         {
                               1022                 :             char       *with_check_value;
 2579 tgl                      1023 EUB             :             ParseState *with_check_pstate;
                               1024                 : 
 2676 sfrost                   1025                 :             /* parsestate is built just to build the range table */
 2676 sfrost                   1026 UBC           0 :             with_check_pstate = make_parsestate(NULL);
                               1027                 : 
 2676 sfrost                   1028 UIC           0 :             with_check_value = TextDatumGetCString(value_datum);
 2676 sfrost                   1029 UBC           0 :             with_check_qual = stringToNode(with_check_value);
                               1030                 : 
                               1031                 :             /* Add this rel to the parsestate's rangetable, for dependencies */
 1193 tgl                      1032 UIC           0 :             (void) addRangeTableEntryForRelation(with_check_pstate,
                               1033                 :                                                  target_table,
 1193 tgl                      1034 EUB             :                                                  AccessShareLock,
                               1035                 :                                                  NULL, false, false);
                               1036                 : 
 2676 sfrost                   1037 UIC           0 :             with_check_parse_rtable = with_check_pstate->p_rtable;
                               1038               0 :             free_parsestate(with_check_pstate);
 2676 sfrost                   1039 ECB             :         }
                               1040                 :     }
                               1041                 : 
 3055 sfrost                   1042 CBC          36 :     new_tuple = heap_modify_tuple(policy_tuple,
                               1043                 :                                   RelationGetDescr(pg_policy_rel),
                               1044                 :                                   values, isnull, replaces);
 2259 alvherre                 1045              36 :     CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple);
                               1046                 : 
                               1047                 :     /* Update Dependencies. */
 3055 sfrost                   1048              36 :     deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
 3124 sfrost                   1049 ECB             : 
                               1050                 :     /* Record Dependencies */
 3124 sfrost                   1051 GIC          36 :     target.classId = RelationRelationId;
 3124 sfrost                   1052 CBC          36 :     target.objectId = table_id;
                               1053              36 :     target.objectSubId = 0;
 3124 sfrost                   1054 ECB             : 
 3055 sfrost                   1055 GIC          36 :     myself.classId = PolicyRelationId;
 3055 sfrost                   1056 CBC          36 :     myself.objectId = policy_id;
 3124 sfrost                   1057 GIC          36 :     myself.objectSubId = 0;
 3124 sfrost                   1058 ECB             : 
 3124 sfrost                   1059 GIC          36 :     recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
 3124 sfrost                   1060 ECB             : 
 3124 sfrost                   1061 GIC          36 :     recordDependencyOnExpr(&myself, qual, qual_parse_rtable, DEPENDENCY_NORMAL);
                               1062                 : 
                               1063              36 :     recordDependencyOnExpr(&myself, with_check_qual, with_check_parse_rtable,
 3124 sfrost                   1064 ECB             :                            DEPENDENCY_NORMAL);
                               1065                 : 
 2812 mail                     1066                 :     /* Register role dependencies */
 2812 mail                     1067 CBC          36 :     deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
 2812 mail                     1068 GIC          36 :     target.classId = AuthIdRelationId;
 2812 mail                     1069 CBC          36 :     target.objectSubId = 0;
 2812 mail                     1070 GIC          78 :     for (i = 0; i < nitems; i++)
 2812 mail                     1071 ECB             :     {
 2812 mail                     1072 CBC          42 :         target.objectId = DatumGetObjectId(role_oids[i]);
                               1073                 :         /* no dependency if public */
 2812 mail                     1074 GIC          42 :         if (target.objectId != ACL_ID_PUBLIC)
                               1075              15 :             recordSharedDependencyOn(&myself, &target,
 2812 mail                     1076 ECB             :                                      SHARED_DEPENDENCY_POLICY);
                               1077                 :     }
                               1078                 : 
 2811 mail                     1079 GIC          36 :     InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
                               1080                 : 
 3124 sfrost                   1081 CBC          36 :     heap_freetuple(new_tuple);
                               1082                 : 
                               1083                 :     /* Invalidate Relation Cache */
                               1084              36 :     CacheInvalidateRelcache(target_table);
 3124 sfrost                   1085 ECB             : 
                               1086                 :     /* Clean up. */
 3124 sfrost                   1087 GIC          36 :     systable_endscan(sscan);
 3124 sfrost                   1088 CBC          36 :     relation_close(target_table, NoLock);
 1539 andres                   1089 GIC          36 :     table_close(pg_policy_rel, RowExclusiveLock);
                               1090                 : 
 2959 alvherre                 1091              36 :     return myself;
                               1092                 : }
                               1093                 : 
                               1094                 : /*
                               1095                 :  * rename_policy -
 2878 bruce                    1096 ECB             :  *   change the name of a policy on a relation
                               1097                 :  */
                               1098                 : ObjectAddress
 3124 sfrost                   1099 GIC           9 : rename_policy(RenameStmt *stmt)
                               1100                 : {
                               1101                 :     Relation    pg_policy_rel;
                               1102                 :     Relation    target_table;
                               1103                 :     Oid         table_id;
                               1104                 :     Oid         opoloid;
                               1105                 :     ScanKeyData skey[2];
                               1106                 :     SysScanDesc sscan;
                               1107                 :     HeapTuple   policy_tuple;
 2878 bruce                    1108 ECB             :     ObjectAddress address;
                               1109                 : 
                               1110                 :     /* Get id of table.  Also handles permissions checks. */
 3124 sfrost                   1111 GIC           9 :     table_id = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
                               1112                 :                                         0,
 3124 sfrost                   1113 ECB             :                                         RangeVarCallbackForPolicy,
                               1114                 :                                         (void *) stmt);
                               1115                 : 
 3124 sfrost                   1116 GIC           9 :     target_table = relation_open(table_id, NoLock);
                               1117                 : 
 1539 andres                   1118               9 :     pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock);
                               1119                 : 
 3119 sfrost                   1120 ECB             :     /* First pass -- check for conflict */
                               1121                 : 
                               1122                 :     /* Add key - policy's relation id. */
 3124 sfrost                   1123 GIC           9 :     ScanKeyInit(&skey[0],
                               1124                 :                 Anum_pg_policy_polrelid,
                               1125                 :                 BTEqualStrategyNumber, F_OIDEQ,
 3124 sfrost                   1126 ECB             :                 ObjectIdGetDatum(table_id));
                               1127                 : 
                               1128                 :     /* Add key - policy's name. */
 3124 sfrost                   1129 CBC           9 :     ScanKeyInit(&skey[1],
                               1130                 :                 Anum_pg_policy_polname,
 3124 sfrost                   1131 ECB             :                 BTEqualStrategyNumber, F_NAMEEQ,
 3124 sfrost                   1132 GIC           9 :                 CStringGetDatum(stmt->newname));
                               1133                 : 
 3055                          1134               9 :     sscan = systable_beginscan(pg_policy_rel,
 3055 sfrost                   1135 ECB             :                                PolicyPolrelidPolnameIndexId, true, NULL, 2,
 3124                          1136                 :                                skey);
                               1137                 : 
 3119 sfrost                   1138 GIC           9 :     if (HeapTupleIsValid(systable_getnext(sscan)))
 3124                          1139               3 :         ereport(ERROR,
                               1140                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
 3055 sfrost                   1141 ECB             :                  errmsg("policy \"%s\" for table \"%s\" already exists",
                               1142                 :                         stmt->newname, RelationGetRelationName(target_table))));
                               1143                 : 
 3124 sfrost                   1144 GIC           6 :     systable_endscan(sscan);
 3124 sfrost                   1145 ECB             : 
                               1146                 :     /* Second pass -- find existing policy and update */
                               1147                 :     /* Add key - policy's relation id. */
 3124 sfrost                   1148 GIC           6 :     ScanKeyInit(&skey[0],
                               1149                 :                 Anum_pg_policy_polrelid,
                               1150                 :                 BTEqualStrategyNumber, F_OIDEQ,
 3124 sfrost                   1151 ECB             :                 ObjectIdGetDatum(table_id));
                               1152                 : 
                               1153                 :     /* Add key - policy's name. */
 3124 sfrost                   1154 CBC           6 :     ScanKeyInit(&skey[1],
                               1155                 :                 Anum_pg_policy_polname,
 3124 sfrost                   1156 ECB             :                 BTEqualStrategyNumber, F_NAMEEQ,
 3124 sfrost                   1157 GIC           6 :                 CStringGetDatum(stmt->subname));
                               1158                 : 
 3055                          1159               6 :     sscan = systable_beginscan(pg_policy_rel,
 3055 sfrost                   1160 ECB             :                                PolicyPolrelidPolnameIndexId, true, NULL, 2,
                               1161                 :                                skey);
                               1162                 : 
 3055 sfrost                   1163 CBC           6 :     policy_tuple = systable_getnext(sscan);
 3124 sfrost                   1164 EUB             : 
                               1165                 :     /* Complain if we did not find the policy */
 3055 sfrost                   1166 GIC           6 :     if (!HeapTupleIsValid(policy_tuple))
 3124 sfrost                   1167 UIC           0 :         ereport(ERROR,
                               1168                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
 3055 sfrost                   1169 ECB             :                  errmsg("policy \"%s\" for table \"%s\" does not exist",
                               1170                 :                         stmt->subname, RelationGetRelationName(target_table))));
 3124                          1171                 : 
 1601 andres                   1172 GIC           6 :     opoloid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
 3124 sfrost                   1173 ECB             : 
 3055 sfrost                   1174 CBC           6 :     policy_tuple = heap_copytuple(policy_tuple);
                               1175                 : 
                               1176               6 :     namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname,
 3124 sfrost                   1177 GIC           6 :                stmt->newname);
 3124 sfrost                   1178 ECB             : 
 2259 alvherre                 1179 GIC           6 :     CatalogTupleUpdate(pg_policy_rel, &policy_tuple->t_self, policy_tuple);
 3124 sfrost                   1180 ECB             : 
 1601 andres                   1181 GIC           6 :     InvokeObjectPostAlterHook(PolicyRelationId, opoloid, 0);
                               1182                 : 
 2959 alvherre                 1183               6 :     ObjectAddressSet(address, PolicyRelationId, opoloid);
                               1184                 : 
                               1185                 :     /*
                               1186                 :      * Invalidate relation's relcache entry so that other backends (and this
 2878 bruce                    1187 ECB             :      * one too!) are sent SI message to make them rebuild relcache entries.
                               1188                 :      * (Ideally this should happen automatically...)
                               1189                 :      */
 3124 sfrost                   1190 CBC           6 :     CacheInvalidateRelcache(target_table);
 3124 sfrost                   1191 ECB             : 
                               1192                 :     /* Clean up. */
 3124 sfrost                   1193 GIC           6 :     systable_endscan(sscan);
 1539 andres                   1194 CBC           6 :     table_close(pg_policy_rel, RowExclusiveLock);
 3124 sfrost                   1195 GIC           6 :     relation_close(target_table, NoLock);
                               1196                 : 
 2959 alvherre                 1197               6 :     return address;
                               1198                 : }
                               1199                 : 
                               1200                 : /*
                               1201                 :  * get_relation_policy_oid - Look up a policy by name to find its OID
                               1202                 :  *
                               1203                 :  * If missing_ok is false, throw an error if policy not found.  If
 3124 sfrost                   1204 ECB             :  * true, just return InvalidOid.
                               1205                 :  */
                               1206                 : Oid
 3124 sfrost                   1207 GIC          82 : get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
                               1208                 : {
                               1209                 :     Relation    pg_policy_rel;
                               1210                 :     ScanKeyData skey[2];
                               1211                 :     SysScanDesc sscan;
 2878 bruce                    1212 ECB             :     HeapTuple   policy_tuple;
                               1213                 :     Oid         policy_oid;
                               1214                 : 
 1539 andres                   1215 CBC          82 :     pg_policy_rel = table_open(PolicyRelationId, AccessShareLock);
                               1216                 : 
                               1217                 :     /* Add key - policy's relation id. */
 3124 sfrost                   1218 GIC          82 :     ScanKeyInit(&skey[0],
                               1219                 :                 Anum_pg_policy_polrelid,
                               1220                 :                 BTEqualStrategyNumber, F_OIDEQ,
 3124 sfrost                   1221 ECB             :                 ObjectIdGetDatum(relid));
                               1222                 : 
                               1223                 :     /* Add key - policy's name. */
 3124 sfrost                   1224 GIC          82 :     ScanKeyInit(&skey[1],
                               1225                 :                 Anum_pg_policy_polname,
 3124 sfrost                   1226 ECB             :                 BTEqualStrategyNumber, F_NAMEEQ,
                               1227                 :                 CStringGetDatum(policy_name));
                               1228                 : 
 3055 sfrost                   1229 GIC          82 :     sscan = systable_beginscan(pg_policy_rel,
 3055 sfrost                   1230 ECB             :                                PolicyPolrelidPolnameIndexId, true, NULL, 2,
                               1231                 :                                skey);
 3124                          1232                 : 
 3055 sfrost                   1233 GIC          82 :     policy_tuple = systable_getnext(sscan);
 3124 sfrost                   1234 ECB             : 
 3055 sfrost                   1235 CBC          82 :     if (!HeapTupleIsValid(policy_tuple))
                               1236                 :     {
 3124 sfrost                   1237 GIC           6 :         if (!missing_ok)
                               1238               6 :             ereport(ERROR,
                               1239                 :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
 2834 mail                     1240 EUB             :                      errmsg("policy \"%s\" for table \"%s\" does not exist",
                               1241                 :                             policy_name, get_rel_name(relid))));
                               1242                 : 
 3124 sfrost                   1243 LBC           0 :         policy_oid = InvalidOid;
                               1244                 :     }
                               1245                 :     else
 1601 andres                   1246 CBC          76 :         policy_oid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid;
 3124 sfrost                   1247 ECB             : 
                               1248                 :     /* Clean up. */
 3124 sfrost                   1249 CBC          76 :     systable_endscan(sscan);
 1539 andres                   1250 GIC          76 :     table_close(pg_policy_rel, AccessShareLock);
                               1251                 : 
 3124 sfrost                   1252              76 :     return policy_oid;
                               1253                 : }
                               1254                 : 
                               1255                 : /*
 2812 mail                     1256 EUB             :  * relation_has_policies - Determine if relation has any policies
                               1257                 :  */
                               1258                 : bool
 2812 mail                     1259 UIC           0 : relation_has_policies(Relation rel)
                               1260                 : {
                               1261                 :     Relation    catalog;
 2812 mail                     1262 EUB             :     ScanKeyData skey;
                               1263                 :     SysScanDesc sscan;
                               1264                 :     HeapTuple   policy_tuple;
 2812 mail                     1265 UBC           0 :     bool        ret = false;
                               1266                 : 
 1539 andres                   1267 UIC           0 :     catalog = table_open(PolicyRelationId, AccessShareLock);
 2812 mail                     1268               0 :     ScanKeyInit(&skey,
 2812 mail                     1269 EUB             :                 Anum_pg_policy_polrelid,
                               1270                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               1271                 :                 ObjectIdGetDatum(RelationGetRelid(rel)));
 2812 mail                     1272 UBC           0 :     sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
 2812 mail                     1273 EUB             :                                NULL, 1, &skey);
 2812 mail                     1274 UIC           0 :     policy_tuple = systable_getnext(sscan);
 2812 mail                     1275 UBC           0 :     if (HeapTupleIsValid(policy_tuple))
                               1276               0 :         ret = true;
                               1277                 : 
                               1278               0 :     systable_endscan(sscan);
 1539 andres                   1279 UIC           0 :     table_close(catalog, AccessShareLock);
                               1280                 : 
 2812 mail                     1281               0 :     return ret;
                               1282                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a