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

Generated by: LCOV version 1.14