Age Owner Branch data 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-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
5864 alvherre@alvh.no-ip. 24 :CBC 622 : 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 : 622 : valuestr = ExtractSetVariableArgs(setstmt);
33 : :
34 : : /* Get the old tuple, if any. */
35 : :
2471 andres@anarazel.de 36 : 622 : rel = table_open(DbRoleSettingRelationId, RowExclusiveLock);
5864 alvherre@alvh.no-ip. 37 : 622 : ScanKeyInit(&scankey[0],
38 : : Anum_pg_db_role_setting_setdatabase,
39 : : BTEqualStrategyNumber, F_OIDEQ,
40 : : ObjectIdGetDatum(databaseid));
41 : 622 : ScanKeyInit(&scankey[1],
42 : : Anum_pg_db_role_setting_setrole,
43 : : BTEqualStrategyNumber, F_OIDEQ,
44 : : ObjectIdGetDatum(roleid));
45 : 622 : scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true,
46 : : NULL, 2, scankey);
47 : 622 : 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 [ + + ]: 622 : if (setstmt->kind == VAR_RESET_ALL)
62 : : {
63 [ + - ]: 1 : if (HeapTupleIsValid(tuple))
64 : : {
5695 65 : 1 : ArrayType *new = NULL;
66 : : Datum datum;
67 : : bool isnull;
68 : :
69 : 1 : datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
70 : : RelationGetDescr(rel), &isnull);
71 : :
72 [ + - ]: 1 : if (!isnull)
894 akorotkov@postgresql 73 : 1 : new = GUCArrayReset(DatumGetArrayTypeP(datum));
74 : :
5695 alvherre@alvh.no-ip. 75 [ + - ]: 1 : 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 : 1 : memset(repl_repl, false, sizeof(repl_repl));
83 : :
84 : 1 : repl_val[Anum_pg_db_role_setting_setconfig - 1] =
85 : 1 : PointerGetDatum(new);
86 : 1 : repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
87 : 1 : repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
88 : :
89 : 1 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
90 : : repl_val, repl_null, repl_repl);
3191 91 : 1 : CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
92 : : }
93 : : else
3190 tgl@sss.pgh.pa.us 94 :UBC 0 : CatalogTupleDelete(rel, &tuple->t_self);
95 : : }
96 : : }
5864 alvherre@alvh.no-ip. 97 [ + + ]:CBC 621 : 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 : 503 : memset(repl_repl, false, sizeof(repl_repl));
108 : 503 : repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
109 : 503 : repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
110 : :
111 : : /* Extract old value of setconfig */
112 : 503 : datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
113 : : RelationGetDescr(rel), &isnull);
114 [ + - ]: 503 : a = isnull ? NULL : DatumGetArrayTypeP(datum);
115 : :
116 : : /* Update (valuestr is NULL in RESET cases) */
117 [ + + ]: 503 : if (valuestr)
894 akorotkov@postgresql 118 : 486 : a = GUCArrayAdd(a, setstmt->name, valuestr);
119 : : else
120 : 17 : a = GUCArrayDelete(a, setstmt->name);
121 : :
5864 alvherre@alvh.no-ip. 122 [ + + ]: 500 : if (a)
123 : : {
124 : 488 : repl_val[Anum_pg_db_role_setting_setconfig - 1] =
125 : 488 : PointerGetDatum(a);
126 : :
127 : 488 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
128 : : repl_val, repl_null, repl_repl);
3191 129 : 488 : CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
130 : : }
131 : : else
3190 tgl@sss.pgh.pa.us 132 : 12 : CatalogTupleDelete(rel, &tuple->t_self);
133 : : }
5864 alvherre@alvh.no-ip. 134 [ + + ]: 118 : 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 : 115 : memset(nulls, false, sizeof(nulls));
143 : :
894 akorotkov@postgresql 144 : 115 : a = GUCArrayAdd(NULL, setstmt->name, valuestr);
145 : :
5864 alvherre@alvh.no-ip. 146 : 115 : values[Anum_pg_db_role_setting_setdatabase - 1] =
147 : 115 : ObjectIdGetDatum(databaseid);
148 : 115 : values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
149 : 115 : values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
150 : 115 : newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
151 : :
3191 152 : 115 : 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 : : */
45 tgl@sss.pgh.pa.us 161 :GNC 3 : (void) GUCArrayDelete(NULL, setstmt->name);
162 : : }
163 : :
4607 rhaas@postgresql.org 164 [ - + ]:CBC 618 : InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
165 : : databaseid, 0, roleid, false);
166 : :
5864 alvherre@alvh.no-ip. 167 : 618 : systable_endscan(scan);
168 : :
169 : : /* Close pg_db_role_setting, but keep lock till commit */
2471 andres@anarazel.de 170 : 618 : table_close(rel, NoLock);
5864 alvherre@alvh.no-ip. 171 : 618 : }
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 : 735 : DropSetting(Oid databaseid, Oid roleid)
180 : : {
181 : : Relation relsetting;
182 : : TableScanDesc scan;
183 : : ScanKeyData keys[2];
184 : : HeapTuple tup;
5722 bruce@momjian.us 185 : 735 : int numkeys = 0;
186 : :
2471 andres@anarazel.de 187 : 735 : relsetting = table_open(DbRoleSettingRelationId, RowExclusiveLock);
188 : :
5864 alvherre@alvh.no-ip. 189 [ + + ]: 735 : if (OidIsValid(databaseid))
190 : : {
191 : 44 : ScanKeyInit(&keys[numkeys],
192 : : Anum_pg_db_role_setting_setdatabase,
193 : : BTEqualStrategyNumber,
194 : : F_OIDEQ,
195 : : ObjectIdGetDatum(databaseid));
196 : 44 : numkeys++;
197 : : }
198 [ + + ]: 735 : if (OidIsValid(roleid))
199 : : {
200 : 691 : ScanKeyInit(&keys[numkeys],
201 : : Anum_pg_db_role_setting_setrole,
202 : : BTEqualStrategyNumber,
203 : : F_OIDEQ,
204 : : ObjectIdGetDatum(roleid));
205 : 691 : numkeys++;
206 : : }
207 : :
2422 andres@anarazel.de 208 : 735 : scan = table_beginscan_catalog(relsetting, numkeys, keys);
5864 alvherre@alvh.no-ip. 209 [ + + ]: 740 : while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
210 : : {
3190 tgl@sss.pgh.pa.us 211 : 5 : CatalogTupleDelete(relsetting, &tup->t_self);
212 : : }
2422 andres@anarazel.de 213 : 735 : table_endscan(scan);
214 : :
2471 215 : 735 : table_close(relsetting, RowExclusiveLock);
5864 alvherre@alvh.no-ip. 216 : 735 : }
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
4500 rhaas@postgresql.org 229 : 53492 : ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
230 : : Relation relsetting, GucSource source)
231 : : {
232 : : SysScanDesc scan;
233 : : ScanKeyData keys[2];
234 : : HeapTuple tup;
235 : :
5864 alvherre@alvh.no-ip. 236 : 53492 : ScanKeyInit(&keys[0],
237 : : Anum_pg_db_role_setting_setdatabase,
238 : : BTEqualStrategyNumber,
239 : : F_OIDEQ,
240 : : ObjectIdGetDatum(databaseid));
241 : 53492 : ScanKeyInit(&keys[1],
242 : : Anum_pg_db_role_setting_setrole,
243 : : BTEqualStrategyNumber,
244 : : F_OIDEQ,
245 : : ObjectIdGetDatum(roleid));
246 : :
247 : 53492 : scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
248 : : snapshot, 2, keys);
249 [ + + ]: 56757 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
250 : : {
251 : : bool isnull;
252 : : Datum datum;
253 : :
254 : 3265 : datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
255 : : RelationGetDescr(relsetting), &isnull);
256 [ + - ]: 3265 : if (!isnull)
257 : : {
258 : 3265 : 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 : : */
894 akorotkov@postgresql 265 : 3265 : ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
266 : : }
267 : : }
268 : :
5864 alvherre@alvh.no-ip. 269 : 53492 : systable_endscan(scan);
270 : 53492 : }
|