Age Owner TLA 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-2023, 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
4932 alvherre 24 CBC 558 : 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 558 : valuestr = ExtractSetVariableArgs(setstmt);
33 :
34 : /* Get the old tuple, if any. */
35 :
1539 andres 36 558 : rel = table_open(DbRoleSettingRelationId, RowExclusiveLock);
4932 alvherre 37 558 : ScanKeyInit(&scankey[0],
38 : Anum_pg_db_role_setting_setdatabase,
39 : BTEqualStrategyNumber, F_OIDEQ,
40 : ObjectIdGetDatum(databaseid));
41 558 : ScanKeyInit(&scankey[1],
42 : Anum_pg_db_role_setting_setrole,
43 : BTEqualStrategyNumber, F_OIDEQ,
44 : ObjectIdGetDatum(roleid));
45 558 : scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
46 : NULL, 2, scankey);
47 558 : 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 558 : if (setstmt->kind == VAR_RESET_ALL)
62 : {
63 1 : if (HeapTupleIsValid(tuple))
64 : {
4763 65 1 : ArrayType *new = NULL;
66 : ArrayType *usersetArray;
67 : Datum datum;
68 : Datum usersetDatum;
69 : bool isnull;
70 : bool usersetIsnull;
71 :
4763 alvherre 72 GIC 1 : datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
73 : RelationGetDescr(rel), &isnull);
121 akorotkov 74 GNC 1 : usersetDatum = heap_getattr(tuple, Anum_pg_db_role_setting_setuser,
75 : RelationGetDescr(rel), &usersetIsnull);
76 :
4763 alvherre 77 CBC 1 : if (!isnull)
78 : {
121 akorotkov 79 GNC 1 : Assert(!usersetIsnull);
80 1 : usersetArray = DatumGetArrayTypeP(usersetDatum);
81 1 : new = GUCArrayReset(DatumGetArrayTypeP(datum), &usersetArray);
82 : }
4763 alvherre 83 ECB :
4763 alvherre 84 GIC 1 : if (new)
85 : {
4763 alvherre 86 ECB : Datum repl_val[Natts_pg_db_role_setting];
87 : bool repl_null[Natts_pg_db_role_setting];
88 : bool repl_repl[Natts_pg_db_role_setting];
89 : HeapTuple newtuple;
90 :
4763 alvherre 91 GIC 1 : memset(repl_repl, false, sizeof(repl_repl));
92 :
4763 alvherre 93 CBC 1 : repl_val[Anum_pg_db_role_setting_setconfig - 1] =
4763 alvherre 94 GIC 1 : PointerGetDatum(new);
95 1 : repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
96 1 : repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
97 :
121 akorotkov 98 GNC 1 : repl_val[Anum_pg_db_role_setting_setuser - 1] =
99 1 : PointerGetDatum(usersetArray);
100 1 : repl_repl[Anum_pg_db_role_setting_setuser - 1] = true;
101 1 : repl_null[Anum_pg_db_role_setting_setuser - 1] = false;
102 :
4763 alvherre 103 GIC 1 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
104 : repl_val, repl_null, repl_repl);
2259 alvherre 105 CBC 1 : CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
106 : }
4763 alvherre 107 ECB : else
2258 tgl 108 LBC 0 : CatalogTupleDelete(rel, &tuple->t_self);
4763 alvherre 109 ECB : }
4932 110 : }
4932 alvherre 111 GIC 557 : else if (HeapTupleIsValid(tuple))
4932 alvherre 112 ECB : {
113 : Datum repl_val[Natts_pg_db_role_setting];
114 : bool repl_null[Natts_pg_db_role_setting];
115 : bool repl_repl[Natts_pg_db_role_setting];
116 : HeapTuple newtuple;
117 : Datum datum;
118 : Datum usersetDatum;
119 : bool isnull;
120 : bool usersetIsnull;
121 : ArrayType *a;
122 : ArrayType *usersetArray;
123 :
4932 alvherre 124 GIC 452 : memset(repl_repl, false, sizeof(repl_repl));
4932 alvherre 125 GBC 452 : repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
4932 alvherre 126 GIC 452 : repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
121 akorotkov 127 GNC 452 : repl_repl[Anum_pg_db_role_setting_setuser - 1] = true;
128 452 : repl_null[Anum_pg_db_role_setting_setuser - 1] = false;
129 :
130 : /* Extract old values of setconfig and setuser */
4932 alvherre 131 GIC 452 : datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
132 : RelationGetDescr(rel), &isnull);
133 452 : a = isnull ? NULL : DatumGetArrayTypeP(datum);
134 :
121 akorotkov 135 GNC 452 : usersetDatum = heap_getattr(tuple, Anum_pg_db_role_setting_setuser,
136 : RelationGetDescr(rel), &usersetIsnull);
137 452 : usersetArray = usersetIsnull ? NULL : DatumGetArrayTypeP(usersetDatum);
138 :
139 : /* Update (valuestr is NULL in RESET cases) */
4932 alvherre 140 GIC 452 : if (valuestr)
121 akorotkov 141 GNC 441 : a = GUCArrayAdd(a, &usersetArray, setstmt->name, valuestr, setstmt->user_set);
142 : else
143 11 : a = GUCArrayDelete(a, &usersetArray, setstmt->name);
144 :
4932 alvherre 145 GIC 450 : if (a)
146 : {
4932 alvherre 147 CBC 440 : repl_val[Anum_pg_db_role_setting_setconfig - 1] =
148 440 : PointerGetDatum(a);
121 akorotkov 149 GNC 440 : repl_val[Anum_pg_db_role_setting_setuser - 1] =
150 440 : PointerGetDatum(usersetArray);
4932 alvherre 151 ECB :
4932 alvherre 152 CBC 440 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
4932 alvherre 153 ECB : repl_val, repl_null, repl_repl);
2259 alvherre 154 GIC 440 : CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
155 : }
4932 alvherre 156 ECB : else
2258 tgl 157 GIC 10 : CatalogTupleDelete(rel, &tuple->t_self);
4932 alvherre 158 ECB : }
4932 alvherre 159 GIC 105 : else if (valuestr)
4932 alvherre 160 ECB : {
161 : /* non-null valuestr means it's not RESET, so insert a new tuple */
162 : HeapTuple newtuple;
163 : Datum values[Natts_pg_db_role_setting];
164 : bool nulls[Natts_pg_db_role_setting];
165 : ArrayType *a,
166 : *usersetArray;
167 :
4932 alvherre 168 GIC 103 : memset(nulls, false, sizeof(nulls));
4790 bruce 169 ECB :
121 akorotkov 170 GNC 103 : a = GUCArrayAdd(NULL, &usersetArray, setstmt->name, valuestr, setstmt->user_set);
4932 alvherre 171 ECB :
4932 alvherre 172 GIC 101 : values[Anum_pg_db_role_setting_setdatabase - 1] =
4932 alvherre 173 CBC 101 : ObjectIdGetDatum(databaseid);
174 101 : values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
175 101 : values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
121 akorotkov 176 GNC 101 : values[Anum_pg_db_role_setting_setuser - 1] = PointerGetDatum(usersetArray);
4932 alvherre 177 CBC 101 : newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
178 :
2259 179 101 : CatalogTupleInsert(rel, newtuple);
180 : }
4932 alvherre 181 ECB :
3675 rhaas 182 GIC 554 : InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
183 : databaseid, 0, roleid, false);
3675 rhaas 184 ECB :
4932 alvherre 185 GIC 554 : systable_endscan(scan);
4932 alvherre 186 ECB :
187 : /* Close pg_db_role_setting, but keep lock till commit */
1539 andres 188 GIC 554 : table_close(rel, NoLock);
4932 alvherre 189 554 : }
190 :
191 : /*
192 : * Drop some settings from the catalog. These can be for a particular
193 : * database, or for a particular role. (It is of course possible to do both
194 : * too, but it doesn't make sense for current uses.)
4932 alvherre 195 ECB : */
196 : void
4932 alvherre 197 CBC 639 : DropSetting(Oid databaseid, Oid roleid)
198 : {
4790 bruce 199 ECB : Relation relsetting;
1490 andres 200 : TableScanDesc scan;
4790 bruce 201 : ScanKeyData keys[2];
202 : HeapTuple tup;
4790 bruce 203 CBC 639 : int numkeys = 0;
4932 alvherre 204 ECB :
1539 andres 205 GIC 639 : relsetting = table_open(DbRoleSettingRelationId, RowExclusiveLock);
4932 alvherre 206 ECB :
4932 alvherre 207 GIC 639 : if (OidIsValid(databaseid))
208 : {
4932 alvherre 209 CBC 20 : ScanKeyInit(&keys[numkeys],
210 : Anum_pg_db_role_setting_setdatabase,
211 : BTEqualStrategyNumber,
4932 alvherre 212 ECB : F_OIDEQ,
213 : ObjectIdGetDatum(databaseid));
4932 alvherre 214 GIC 20 : numkeys++;
4932 alvherre 215 ECB : }
4932 alvherre 216 CBC 639 : if (OidIsValid(roleid))
217 : {
4932 alvherre 218 GIC 619 : ScanKeyInit(&keys[numkeys],
219 : Anum_pg_db_role_setting_setrole,
220 : BTEqualStrategyNumber,
221 : F_OIDEQ,
222 : ObjectIdGetDatum(roleid));
223 619 : numkeys++;
4932 alvherre 224 ECB : }
225 :
1490 andres 226 GIC 639 : scan = table_beginscan_catalog(relsetting, numkeys, keys);
4932 alvherre 227 643 : while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
228 : {
2258 tgl 229 4 : CatalogTupleDelete(relsetting, &tup->t_self);
4932 alvherre 230 ECB : }
1490 andres 231 GIC 639 : table_endscan(scan);
4932 alvherre 232 ECB :
1539 andres 233 GIC 639 : table_close(relsetting, RowExclusiveLock);
4932 alvherre 234 CBC 639 : }
235 :
4932 alvherre 236 ECB : /*
237 : * Scan pg_db_role_setting looking for applicable settings, and load them on
238 : * the current process.
239 : *
240 : * relsetting is pg_db_role_setting, already opened and locked.
241 : *
242 : * Note: we only consider setting for the exact databaseid/roleid combination.
243 : * This probably needs to be called more than once, with InvalidOid passed as
244 : * databaseid/roleid.
245 : */
246 : void
3568 rhaas 247 GIC 39121 : ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
248 : Relation relsetting, GucSource source)
249 : {
4790 bruce 250 ECB : SysScanDesc scan;
251 : ScanKeyData keys[2];
252 : HeapTuple tup;
4932 alvherre 253 :
4932 alvherre 254 CBC 39121 : ScanKeyInit(&keys[0],
255 : Anum_pg_db_role_setting_setdatabase,
4932 alvherre 256 ECB : BTEqualStrategyNumber,
257 : F_OIDEQ,
258 : ObjectIdGetDatum(databaseid));
4932 alvherre 259 GIC 39121 : ScanKeyInit(&keys[1],
4932 alvherre 260 ECB : Anum_pg_db_role_setting_setrole,
261 : BTEqualStrategyNumber,
262 : F_OIDEQ,
263 : ObjectIdGetDatum(roleid));
264 :
4932 alvherre 265 GIC 39121 : scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
266 : snapshot, 2, keys);
267 42142 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
268 : {
269 : bool isnull;
270 : bool usersetIsnull;
271 : Datum datum;
272 : Datum usersetDatum;
273 :
274 3022 : datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
275 : RelationGetDescr(relsetting), &isnull);
121 akorotkov 276 GNC 3022 : usersetDatum = heap_getattr(tup, Anum_pg_db_role_setting_setuser,
277 : RelationGetDescr(relsetting), &usersetIsnull);
4932 alvherre 278 CBC 3022 : if (!isnull)
279 : {
4932 alvherre 280 GIC 3022 : ArrayType *a = DatumGetArrayTypeP(datum);
121 akorotkov 281 GNC 3022 : ArrayType *usersetArray = DatumGetArrayTypeP(usersetDatum);
282 :
283 : /*
284 : * We process all the options at SUSET level. We assume that the
285 : * right to insert an option into pg_db_role_setting was checked
4932 alvherre 286 ECB : * when it was inserted.
287 : */
121 akorotkov 288 GNC 3022 : ProcessGUCArray(a, usersetArray, PGC_SUSET, source, GUC_ACTION_SET);
289 : }
290 : }
4932 alvherre 291 ECB :
4932 alvherre 292 GIC 39120 : systable_endscan(scan);
293 39120 : }
|