LCOV - code coverage report
Current view: top level - src/backend/commands - variable.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 68.8 % 449 309
Test Date: 2026-03-01 23:14:58 Functions: 97.3 % 37 36
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-2026, 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        13854 : check_datestyle(char **newval, void **extra, GucSource source)
      53              : {
      54        13854 :     int         newDateStyle = DateStyle;
      55        13854 :     int         newDateOrder = DateOrder;
      56        13854 :     bool        have_style = false;
      57        13854 :     bool        have_order = false;
      58        13854 :     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        13854 :     rawstring = pstrdup(*newval);
      67              : 
      68              :     /* Parse string into list of identifiers */
      69        13854 :     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        36221 :     foreach(l, elemlist)
      79              :     {
      80        22367 :         char       *tok = (char *) lfirst(l);
      81              : 
      82              :         /* Ugh. Somebody ought to write a table driven version -- mjl */
      83              : 
      84        22367 :         if (pg_strcasecmp(tok, "ISO") == 0)
      85              :         {
      86         9872 :             if (have_style && newDateStyle != USE_ISO_DATES)
      87            0 :                 ok = false;     /* conflicting styles */
      88         9872 :             newDateStyle = USE_ISO_DATES;
      89         9872 :             have_style = true;
      90              :         }
      91        12495 :         else if (pg_strcasecmp(tok, "SQL") == 0)
      92              :         {
      93           15 :             if (have_style && newDateStyle != USE_SQL_DATES)
      94            0 :                 ok = false;     /* conflicting styles */
      95           15 :             newDateStyle = USE_SQL_DATES;
      96           15 :             have_style = true;
      97              :         }
      98        12480 :         else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
      99              :         {
     100         3918 :             if (have_style && newDateStyle != USE_POSTGRES_DATES)
     101            0 :                 ok = false;     /* conflicting styles */
     102         3918 :             newDateStyle = USE_POSTGRES_DATES;
     103         3918 :             have_style = true;
     104              :         }
     105         8562 :         else if (pg_strcasecmp(tok, "GERMAN") == 0)
     106              :         {
     107           24 :             if (have_style && newDateStyle != USE_GERMAN_DATES)
     108            0 :                 ok = false;     /* conflicting styles */
     109           24 :             newDateStyle = USE_GERMAN_DATES;
     110           24 :             have_style = true;
     111              :             /* GERMAN also sets DMY, unless explicitly overridden */
     112           24 :             if (!have_order)
     113           24 :                 newDateOrder = DATEORDER_DMY;
     114              :         }
     115         8538 :         else if (pg_strcasecmp(tok, "YMD") == 0)
     116              :         {
     117           21 :             if (have_order && newDateOrder != DATEORDER_YMD)
     118            0 :                 ok = false;     /* conflicting orders */
     119           21 :             newDateOrder = DATEORDER_YMD;
     120           21 :             have_order = true;
     121              :         }
     122        17010 :         else if (pg_strcasecmp(tok, "DMY") == 0 ||
     123         8493 :                  pg_strncasecmp(tok, "EURO", 4) == 0)
     124              :         {
     125           33 :             if (have_order && newDateOrder != DATEORDER_DMY)
     126            0 :                 ok = false;     /* conflicting orders */
     127           33 :             newDateOrder = DATEORDER_DMY;
     128           33 :             have_order = true;
     129              :         }
     130         8493 :         else if (pg_strcasecmp(tok, "MDY") == 0 ||
     131            9 :                  pg_strcasecmp(tok, "US") == 0 ||
     132            0 :                  pg_strncasecmp(tok, "NONEURO", 7) == 0)
     133              :         {
     134         8484 :             if (have_order && newDateOrder != DATEORDER_MDY)
     135            0 :                 ok = false;     /* conflicting orders */
     136         8484 :             newDateOrder = DATEORDER_MDY;
     137         8484 :             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        13854 :     pfree(rawstring);
     181        13854 :     list_free(elemlist);
     182              : 
     183        13854 :     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        13854 :     result = (char *) guc_malloc(LOG, 32);
     193        13854 :     if (!result)
     194            0 :         return false;
     195              : 
     196        13854 :     switch (newDateStyle)
     197              :     {
     198         9884 :         case USE_ISO_DATES:
     199         9884 :             strcpy(result, "ISO");
     200         9884 :             break;
     201           15 :         case USE_SQL_DATES:
     202           15 :             strcpy(result, "SQL");
     203           15 :             break;
     204           24 :         case USE_GERMAN_DATES:
     205           24 :             strcpy(result, "German");
     206           24 :             break;
     207         3931 :         default:
     208         3931 :             strcpy(result, "Postgres");
     209         3931 :             break;
     210              :     }
     211        13854 :     switch (newDateOrder)
     212              :     {
     213           27 :         case DATEORDER_YMD:
     214           27 :             strcat(result, ", YMD");
     215           27 :             break;
     216           47 :         case DATEORDER_DMY:
     217           47 :             strcat(result, ", DMY");
     218           47 :             break;
     219        13780 :         default:
     220        13780 :             strcat(result, ", MDY");
     221        13780 :             break;
     222              :     }
     223              : 
     224        13854 :     guc_free(*newval);
     225        13854 :     *newval = result;
     226              : 
     227              :     /*
     228              :      * Set up the "extra" struct actually used by assign_datestyle.
     229              :      */
     230        13854 :     myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
     231        13854 :     if (!myextra)
     232            0 :         return false;
     233        13854 :     myextra[0] = newDateStyle;
     234        13854 :     myextra[1] = newDateOrder;
     235        13854 :     *extra = myextra;
     236              : 
     237        13854 :     return true;
     238              : }
     239              : 
     240              : /*
     241              :  * assign_datestyle: GUC assign_hook for datestyle
     242              :  */
     243              : void
     244        18150 : assign_datestyle(const char *newval, void *extra)
     245              : {
     246        18150 :     int        *myextra = (int *) extra;
     247              : 
     248        18150 :     DateStyle = myextra[0];
     249        18150 :     DateOrder = myextra[1];
     250        18150 : }
     251              : 
     252              : 
     253              : /*
     254              :  * TIMEZONE
     255              :  */
     256              : 
     257              : /*
     258              :  * check_timezone: GUC check_hook for timezone
     259              :  */
     260              : bool
     261         8553 : 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         8553 :     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         8553 :         hours = strtod(*newval, &endptr);
     330         8553 :         if (endptr != *newval && *endptr == '\0')
     331              :         {
     332              :             /* Here we change from SQL to Unix sign convention */
     333           36 :             gmtoffset = -hours * SECS_PER_HOUR;
     334           36 :             new_tz = pg_tzset_offset(gmtoffset);
     335              :         }
     336              :         else
     337              :         {
     338              :             /*
     339              :              * Otherwise assume it is a timezone name, and try to load it.
     340              :              */
     341         8517 :             new_tz = pg_tzset(*newval);
     342              : 
     343         8517 :             if (!new_tz)
     344              :             {
     345              :                 /* Doesn't seem to be any great value in errdetail here */
     346            0 :                 return false;
     347              :             }
     348              : 
     349         8517 :             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         8553 :     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         8553 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     370         8553 :     if (!*extra)
     371            0 :         return false;
     372         8553 :     *((pg_tz **) *extra) = new_tz;
     373              : 
     374         8553 :     return true;
     375              : }
     376              : 
     377              : /*
     378              :  * assign_timezone: GUC assign_hook for timezone
     379              :  */
     380              : void
     381         8615 : assign_timezone(const char *newval, void *extra)
     382              : {
     383         8615 :     session_timezone = *((pg_tz **) extra);
     384              :     /* datetime.c's cache of timezone abbrevs may now be obsolete */
     385         8615 :     ClearTimeZoneAbbrevCache();
     386         8615 : }
     387              : 
     388              : /*
     389              :  * show_timezone: GUC show_hook for timezone
     390              :  */
     391              : const char *
     392        29560 : show_timezone(void)
     393              : {
     394              :     const char *tzn;
     395              : 
     396              :     /* Always show the zone's canonical name */
     397        29560 :     tzn = pg_get_timezone_name(session_timezone);
     398              : 
     399        29560 :     if (tzn != NULL)
     400        29560 :         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         6031 : 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         6031 :     new_tz = pg_tzset(*newval);
     426              : 
     427         6031 :     if (!new_tz)
     428              :     {
     429              :         /* Doesn't seem to be any great value in errdetail here */
     430            0 :         return false;
     431              :     }
     432              : 
     433         6031 :     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         6031 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     445         6031 :     if (!*extra)
     446            0 :         return false;
     447         6031 :     *((pg_tz **) *extra) = new_tz;
     448              : 
     449         6031 :     return true;
     450              : }
     451              : 
     452              : /*
     453              :  * assign_log_timezone: GUC assign_hook for log_timezone
     454              :  */
     455              : void
     456         6028 : assign_log_timezone(const char *newval, void *extra)
     457              : {
     458         6028 :     log_timezone = *((pg_tz **) extra);
     459         6028 : }
     460              : 
     461              : /*
     462              :  * show_log_timezone: GUC show_hook for log_timezone
     463              :  */
     464              : const char *
     465         1799 : show_log_timezone(void)
     466              : {
     467              :     const char *tzn;
     468              : 
     469              :     /* Always show the zone's canonical name */
     470         1799 :     tzn = pg_get_timezone_name(log_timezone);
     471              : 
     472         1799 :     if (tzn != NULL)
     473         1799 :         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         9824 : 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         9824 :     if (*newval == NULL)
     500              :     {
     501              :         Assert(source == PGC_S_DEFAULT);
     502         2676 :         return true;
     503              :     }
     504              : 
     505              :     /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
     506         7148 :     *extra = load_tzoffsets(*newval);
     507              : 
     508              :     /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
     509         7148 :     if (!*extra)
     510            0 :         return false;
     511              : 
     512         7148 :     return true;
     513              : }
     514              : 
     515              : /*
     516              :  * GUC assign_hook for timezone_abbreviations
     517              :  */
     518              : void
     519         9719 : assign_timezone_abbreviations(const char *newval, void *extra)
     520              : {
     521              :     /* Do nothing for the boot_val default of NULL */
     522         9719 :     if (!extra)
     523         2676 :         return;
     524              : 
     525         7043 :     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         6162 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
     547              : {
     548         6162 :     if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
     549              :     {
     550              :         /* Can't go to r/w mode inside a r/o transaction */
     551           32 :         if (IsSubTransaction())
     552              :         {
     553            6 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     554            6 :             GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
     555            6 :             return false;
     556              :         }
     557              :         /* Top level transaction can't change to r/w after first snapshot. */
     558           26 :         if (FirstSnapshotSet)
     559              :         {
     560            3 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     561            3 :             GUC_check_errmsg("transaction read-write mode must be set before any query");
     562            3 :             return false;
     563              :         }
     564              :         /* Can't go to r/w mode while recovery is still active */
     565           23 :         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         6153 :     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         8968 : check_transaction_isolation(int *newval, void **extra, GucSource source)
     587              : {
     588         8968 :     int         newXactIsoLevel = *newval;
     589              : 
     590        12083 :     if (newXactIsoLevel != XactIsoLevel &&
     591         6230 :         IsTransactionState() && !InitializingParallelWorker)
     592              :     {
     593         3075 :         if (FirstSnapshotSet)
     594              :         {
     595            1 :             GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     596            1 :             GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
     597            1 :             return false;
     598              :         }
     599              :         /* We ignore a subtransaction setting it to the existing value. */
     600         3074 :         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         3074 :         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         8967 :     return true;
     617              : }
     618              : 
     619              : /*
     620              :  * SET TRANSACTION [NOT] DEFERRABLE
     621              :  */
     622              : 
     623              : bool
     624         5379 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
     625              : {
     626              :     /* Just accept the value when restoring state in a parallel worker */
     627         5379 :     if (InitializingParallelWorker)
     628         2978 :         return true;
     629              : 
     630         2401 :     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         2401 :     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         2401 :     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         1187 : check_random_seed(double *newval, void **extra, GucSource source)
     657              : {
     658         1187 :     *extra = guc_malloc(LOG, sizeof(int));
     659         1187 :     if (!*extra)
     660            0 :         return false;
     661              :     /* Arm the assign only if source of value is an interactive SET */
     662         1187 :     *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
     663              : 
     664         1187 :     return true;
     665              : }
     666              : 
     667              : void
     668         1187 : assign_random_seed(double newval, void *extra)
     669              : {
     670              :     /* We'll do this at most once for any setting of the GUC variable */
     671         1187 :     if (*((int *) extra))
     672            0 :         DirectFunctionCall1(setseed, Float8GetDatum(newval));
     673         1187 :     *((int *) extra) = 0;
     674         1187 : }
     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        23226 : 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        23226 :     encoding = pg_valid_client_encoding(*newval);
     695        23226 :     if (encoding < 0)
     696            0 :         return false;
     697              : 
     698              :     /* Get the canonical name (no aliases, uniform case) */
     699        23226 :     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        23226 :     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        41985 :     if (!IsParallelWorker() &&
     737        18759 :         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        23226 :     if (strcmp(*newval, canonical_name) != 0 &&
     766           71 :         strcmp(*newval, "UNICODE") != 0)
     767              :     {
     768           71 :         guc_free(*newval);
     769           71 :         *newval = guc_strdup(LOG, canonical_name);
     770           71 :         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        23226 :     *extra = guc_malloc(LOG, sizeof(int));
     778        23226 :     if (!*extra)
     779            0 :         return false;
     780        23226 :     *((int *) *extra) = encoding;
     781              : 
     782        23226 :     return true;
     783              : }
     784              : 
     785              : void
     786        23141 : assign_client_encoding(const char *newval, void *extra)
     787              : {
     788        23141 :     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        23141 :     if (IsParallelWorker())
     795         4467 :         return;
     796              : 
     797              :     /* We do not expect an error if PrepareClientEncoding succeeded */
     798        18674 :     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        18330 : 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        18330 :     if (*newval == NULL)
     825         1187 :         return true;
     826              : 
     827        17143 :     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         1489 :         roleid = GetSessionUserId();
     835         1489 :         is_superuser = GetSessionUserIsSuperuser();
     836              :     }
     837              :     else
     838              :     {
     839        15654 :         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        15654 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     858        15654 :         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        15654 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     872        15654 :         roleid = roleform->oid;
     873        15654 :         is_superuser = roleform->rolsuper;
     874              : 
     875        15654 :         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        15654 :         if (roleid != GetAuthenticatedUserId() &&
     883         1379 :             !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        17143 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
     902        17143 :     if (!myextra)
     903            0 :         return false;
     904        17143 :     myextra->roleid = roleid;
     905        17143 :     myextra->is_superuser = is_superuser;
     906        17143 :     *extra = myextra;
     907              : 
     908        17143 :     return true;
     909              : }
     910              : 
     911              : void
     912        18834 : assign_session_authorization(const char *newval, void *extra)
     913              : {
     914        18834 :     role_auth_extra *myextra = (role_auth_extra *) extra;
     915              : 
     916              :     /* Do nothing for the boot_val default of NULL */
     917        18834 :     if (!myextra)
     918         1187 :         return;
     919              : 
     920        17647 :     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        18860 : 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        18860 :     if (strcmp(*newval, "none") == 0)
     942              :     {
     943              :         /* hardwired translation */
     944        18320 :         roleid = InvalidOid;
     945        18320 :         is_superuser = false;
     946              :     }
     947          540 :     else if (InitializingParallelWorker)
     948              :     {
     949              :         /*
     950              :          * In parallel worker initialization, we want to copy the leader's
     951              :          * state even if it no longer matches the catalogs. ParallelWorkerMain
     952              :          * already installed the correct role OID and superuser state.
     953              :          */
     954            6 :         roleid = GetCurrentRoleId();
     955            6 :         is_superuser = current_role_is_superuser;
     956              :     }
     957              :     else
     958              :     {
     959          534 :         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          534 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     977          534 :         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          534 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     991          534 :         roleid = roleform->oid;
     992          534 :         is_superuser = roleform->rolsuper;
     993              : 
     994          534 :         ReleaseSysCache(roleTup);
     995              : 
     996              :         /* Verify that session user is allowed to become this role */
     997          534 :         if (!member_can_set_role(GetSessionUserId(), roleid))
     998              :         {
     999            6 :             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            6 :             GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
    1008            6 :             GUC_check_errmsg("permission denied to set role \"%s\"",
    1009              :                              *newval);
    1010            6 :             return false;
    1011              :         }
    1012              :     }
    1013              : 
    1014              :     /* Set up "extra" struct for assign_role to use */
    1015        18854 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
    1016        18854 :     if (!myextra)
    1017            0 :         return false;
    1018        18854 :     myextra->roleid = roleid;
    1019        18854 :     myextra->is_superuser = is_superuser;
    1020        18854 :     *extra = myextra;
    1021              : 
    1022        18854 :     return true;
    1023              : }
    1024              : 
    1025              : void
    1026        19737 : assign_role(const char *newval, void *extra)
    1027              : {
    1028        19737 :     role_auth_extra *myextra = (role_auth_extra *) extra;
    1029              : 
    1030        19737 :     SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
    1031        19737 : }
    1032              : 
    1033              : const char *
    1034           30 : show_role(void)
    1035              : {
    1036              :     /*
    1037              :      * Check whether SET ROLE is active; if not return "none".  This is a
    1038              :      * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
    1039              :      * resets SET ROLE to NONE, but we cannot set the GUC role variable from
    1040              :      * assign_session_authorization (because we haven't got enough info to
    1041              :      * call set_config_option).
    1042              :      */
    1043           30 :     if (!OidIsValid(GetCurrentRoleId()))
    1044           12 :         return "none";
    1045              : 
    1046              :     /* Otherwise we can just use the GUC string */
    1047           18 :     return role_string ? role_string : "none";
    1048              : }
    1049              : 
    1050              : 
    1051              : /*
    1052              :  * PATH VARIABLES
    1053              :  *
    1054              :  * check_canonical_path is used for log_directory and some other GUCs where
    1055              :  * all we want to do is canonicalize the represented path name.
    1056              :  */
    1057              : 
    1058              : bool
    1059         2374 : 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         2374 :     if (*newval)
    1067         1187 :         canonicalize_path(*newval);
    1068         2374 :     return true;
    1069              : }
    1070              : 
    1071              : 
    1072              : /*
    1073              :  * MISCELLANEOUS
    1074              :  */
    1075              : 
    1076              : /*
    1077              :  * GUC check_hook for application_name
    1078              :  */
    1079              : bool
    1080        16913 : 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        16913 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1087        16913 :     if (!clean)
    1088            0 :         return false;
    1089              : 
    1090        16913 :     ret = guc_strdup(LOG, clean);
    1091        16913 :     if (!ret)
    1092              :     {
    1093            0 :         pfree(clean);
    1094            0 :         return false;
    1095              :     }
    1096              : 
    1097        16913 :     guc_free(*newval);
    1098              : 
    1099        16913 :     pfree(clean);
    1100        16913 :     *newval = ret;
    1101        16913 :     return true;
    1102              : }
    1103              : 
    1104              : /*
    1105              :  * GUC assign_hook for application_name
    1106              :  */
    1107              : void
    1108        16900 : assign_application_name(const char *newval, void *extra)
    1109              : {
    1110              :     /* Update the pg_stat_activity view */
    1111        16900 :     pgstat_report_appname(newval);
    1112        16900 : }
    1113              : 
    1114              : /*
    1115              :  * GUC check_hook for cluster_name
    1116              :  */
    1117              : bool
    1118         1941 : 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         1941 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1125         1941 :     if (!clean)
    1126            0 :         return false;
    1127              : 
    1128         1941 :     ret = guc_strdup(LOG, clean);
    1129         1941 :     if (!ret)
    1130              :     {
    1131            0 :         pfree(clean);
    1132            0 :         return false;
    1133              :     }
    1134              : 
    1135         1941 :     guc_free(*newval);
    1136              : 
    1137         1941 :     pfree(clean);
    1138         1941 :     *newval = ret;
    1139         1941 :     return true;
    1140              : }
    1141              : 
    1142              : /*
    1143              :  * GUC assign_hook for maintenance_io_concurrency
    1144              :  */
    1145              : void
    1146         1188 : assign_maintenance_io_concurrency(int newval, void *extra)
    1147              : {
    1148              :     /*
    1149              :      * Reconfigure recovery prefetching, because a setting it depends on
    1150              :      * changed.
    1151              :      */
    1152         1188 :     maintenance_io_concurrency = newval;
    1153         1188 :     if (AmStartupProcess())
    1154            0 :         XLogPrefetchReconfigure();
    1155         1188 : }
    1156              : 
    1157              : /*
    1158              :  * GUC assign hooks that recompute io_combine_limit whenever
    1159              :  * io_combine_limit_guc and io_max_combine_limit are changed.  These are needed
    1160              :  * because the GUC subsystem doesn't support dependencies between GUCs, and
    1161              :  * they may be assigned in either order.
    1162              :  */
    1163              : void
    1164         1187 : assign_io_max_combine_limit(int newval, void *extra)
    1165              : {
    1166         1187 :     io_combine_limit = Min(newval, io_combine_limit_guc);
    1167         1187 : }
    1168              : void
    1169         1206 : assign_io_combine_limit(int newval, void *extra)
    1170              : {
    1171         1206 :     io_combine_limit = Min(io_max_combine_limit, newval);
    1172         1206 : }
    1173              : 
    1174              : /*
    1175              :  * These show hooks just exist because we want to show the values in octal.
    1176              :  */
    1177              : 
    1178              : /*
    1179              :  * GUC show_hook for data_directory_mode
    1180              :  */
    1181              : const char *
    1182         2189 : show_data_directory_mode(void)
    1183              : {
    1184              :     static char buf[12];
    1185              : 
    1186         2189 :     snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
    1187         2189 :     return buf;
    1188              : }
    1189              : 
    1190              : /*
    1191              :  * GUC show_hook for log_file_mode
    1192              :  */
    1193              : const char *
    1194         1799 : show_log_file_mode(void)
    1195              : {
    1196              :     static char buf[12];
    1197              : 
    1198         1799 :     snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
    1199         1799 :     return buf;
    1200              : }
    1201              : 
    1202              : /*
    1203              :  * GUC show_hook for unix_socket_permissions
    1204              :  */
    1205              : const char *
    1206         1799 : show_unix_socket_permissions(void)
    1207              : {
    1208              :     static char buf[12];
    1209              : 
    1210         1799 :     snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
    1211         1799 :     return buf;
    1212              : }
    1213              : 
    1214              : 
    1215              : /*
    1216              :  * These check hooks do nothing more than reject non-default settings
    1217              :  * in builds that don't support them.
    1218              :  */
    1219              : 
    1220              : bool
    1221         1187 : check_bonjour(bool *newval, void **extra, GucSource source)
    1222              : {
    1223              : #ifndef USE_BONJOUR
    1224         1187 :     if (*newval)
    1225              :     {
    1226            0 :         GUC_check_errmsg("Bonjour is not supported by this build");
    1227            0 :         return false;
    1228              :     }
    1229              : #endif
    1230         1187 :     return true;
    1231              : }
    1232              : 
    1233              : bool
    1234         1193 : check_default_with_oids(bool *newval, void **extra, GucSource source)
    1235              : {
    1236         1193 :     if (*newval)
    1237              :     {
    1238              :         /* check the GUC's definition for an explanation */
    1239            3 :         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1240            3 :         GUC_check_errmsg("tables declared WITH OIDS are not supported");
    1241              : 
    1242            3 :         return false;
    1243              :     }
    1244              : 
    1245         1190 :     return true;
    1246              : }
    1247              : 
    1248              : bool
    1249         1257 : check_ssl(bool *newval, void **extra, GucSource source)
    1250              : {
    1251              : #ifndef USE_SSL
    1252              :     if (*newval)
    1253              :     {
    1254              :         GUC_check_errmsg("SSL is not supported by this build");
    1255              :         return false;
    1256              :     }
    1257              : #endif
    1258         1257 :     return true;
    1259              : }
    1260              : 
    1261              : bool
    1262         1656 : check_standard_conforming_strings(bool *newval, void **extra, GucSource source)
    1263              : {
    1264         1656 :     if (!*newval)
    1265              :     {
    1266              :         /* check the GUC's definition for an explanation */
    1267            3 :         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1268            3 :         GUC_check_errmsg("non-standard string literals are not supported");
    1269              : 
    1270            3 :         return false;
    1271              :     }
    1272              : 
    1273         1653 :     return true;
    1274              : }
        

Generated by: LCOV version 2.0-1