LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_db_role_setting.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 76 77 98.7 %
Date: 2025-09-19 06:19:22 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-2025, 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        1304 : 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        1304 :     valuestr = ExtractSetVariableArgs(setstmt);
      33             : 
      34             :     /* Get the old tuple, if any. */
      35             : 
      36        1304 :     rel = table_open(DbRoleSettingRelationId, RowExclusiveLock);
      37        1304 :     ScanKeyInit(&scankey[0],
      38             :                 Anum_pg_db_role_setting_setdatabase,
      39             :                 BTEqualStrategyNumber, F_OIDEQ,
      40             :                 ObjectIdGetDatum(databaseid));
      41        1304 :     ScanKeyInit(&scankey[1],
      42             :                 Anum_pg_db_role_setting_setrole,
      43             :                 BTEqualStrategyNumber, F_OIDEQ,
      44             :                 ObjectIdGetDatum(roleid));
      45        1304 :     scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
      46             :                               NULL, 2, scankey);
      47        1304 :     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        1304 :     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        1302 :     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        1056 :         memset(repl_repl, false, sizeof(repl_repl));
     108        1056 :         repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
     109        1056 :         repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
     110             : 
     111             :         /* Extract old value of setconfig */
     112        1056 :         datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
     113             :                              RelationGetDescr(rel), &isnull);
     114        1056 :         a = isnull ? NULL : DatumGetArrayTypeP(datum);
     115             : 
     116             :         /* Update (valuestr is NULL in RESET cases) */
     117        1056 :         if (valuestr)
     118        1022 :             a = GUCArrayAdd(a, setstmt->name, valuestr);
     119             :         else
     120          34 :             a = GUCArrayDelete(a, setstmt->name);
     121             : 
     122        1050 :         if (a)
     123             :         {
     124        1026 :             repl_val[Anum_pg_db_role_setting_setconfig - 1] =
     125        1026 :                 PointerGetDatum(a);
     126             : 
     127        1026 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
     128             :                                          repl_val, repl_null, repl_repl);
     129        1026 :             CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
     130             :         }
     131             :         else
     132          24 :             CatalogTupleDelete(rel, &tuple->t_self);
     133             :     }
     134         246 :     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         240 :         memset(nulls, false, sizeof(nulls));
     143             : 
     144         240 :         a = GUCArrayAdd(NULL, setstmt->name, valuestr);
     145             : 
     146         240 :         values[Anum_pg_db_role_setting_setdatabase - 1] =
     147         240 :             ObjectIdGetDatum(databaseid);
     148         240 :         values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
     149         240 :         values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
     150         240 :         newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
     151             : 
     152         240 :         CatalogTupleInsert(rel, newtuple);
     153             :     }
     154             :     else
     155             :     {
     156             :         /*
     157             :          * RESET doesn't need to change any state if there's no pre-existing
     158             :          * pg_db_role_setting entry, but for consistency we should still check
     159             :          * that the option is valid and we're allowed to set it.
     160             :          */
     161           6 :         (void) GUCArrayDelete(NULL, setstmt->name);
     162             :     }
     163             : 
     164        1296 :     InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
     165             :                                  databaseid, 0, roleid, false);
     166             : 
     167        1296 :     systable_endscan(scan);
     168             : 
     169             :     /* Close pg_db_role_setting, but keep lock till commit */
     170        1296 :     table_close(rel, NoLock);
     171        1296 : }
     172             : 
     173             : /*
     174             :  * Drop some settings from the catalog.  These can be for a particular
     175             :  * database, or for a particular role.  (It is of course possible to do both
     176             :  * too, but it doesn't make sense for current uses.)
     177             :  */
     178             : void
     179        1474 : DropSetting(Oid databaseid, Oid roleid)
     180             : {
     181             :     Relation    relsetting;
     182             :     TableScanDesc scan;
     183             :     ScanKeyData keys[2];
     184             :     HeapTuple   tup;
     185        1474 :     int         numkeys = 0;
     186             : 
     187        1474 :     relsetting = table_open(DbRoleSettingRelationId, RowExclusiveLock);
     188             : 
     189        1474 :     if (OidIsValid(databaseid))
     190             :     {
     191          90 :         ScanKeyInit(&keys[numkeys],
     192             :                     Anum_pg_db_role_setting_setdatabase,
     193             :                     BTEqualStrategyNumber,
     194             :                     F_OIDEQ,
     195             :                     ObjectIdGetDatum(databaseid));
     196          90 :         numkeys++;
     197             :     }
     198        1474 :     if (OidIsValid(roleid))
     199             :     {
     200        1384 :         ScanKeyInit(&keys[numkeys],
     201             :                     Anum_pg_db_role_setting_setrole,
     202             :                     BTEqualStrategyNumber,
     203             :                     F_OIDEQ,
     204             :                     ObjectIdGetDatum(roleid));
     205        1384 :         numkeys++;
     206             :     }
     207             : 
     208        1474 :     scan = table_beginscan_catalog(relsetting, numkeys, keys);
     209        1484 :     while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
     210             :     {
     211          10 :         CatalogTupleDelete(relsetting, &tup->t_self);
     212             :     }
     213        1474 :     table_endscan(scan);
     214             : 
     215        1474 :     table_close(relsetting, RowExclusiveLock);
     216        1474 : }
     217             : 
     218             : /*
     219             :  * Scan pg_db_role_setting looking for applicable settings, and load them on
     220             :  * the current process.
     221             :  *
     222             :  * relsetting is pg_db_role_setting, already opened and locked.
     223             :  *
     224             :  * Note: we only consider setting for the exact databaseid/roleid combination.
     225             :  * This probably needs to be called more than once, with InvalidOid passed as
     226             :  * databaseid/roleid.
     227             :  */
     228             : void
     229      130696 : ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
     230             :              Relation relsetting, GucSource source)
     231             : {
     232             :     SysScanDesc scan;
     233             :     ScanKeyData keys[2];
     234             :     HeapTuple   tup;
     235             : 
     236      130696 :     ScanKeyInit(&keys[0],
     237             :                 Anum_pg_db_role_setting_setdatabase,
     238             :                 BTEqualStrategyNumber,
     239             :                 F_OIDEQ,
     240             :                 ObjectIdGetDatum(databaseid));
     241      130696 :     ScanKeyInit(&keys[1],
     242             :                 Anum_pg_db_role_setting_setrole,
     243             :                 BTEqualStrategyNumber,
     244             :                 F_OIDEQ,
     245             :                 ObjectIdGetDatum(roleid));
     246             : 
     247      130696 :     scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
     248             :                               snapshot, 2, keys);
     249      137492 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
     250             :     {
     251             :         bool        isnull;
     252             :         Datum       datum;
     253             : 
     254        6796 :         datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
     255             :                              RelationGetDescr(relsetting), &isnull);
     256        6796 :         if (!isnull)
     257             :         {
     258        6796 :             ArrayType  *a = DatumGetArrayTypeP(datum);
     259             : 
     260             :             /*
     261             :              * We process all the options at SUSET level.  We assume that the
     262             :              * right to insert an option into pg_db_role_setting was checked
     263             :              * when it was inserted.
     264             :              */
     265        6796 :             ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
     266             :         }
     267             :     }
     268             : 
     269      130696 :     systable_endscan(scan);
     270      130696 : }

Generated by: LCOV version 1.16