LCOV - code coverage report
Current view: top level - src/backend/commands - variable.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 298 438 68.0 %
Date: 2024-11-21 08:14:44 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-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
      52       24238 : check_datestyle(char **newval, void **extra, GucSource source)
      53             : {
      54       24238 :     int         newDateStyle = DateStyle;
      55       24238 :     int         newDateOrder = DateOrder;
      56       24238 :     bool        have_style = false;
      57       24238 :     bool        have_order = false;
      58       24238 :     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       24238 :     rawstring = pstrdup(*newval);
      67             : 
      68             :     /* Parse string into list of identifiers */
      69       24238 :     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       63000 :     foreach(l, elemlist)
      79             :     {
      80       38762 :         char       *tok = (char *) lfirst(l);
      81             : 
      82             :         /* Ugh. Somebody ought to write a table driven version -- mjl */
      83             : 
      84       38762 :         if (pg_strcasecmp(tok, "ISO") == 0)
      85             :         {
      86       16914 :             if (have_style && newDateStyle != USE_ISO_DATES)
      87           0 :                 ok = false;     /* conflicting styles */
      88       16914 :             newDateStyle = USE_ISO_DATES;
      89       16914 :             have_style = true;
      90             :         }
      91       21848 :         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       21818 :         else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
      99             :         {
     100        7196 :             if (have_style && newDateStyle != USE_POSTGRES_DATES)
     101           0 :                 ok = false;     /* conflicting styles */
     102        7196 :             newDateStyle = USE_POSTGRES_DATES;
     103        7196 :             have_style = true;
     104             :         }
     105       14622 :         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       14574 :         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       29016 :         else if (pg_strcasecmp(tok, "DMY") == 0 ||
     123       14484 :                  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       14484 :         else if (pg_strcasecmp(tok, "MDY") == 0 ||
     131          18 :                  pg_strcasecmp(tok, "US") == 0 ||
     132           0 :                  pg_strncasecmp(tok, "NONEURO", 7) == 0)
     133             :         {
     134       14466 :             if (have_order && newDateOrder != DATEORDER_MDY)
     135           0 :                 ok = false;     /* conflicting orders */
     136       14466 :             newDateOrder = DATEORDER_MDY;
     137       14466 :             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       24238 :     pfree(rawstring);
     181       24238 :     list_free(elemlist);
     182             : 
     183       24238 :     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       24238 :     result = (char *) guc_malloc(LOG, 32);
     193       24238 :     if (!result)
     194           0 :         return false;
     195             : 
     196       24238 :     switch (newDateStyle)
     197             :     {
     198       16938 :         case USE_ISO_DATES:
     199       16938 :             strcpy(result, "ISO");
     200       16938 :             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        7222 :         default:
     208        7222 :             strcpy(result, "Postgres");
     209        7222 :             break;
     210             :     }
     211       24238 :     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       24090 :         default:
     220       24090 :             strcat(result, ", MDY");
     221       24090 :             break;
     222             :     }
     223             : 
     224       24238 :     guc_free(*newval);
     225       24238 :     *newval = result;
     226             : 
     227             :     /*
     228             :      * Set up the "extra" struct actually used by assign_datestyle.
     229             :      */
     230       24238 :     myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
     231       24238 :     if (!myextra)
     232           0 :         return false;
     233       24238 :     myextra[0] = newDateStyle;
     234       24238 :     myextra[1] = newDateOrder;
     235       24238 :     *extra = (void *) myextra;
     236             : 
     237       24238 :     return true;
     238             : }
     239             : 
     240             : /*
     241             :  * assign_datestyle: GUC assign_hook for datestyle
     242             :  */
     243             : void
     244       32366 : assign_datestyle(const char *newval, void *extra)
     245             : {
     246       32366 :     int        *myextra = (int *) extra;
     247             : 
     248       32366 :     DateStyle = myextra[0];
     249       32366 :     DateOrder = myextra[1];
     250       32366 : }
     251             : 
     252             : 
     253             : /*
     254             :  * TIMEZONE
     255             :  */
     256             : 
     257             : /*
     258             :  * check_timezone: GUC check_hook for timezone
     259             :  */
     260             : bool
     261       14584 : 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       14584 :     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       14584 :         hours = strtod(*newval, &endptr);
     330       14584 :         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       14512 :             new_tz = pg_tzset(*newval);
     342             : 
     343       14512 :             if (!new_tz)
     344             :             {
     345             :                 /* Doesn't seem to be any great value in errdetail here */
     346           0 :                 return false;
     347             :             }
     348             : 
     349       14512 :             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       14584 :     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       14584 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     370       14584 :     if (!*extra)
     371           0 :         return false;
     372       14584 :     *((pg_tz **) *extra) = new_tz;
     373             : 
     374       14584 :     return true;
     375             : }
     376             : 
     377             : /*
     378             :  * assign_timezone: GUC assign_hook for timezone
     379             :  */
     380             : void
     381       14702 : assign_timezone(const char *newval, void *extra)
     382             : {
     383       14702 :     session_timezone = *((pg_tz **) extra);
     384       14702 : }
     385             : 
     386             : /*
     387             :  * show_timezone: GUC show_hook for timezone
     388             :  */
     389             : const char *
     390       53424 : show_timezone(void)
     391             : {
     392             :     const char *tzn;
     393             : 
     394             :     /* Always show the zone's canonical name */
     395       53424 :     tzn = pg_get_timezone_name(session_timezone);
     396             : 
     397       53424 :     if (tzn != NULL)
     398       53424 :         return tzn;
     399             : 
     400           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
     416        9938 : 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        9938 :     new_tz = pg_tzset(*newval);
     424             : 
     425        9938 :     if (!new_tz)
     426             :     {
     427             :         /* Doesn't seem to be any great value in errdetail here */
     428           0 :         return false;
     429             :     }
     430             : 
     431        9938 :     if (!pg_tz_acceptable(new_tz))
     432             :     {
     433           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             :      */
     442        9938 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     443        9938 :     if (!*extra)
     444           0 :         return false;
     445        9938 :     *((pg_tz **) *extra) = new_tz;
     446             : 
     447        9938 :     return true;
     448             : }
     449             : 
     450             : /*
     451             :  * assign_log_timezone: GUC assign_hook for log_timezone
     452             :  */
     453             : void
     454        9932 : assign_log_timezone(const char *newval, void *extra)
     455             : {
     456        9932 :     log_timezone = *((pg_tz **) extra);
     457        9932 : }
     458             : 
     459             : /*
     460             :  * show_log_timezone: GUC show_hook for log_timezone
     461             :  */
     462             : const char *
     463        3400 : show_log_timezone(void)
     464             : {
     465             :     const char *tzn;
     466             : 
     467             :     /* Always show the zone's canonical name */
     468        3400 :     tzn = pg_get_timezone_name(log_timezone);
     469             : 
     470        3400 :     if (tzn != NULL)
     471        3400 :         return tzn;
     472             : 
     473           0 :     return "unknown";
     474             : }
     475             : 
     476             : 
     477             : /*
     478             :  * TIMEZONE_ABBREVIATIONS
     479             :  */
     480             : 
     481             : /*
     482             :  * GUC check_hook for assign_timezone_abbreviations
     483             :  */
     484             : bool
     485       16908 : 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       16908 :     if (*newval == NULL)
     498             :     {
     499             :         Assert(source == PGC_S_DEFAULT);
     500        4678 :         return true;
     501             :     }
     502             : 
     503             :     /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
     504       12230 :     *extra = load_tzoffsets(*newval);
     505             : 
     506             :     /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
     507       12230 :     if (!*extra)
     508           0 :         return false;
     509             : 
     510       12230 :     return true;
     511             : }
     512             : 
     513             : /*
     514             :  * GUC assign_hook for assign_timezone_abbreviations
     515             :  */
     516             : void
     517       16720 : assign_timezone_abbreviations(const char *newval, void *extra)
     518             : {
     519             :     /* Do nothing for the boot_val default of NULL */
     520       16720 :     if (!extra)
     521        4678 :         return;
     522             : 
     523       12042 :     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
     544       10736 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
     545             : {
     546       10736 :     if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
     547             :     {
     548             :         /* Can't go to r/w mode inside a r/o transaction */
     549          64 :         if (IsSubTransaction())
     550             :         {
     551          12 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     552          12 :             GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
     553          12 :             return false;
     554             :         }
     555             :         /* Top level transaction can't change to r/w after first snapshot. */
     556          52 :         if (FirstSnapshotSet)
     557             :         {
     558           6 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     559           6 :             GUC_check_errmsg("transaction read-write mode must be set before any query");
     560           6 :             return false;
     561             :         }
     562             :         /* Can't go to r/w mode while recovery is still active */
     563          46 :         if (RecoveryInProgress())
     564             :         {
     565           0 :             GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     566           0 :             GUC_check_errmsg("cannot set transaction read-write mode during recovery");
     567           0 :             return false;
     568             :         }
     569             :     }
     570             : 
     571       10718 :     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             :  * or if restoring state in a parallel worker.
     582             :  */
     583             : bool
     584       15974 : check_transaction_isolation(int *newval, void **extra, GucSource source)
     585             : {
     586       15974 :     int         newXactIsoLevel = *newval;
     587             : 
     588       21764 :     if (newXactIsoLevel != XactIsoLevel &&
     589       11580 :         IsTransactionState() && !InitializingParallelWorker)
     590             :     {
     591        5710 :         if (FirstSnapshotSet)
     592             :         {
     593           2 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     594           2 :             GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
     595           2 :             return false;
     596             :         }
     597             :         /* We ignore a subtransaction setting it to the existing value. */
     598        5708 :         if (IsSubTransaction())
     599             :         {
     600           0 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     601           0 :             GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
     602           0 :             return false;
     603             :         }
     604             :         /* Can't go to serializable mode while recovery is still active */
     605        5708 :         if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
     606             :         {
     607           0 :             GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     608           0 :             GUC_check_errmsg("cannot use serializable mode in a hot standby");
     609           0 :             GUC_check_errhint("You can use REPEATABLE READ instead.");
     610           0 :             return false;
     611             :         }
     612             :     }
     613             : 
     614       15972 :     return true;
     615             : }
     616             : 
     617             : /*
     618             :  * SET TRANSACTION [NOT] DEFERRABLE
     619             :  */
     620             : 
     621             : bool
     622        9410 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
     623             : {
     624             :     /* Just accept the value when restoring state in a parallel worker */
     625        9410 :     if (InitializingParallelWorker)
     626        5424 :         return true;
     627             : 
     628        3986 :     if (IsSubTransaction())
     629             :     {
     630           0 :         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     631           0 :         GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
     632           0 :         return false;
     633             :     }
     634        3986 :     if (FirstSnapshotSet)
     635             :     {
     636           0 :         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     637           0 :         GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
     638           0 :         return false;
     639             :     }
     640             : 
     641        3986 :     return true;
     642             : }
     643             : 
     644             : /*
     645             :  * Random number seed
     646             :  *
     647             :  * We can't roll back the random sequence on error, and we don't want
     648             :  * config file reloads to affect it, so we only want interactive SET SEED
     649             :  * commands to set it.  We use the "extra" storage to ensure that rollbacks
     650             :  * don't try to do the operation again.
     651             :  */
     652             : 
     653             : bool
     654        1966 : check_random_seed(double *newval, void **extra, GucSource source)
     655             : {
     656        1966 :     *extra = guc_malloc(LOG, sizeof(int));
     657        1966 :     if (!*extra)
     658           0 :         return false;
     659             :     /* Arm the assign only if source of value is an interactive SET */
     660        1966 :     *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
     661             : 
     662        1966 :     return true;
     663             : }
     664             : 
     665             : void
     666        1966 : assign_random_seed(double newval, void *extra)
     667             : {
     668             :     /* We'll do this at most once for any setting of the GUC variable */
     669        1966 :     if (*((int *) extra))
     670           0 :         DirectFunctionCall1(setseed, Float8GetDatum(newval));
     671        1966 :     *((int *) extra) = 0;
     672        1966 : }
     673             : 
     674             : const char *
     675           0 : show_random_seed(void)
     676             : {
     677           0 :     return "unavailable";
     678             : }
     679             : 
     680             : 
     681             : /*
     682             :  * SET CLIENT_ENCODING
     683             :  */
     684             : 
     685             : bool
     686       38252 : check_client_encoding(char **newval, void **extra, GucSource source)
     687             : {
     688             :     int         encoding;
     689             :     const char *canonical_name;
     690             : 
     691             :     /* Look up the encoding by name */
     692       38252 :     encoding = pg_valid_client_encoding(*newval);
     693       38252 :     if (encoding < 0)
     694           0 :         return false;
     695             : 
     696             :     /* Get the canonical name (no aliases, uniform case) */
     697       38252 :     canonical_name = pg_encoding_to_char(encoding);
     698             : 
     699             :     /*
     700             :      * Parallel workers send data to the leader, not the client.  They always
     701             :      * send data using the database encoding; therefore, we should never
     702             :      * actually change the client encoding in a parallel worker.  However,
     703             :      * during parallel worker startup, we want to accept the leader's
     704             :      * client_encoding setting so that anyone who looks at the value in the
     705             :      * worker sees the same value that they would see in the leader.  A change
     706             :      * other than during startup, for example due to a SET clause attached to
     707             :      * a function definition, should be rejected, as there is nothing we can
     708             :      * do inside the worker to make it take effect.
     709             :      */
     710       38252 :     if (IsParallelWorker() && !InitializingParallelWorker)
     711             :     {
     712           0 :         GUC_check_errcode(ERRCODE_INVALID_TRANSACTION_STATE);
     713           0 :         GUC_check_errdetail("Cannot change \"client_encoding\" during a parallel operation.");
     714           0 :         return false;
     715             :     }
     716             : 
     717             :     /*
     718             :      * If we are not within a transaction then PrepareClientEncoding will not
     719             :      * be able to look up the necessary conversion procs.  If we are still
     720             :      * starting up, it will return "OK" anyway, and InitializeClientEncoding
     721             :      * will fix things once initialization is far enough along.  After
     722             :      * startup, we'll fail.  This would only happen if someone tries to change
     723             :      * client_encoding in postgresql.conf and then SIGHUP existing sessions.
     724             :      * It seems like a bad idea for client_encoding to change that way anyhow,
     725             :      * so we don't go out of our way to support it.
     726             :      *
     727             :      * In a parallel worker, we might as well skip PrepareClientEncoding since
     728             :      * we're not going to use its results.
     729             :      *
     730             :      * Note: in the postmaster, or any other process that never calls
     731             :      * InitializeClientEncoding, PrepareClientEncoding will always succeed,
     732             :      * and so will SetClientEncoding; but they won't do anything, which is OK.
     733             :      */
     734       68368 :     if (!IsParallelWorker() &&
     735       30116 :         PrepareClientEncoding(encoding) < 0)
     736             :     {
     737           0 :         if (IsTransactionState())
     738             :         {
     739             :             /* Must be a genuine no-such-conversion problem */
     740           0 :             GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     741           0 :             GUC_check_errdetail("Conversion between %s and %s is not supported.",
     742             :                                 canonical_name,
     743             :                                 GetDatabaseEncodingName());
     744             :         }
     745             :         else
     746             :         {
     747             :             /* Provide a useful complaint */
     748           0 :             GUC_check_errdetail("Cannot change \"client_encoding\" now.");
     749             :         }
     750           0 :         return false;
     751             :     }
     752             : 
     753             :     /*
     754             :      * Replace the user-supplied string with the encoding's canonical name.
     755             :      * This gets rid of aliases and case-folding variations.
     756             :      *
     757             :      * XXX Although canonicalizing seems like a good idea in the abstract, it
     758             :      * breaks pre-9.1 JDBC drivers, which expect that if they send "UNICODE"
     759             :      * as the client_encoding setting then it will read back the same way. As
     760             :      * a workaround, don't replace the string if it's "UNICODE".  Remove that
     761             :      * hack when pre-9.1 JDBC drivers are no longer in use.
     762             :      */
     763       38252 :     if (strcmp(*newval, canonical_name) != 0 &&
     764          34 :         strcmp(*newval, "UNICODE") != 0)
     765             :     {
     766          34 :         guc_free(*newval);
     767          34 :         *newval = guc_strdup(LOG, canonical_name);
     768          34 :         if (!*newval)
     769           0 :             return false;
     770             :     }
     771             : 
     772             :     /*
     773             :      * Save the encoding's ID in *extra, for use by assign_client_encoding.
     774             :      */
     775       38252 :     *extra = guc_malloc(LOG, sizeof(int));
     776       38252 :     if (!*extra)
     777           0 :         return false;
     778       38252 :     *((int *) *extra) = encoding;
     779             : 
     780       38252 :     return true;
     781             : }
     782             : 
     783             : void
     784       38064 : assign_client_encoding(const char *newval, void *extra)
     785             : {
     786       38064 :     int         encoding = *((int *) extra);
     787             : 
     788             :     /*
     789             :      * In a parallel worker, we never override the client encoding that was
     790             :      * set by ParallelWorkerMain().
     791             :      */
     792       38064 :     if (IsParallelWorker())
     793        8136 :         return;
     794             : 
     795             :     /* We do not expect an error if PrepareClientEncoding succeeded */
     796       29928 :     if (SetClientEncoding(encoding) < 0)
     797           0 :         elog(LOG, "SetClientEncoding(%d) failed", encoding);
     798             : }
     799             : 
     800             : 
     801             : /*
     802             :  * SET SESSION AUTHORIZATION
     803             :  */
     804             : 
     805             : typedef struct
     806             : {
     807             :     /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
     808             :     Oid         roleid;
     809             :     bool        is_superuser;
     810             : } role_auth_extra;
     811             : 
     812             : bool
     813       32716 : check_session_authorization(char **newval, void **extra, GucSource source)
     814             : {
     815             :     HeapTuple   roleTup;
     816             :     Form_pg_authid roleform;
     817             :     Oid         roleid;
     818             :     bool        is_superuser;
     819             :     role_auth_extra *myextra;
     820             : 
     821             :     /* Do nothing for the boot_val default of NULL */
     822       32716 :     if (*newval == NULL)
     823        1966 :         return true;
     824             : 
     825       30750 :     if (InitializingParallelWorker)
     826             :     {
     827             :         /*
     828             :          * In parallel worker initialization, we want to copy the leader's
     829             :          * state even if it no longer matches the catalogs. ParallelWorkerMain
     830             :          * already installed the correct role OID and superuser state.
     831             :          */
     832        2712 :         roleid = GetSessionUserId();
     833        2712 :         is_superuser = GetSessionUserIsSuperuser();
     834             :     }
     835             :     else
     836             :     {
     837       28038 :         if (!IsTransactionState())
     838             :         {
     839             :             /*
     840             :              * Can't do catalog lookups, so fail.  The result of this is that
     841             :              * session_authorization cannot be set in postgresql.conf, which
     842             :              * seems like a good thing anyway, so we don't work hard to avoid
     843             :              * it.
     844             :              */
     845           0 :             return false;
     846             :         }
     847             : 
     848             :         /*
     849             :          * When source == PGC_S_TEST, we don't throw a hard error for a
     850             :          * nonexistent user name or insufficient privileges, only a NOTICE.
     851             :          * See comments in guc.h.
     852             :          */
     853             : 
     854             :         /* Look up the username */
     855       28038 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     856       28038 :         if (!HeapTupleIsValid(roleTup))
     857             :         {
     858           0 :             if (source == PGC_S_TEST)
     859             :             {
     860           0 :                 ereport(NOTICE,
     861             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
     862             :                          errmsg("role \"%s\" does not exist", *newval)));
     863           0 :                 return true;
     864             :             }
     865           0 :             GUC_check_errmsg("role \"%s\" does not exist", *newval);
     866           0 :             return false;
     867             :         }
     868             : 
     869       28038 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     870       28038 :         roleid = roleform->oid;
     871       28038 :         is_superuser = roleform->rolsuper;
     872             : 
     873       28038 :         ReleaseSysCache(roleTup);
     874             : 
     875             :         /*
     876             :          * Only superusers may SET SESSION AUTHORIZATION a role other than
     877             :          * itself. Note that in case of multiple SETs in a single session, the
     878             :          * original authenticated user's superuserness is what matters.
     879             :          */
     880       28038 :         if (roleid != GetAuthenticatedUserId() &&
     881        2542 :             !superuser_arg(GetAuthenticatedUserId()))
     882             :         {
     883           0 :             if (source == PGC_S_TEST)
     884             :             {
     885           0 :                 ereport(NOTICE,
     886             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     887             :                          errmsg("permission will be denied to set session authorization \"%s\"",
     888             :                                 *newval)));
     889           0 :                 return true;
     890             :             }
     891           0 :             GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
     892           0 :             GUC_check_errmsg("permission denied to set session authorization \"%s\"",
     893             :                              *newval);
     894           0 :             return false;
     895             :         }
     896             :     }
     897             : 
     898             :     /* Set up "extra" struct for assign_session_authorization to use */
     899       30750 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
     900       30750 :     if (!myextra)
     901           0 :         return false;
     902       30750 :     myextra->roleid = roleid;
     903       30750 :     myextra->is_superuser = is_superuser;
     904       30750 :     *extra = (void *) myextra;
     905             : 
     906       30750 :     return true;
     907             : }
     908             : 
     909             : void
     910       33614 : assign_session_authorization(const char *newval, void *extra)
     911             : {
     912       33614 :     role_auth_extra *myextra = (role_auth_extra *) extra;
     913             : 
     914             :     /* Do nothing for the boot_val default of NULL */
     915       33614 :     if (!myextra)
     916        1966 :         return;
     917             : 
     918       31648 :     SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
     919             : }
     920             : 
     921             : 
     922             : /*
     923             :  * SET ROLE
     924             :  *
     925             :  * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
     926             :  * a translation of "none" to InvalidOid.  Otherwise this is much like
     927             :  * SET SESSION AUTHORIZATION.
     928             :  */
     929             : 
     930             : bool
     931       33680 : check_role(char **newval, void **extra, GucSource source)
     932             : {
     933             :     HeapTuple   roleTup;
     934             :     Oid         roleid;
     935             :     bool        is_superuser;
     936             :     role_auth_extra *myextra;
     937             :     Form_pg_authid roleform;
     938             : 
     939       33680 :     if (strcmp(*newval, "none") == 0)
     940             :     {
     941             :         /* hardwired translation */
     942       32700 :         roleid = InvalidOid;
     943       32700 :         is_superuser = false;
     944             :     }
     945         980 :     else if (InitializingParallelWorker)
     946             :     {
     947             :         /*
     948             :          * In parallel worker initialization, we want to copy the leader's
     949             :          * state even if it no longer matches the catalogs. ParallelWorkerMain
     950             :          * already installed the correct role OID and superuser state.
     951             :          */
     952          12 :         roleid = GetCurrentRoleId();
     953          12 :         is_superuser = current_role_is_superuser;
     954             :     }
     955             :     else
     956             :     {
     957         968 :         if (!IsTransactionState())
     958             :         {
     959             :             /*
     960             :              * Can't do catalog lookups, so fail.  The result of this is that
     961             :              * role cannot be set in postgresql.conf, which seems like a good
     962             :              * thing anyway, so we don't work hard to avoid it.
     963             :              */
     964           0 :             return false;
     965             :         }
     966             : 
     967             :         /*
     968             :          * When source == PGC_S_TEST, we don't throw a hard error for a
     969             :          * nonexistent user name or insufficient privileges, only a NOTICE.
     970             :          * See comments in guc.h.
     971             :          */
     972             : 
     973             :         /* Look up the username */
     974         968 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     975         968 :         if (!HeapTupleIsValid(roleTup))
     976             :         {
     977           0 :             if (source == PGC_S_TEST)
     978             :             {
     979           0 :                 ereport(NOTICE,
     980             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
     981             :                          errmsg("role \"%s\" does not exist", *newval)));
     982           0 :                 return true;
     983             :             }
     984           0 :             GUC_check_errmsg("role \"%s\" does not exist", *newval);
     985           0 :             return false;
     986             :         }
     987             : 
     988         968 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     989         968 :         roleid = roleform->oid;
     990         968 :         is_superuser = roleform->rolsuper;
     991             : 
     992         968 :         ReleaseSysCache(roleTup);
     993             : 
     994             :         /* Verify that session user is allowed to become this role */
     995         968 :         if (!member_can_set_role(GetSessionUserId(), roleid))
     996             :         {
     997          12 :             if (source == PGC_S_TEST)
     998             :             {
     999           0 :                 ereport(NOTICE,
    1000             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1001             :                          errmsg("permission will be denied to set role \"%s\"",
    1002             :                                 *newval)));
    1003           0 :                 return true;
    1004             :             }
    1005          12 :             GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
    1006          12 :             GUC_check_errmsg("permission denied to set role \"%s\"",
    1007             :                              *newval);
    1008          12 :             return false;
    1009             :         }
    1010             :     }
    1011             : 
    1012             :     /* Set up "extra" struct for assign_role to use */
    1013       33668 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
    1014       33668 :     if (!myextra)
    1015           0 :         return false;
    1016       33668 :     myextra->roleid = roleid;
    1017       33668 :     myextra->is_superuser = is_superuser;
    1018       33668 :     *extra = (void *) myextra;
    1019             : 
    1020       33668 :     return true;
    1021             : }
    1022             : 
    1023             : void
    1024       35226 : assign_role(const char *newval, void *extra)
    1025             : {
    1026       35226 :     role_auth_extra *myextra = (role_auth_extra *) extra;
    1027             : 
    1028       35226 :     SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
    1029       35226 : }
    1030             : 
    1031             : const char *
    1032          60 : show_role(void)
    1033             : {
    1034             :     /*
    1035             :      * Check whether SET ROLE is active; if not return "none".  This is a
    1036             :      * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
    1037             :      * resets SET ROLE to NONE, but we cannot set the GUC role variable from
    1038             :      * assign_session_authorization (because we haven't got enough info to
    1039             :      * call set_config_option).
    1040             :      */
    1041          60 :     if (!OidIsValid(GetCurrentRoleId()))
    1042          24 :         return "none";
    1043             : 
    1044             :     /* Otherwise we can just use the GUC string */
    1045          36 :     return role_string ? role_string : "none";
    1046             : }
    1047             : 
    1048             : 
    1049             : /*
    1050             :  * PATH VARIABLES
    1051             :  *
    1052             :  * check_canonical_path is used for log_directory and some other GUCs where
    1053             :  * all we want to do is canonicalize the represented path name.
    1054             :  */
    1055             : 
    1056             : bool
    1057        3932 : check_canonical_path(char **newval, void **extra, GucSource source)
    1058             : {
    1059             :     /*
    1060             :      * Since canonicalize_path never enlarges the string, we can just modify
    1061             :      * newval in-place.  But watch out for NULL, which is the default value
    1062             :      * for external_pid_file.
    1063             :      */
    1064        3932 :     if (*newval)
    1065        1966 :         canonicalize_path(*newval);
    1066        3932 :     return true;
    1067             : }
    1068             : 
    1069             : 
    1070             : /*
    1071             :  * MISCELLANEOUS
    1072             :  */
    1073             : 
    1074             : /*
    1075             :  * GUC check_hook for application_name
    1076             :  */
    1077             : bool
    1078       30350 : check_application_name(char **newval, void **extra, GucSource source)
    1079             : {
    1080             :     char       *clean;
    1081             :     char       *ret;
    1082             : 
    1083             :     /* Only allow clean ASCII chars in the application name */
    1084       30350 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1085       30350 :     if (!clean)
    1086           0 :         return false;
    1087             : 
    1088       30350 :     ret = guc_strdup(WARNING, clean);
    1089       30350 :     if (!ret)
    1090             :     {
    1091           0 :         pfree(clean);
    1092           0 :         return false;
    1093             :     }
    1094             : 
    1095       30350 :     pfree(clean);
    1096       30350 :     *newval = ret;
    1097       30350 :     return true;
    1098             : }
    1099             : 
    1100             : /*
    1101             :  * GUC assign_hook for application_name
    1102             :  */
    1103             : void
    1104       30322 : assign_application_name(const char *newval, void *extra)
    1105             : {
    1106             :     /* Update the pg_stat_activity view */
    1107       30322 :     pgstat_report_appname(newval);
    1108       30322 : }
    1109             : 
    1110             : /*
    1111             :  * GUC check_hook for cluster_name
    1112             :  */
    1113             : bool
    1114        3234 : check_cluster_name(char **newval, void **extra, GucSource source)
    1115             : {
    1116             :     char       *clean;
    1117             :     char       *ret;
    1118             : 
    1119             :     /* Only allow clean ASCII chars in the cluster name */
    1120        3234 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1121        3234 :     if (!clean)
    1122           0 :         return false;
    1123             : 
    1124        3234 :     ret = guc_strdup(WARNING, clean);
    1125        3234 :     if (!ret)
    1126             :     {
    1127           0 :         pfree(clean);
    1128           0 :         return false;
    1129             :     }
    1130             : 
    1131        3234 :     pfree(clean);
    1132        3234 :     *newval = ret;
    1133        3234 :     return true;
    1134             : }
    1135             : 
    1136             : /*
    1137             :  * GUC assign_hook for maintenance_io_concurrency
    1138             :  */
    1139             : void
    1140        1966 : assign_maintenance_io_concurrency(int newval, void *extra)
    1141             : {
    1142             : #ifdef USE_PREFETCH
    1143             :     /*
    1144             :      * Reconfigure recovery prefetching, because a setting it depends on
    1145             :      * changed.
    1146             :      */
    1147        1966 :     maintenance_io_concurrency = newval;
    1148        1966 :     if (AmStartupProcess())
    1149           0 :         XLogPrefetchReconfigure();
    1150             : #endif
    1151        1966 : }
    1152             : 
    1153             : 
    1154             : /*
    1155             :  * These show hooks just exist because we want to show the values in octal.
    1156             :  */
    1157             : 
    1158             : /*
    1159             :  * GUC show_hook for data_directory_mode
    1160             :  */
    1161             : const char *
    1162        4120 : show_data_directory_mode(void)
    1163             : {
    1164             :     static char buf[12];
    1165             : 
    1166        4120 :     snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
    1167        4120 :     return buf;
    1168             : }
    1169             : 
    1170             : /*
    1171             :  * GUC show_hook for log_file_mode
    1172             :  */
    1173             : const char *
    1174        3400 : show_log_file_mode(void)
    1175             : {
    1176             :     static char buf[12];
    1177             : 
    1178        3400 :     snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
    1179        3400 :     return buf;
    1180             : }
    1181             : 
    1182             : /*
    1183             :  * GUC show_hook for unix_socket_permissions
    1184             :  */
    1185             : const char *
    1186        3400 : show_unix_socket_permissions(void)
    1187             : {
    1188             :     static char buf[12];
    1189             : 
    1190        3400 :     snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
    1191        3400 :     return buf;
    1192             : }
    1193             : 
    1194             : 
    1195             : /*
    1196             :  * These check hooks do nothing more than reject non-default settings
    1197             :  * in builds that don't support them.
    1198             :  */
    1199             : 
    1200             : bool
    1201        1966 : check_bonjour(bool *newval, void **extra, GucSource source)
    1202             : {
    1203             : #ifndef USE_BONJOUR
    1204        1966 :     if (*newval)
    1205             :     {
    1206           0 :         GUC_check_errmsg("Bonjour is not supported by this build");
    1207           0 :         return false;
    1208             :     }
    1209             : #endif
    1210        1966 :     return true;
    1211             : }
    1212             : 
    1213             : bool
    1214        1978 : check_default_with_oids(bool *newval, void **extra, GucSource source)
    1215             : {
    1216        1978 :     if (*newval)
    1217             :     {
    1218             :         /* check the GUC's definition for an explanation */
    1219           6 :         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1220           6 :         GUC_check_errmsg("tables declared WITH OIDS are not supported");
    1221             : 
    1222           6 :         return false;
    1223             :     }
    1224             : 
    1225        1972 :     return true;
    1226             : }
    1227             : 
    1228             : bool
    1229        2578 : check_effective_io_concurrency(int *newval, void **extra, GucSource source)
    1230             : {
    1231             : #ifndef USE_PREFETCH
    1232             :     if (*newval != 0)
    1233             :     {
    1234             :         GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
    1235             :                             "effective_io_concurrency");
    1236             :         return false;
    1237             :     }
    1238             : #endif                          /* USE_PREFETCH */
    1239        2578 :     return true;
    1240             : }
    1241             : 
    1242             : bool
    1243        1966 : check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
    1244             : {
    1245             : #ifndef USE_PREFETCH
    1246             :     if (*newval != 0)
    1247             :     {
    1248             :         GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
    1249             :                             "maintenance_io_concurrency");
    1250             :         return false;
    1251             :     }
    1252             : #endif                          /* USE_PREFETCH */
    1253        1966 :     return true;
    1254             : }
    1255             : 
    1256             : bool
    1257        2056 : check_ssl(bool *newval, void **extra, GucSource source)
    1258             : {
    1259             : #ifndef USE_SSL
    1260             :     if (*newval)
    1261             :     {
    1262             :         GUC_check_errmsg("SSL is not supported by this build");
    1263             :         return false;
    1264             :     }
    1265             : #endif
    1266        2056 :     return true;
    1267             : }

Generated by: LCOV version 1.14