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-2016, 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 "catalog/indexing.h"
17 #include "catalog/objectaccess.h"
18 #include "catalog/pg_db_role_setting.h"
19 #include "utils/fmgroids.h"
20 #include "utils/rel.h"
21 #include "utils/tqual.h"
22
23 void
AlterSetting(Oid databaseid,Oid roleid,VariableSetStmt * setstmt)24 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 valuestr = ExtractSetVariableArgs(setstmt);
33
34 /* Get the old tuple, if any. */
35
36 rel = heap_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,
46 NULL, 2, scankey);
47 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 if (setstmt->kind == VAR_RESET_ALL)
62 {
63 if (HeapTupleIsValid(tuple))
64 {
65 ArrayType *new = NULL;
66 Datum datum;
67 bool isnull;
68
69 datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
70 RelationGetDescr(rel), &isnull);
71
72 if (!isnull)
73 new = GUCArrayReset(DatumGetArrayTypeP(datum));
74
75 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 memset(repl_repl, false, sizeof(repl_repl));
83
84 repl_val[Anum_pg_db_role_setting_setconfig - 1] =
85 PointerGetDatum(new);
86 repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
87 repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
88
89 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
90 repl_val, repl_null, repl_repl);
91 simple_heap_update(rel, &tuple->t_self, newtuple);
92
93 /* Update indexes */
94 CatalogUpdateIndexes(rel, newtuple);
95 }
96 else
97 simple_heap_delete(rel, &tuple->t_self);
98 }
99 }
100 else if (HeapTupleIsValid(tuple))
101 {
102 Datum repl_val[Natts_pg_db_role_setting];
103 bool repl_null[Natts_pg_db_role_setting];
104 bool repl_repl[Natts_pg_db_role_setting];
105 HeapTuple newtuple;
106 Datum datum;
107 bool isnull;
108 ArrayType *a;
109
110 memset(repl_repl, false, sizeof(repl_repl));
111 repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
112 repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
113
114 /* Extract old value of setconfig */
115 datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
116 RelationGetDescr(rel), &isnull);
117 a = isnull ? NULL : DatumGetArrayTypeP(datum);
118
119 /* Update (valuestr is NULL in RESET cases) */
120 if (valuestr)
121 a = GUCArrayAdd(a, setstmt->name, valuestr);
122 else
123 a = GUCArrayDelete(a, setstmt->name);
124
125 if (a)
126 {
127 repl_val[Anum_pg_db_role_setting_setconfig - 1] =
128 PointerGetDatum(a);
129
130 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
131 repl_val, repl_null, repl_repl);
132 simple_heap_update(rel, &tuple->t_self, newtuple);
133
134 /* Update indexes */
135 CatalogUpdateIndexes(rel, newtuple);
136 }
137 else
138 simple_heap_delete(rel, &tuple->t_self);
139 }
140 else if (valuestr)
141 {
142 /* non-null valuestr means it's not RESET, so insert a new tuple */
143 HeapTuple newtuple;
144 Datum values[Natts_pg_db_role_setting];
145 bool nulls[Natts_pg_db_role_setting];
146 ArrayType *a;
147
148 memset(nulls, false, sizeof(nulls));
149
150 a = GUCArrayAdd(NULL, setstmt->name, valuestr);
151
152 values[Anum_pg_db_role_setting_setdatabase - 1] =
153 ObjectIdGetDatum(databaseid);
154 values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
155 values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
156 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
157
158 simple_heap_insert(rel, newtuple);
159
160 /* Update indexes */
161 CatalogUpdateIndexes(rel, newtuple);
162 }
163
164 InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
165 databaseid, 0, roleid, false);
166
167 systable_endscan(scan);
168
169 /* Close pg_db_role_setting, but keep lock till commit */
170 heap_close(rel, NoLock);
171 }
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
DropSetting(Oid databaseid,Oid roleid)179 DropSetting(Oid databaseid, Oid roleid)
180 {
181 Relation relsetting;
182 HeapScanDesc scan;
183 ScanKeyData keys[2];
184 HeapTuple tup;
185 int numkeys = 0;
186
187 relsetting = heap_open(DbRoleSettingRelationId, RowExclusiveLock);
188
189 if (OidIsValid(databaseid))
190 {
191 ScanKeyInit(&keys[numkeys],
192 Anum_pg_db_role_setting_setdatabase,
193 BTEqualStrategyNumber,
194 F_OIDEQ,
195 ObjectIdGetDatum(databaseid));
196 numkeys++;
197 }
198 if (OidIsValid(roleid))
199 {
200 ScanKeyInit(&keys[numkeys],
201 Anum_pg_db_role_setting_setrole,
202 BTEqualStrategyNumber,
203 F_OIDEQ,
204 ObjectIdGetDatum(roleid));
205 numkeys++;
206 }
207
208 scan = heap_beginscan_catalog(relsetting, numkeys, keys);
209 while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
210 {
211 simple_heap_delete(relsetting, &tup->t_self);
212 }
213 heap_endscan(scan);
214
215 heap_close(relsetting, RowExclusiveLock);
216 }
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
ApplySetting(Snapshot snapshot,Oid databaseid,Oid roleid,Relation relsetting,GucSource source)229 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 ScanKeyInit(&keys[0],
237 Anum_pg_db_role_setting_setdatabase,
238 BTEqualStrategyNumber,
239 F_OIDEQ,
240 ObjectIdGetDatum(databaseid));
241 ScanKeyInit(&keys[1],
242 Anum_pg_db_role_setting_setrole,
243 BTEqualStrategyNumber,
244 F_OIDEQ,
245 ObjectIdGetDatum(roleid));
246
247 scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
248 snapshot, 2, keys);
249 while (HeapTupleIsValid(tup = systable_getnext(scan)))
250 {
251 bool isnull;
252 Datum datum;
253
254 datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
255 RelationGetDescr(relsetting), &isnull);
256 if (!isnull)
257 {
258 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 ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET);
266 }
267 }
268
269 systable_endscan(scan);
270 }
271