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 : }
|