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