LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_db_role_setting.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 75 76 98.7 %
Date: 2024-04-19 04:11:42 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * pg_db_role_setting.c
       3             :  *      Routines to support manipulation of the pg_db_role_setting relation
       4             :  *
       5             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       6             :  * Portions Copyright (c) 1994, Regents of the University of California
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *      src/backend/catalog/pg_db_role_setting.c
      10             :  */
      11             : #include "postgres.h"
      12             : 
      13             : #include "access/genam.h"
      14             : #include "access/heapam.h"
      15             : #include "access/htup_details.h"
      16             : #include "access/tableam.h"
      17             : #include "catalog/indexing.h"
      18             : #include "catalog/objectaccess.h"
      19             : #include "catalog/pg_db_role_setting.h"
      20             : #include "utils/fmgroids.h"
      21             : #include "utils/rel.h"
      22             : 
      23             : void
      24        1128 : AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
      25             : {
      26             :     char       *valuestr;
      27             :     HeapTuple   tuple;
      28             :     Relation    rel;
      29             :     ScanKeyData scankey[2];
      30             :     SysScanDesc scan;
      31             : 
      32        1128 :     valuestr = ExtractSetVariableArgs(setstmt);
      33             : 
      34             :     /* Get the old tuple, if any. */
      35             : 
      36        1128 :     rel = table_open(DbRoleSettingRelationId, RowExclusiveLock);
      37        1128 :     ScanKeyInit(&scankey[0],
      38             :                 Anum_pg_db_role_setting_setdatabase,
      39             :                 BTEqualStrategyNumber, F_OIDEQ,
      40             :                 ObjectIdGetDatum(databaseid));
      41        1128 :     ScanKeyInit(&scankey[1],
      42             :                 Anum_pg_db_role_setting_setrole,
      43             :                 BTEqualStrategyNumber, F_OIDEQ,
      44             :                 ObjectIdGetDatum(roleid));
      45        1128 :     scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
      46             :                               NULL, 2, scankey);
      47        1128 :     tuple = systable_getnext(scan);
      48             : 
      49             :     /*
      50             :      * There are three cases:
      51             :      *
      52             :      * - in RESET ALL, request GUC to reset the settings array and update the
      53             :      * catalog if there's anything left, delete it otherwise
      54             :      *
      55             :      * - in other commands, if there's a tuple in pg_db_role_setting, update
      56             :      * it; if it ends up empty, delete it
      57             :      *
      58             :      * - otherwise, insert a new pg_db_role_setting tuple, but only if the
      59             :      * command is not RESET
      60             :      */
      61        1128 :     if (setstmt->kind == VAR_RESET_ALL)
      62             :     {
      63           2 :         if (HeapTupleIsValid(tuple))
      64             :         {
      65           2 :             ArrayType  *new = NULL;
      66             :             Datum       datum;
      67             :             bool        isnull;
      68             : 
      69           2 :             datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
      70             :                                  RelationGetDescr(rel), &isnull);
      71             : 
      72           2 :             if (!isnull)
      73           2 :                 new = GUCArrayReset(DatumGetArrayTypeP(datum));
      74             : 
      75           2 :             if (new)
      76             :             {
      77             :                 Datum       repl_val[Natts_pg_db_role_setting];
      78             :                 bool        repl_null[Natts_pg_db_role_setting];
      79             :                 bool        repl_repl[Natts_pg_db_role_setting];
      80             :                 HeapTuple   newtuple;
      81             : 
      82           2 :                 memset(repl_repl, false, sizeof(repl_repl));
      83             : 
      84           2 :                 repl_val[Anum_pg_db_role_setting_setconfig - 1] =
      85           2 :                     PointerGetDatum(new);
      86           2 :                 repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
      87           2 :                 repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
      88             : 
      89           2 :                 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
      90             :                                              repl_val, repl_null, repl_repl);
      91           2 :                 CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
      92             :             }
      93             :             else
      94           0 :                 CatalogTupleDelete(rel, &tuple->t_self);
      95             :         }
      96             :     }
      97        1126 :     else if (HeapTupleIsValid(tuple))
      98             :     {
      99             :         Datum       repl_val[Natts_pg_db_role_setting];
     100             :         bool        repl_null[Natts_pg_db_role_setting];
     101             :         bool        repl_repl[Natts_pg_db_role_setting];
     102             :         HeapTuple   newtuple;
     103             :         Datum       datum;
     104             :         bool        isnull;
     105             :         ArrayType  *a;
     106             : 
     107         916 :         memset(repl_repl, false, sizeof(repl_repl));
     108         916 :         repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
     109         916 :         repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
     110             : 
     111             :         /* Extract old value of setconfig */
     112         916 :         datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
     113             :                              RelationGetDescr(rel), &isnull);
     114         916 :         a = isnull ? NULL : DatumGetArrayTypeP(datum);
     115             : 
     116             :         /* Update (valuestr is NULL in RESET cases) */
     117         916 :         if (valuestr)
     118         894 :             a = GUCArrayAdd(a, setstmt->name, valuestr);
     119             :         else
     120          22 :             a = GUCArrayDelete(a, setstmt->name);
     121             : 
     122         914 :         if (a)
     123             :         {
     124         894 :             repl_val[Anum_pg_db_role_setting_setconfig - 1] =
     125         894 :                 PointerGetDatum(a);
     126             : 
     127         894 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
     128             :                                          repl_val, repl_null, repl_repl);
     129         894 :             CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
     130             :         }
     131             :         else
     132          20 :             CatalogTupleDelete(rel, &tuple->t_self);
     133             :     }
     134         210 :     else if (valuestr)
     135             :     {
     136             :         /* non-null valuestr means it's not RESET, so insert a new tuple */
     137             :         HeapTuple   newtuple;
     138             :         Datum       values[Natts_pg_db_role_setting];
     139             :         bool        nulls[Natts_pg_db_role_setting];
     140             :         ArrayType  *a;
     141             : 
     142         206 :         memset(nulls, false, sizeof(nulls));
     143             : 
     144         206 :         a = GUCArrayAdd(NULL, setstmt->name, valuestr);
     145             : 
     146         206 :         values[Anum_pg_db_role_setting_setdatabase - 1] =
     147         206 :             ObjectIdGetDatum(databaseid);
     148         206 :         values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
     149         206 :         values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
     150         206 :         newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
     151             : 
     152         206 :         CatalogTupleInsert(rel, newtuple);
     153             :     }
     154             : 
     155        1126 :     InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
     156             :                                  databaseid, 0, roleid, false);
     157             : 
     158        1126 :     systable_endscan(scan);
     159             : 
     160             :     /* Close pg_db_role_setting, but keep lock till commit */
     161        1126 :     table_close(rel, NoLock);
     162        1126 : }
     163             : 
     164             : /*
     165             :  * Drop some settings from the catalog.  These can be for a particular
     166             :  * database, or for a particular role.  (It is of course possible to do both
     167             :  * too, but it doesn't make sense for current uses.)
     168             :  */
     169             : void
     170        1354 : DropSetting(Oid databaseid, Oid roleid)
     171             : {
     172             :     Relation    relsetting;
     173             :     TableScanDesc scan;
     174             :     ScanKeyData keys[2];
     175             :     HeapTuple   tup;
     176        1354 :     int         numkeys = 0;
     177             : 
     178        1354 :     relsetting = table_open(DbRoleSettingRelationId, RowExclusiveLock);
     179             : 
     180        1354 :     if (OidIsValid(databaseid))
     181             :     {
     182          60 :         ScanKeyInit(&keys[numkeys],
     183             :                     Anum_pg_db_role_setting_setdatabase,
     184             :                     BTEqualStrategyNumber,
     185             :                     F_OIDEQ,
     186             :                     ObjectIdGetDatum(databaseid));
     187          60 :         numkeys++;
     188             :     }
     189        1354 :     if (OidIsValid(roleid))
     190             :     {
     191        1294 :         ScanKeyInit(&keys[numkeys],
     192             :                     Anum_pg_db_role_setting_setrole,
     193             :                     BTEqualStrategyNumber,
     194             :                     F_OIDEQ,
     195             :                     ObjectIdGetDatum(roleid));
     196        1294 :         numkeys++;
     197             :     }
     198             : 
     199        1354 :     scan = table_beginscan_catalog(relsetting, numkeys, keys);
     200        1364 :     while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
     201             :     {
     202          10 :         CatalogTupleDelete(relsetting, &tup->t_self);
     203             :     }
     204        1354 :     table_endscan(scan);
     205             : 
     206        1354 :     table_close(relsetting, RowExclusiveLock);
     207        1354 : }
     208             : 
     209             : /*
     210             :  * Scan pg_db_role_setting looking for applicable settings, and load them on
     211             :  * the current process.
     212             :  *
     213             :  * relsetting is pg_db_role_setting, already opened and locked.
     214             :  *
     215             :  * Note: we only consider setting for the exact databaseid/roleid combination.
     216             :  * This probably needs to be called more than once, with InvalidOid passed as
     217             :  * databaseid/roleid.
     218             :  */
     219             : void
     220       92676 : ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
     221             :              Relation relsetting, GucSource source)
     222             : {
     223             :     SysScanDesc scan;
     224             :     ScanKeyData keys[2];
     225             :     HeapTuple   tup;
     226             : 
     227       92676 :     ScanKeyInit(&keys[0],
     228             :                 Anum_pg_db_role_setting_setdatabase,
     229             :                 BTEqualStrategyNumber,
     230             :                 F_OIDEQ,
     231             :                 ObjectIdGetDatum(databaseid));
     232       92676 :     ScanKeyInit(&keys[1],
     233             :                 Anum_pg_db_role_setting_setrole,
     234             :                 BTEqualStrategyNumber,
     235             :                 F_OIDEQ,
     236             :                 ObjectIdGetDatum(roleid));
     237             : 
     238       92676 :     scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
     239             :                               snapshot, 2, keys);
     240       99128 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     241             :     {
     242             :         bool        isnull;
     243             :         Datum       datum;
     244             : 
     245        6456 :         datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
     246             :                              RelationGetDescr(relsetting), &isnull);
     247        6456 :         if (!isnull)
     248             :         {
     249        6456 :             ArrayType  *a = DatumGetArrayTypeP(datum);
     250             : 
     251             :             /*
     252             :              * We process all the options at SUSET level.  We assume that the
     253             :              * right to insert an option into pg_db_role_setting was checked
     254             :              * when it was inserted.
     255             :              */
     256        6456 :             ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
     257             :         }
     258             :     }
     259             : 
     260       92672 :     systable_endscan(scan);
     261       92672 : }

Generated by: LCOV version 1.14