PostgreSQL Source Code  git master
pg_db_role_setting.c
Go to the documentation of this file.
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"
20 #include "utils/fmgroids.h"
21 #include "utils/rel.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 = table_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  ArrayType *usersetArray;
67  Datum datum;
68  Datum usersetDatum;
69  bool isnull;
70  bool usersetIsnull;
71 
72  datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
73  RelationGetDescr(rel), &isnull);
74  usersetDatum = heap_getattr(tuple, Anum_pg_db_role_setting_setuser,
75  RelationGetDescr(rel), &usersetIsnull);
76 
77  if (!isnull)
78  {
79  Assert(!usersetIsnull);
80  usersetArray = DatumGetArrayTypeP(usersetDatum);
81  new = GUCArrayReset(DatumGetArrayTypeP(datum), &usersetArray);
82  }
83 
84  if (new)
85  {
86  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 
91  memset(repl_repl, false, sizeof(repl_repl));
92 
93  repl_val[Anum_pg_db_role_setting_setconfig - 1] =
94  PointerGetDatum(new);
95  repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
96  repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
97 
98  repl_val[Anum_pg_db_role_setting_setuser - 1] =
99  PointerGetDatum(usersetArray);
100  repl_repl[Anum_pg_db_role_setting_setuser - 1] = true;
101  repl_null[Anum_pg_db_role_setting_setuser - 1] = false;
102 
103  newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
104  repl_val, repl_null, repl_repl);
105  CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
106  }
107  else
108  CatalogTupleDelete(rel, &tuple->t_self);
109  }
110  }
111  else if (HeapTupleIsValid(tuple))
112  {
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 
124  memset(repl_repl, false, sizeof(repl_repl));
125  repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
126  repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
127  repl_repl[Anum_pg_db_role_setting_setuser - 1] = true;
128  repl_null[Anum_pg_db_role_setting_setuser - 1] = false;
129 
130  /* Extract old values of setconfig and setuser */
131  datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
132  RelationGetDescr(rel), &isnull);
133  a = isnull ? NULL : DatumGetArrayTypeP(datum);
134 
135  usersetDatum = heap_getattr(tuple, Anum_pg_db_role_setting_setuser,
136  RelationGetDescr(rel), &usersetIsnull);
137  usersetArray = usersetIsnull ? NULL : DatumGetArrayTypeP(usersetDatum);
138 
139  /* Update (valuestr is NULL in RESET cases) */
140  if (valuestr)
141  a = GUCArrayAdd(a, &usersetArray, setstmt->name, valuestr, setstmt->user_set);
142  else
143  a = GUCArrayDelete(a, &usersetArray, setstmt->name);
144 
145  if (a)
146  {
147  repl_val[Anum_pg_db_role_setting_setconfig - 1] =
149  repl_val[Anum_pg_db_role_setting_setuser - 1] =
150  PointerGetDatum(usersetArray);
151 
152  newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
153  repl_val, repl_null, repl_repl);
154  CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
155  }
156  else
157  CatalogTupleDelete(rel, &tuple->t_self);
158  }
159  else if (valuestr)
160  {
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 
168  memset(nulls, false, sizeof(nulls));
169 
170  a = GUCArrayAdd(NULL, &usersetArray, setstmt->name, valuestr, setstmt->user_set);
171 
172  values[Anum_pg_db_role_setting_setdatabase - 1] =
173  ObjectIdGetDatum(databaseid);
174  values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid);
175  values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a);
176  values[Anum_pg_db_role_setting_setuser - 1] = PointerGetDatum(usersetArray);
177  newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
178 
179  CatalogTupleInsert(rel, newtuple);
180  }
181 
182  InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
183  databaseid, 0, roleid, false);
184 
185  systable_endscan(scan);
186 
187  /* Close pg_db_role_setting, but keep lock till commit */
188  table_close(rel, NoLock);
189 }
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.)
195  */
196 void
197 DropSetting(Oid databaseid, Oid roleid)
198 {
199  Relation relsetting;
200  TableScanDesc scan;
201  ScanKeyData keys[2];
202  HeapTuple tup;
203  int numkeys = 0;
204 
205  relsetting = table_open(DbRoleSettingRelationId, RowExclusiveLock);
206 
207  if (OidIsValid(databaseid))
208  {
209  ScanKeyInit(&keys[numkeys],
210  Anum_pg_db_role_setting_setdatabase,
212  F_OIDEQ,
213  ObjectIdGetDatum(databaseid));
214  numkeys++;
215  }
216  if (OidIsValid(roleid))
217  {
218  ScanKeyInit(&keys[numkeys],
219  Anum_pg_db_role_setting_setrole,
221  F_OIDEQ,
222  ObjectIdGetDatum(roleid));
223  numkeys++;
224  }
225 
226  scan = table_beginscan_catalog(relsetting, numkeys, keys);
228  {
229  CatalogTupleDelete(relsetting, &tup->t_self);
230  }
231  table_endscan(scan);
232 
233  table_close(relsetting, RowExclusiveLock);
234 }
235 
236 /*
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
247 ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid,
248  Relation relsetting, GucSource source)
249 {
250  SysScanDesc scan;
251  ScanKeyData keys[2];
252  HeapTuple tup;
253 
254  ScanKeyInit(&keys[0],
255  Anum_pg_db_role_setting_setdatabase,
257  F_OIDEQ,
258  ObjectIdGetDatum(databaseid));
259  ScanKeyInit(&keys[1],
260  Anum_pg_db_role_setting_setrole,
262  F_OIDEQ,
263  ObjectIdGetDatum(roleid));
264 
265  scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true,
266  snapshot, 2, keys);
267  while (HeapTupleIsValid(tup = systable_getnext(scan)))
268  {
269  bool isnull;
270  bool usersetIsnull;
271  Datum datum;
272  Datum usersetDatum;
273 
274  datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig,
275  RelationGetDescr(relsetting), &isnull);
276  usersetDatum = heap_getattr(tup, Anum_pg_db_role_setting_setuser,
277  RelationGetDescr(relsetting), &usersetIsnull);
278  if (!isnull)
279  {
280  ArrayType *a = DatumGetArrayTypeP(datum);
281  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
286  * when it was inserted.
287  */
288  ProcessGUCArray(a, usersetArray, PGC_SUSET, source, GUC_ACTION_SET);
289  }
290  }
291 
292  systable_endscan(scan);
293 }
#define DatumGetArrayTypeP(X)
Definition: array.h:254
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define OidIsValid(objectId)
Definition: c.h:759
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
void ProcessGUCArray(ArrayType *array, ArrayType *usersetArray, GucContext context, GucSource source, GucAction action)
Definition: guc.c:6201
ArrayType * GUCArrayDelete(ArrayType *array, ArrayType **usersetArray, const char *name)
Definition: guc.c:6395
ArrayType * GUCArrayReset(ArrayType *array, ArrayType **usersetArray)
Definition: guc.c:6497
ArrayType * GUCArrayAdd(ArrayType *array, ArrayType **usersetArray, const char *name, const char *value, bool user_set)
Definition: guc.c:6279
@ GUC_ACTION_SET
Definition: guc.h:197
GucSource
Definition: guc.h:108
@ PGC_SUSET
Definition: guc.h:74
char * ExtractSetVariableArgs(VariableSetStmt *stmt)
Definition: guc_funcs.c:167
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1216
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
int a
Definition: isn.c:69
Assert(fmt[strlen(fmt) - 1] !='\n')
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:200
@ VAR_RESET_ALL
Definition: parsenodes.h:2325
void DropSetting(Oid databaseid, Oid roleid)
void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
void ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid, Relation relsetting, GucSource source)
static rewind_source * source
Definition: pg_rewind.c:81
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:527
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
VariableSetKind kind
Definition: parsenodes.h:2331
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:993