]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_db_role_setting.c
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
[postgresql] / src / backend / catalog / pg_db_role_setting.c
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-2013, 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
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
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
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 }