LCOV - code coverage report
Current view: top level - src/backend/commands - variable.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 516 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 37 0
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 0.0 % 279 0

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * variable.c
       4                 :             :  *              Routines for handling specialized SET variables.
       5                 :             :  *
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  *
      11                 :             :  * IDENTIFICATION
      12                 :             :  *        src/backend/commands/variable.c
      13                 :             :  *
      14                 :             :  *-------------------------------------------------------------------------
      15                 :             :  */
      16                 :             : 
      17                 :             : #include "postgres.h"
      18                 :             : 
      19                 :             : #include <ctype.h>
      20                 :             : 
      21                 :             : #include "access/htup_details.h"
      22                 :             : #include "access/parallel.h"
      23                 :             : #include "access/xact.h"
      24                 :             : #include "access/xlog.h"
      25                 :             : #include "access/xlogprefetcher.h"
      26                 :             : #include "catalog/pg_authid.h"
      27                 :             : #include "common/string.h"
      28                 :             : #include "mb/pg_wchar.h"
      29                 :             : #include "miscadmin.h"
      30                 :             : #include "postmaster/postmaster.h"
      31                 :             : #include "postmaster/syslogger.h"
      32                 :             : #include "storage/bufmgr.h"
      33                 :             : #include "utils/acl.h"
      34                 :             : #include "utils/backend_status.h"
      35                 :             : #include "utils/datetime.h"
      36                 :             : #include "utils/fmgrprotos.h"
      37                 :             : #include "utils/guc_hooks.h"
      38                 :             : #include "utils/snapmgr.h"
      39                 :             : #include "utils/syscache.h"
      40                 :             : #include "utils/timestamp.h"
      41                 :             : #include "utils/tzparser.h"
      42                 :             : #include "utils/varlena.h"
      43                 :             : 
      44                 :             : /*
      45                 :             :  * DATESTYLE
      46                 :             :  */
      47                 :             : 
      48                 :             : /*
      49                 :             :  * check_datestyle: GUC check_hook for datestyle
      50                 :             :  */
      51                 :             : bool
      52                 :           0 : check_datestyle(char **newval, void **extra, GucSource source)
      53                 :             : {
      54                 :           0 :         int                     newDateStyle = DateStyle;
      55                 :           0 :         int                     newDateOrder = DateOrder;
      56                 :           0 :         bool            have_style = false;
      57                 :           0 :         bool            have_order = false;
      58                 :           0 :         bool            ok = true;
      59                 :           0 :         char       *rawstring;
      60                 :           0 :         int                *myextra;
      61                 :           0 :         char       *result;
      62                 :           0 :         List       *elemlist;
      63                 :           0 :         ListCell   *l;
      64                 :             : 
      65                 :             :         /* Need a modifiable copy of string */
      66                 :           0 :         rawstring = pstrdup(*newval);
      67                 :             : 
      68                 :             :         /* Parse string into list of identifiers */
      69         [ #  # ]:           0 :         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   [ #  #  #  #  :           0 :         foreach(l, elemlist)
             #  #  #  # ]
      79                 :             :         {
      80                 :           0 :                 char       *tok = (char *) lfirst(l);
      81                 :             : 
      82                 :             :                 /* Ugh. Somebody ought to write a table driven version -- mjl */
      83                 :             : 
      84         [ #  # ]:           0 :                 if (pg_strcasecmp(tok, "ISO") == 0)
      85                 :             :                 {
      86   [ #  #  #  # ]:           0 :                         if (have_style && newDateStyle != USE_ISO_DATES)
      87                 :           0 :                                 ok = false;             /* conflicting styles */
      88                 :           0 :                         newDateStyle = USE_ISO_DATES;
      89                 :           0 :                         have_style = true;
      90                 :           0 :                 }
      91         [ #  # ]:           0 :                 else if (pg_strcasecmp(tok, "SQL") == 0)
      92                 :             :                 {
      93   [ #  #  #  # ]:           0 :                         if (have_style && newDateStyle != USE_SQL_DATES)
      94                 :           0 :                                 ok = false;             /* conflicting styles */
      95                 :           0 :                         newDateStyle = USE_SQL_DATES;
      96                 :           0 :                         have_style = true;
      97                 :           0 :                 }
      98         [ #  # ]:           0 :                 else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
      99                 :             :                 {
     100   [ #  #  #  # ]:           0 :                         if (have_style && newDateStyle != USE_POSTGRES_DATES)
     101                 :           0 :                                 ok = false;             /* conflicting styles */
     102                 :           0 :                         newDateStyle = USE_POSTGRES_DATES;
     103                 :           0 :                         have_style = true;
     104                 :           0 :                 }
     105         [ #  # ]:           0 :                 else if (pg_strcasecmp(tok, "GERMAN") == 0)
     106                 :             :                 {
     107   [ #  #  #  # ]:           0 :                         if (have_style && newDateStyle != USE_GERMAN_DATES)
     108                 :           0 :                                 ok = false;             /* conflicting styles */
     109                 :           0 :                         newDateStyle = USE_GERMAN_DATES;
     110                 :           0 :                         have_style = true;
     111                 :             :                         /* GERMAN also sets DMY, unless explicitly overridden */
     112         [ #  # ]:           0 :                         if (!have_order)
     113                 :           0 :                                 newDateOrder = DATEORDER_DMY;
     114                 :           0 :                 }
     115         [ #  # ]:           0 :                 else if (pg_strcasecmp(tok, "YMD") == 0)
     116                 :             :                 {
     117   [ #  #  #  # ]:           0 :                         if (have_order && newDateOrder != DATEORDER_YMD)
     118                 :           0 :                                 ok = false;             /* conflicting orders */
     119                 :           0 :                         newDateOrder = DATEORDER_YMD;
     120                 :           0 :                         have_order = true;
     121                 :           0 :                 }
     122   [ #  #  #  # ]:           0 :                 else if (pg_strcasecmp(tok, "DMY") == 0 ||
     123                 :           0 :                                  pg_strncasecmp(tok, "EURO", 4) == 0)
     124                 :             :                 {
     125   [ #  #  #  # ]:           0 :                         if (have_order && newDateOrder != DATEORDER_DMY)
     126                 :           0 :                                 ok = false;             /* conflicting orders */
     127                 :           0 :                         newDateOrder = DATEORDER_DMY;
     128                 :           0 :                         have_order = true;
     129                 :           0 :                 }
     130         [ #  # ]:           0 :                 else if (pg_strcasecmp(tok, "MDY") == 0 ||
     131   [ #  #  #  # ]:           0 :                                  pg_strcasecmp(tok, "US") == 0 ||
     132                 :           0 :                                  pg_strncasecmp(tok, "NONEURO", 7) == 0)
     133                 :             :                 {
     134   [ #  #  #  # ]:           0 :                         if (have_order && newDateOrder != DATEORDER_MDY)
     135                 :           0 :                                 ok = false;             /* conflicting orders */
     136                 :           0 :                         newDateOrder = DATEORDER_MDY;
     137                 :           0 :                         have_order = true;
     138                 :           0 :                 }
     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                 :           0 :                         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         [ #  # ]:           0 :                 }
     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         [ #  # ]:           0 :         }
     179                 :             : 
     180                 :           0 :         pfree(rawstring);
     181                 :           0 :         list_free(elemlist);
     182                 :             : 
     183         [ #  # ]:           0 :         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                 :           0 :         result = (char *) guc_malloc(LOG, 32);
     193         [ #  # ]:           0 :         if (!result)
     194                 :           0 :                 return false;
     195                 :             : 
     196   [ #  #  #  # ]:           0 :         switch (newDateStyle)
     197                 :             :         {
     198                 :             :                 case USE_ISO_DATES:
     199                 :           0 :                         strcpy(result, "ISO");
     200                 :           0 :                         break;
     201                 :             :                 case USE_SQL_DATES:
     202                 :           0 :                         strcpy(result, "SQL");
     203                 :           0 :                         break;
     204                 :             :                 case USE_GERMAN_DATES:
     205                 :           0 :                         strcpy(result, "German");
     206                 :           0 :                         break;
     207                 :             :                 default:
     208                 :           0 :                         strcpy(result, "Postgres");
     209                 :           0 :                         break;
     210                 :             :         }
     211      [ #  #  # ]:           0 :         switch (newDateOrder)
     212                 :             :         {
     213                 :             :                 case DATEORDER_YMD:
     214                 :           0 :                         strcat(result, ", YMD");
     215                 :           0 :                         break;
     216                 :             :                 case DATEORDER_DMY:
     217                 :           0 :                         strcat(result, ", DMY");
     218                 :           0 :                         break;
     219                 :             :                 default:
     220                 :           0 :                         strcat(result, ", MDY");
     221                 :           0 :                         break;
     222                 :             :         }
     223                 :             : 
     224                 :           0 :         guc_free(*newval);
     225                 :           0 :         *newval = result;
     226                 :             : 
     227                 :             :         /*
     228                 :             :          * Set up the "extra" struct actually used by assign_datestyle.
     229                 :             :          */
     230                 :           0 :         myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
     231         [ #  # ]:           0 :         if (!myextra)
     232                 :           0 :                 return false;
     233                 :           0 :         myextra[0] = newDateStyle;
     234                 :           0 :         myextra[1] = newDateOrder;
     235                 :           0 :         *extra = myextra;
     236                 :             : 
     237                 :           0 :         return true;
     238                 :           0 : }
     239                 :             : 
     240                 :             : /*
     241                 :             :  * assign_datestyle: GUC assign_hook for datestyle
     242                 :             :  */
     243                 :             : void
     244                 :           0 : assign_datestyle(const char *newval, void *extra)
     245                 :             : {
     246                 :           0 :         int                *myextra = (int *) extra;
     247                 :             : 
     248                 :           0 :         DateStyle = myextra[0];
     249                 :           0 :         DateOrder = myextra[1];
     250                 :           0 : }
     251                 :             : 
     252                 :             : 
     253                 :             : /*
     254                 :             :  * TIMEZONE
     255                 :             :  */
     256                 :             : 
     257                 :             : /*
     258                 :             :  * check_timezone: GUC check_hook for timezone
     259                 :             :  */
     260                 :             : bool
     261                 :           0 : check_timezone(char **newval, void **extra, GucSource source)
     262                 :             : {
     263                 :           0 :         pg_tz      *new_tz;
     264                 :           0 :         long            gmtoffset;
     265                 :           0 :         char       *endptr;
     266                 :           0 :         double          hours;
     267                 :             : 
     268         [ #  # ]:           0 :         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                 :           0 :                 char       *val;
     276                 :           0 :                 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         [ #  # ]:           0 :         }
     324                 :             :         else
     325                 :             :         {
     326                 :             :                 /*
     327                 :             :                  * Try it as a numeric number of hours (possibly fractional).
     328                 :             :                  */
     329                 :           0 :                 hours = strtod(*newval, &endptr);
     330   [ #  #  #  # ]:           0 :                 if (endptr != *newval && *endptr == '\0')
     331                 :             :                 {
     332                 :             :                         /* Here we change from SQL to Unix sign convention */
     333                 :           0 :                         gmtoffset = -hours * SECS_PER_HOUR;
     334                 :           0 :                         new_tz = pg_tzset_offset(gmtoffset);
     335                 :           0 :                 }
     336                 :             :                 else
     337                 :             :                 {
     338                 :             :                         /*
     339                 :             :                          * Otherwise assume it is a timezone name, and try to load it.
     340                 :             :                          */
     341                 :           0 :                         new_tz = pg_tzset(*newval);
     342                 :             : 
     343         [ #  # ]:           0 :                         if (!new_tz)
     344                 :             :                         {
     345                 :             :                                 /* Doesn't seem to be any great value in errdetail here */
     346                 :           0 :                                 return false;
     347                 :             :                         }
     348                 :             : 
     349         [ #  # ]:           0 :                         if (!pg_tz_acceptable(new_tz))
     350                 :             :                         {
     351                 :           0 :                                 GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
     352                 :           0 :                                                                  *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         [ #  # ]:           0 :         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                 :           0 :         *extra = guc_malloc(LOG, sizeof(pg_tz *));
     370         [ #  # ]:           0 :         if (!*extra)
     371                 :           0 :                 return false;
     372                 :           0 :         *((pg_tz **) *extra) = new_tz;
     373                 :             : 
     374                 :           0 :         return true;
     375                 :           0 : }
     376                 :             : 
     377                 :             : /*
     378                 :             :  * assign_timezone: GUC assign_hook for timezone
     379                 :             :  */
     380                 :             : void
     381                 :           0 : assign_timezone(const char *newval, void *extra)
     382                 :             : {
     383                 :           0 :         session_timezone = *((pg_tz **) extra);
     384                 :             :         /* datetime.c's cache of timezone abbrevs may now be obsolete */
     385                 :           0 :         ClearTimeZoneAbbrevCache();
     386                 :           0 : }
     387                 :             : 
     388                 :             : /*
     389                 :             :  * show_timezone: GUC show_hook for timezone
     390                 :             :  */
     391                 :             : const char *
     392                 :           0 : show_timezone(void)
     393                 :             : {
     394                 :           0 :         const char *tzn;
     395                 :             : 
     396                 :             :         /* Always show the zone's canonical name */
     397                 :           0 :         tzn = pg_get_timezone_name(session_timezone);
     398                 :             : 
     399         [ #  # ]:           0 :         if (tzn != NULL)
     400                 :           0 :                 return tzn;
     401                 :             : 
     402                 :           0 :         return "unknown";
     403                 :           0 : }
     404                 :             : 
     405                 :             : 
     406                 :             : /*
     407                 :             :  * LOG_TIMEZONE
     408                 :             :  *
     409                 :             :  * For log_timezone, we don't support the interval-based methods of setting a
     410                 :             :  * zone, which are only there for SQL spec compliance not because they're
     411                 :             :  * actually useful.
     412                 :             :  */
     413                 :             : 
     414                 :             : /*
     415                 :             :  * check_log_timezone: GUC check_hook for log_timezone
     416                 :             :  */
     417                 :             : bool
     418                 :           0 : check_log_timezone(char **newval, void **extra, GucSource source)
     419                 :             : {
     420                 :           0 :         pg_tz      *new_tz;
     421                 :             : 
     422                 :             :         /*
     423                 :             :          * Assume it is a timezone name, and try to load it.
     424                 :             :          */
     425                 :           0 :         new_tz = pg_tzset(*newval);
     426                 :             : 
     427         [ #  # ]:           0 :         if (!new_tz)
     428                 :             :         {
     429                 :             :                 /* Doesn't seem to be any great value in errdetail here */
     430                 :           0 :                 return false;
     431                 :             :         }
     432                 :             : 
     433         [ #  # ]:           0 :         if (!pg_tz_acceptable(new_tz))
     434                 :             :         {
     435                 :           0 :                 GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
     436                 :           0 :                                                  *newval);
     437                 :           0 :                 GUC_check_errdetail("PostgreSQL does not support leap seconds.");
     438                 :           0 :                 return false;
     439                 :             :         }
     440                 :             : 
     441                 :             :         /*
     442                 :             :          * Pass back data for assign_log_timezone to use
     443                 :             :          */
     444                 :           0 :         *extra = guc_malloc(LOG, sizeof(pg_tz *));
     445         [ #  # ]:           0 :         if (!*extra)
     446                 :           0 :                 return false;
     447                 :           0 :         *((pg_tz **) *extra) = new_tz;
     448                 :             : 
     449                 :           0 :         return true;
     450                 :           0 : }
     451                 :             : 
     452                 :             : /*
     453                 :             :  * assign_log_timezone: GUC assign_hook for log_timezone
     454                 :             :  */
     455                 :             : void
     456                 :           0 : assign_log_timezone(const char *newval, void *extra)
     457                 :             : {
     458                 :           0 :         log_timezone = *((pg_tz **) extra);
     459                 :           0 : }
     460                 :             : 
     461                 :             : /*
     462                 :             :  * show_log_timezone: GUC show_hook for log_timezone
     463                 :             :  */
     464                 :             : const char *
     465                 :           0 : show_log_timezone(void)
     466                 :             : {
     467                 :           0 :         const char *tzn;
     468                 :             : 
     469                 :             :         /* Always show the zone's canonical name */
     470                 :           0 :         tzn = pg_get_timezone_name(log_timezone);
     471                 :             : 
     472         [ #  # ]:           0 :         if (tzn != NULL)
     473                 :           0 :                 return tzn;
     474                 :             : 
     475                 :           0 :         return "unknown";
     476                 :           0 : }
     477                 :             : 
     478                 :             : 
     479                 :             : /*
     480                 :             :  * TIMEZONE_ABBREVIATIONS
     481                 :             :  */
     482                 :             : 
     483                 :             : /*
     484                 :             :  * GUC check_hook for timezone_abbreviations
     485                 :             :  */
     486                 :             : bool
     487                 :           0 : check_timezone_abbreviations(char **newval, void **extra, GucSource source)
     488                 :             : {
     489                 :             :         /*
     490                 :             :          * The boot_val for timezone_abbreviations is NULL.  When we see that we
     491                 :             :          * just do nothing.  If the value isn't overridden from the config file
     492                 :             :          * then pg_timezone_abbrev_initialize() will eventually replace it with
     493                 :             :          * "Default".  This hack has two purposes: to avoid wasting cycles loading
     494                 :             :          * values that might soon be overridden from the config file, and to avoid
     495                 :             :          * trying to read the timezone abbrev files during InitializeGUCOptions().
     496                 :             :          * The latter doesn't work in an EXEC_BACKEND subprocess because
     497                 :             :          * my_exec_path hasn't been set yet and so we can't locate PGSHAREDIR.
     498                 :             :          */
     499         [ #  # ]:           0 :         if (*newval == NULL)
     500                 :             :         {
     501         [ #  # ]:           0 :                 Assert(source == PGC_S_DEFAULT);
     502                 :           0 :                 return true;
     503                 :             :         }
     504                 :             : 
     505                 :             :         /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
     506                 :           0 :         *extra = load_tzoffsets(*newval);
     507                 :             : 
     508                 :             :         /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
     509         [ #  # ]:           0 :         if (!*extra)
     510                 :           0 :                 return false;
     511                 :             : 
     512                 :           0 :         return true;
     513                 :           0 : }
     514                 :             : 
     515                 :             : /*
     516                 :             :  * GUC assign_hook for timezone_abbreviations
     517                 :             :  */
     518                 :             : void
     519                 :           0 : assign_timezone_abbreviations(const char *newval, void *extra)
     520                 :             : {
     521                 :             :         /* Do nothing for the boot_val default of NULL */
     522         [ #  # ]:           0 :         if (!extra)
     523                 :           0 :                 return;
     524                 :             : 
     525                 :           0 :         InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
     526                 :           0 : }
     527                 :             : 
     528                 :             : 
     529                 :             : /*
     530                 :             :  * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
     531                 :             :  *
     532                 :             :  * We allow idempotent changes (r/w -> r/w and r/o -> r/o) at any time, and
     533                 :             :  * we also always allow changes from read-write to read-only.  However,
     534                 :             :  * read-only may be changed to read-write only when in a top-level transaction
     535                 :             :  * that has not yet taken an initial snapshot.  Can't do it in a hot standby,
     536                 :             :  * either.
     537                 :             :  *
     538                 :             :  * If we are not in a transaction at all, just allow the change; it means
     539                 :             :  * nothing since XactReadOnly will be reset by the next StartTransaction().
     540                 :             :  * The IsTransactionState() test protects us against trying to check
     541                 :             :  * RecoveryInProgress() in contexts where shared memory is not accessible.
     542                 :             :  * (Similarly, if we're restoring state in a parallel worker, just allow
     543                 :             :  * the change.)
     544                 :             :  */
     545                 :             : bool
     546                 :           0 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
     547                 :             : {
     548   [ #  #  #  #  :           0 :         if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
             #  #  #  # ]
     549                 :             :         {
     550                 :             :                 /* Can't go to r/w mode inside a r/o transaction */
     551         [ #  # ]:           0 :                 if (IsSubTransaction())
     552                 :             :                 {
     553                 :           0 :                         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     554                 :           0 :                         GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
     555                 :           0 :                         return false;
     556                 :             :                 }
     557                 :             :                 /* Top level transaction can't change to r/w after first snapshot. */
     558         [ #  # ]:           0 :                 if (FirstSnapshotSet)
     559                 :             :                 {
     560                 :           0 :                         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     561                 :           0 :                         GUC_check_errmsg("transaction read-write mode must be set before any query");
     562                 :           0 :                         return false;
     563                 :             :                 }
     564                 :             :                 /* Can't go to r/w mode while recovery is still active */
     565         [ #  # ]:           0 :                 if (RecoveryInProgress())
     566                 :             :                 {
     567                 :           0 :                         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     568                 :           0 :                         GUC_check_errmsg("cannot set transaction read-write mode during recovery");
     569                 :           0 :                         return false;
     570                 :             :                 }
     571                 :           0 :         }
     572                 :             : 
     573                 :           0 :         return true;
     574                 :           0 : }
     575                 :             : 
     576                 :             : /*
     577                 :             :  * SET TRANSACTION ISOLATION LEVEL
     578                 :             :  *
     579                 :             :  * We allow idempotent changes at any time, but otherwise this can only be
     580                 :             :  * changed in a toplevel transaction that has not yet taken a snapshot.
     581                 :             :  *
     582                 :             :  * As in check_transaction_read_only, allow it if not inside a transaction,
     583                 :             :  * or if restoring state in a parallel worker.
     584                 :             :  */
     585                 :             : bool
     586                 :           0 : check_transaction_isolation(int *newval, void **extra, GucSource source)
     587                 :             : {
     588                 :           0 :         int                     newXactIsoLevel = *newval;
     589                 :             : 
     590         [ #  # ]:           0 :         if (newXactIsoLevel != XactIsoLevel &&
     591   [ #  #  #  # ]:           0 :                 IsTransactionState() && !InitializingParallelWorker)
     592                 :             :         {
     593         [ #  # ]:           0 :                 if (FirstSnapshotSet)
     594                 :             :                 {
     595                 :           0 :                         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     596                 :           0 :                         GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
     597                 :           0 :                         return false;
     598                 :             :                 }
     599                 :             :                 /* We ignore a subtransaction setting it to the existing value. */
     600         [ #  # ]:           0 :                 if (IsSubTransaction())
     601                 :             :                 {
     602                 :           0 :                         GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     603                 :           0 :                         GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
     604                 :           0 :                         return false;
     605                 :             :                 }
     606                 :             :                 /* Can't go to serializable mode while recovery is still active */
     607   [ #  #  #  # ]:           0 :                 if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
     608                 :             :                 {
     609                 :           0 :                         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     610                 :           0 :                         GUC_check_errmsg("cannot use serializable mode in a hot standby");
     611                 :           0 :                         GUC_check_errhint("You can use REPEATABLE READ instead.");
     612                 :           0 :                         return false;
     613                 :             :                 }
     614                 :           0 :         }
     615                 :             : 
     616                 :           0 :         return true;
     617                 :           0 : }
     618                 :             : 
     619                 :             : /*
     620                 :             :  * SET TRANSACTION [NOT] DEFERRABLE
     621                 :             :  */
     622                 :             : 
     623                 :             : bool
     624                 :           0 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
     625                 :             : {
     626                 :             :         /* Just accept the value when restoring state in a parallel worker */
     627         [ #  # ]:           0 :         if (InitializingParallelWorker)
     628                 :           0 :                 return true;
     629                 :             : 
     630         [ #  # ]:           0 :         if (IsSubTransaction())
     631                 :             :         {
     632                 :           0 :                 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     633                 :           0 :                 GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
     634                 :           0 :                 return false;
     635                 :             :         }
     636         [ #  # ]:           0 :         if (FirstSnapshotSet)
     637                 :             :         {
     638                 :           0 :                 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
     639                 :           0 :                 GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
     640                 :           0 :                 return false;
     641                 :             :         }
     642                 :             : 
     643                 :           0 :         return true;
     644                 :           0 : }
     645                 :             : 
     646                 :             : /*
     647                 :             :  * Random number seed
     648                 :             :  *
     649                 :             :  * We can't roll back the random sequence on error, and we don't want
     650                 :             :  * config file reloads to affect it, so we only want interactive SET SEED
     651                 :             :  * commands to set it.  We use the "extra" storage to ensure that rollbacks
     652                 :             :  * don't try to do the operation again.
     653                 :             :  */
     654                 :             : 
     655                 :             : bool
     656                 :           0 : check_random_seed(double *newval, void **extra, GucSource source)
     657                 :             : {
     658                 :           0 :         *extra = guc_malloc(LOG, sizeof(int));
     659         [ #  # ]:           0 :         if (!*extra)
     660                 :           0 :                 return false;
     661                 :             :         /* Arm the assign only if source of value is an interactive SET */
     662                 :           0 :         *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
     663                 :             : 
     664                 :           0 :         return true;
     665                 :           0 : }
     666                 :             : 
     667                 :             : void
     668                 :           0 : assign_random_seed(double newval, void *extra)
     669                 :             : {
     670                 :             :         /* We'll do this at most once for any setting of the GUC variable */
     671         [ #  # ]:           0 :         if (*((int *) extra))
     672                 :           0 :                 DirectFunctionCall1(setseed, Float8GetDatum(newval));
     673                 :           0 :         *((int *) extra) = 0;
     674                 :           0 : }
     675                 :             : 
     676                 :             : const char *
     677                 :           0 : show_random_seed(void)
     678                 :             : {
     679                 :           0 :         return "unavailable";
     680                 :             : }
     681                 :             : 
     682                 :             : 
     683                 :             : /*
     684                 :             :  * SET CLIENT_ENCODING
     685                 :             :  */
     686                 :             : 
     687                 :             : bool
     688                 :           0 : check_client_encoding(char **newval, void **extra, GucSource source)
     689                 :             : {
     690                 :           0 :         int                     encoding;
     691                 :           0 :         const char *canonical_name;
     692                 :             : 
     693                 :             :         /* Look up the encoding by name */
     694                 :           0 :         encoding = pg_valid_client_encoding(*newval);
     695         [ #  # ]:           0 :         if (encoding < 0)
     696                 :           0 :                 return false;
     697                 :             : 
     698                 :             :         /* Get the canonical name (no aliases, uniform case) */
     699                 :           0 :         canonical_name = pg_encoding_to_char(encoding);
     700                 :             : 
     701                 :             :         /*
     702                 :             :          * Parallel workers send data to the leader, not the client.  They always
     703                 :             :          * send data using the database encoding; therefore, we should never
     704                 :             :          * actually change the client encoding in a parallel worker.  However,
     705                 :             :          * during parallel worker startup, we want to accept the leader's
     706                 :             :          * client_encoding setting so that anyone who looks at the value in the
     707                 :             :          * worker sees the same value that they would see in the leader.  A change
     708                 :             :          * other than during startup, for example due to a SET clause attached to
     709                 :             :          * a function definition, should be rejected, as there is nothing we can
     710                 :             :          * do inside the worker to make it take effect.
     711                 :             :          */
     712   [ #  #  #  # ]:           0 :         if (IsParallelWorker() && !InitializingParallelWorker)
     713                 :             :         {
     714                 :           0 :                 GUC_check_errcode(ERRCODE_INVALID_TRANSACTION_STATE);
     715                 :           0 :                 GUC_check_errdetail("Cannot change \"client_encoding\" during a parallel operation.");
     716                 :           0 :                 return false;
     717                 :             :         }
     718                 :             : 
     719                 :             :         /*
     720                 :             :          * If we are not within a transaction then PrepareClientEncoding will not
     721                 :             :          * be able to look up the necessary conversion procs.  If we are still
     722                 :             :          * starting up, it will return "OK" anyway, and InitializeClientEncoding
     723                 :             :          * will fix things once initialization is far enough along.  After
     724                 :             :          * startup, we'll fail.  This would only happen if someone tries to change
     725                 :             :          * client_encoding in postgresql.conf and then SIGHUP existing sessions.
     726                 :             :          * It seems like a bad idea for client_encoding to change that way anyhow,
     727                 :             :          * so we don't go out of our way to support it.
     728                 :             :          *
     729                 :             :          * In a parallel worker, we might as well skip PrepareClientEncoding since
     730                 :             :          * we're not going to use its results.
     731                 :             :          *
     732                 :             :          * Note: in the postmaster, or any other process that never calls
     733                 :             :          * InitializeClientEncoding, PrepareClientEncoding will always succeed,
     734                 :             :          * and so will SetClientEncoding; but they won't do anything, which is OK.
     735                 :             :          */
     736   [ #  #  #  # ]:           0 :         if (!IsParallelWorker() &&
     737                 :           0 :                 PrepareClientEncoding(encoding) < 0)
     738                 :             :         {
     739         [ #  # ]:           0 :                 if (IsTransactionState())
     740                 :             :                 {
     741                 :             :                         /* Must be a genuine no-such-conversion problem */
     742                 :           0 :                         GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
     743                 :           0 :                         GUC_check_errdetail("Conversion between %s and %s is not supported.",
     744                 :           0 :                                                                 canonical_name,
     745                 :           0 :                                                                 GetDatabaseEncodingName());
     746                 :           0 :                 }
     747                 :             :                 else
     748                 :             :                 {
     749                 :             :                         /* Provide a useful complaint */
     750                 :           0 :                         GUC_check_errdetail("Cannot change \"client_encoding\" now.");
     751                 :             :                 }
     752                 :           0 :                 return false;
     753                 :             :         }
     754                 :             : 
     755                 :             :         /*
     756                 :             :          * Replace the user-supplied string with the encoding's canonical name.
     757                 :             :          * This gets rid of aliases and case-folding variations.
     758                 :             :          *
     759                 :             :          * XXX Although canonicalizing seems like a good idea in the abstract, it
     760                 :             :          * breaks pre-9.1 JDBC drivers, which expect that if they send "UNICODE"
     761                 :             :          * as the client_encoding setting then it will read back the same way. As
     762                 :             :          * a workaround, don't replace the string if it's "UNICODE".  Remove that
     763                 :             :          * hack when pre-9.1 JDBC drivers are no longer in use.
     764                 :             :          */
     765   [ #  #  #  # ]:           0 :         if (strcmp(*newval, canonical_name) != 0 &&
     766                 :           0 :                 strcmp(*newval, "UNICODE") != 0)
     767                 :             :         {
     768                 :           0 :                 guc_free(*newval);
     769                 :           0 :                 *newval = guc_strdup(LOG, canonical_name);
     770         [ #  # ]:           0 :                 if (!*newval)
     771                 :           0 :                         return false;
     772                 :           0 :         }
     773                 :             : 
     774                 :             :         /*
     775                 :             :          * Save the encoding's ID in *extra, for use by assign_client_encoding.
     776                 :             :          */
     777                 :           0 :         *extra = guc_malloc(LOG, sizeof(int));
     778         [ #  # ]:           0 :         if (!*extra)
     779                 :           0 :                 return false;
     780                 :           0 :         *((int *) *extra) = encoding;
     781                 :             : 
     782                 :           0 :         return true;
     783                 :           0 : }
     784                 :             : 
     785                 :             : void
     786                 :           0 : assign_client_encoding(const char *newval, void *extra)
     787                 :             : {
     788                 :           0 :         int                     encoding = *((int *) extra);
     789                 :             : 
     790                 :             :         /*
     791                 :             :          * In a parallel worker, we never override the client encoding that was
     792                 :             :          * set by ParallelWorkerMain().
     793                 :             :          */
     794         [ #  # ]:           0 :         if (IsParallelWorker())
     795                 :           0 :                 return;
     796                 :             : 
     797                 :             :         /* We do not expect an error if PrepareClientEncoding succeeded */
     798         [ #  # ]:           0 :         if (SetClientEncoding(encoding) < 0)
     799   [ #  #  #  # ]:           0 :                 elog(LOG, "SetClientEncoding(%d) failed", encoding);
     800         [ #  # ]:           0 : }
     801                 :             : 
     802                 :             : 
     803                 :             : /*
     804                 :             :  * SET SESSION AUTHORIZATION
     805                 :             :  */
     806                 :             : 
     807                 :             : typedef struct
     808                 :             : {
     809                 :             :         /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
     810                 :             :         Oid                     roleid;
     811                 :             :         bool            is_superuser;
     812                 :             : } role_auth_extra;
     813                 :             : 
     814                 :             : bool
     815                 :           0 : check_session_authorization(char **newval, void **extra, GucSource source)
     816                 :             : {
     817                 :           0 :         HeapTuple       roleTup;
     818                 :           0 :         Form_pg_authid roleform;
     819                 :           0 :         Oid                     roleid;
     820                 :           0 :         bool            is_superuser;
     821                 :           0 :         role_auth_extra *myextra;
     822                 :             : 
     823                 :             :         /* Do nothing for the boot_val default of NULL */
     824         [ #  # ]:           0 :         if (*newval == NULL)
     825                 :           0 :                 return true;
     826                 :             : 
     827         [ #  # ]:           0 :         if (InitializingParallelWorker)
     828                 :             :         {
     829                 :             :                 /*
     830                 :             :                  * In parallel worker initialization, we want to copy the leader's
     831                 :             :                  * state even if it no longer matches the catalogs. ParallelWorkerMain
     832                 :             :                  * already installed the correct role OID and superuser state.
     833                 :             :                  */
     834                 :           0 :                 roleid = GetSessionUserId();
     835                 :           0 :                 is_superuser = GetSessionUserIsSuperuser();
     836                 :           0 :         }
     837                 :             :         else
     838                 :             :         {
     839         [ #  # ]:           0 :                 if (!IsTransactionState())
     840                 :             :                 {
     841                 :             :                         /*
     842                 :             :                          * Can't do catalog lookups, so fail.  The result of this is that
     843                 :             :                          * session_authorization cannot be set in postgresql.conf, which
     844                 :             :                          * seems like a good thing anyway, so we don't work hard to avoid
     845                 :             :                          * it.
     846                 :             :                          */
     847                 :           0 :                         return false;
     848                 :             :                 }
     849                 :             : 
     850                 :             :                 /*
     851                 :             :                  * When source == PGC_S_TEST, we don't throw a hard error for a
     852                 :             :                  * nonexistent user name or insufficient privileges, only a NOTICE.
     853                 :             :                  * See comments in guc.h.
     854                 :             :                  */
     855                 :             : 
     856                 :             :                 /* Look up the username */
     857                 :           0 :                 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     858         [ #  # ]:           0 :                 if (!HeapTupleIsValid(roleTup))
     859                 :             :                 {
     860         [ #  # ]:           0 :                         if (source == PGC_S_TEST)
     861                 :             :                         {
     862   [ #  #  #  # ]:           0 :                                 ereport(NOTICE,
     863                 :             :                                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     864                 :             :                                                  errmsg("role \"%s\" does not exist", *newval)));
     865                 :           0 :                                 return true;
     866                 :             :                         }
     867                 :           0 :                         GUC_check_errmsg("role \"%s\" does not exist", *newval);
     868                 :           0 :                         return false;
     869                 :             :                 }
     870                 :             : 
     871                 :           0 :                 roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     872                 :           0 :                 roleid = roleform->oid;
     873                 :           0 :                 is_superuser = roleform->rolsuper;
     874                 :             : 
     875                 :           0 :                 ReleaseSysCache(roleTup);
     876                 :             : 
     877                 :             :                 /*
     878                 :             :                  * Only superusers may SET SESSION AUTHORIZATION a role other than
     879                 :             :                  * itself. Note that in case of multiple SETs in a single session, the
     880                 :             :                  * original authenticated user's superuserness is what matters.
     881                 :             :                  */
     882   [ #  #  #  # ]:           0 :                 if (roleid != GetAuthenticatedUserId() &&
     883                 :           0 :                         !superuser_arg(GetAuthenticatedUserId()))
     884                 :             :                 {
     885         [ #  # ]:           0 :                         if (source == PGC_S_TEST)
     886                 :             :                         {
     887   [ #  #  #  # ]:           0 :                                 ereport(NOTICE,
     888                 :             :                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     889                 :             :                                                  errmsg("permission will be denied to set session authorization \"%s\"",
     890                 :             :                                                                 *newval)));
     891                 :           0 :                                 return true;
     892                 :             :                         }
     893                 :           0 :                         GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
     894                 :           0 :                         GUC_check_errmsg("permission denied to set session authorization \"%s\"",
     895                 :           0 :                                                          *newval);
     896                 :           0 :                         return false;
     897                 :             :                 }
     898                 :             :         }
     899                 :             : 
     900                 :             :         /* Set up "extra" struct for assign_session_authorization to use */
     901                 :           0 :         myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
     902         [ #  # ]:           0 :         if (!myextra)
     903                 :           0 :                 return false;
     904                 :           0 :         myextra->roleid = roleid;
     905                 :           0 :         myextra->is_superuser = is_superuser;
     906                 :           0 :         *extra = myextra;
     907                 :             : 
     908                 :           0 :         return true;
     909                 :           0 : }
     910                 :             : 
     911                 :             : void
     912                 :           0 : assign_session_authorization(const char *newval, void *extra)
     913                 :             : {
     914                 :           0 :         role_auth_extra *myextra = (role_auth_extra *) extra;
     915                 :             : 
     916                 :             :         /* Do nothing for the boot_val default of NULL */
     917         [ #  # ]:           0 :         if (!myextra)
     918                 :           0 :                 return;
     919                 :             : 
     920                 :           0 :         SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
     921         [ #  # ]:           0 : }
     922                 :             : 
     923                 :             : 
     924                 :             : /*
     925                 :             :  * SET ROLE
     926                 :             :  *
     927                 :             :  * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
     928                 :             :  * a translation of "none" to InvalidOid.  Otherwise this is much like
     929                 :             :  * SET SESSION AUTHORIZATION.
     930                 :             :  */
     931                 :             : 
     932                 :             : bool
     933                 :           0 : check_role(char **newval, void **extra, GucSource source)
     934                 :             : {
     935                 :           0 :         HeapTuple       roleTup;
     936                 :           0 :         Oid                     roleid;
     937                 :           0 :         bool            is_superuser;
     938                 :           0 :         role_auth_extra *myextra;
     939                 :           0 :         Form_pg_authid roleform;
     940                 :             : 
     941         [ #  # ]:           0 :         if (strcmp(*newval, "none") == 0)
     942                 :             :         {
     943                 :             :                 /* hardwired translation */
     944                 :           0 :                 roleid = InvalidOid;
     945                 :           0 :                 is_superuser = false;
     946                 :           0 :         }
     947         [ #  # ]:           0 :         else if (InitializingParallelWorker)
     948                 :             :         {
     949                 :             :                 /*
     950                 :             :                  * In parallel worker initialization, we want to copy the leader's
     951                 :             :                  * state even if it no longer matches the catalogs. ParallelWorkerMain
     952                 :             :                  * already installed the correct role OID and superuser state.
     953                 :             :                  */
     954                 :           0 :                 roleid = GetCurrentRoleId();
     955                 :           0 :                 is_superuser = current_role_is_superuser;
     956                 :           0 :         }
     957                 :             :         else
     958                 :             :         {
     959         [ #  # ]:           0 :                 if (!IsTransactionState())
     960                 :             :                 {
     961                 :             :                         /*
     962                 :             :                          * Can't do catalog lookups, so fail.  The result of this is that
     963                 :             :                          * role cannot be set in postgresql.conf, which seems like a good
     964                 :             :                          * thing anyway, so we don't work hard to avoid it.
     965                 :             :                          */
     966                 :           0 :                         return false;
     967                 :             :                 }
     968                 :             : 
     969                 :             :                 /*
     970                 :             :                  * When source == PGC_S_TEST, we don't throw a hard error for a
     971                 :             :                  * nonexistent user name or insufficient privileges, only a NOTICE.
     972                 :             :                  * See comments in guc.h.
     973                 :             :                  */
     974                 :             : 
     975                 :             :                 /* Look up the username */
     976                 :           0 :                 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
     977         [ #  # ]:           0 :                 if (!HeapTupleIsValid(roleTup))
     978                 :             :                 {
     979         [ #  # ]:           0 :                         if (source == PGC_S_TEST)
     980                 :             :                         {
     981   [ #  #  #  # ]:           0 :                                 ereport(NOTICE,
     982                 :             :                                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     983                 :             :                                                  errmsg("role \"%s\" does not exist", *newval)));
     984                 :           0 :                                 return true;
     985                 :             :                         }
     986                 :           0 :                         GUC_check_errmsg("role \"%s\" does not exist", *newval);
     987                 :           0 :                         return false;
     988                 :             :                 }
     989                 :             : 
     990                 :           0 :                 roleform = (Form_pg_authid) GETSTRUCT(roleTup);
     991                 :           0 :                 roleid = roleform->oid;
     992                 :           0 :                 is_superuser = roleform->rolsuper;
     993                 :             : 
     994                 :           0 :                 ReleaseSysCache(roleTup);
     995                 :             : 
     996                 :             :                 /* Verify that session user is allowed to become this role */
     997         [ #  # ]:           0 :                 if (!member_can_set_role(GetSessionUserId(), roleid))
     998                 :             :                 {
     999         [ #  # ]:           0 :                         if (source == PGC_S_TEST)
    1000                 :             :                         {
    1001   [ #  #  #  # ]:           0 :                                 ereport(NOTICE,
    1002                 :             :                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1003                 :             :                                                  errmsg("permission will be denied to set role \"%s\"",
    1004                 :             :                                                                 *newval)));
    1005                 :           0 :                                 return true;
    1006                 :             :                         }
    1007                 :           0 :                         GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
    1008                 :           0 :                         GUC_check_errmsg("permission denied to set role \"%s\"",
    1009                 :           0 :                                                          *newval);
    1010                 :           0 :                         return false;
    1011                 :             :                 }
    1012                 :             :         }
    1013                 :             : 
    1014                 :             :         /* Set up "extra" struct for assign_role to use */
    1015                 :           0 :         myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
    1016         [ #  # ]:           0 :         if (!myextra)
    1017                 :           0 :                 return false;
    1018                 :           0 :         myextra->roleid = roleid;
    1019                 :           0 :         myextra->is_superuser = is_superuser;
    1020                 :           0 :         *extra = myextra;
    1021                 :             : 
    1022                 :           0 :         return true;
    1023                 :           0 : }
    1024                 :             : 
    1025                 :             : void
    1026                 :           0 : assign_role(const char *newval, void *extra)
    1027                 :             : {
    1028                 :           0 :         role_auth_extra *myextra = (role_auth_extra *) extra;
    1029                 :             : 
    1030                 :           0 :         SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
    1031                 :           0 : }
    1032                 :             : 
    1033                 :             : const char *
    1034                 :           0 : show_role(void)
    1035                 :             : {
    1036                 :             :         /*
    1037                 :             :          * Check whether SET ROLE is active; if not return "none".  This is a
    1038                 :             :          * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
    1039                 :             :          * resets SET ROLE to NONE, but we cannot set the GUC role variable from
    1040                 :             :          * assign_session_authorization (because we haven't got enough info to
    1041                 :             :          * call set_config_option).
    1042                 :             :          */
    1043         [ #  # ]:           0 :         if (!OidIsValid(GetCurrentRoleId()))
    1044                 :           0 :                 return "none";
    1045                 :             : 
    1046                 :             :         /* Otherwise we can just use the GUC string */
    1047         [ #  # ]:           0 :         return role_string ? role_string : "none";
    1048                 :           0 : }
    1049                 :             : 
    1050                 :             : 
    1051                 :             : /*
    1052                 :             :  * PATH VARIABLES
    1053                 :             :  *
    1054                 :             :  * check_canonical_path is used for log_directory and some other GUCs where
    1055                 :             :  * all we want to do is canonicalize the represented path name.
    1056                 :             :  */
    1057                 :             : 
    1058                 :             : bool
    1059                 :           0 : check_canonical_path(char **newval, void **extra, GucSource source)
    1060                 :             : {
    1061                 :             :         /*
    1062                 :             :          * Since canonicalize_path never enlarges the string, we can just modify
    1063                 :             :          * newval in-place.  But watch out for NULL, which is the default value
    1064                 :             :          * for external_pid_file.
    1065                 :             :          */
    1066         [ #  # ]:           0 :         if (*newval)
    1067                 :           0 :                 canonicalize_path(*newval);
    1068                 :           0 :         return true;
    1069                 :             : }
    1070                 :             : 
    1071                 :             : 
    1072                 :             : /*
    1073                 :             :  * MISCELLANEOUS
    1074                 :             :  */
    1075                 :             : 
    1076                 :             : /*
    1077                 :             :  * GUC check_hook for application_name
    1078                 :             :  */
    1079                 :             : bool
    1080                 :           0 : check_application_name(char **newval, void **extra, GucSource source)
    1081                 :             : {
    1082                 :           0 :         char       *clean;
    1083                 :           0 :         char       *ret;
    1084                 :             : 
    1085                 :             :         /* Only allow clean ASCII chars in the application name */
    1086                 :           0 :         clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1087         [ #  # ]:           0 :         if (!clean)
    1088                 :           0 :                 return false;
    1089                 :             : 
    1090                 :           0 :         ret = guc_strdup(LOG, clean);
    1091         [ #  # ]:           0 :         if (!ret)
    1092                 :             :         {
    1093                 :           0 :                 pfree(clean);
    1094                 :           0 :                 return false;
    1095                 :             :         }
    1096                 :             : 
    1097                 :           0 :         guc_free(*newval);
    1098                 :             : 
    1099                 :           0 :         pfree(clean);
    1100                 :           0 :         *newval = ret;
    1101                 :           0 :         return true;
    1102                 :           0 : }
    1103                 :             : 
    1104                 :             : /*
    1105                 :             :  * GUC assign_hook for application_name
    1106                 :             :  */
    1107                 :             : void
    1108                 :           0 : assign_application_name(const char *newval, void *extra)
    1109                 :             : {
    1110                 :             :         /* Update the pg_stat_activity view */
    1111                 :           0 :         pgstat_report_appname(newval);
    1112                 :           0 : }
    1113                 :             : 
    1114                 :             : /*
    1115                 :             :  * GUC check_hook for cluster_name
    1116                 :             :  */
    1117                 :             : bool
    1118                 :           0 : check_cluster_name(char **newval, void **extra, GucSource source)
    1119                 :             : {
    1120                 :           0 :         char       *clean;
    1121                 :           0 :         char       *ret;
    1122                 :             : 
    1123                 :             :         /* Only allow clean ASCII chars in the cluster name */
    1124                 :           0 :         clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
    1125         [ #  # ]:           0 :         if (!clean)
    1126                 :           0 :                 return false;
    1127                 :             : 
    1128                 :           0 :         ret = guc_strdup(LOG, clean);
    1129         [ #  # ]:           0 :         if (!ret)
    1130                 :             :         {
    1131                 :           0 :                 pfree(clean);
    1132                 :           0 :                 return false;
    1133                 :             :         }
    1134                 :             : 
    1135                 :           0 :         guc_free(*newval);
    1136                 :             : 
    1137                 :           0 :         pfree(clean);
    1138                 :           0 :         *newval = ret;
    1139                 :           0 :         return true;
    1140                 :           0 : }
    1141                 :             : 
    1142                 :             : /*
    1143                 :             :  * GUC assign_hook for maintenance_io_concurrency
    1144                 :             :  */
    1145                 :             : void
    1146                 :           0 : assign_maintenance_io_concurrency(int newval, void *extra)
    1147                 :             : {
    1148                 :             :         /*
    1149                 :             :          * Reconfigure recovery prefetching, because a setting it depends on
    1150                 :             :          * changed.
    1151                 :             :          */
    1152                 :           0 :         maintenance_io_concurrency = newval;
    1153         [ #  # ]:           0 :         if (AmStartupProcess())
    1154                 :           0 :                 XLogPrefetchReconfigure();
    1155                 :           0 : }
    1156                 :             : 
    1157                 :             : /*
    1158                 :             :  * GUC assign hooks that recompute io_combine_limit whenever
    1159                 :             :  * io_combine_limit_guc and io_max_combine_limit are changed.  These are needed
    1160                 :             :  * because the GUC subsystem doesn't support dependencies between GUCs, and
    1161                 :             :  * they may be assigned in either order.
    1162                 :             :  */
    1163                 :             : void
    1164                 :           0 : assign_io_max_combine_limit(int newval, void *extra)
    1165                 :             : {
    1166         [ #  # ]:           0 :         io_combine_limit = Min(newval, io_combine_limit_guc);
    1167                 :           0 : }
    1168                 :             : void
    1169                 :           0 : assign_io_combine_limit(int newval, void *extra)
    1170                 :             : {
    1171         [ #  # ]:           0 :         io_combine_limit = Min(io_max_combine_limit, newval);
    1172                 :           0 : }
    1173                 :             : 
    1174                 :             : /*
    1175                 :             :  * These show hooks just exist because we want to show the values in octal.
    1176                 :             :  */
    1177                 :             : 
    1178                 :             : /*
    1179                 :             :  * GUC show_hook for data_directory_mode
    1180                 :             :  */
    1181                 :             : const char *
    1182                 :           0 : show_data_directory_mode(void)
    1183                 :             : {
    1184                 :             :         static char buf[12];
    1185                 :             : 
    1186                 :           0 :         snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
    1187                 :           0 :         return buf;
    1188                 :             : }
    1189                 :             : 
    1190                 :             : /*
    1191                 :             :  * GUC show_hook for log_file_mode
    1192                 :             :  */
    1193                 :             : const char *
    1194                 :           0 : show_log_file_mode(void)
    1195                 :             : {
    1196                 :             :         static char buf[12];
    1197                 :             : 
    1198                 :           0 :         snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
    1199                 :           0 :         return buf;
    1200                 :             : }
    1201                 :             : 
    1202                 :             : /*
    1203                 :             :  * GUC show_hook for unix_socket_permissions
    1204                 :             :  */
    1205                 :             : const char *
    1206                 :           0 : show_unix_socket_permissions(void)
    1207                 :             : {
    1208                 :             :         static char buf[12];
    1209                 :             : 
    1210                 :           0 :         snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
    1211                 :           0 :         return buf;
    1212                 :             : }
    1213                 :             : 
    1214                 :             : 
    1215                 :             : /*
    1216                 :             :  * These check hooks do nothing more than reject non-default settings
    1217                 :             :  * in builds that don't support them.
    1218                 :             :  */
    1219                 :             : 
    1220                 :             : bool
    1221                 :           0 : check_bonjour(bool *newval, void **extra, GucSource source)
    1222                 :             : {
    1223                 :             : #ifndef USE_BONJOUR
    1224                 :             :         if (*newval)
    1225                 :             :         {
    1226                 :             :                 GUC_check_errmsg("Bonjour is not supported by this build");
    1227                 :             :                 return false;
    1228                 :             :         }
    1229                 :             : #endif
    1230                 :           0 :         return true;
    1231                 :             : }
    1232                 :             : 
    1233                 :             : bool
    1234                 :           0 : check_default_with_oids(bool *newval, void **extra, GucSource source)
    1235                 :             : {
    1236         [ #  # ]:           0 :         if (*newval)
    1237                 :             :         {
    1238                 :             :                 /* check the GUC's definition for an explanation */
    1239                 :           0 :                 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1240                 :           0 :                 GUC_check_errmsg("tables declared WITH OIDS are not supported");
    1241                 :             : 
    1242                 :           0 :                 return false;
    1243                 :             :         }
    1244                 :             : 
    1245                 :           0 :         return true;
    1246                 :           0 : }
    1247                 :             : 
    1248                 :             : bool
    1249                 :           0 : check_ssl(bool *newval, void **extra, GucSource source)
    1250                 :             : {
    1251                 :             : #ifndef USE_SSL
    1252                 :             :         if (*newval)
    1253                 :             :         {
    1254                 :             :                 GUC_check_errmsg("SSL is not supported by this build");
    1255                 :             :                 return false;
    1256                 :             :         }
    1257                 :             : #endif
    1258                 :           0 :         return true;
    1259                 :             : }
    1260                 :             : 
    1261                 :             : bool
    1262                 :           0 : check_standard_conforming_strings(bool *newval, void **extra, GucSource source)
    1263                 :             : {
    1264         [ #  # ]:           0 :         if (!*newval)
    1265                 :             :         {
    1266                 :             :                 /* check the GUC's definition for an explanation */
    1267                 :           0 :                 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
    1268                 :           0 :                 GUC_check_errmsg("non-standard string literals are not supported");
    1269                 :             : 
    1270                 :           0 :                 return false;
    1271                 :             :         }
    1272                 :             : 
    1273                 :           0 :         return true;
    1274                 :           0 : }
        

Generated by: LCOV version 2.3.2-1