LCOV - differential code coverage report
Current view: top level - src/backend/commands - policy.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 87.5 % 401 351 50 351
Current Date: 2024-04-14 14:21:10 Functions: 90.9 % 11 10 1 10
Baseline: 16@8cea358b128 Branches: 60.3 % 194 117 77 117
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 87.5 % 401 351 50 351
Function coverage date bins:
(240..) days: 90.9 % 11 10 1 10
Branch coverage date bins:
(240..) days: 60.3 % 194 117 77 117

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

Generated by: LCOV version 2.1-beta2-3-g6141622