LCOV - code coverage report
Current view: top level - src/backend/commands - variable.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 301 441 68.3 %
Date: 2025-01-18 04:15:08 Functions: 35 36 97.2 %
Legend: Lines: hit not hit

          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
      52       24494 : check_datestyle(char **newval, void **extra, GucSource source)
      53             : {
      54       24494 :     int         newDateStyle = DateStyle;
      55       24494 :     int         newDateOrder = DateOrder;
      56       24494 :     bool        have_style = false;
      57       24494 :     bool        have_order = false;
      58       24494 :     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 */
      66       24494 :     rawstring = pstrdup(*newval);
      67             : 
      68             :     /* Parse string into list of identifiers */
      69       24494 :     if (!SplitIdentifierString(rawstring, ',', &elemlist))
      70             :     {
      71             :         /* syntax error in list */
      72           0 :         GUC_check_errdetail("List syntax is invalid.");
      73           0 :         pfree(rawstring);
      74           0 :         list_free(elemlist);
      75           0 :         return false;
      76             :     }
      77             : 
      78       63584 :     foreach(l, elemlist)
      79             :     {
      80       39090 :         char       *tok = (char *) lfirst(l);
      81             : 
      82             :         /* Ugh. Somebody ought to write a table driven version -- mjl */
      83             : 
      84       39090 :         if (pg_strcasecmp(tok, "ISO") == 0)
      85             :         {
      86       17144 :             if (have_style && newDateStyle != USE_ISO_DATES)
      87           0 :                 ok = false;     /* conflicting styles */
      88       17144 :             newDateStyle = USE_ISO_DATES;
      89       17144 :             have_style = true;
      90             :         }
      91       21946 :         else if (pg_strcasecmp(tok, "SQL") == 0)
      92             :         {
      93          30 :             if (have_style && newDateStyle != USE_SQL_DATES)
      94           0 :                 ok = false;     /* conflicting styles */
      95          30 :             newDateStyle = USE_SQL_DATES;
      96          30 :             have_style = true;
      97             :         }
      98       21916 :         else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
      99             :         {
     100        7222 :             if (have_style && newDateStyle != USE_POSTGRES_DATES)
     101           0 :                 ok = false;     /* conflicting styles */
     102        7222 :             newDateStyle = USE_POSTGRES_DATES;
     103        7222 :             have_style = true;
     104             :         }
     105       14694 :         else if (pg_strcasecmp(tok, "GERMAN") == 0)
     106             :         {
     107          48 :             if (have_style && newDateStyle != USE_GERMAN_DATES)
     108           0 :                 ok = false;     /* conflicting styles */
     109          48 :             newDateStyle = USE_GERMAN_DATES;
     110          48 :             have_style = true;
     111             :             /* GERMAN also sets DMY, unless explicitly overridden */
     112          48 :             if (!have_order)
     113          48 :                 newDateOrder = DATEORDER_DMY;
     114             :         }
     115       14646 :         else if (pg_strcasecmp(tok, "YMD") == 0)
     116             :         {
     117          42 :             if (have_order && newDateOrder != DATEORDER_YMD)
     118           0 :                 ok = false;     /* conflicting orders */
     119          42 :             newDateOrder = DATEORDER_YMD;
     120          42 :             have_order = true;
     121             :         }
     122       29160 :         else if (pg_strcasecmp(tok, "DMY") == 0 ||
     123       14556 :                  pg_strncasecmp(tok, "EURO", 4) == 0)
     124             :         {
     125          66 :             if (have_order && newDateOrder != DATEORDER_DMY)
     126           0 :                 ok = false;     /* conflicting orders */
     127          66 :             newDateOrder = DATEORDER_DMY;
     128          66 :             have_order = true;
     129             :         }
     130       14556 :         else if (pg_strcasecmp(tok, "MDY") == 0 ||
     131          18 :                  pg_strcasecmp(tok, "US") == 0 ||
     132           0 :                  pg_strncasecmp(tok, "NONEURO", 7) == 0)
     133             :         {
     134       14538 :             if (have_order && newDateOrder != DATEORDER_MDY)
     135           0 :                 ok = false;     /* conflicting orders */
     136       14538 :             newDateOrder = DATEORDER_MDY;
     137       14538 :             have_order = true;
     138             :         }
     139           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;
     149           0 :             void       *subextra = NULL;
     150             : 
     151           0 :             subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
     152           0 :             if (!subval)
     153             :             {
     154           0 :                 ok = false;
     155           0 :                 break;
     156             :             }
     157           0 :             if (!check_datestyle(&subval, &subextra, source))
     158             :             {
     159           0 :                 guc_free(subval);
     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];
     168           0 :             guc_free(subval);
     169           0 :             guc_free(subextra);
     170             :         }
     171             :         else
     172             :         {
     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             : 
     180       24494 :     pfree(rawstring);
     181       24494 :     list_free(elemlist);
     182             : 
     183       24494 :     if (!ok)
     184             :     {
     185           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             :      */
     192       24494 :     result = (char *) guc_malloc(LOG, 32);
     193       24494 :     if (!result)
     194           0 :         return false;
     195             : 
     196       24494 :     switch (newDateStyle)
     197             :     {
     198       17168 :         case USE_ISO_DATES:
     199       17168 :             strcpy(result, "ISO");
     200       17168 :             break;
     201          30 :         case USE_SQL_DATES:
     202          30 :             strcpy(result, "SQL");
     203          30 :             break;
     204          48 :         case USE_GERMAN_DATES:
     205          48 :             strcpy(result, "German");
     206          48 :             break;
     207        7248 :         default:
     208        7248 :             strcpy(result, "Postgres");
     209        7248 :             break;
     210             :     }
     211       24494 :     switch (newDateOrder)
     212             :     {
     213          54 :         case DATEORDER_YMD:
     214          54 :             strcat(result, ", YMD");
     215          54 :             break;
     216          94 :         case DATEORDER_DMY:
     217          94 :             strcat(result, ", DMY");
     218          94 :             break;
     219       24346 :         default:
     220       24346 :             strcat(result, ", MDY");
     221       24346 :             break;
     222             :     }
     223             : 
     224       24494 :     guc_free(*newval);
     225       24494 :     *newval = result;
     226             : 
     227             :     /*
     228             :      * Set up the "extra" struct actually used by assign_datestyle.
     229             :      */
     230       24494 :     myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
     231       24494 :     if (!myextra)
     232           0 :         return false;
     233       24494 :     myextra[0] = newDateStyle;
     234       24494 :     myextra[1] = newDateOrder;
     235       24494 :     *extra = myextra;
     236             : 
     237       24494 :     return true;
     238             : }
     239             : 
     240             : /*
     241             :  * assign_datestyle: GUC assign_hook for datestyle
     242             :  */
     243             : void
     244       32742 : assign_datestyle(const char *newval, void *extra)
     245             : {
     246       32742 :     int        *myextra = (int *) extra;
     247             : 
     248       32742 :     DateStyle = myextra[0];
     249       32742 :     DateOrder = myextra[1];
     250       32742 : }
     251             : 
     252             : 
     253             : /*
     254             :  * TIMEZONE
     255             :  */
     256             : 
     257             : /*
     258             :  * check_timezone: GUC check_hook for timezone
     259             :  */
     260             : bool
     261       14682 : 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       14682 :     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             :          */
     274           0 :         const char *valueptr = *newval;
     275             :         char       *val;
     276             :         Interval   *interval;
     277             : 
     278           0 :         valueptr += 8;
     279           0 :         while (isspace((unsigned char) *valueptr))
     280           0 :             valueptr++;
     281           0 :         if (*valueptr++ != '\'')
     282           0 :             return false;
     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);
     289           0 :             return false;
     290             :         }
     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             :         {
     307           0 :             GUC_check_errdetail("Cannot specify months in time zone interval.");
     308           0 :             pfree(interval);
     309           0 :             return false;
     310             :         }
     311           0 :         if (interval->day != 0)
     312             :         {
     313           0 :             GUC_check_errdetail("Cannot specify days in time zone interval.");
     314           0 :             pfree(interval);
     315           0 :             return false;
     316             :         }
     317             : 
     318             :         /* Here we change from SQL to Unix sign convention */
     319           0 :         gmtoffset = -(interval->time / USECS_PER_SEC);
     320           0 :         new_tz = pg_tzset_offset(gmtoffset);
     321             : 
     322           0 :         pfree(interval);
     323             :     }
     324             :     else
     325             :     {
     326             :         /*
     327             :          * Try it as a numeric number of hours (possibly fractional).
     328             :          */
     329       14682 :         hours = strtod(*newval, &endptr);
     330       14682 :         if (endptr != *newval && *endptr == '\0')
     331             :         {
     332             :             /* Here we change from SQL to Unix sign convention */
     333          72 :             gmtoffset = -hours * SECS_PER_HOUR;
     334          72 :             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             :              */
     341       14610 :             new_tz = pg_tzset(*newval);
     342             : 
     343       14610 :             if (!new_tz)
     344             :             {
     345             :                 /* Doesn't seem to be any great value in errdetail here */
     346           0 :                 return false;
     347             :             }
     348             : 
     349       14610 :             if (!pg_tz_acceptable(new_tz))
     350             :             {
     351           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 */
     360       14682 :     if (!new_tz)
     361             :     {
     362           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             :      */
     369       14682 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     370       14682 :     if (!*extra)
     371           0 :         return false;
     372       14682 :     *((pg_tz **) *extra) = new_tz;
     373             : 
     374       14682 :     return true;
     375             : }
     376             : 
     377             : /*
     378             :  * assign_timezone: GUC assign_hook for timezone
     379             :  */
     380             : void
     381       14806 : assign_timezone(const char *newval, void *extra)
     382             : {
     383       14806 :     session_timezone = *((pg_tz **) extra);
     384             :     /* datetime.c's cache of timezone abbrevs may now be obsolete */
     385       14806 :     ClearTimeZoneAbbrevCache();
     386       14806 : }
     387             : 
     388             : /*
     389             :  * show_timezone: GUC show_hook for timezone
     390             :  */
     391             : const char *
     392       49140 : show_timezone(void)
     393             : {
     394             :     const char *tzn;
     395             : 
     396             :     /* Always show the zone's canonical name */
     397       49140 :     tzn = pg_get_timezone_name(session_timezone);
     398             : 
     399       49140 :     if (tzn != NULL)
     400       49140 :         return tzn;
     401             : 
     402           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
     418        9984 : 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        9984 :     new_tz = pg_tzset(*newval);
     426             : 
     427        9984 :     if (!new_tz)
     428             :     {
     429             :         /* Doesn't seem to be any great value in errdetail here */
     430           0 :         return false;
     431             :     }
     432             : 
     433        9984 :     if (!pg_tz_acceptable(new_tz))
     434             :     {
     435           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             :      */
     444        9984 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     445        9984 :     if (!*extra)
     446           0 :         return false;
     447        9984 :     *((pg_tz **) *extra) = new_tz;
     448             : 
     449        9984 :     return true;
     450             : }
     451             : 
     452             : /*
     453             :  * assign_log_timezone: GUC assign_hook for log_timezone
     454             :  */
     455             : void
     456        9978 : assign_log_timezone(const char *newval, void *extra)
     457             : {
     458        9978 :     log_timezone = *((pg_tz **) extra);
     459        9978 : }
     460             : 
     461             : /*
     462             :  * show_log_timezone: GUC show_hook for log_timezone
     463             :  */
     464             : const char *
     465        3408 : show_log_timezone(void)
     466             : {
     467             :     const char *tzn;
     468             : 
     469             :     /* Always show the zone's canonical name */
     470        3408 :     tzn = pg_get_timezone_name(log_timezone);
     471             : 
     472        3408 :     if (tzn != NULL)
     473        3408 :         return tzn;
     474             : 
     475           0 :     return "unknown";
     476             : }
     477             : 
     478             : 
     479             : /*
     480             :  * TIMEZONE_ABBREVIATIONS
     481             :  */
     482             : 
     483             : /*
     484             :  * GUC check_hook for timezone_abbreviations
     485             :  */
     486             : bool
     487       16978 : 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       16978 :     if (*newval == NULL)
     500             :     {
     501             :         Assert(source == PGC_S_DEFAULT);
     502        4694 :         return true;
     503             :     }
     504             : 
     505             :     /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
     506       12284 :     *extra = load_tzoffsets(*newval);
     507             : 
     508             :     /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
     509       12284 :     if (!*extra)
     510           0 :         return false;
     511             : 
     512       12284 :     return true;
     513             : }
     514             : 
     515             : /*
     516             :  * GUC assign_hook for timezone_abbreviations
     517             :  */
     518             : void
     519       16790 : assign_timezone_abbreviations(const char *newval, void *extra)
     520             : {
     521             :     /* Do nothing for the boot_val default of NULL */
     522       16790 :     if (!extra)
     523        4694 :         return;
     524             : 
     525       12096 :     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
     546       10790 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
     547             : {
     548       10790 :     if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
     549             :     {
     550             :         /* Can't go to r/w mode inside a r/o transaction */
     551          64 :         if (IsSubTransaction())
     552             :         {
     553          12 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     554          12 :             GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
     555          12 :             return false;
     556             :         }
     557             :         /* Top level transaction can't change to r/w after first snapshot. */
     558          52 :         if (FirstSnapshotSet)
     559             :         {
     560           6 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     561           6 :             GUC_check_errmsg("transaction read-write mode must be set before any query");
     562           6 :             return false;
     563             :         }
     564             :         /* Can't go to r/w mode while recovery is still active */
     565          46 :         if (RecoveryInProgress())
     566             :         {
     567           0 :             GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     568           0 :             GUC_check_errmsg("cannot set transaction read-write mode during recovery");
     569           0 :             return false;
     570             :         }
     571             :     }
     572             : 
     573       10772 :     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
     586       16042 : check_transaction_isolation(int *newval, void **extra, GucSource source)
     587             : {
     588       16042 :     int         newXactIsoLevel = *newval;
     589             : 
     590       21868 :     if (newXactIsoLevel != XactIsoLevel &&
     591       11652 :         IsTransactionState() && !InitializingParallelWorker)
     592             :     {
     593        5746 :         if (FirstSnapshotSet)
     594             :         {
     595           2 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     596           2 :             GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
     597           2 :             return false;
     598             :         }
     599             :         /* We ignore a subtransaction setting it to the existing value. */
     600        5744 :         if (IsSubTransaction())
     601             :         {
     602           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 */
     607        5744 :         if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
     608             :         {
     609           0 :             GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     610           0 :             GUC_check_errmsg("cannot use serializable mode in a hot standby");
     611           0 :             GUC_check_errhint("You can use REPEATABLE READ instead.");
     612           0 :             return false;
     613             :         }
     614             :     }
     615             : 
     616       16040 :     return true;
     617             : }
     618             : 
     619             : /*
     620             :  * SET TRANSACTION [NOT] DEFERRABLE
     621             :  */
     622             : 
     623             : bool
     624        9442 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
     625             : {
     626             :     /* Just accept the value when restoring state in a parallel worker */
     627        9442 :     if (InitializingParallelWorker)
     628        5424 :         return true;
     629             : 
     630        4018 :     if (IsSubTransaction())
     631             :     {
     632           0 :         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     633           0 :         GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
     634           0 :         return false;
     635             :     }
     636        4018 :     if (FirstSnapshotSet)
     637             :     {
     638           0 :         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     639           0 :         GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
     640           0 :         return false;
     641             :     }
     642             : 
     643        4018 :     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
     656        1982 : check_random_seed(double *newval, void **extra, GucSource source)
     657             : {
     658        1982 :     *extra = guc_malloc(LOG, sizeof(int));
     659        1982 :     if (!*extra)
     660           0 :         return false;
     661             :     /* Arm the assign only if source of value is an interactive SET */
     662        1982 :     *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
     663             : 
     664        1982 :     return true;
     665             : }
     666             : 
     667             : void
     668        1982 : assign_random_seed(double newval, void *extra)
     669             : {
     670             :     /* We'll do this at most once for any setting of the GUC variable */
     671        1982 :     if (*((int *) extra))
     672           0 :         DirectFunctionCall1(setseed, Float8GetDatum(newval));
     673        1982 :     *((int *) extra) = 0;
     674        1982 : }
     675             : 
     676             : const char *
     677           0 : show_random_seed(void)
     678             : {
     679           0 :     return "unavailable";
     680             : }
     681             : 
     682             : 
     683             : /*
     684             :  * SET CLIENT_ENCODING
     685             :  */
     686             : 
     687             : bool
     688       37468 : 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       37468 :     encoding = pg_valid_client_encoding(*newval);
     695       37468 :     if (encoding < 0)
     696           0 :         return false;
     697             : 
     698             :     /* Get the canonical name (no aliases, uniform case) */
     699       37468 :     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             :      */
     712       37468 :     if (IsParallelWorker() && !InitializingParallelWorker)
     713             :     {
     714           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             :      */
     736       66800 :     if (!IsParallelWorker() &&
     737       29332 :         PrepareClientEncoding(encoding) < 0)
     738             :     {
     739           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 */
     750           0 :             GUC_check_errdetail("Cannot change \"client_encoding\" now.");
     751             :         }
     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             :      */
     765       37468 :     if (strcmp(*newval, canonical_name) != 0 &&
     766          58 :         strcmp(*newval, "UNICODE") != 0)
     767             :     {
     768          58 :         guc_free(*newval);
     769          58 :         *newval = guc_strdup(LOG, canonical_name);
     770          58 :         if (!*newval)
     771           0 :             return false;
     772             :     }
     773             : 
     774             :     /*
     775             :      * Save the encoding's ID in *extra, for use by assign_client_encoding.
     776             :      */
     777       37468 :     *extra = guc_malloc(LOG, sizeof(int));
     778       37468 :     if (!*extra)
     779           0 :         return false;
     780       37468 :     *((int *) *extra) = encoding;
     781             : 
     782       37468 :     return true;
     783             : }
     784             : 
     785             : void
     786       37292 : assign_client_encoding(const char *newval, void *extra)
     787             : {
     788       37292 :     int         encoding = *((int *) extra);
     789             : 
     790             :     /*
     791             :      * In a parallel worker, we never override the client encoding that was
     792             :      * set by ParallelWorkerMain().
     793             :      */
     794       37292 :     if (IsParallelWorker())
     795        8136 :         return;
     796             : 
     797             :     /* We do not expect an error if PrepareClientEncoding succeeded */
     798       29156 :     if (SetClientEncoding(encoding) < 0)
     799           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
     815       30622 : 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       30622 :     if (*newval == NULL)
     825        1982 :         return true;
     826             : 
     827       28640 :     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        2712 :         roleid = GetSessionUserId();
     835        2712 :         is_superuser = GetSessionUserIsSuperuser();
     836             :     }
     837             :     else
     838             :     {
     839       25928 :         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             :              */
     847           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 */
     857       25928 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     858       25928 :         if (!HeapTupleIsValid(roleTup))
     859             :         {
     860           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             : 
     871       25928 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     872       25928 :         roleid = roleform->oid;
     873       25928 :         is_superuser = roleform->rolsuper;
     874             : 
     875       25928 :         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       25928 :         if (roleid != GetAuthenticatedUserId() &&
     883        2554 :             !superuser_arg(GetAuthenticatedUserId()))
     884             :         {
     885           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 */
     901       28640 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
     902       28640 :     if (!myextra)
     903           0 :         return false;
     904       28640 :     myextra->roleid = roleid;
     905       28640 :     myextra->is_superuser = is_superuser;
     906       28640 :     *extra = myextra;
     907             : 
     908       28640 :     return true;
     909             : }
     910             : 
     911             : void
     912       31516 : assign_session_authorization(const char *newval, void *extra)
     913             : {
     914       31516 :     role_auth_extra *myextra = (role_auth_extra *) extra;
     915             : 
     916             :     /* Do nothing for the boot_val default of NULL */
     917       31516 :     if (!myextra)
     918        1982 :         return;
     919             : 
     920       29534 :     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       31590 : 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       31590 :     if (strcmp(*newval, "none") == 0)
     942             :     {
     943             :         /* hardwired translation */
     944       30602 :         roleid = InvalidOid;
     945       30602 :         is_superuser = false;
     946             :     }
     947         988 :     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          12 :         roleid = GetCurrentRoleId();
     955          12 :         is_superuser = current_role_is_superuser;
     956             :     }
     957             :     else
     958             :     {
     959         976 :         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             :              */
     966           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 */
     976         976 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     977         976 :         if (!HeapTupleIsValid(roleTup))
     978             :         {
     979           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             :             }
     986           0 :             GUC_check_errmsg("role \"%s\" does not exist", *newval);
     987           0 :             return false;
     988             :         }
     989             : 
     990         976 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     991         976 :         roleid = roleform->oid;
     992         976 :         is_superuser = roleform->rolsuper;
     993             : 
     994         976 :         ReleaseSysCache(roleTup);
     995             : 
     996             :         /* Verify that session user is allowed to become this role */
     997         976 :         if (!member_can_set_role(GetSessionUserId(), roleid))
     998             :         {
     999          12 :             if (source == PGC_S_TEST)
    1000             :             {
    1001           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             :             }
    1007          12 :             GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
    1008          12 :             GUC_check_errmsg("permission denied to set role \"%s\"",
    1009             :                              *newval);
    1010          12 :             return false;
    1011             :         }
    1012             :     }
    1013             : 
    1014             :     /* Set up "extra" struct for assign_role to use */
    1015       31578 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
    1016       31578 :     if (!myextra)
    1017           0 :         return false;
    1018       31578 :     myextra->roleid = roleid;
    1019       31578 :     myextra->is_superuser = is_superuser;
    1020       31578 :     *extra = myextra;
    1021             : 
    1022       31578 :     return true;
    1023             : }
    1024             : 
    1025             : void
    1026       33136 : assign_role(const char *newval, void *extra)
    1027             : {
    1028       33136 :     role_auth_extra *myextra = (role_auth_extra *) extra;
    1029             : 
    1030       33136 :     SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
    1031       33136 : }
    1032             : 
    1033             : const char *
    1034          60 : 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             :      */
    1043          60 :     if (!OidIsValid(GetCurrentRoleId()))
    1044          24 :         return "none";
    1045             : 
    1046             :     /* Otherwise we can just use the GUC string */
    1047          36 :     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
    1059        3964 : 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        3964 :     if (*newval)
    1067        1982 :         canonicalize_path(*newval);
    1068        3964 :     return true;
    1069             : }
    1070             : 
    1071             : 
    1072             : /*
    1073             :  * MISCELLANEOUS
    1074             :  */
    1075             : 
    1076             : /*
    1077             :  * GUC check_hook for application_name
    1078             :  */
    1079             : bool
    1080       28204 : 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       28204 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1087       28204 :     if (!clean)
    1088           0 :         return false;
    1089             : 
    1090       28204 :     ret = guc_strdup(WARNING, clean);
    1091       28204 :     if (!ret)
    1092             :     {
    1093           0 :         pfree(clean);
    1094           0 :         return false;
    1095             :     }
    1096             : 
    1097       28204 :     guc_free(*newval);
    1098             : 
    1099       28204 :     pfree(clean);
    1100       28204 :     *newval = ret;
    1101       28204 :     return true;
    1102             : }
    1103             : 
    1104             : /*
    1105             :  * GUC assign_hook for application_name
    1106             :  */
    1107             : void
    1108       28176 : assign_application_name(const char *newval, void *extra)
    1109             : {
    1110             :     /* Update the pg_stat_activity view */
    1111       28176 :     pgstat_report_appname(newval);
    1112       28176 : }
    1113             : 
    1114             : /*
    1115             :  * GUC check_hook for cluster_name
    1116             :  */
    1117             : bool
    1118        3266 : 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        3266 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1125        3266 :     if (!clean)
    1126           0 :         return false;
    1127             : 
    1128        3266 :     ret = guc_strdup(WARNING, clean);
    1129        3266 :     if (!ret)
    1130             :     {
    1131           0 :         pfree(clean);
    1132           0 :         return false;
    1133             :     }
    1134             : 
    1135        3266 :     guc_free(*newval);
    1136             : 
    1137        3266 :     pfree(clean);
    1138        3266 :     *newval = ret;
    1139        3266 :     return true;
    1140             : }
    1141             : 
    1142             : /*
    1143             :  * GUC assign_hook for maintenance_io_concurrency
    1144             :  */
    1145             : void
    1146        1982 : assign_maintenance_io_concurrency(int newval, void *extra)
    1147             : {
    1148             : #ifdef USE_PREFETCH
    1149             :     /*
    1150             :      * Reconfigure recovery prefetching, because a setting it depends on
    1151             :      * changed.
    1152             :      */
    1153        1982 :     maintenance_io_concurrency = newval;
    1154        1982 :     if (AmStartupProcess())
    1155           0 :         XLogPrefetchReconfigure();
    1156             : #endif
    1157        1982 : }
    1158             : 
    1159             : 
    1160             : /*
    1161             :  * These show hooks just exist because we want to show the values in octal.
    1162             :  */
    1163             : 
    1164             : /*
    1165             :  * GUC show_hook for data_directory_mode
    1166             :  */
    1167             : const char *
    1168        4130 : show_data_directory_mode(void)
    1169             : {
    1170             :     static char buf[12];
    1171             : 
    1172        4130 :     snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
    1173        4130 :     return buf;
    1174             : }
    1175             : 
    1176             : /*
    1177             :  * GUC show_hook for log_file_mode
    1178             :  */
    1179             : const char *
    1180        3408 : show_log_file_mode(void)
    1181             : {
    1182             :     static char buf[12];
    1183             : 
    1184        3408 :     snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
    1185        3408 :     return buf;
    1186             : }
    1187             : 
    1188             : /*
    1189             :  * GUC show_hook for unix_socket_permissions
    1190             :  */
    1191             : const char *
    1192        3408 : show_unix_socket_permissions(void)
    1193             : {
    1194             :     static char buf[12];
    1195             : 
    1196        3408 :     snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
    1197        3408 :     return buf;
    1198             : }
    1199             : 
    1200             : 
    1201             : /*
    1202             :  * These check hooks do nothing more than reject non-default settings
    1203             :  * in builds that don't support them.
    1204             :  */
    1205             : 
    1206             : bool
    1207        1982 : check_bonjour(bool *newval, void **extra, GucSource source)
    1208             : {
    1209             : #ifndef USE_BONJOUR
    1210        1982 :     if (*newval)
    1211             :     {
    1212           0 :         GUC_check_errmsg("Bonjour is not supported by this build");
    1213           0 :         return false;
    1214             :     }
    1215             : #endif
    1216        1982 :     return true;
    1217             : }
    1218             : 
    1219             : bool
    1220        1994 : check_default_with_oids(bool *newval, void **extra, GucSource source)
    1221             : {
    1222        1994 :     if (*newval)
    1223             :     {
    1224             :         /* check the GUC's definition for an explanation */
    1225           6 :         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1226           6 :         GUC_check_errmsg("tables declared WITH OIDS are not supported");
    1227             : 
    1228           6 :         return false;
    1229             :     }
    1230             : 
    1231        1988 :     return true;
    1232             : }
    1233             : 
    1234             : bool
    1235        2594 : check_effective_io_concurrency(int *newval, void **extra, GucSource source)
    1236             : {
    1237             : #ifndef USE_PREFETCH
    1238             :     if (*newval != 0)
    1239             :     {
    1240             :         GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
    1241             :                             "effective_io_concurrency");
    1242             :         return false;
    1243             :     }
    1244             : #endif                          /* USE_PREFETCH */
    1245        2594 :     return true;
    1246             : }
    1247             : 
    1248             : bool
    1249        1982 : check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
    1250             : {
    1251             : #ifndef USE_PREFETCH
    1252             :     if (*newval != 0)
    1253             :     {
    1254             :         GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
    1255             :                             "maintenance_io_concurrency");
    1256             :         return false;
    1257             :     }
    1258             : #endif                          /* USE_PREFETCH */
    1259        1982 :     return true;
    1260             : }
    1261             : 
    1262             : bool
    1263        2072 : check_ssl(bool *newval, void **extra, GucSource source)
    1264             : {
    1265             : #ifndef USE_SSL
    1266             :     if (*newval)
    1267             :     {
    1268             :         GUC_check_errmsg("SSL is not supported by this build");
    1269             :         return false;
    1270             :     }
    1271             : #endif
    1272        2072 :     return true;
    1273             : }

Generated by: LCOV version 1.14