3 * Routines to support manipulation of the pg_db_role_setting relation
5 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/backend/catalog/pg_db_role_setting.c
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"
24 AlterSetting(Oid databaseid
, Oid roleid
, VariableSetStmt
*setstmt
)
29 ScanKeyData scankey
[2];
32 valuestr
= ExtractSetVariableArgs(setstmt
);
34 /* Get the old tuple, if any. */
36 rel
= table_open(DbRoleSettingRelationId
, RowExclusiveLock
);
37 ScanKeyInit(&scankey
[0],
38 Anum_pg_db_role_setting_setdatabase
,
39 BTEqualStrategyNumber
, F_OIDEQ
,
40 ObjectIdGetDatum(databaseid
));
41 ScanKeyInit(&scankey
[1],
42 Anum_pg_db_role_setting_setrole
,
43 BTEqualStrategyNumber
, F_OIDEQ
,
44 ObjectIdGetDatum(roleid
));
45 scan
= systable_beginscan(rel
, DbRoleSettingDatidRolidIndexId
, true,
47 tuple
= systable_getnext(scan
);
50 * There are three cases:
52 * - in RESET ALL, request GUC to reset the settings array and update the
53 * catalog if there's anything left, delete it otherwise
55 * - in other commands, if there's a tuple in pg_db_role_setting, update
56 * it; if it ends up empty, delete it
58 * - otherwise, insert a new pg_db_role_setting tuple, but only if the
59 * command is not RESET
61 if (setstmt
->kind
== VAR_RESET_ALL
)
63 if (HeapTupleIsValid(tuple
))
65 ArrayType
*new = NULL
;
69 datum
= heap_getattr(tuple
, Anum_pg_db_role_setting_setconfig
,
70 RelationGetDescr(rel
), &isnull
);
73 new = GUCArrayReset(DatumGetArrayTypeP(datum
));
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
];
82 memset(repl_repl
, false, sizeof(repl_repl
));
84 repl_val
[Anum_pg_db_role_setting_setconfig
- 1] =
86 repl_repl
[Anum_pg_db_role_setting_setconfig
- 1] = true;
87 repl_null
[Anum_pg_db_role_setting_setconfig
- 1] = false;
89 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(rel
),
90 repl_val
, repl_null
, repl_repl
);
91 CatalogTupleUpdate(rel
, &tuple
->t_self
, newtuple
);
94 CatalogTupleDelete(rel
, &tuple
->t_self
);
97 else if (HeapTupleIsValid(tuple
))
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
];
107 memset(repl_repl
, false, sizeof(repl_repl
));
108 repl_repl
[Anum_pg_db_role_setting_setconfig
- 1] = true;
109 repl_null
[Anum_pg_db_role_setting_setconfig
- 1] = false;
111 /* Extract old value of setconfig */
112 datum
= heap_getattr(tuple
, Anum_pg_db_role_setting_setconfig
,
113 RelationGetDescr(rel
), &isnull
);
114 a
= isnull
? NULL
: DatumGetArrayTypeP(datum
);
116 /* Update (valuestr is NULL in RESET cases) */
118 a
= GUCArrayAdd(a
, setstmt
->name
, valuestr
);
120 a
= GUCArrayDelete(a
, setstmt
->name
);
124 repl_val
[Anum_pg_db_role_setting_setconfig
- 1] =
127 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(rel
),
128 repl_val
, repl_null
, repl_repl
);
129 CatalogTupleUpdate(rel
, &tuple
->t_self
, newtuple
);
132 CatalogTupleDelete(rel
, &tuple
->t_self
);
136 /* non-null valuestr means it's not RESET, so insert a new tuple */
138 Datum values
[Natts_pg_db_role_setting
];
139 bool nulls
[Natts_pg_db_role_setting
];
142 memset(nulls
, false, sizeof(nulls
));
144 a
= GUCArrayAdd(NULL
, setstmt
->name
, valuestr
);
146 values
[Anum_pg_db_role_setting_setdatabase
- 1] =
147 ObjectIdGetDatum(databaseid
);
148 values
[Anum_pg_db_role_setting_setrole
- 1] = ObjectIdGetDatum(roleid
);
149 values
[Anum_pg_db_role_setting_setconfig
- 1] = PointerGetDatum(a
);
150 newtuple
= heap_form_tuple(RelationGetDescr(rel
), values
, nulls
);
152 CatalogTupleInsert(rel
, newtuple
);
155 InvokeObjectPostAlterHookArg(DbRoleSettingRelationId
,
156 databaseid
, 0, roleid
, false);
158 systable_endscan(scan
);
160 /* Close pg_db_role_setting, but keep lock till commit */
161 table_close(rel
, NoLock
);
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.)
170 DropSetting(Oid databaseid
, Oid roleid
)
178 relsetting
= table_open(DbRoleSettingRelationId
, RowExclusiveLock
);
180 if (OidIsValid(databaseid
))
182 ScanKeyInit(&keys
[numkeys
],
183 Anum_pg_db_role_setting_setdatabase
,
184 BTEqualStrategyNumber
,
186 ObjectIdGetDatum(databaseid
));
189 if (OidIsValid(roleid
))
191 ScanKeyInit(&keys
[numkeys
],
192 Anum_pg_db_role_setting_setrole
,
193 BTEqualStrategyNumber
,
195 ObjectIdGetDatum(roleid
));
199 scan
= table_beginscan_catalog(relsetting
, numkeys
, keys
);
200 while (HeapTupleIsValid(tup
= heap_getnext(scan
, ForwardScanDirection
)))
202 CatalogTupleDelete(relsetting
, &tup
->t_self
);
206 table_close(relsetting
, RowExclusiveLock
);
210 * Scan pg_db_role_setting looking for applicable settings, and load them on
211 * the current process.
213 * relsetting is pg_db_role_setting, already opened and locked.
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
220 ApplySetting(Snapshot snapshot
, Oid databaseid
, Oid roleid
,
221 Relation relsetting
, GucSource source
)
227 ScanKeyInit(&keys
[0],
228 Anum_pg_db_role_setting_setdatabase
,
229 BTEqualStrategyNumber
,
231 ObjectIdGetDatum(databaseid
));
232 ScanKeyInit(&keys
[1],
233 Anum_pg_db_role_setting_setrole
,
234 BTEqualStrategyNumber
,
236 ObjectIdGetDatum(roleid
));
238 scan
= systable_beginscan(relsetting
, DbRoleSettingDatidRolidIndexId
, true,
240 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
245 datum
= heap_getattr(tup
, Anum_pg_db_role_setting_setconfig
,
246 RelationGetDescr(relsetting
), &isnull
);
249 ArrayType
*a
= DatumGetArrayTypeP(datum
);
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.
256 ProcessGUCArray(a
, PGC_SUSET
, source
, GUC_ACTION_SET
);
260 systable_endscan(scan
);