LCOV - code coverage report
Current view: top level - src/backend/commands - variable.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 285 427 66.7 %
Date: 2024-07-27 07:11:05 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       23736 : check_datestyle(char **newval, void **extra, GucSource source)
      53             : {
      54       23736 :     int         newDateStyle = DateStyle;
      55       23736 :     int         newDateOrder = DateOrder;
      56       23736 :     bool        have_style = false;
      57       23736 :     bool        have_order = false;
      58       23736 :     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       23736 :     rawstring = pstrdup(*newval);
      67             : 
      68             :     /* Parse string into list of identifiers */
      69       23736 :     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       61542 :     foreach(l, elemlist)
      79             :     {
      80       37806 :         char       *tok = (char *) lfirst(l);
      81             : 
      82             :         /* Ugh. Somebody ought to write a table driven version -- mjl */
      83             : 
      84       37806 :         if (pg_strcasecmp(tok, "ISO") == 0)
      85             :         {
      86       16574 :             if (have_style && newDateStyle != USE_ISO_DATES)
      87           0 :                 ok = false;     /* conflicting styles */
      88       16574 :             newDateStyle = USE_ISO_DATES;
      89       16574 :             have_style = true;
      90             :         }
      91       21232 :         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       21202 :         else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
      99             :         {
     100        7040 :             if (have_style && newDateStyle != USE_POSTGRES_DATES)
     101           0 :                 ok = false;     /* conflicting styles */
     102        7040 :             newDateStyle = USE_POSTGRES_DATES;
     103        7040 :             have_style = true;
     104             :         }
     105       14162 :         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       14120 :         else if (pg_strcasecmp(tok, "YMD") == 0)
     116             :         {
     117          36 :             if (have_order && newDateOrder != DATEORDER_YMD)
     118           0 :                 ok = false;     /* conflicting orders */
     119          36 :             newDateOrder = DATEORDER_YMD;
     120          36 :             have_order = true;
     121             :         }
     122       28120 :         else if (pg_strcasecmp(tok, "DMY") == 0 ||
     123       14036 :                  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       14036 :         else if (pg_strcasecmp(tok, "MDY") == 0 ||
     131          18 :                  pg_strcasecmp(tok, "US") == 0 ||
     132           0 :                  pg_strncasecmp(tok, "NONEURO", 7) == 0)
     133             :         {
     134       14018 :             if (have_order && newDateOrder != DATEORDER_MDY)
     135           0 :                 ok = false;     /* conflicting orders */
     136       14018 :             newDateOrder = DATEORDER_MDY;
     137       14018 :             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       23736 :     pfree(rawstring);
     181       23736 :     list_free(elemlist);
     182             : 
     183       23736 :     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       23736 :     result = (char *) guc_malloc(LOG, 32);
     193       23736 :     if (!result)
     194           0 :         return false;
     195             : 
     196       23736 :     switch (newDateStyle)
     197             :     {
     198       16598 :         case USE_ISO_DATES:
     199       16598 :             strcpy(result, "ISO");
     200       16598 :             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        7066 :         default:
     208        7066 :             strcpy(result, "Postgres");
     209        7066 :             break;
     210             :     }
     211       23736 :     switch (newDateOrder)
     212             :     {
     213          48 :         case DATEORDER_YMD:
     214          48 :             strcat(result, ", YMD");
     215          48 :             break;
     216          88 :         case DATEORDER_DMY:
     217          88 :             strcat(result, ", DMY");
     218          88 :             break;
     219       23600 :         default:
     220       23600 :             strcat(result, ", MDY");
     221       23600 :             break;
     222             :     }
     223             : 
     224       23736 :     guc_free(*newval);
     225       23736 :     *newval = result;
     226             : 
     227             :     /*
     228             :      * Set up the "extra" struct actually used by assign_datestyle.
     229             :      */
     230       23736 :     myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
     231       23736 :     if (!myextra)
     232           0 :         return false;
     233       23736 :     myextra[0] = newDateStyle;
     234       23736 :     myextra[1] = newDateOrder;
     235       23736 :     *extra = (void *) myextra;
     236             : 
     237       23736 :     return true;
     238             : }
     239             : 
     240             : /*
     241             :  * assign_datestyle: GUC assign_hook for datestyle
     242             :  */
     243             : void
     244       31852 : assign_datestyle(const char *newval, void *extra)
     245             : {
     246       31852 :     int        *myextra = (int *) extra;
     247             : 
     248       31852 :     DateStyle = myextra[0];
     249       31852 :     DateOrder = myextra[1];
     250       31852 : }
     251             : 
     252             : 
     253             : /*
     254             :  * TIMEZONE
     255             :  */
     256             : 
     257             : /*
     258             :  * check_timezone: GUC check_hook for timezone
     259             :  */
     260             : bool
     261       14122 : 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       14122 :     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       14122 :         hours = strtod(*newval, &endptr);
     330       14122 :         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       14050 :             new_tz = pg_tzset(*newval);
     342             : 
     343       14050 :             if (!new_tz)
     344             :             {
     345             :                 /* Doesn't seem to be any great value in errdetail here */
     346           0 :                 return false;
     347             :             }
     348             : 
     349       14050 :             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       14122 :     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       14122 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     370       14122 :     if (!*extra)
     371           0 :         return false;
     372       14122 :     *((pg_tz **) *extra) = new_tz;
     373             : 
     374       14122 :     return true;
     375             : }
     376             : 
     377             : /*
     378             :  * assign_timezone: GUC assign_hook for timezone
     379             :  */
     380             : void
     381       14222 : assign_timezone(const char *newval, void *extra)
     382             : {
     383       14222 :     session_timezone = *((pg_tz **) extra);
     384       14222 : }
     385             : 
     386             : /*
     387             :  * show_timezone: GUC show_hook for timezone
     388             :  */
     389             : const char *
     390       45948 : show_timezone(void)
     391             : {
     392             :     const char *tzn;
     393             : 
     394             :     /* Always show the zone's canonical name */
     395       45948 :     tzn = pg_get_timezone_name(session_timezone);
     396             : 
     397       45948 :     if (tzn != NULL)
     398       45948 :         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        9562 : 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        9562 :     new_tz = pg_tzset(*newval);
     424             : 
     425        9562 :     if (!new_tz)
     426             :     {
     427             :         /* Doesn't seem to be any great value in errdetail here */
     428           0 :         return false;
     429             :     }
     430             : 
     431        9562 :     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        9562 :     *extra = guc_malloc(LOG, sizeof(pg_tz *));
     443        9562 :     if (!*extra)
     444           0 :         return false;
     445        9562 :     *((pg_tz **) *extra) = new_tz;
     446             : 
     447        9562 :     return true;
     448             : }
     449             : 
     450             : /*
     451             :  * assign_log_timezone: GUC assign_hook for log_timezone
     452             :  */
     453             : void
     454        9556 : assign_log_timezone(const char *newval, void *extra)
     455             : {
     456        9556 :     log_timezone = *((pg_tz **) extra);
     457        9556 : }
     458             : 
     459             : /*
     460             :  * show_log_timezone: GUC show_hook for log_timezone
     461             :  */
     462             : const char *
     463        3856 : show_log_timezone(void)
     464             : {
     465             :     const char *tzn;
     466             : 
     467             :     /* Always show the zone's canonical name */
     468        3856 :     tzn = pg_get_timezone_name(log_timezone);
     469             : 
     470        3856 :     if (tzn != NULL)
     471        3856 :         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       16382 : 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       16382 :     if (*newval == NULL)
     498             :     {
     499             :         Assert(source == PGC_S_DEFAULT);
     500        4480 :         return true;
     501             :     }
     502             : 
     503             :     /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
     504       11902 :     *extra = load_tzoffsets(*newval);
     505             : 
     506             :     /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
     507       11902 :     if (!*extra)
     508           0 :         return false;
     509             : 
     510       11902 :     return true;
     511             : }
     512             : 
     513             : /*
     514             :  * GUC assign_hook for assign_timezone_abbreviations
     515             :  */
     516             : void
     517       16204 : assign_timezone_abbreviations(const char *newval, void *extra)
     518             : {
     519             :     /* Do nothing for the boot_val default of NULL */
     520       16204 :     if (!extra)
     521        4480 :         return;
     522             : 
     523       11724 :     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       10332 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
     545             : {
     546       10332 :     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       10314 :     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       15616 : check_transaction_isolation(int *newval, void **extra, GucSource source)
     584             : {
     585       15616 :     int         newXactIsoLevel = *newval;
     586             : 
     587       15616 :     if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
     588             :     {
     589        5790 :         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        5788 :         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        5788 :         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       15614 :     return true;
     613             : }
     614             : 
     615             : /*
     616             :  * SET TRANSACTION [NOT] DEFERRABLE
     617             :  */
     618             : 
     619             : bool
     620        9014 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
     621             : {
     622        9014 :     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        9014 :     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        9014 :     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        1852 : check_random_seed(double *newval, void **extra, GucSource source)
     649             : {
     650        1852 :     *extra = guc_malloc(LOG, sizeof(int));
     651        1852 :     if (!*extra)
     652           0 :         return false;
     653             :     /* Arm the assign only if source of value is an interactive SET */
     654        1852 :     *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
     655             : 
     656        1852 :     return true;
     657             : }
     658             : 
     659             : void
     660        1852 : assign_random_seed(double newval, void *extra)
     661             : {
     662             :     /* We'll do this at most once for any setting of the GUC variable */
     663        1852 :     if (*((int *) extra))
     664           0 :         DirectFunctionCall1(setseed, Float8GetDatum(newval));
     665        1852 :     *((int *) extra) = 0;
     666        1852 : }
     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       32882 : 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       32882 :     encoding = pg_valid_client_encoding(*newval);
     687       32882 :     if (encoding < 0)
     688           0 :         return false;
     689             : 
     690             :     /* Get the canonical name (no aliases, uniform case) */
     691       32882 :     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       32882 :     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       32882 :     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       32882 :     *extra = guc_malloc(LOG, sizeof(int));
     748       32882 :     if (!*extra)
     749           0 :         return false;
     750       32882 :     *((int *) *extra) = encoding;
     751             : 
     752       32882 :     return true;
     753             : }
     754             : 
     755             : void
     756       32694 : assign_client_encoding(const char *newval, void *extra)
     757             : {
     758       32694 :     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       32694 :     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        7884 :         if (InitializingParallelWorker)
     772        7884 :             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       24810 :     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       33808 : 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       33808 :     if (*newval == NULL)
     812        4480 :         return true;
     813             : 
     814       29328 :     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       29328 :     roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     832       29328 :     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       29328 :     roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     846       29328 :     roleid = roleform->oid;
     847       29328 :     is_superuser = roleform->rolsuper;
     848             : 
     849       29328 :     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       29328 :     if (roleid != GetAuthenticatedUserId() &&
     857        2560 :         !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       29328 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
     875       29328 :     if (!myextra)
     876           0 :         return false;
     877       29328 :     myextra->roleid = roleid;
     878       29328 :     myextra->is_superuser = is_superuser;
     879       29328 :     *extra = (void *) myextra;
     880             : 
     881       29328 :     return true;
     882             : }
     883             : 
     884             : void
     885       34732 : assign_session_authorization(const char *newval, void *extra)
     886             : {
     887       34732 :     role_auth_extra *myextra = (role_auth_extra *) extra;
     888             : 
     889             :     /* Do nothing for the boot_val default of NULL */
     890       34732 :     if (!myextra)
     891        4480 :         return;
     892             : 
     893       30252 :     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             : 
     905             : bool
     906        2698 : check_role(char **newval, void **extra, GucSource source)
     907             : {
     908             :     HeapTuple   roleTup;
     909             :     Oid         roleid;
     910             :     bool        is_superuser;
     911             :     role_auth_extra *myextra;
     912             :     Form_pg_authid roleform;
     913             : 
     914        2698 :     if (strcmp(*newval, "none") == 0)
     915             :     {
     916             :         /* hardwired translation */
     917        1852 :         roleid = InvalidOid;
     918        1852 :         is_superuser = false;
     919             :     }
     920             :     else
     921             :     {
     922         846 :         if (!IsTransactionState())
     923             :         {
     924             :             /*
     925             :              * Can't do catalog lookups, so fail.  The result of this is that
     926             :              * role cannot be set in postgresql.conf, which seems like a good
     927             :              * thing anyway, so we don't work hard to avoid it.
     928             :              */
     929           0 :             return false;
     930             :         }
     931             : 
     932             :         /*
     933             :          * When source == PGC_S_TEST, we don't throw a hard error for a
     934             :          * nonexistent user name or insufficient privileges, only a NOTICE.
     935             :          * See comments in guc.h.
     936             :          */
     937             : 
     938             :         /* Look up the username */
     939         846 :         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     940         846 :         if (!HeapTupleIsValid(roleTup))
     941             :         {
     942           0 :             if (source == PGC_S_TEST)
     943             :             {
     944           0 :                 ereport(NOTICE,
     945             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
     946             :                          errmsg("role \"%s\" does not exist", *newval)));
     947           0 :                 return true;
     948             :             }
     949           0 :             GUC_check_errmsg("role \"%s\" does not exist", *newval);
     950           0 :             return false;
     951             :         }
     952             : 
     953         846 :         roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     954         846 :         roleid = roleform->oid;
     955         846 :         is_superuser = roleform->rolsuper;
     956             : 
     957         846 :         ReleaseSysCache(roleTup);
     958             : 
     959             :         /*
     960             :          * Verify that session user is allowed to become this role, but skip
     961             :          * this in parallel mode, where we must blindly recreate the parallel
     962             :          * leader's state.
     963             :          */
     964         846 :         if (!InitializingParallelWorker &&
     965         846 :             !member_can_set_role(GetSessionUserId(), roleid))
     966             :         {
     967          12 :             if (source == PGC_S_TEST)
     968             :             {
     969           0 :                 ereport(NOTICE,
     970             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     971             :                          errmsg("permission will be denied to set role \"%s\"",
     972             :                                 *newval)));
     973           0 :                 return true;
     974             :             }
     975          12 :             GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
     976          12 :             GUC_check_errmsg("permission denied to set role \"%s\"",
     977             :                              *newval);
     978          12 :             return false;
     979             :         }
     980             :     }
     981             : 
     982             :     /* Set up "extra" struct for assign_role to use */
     983        2686 :     myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
     984        2686 :     if (!myextra)
     985           0 :         return false;
     986        2686 :     myextra->roleid = roleid;
     987        2686 :     myextra->is_superuser = is_superuser;
     988        2686 :     *extra = (void *) myextra;
     989             : 
     990        2686 :     return true;
     991             : }
     992             : 
     993             : void
     994        3290 : assign_role(const char *newval, void *extra)
     995             : {
     996        3290 :     role_auth_extra *myextra = (role_auth_extra *) extra;
     997             : 
     998        3290 :     SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
     999        3290 : }
    1000             : 
    1001             : const char *
    1002           0 : show_role(void)
    1003             : {
    1004             :     /*
    1005             :      * Check whether SET ROLE is active; if not return "none".  This is a
    1006             :      * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
    1007             :      * resets SET ROLE to NONE, but we cannot set the GUC role variable from
    1008             :      * assign_session_authorization (because we haven't got enough info to
    1009             :      * call set_config_option).
    1010             :      */
    1011           0 :     if (!OidIsValid(GetCurrentRoleId()))
    1012           0 :         return "none";
    1013             : 
    1014             :     /* Otherwise we can just use the GUC string */
    1015           0 :     return role_string ? role_string : "none";
    1016             : }
    1017             : 
    1018             : 
    1019             : /*
    1020             :  * PATH VARIABLES
    1021             :  *
    1022             :  * check_canonical_path is used for log_directory and some other GUCs where
    1023             :  * all we want to do is canonicalize the represented path name.
    1024             :  */
    1025             : 
    1026             : bool
    1027        3704 : check_canonical_path(char **newval, void **extra, GucSource source)
    1028             : {
    1029             :     /*
    1030             :      * Since canonicalize_path never enlarges the string, we can just modify
    1031             :      * newval in-place.  But watch out for NULL, which is the default value
    1032             :      * for external_pid_file.
    1033             :      */
    1034        3704 :     if (*newval)
    1035        1852 :         canonicalize_path(*newval);
    1036        3704 :     return true;
    1037             : }
    1038             : 
    1039             : 
    1040             : /*
    1041             :  * MISCELLANEOUS
    1042             :  */
    1043             : 
    1044             : /*
    1045             :  * GUC check_hook for application_name
    1046             :  */
    1047             : bool
    1048       26196 : check_application_name(char **newval, void **extra, GucSource source)
    1049             : {
    1050             :     char       *clean;
    1051             :     char       *ret;
    1052             : 
    1053             :     /* Only allow clean ASCII chars in the application name */
    1054       26196 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1055       26196 :     if (!clean)
    1056           0 :         return false;
    1057             : 
    1058       26196 :     ret = guc_strdup(WARNING, clean);
    1059       26196 :     if (!ret)
    1060             :     {
    1061           0 :         pfree(clean);
    1062           0 :         return false;
    1063             :     }
    1064             : 
    1065       26196 :     pfree(clean);
    1066       26196 :     *newval = ret;
    1067       26196 :     return true;
    1068             : }
    1069             : 
    1070             : /*
    1071             :  * GUC assign_hook for application_name
    1072             :  */
    1073             : void
    1074       26168 : assign_application_name(const char *newval, void *extra)
    1075             : {
    1076             :     /* Update the pg_stat_activity view */
    1077       26168 :     pgstat_report_appname(newval);
    1078       26168 : }
    1079             : 
    1080             : /*
    1081             :  * GUC check_hook for cluster_name
    1082             :  */
    1083             : bool
    1084        3056 : check_cluster_name(char **newval, void **extra, GucSource source)
    1085             : {
    1086             :     char       *clean;
    1087             :     char       *ret;
    1088             : 
    1089             :     /* Only allow clean ASCII chars in the cluster name */
    1090        3056 :     clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1091        3056 :     if (!clean)
    1092           0 :         return false;
    1093             : 
    1094        3056 :     ret = guc_strdup(WARNING, clean);
    1095        3056 :     if (!ret)
    1096             :     {
    1097           0 :         pfree(clean);
    1098           0 :         return false;
    1099             :     }
    1100             : 
    1101        3056 :     pfree(clean);
    1102        3056 :     *newval = ret;
    1103        3056 :     return true;
    1104             : }
    1105             : 
    1106             : /*
    1107             :  * GUC assign_hook for maintenance_io_concurrency
    1108             :  */
    1109             : void
    1110        1852 : assign_maintenance_io_concurrency(int newval, void *extra)
    1111             : {
    1112             : #ifdef USE_PREFETCH
    1113             :     /*
    1114             :      * Reconfigure recovery prefetching, because a setting it depends on
    1115             :      * changed.
    1116             :      */
    1117        1852 :     maintenance_io_concurrency = newval;
    1118        1852 :     if (AmStartupProcess())
    1119           0 :         XLogPrefetchReconfigure();
    1120             : #endif
    1121        1852 : }
    1122             : 
    1123             : 
    1124             : /*
    1125             :  * These show hooks just exist because we want to show the values in octal.
    1126             :  */
    1127             : 
    1128             : /*
    1129             :  * GUC show_hook for data_directory_mode
    1130             :  */
    1131             : const char *
    1132        4528 : show_data_directory_mode(void)
    1133             : {
    1134             :     static char buf[12];
    1135             : 
    1136        4528 :     snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
    1137        4528 :     return buf;
    1138             : }
    1139             : 
    1140             : /*
    1141             :  * GUC show_hook for log_file_mode
    1142             :  */
    1143             : const char *
    1144        3856 : show_log_file_mode(void)
    1145             : {
    1146             :     static char buf[12];
    1147             : 
    1148        3856 :     snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
    1149        3856 :     return buf;
    1150             : }
    1151             : 
    1152             : /*
    1153             :  * GUC show_hook for unix_socket_permissions
    1154             :  */
    1155             : const char *
    1156        3856 : show_unix_socket_permissions(void)
    1157             : {
    1158             :     static char buf[12];
    1159             : 
    1160        3856 :     snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
    1161        3856 :     return buf;
    1162             : }
    1163             : 
    1164             : 
    1165             : /*
    1166             :  * These check hooks do nothing more than reject non-default settings
    1167             :  * in builds that don't support them.
    1168             :  */
    1169             : 
    1170             : bool
    1171        1852 : check_bonjour(bool *newval, void **extra, GucSource source)
    1172             : {
    1173             : #ifndef USE_BONJOUR
    1174        1852 :     if (*newval)
    1175             :     {
    1176           0 :         GUC_check_errmsg("Bonjour is not supported by this build");
    1177           0 :         return false;
    1178             :     }
    1179             : #endif
    1180        1852 :     return true;
    1181             : }
    1182             : 
    1183             : bool
    1184        1864 : check_default_with_oids(bool *newval, void **extra, GucSource source)
    1185             : {
    1186        1864 :     if (*newval)
    1187             :     {
    1188             :         /* check the GUC's definition for an explanation */
    1189           6 :         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1190           6 :         GUC_check_errmsg("tables declared WITH OIDS are not supported");
    1191             : 
    1192           6 :         return false;
    1193             :     }
    1194             : 
    1195        1858 :     return true;
    1196             : }
    1197             : 
    1198             : bool
    1199        2446 : check_effective_io_concurrency(int *newval, void **extra, GucSource source)
    1200             : {
    1201             : #ifndef USE_PREFETCH
    1202             :     if (*newval != 0)
    1203             :     {
    1204             :         GUC_check_errdetail("\"effective_io_concurrency\" must be set to 0 on platforms that lack posix_fadvise().");
    1205             :         return false;
    1206             :     }
    1207             : #endif                          /* USE_PREFETCH */
    1208        2446 :     return true;
    1209             : }
    1210             : 
    1211             : bool
    1212        1852 : check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
    1213             : {
    1214             : #ifndef USE_PREFETCH
    1215             :     if (*newval != 0)
    1216             :     {
    1217             :         GUC_check_errdetail("\"maintenance_io_concurrency\" must be set to 0 on platforms that lack posix_fadvise().");
    1218             :         return false;
    1219             :     }
    1220             : #endif                          /* USE_PREFETCH */
    1221        1852 :     return true;
    1222             : }
    1223             : 
    1224             : bool
    1225        1904 : check_ssl(bool *newval, void **extra, GucSource source)
    1226             : {
    1227             : #ifndef USE_SSL
    1228             :     if (*newval)
    1229             :     {
    1230             :         GUC_check_errmsg("SSL is not supported by this build");
    1231             :         return false;
    1232             :     }
    1233             : #endif
    1234        1904 :     return true;
    1235             : }

Generated by: LCOV version 1.14