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-2024, 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
4756 tgl@sss.pgh.pa.us 52 :CBC 12153 : check_datestyle(char **newval, void **extra, GucSource source)
53 : : {
8003 54 : 12153 : int newDateStyle = DateStyle;
7565 55 : 12153 : int newDateOrder = DateOrder;
6884 56 : 12153 : bool have_style = false;
57 : 12153 : bool have_order = false;
8003 58 : 12153 : 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 */
4756 66 : 12153 : rawstring = pstrdup(*newval);
67 : :
68 : : /* Parse string into list of identifiers */
8003 69 [ - + ]: 12153 : if (!SplitIdentifierString(rawstring, ',', &elemlist))
70 : : {
71 : : /* syntax error in list */
4756 tgl@sss.pgh.pa.us 72 :UBC 0 : GUC_check_errdetail("List syntax is invalid.");
8003 73 : 0 : pfree(rawstring);
7263 neilc@samurai.com 74 : 0 : list_free(elemlist);
4756 tgl@sss.pgh.pa.us 75 : 0 : return false;
76 : : }
77 : :
8003 tgl@sss.pgh.pa.us 78 [ + - + + :CBC 31622 : foreach(l, elemlist)
+ + ]
79 : : {
80 : 19469 : char *tok = (char *) lfirst(l);
81 : :
82 : : /* Ugh. Somebody ought to write a table driven version -- mjl */
83 : :
7282 84 [ + + ]: 19469 : if (pg_strcasecmp(tok, "ISO") == 0)
85 : : {
6884 86 [ - + - - ]: 8717 : if (have_style && newDateStyle != USE_ISO_DATES)
6884 tgl@sss.pgh.pa.us 87 :UBC 0 : ok = false; /* conflicting styles */
8003 tgl@sss.pgh.pa.us 88 :CBC 8717 : newDateStyle = USE_ISO_DATES;
6884 89 : 8717 : have_style = true;
90 : : }
7282 91 [ + + ]: 10752 : else if (pg_strcasecmp(tok, "SQL") == 0)
92 : : {
6884 93 [ - + - - ]: 15 : if (have_style && newDateStyle != USE_SQL_DATES)
6884 tgl@sss.pgh.pa.us 94 :UBC 0 : ok = false; /* conflicting styles */
8003 tgl@sss.pgh.pa.us 95 :CBC 15 : newDateStyle = USE_SQL_DATES;
6884 96 : 15 : have_style = true;
97 : : }
7282 98 [ + + ]: 10737 : else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
99 : : {
6884 100 [ - + - - ]: 3378 : if (have_style && newDateStyle != USE_POSTGRES_DATES)
6884 tgl@sss.pgh.pa.us 101 :UBC 0 : ok = false; /* conflicting styles */
8003 tgl@sss.pgh.pa.us 102 :CBC 3378 : newDateStyle = USE_POSTGRES_DATES;
6884 103 : 3378 : have_style = true;
104 : : }
7282 105 [ + + ]: 7359 : else if (pg_strcasecmp(tok, "GERMAN") == 0)
106 : : {
6884 107 [ - + - - ]: 20 : if (have_style && newDateStyle != USE_GERMAN_DATES)
6884 tgl@sss.pgh.pa.us 108 :UBC 0 : ok = false; /* conflicting styles */
8003 tgl@sss.pgh.pa.us 109 :CBC 20 : newDateStyle = USE_GERMAN_DATES;
6884 110 : 20 : have_style = true;
111 : : /* GERMAN also sets DMY, unless explicitly overridden */
112 [ + - ]: 20 : if (!have_order)
7565 113 : 20 : newDateOrder = DATEORDER_DMY;
114 : : }
7282 115 [ + + ]: 7339 : else if (pg_strcasecmp(tok, "YMD") == 0)
116 : : {
6884 117 [ - + - - ]: 21 : if (have_order && newDateOrder != DATEORDER_YMD)
6884 tgl@sss.pgh.pa.us 118 :UBC 0 : ok = false; /* conflicting orders */
7565 tgl@sss.pgh.pa.us 119 :CBC 21 : newDateOrder = DATEORDER_YMD;
6884 120 : 21 : have_order = true;
121 : : }
7282 122 [ + + + + ]: 14613 : else if (pg_strcasecmp(tok, "DMY") == 0 ||
123 : 7295 : pg_strncasecmp(tok, "EURO", 4) == 0)
124 : : {
6884 125 [ - + - - ]: 32 : if (have_order && newDateOrder != DATEORDER_DMY)
6884 tgl@sss.pgh.pa.us 126 :UBC 0 : ok = false; /* conflicting orders */
7565 tgl@sss.pgh.pa.us 127 :CBC 32 : newDateOrder = DATEORDER_DMY;
6884 128 : 32 : have_order = true;
129 : : }
7282 130 [ + + - + ]: 7295 : else if (pg_strcasecmp(tok, "MDY") == 0 ||
131 [ - - ]: 9 : pg_strcasecmp(tok, "US") == 0 ||
7282 tgl@sss.pgh.pa.us 132 :UBC 0 : pg_strncasecmp(tok, "NONEURO", 7) == 0)
133 : : {
6884 tgl@sss.pgh.pa.us 134 [ - + - - ]:CBC 7286 : if (have_order && newDateOrder != DATEORDER_MDY)
6884 tgl@sss.pgh.pa.us 135 :UBC 0 : ok = false; /* conflicting orders */
7565 tgl@sss.pgh.pa.us 136 :CBC 7286 : newDateOrder = DATEORDER_MDY;
6884 137 : 7286 : have_order = true;
138 : : }
7282 tgl@sss.pgh.pa.us 139 [ # # ]:UBC 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;
4753 bruce@momjian.us 149 : 0 : void *subextra = NULL;
150 : :
548 tgl@sss.pgh.pa.us 151 : 0 : subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
8003 152 [ # # ]: 0 : if (!subval)
153 : : {
154 : 0 : ok = false;
155 : 0 : break;
156 : : }
4756 157 [ # # ]: 0 : if (!check_datestyle(&subval, &subextra, source))
158 : : {
548 159 : 0 : guc_free(subval);
4756 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];
548 168 : 0 : guc_free(subval);
169 : 0 : guc_free(subextra);
170 : : }
171 : : else
172 : : {
4756 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 : :
8003 tgl@sss.pgh.pa.us 180 :CBC 12153 : pfree(rawstring);
7263 neilc@samurai.com 181 : 12153 : list_free(elemlist);
182 : :
8003 tgl@sss.pgh.pa.us 183 [ - + ]: 12153 : if (!ok)
184 : : {
4756 tgl@sss.pgh.pa.us 185 :UBC 0 : GUC_check_errdetail("Conflicting \"datestyle\" specifications.");
186 : 0 : return false;
187 : : }
188 : :
189 : : /*
190 : : * Prepare the canonical string to return. GUC wants it guc_malloc'd.
191 : : */
548 tgl@sss.pgh.pa.us 192 :CBC 12153 : result = (char *) guc_malloc(LOG, 32);
8003 193 [ - + ]: 12153 : if (!result)
4756 tgl@sss.pgh.pa.us 194 :UBC 0 : return false;
195 : :
8003 tgl@sss.pgh.pa.us 196 [ + + + + ]:CBC 12153 : switch (newDateStyle)
197 : : {
198 : 8729 : case USE_ISO_DATES:
199 : 8729 : strcpy(result, "ISO");
200 : 8729 : break;
201 : 15 : case USE_SQL_DATES:
202 : 15 : strcpy(result, "SQL");
203 : 15 : break;
204 : 20 : case USE_GERMAN_DATES:
7579 205 : 20 : strcpy(result, "German");
8003 206 : 20 : break;
207 : 3389 : default:
7579 208 : 3389 : strcpy(result, "Postgres");
8003 209 : 3389 : break;
210 : : }
7565 211 [ + + + ]: 12153 : switch (newDateOrder)
212 : : {
213 : 27 : case DATEORDER_YMD:
214 : 27 : strcat(result, ", YMD");
215 : 27 : break;
216 : 42 : case DATEORDER_DMY:
217 : 42 : strcat(result, ", DMY");
218 : 42 : break;
219 : 12084 : default:
220 : 12084 : strcat(result, ", MDY");
221 : 12084 : break;
222 : : }
223 : :
548 224 : 12153 : guc_free(*newval);
4756 225 : 12153 : *newval = result;
226 : :
227 : : /*
228 : : * Set up the "extra" struct actually used by assign_datestyle.
229 : : */
548 230 : 12153 : myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
4756 231 [ - + ]: 12153 : if (!myextra)
4756 tgl@sss.pgh.pa.us 232 :UBC 0 : return false;
4756 tgl@sss.pgh.pa.us 233 :CBC 12153 : myextra[0] = newDateStyle;
234 : 12153 : myextra[1] = newDateOrder;
235 : 12153 : *extra = (void *) myextra;
236 : :
237 : 12153 : return true;
238 : : }
239 : :
240 : : /*
241 : : * assign_datestyle: GUC assign_hook for datestyle
242 : : */
243 : : void
244 : 16197 : assign_datestyle(const char *newval, void *extra)
245 : : {
246 : 16197 : int *myextra = (int *) extra;
247 : :
248 : 16197 : DateStyle = myextra[0];
249 : 16197 : DateOrder = myextra[1];
8214 lockhart@fourpalms.o 250 : 16197 : }
251 : :
252 : :
253 : : /*
254 : : * TIMEZONE
255 : : */
256 : :
257 : : /*
258 : : * check_timezone: GUC check_hook for timezone
259 : : */
260 : : bool
4756 tgl@sss.pgh.pa.us 261 : 7335 : 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 [ - + ]: 7335 : 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 : : */
4756 tgl@sss.pgh.pa.us 274 :UBC 0 : const char *valueptr = *newval;
275 : : char *val;
276 : : Interval *interval;
277 : :
8003 278 : 0 : valueptr += 8;
279 [ # # ]: 0 : while (isspace((unsigned char) *valueptr))
280 : 0 : valueptr++;
281 [ # # ]: 0 : if (*valueptr++ != '\'')
4756 282 : 0 : return false;
8003 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);
4756 289 : 0 : return false;
290 : : }
8003 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 : : {
4756 307 : 0 : GUC_check_errdetail("Cannot specify months in time zone interval.");
8003 308 : 0 : pfree(interval);
4756 309 : 0 : return false;
310 : : }
6843 bruce@momjian.us 311 [ # # ]: 0 : if (interval->day != 0)
312 : : {
4756 tgl@sss.pgh.pa.us 313 : 0 : GUC_check_errdetail("Cannot specify days in time zone interval.");
6843 bruce@momjian.us 314 : 0 : pfree(interval);
4756 tgl@sss.pgh.pa.us 315 : 0 : return false;
316 : : }
317 : :
318 : : /* Here we change from SQL to Unix sign convention */
3817 319 : 0 : gmtoffset = -(interval->time / USECS_PER_SEC);
320 : 0 : new_tz = pg_tzset_offset(gmtoffset);
321 : :
8003 322 : 0 : pfree(interval);
323 : : }
324 : : else
325 : : {
326 : : /*
327 : : * Try it as a numeric number of hours (possibly fractional).
328 : : */
4756 tgl@sss.pgh.pa.us 329 :CBC 7335 : hours = strtod(*newval, &endptr);
330 [ + + + + ]: 7335 : if (endptr != *newval && *endptr == '\0')
331 : : {
332 : : /* Here we change from SQL to Unix sign convention */
3817 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 : : */
4756 341 : 7299 : new_tz = pg_tzset(*newval);
342 : :
6935 bruce@momjian.us 343 [ - + ]: 7299 : if (!new_tz)
344 : : {
345 : : /* Doesn't seem to be any great value in errdetail here */
4756 tgl@sss.pgh.pa.us 346 :UBC 0 : return false;
347 : : }
348 : :
4601 tgl@sss.pgh.pa.us 349 [ - + ]:CBC 7299 : if (!pg_tz_acceptable(new_tz))
350 : : {
4756 tgl@sss.pgh.pa.us 351 :UBC 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 */
3555 tgl@sss.pgh.pa.us 360 [ - + ]:CBC 7335 : if (!new_tz)
361 : : {
3555 tgl@sss.pgh.pa.us 362 :UBC 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 : : */
548 tgl@sss.pgh.pa.us 369 :CBC 7335 : *extra = guc_malloc(LOG, sizeof(pg_tz *));
4756 370 [ - + ]: 7335 : if (!*extra)
4756 tgl@sss.pgh.pa.us 371 :UBC 0 : return false;
3817 tgl@sss.pgh.pa.us 372 :CBC 7335 : *((pg_tz **) *extra) = new_tz;
373 : :
4756 374 : 7335 : return true;
375 : : }
376 : :
377 : : /*
378 : : * assign_timezone: GUC assign_hook for timezone
379 : : */
380 : : void
381 : 7383 : assign_timezone(const char *newval, void *extra)
382 : : {
3817 383 : 7383 : session_timezone = *((pg_tz **) extra);
8003 384 : 7383 : }
385 : :
386 : : /*
387 : : * show_timezone: GUC show_hook for timezone
388 : : */
389 : : const char *
8572 390 : 24186 : show_timezone(void)
391 : : {
392 : : const char *tzn;
393 : :
394 : : /* Always show the zone's canonical name */
3817 395 : 24186 : tzn = pg_get_timezone_name(session_timezone);
396 : :
6098 397 [ + - ]: 24186 : if (tzn != NULL)
398 : 24186 : return tzn;
399 : :
6098 tgl@sss.pgh.pa.us 400 :UBC 0 : return "unknown";
401 : : }
402 : :
403 : :
404 : : /*
405 : : * LOG_TIMEZONE
406 : : *
407 : : * For log_timezone, we don't support the interval-based methods of setting a
408 : : * 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
4756 tgl@sss.pgh.pa.us 416 :CBC 5206 : 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 : 5206 : new_tz = pg_tzset(*newval);
424 : :
425 [ - + ]: 5206 : if (!new_tz)
426 : : {
427 : : /* Doesn't seem to be any great value in errdetail here */
4756 tgl@sss.pgh.pa.us 428 :UBC 0 : return false;
429 : : }
430 : :
4601 tgl@sss.pgh.pa.us 431 [ - + ]:CBC 5206 : if (!pg_tz_acceptable(new_tz))
432 : : {
4756 tgl@sss.pgh.pa.us 433 :UBC 0 : GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
434 : : *newval);
435 : 0 : GUC_check_errdetail("PostgreSQL does not support leap seconds.");
436 : 0 : return false;
437 : : }
438 : :
439 : : /*
440 : : * Pass back data for assign_log_timezone to use
441 : : */
548 tgl@sss.pgh.pa.us 442 :CBC 5206 : *extra = guc_malloc(LOG, sizeof(pg_tz *));
4756 443 [ - + ]: 5206 : if (!*extra)
4756 tgl@sss.pgh.pa.us 444 :UBC 0 : return false;
3817 tgl@sss.pgh.pa.us 445 :CBC 5206 : *((pg_tz **) *extra) = new_tz;
446 : :
4756 447 : 5206 : return true;
448 : : }
449 : :
450 : : /*
451 : : * assign_log_timezone: GUC assign_hook for log_timezone
452 : : */
453 : : void
454 : 5203 : assign_log_timezone(const char *newval, void *extra)
455 : : {
456 : 5203 : log_timezone = *((pg_tz **) extra);
6098 457 : 5203 : }
458 : :
459 : : /*
460 : : * show_log_timezone: GUC show_hook for log_timezone
461 : : */
462 : : const char *
463 : 1892 : show_log_timezone(void)
464 : : {
465 : : const char *tzn;
466 : :
467 : : /* Always show the zone's canonical name */
468 : 1892 : tzn = pg_get_timezone_name(log_timezone);
469 : :
8214 lockhart@fourpalms.o 470 [ + - ]: 1892 : if (tzn != NULL)
8003 tgl@sss.pgh.pa.us 471 : 1892 : return tzn;
472 : :
8003 tgl@sss.pgh.pa.us 473 :UBC 0 : return "unknown";
474 : : }
475 : :
476 : :
477 : : /*
478 : : * TIMEZONE_ABBREVIATIONS
479 : : */
480 : :
481 : : /*
482 : : * GUC check_hook for assign_timezone_abbreviations
483 : : */
484 : : bool
579 tgl@sss.pgh.pa.us 485 :CBC 8475 : 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 [ + + ]: 8475 : if (*newval == NULL)
498 : : {
499 [ - + ]: 2250 : Assert(source == PGC_S_DEFAULT);
500 : 2250 : return true;
501 : : }
502 : :
503 : : /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
504 : 6225 : *extra = load_tzoffsets(*newval);
505 : :
506 : : /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
507 [ - + ]: 6225 : if (!*extra)
579 tgl@sss.pgh.pa.us 508 :UBC 0 : return false;
509 : :
579 tgl@sss.pgh.pa.us 510 :CBC 6225 : return true;
511 : : }
512 : :
513 : : /*
514 : : * GUC assign_hook for assign_timezone_abbreviations
515 : : */
516 : : void
517 : 8385 : assign_timezone_abbreviations(const char *newval, void *extra)
518 : : {
519 : : /* Do nothing for the boot_val default of NULL */
520 [ + + ]: 8385 : if (!extra)
521 : 2250 : return;
522 : :
523 : 6135 : InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
524 : : }
525 : :
526 : :
527 : : /*
528 : : * 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
531 : : * 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 : : */
543 : : bool
4756 544 : 5189 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
545 : : {
2959 rhaas@postgresql.org 546 [ + + + + : 5189 : if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
+ - + - ]
547 : : {
548 : : /* Can't go to r/w mode inside a r/o transaction */
4831 549 [ + + ]: 32 : if (IsSubTransaction())
550 : : {
4756 tgl@sss.pgh.pa.us 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");
4831 rhaas@postgresql.org 553 : 6 : return false;
554 : : }
555 : : /* Top level transaction can't change to r/w after first snapshot. */
556 [ + + ]: 26 : if (FirstSnapshotSet)
557 : : {
4756 tgl@sss.pgh.pa.us 558 : 3 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
559 : 3 : GUC_check_errmsg("transaction read-write mode must be set before any query");
4831 rhaas@postgresql.org 560 : 3 : return false;
561 : : }
562 : : /* Can't go to r/w mode while recovery is still active */
563 [ - + ]: 23 : if (RecoveryInProgress())
564 : : {
4251 tgl@sss.pgh.pa.us 565 :UBC 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
4756 566 : 0 : GUC_check_errmsg("cannot set transaction read-write mode during recovery");
4831 rhaas@postgresql.org 567 : 0 : return false;
568 : : }
569 : : }
570 : :
4831 rhaas@postgresql.org 571 :CBC 5180 : return true;
572 : : }
573 : :
574 : : /*
575 : : * SET TRANSACTION ISOLATION LEVEL
576 : : *
577 : : * We allow idempotent changes at any time, but otherwise this can only be
578 : : * changed in a toplevel transaction that has not yet taken a snapshot.
579 : : *
580 : : * As in check_transaction_read_only, allow it if not inside a transaction.
581 : : */
582 : : bool
579 tgl@sss.pgh.pa.us 583 : 7817 : check_transaction_isolation(int *newval, void **extra, GucSource source)
584 : : {
2014 peter_e@gmx.net 585 : 7817 : int newXactIsoLevel = *newval;
586 : :
4251 tgl@sss.pgh.pa.us 587 [ + + + - ]: 7817 : if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
588 : : {
4832 rhaas@postgresql.org 589 [ + + ]: 2895 : if (FirstSnapshotSet)
590 : : {
4756 tgl@sss.pgh.pa.us 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. */
4831 rhaas@postgresql.org 596 [ - + ]: 2894 : if (IsSubTransaction())
597 : : {
4756 tgl@sss.pgh.pa.us 598 :UBC 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 : : }
602 : : /* Can't go to serializable mode while recovery is still active */
4756 tgl@sss.pgh.pa.us 603 [ + + - + ]:CBC 2894 : if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
604 : : {
4251 tgl@sss.pgh.pa.us 605 :UBC 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
4756 606 : 0 : GUC_check_errmsg("cannot use serializable mode in a hot standby");
607 : 0 : GUC_check_errhint("You can use REPEATABLE READ instead.");
4815 heikki.linnakangas@i 608 : 0 : return false;
609 : : }
610 : : }
611 : :
4756 tgl@sss.pgh.pa.us 612 :CBC 7816 : return true;
613 : : }
614 : :
615 : : /*
616 : : * SET TRANSACTION [NOT] DEFERRABLE
617 : : */
618 : :
619 : : bool
620 : 4527 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
621 : : {
4815 heikki.linnakangas@i 622 [ - + ]: 4527 : if (IsSubTransaction())
623 : : {
4756 tgl@sss.pgh.pa.us 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");
4815 heikki.linnakangas@i 626 : 0 : return false;
627 : : }
4815 heikki.linnakangas@i 628 [ - + ]:CBC 4527 : if (FirstSnapshotSet)
629 : : {
4756 tgl@sss.pgh.pa.us 630 :UBC 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
631 : 0 : GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
4815 heikki.linnakangas@i 632 : 0 : return false;
633 : : }
634 : :
4815 heikki.linnakangas@i 635 :CBC 4527 : return true;
636 : : }
637 : :
638 : : /*
639 : : * Random number seed
640 : : *
641 : : * 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
643 : : * commands to set it. We use the "extra" storage to ensure that rollbacks
644 : : * don't try to do the operation again.
645 : : */
646 : :
647 : : bool
4756 tgl@sss.pgh.pa.us 648 : 928 : check_random_seed(double *newval, void **extra, GucSource source)
649 : : {
548 650 : 928 : *extra = guc_malloc(LOG, sizeof(int));
4756 651 [ - + ]: 928 : if (!*extra)
4756 tgl@sss.pgh.pa.us 652 :UBC 0 : return false;
653 : : /* Arm the assign only if source of value is an interactive SET */
4756 tgl@sss.pgh.pa.us 654 :CBC 928 : *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
655 : :
8003 656 : 928 : return true;
657 : : }
658 : :
659 : : void
4756 660 : 928 : assign_random_seed(double newval, void *extra)
661 : : {
662 : : /* We'll do this at most once for any setting of the GUC variable */
663 [ - + ]: 928 : if (*((int *) extra))
4756 tgl@sss.pgh.pa.us 664 :UBC 0 : DirectFunctionCall1(setseed, Float8GetDatum(newval));
4756 tgl@sss.pgh.pa.us 665 :CBC 928 : *((int *) extra) = 0;
666 : 928 : }
667 : :
668 : : const char *
8003 tgl@sss.pgh.pa.us 669 :UBC 0 : show_random_seed(void)
670 : : {
671 : 0 : return "unavailable";
672 : : }
673 : :
674 : :
675 : : /*
676 : : * SET CLIENT_ENCODING
677 : : */
678 : :
679 : : bool
4756 tgl@sss.pgh.pa.us 680 :CBC 18309 : check_client_encoding(char **newval, void **extra, GucSource source)
681 : : {
682 : : int encoding;
683 : : const char *canonical_name;
684 : :
685 : : /* Look up the encoding by name */
686 : 18309 : encoding = pg_valid_client_encoding(*newval);
8572 687 [ - + ]: 18309 : if (encoding < 0)
4756 tgl@sss.pgh.pa.us 688 :UBC 0 : return false;
689 : :
690 : : /* Get the canonical name (no aliases, uniform case) */
4744 tgl@sss.pgh.pa.us 691 :CBC 18309 : canonical_name = pg_encoding_to_char(encoding);
692 : :
693 : : /*
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.
706 : : */
4756 707 [ - + ]: 18309 : if (PrepareClientEncoding(encoding) < 0)
708 : : {
4756 tgl@sss.pgh.pa.us 709 [ # # ]:UBC 0 : if (IsTransactionState())
710 : : {
711 : : /* Must be a genuine no-such-conversion problem */
712 : 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
713 : 0 : GUC_check_errdetail("Conversion between %s and %s is not supported.",
714 : : canonical_name,
715 : : GetDatabaseEncodingName());
716 : : }
717 : : else
718 : : {
719 : : /* Provide a useful complaint */
136 michael@paquier.xyz 720 :UNC 0 : GUC_check_errdetail("Cannot change client_encoding now.");
721 : : }
4756 tgl@sss.pgh.pa.us 722 :UBC 0 : return false;
723 : : }
724 : :
725 : : /*
726 : : * Replace the user-supplied string with the encoding's canonical name.
727 : : * 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 : : */
4744 tgl@sss.pgh.pa.us 735 [ + + ]:CBC 18309 : if (strcmp(*newval, canonical_name) != 0 &&
736 [ + - ]: 16 : strcmp(*newval, "UNICODE") != 0)
737 : : {
548 738 : 16 : guc_free(*newval);
739 : 16 : *newval = guc_strdup(LOG, canonical_name);
4744 740 [ - + ]: 16 : if (!*newval)
4744 tgl@sss.pgh.pa.us 741 :UBC 0 : return false;
742 : : }
743 : :
744 : : /*
745 : : * Save the encoding's ID in *extra, for use by assign_client_encoding.
746 : : */
548 tgl@sss.pgh.pa.us 747 :CBC 18309 : *extra = guc_malloc(LOG, sizeof(int));
4756 748 [ - + ]: 18309 : if (!*extra)
4756 tgl@sss.pgh.pa.us 749 :UBC 0 : return false;
4756 tgl@sss.pgh.pa.us 750 :CBC 18309 : *((int *) *extra) = encoding;
751 : :
752 : 18309 : return true;
753 : : }
754 : :
755 : : void
756 : 18211 : assign_client_encoding(const char *newval, void *extra)
757 : : {
758 : 18211 : 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 : : */
2845 rhaas@postgresql.org 764 [ + + ]: 18211 : if (IsParallelWorker())
765 : : {
766 : : /*
767 : : * 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 : : */
771 [ + - ]: 3966 : if (InitializingParallelWorker)
772 : 3966 : 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.
778 : : */
2845 rhaas@postgresql.org 779 [ # # ]:UBC 0 : ereport(ERROR,
780 : : (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 */
4756 tgl@sss.pgh.pa.us 785 [ - + ]:CBC 14245 : if (SetClientEncoding(encoding) < 0)
4756 tgl@sss.pgh.pa.us 786 [ # # ]:UBC 0 : elog(LOG, "SetClientEncoding(%d) failed", encoding);
787 : : }
788 : :
789 : :
790 : : /*
791 : : * SET SESSION AUTHORIZATION
792 : : */
793 : :
794 : : typedef struct
795 : : {
796 : : /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
797 : : Oid roleid;
798 : : bool is_superuser;
799 : : } role_auth_extra;
800 : :
801 : : bool
4756 tgl@sss.pgh.pa.us 802 :CBC 17606 : check_session_authorization(char **newval, void **extra, GucSource source)
803 : : {
804 : : HeapTuple roleTup;
805 : : Form_pg_authid roleform;
806 : : Oid roleid;
807 : : bool is_superuser;
808 : : role_auth_extra *myextra;
809 : :
810 : : /* Do nothing for the boot_val default of NULL */
811 [ + + ]: 17606 : if (*newval == NULL)
812 : 2250 : return true;
813 : :
814 [ - + ]: 15356 : if (!IsTransactionState())
815 : : {
816 : : /*
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 : : */
4756 tgl@sss.pgh.pa.us 821 :UBC 0 : return false;
822 : : }
823 : :
824 : : /*
825 : : * When source == PGC_S_TEST, we don't throw a hard error for a
826 : : * nonexistent user name or insufficient privileges, only a NOTICE. See
827 : : * comments in guc.h.
828 : : */
829 : :
830 : : /* Look up the username */
4756 tgl@sss.pgh.pa.us 831 :CBC 15356 : roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
832 [ - + ]: 15356 : if (!HeapTupleIsValid(roleTup))
833 : : {
1097 tgl@sss.pgh.pa.us 834 [ # # ]:UBC 0 : if (source == PGC_S_TEST)
835 : : {
836 [ # # ]: 0 : ereport(NOTICE,
837 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
838 : : errmsg("role \"%s\" does not exist", *newval)));
839 : 0 : return true;
840 : : }
4756 841 : 0 : GUC_check_errmsg("role \"%s\" does not exist", *newval);
842 : 0 : return false;
843 : : }
844 : :
1972 andres@anarazel.de 845 :CBC 15356 : roleform = (Form_pg_authid) GETSTRUCT(roleTup);
846 : 15356 : roleid = roleform->oid;
847 : 15356 : is_superuser = roleform->rolsuper;
848 : :
4756 tgl@sss.pgh.pa.us 849 : 15356 : ReleaseSysCache(roleTup);
850 : :
851 : : /*
852 : : * Only superusers may SET SESSION AUTHORIZATION a role other than itself.
853 : : * Note that in case of multiple SETs in a single session, the original
854 : : * authenticated user's superuserness is what matters.
855 : : */
276 nathan@postgresql.or 856 [ + + ]:GNC 15356 : if (roleid != GetAuthenticatedUserId() &&
857 [ - + ]: 1247 : !superuser_arg(GetAuthenticatedUserId()))
858 : : {
276 nathan@postgresql.or 859 [ # # ]:UNC 0 : if (source == PGC_S_TEST)
860 : : {
861 [ # # ]: 0 : ereport(NOTICE,
862 : : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
863 : : errmsg("permission will be denied to set session authorization \"%s\"",
864 : : *newval)));
865 : 0 : return true;
866 : : }
867 : 0 : GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
868 : 0 : GUC_check_errmsg("permission denied to set session authorization \"%s\"",
869 : : *newval);
870 : 0 : return false;
871 : : }
872 : :
873 : : /* Set up "extra" struct for assign_session_authorization to use */
548 tgl@sss.pgh.pa.us 874 :CBC 15356 : myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
4756 875 [ - + ]: 15356 : if (!myextra)
4756 tgl@sss.pgh.pa.us 876 :UBC 0 : return false;
4756 tgl@sss.pgh.pa.us 877 :CBC 15356 : myextra->roleid = roleid;
878 : 15356 : myextra->is_superuser = is_superuser;
879 : 15356 : *extra = (void *) myextra;
880 : :
881 : 15356 : return true;
882 : : }
883 : :
884 : : void
885 : 18041 : assign_session_authorization(const char *newval, void *extra)
886 : : {
887 : 18041 : role_auth_extra *myextra = (role_auth_extra *) extra;
888 : :
889 : : /* Do nothing for the boot_val default of NULL */
890 [ + + ]: 18041 : if (!myextra)
891 : 2250 : return;
892 : :
893 : 15791 : SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
894 : : }
895 : :
896 : :
897 : : /*
898 : : * SET ROLE
899 : : *
900 : : * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
901 : : * a translation of "none" to InvalidOid. Otherwise this is much like
902 : : * SET SESSION AUTHORIZATION.
903 : : */
904 : : extern char *role_string; /* in guc_tables.c */
905 : :
906 : : bool
907 : 1345 : check_role(char **newval, void **extra, GucSource source)
908 : : {
909 : : HeapTuple roleTup;
910 : : Oid roleid;
911 : : bool is_superuser;
912 : : role_auth_extra *myextra;
913 : : Form_pg_authid roleform;
914 : :
915 [ + + ]: 1345 : if (strcmp(*newval, "none") == 0)
916 : : {
917 : : /* hardwired translation */
918 : 928 : roleid = InvalidOid;
919 : 928 : is_superuser = false;
920 : : }
921 : : else
922 : : {
6838 923 [ - + ]: 417 : if (!IsTransactionState())
924 : : {
925 : : /*
926 : : * Can't do catalog lookups, so fail. The result of this is that
927 : : * role cannot be set in postgresql.conf, which seems like a good
928 : : * thing anyway, so we don't work hard to avoid it.
929 : : */
4756 tgl@sss.pgh.pa.us 930 :UBC 0 : return false;
931 : : }
932 : :
933 : : /*
934 : : * When source == PGC_S_TEST, we don't throw a hard error for a
935 : : * nonexistent user name or insufficient privileges, only a NOTICE.
936 : : * See comments in guc.h.
937 : : */
938 : :
939 : : /* Look up the username */
4756 tgl@sss.pgh.pa.us 940 :CBC 417 : roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
6838 941 [ - + ]: 417 : if (!HeapTupleIsValid(roleTup))
942 : : {
1097 tgl@sss.pgh.pa.us 943 [ # # ]:UBC 0 : if (source == PGC_S_TEST)
944 : : {
945 [ # # ]: 0 : ereport(NOTICE,
946 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
947 : : errmsg("role \"%s\" does not exist", *newval)));
948 : 0 : return true;
949 : : }
4756 950 : 0 : GUC_check_errmsg("role \"%s\" does not exist", *newval);
951 : 0 : return false;
952 : : }
953 : :
1972 andres@anarazel.de 954 :CBC 417 : roleform = (Form_pg_authid) GETSTRUCT(roleTup);
955 : 417 : roleid = roleform->oid;
956 : 417 : is_superuser = roleform->rolsuper;
957 : :
6838 tgl@sss.pgh.pa.us 958 : 417 : ReleaseSysCache(roleTup);
959 : :
960 : : /*
961 : : * Verify that session user is allowed to become this role, but skip
962 : : * this in parallel mode, where we must blindly recreate the parallel
963 : : * leader's state.
964 : : */
3103 rhaas@postgresql.org 965 [ + - ]: 417 : if (!InitializingParallelWorker &&
513 966 [ + + ]: 417 : !member_can_set_role(GetSessionUserId(), roleid))
967 : : {
1097 tgl@sss.pgh.pa.us 968 [ - + ]: 6 : if (source == PGC_S_TEST)
969 : : {
1097 tgl@sss.pgh.pa.us 970 [ # # ]:UBC 0 : ereport(NOTICE,
971 : : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
972 : : errmsg("permission will be denied to set role \"%s\"",
973 : : *newval)));
974 : 0 : return true;
975 : : }
4756 tgl@sss.pgh.pa.us 976 :CBC 6 : GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
977 : 6 : GUC_check_errmsg("permission denied to set role \"%s\"",
978 : : *newval);
979 : 6 : return false;
980 : : }
981 : : }
982 : :
983 : : /* Set up "extra" struct for assign_role to use */
548 984 : 1339 : myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
4756 985 [ - + ]: 1339 : if (!myextra)
4756 tgl@sss.pgh.pa.us 986 :UBC 0 : return false;
4756 tgl@sss.pgh.pa.us 987 :CBC 1339 : myextra->roleid = roleid;
988 : 1339 : myextra->is_superuser = is_superuser;
989 : 1339 : *extra = (void *) myextra;
990 : :
991 : 1339 : return true;
992 : : }
993 : :
994 : : void
995 : 1639 : assign_role(const char *newval, void *extra)
996 : : {
997 : 1639 : role_auth_extra *myextra = (role_auth_extra *) extra;
998 : :
999 : 1639 : SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
6838 1000 : 1639 : }
1001 : :
1002 : : const char *
6838 tgl@sss.pgh.pa.us 1003 :UBC 0 : show_role(void)
1004 : : {
1005 : : /*
1006 : : * Check whether SET ROLE is active; if not return "none". This is a
1007 : : * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
1008 : : * resets SET ROLE to NONE, but we cannot set the GUC role variable from
1009 : : * assign_session_authorization (because we haven't got enough info to
1010 : : * call set_config_option).
1011 : : */
4756 1012 [ # # ]: 0 : if (!OidIsValid(GetCurrentRoleId()))
6838 1013 : 0 : return "none";
1014 : :
1015 : : /* Otherwise we can just use the GUC string */
4756 1016 [ # # ]: 0 : return role_string ? role_string : "none";
1017 : : }
1018 : :
1019 : :
1020 : : /*
1021 : : * PATH VARIABLES
1022 : : *
1023 : : * check_canonical_path is used for log_directory and some other GUCs where
1024 : : * all we want to do is canonicalize the represented path name.
1025 : : */
1026 : :
1027 : : bool
579 tgl@sss.pgh.pa.us 1028 :CBC 1856 : check_canonical_path(char **newval, void **extra, GucSource source)
1029 : : {
1030 : : /*
1031 : : * Since canonicalize_path never enlarges the string, we can just modify
1032 : : * newval in-place. But watch out for NULL, which is the default value
1033 : : * for external_pid_file.
1034 : : */
1035 [ + + ]: 1856 : if (*newval)
1036 : 928 : canonicalize_path(*newval);
1037 : 1856 : return true;
1038 : : }
1039 : :
1040 : :
1041 : : /*
1042 : : * MISCELLANEOUS
1043 : : */
1044 : :
1045 : : /*
1046 : : * GUC check_hook for application_name
1047 : : */
1048 : : bool
1049 : 13713 : check_application_name(char **newval, void **extra, GucSource source)
1050 : : {
1051 : : char *clean;
1052 : : char *ret;
1053 : :
1054 : : /* Only allow clean ASCII chars in the application name */
1055 : 13713 : clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1056 [ - + ]: 13713 : if (!clean)
579 tgl@sss.pgh.pa.us 1057 :UBC 0 : return false;
1058 : :
561 peter@eisentraut.org 1059 :CBC 13713 : ret = guc_strdup(WARNING, clean);
1060 [ - + ]: 13713 : if (!ret)
1061 : : {
561 peter@eisentraut.org 1062 :UBC 0 : pfree(clean);
579 tgl@sss.pgh.pa.us 1063 : 0 : return false;
1064 : : }
1065 : :
561 peter@eisentraut.org 1066 :CBC 13713 : pfree(clean);
1067 : 13713 : *newval = ret;
579 tgl@sss.pgh.pa.us 1068 : 13713 : return true;
1069 : : }
1070 : :
1071 : : /*
1072 : : * GUC assign_hook for application_name
1073 : : */
1074 : : void
1075 : 13699 : assign_application_name(const char *newval, void *extra)
1076 : : {
1077 : : /* Update the pg_stat_activity view */
1078 : 13699 : pgstat_report_appname(newval);
1079 : 13699 : }
1080 : :
1081 : : /*
1082 : : * GUC check_hook for cluster_name
1083 : : */
1084 : : bool
1085 : 1534 : check_cluster_name(char **newval, void **extra, GucSource source)
1086 : : {
1087 : : char *clean;
1088 : : char *ret;
1089 : :
1090 : : /* Only allow clean ASCII chars in the cluster name */
1091 : 1534 : clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1092 [ - + ]: 1534 : if (!clean)
579 tgl@sss.pgh.pa.us 1093 :UBC 0 : return false;
1094 : :
561 peter@eisentraut.org 1095 :CBC 1534 : ret = guc_strdup(WARNING, clean);
1096 [ - + ]: 1534 : if (!ret)
1097 : : {
561 peter@eisentraut.org 1098 :UBC 0 : pfree(clean);
579 tgl@sss.pgh.pa.us 1099 : 0 : return false;
1100 : : }
1101 : :
561 peter@eisentraut.org 1102 :CBC 1534 : pfree(clean);
1103 : 1534 : *newval = ret;
579 tgl@sss.pgh.pa.us 1104 : 1534 : return true;
1105 : : }
1106 : :
1107 : : /*
1108 : : * GUC assign_hook for maintenance_io_concurrency
1109 : : */
1110 : : void
1111 : 928 : assign_maintenance_io_concurrency(int newval, void *extra)
1112 : : {
1113 : : #ifdef USE_PREFETCH
1114 : : /*
1115 : : * Reconfigure recovery prefetching, because a setting it depends on
1116 : : * changed.
1117 : : */
1118 : 928 : maintenance_io_concurrency = newval;
1119 [ - + ]: 928 : if (AmStartupProcess())
579 tgl@sss.pgh.pa.us 1120 :UBC 0 : XLogPrefetchReconfigure();
1121 : : #endif
579 tgl@sss.pgh.pa.us 1122 :CBC 928 : }
1123 : :
1124 : :
1125 : : /*
1126 : : * These show hooks just exist because we want to show the values in octal.
1127 : : */
1128 : :
1129 : : /*
1130 : : * GUC show_hook for data_directory_mode
1131 : : */
1132 : : const char *
1133 : 2234 : show_data_directory_mode(void)
1134 : : {
1135 : : static char buf[12];
1136 : :
1137 : 2234 : snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
1138 : 2234 : return buf;
1139 : : }
1140 : :
1141 : : /*
1142 : : * GUC show_hook for log_file_mode
1143 : : */
1144 : : const char *
1145 : 1892 : show_log_file_mode(void)
1146 : : {
1147 : : static char buf[12];
1148 : :
1149 : 1892 : snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
1150 : 1892 : return buf;
1151 : : }
1152 : :
1153 : : /*
1154 : : * GUC show_hook for unix_socket_permissions
1155 : : */
1156 : : const char *
1157 : 1892 : show_unix_socket_permissions(void)
1158 : : {
1159 : : static char buf[12];
1160 : :
1161 : 1892 : snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
1162 : 1892 : return buf;
1163 : : }
1164 : :
1165 : :
1166 : : /*
1167 : : * These check hooks do nothing more than reject non-default settings
1168 : : * in builds that don't support them.
1169 : : */
1170 : :
1171 : : bool
1172 : 928 : check_bonjour(bool *newval, void **extra, GucSource source)
1173 : : {
1174 : : #ifndef USE_BONJOUR
1175 [ - + ]: 928 : if (*newval)
1176 : : {
579 tgl@sss.pgh.pa.us 1177 :UBC 0 : GUC_check_errmsg("Bonjour is not supported by this build");
1178 : 0 : return false;
1179 : : }
1180 : : #endif
579 tgl@sss.pgh.pa.us 1181 :CBC 928 : return true;
1182 : : }
1183 : :
1184 : : bool
1185 : 934 : check_default_with_oids(bool *newval, void **extra, GucSource source)
1186 : : {
1187 [ + + ]: 934 : if (*newval)
1188 : : {
1189 : : /* check the GUC's definition for an explanation */
1190 : 3 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
1191 : 3 : GUC_check_errmsg("tables declared WITH OIDS are not supported");
1192 : :
1193 : 3 : return false;
1194 : : }
1195 : :
1196 : 931 : return true;
1197 : : }
1198 : :
1199 : : bool
1200 : 1225 : check_effective_io_concurrency(int *newval, void **extra, GucSource source)
1201 : : {
1202 : : #ifndef USE_PREFETCH
1203 : : if (*newval != 0)
1204 : : {
1205 : : GUC_check_errdetail("effective_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
1206 : : return false;
1207 : : }
1208 : : #endif /* USE_PREFETCH */
1209 : 1225 : return true;
1210 : : }
1211 : :
1212 : : bool
1213 : 928 : check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
1214 : : {
1215 : : #ifndef USE_PREFETCH
1216 : : if (*newval != 0)
1217 : : {
1218 : : GUC_check_errdetail("maintenance_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
1219 : : return false;
1220 : : }
1221 : : #endif /* USE_PREFETCH */
1222 : 928 : return true;
1223 : : }
1224 : :
1225 : : bool
1226 : 979 : check_ssl(bool *newval, void **extra, GucSource source)
1227 : : {
1228 : : #ifndef USE_SSL
1229 : : if (*newval)
1230 : : {
1231 : : GUC_check_errmsg("SSL is not supported by this build");
1232 : : return false;
1233 : : }
1234 : : #endif
1235 : 979 : return true;
1236 : : }
|