Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * variable.c
4 : : * Routines for handling specialized SET variables.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/backend/commands/variable.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : : #include "postgres.h"
18 : :
19 : : #include <ctype.h>
20 : :
21 : : #include "access/htup_details.h"
22 : : #include "access/parallel.h"
23 : : #include "access/xact.h"
24 : : #include "access/xlog.h"
25 : : #include "access/xlogprefetcher.h"
26 : : #include "catalog/pg_authid.h"
27 : : #include "common/string.h"
28 : : #include "mb/pg_wchar.h"
29 : : #include "miscadmin.h"
30 : : #include "postmaster/postmaster.h"
31 : : #include "postmaster/syslogger.h"
32 : : #include "storage/bufmgr.h"
33 : : #include "utils/acl.h"
34 : : #include "utils/backend_status.h"
35 : : #include "utils/datetime.h"
36 : : #include "utils/fmgrprotos.h"
37 : : #include "utils/guc_hooks.h"
38 : : #include "utils/snapmgr.h"
39 : : #include "utils/syscache.h"
40 : : #include "utils/timestamp.h"
41 : : #include "utils/tzparser.h"
42 : : #include "utils/varlena.h"
43 : :
44 : : /*
45 : : * DATESTYLE
46 : : */
47 : :
48 : : /*
49 : : * check_datestyle: GUC check_hook for datestyle
50 : : */
51 : : bool
5266 tgl@sss.pgh.pa.us 52 :GIC 12851 : check_datestyle(char **newval, void **extra, GucSource source)
53 : : {
8513 54 : 12851 : int newDateStyle = DateStyle;
8075 55 : 12851 : int newDateOrder = DateOrder;
7394 56 : 12851 : bool have_style = false;
57 : 12851 : bool have_order = false;
8513 58 : 12851 : bool ok = true;
59 : : char *rawstring;
60 : : int *myextra;
61 : : char *result;
62 : : List *elemlist;
63 : : ListCell *l;
64 : :
65 : : /* Need a modifiable copy of string */
5266 66 : 12851 : rawstring = pstrdup(*newval);
67 : :
68 : : /* Parse string into list of identifiers */
8513 69 [ - + ]: 12851 : if (!SplitIdentifierString(rawstring, ',', &elemlist))
70 : : {
71 : : /* syntax error in list */
5266 tgl@sss.pgh.pa.us 72 :UIC 0 : GUC_check_errdetail("List syntax is invalid.");
8513 73 : 0 : pfree(rawstring);
7773 neilc@samurai.com 74 : 0 : list_free(elemlist);
5266 tgl@sss.pgh.pa.us 75 : 0 : return false;
76 : : }
77 : :
8513 tgl@sss.pgh.pa.us 78 [ + - + + :GIC 33364 : foreach(l, elemlist)
+ + ]
79 : : {
80 : 20513 : char *tok = (char *) lfirst(l);
81 : :
82 : : /* Ugh. Somebody ought to write a table driven version -- mjl */
83 : :
7792 84 [ + + ]: 20513 : if (pg_strcasecmp(tok, "ISO") == 0)
85 : : {
7394 86 [ - + - - ]: 9254 : if (have_style && newDateStyle != USE_ISO_DATES)
7394 tgl@sss.pgh.pa.us 87 :UIC 0 : ok = false; /* conflicting styles */
8513 tgl@sss.pgh.pa.us 88 :GIC 9254 : newDateStyle = USE_ISO_DATES;
7394 89 : 9254 : have_style = true;
90 : : }
7792 91 [ + + ]: 11259 : else if (pg_strcasecmp(tok, "SQL") == 0)
92 : : {
7394 93 [ - + - - ]: 15 : if (have_style && newDateStyle != USE_SQL_DATES)
7394 tgl@sss.pgh.pa.us 94 :UIC 0 : ok = false; /* conflicting styles */
8513 tgl@sss.pgh.pa.us 95 :GIC 15 : newDateStyle = USE_SQL_DATES;
7394 96 : 15 : have_style = true;
97 : : }
7792 98 [ + + ]: 11244 : else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
99 : : {
7394 100 [ - + - - ]: 3536 : if (have_style && newDateStyle != USE_POSTGRES_DATES)
7394 tgl@sss.pgh.pa.us 101 :UIC 0 : ok = false; /* conflicting styles */
8513 tgl@sss.pgh.pa.us 102 :GIC 3536 : newDateStyle = USE_POSTGRES_DATES;
7394 103 : 3536 : have_style = true;
104 : : }
7792 105 [ + + ]: 7708 : else if (pg_strcasecmp(tok, "GERMAN") == 0)
106 : : {
7394 107 [ - + - - ]: 23 : if (have_style && newDateStyle != USE_GERMAN_DATES)
7394 tgl@sss.pgh.pa.us 108 :UIC 0 : ok = false; /* conflicting styles */
8513 tgl@sss.pgh.pa.us 109 :GIC 23 : newDateStyle = USE_GERMAN_DATES;
7394 110 : 23 : have_style = true;
111 : : /* GERMAN also sets DMY, unless explicitly overridden */
112 [ + - ]: 23 : if (!have_order)
8075 113 : 23 : newDateOrder = DATEORDER_DMY;
114 : : }
7792 115 [ + + ]: 7685 : else if (pg_strcasecmp(tok, "YMD") == 0)
116 : : {
7394 117 [ - + - - ]: 21 : if (have_order && newDateOrder != DATEORDER_YMD)
7394 tgl@sss.pgh.pa.us 118 :UIC 0 : ok = false; /* conflicting orders */
8075 tgl@sss.pgh.pa.us 119 :GIC 21 : newDateOrder = DATEORDER_YMD;
7394 120 : 21 : have_order = true;
121 : : }
7792 122 [ + + + + ]: 15305 : else if (pg_strcasecmp(tok, "DMY") == 0 ||
123 : 7641 : pg_strncasecmp(tok, "EURO", 4) == 0)
124 : : {
7394 125 [ - + - - ]: 32 : if (have_order && newDateOrder != DATEORDER_DMY)
7394 tgl@sss.pgh.pa.us 126 :UIC 0 : ok = false; /* conflicting orders */
8075 tgl@sss.pgh.pa.us 127 :GIC 32 : newDateOrder = DATEORDER_DMY;
7394 128 : 32 : have_order = true;
129 : : }
7792 130 [ + + - + ]: 7641 : else if (pg_strcasecmp(tok, "MDY") == 0 ||
131 [ - - ]: 9 : pg_strcasecmp(tok, "US") == 0 ||
7792 tgl@sss.pgh.pa.us 132 :UIC 0 : pg_strncasecmp(tok, "NONEURO", 7) == 0)
133 : : {
7394 tgl@sss.pgh.pa.us 134 [ - + - - ]:GIC 7632 : if (have_order && newDateOrder != DATEORDER_MDY)
7394 tgl@sss.pgh.pa.us 135 :UIC 0 : ok = false; /* conflicting orders */
8075 tgl@sss.pgh.pa.us 136 :GIC 7632 : newDateOrder = DATEORDER_MDY;
7394 137 : 7632 : have_order = true;
138 : : }
7792 tgl@sss.pgh.pa.us 139 [ # # ]:UIC 0 : else if (pg_strcasecmp(tok, "DEFAULT") == 0)
140 : : {
141 : : /*
142 : : * Easiest way to get the current DEFAULT state is to fetch the
143 : : * DEFAULT string from guc.c and recursively parse it.
144 : : *
145 : : * We can't simply "return check_datestyle(...)" because we need
146 : : * to handle constructs like "DEFAULT, ISO".
147 : : */
148 : : char *subval;
5263 bruce@momjian.us 149 : 0 : void *subextra = NULL;
150 : :
1058 tgl@sss.pgh.pa.us 151 : 0 : subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
8513 152 [ # # ]: 0 : if (!subval)
153 : : {
154 : 0 : ok = false;
155 : 0 : break;
156 : : }
5266 157 [ # # ]: 0 : if (!check_datestyle(&subval, &subextra, source))
158 : : {
1058 159 : 0 : guc_free(subval);
5266 160 : 0 : ok = false;
161 : 0 : break;
162 : : }
163 : 0 : myextra = (int *) subextra;
164 [ # # ]: 0 : if (!have_style)
165 : 0 : newDateStyle = myextra[0];
166 [ # # ]: 0 : if (!have_order)
167 : 0 : newDateOrder = myextra[1];
1058 168 : 0 : guc_free(subval);
169 : 0 : guc_free(subextra);
170 : : }
171 : : else
172 : : {
5266 173 : 0 : GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
174 : 0 : pfree(rawstring);
175 : 0 : list_free(elemlist);
176 : 0 : return false;
177 : : }
178 : : }
179 : :
8513 tgl@sss.pgh.pa.us 180 :GIC 12851 : pfree(rawstring);
7773 neilc@samurai.com 181 : 12851 : list_free(elemlist);
182 : :
8513 tgl@sss.pgh.pa.us 183 [ - + ]: 12851 : if (!ok)
184 : : {
334 michael@paquier.xyz 185 :UIC 0 : GUC_check_errdetail("Conflicting \"DateStyle\" specifications.");
5266 tgl@sss.pgh.pa.us 186 : 0 : return false;
187 : : }
188 : :
189 : : /*
190 : : * Prepare the canonical string to return. GUC wants it guc_malloc'd.
191 : : */
1058 tgl@sss.pgh.pa.us 192 :GIC 12851 : result = (char *) guc_malloc(LOG, 32);
8513 193 [ - + ]: 12851 : if (!result)
5266 tgl@sss.pgh.pa.us 194 :UIC 0 : return false;
195 : :
8513 tgl@sss.pgh.pa.us 196 [ + + + + ]:GIC 12851 : switch (newDateStyle)
197 : : {
198 : 9266 : case USE_ISO_DATES:
199 : 9266 : strcpy(result, "ISO");
200 : 9266 : break;
201 : 15 : case USE_SQL_DATES:
202 : 15 : strcpy(result, "SQL");
203 : 15 : break;
204 : 23 : case USE_GERMAN_DATES:
8089 205 : 23 : strcpy(result, "German");
8513 206 : 23 : break;
207 : 3547 : default:
8089 208 : 3547 : strcpy(result, "Postgres");
8513 209 : 3547 : break;
210 : : }
8075 211 [ + + + ]: 12851 : switch (newDateOrder)
212 : : {
213 : 27 : case DATEORDER_YMD:
214 : 27 : strcat(result, ", YMD");
215 : 27 : break;
216 : 45 : case DATEORDER_DMY:
217 : 45 : strcat(result, ", DMY");
218 : 45 : break;
219 : 12779 : default:
220 : 12779 : strcat(result, ", MDY");
221 : 12779 : break;
222 : : }
223 : :
1058 224 : 12851 : guc_free(*newval);
5266 225 : 12851 : *newval = result;
226 : :
227 : : /*
228 : : * Set up the "extra" struct actually used by assign_datestyle.
229 : : */
1058 230 : 12851 : myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
5266 231 [ - + ]: 12851 : if (!myextra)
5266 tgl@sss.pgh.pa.us 232 :UIC 0 : return false;
5266 tgl@sss.pgh.pa.us 233 :GIC 12851 : myextra[0] = newDateStyle;
234 : 12851 : myextra[1] = newDateOrder;
282 peter@eisentraut.org 235 : 12851 : *extra = myextra;
236 : :
5266 tgl@sss.pgh.pa.us 237 : 12851 : return true;
238 : : }
239 : :
240 : : /*
241 : : * assign_datestyle: GUC assign_hook for datestyle
242 : : */
243 : : void
244 : 17101 : assign_datestyle(const char *newval, void *extra)
245 : : {
246 : 17101 : int *myextra = (int *) extra;
247 : :
248 : 17101 : DateStyle = myextra[0];
249 : 17101 : DateOrder = myextra[1];
8724 lockhart@fourpalms.o 250 : 17101 : }
251 : :
252 : :
253 : : /*
254 : : * TIMEZONE
255 : : */
256 : :
257 : : /*
258 : : * check_timezone: GUC check_hook for timezone
259 : : */
260 : : bool
5266 tgl@sss.pgh.pa.us 261 : 7709 : check_timezone(char **newval, void **extra, GucSource source)
262 : : {
263 : : pg_tz *new_tz;
264 : : long gmtoffset;
265 : : char *endptr;
266 : : double hours;
267 : :
268 [ - + ]: 7709 : if (pg_strncasecmp(*newval, "interval", 8) == 0)
269 : : {
270 : : /*
271 : : * Support INTERVAL 'foo'. This is for SQL spec compliance, not
272 : : * because it has any actual real-world usefulness.
273 : : */
5266 tgl@sss.pgh.pa.us 274 :UIC 0 : const char *valueptr = *newval;
275 : : char *val;
276 : : Interval *interval;
277 : :
8513 278 : 0 : valueptr += 8;
279 [ # # ]: 0 : while (isspace((unsigned char) *valueptr))
280 : 0 : valueptr++;
281 [ # # ]: 0 : if (*valueptr++ != '\'')
5266 282 : 0 : return false;
8513 283 : 0 : val = pstrdup(valueptr);
284 : : /* Check and remove trailing quote */
285 : 0 : endptr = strchr(val, '\'');
286 [ # # # # ]: 0 : if (!endptr || endptr[1] != '\0')
287 : : {
288 : 0 : pfree(val);
5266 289 : 0 : return false;
290 : : }
8513 291 : 0 : *endptr = '\0';
292 : :
293 : : /*
294 : : * Try to parse it. XXX an invalid interval format will result in
295 : : * ereport(ERROR), which is not desirable for GUC. We did what we
296 : : * could to guard against this in flatten_set_variable_args, but a
297 : : * string coming in from postgresql.conf might contain anything.
298 : : */
299 : 0 : interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
300 : : CStringGetDatum(val),
301 : : ObjectIdGetDatum(InvalidOid),
302 : : Int32GetDatum(-1)));
303 : :
304 : 0 : pfree(val);
305 [ # # ]: 0 : if (interval->month != 0)
306 : : {
5266 307 : 0 : GUC_check_errdetail("Cannot specify months in time zone interval.");
8513 308 : 0 : pfree(interval);
5266 309 : 0 : return false;
310 : : }
7353 bruce@momjian.us 311 [ # # ]: 0 : if (interval->day != 0)
312 : : {
5266 tgl@sss.pgh.pa.us 313 : 0 : GUC_check_errdetail("Cannot specify days in time zone interval.");
7353 bruce@momjian.us 314 : 0 : pfree(interval);
5266 tgl@sss.pgh.pa.us 315 : 0 : return false;
316 : : }
317 : :
318 : : /* Here we change from SQL to Unix sign convention */
4327 319 : 0 : gmtoffset = -(interval->time / USECS_PER_SEC);
320 : 0 : new_tz = pg_tzset_offset(gmtoffset);
321 : :
8513 322 : 0 : pfree(interval);
323 : : }
324 : : else
325 : : {
326 : : /*
327 : : * Try it as a numeric number of hours (possibly fractional).
328 : : */
5266 tgl@sss.pgh.pa.us 329 :GIC 7709 : hours = strtod(*newval, &endptr);
330 [ + + + + ]: 7709 : if (endptr != *newval && *endptr == '\0')
331 : : {
332 : : /* Here we change from SQL to Unix sign convention */
4327 333 : 36 : gmtoffset = -hours * SECS_PER_HOUR;
334 : 36 : new_tz = pg_tzset_offset(gmtoffset);
335 : : }
336 : : else
337 : : {
338 : : /*
339 : : * Otherwise assume it is a timezone name, and try to load it.
340 : : */
5266 341 : 7673 : new_tz = pg_tzset(*newval);
342 : :
7445 bruce@momjian.us 343 [ - + ]: 7673 : if (!new_tz)
344 : : {
345 : : /* Doesn't seem to be any great value in errdetail here */
5266 tgl@sss.pgh.pa.us 346 :UIC 0 : return false;
347 : : }
348 : :
5111 tgl@sss.pgh.pa.us 349 [ - + ]:GIC 7673 : if (!pg_tz_acceptable(new_tz))
350 : : {
5266 tgl@sss.pgh.pa.us 351 :UIC 0 : GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
352 : : *newval);
353 : 0 : GUC_check_errdetail("PostgreSQL does not support leap seconds.");
354 : 0 : return false;
355 : : }
356 : : }
357 : : }
358 : :
359 : : /* Test for failure in pg_tzset_offset, which we assume is out-of-range */
4065 tgl@sss.pgh.pa.us 360 [ - + ]:GIC 7709 : if (!new_tz)
361 : : {
4065 tgl@sss.pgh.pa.us 362 :UIC 0 : GUC_check_errdetail("UTC timezone offset is out of range.");
363 : 0 : return false;
364 : : }
365 : :
366 : : /*
367 : : * Pass back data for assign_timezone to use
368 : : */
1058 tgl@sss.pgh.pa.us 369 :GIC 7709 : *extra = guc_malloc(LOG, sizeof(pg_tz *));
5266 370 [ - + ]: 7709 : if (!*extra)
5266 tgl@sss.pgh.pa.us 371 :UIC 0 : return false;
4327 tgl@sss.pgh.pa.us 372 :GIC 7709 : *((pg_tz **) *extra) = new_tz;
373 : :
5266 374 : 7709 : return true;
375 : : }
376 : :
377 : : /*
378 : : * assign_timezone: GUC assign_hook for timezone
379 : : */
380 : : void
381 : 7769 : assign_timezone(const char *newval, void *extra)
382 : : {
4327 383 : 7769 : session_timezone = *((pg_tz **) extra);
384 : : /* datetime.c's cache of timezone abbrevs may now be obsolete */
233 385 : 7769 : ClearTimeZoneAbbrevCache();
8513 386 : 7769 : }
387 : :
388 : : /*
389 : : * show_timezone: GUC show_hook for timezone
390 : : */
391 : : const char *
9082 392 : 25562 : show_timezone(void)
393 : : {
394 : : const char *tzn;
395 : :
396 : : /* Always show the zone's canonical name */
4327 397 : 25562 : tzn = pg_get_timezone_name(session_timezone);
398 : :
6608 399 [ + - ]: 25562 : if (tzn != NULL)
400 : 25562 : return tzn;
401 : :
6608 tgl@sss.pgh.pa.us 402 :UIC 0 : return "unknown";
403 : : }
404 : :
405 : :
406 : : /*
407 : : * LOG_TIMEZONE
408 : : *
409 : : * For log_timezone, we don't support the interval-based methods of setting a
410 : : * zone, which are only there for SQL spec compliance not because they're
411 : : * actually useful.
412 : : */
413 : :
414 : : /*
415 : : * check_log_timezone: GUC check_hook for log_timezone
416 : : */
417 : : bool
5266 tgl@sss.pgh.pa.us 418 :GIC 5450 : check_log_timezone(char **newval, void **extra, GucSource source)
419 : : {
420 : : pg_tz *new_tz;
421 : :
422 : : /*
423 : : * Assume it is a timezone name, and try to load it.
424 : : */
425 : 5450 : new_tz = pg_tzset(*newval);
426 : :
427 [ - + ]: 5450 : if (!new_tz)
428 : : {
429 : : /* Doesn't seem to be any great value in errdetail here */
5266 tgl@sss.pgh.pa.us 430 :UIC 0 : return false;
431 : : }
432 : :
5111 tgl@sss.pgh.pa.us 433 [ - + ]:GIC 5450 : if (!pg_tz_acceptable(new_tz))
434 : : {
5266 tgl@sss.pgh.pa.us 435 :UIC 0 : GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
436 : : *newval);
437 : 0 : GUC_check_errdetail("PostgreSQL does not support leap seconds.");
438 : 0 : return false;
439 : : }
440 : :
441 : : /*
442 : : * Pass back data for assign_log_timezone to use
443 : : */
1058 tgl@sss.pgh.pa.us 444 :GIC 5450 : *extra = guc_malloc(LOG, sizeof(pg_tz *));
5266 445 [ - + ]: 5450 : if (!*extra)
5266 tgl@sss.pgh.pa.us 446 :UIC 0 : return false;
4327 tgl@sss.pgh.pa.us 447 :GIC 5450 : *((pg_tz **) *extra) = new_tz;
448 : :
5266 449 : 5450 : return true;
450 : : }
451 : :
452 : : /*
453 : : * assign_log_timezone: GUC assign_hook for log_timezone
454 : : */
455 : : void
456 : 5447 : assign_log_timezone(const char *newval, void *extra)
457 : : {
458 : 5447 : log_timezone = *((pg_tz **) extra);
6608 459 : 5447 : }
460 : :
461 : : /*
462 : : * show_log_timezone: GUC show_hook for log_timezone
463 : : */
464 : : const char *
465 : 1694 : show_log_timezone(void)
466 : : {
467 : : const char *tzn;
468 : :
469 : : /* Always show the zone's canonical name */
470 : 1694 : tzn = pg_get_timezone_name(log_timezone);
471 : :
8724 lockhart@fourpalms.o 472 [ + - ]: 1694 : if (tzn != NULL)
8513 tgl@sss.pgh.pa.us 473 : 1694 : return tzn;
474 : :
8513 tgl@sss.pgh.pa.us 475 :UIC 0 : return "unknown";
476 : : }
477 : :
478 : :
479 : : /*
480 : : * TIMEZONE_ABBREVIATIONS
481 : : */
482 : :
483 : : /*
484 : : * GUC check_hook for timezone_abbreviations
485 : : */
486 : : bool
1089 tgl@sss.pgh.pa.us 487 :GIC 8882 : check_timezone_abbreviations(char **newval, void **extra, GucSource source)
488 : : {
489 : : /*
490 : : * The boot_val for timezone_abbreviations is NULL. When we see that we
491 : : * just do nothing. If the value isn't overridden from the config file
492 : : * then pg_timezone_abbrev_initialize() will eventually replace it with
493 : : * "Default". This hack has two purposes: to avoid wasting cycles loading
494 : : * values that might soon be overridden from the config file, and to avoid
495 : : * trying to read the timezone abbrev files during InitializeGUCOptions().
496 : : * The latter doesn't work in an EXEC_BACKEND subprocess because
497 : : * my_exec_path hasn't been set yet and so we can't locate PGSHAREDIR.
498 : : */
499 [ + + ]: 8882 : if (*newval == NULL)
500 : : {
501 [ - + ]: 2445 : Assert(source == PGC_S_DEFAULT);
502 : 2445 : return true;
503 : : }
504 : :
505 : : /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
506 : 6437 : *extra = load_tzoffsets(*newval);
507 : :
508 : : /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
509 [ - + ]: 6437 : if (!*extra)
1089 tgl@sss.pgh.pa.us 510 :UIC 0 : return false;
511 : :
1089 tgl@sss.pgh.pa.us 512 :GIC 6437 : return true;
513 : : }
514 : :
515 : : /*
516 : : * GUC assign_hook for timezone_abbreviations
517 : : */
518 : : void
519 : 8789 : assign_timezone_abbreviations(const char *newval, void *extra)
520 : : {
521 : : /* Do nothing for the boot_val default of NULL */
522 [ + + ]: 8789 : if (!extra)
523 : 2445 : return;
524 : :
525 : 6344 : InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
526 : : }
527 : :
528 : :
529 : : /*
530 : : * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
531 : : *
532 : : * We allow idempotent changes (r/w -> r/w and r/o -> r/o) at any time, and
533 : : * we also always allow changes from read-write to read-only. However,
534 : : * read-only may be changed to read-write only when in a top-level transaction
535 : : * that has not yet taken an initial snapshot. Can't do it in a hot standby,
536 : : * either.
537 : : *
538 : : * If we are not in a transaction at all, just allow the change; it means
539 : : * nothing since XactReadOnly will be reset by the next StartTransaction().
540 : : * The IsTransactionState() test protects us against trying to check
541 : : * RecoveryInProgress() in contexts where shared memory is not accessible.
542 : : * (Similarly, if we're restoring state in a parallel worker, just allow
543 : : * the change.)
544 : : */
545 : : bool
5266 546 : 5634 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
547 : : {
3469 rhaas@postgresql.org 548 [ + + + + : 5634 : if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
+ - + - ]
549 : : {
550 : : /* Can't go to r/w mode inside a r/o transaction */
5341 551 [ + + ]: 32 : if (IsSubTransaction())
552 : : {
5266 tgl@sss.pgh.pa.us 553 : 6 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
554 : 6 : GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
5341 rhaas@postgresql.org 555 : 6 : return false;
556 : : }
557 : : /* Top level transaction can't change to r/w after first snapshot. */
558 [ + + ]: 26 : if (FirstSnapshotSet)
559 : : {
5266 tgl@sss.pgh.pa.us 560 : 3 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
561 : 3 : GUC_check_errmsg("transaction read-write mode must be set before any query");
5341 rhaas@postgresql.org 562 : 3 : return false;
563 : : }
564 : : /* Can't go to r/w mode while recovery is still active */
565 [ - + ]: 23 : if (RecoveryInProgress())
566 : : {
4761 tgl@sss.pgh.pa.us 567 :UIC 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
5266 568 : 0 : GUC_check_errmsg("cannot set transaction read-write mode during recovery");
5341 rhaas@postgresql.org 569 : 0 : return false;
570 : : }
571 : : }
572 : :
5341 rhaas@postgresql.org 573 :GIC 5625 : return true;
574 : : }
575 : :
576 : : /*
577 : : * SET TRANSACTION ISOLATION LEVEL
578 : : *
579 : : * We allow idempotent changes at any time, but otherwise this can only be
580 : : * changed in a toplevel transaction that has not yet taken a snapshot.
581 : : *
582 : : * As in check_transaction_read_only, allow it if not inside a transaction,
583 : : * or if restoring state in a parallel worker.
584 : : */
585 : : bool
1089 tgl@sss.pgh.pa.us 586 : 8292 : check_transaction_isolation(int *newval, void **extra, GucSource source)
587 : : {
2524 peter_e@gmx.net 588 : 8292 : int newXactIsoLevel = *newval;
589 : :
396 tgl@sss.pgh.pa.us 590 [ + + + - ]: 11269 : if (newXactIsoLevel != XactIsoLevel &&
591 [ + + ]: 5954 : IsTransactionState() && !InitializingParallelWorker)
592 : : {
5342 rhaas@postgresql.org 593 [ + + ]: 2937 : if (FirstSnapshotSet)
594 : : {
5266 tgl@sss.pgh.pa.us 595 : 1 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
596 : 1 : GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
597 : 1 : return false;
598 : : }
599 : : /* We ignore a subtransaction setting it to the existing value. */
5341 rhaas@postgresql.org 600 [ - + ]: 2936 : if (IsSubTransaction())
601 : : {
5266 tgl@sss.pgh.pa.us 602 :UIC 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
603 : 0 : GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
604 : 0 : return false;
605 : : }
606 : : /* Can't go to serializable mode while recovery is still active */
5266 tgl@sss.pgh.pa.us 607 [ + + - + ]:GIC 2936 : if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
608 : : {
4761 tgl@sss.pgh.pa.us 609 :UIC 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
5266 610 : 0 : GUC_check_errmsg("cannot use serializable mode in a hot standby");
611 : 0 : GUC_check_errhint("You can use REPEATABLE READ instead.");
5325 heikki.linnakangas@i 612 : 0 : return false;
613 : : }
614 : : }
615 : :
5266 tgl@sss.pgh.pa.us 616 :GIC 8291 : return true;
617 : : }
618 : :
619 : : /*
620 : : * SET TRANSACTION [NOT] DEFERRABLE
621 : : */
622 : :
623 : : bool
624 : 4917 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
625 : : {
626 : : /* Just accept the value when restoring state in a parallel worker */
396 627 [ + + ]: 4917 : if (InitializingParallelWorker)
628 : 2756 : return true;
629 : :
5325 heikki.linnakangas@i 630 [ - + ]: 2161 : if (IsSubTransaction())
631 : : {
5266 tgl@sss.pgh.pa.us 632 :UIC 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
633 : 0 : GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
5325 heikki.linnakangas@i 634 : 0 : return false;
635 : : }
5325 heikki.linnakangas@i 636 [ - + ]:GIC 2161 : if (FirstSnapshotSet)
637 : : {
5266 tgl@sss.pgh.pa.us 638 :UIC 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
639 : 0 : GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
5325 heikki.linnakangas@i 640 : 0 : return false;
641 : : }
642 : :
5325 heikki.linnakangas@i 643 :GIC 2161 : return true;
644 : : }
645 : :
646 : : /*
647 : : * Random number seed
648 : : *
649 : : * We can't roll back the random sequence on error, and we don't want
650 : : * config file reloads to affect it, so we only want interactive SET SEED
651 : : * commands to set it. We use the "extra" storage to ensure that rollbacks
652 : : * don't try to do the operation again.
653 : : */
654 : :
655 : : bool
5266 tgl@sss.pgh.pa.us 656 : 1067 : check_random_seed(double *newval, void **extra, GucSource source)
657 : : {
1058 658 : 1067 : *extra = guc_malloc(LOG, sizeof(int));
5266 659 [ - + ]: 1067 : if (!*extra)
5266 tgl@sss.pgh.pa.us 660 :UIC 0 : return false;
661 : : /* Arm the assign only if source of value is an interactive SET */
5266 tgl@sss.pgh.pa.us 662 :GIC 1067 : *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
663 : :
8513 664 : 1067 : return true;
665 : : }
666 : :
667 : : void
5266 668 : 1067 : assign_random_seed(double newval, void *extra)
669 : : {
670 : : /* We'll do this at most once for any setting of the GUC variable */
671 [ - + ]: 1067 : if (*((int *) extra))
5266 tgl@sss.pgh.pa.us 672 :UIC 0 : DirectFunctionCall1(setseed, Float8GetDatum(newval));
5266 tgl@sss.pgh.pa.us 673 :GIC 1067 : *((int *) extra) = 0;
674 : 1067 : }
675 : :
676 : : const char *
8513 tgl@sss.pgh.pa.us 677 :UIC 0 : show_random_seed(void)
678 : : {
679 : 0 : return "unavailable";
680 : : }
681 : :
682 : :
683 : : /*
684 : : * SET CLIENT_ENCODING
685 : : */
686 : :
687 : : bool
5266 tgl@sss.pgh.pa.us 688 :GIC 18892 : check_client_encoding(char **newval, void **extra, GucSource source)
689 : : {
690 : : int encoding;
691 : : const char *canonical_name;
692 : :
693 : : /* Look up the encoding by name */
694 : 18892 : encoding = pg_valid_client_encoding(*newval);
9082 695 [ - + ]: 18892 : if (encoding < 0)
5266 tgl@sss.pgh.pa.us 696 :UIC 0 : return false;
697 : :
698 : : /* Get the canonical name (no aliases, uniform case) */
5254 tgl@sss.pgh.pa.us 699 :GIC 18892 : canonical_name = pg_encoding_to_char(encoding);
700 : :
701 : : /*
702 : : * Parallel workers send data to the leader, not the client. They always
703 : : * send data using the database encoding; therefore, we should never
704 : : * actually change the client encoding in a parallel worker. However,
705 : : * during parallel worker startup, we want to accept the leader's
706 : : * client_encoding setting so that anyone who looks at the value in the
707 : : * worker sees the same value that they would see in the leader. A change
708 : : * other than during startup, for example due to a SET clause attached to
709 : : * a function definition, should be rejected, as there is nothing we can
710 : : * do inside the worker to make it take effect.
711 : : */
396 712 [ + + - + ]: 18892 : if (IsParallelWorker() && !InitializingParallelWorker)
713 : : {
396 tgl@sss.pgh.pa.us 714 :UIC 0 : GUC_check_errcode(ERRCODE_INVALID_TRANSACTION_STATE);
715 : 0 : GUC_check_errdetail("Cannot change \"client_encoding\" during a parallel operation.");
716 : 0 : return false;
717 : : }
718 : :
719 : : /*
720 : : * If we are not within a transaction then PrepareClientEncoding will not
721 : : * be able to look up the necessary conversion procs. If we are still
722 : : * starting up, it will return "OK" anyway, and InitializeClientEncoding
723 : : * will fix things once initialization is far enough along. After
724 : : * startup, we'll fail. This would only happen if someone tries to change
725 : : * client_encoding in postgresql.conf and then SIGHUP existing sessions.
726 : : * It seems like a bad idea for client_encoding to change that way anyhow,
727 : : * so we don't go out of our way to support it.
728 : : *
729 : : * In a parallel worker, we might as well skip PrepareClientEncoding since
730 : : * we're not going to use its results.
731 : : *
732 : : * Note: in the postmaster, or any other process that never calls
733 : : * InitializeClientEncoding, PrepareClientEncoding will always succeed,
734 : : * and so will SetClientEncoding; but they won't do anything, which is OK.
735 : : */
396 tgl@sss.pgh.pa.us 736 [ + + - + ]:GIC 33650 : if (!IsParallelWorker() &&
737 : 14758 : PrepareClientEncoding(encoding) < 0)
738 : : {
5266 tgl@sss.pgh.pa.us 739 [ # # ]:UIC 0 : if (IsTransactionState())
740 : : {
741 : : /* Must be a genuine no-such-conversion problem */
742 : 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
743 : 0 : GUC_check_errdetail("Conversion between %s and %s is not supported.",
744 : : canonical_name,
745 : : GetDatabaseEncodingName());
746 : : }
747 : : else
748 : : {
749 : : /* Provide a useful complaint */
477 peter@eisentraut.org 750 : 0 : GUC_check_errdetail("Cannot change \"client_encoding\" now.");
751 : : }
5266 tgl@sss.pgh.pa.us 752 : 0 : return false;
753 : : }
754 : :
755 : : /*
756 : : * Replace the user-supplied string with the encoding's canonical name.
757 : : * This gets rid of aliases and case-folding variations.
758 : : *
759 : : * XXX Although canonicalizing seems like a good idea in the abstract, it
760 : : * breaks pre-9.1 JDBC drivers, which expect that if they send "UNICODE"
761 : : * as the client_encoding setting then it will read back the same way. As
762 : : * a workaround, don't replace the string if it's "UNICODE". Remove that
763 : : * hack when pre-9.1 JDBC drivers are no longer in use.
764 : : */
5254 tgl@sss.pgh.pa.us 765 [ + + ]:GIC 18892 : if (strcmp(*newval, canonical_name) != 0 &&
766 [ + - ]: 70 : strcmp(*newval, "UNICODE") != 0)
767 : : {
1058 768 : 70 : guc_free(*newval);
769 : 70 : *newval = guc_strdup(LOG, canonical_name);
5254 770 [ - + ]: 70 : if (!*newval)
5254 tgl@sss.pgh.pa.us 771 :UIC 0 : return false;
772 : : }
773 : :
774 : : /*
775 : : * Save the encoding's ID in *extra, for use by assign_client_encoding.
776 : : */
1058 tgl@sss.pgh.pa.us 777 :GIC 18892 : *extra = guc_malloc(LOG, sizeof(int));
5266 778 [ - + ]: 18892 : if (!*extra)
5266 tgl@sss.pgh.pa.us 779 :UIC 0 : return false;
5266 tgl@sss.pgh.pa.us 780 :GIC 18892 : *((int *) *extra) = encoding;
781 : :
782 : 18892 : return true;
783 : : }
784 : :
785 : : void
786 : 18806 : assign_client_encoding(const char *newval, void *extra)
787 : : {
788 : 18806 : int encoding = *((int *) extra);
789 : :
790 : : /*
791 : : * In a parallel worker, we never override the client encoding that was
792 : : * set by ParallelWorkerMain().
793 : : */
3355 rhaas@postgresql.org 794 [ + + ]: 18806 : if (IsParallelWorker())
396 tgl@sss.pgh.pa.us 795 : 4134 : return;
796 : :
797 : : /* We do not expect an error if PrepareClientEncoding succeeded */
5266 798 [ - + ]: 14672 : if (SetClientEncoding(encoding) < 0)
5266 tgl@sss.pgh.pa.us 799 [ # # ]:UIC 0 : elog(LOG, "SetClientEncoding(%d) failed", encoding);
800 : : }
801 : :
802 : :
803 : : /*
804 : : * SET SESSION AUTHORIZATION
805 : : */
806 : :
807 : : typedef struct
808 : : {
809 : : /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
810 : : Oid roleid;
811 : : bool is_superuser;
812 : : } role_auth_extra;
813 : :
814 : : bool
5266 tgl@sss.pgh.pa.us 815 :GIC 16044 : check_session_authorization(char **newval, void **extra, GucSource source)
816 : : {
817 : : HeapTuple roleTup;
818 : : Form_pg_authid roleform;
819 : : Oid roleid;
820 : : bool is_superuser;
821 : : role_auth_extra *myextra;
822 : :
823 : : /* Do nothing for the boot_val default of NULL */
824 [ + + ]: 16044 : if (*newval == NULL)
825 : 1067 : return true;
826 : :
299 827 [ + + ]: 14977 : if (InitializingParallelWorker)
828 : : {
829 : : /*
830 : : * In parallel worker initialization, we want to copy the leader's
831 : : * state even if it no longer matches the catalogs. ParallelWorkerMain
832 : : * already installed the correct role OID and superuser state.
833 : : */
834 : 1378 : roleid = GetSessionUserId();
835 : 1378 : is_superuser = GetSessionUserIsSuperuser();
836 : : }
837 : : else
838 : : {
839 [ - + ]: 13599 : if (!IsTransactionState())
840 : : {
841 : : /*
842 : : * Can't do catalog lookups, so fail. The result of this is that
843 : : * session_authorization cannot be set in postgresql.conf, which
844 : : * seems like a good thing anyway, so we don't work hard to avoid
845 : : * it.
846 : : */
299 tgl@sss.pgh.pa.us 847 :UIC 0 : return false;
848 : : }
849 : :
850 : : /*
851 : : * When source == PGC_S_TEST, we don't throw a hard error for a
852 : : * nonexistent user name or insufficient privileges, only a NOTICE.
853 : : * See comments in guc.h.
854 : : */
855 : :
856 : : /* Look up the username */
299 tgl@sss.pgh.pa.us 857 :GIC 13599 : roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
858 [ - + ]: 13599 : if (!HeapTupleIsValid(roleTup))
859 : : {
299 tgl@sss.pgh.pa.us 860 [ # # ]:UIC 0 : if (source == PGC_S_TEST)
861 : : {
862 [ # # ]: 0 : ereport(NOTICE,
863 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
864 : : errmsg("role \"%s\" does not exist", *newval)));
865 : 0 : return true;
866 : : }
867 : 0 : GUC_check_errmsg("role \"%s\" does not exist", *newval);
868 : 0 : return false;
869 : : }
870 : :
299 tgl@sss.pgh.pa.us 871 :GIC 13599 : roleform = (Form_pg_authid) GETSTRUCT(roleTup);
872 : 13599 : roleid = roleform->oid;
873 : 13599 : is_superuser = roleform->rolsuper;
874 : :
875 : 13599 : ReleaseSysCache(roleTup);
876 : :
877 : : /*
878 : : * Only superusers may SET SESSION AUTHORIZATION a role other than
879 : : * itself. Note that in case of multiple SETs in a single session, the
880 : : * original authenticated user's superuserness is what matters.
881 : : */
882 [ + + ]: 13599 : if (roleid != GetAuthenticatedUserId() &&
883 [ - + ]: 1298 : !superuser_arg(GetAuthenticatedUserId()))
884 : : {
299 tgl@sss.pgh.pa.us 885 [ # # ]:UIC 0 : if (source == PGC_S_TEST)
886 : : {
887 [ # # ]: 0 : ereport(NOTICE,
888 : : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
889 : : errmsg("permission will be denied to set session authorization \"%s\"",
890 : : *newval)));
891 : 0 : return true;
892 : : }
893 : 0 : GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
894 : 0 : GUC_check_errmsg("permission denied to set session authorization \"%s\"",
895 : : *newval);
896 : 0 : return false;
897 : : }
898 : : }
899 : :
900 : : /* Set up "extra" struct for assign_session_authorization to use */
1058 tgl@sss.pgh.pa.us 901 :GIC 14977 : myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
5266 902 [ - + ]: 14977 : if (!myextra)
5266 tgl@sss.pgh.pa.us 903 :UIC 0 : return false;
5266 tgl@sss.pgh.pa.us 904 :GIC 14977 : myextra->roleid = roleid;
905 : 14977 : myextra->is_superuser = is_superuser;
282 peter@eisentraut.org 906 : 14977 : *extra = myextra;
907 : :
5266 tgl@sss.pgh.pa.us 908 : 14977 : return true;
909 : : }
910 : :
911 : : void
912 : 16503 : assign_session_authorization(const char *newval, void *extra)
913 : : {
914 : 16503 : role_auth_extra *myextra = (role_auth_extra *) extra;
915 : :
916 : : /* Do nothing for the boot_val default of NULL */
917 [ + + ]: 16503 : if (!myextra)
918 : 1067 : return;
919 : :
920 : 15436 : SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
921 : : }
922 : :
923 : :
924 : : /*
925 : : * SET ROLE
926 : : *
927 : : * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
928 : : * a translation of "none" to InvalidOid. Otherwise this is much like
929 : : * SET SESSION AUTHORIZATION.
930 : : */
931 : :
932 : : bool
933 : 16556 : check_role(char **newval, void **extra, GucSource source)
934 : : {
935 : : HeapTuple roleTup;
936 : : Oid roleid;
937 : : bool is_superuser;
938 : : role_auth_extra *myextra;
939 : : Form_pg_authid roleform;
940 : :
941 [ + + ]: 16556 : if (strcmp(*newval, "none") == 0)
942 : : {
943 : : /* hardwired translation */
944 : 16034 : roleid = InvalidOid;
945 : 16034 : is_superuser = false;
946 : : }
299 947 [ + + ]: 522 : else if (InitializingParallelWorker)
948 : : {
949 : : /*
950 : : * In parallel worker initialization, we want to copy the leader's
951 : : * state even if it no longer matches the catalogs. ParallelWorkerMain
952 : : * already installed the correct role OID and superuser state.
953 : : */
954 : 6 : roleid = GetCurrentRoleId();
955 : 6 : is_superuser = current_role_is_superuser;
956 : : }
957 : : else
958 : : {
7348 959 [ - + ]: 516 : if (!IsTransactionState())
960 : : {
961 : : /*
962 : : * Can't do catalog lookups, so fail. The result of this is that
963 : : * role cannot be set in postgresql.conf, which seems like a good
964 : : * thing anyway, so we don't work hard to avoid it.
965 : : */
5266 tgl@sss.pgh.pa.us 966 :UIC 0 : return false;
967 : : }
968 : :
969 : : /*
970 : : * When source == PGC_S_TEST, we don't throw a hard error for a
971 : : * nonexistent user name or insufficient privileges, only a NOTICE.
972 : : * See comments in guc.h.
973 : : */
974 : :
975 : : /* Look up the username */
5266 tgl@sss.pgh.pa.us 976 :GIC 516 : roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
7348 977 [ - + ]: 516 : if (!HeapTupleIsValid(roleTup))
978 : : {
1607 tgl@sss.pgh.pa.us 979 [ # # ]:UIC 0 : if (source == PGC_S_TEST)
980 : : {
981 [ # # ]: 0 : ereport(NOTICE,
982 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
983 : : errmsg("role \"%s\" does not exist", *newval)));
984 : 0 : return true;
985 : : }
5266 986 : 0 : GUC_check_errmsg("role \"%s\" does not exist", *newval);
987 : 0 : return false;
988 : : }
989 : :
2482 andres@anarazel.de 990 :GIC 516 : roleform = (Form_pg_authid) GETSTRUCT(roleTup);
991 : 516 : roleid = roleform->oid;
992 : 516 : is_superuser = roleform->rolsuper;
993 : :
7348 tgl@sss.pgh.pa.us 994 : 516 : ReleaseSysCache(roleTup);
995 : :
996 : : /* Verify that session user is allowed to become this role */
299 997 [ + + ]: 516 : if (!member_can_set_role(GetSessionUserId(), roleid))
998 : : {
1607 999 [ - + ]: 6 : if (source == PGC_S_TEST)
1000 : : {
1607 tgl@sss.pgh.pa.us 1001 [ # # ]:UIC 0 : ereport(NOTICE,
1002 : : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1003 : : errmsg("permission will be denied to set role \"%s\"",
1004 : : *newval)));
1005 : 0 : return true;
1006 : : }
5266 tgl@sss.pgh.pa.us 1007 :GIC 6 : GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
1008 : 6 : GUC_check_errmsg("permission denied to set role \"%s\"",
1009 : : *newval);
1010 : 6 : return false;
1011 : : }
1012 : : }
1013 : :
1014 : : /* Set up "extra" struct for assign_role to use */
1058 1015 : 16550 : myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
5266 1016 [ - + ]: 16550 : if (!myextra)
5266 tgl@sss.pgh.pa.us 1017 :UIC 0 : return false;
5266 tgl@sss.pgh.pa.us 1018 :GIC 16550 : myextra->roleid = roleid;
1019 : 16550 : myextra->is_superuser = is_superuser;
282 peter@eisentraut.org 1020 : 16550 : *extra = myextra;
1021 : :
5266 tgl@sss.pgh.pa.us 1022 : 16550 : return true;
1023 : : }
1024 : :
1025 : : void
1026 : 17372 : assign_role(const char *newval, void *extra)
1027 : : {
1028 : 17372 : role_auth_extra *myextra = (role_auth_extra *) extra;
1029 : :
1030 : 17372 : SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
7348 1031 : 17372 : }
1032 : :
1033 : : const char *
1034 : 30 : show_role(void)
1035 : : {
1036 : : /*
1037 : : * Check whether SET ROLE is active; if not return "none". This is a
1038 : : * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
1039 : : * resets SET ROLE to NONE, but we cannot set the GUC role variable from
1040 : : * assign_session_authorization (because we haven't got enough info to
1041 : : * call set_config_option).
1042 : : */
5266 1043 [ + + ]: 30 : if (!OidIsValid(GetCurrentRoleId()))
7348 1044 : 12 : return "none";
1045 : :
1046 : : /* Otherwise we can just use the GUC string */
5266 1047 [ + - ]: 18 : return role_string ? role_string : "none";
1048 : : }
1049 : :
1050 : :
1051 : : /*
1052 : : * PATH VARIABLES
1053 : : *
1054 : : * check_canonical_path is used for log_directory and some other GUCs where
1055 : : * all we want to do is canonicalize the represented path name.
1056 : : */
1057 : :
1058 : : bool
1089 1059 : 2134 : check_canonical_path(char **newval, void **extra, GucSource source)
1060 : : {
1061 : : /*
1062 : : * Since canonicalize_path never enlarges the string, we can just modify
1063 : : * newval in-place. But watch out for NULL, which is the default value
1064 : : * for external_pid_file.
1065 : : */
1066 [ + + ]: 2134 : if (*newval)
1067 : 1067 : canonicalize_path(*newval);
1068 : 2134 : return true;
1069 : : }
1070 : :
1071 : :
1072 : : /*
1073 : : * MISCELLANEOUS
1074 : : */
1075 : :
1076 : : /*
1077 : : * GUC check_hook for application_name
1078 : : */
1079 : : bool
1080 : 14695 : check_application_name(char **newval, void **extra, GucSource source)
1081 : : {
1082 : : char *clean;
1083 : : char *ret;
1084 : :
1085 : : /* Only allow clean ASCII chars in the application name */
1086 : 14695 : clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1087 [ - + ]: 14695 : if (!clean)
1089 tgl@sss.pgh.pa.us 1088 :UIC 0 : return false;
1089 : :
163 dgustafsson@postgres 1090 :GIC 14695 : ret = guc_strdup(LOG, clean);
1071 peter@eisentraut.org 1091 [ - + ]: 14695 : if (!ret)
1092 : : {
1071 peter@eisentraut.org 1093 :UIC 0 : pfree(clean);
1089 tgl@sss.pgh.pa.us 1094 : 0 : return false;
1095 : : }
1096 : :
271 dgustafsson@postgres 1097 :GIC 14695 : guc_free(*newval);
1098 : :
1071 peter@eisentraut.org 1099 : 14695 : pfree(clean);
1100 : 14695 : *newval = ret;
1089 tgl@sss.pgh.pa.us 1101 : 14695 : return true;
1102 : : }
1103 : :
1104 : : /*
1105 : : * GUC assign_hook for application_name
1106 : : */
1107 : : void
1108 : 14682 : assign_application_name(const char *newval, void *extra)
1109 : : {
1110 : : /* Update the pg_stat_activity view */
1111 : 14682 : pgstat_report_appname(newval);
1112 : 14682 : }
1113 : :
1114 : : /*
1115 : : * GUC check_hook for cluster_name
1116 : : */
1117 : : bool
1118 : 1723 : check_cluster_name(char **newval, void **extra, GucSource source)
1119 : : {
1120 : : char *clean;
1121 : : char *ret;
1122 : :
1123 : : /* Only allow clean ASCII chars in the cluster name */
1124 : 1723 : clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1125 [ - + ]: 1723 : if (!clean)
1089 tgl@sss.pgh.pa.us 1126 :UIC 0 : return false;
1127 : :
163 dgustafsson@postgres 1128 :GIC 1723 : ret = guc_strdup(LOG, clean);
1071 peter@eisentraut.org 1129 [ - + ]: 1723 : if (!ret)
1130 : : {
1071 peter@eisentraut.org 1131 :UIC 0 : pfree(clean);
1089 tgl@sss.pgh.pa.us 1132 : 0 : return false;
1133 : : }
1134 : :
271 dgustafsson@postgres 1135 :GIC 1723 : guc_free(*newval);
1136 : :
1071 peter@eisentraut.org 1137 : 1723 : pfree(clean);
1138 : 1723 : *newval = ret;
1089 tgl@sss.pgh.pa.us 1139 : 1723 : return true;
1140 : : }
1141 : :
1142 : : /*
1143 : : * GUC assign_hook for maintenance_io_concurrency
1144 : : */
1145 : : void
1146 : 1068 : assign_maintenance_io_concurrency(int newval, void *extra)
1147 : : {
1148 : : /*
1149 : : * Reconfigure recovery prefetching, because a setting it depends on
1150 : : * changed.
1151 : : */
1152 : 1068 : maintenance_io_concurrency = newval;
1153 [ - + ]: 1068 : if (AmStartupProcess())
1089 tgl@sss.pgh.pa.us 1154 :UIC 0 : XLogPrefetchReconfigure();
1089 tgl@sss.pgh.pa.us 1155 :GIC 1068 : }
1156 : :
1157 : : /*
1158 : : * GUC assign hooks that recompute io_combine_limit whenever
1159 : : * io_combine_limit_guc and io_max_combine_limit are changed. These are needed
1160 : : * because the GUC subsystem doesn't support dependencies between GUCs, and
1161 : : * they may be assigned in either order.
1162 : : */
1163 : : void
171 tmunro@postgresql.or 1164 : 1067 : assign_io_max_combine_limit(int newval, void *extra)
1165 : : {
134 andres@anarazel.de 1166 : 1067 : io_combine_limit = Min(newval, io_combine_limit_guc);
171 tmunro@postgresql.or 1167 : 1067 : }
1168 : : void
1169 : 1084 : assign_io_combine_limit(int newval, void *extra)
1170 : : {
134 andres@anarazel.de 1171 : 1084 : io_combine_limit = Min(io_max_combine_limit, newval);
171 tmunro@postgresql.or 1172 : 1084 : }
1173 : :
1174 : : /*
1175 : : * These show hooks just exist because we want to show the values in octal.
1176 : : */
1177 : :
1178 : : /*
1179 : : * GUC show_hook for data_directory_mode
1180 : : */
1181 : : const char *
1089 tgl@sss.pgh.pa.us 1182 : 2028 : show_data_directory_mode(void)
1183 : : {
1184 : : static char buf[12];
1185 : :
1186 : 2028 : snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
1187 : 2028 : return buf;
1188 : : }
1189 : :
1190 : : /*
1191 : : * GUC show_hook for log_file_mode
1192 : : */
1193 : : const char *
1194 : 1694 : show_log_file_mode(void)
1195 : : {
1196 : : static char buf[12];
1197 : :
1198 : 1694 : snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
1199 : 1694 : return buf;
1200 : : }
1201 : :
1202 : : /*
1203 : : * GUC show_hook for unix_socket_permissions
1204 : : */
1205 : : const char *
1206 : 1694 : show_unix_socket_permissions(void)
1207 : : {
1208 : : static char buf[12];
1209 : :
1210 : 1694 : snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
1211 : 1694 : return buf;
1212 : : }
1213 : :
1214 : :
1215 : : /*
1216 : : * These check hooks do nothing more than reject non-default settings
1217 : : * in builds that don't support them.
1218 : : */
1219 : :
1220 : : bool
1221 : 1067 : check_bonjour(bool *newval, void **extra, GucSource source)
1222 : : {
1223 : : #ifndef USE_BONJOUR
1224 [ - + ]: 1067 : if (*newval)
1225 : : {
1089 tgl@sss.pgh.pa.us 1226 :UIC 0 : GUC_check_errmsg("Bonjour is not supported by this build");
1227 : 0 : return false;
1228 : : }
1229 : : #endif
1089 tgl@sss.pgh.pa.us 1230 :GIC 1067 : return true;
1231 : : }
1232 : :
1233 : : bool
1234 : 1073 : check_default_with_oids(bool *newval, void **extra, GucSource source)
1235 : : {
1236 [ + + ]: 1073 : if (*newval)
1237 : : {
1238 : : /* check the GUC's definition for an explanation */
1239 : 3 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
1240 : 3 : GUC_check_errmsg("tables declared WITH OIDS are not supported");
1241 : :
1242 : 3 : return false;
1243 : : }
1244 : :
1245 : 1070 : return true;
1246 : : }
1247 : :
1248 : : bool
1249 : 1100 : check_ssl(bool *newval, void **extra, GucSource source)
1250 : : {
1251 : : #ifndef USE_SSL
1252 : : if (*newval)
1253 : : {
1254 : : GUC_check_errmsg("SSL is not supported by this build");
1255 : : return false;
1256 : : }
1257 : : #endif
1258 : 1100 : return true;
1259 : : }
|