LCOV - differential code coverage report
Current view: top level - src/backend/utils/misc - guc_funcs.c (source / functions) Coverage Total Hit UNC GNC
Current: Differential Code Coverage HEAD vs 15 Lines: 85.4 % 378 323 55 323
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 16 16 16
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*--------------------------------------------------------------------
       2                 :  *
       3                 :  * guc_funcs.c
       4                 :  *
       5                 :  * SQL commands and SQL-accessible functions related to GUC variables.
       6                 :  *
       7                 :  *
       8                 :  * Copyright (c) 2000-2023, PostgreSQL Global Development Group
       9                 :  * Written by Peter Eisentraut <peter_e@gmx.net>.
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *    src/backend/utils/misc/guc_funcs.c
      13                 :  *
      14                 :  *--------------------------------------------------------------------
      15                 :  */
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include <sys/stat.h>
      19                 : #include <unistd.h>
      20                 : 
      21                 : #include "access/xact.h"
      22                 : #include "catalog/objectaccess.h"
      23                 : #include "catalog/pg_authid.h"
      24                 : #include "catalog/pg_parameter_acl.h"
      25                 : #include "funcapi.h"
      26                 : #include "guc_internal.h"
      27                 : #include "parser/parse_type.h"
      28                 : #include "utils/acl.h"
      29                 : #include "utils/backend_status.h"
      30                 : #include "utils/builtins.h"
      31                 : #include "utils/guc_tables.h"
      32                 : #include "utils/snapmgr.h"
      33                 : 
      34                 : static char *flatten_set_variable_args(const char *name, List *args);
      35                 : static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
      36                 : static void ShowAllGUCConfig(DestReceiver *dest);
      37                 : 
      38                 : 
      39                 : /*
      40                 :  * SET command
      41                 :  */
      42                 : void
      43 GNC       16236 : ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
      44                 : {
      45           16236 :     GucAction   action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET;
      46                 : 
      47                 :     /*
      48                 :      * Workers synchronize these parameters at the start of the parallel
      49                 :      * operation; then, we block SET during the operation.
      50                 :      */
      51           16236 :     if (IsInParallelMode())
      52 UNC           0 :         ereport(ERROR,
      53                 :                 (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
      54                 :                  errmsg("cannot set parameters during a parallel operation")));
      55                 : 
      56 GNC       16236 :     switch (stmt->kind)
      57                 :     {
      58           14164 :         case VAR_SET_VALUE:
      59                 :         case VAR_SET_CURRENT:
      60           14164 :             if (stmt->is_local)
      61             492 :                 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
      62           28328 :             (void) set_config_option(stmt->name,
      63           14164 :                                      ExtractSetVariableArgs(stmt),
      64           14164 :                                      (superuser() ? PGC_SUSET : PGC_USERSET),
      65                 :                                      PGC_S_SESSION,
      66                 :                                      action, true, 0, false);
      67           14105 :             break;
      68             241 :         case VAR_SET_MULTI:
      69                 : 
      70                 :             /*
      71                 :              * Special-case SQL syntaxes.  The TRANSACTION and SESSION
      72                 :              * CHARACTERISTICS cases effectively set more than one variable
      73                 :              * per statement.  TRANSACTION SNAPSHOT only takes one argument,
      74                 :              * but we put it here anyway since it's a special case and not
      75                 :              * related to any GUC variable.
      76                 :              */
      77             241 :             if (strcmp(stmt->name, "TRANSACTION") == 0)
      78                 :             {
      79                 :                 ListCell   *head;
      80                 : 
      81             217 :                 WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
      82                 : 
      83             579 :                 foreach(head, stmt->args)
      84                 :                 {
      85             372 :                     DefElem    *item = (DefElem *) lfirst(head);
      86                 : 
      87             372 :                     if (strcmp(item->defname, "transaction_isolation") == 0)
      88             166 :                         SetPGVariable("transaction_isolation",
      89             166 :                                       list_make1(item->arg), stmt->is_local);
      90             206 :                     else if (strcmp(item->defname, "transaction_read_only") == 0)
      91             203 :                         SetPGVariable("transaction_read_only",
      92             203 :                                       list_make1(item->arg), stmt->is_local);
      93               3 :                     else if (strcmp(item->defname, "transaction_deferrable") == 0)
      94               3 :                         SetPGVariable("transaction_deferrable",
      95               3 :                                       list_make1(item->arg), stmt->is_local);
      96                 :                     else
      97 UNC           0 :                         elog(ERROR, "unexpected SET TRANSACTION element: %s",
      98                 :                              item->defname);
      99                 :                 }
     100                 :             }
     101 GNC          24 :             else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0)
     102                 :             {
     103                 :                 ListCell   *head;
     104                 : 
     105              12 :                 foreach(head, stmt->args)
     106                 :                 {
     107               6 :                     DefElem    *item = (DefElem *) lfirst(head);
     108                 : 
     109               6 :                     if (strcmp(item->defname, "transaction_isolation") == 0)
     110 UNC           0 :                         SetPGVariable("default_transaction_isolation",
     111               0 :                                       list_make1(item->arg), stmt->is_local);
     112 GNC           6 :                     else if (strcmp(item->defname, "transaction_read_only") == 0)
     113               6 :                         SetPGVariable("default_transaction_read_only",
     114               6 :                                       list_make1(item->arg), stmt->is_local);
     115 UNC           0 :                     else if (strcmp(item->defname, "transaction_deferrable") == 0)
     116               0 :                         SetPGVariable("default_transaction_deferrable",
     117               0 :                                       list_make1(item->arg), stmt->is_local);
     118                 :                     else
     119               0 :                         elog(ERROR, "unexpected SET SESSION element: %s",
     120                 :                              item->defname);
     121                 :                 }
     122                 :             }
     123 GNC          18 :             else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT") == 0)
     124                 :             {
     125              18 :                 A_Const    *con = linitial_node(A_Const, stmt->args);
     126                 : 
     127              18 :                 if (stmt->is_local)
     128 UNC           0 :                     ereport(ERROR,
     129                 :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     130                 :                              errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented")));
     131                 : 
     132 GNC          18 :                 WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
     133              18 :                 ImportSnapshot(strVal(&con->val));
     134                 :             }
     135                 :             else
     136 UNC           0 :                 elog(ERROR, "unexpected SET MULTI element: %s",
     137                 :                      stmt->name);
     138 GNC         231 :             break;
     139              71 :         case VAR_SET_DEFAULT:
     140              71 :             if (stmt->is_local)
     141               1 :                 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
     142                 :             /* fall through */
     143                 :         case VAR_RESET:
     144            1831 :             (void) set_config_option(stmt->name,
     145                 :                                      NULL,
     146            1831 :                                      (superuser() ? PGC_SUSET : PGC_USERSET),
     147                 :                                      PGC_S_SESSION,
     148                 :                                      action, true, 0, false);
     149            1816 :             break;
     150 UNC           0 :         case VAR_RESET_ALL:
     151               0 :             ResetAllOptions();
     152               0 :             break;
     153                 :     }
     154                 : 
     155                 :     /* Invoke the post-alter hook for setting this GUC variable, by name. */
     156 GNC       16152 :     InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, stmt->name,
     157                 :                                     ACL_SET, stmt->kind, false);
     158           16151 : }
     159                 : 
     160                 : /*
     161                 :  * Get the value to assign for a VariableSetStmt, or NULL if it's RESET.
     162                 :  * The result is palloc'd.
     163                 :  *
     164                 :  * This is exported for use by actions such as ALTER ROLE SET.
     165                 :  */
     166                 : char *
     167           14822 : ExtractSetVariableArgs(VariableSetStmt *stmt)
     168                 : {
     169                 : 
     170           14822 :     switch (stmt->kind)
     171                 :     {
     172           14808 :         case VAR_SET_VALUE:
     173           14808 :             return flatten_set_variable_args(stmt->name, stmt->args);
     174 UNC           0 :         case VAR_SET_CURRENT:
     175                 :             {
     176                 :                 struct config_generic *record;
     177                 :                 char       *result;
     178                 : 
     179               0 :                 result = GetConfigOptionByName(stmt->name, NULL, false);
     180               0 :                 record = find_option(stmt->name, false, false, ERROR);
     181               0 :                 stmt->user_set = (record->scontext == PGC_USERSET);
     182                 : 
     183               0 :                 return result;
     184                 :             }
     185 GNC          14 :         default:
     186              14 :             return NULL;
     187                 :     }
     188                 : }
     189                 : 
     190                 : /*
     191                 :  * flatten_set_variable_args
     192                 :  *      Given a parsenode List as emitted by the grammar for SET,
     193                 :  *      convert to the flat string representation used by GUC.
     194                 :  *
     195                 :  * We need to be told the name of the variable the args are for, because
     196                 :  * the flattening rules vary (ugh).
     197                 :  *
     198                 :  * The result is NULL if args is NIL (i.e., SET ... TO DEFAULT), otherwise
     199                 :  * a palloc'd string.
     200                 :  */
     201                 : static char *
     202           18649 : flatten_set_variable_args(const char *name, List *args)
     203                 : {
     204                 :     struct config_generic *record;
     205                 :     int         flags;
     206                 :     StringInfoData buf;
     207                 :     ListCell   *l;
     208                 : 
     209                 :     /* Fast path if just DEFAULT */
     210           18649 :     if (args == NIL)
     211               3 :         return NULL;
     212                 : 
     213                 :     /*
     214                 :      * Get flags for the variable; if it's not known, use default flags.
     215                 :      * (Caller might throw error later, but not our business to do so here.)
     216                 :      */
     217           18646 :     record = find_option(name, false, true, WARNING);
     218           18646 :     if (record)
     219           18613 :         flags = record->flags;
     220                 :     else
     221              33 :         flags = 0;
     222                 : 
     223                 :     /* Complain if list input and non-list variable */
     224           36112 :     if ((flags & GUC_LIST_INPUT) == 0 &&
     225           17466 :         list_length(args) != 1)
     226 UNC           0 :         ereport(ERROR,
     227                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     228                 :                  errmsg("SET %s takes only one argument", name)));
     229                 : 
     230 GNC       18646 :     initStringInfo(&buf);
     231                 : 
     232                 :     /*
     233                 :      * Each list member may be a plain A_Const node, or an A_Const within a
     234                 :      * TypeCast; the latter case is supported only for ConstInterval arguments
     235                 :      * (for SET TIME ZONE).
     236                 :      */
     237           37362 :     foreach(l, args)
     238                 :     {
     239           18716 :         Node       *arg = (Node *) lfirst(l);
     240                 :         char       *val;
     241           18716 :         TypeName   *typeName = NULL;
     242                 :         A_Const    *con;
     243                 : 
     244           18716 :         if (l != list_head(args))
     245              70 :             appendStringInfoString(&buf, ", ");
     246                 : 
     247           18716 :         if (IsA(arg, TypeCast))
     248                 :         {
     249 UNC           0 :             TypeCast   *tc = (TypeCast *) arg;
     250                 : 
     251               0 :             arg = tc->arg;
     252               0 :             typeName = tc->typeName;
     253                 :         }
     254                 : 
     255 GNC       18716 :         if (!IsA(arg, A_Const))
     256 UNC           0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg));
     257 GNC       18716 :         con = (A_Const *) arg;
     258                 : 
     259           18716 :         switch (nodeTag(&con->val))
     260                 :         {
     261            7237 :             case T_Integer:
     262            7237 :                 appendStringInfo(&buf, "%d", intVal(&con->val));
     263            7237 :                 break;
     264             109 :             case T_Float:
     265                 :                 /* represented as a string, so just copy it */
     266             109 :                 appendStringInfoString(&buf, castNode(Float, &con->val)->fval);
     267             109 :                 break;
     268           11370 :             case T_String:
     269           11370 :                 val = strVal(&con->val);
     270           11370 :                 if (typeName != NULL)
     271                 :                 {
     272                 :                     /*
     273                 :                      * Must be a ConstInterval argument for TIME ZONE. Coerce
     274                 :                      * to interval and back to normalize the value and account
     275                 :                      * for any typmod.
     276                 :                      */
     277                 :                     Oid         typoid;
     278                 :                     int32       typmod;
     279                 :                     Datum       interval;
     280                 :                     char       *intervalout;
     281                 : 
     282 UNC           0 :                     typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod);
     283               0 :                     Assert(typoid == INTERVALOID);
     284                 : 
     285                 :                     interval =
     286               0 :                         DirectFunctionCall3(interval_in,
     287                 :                                             CStringGetDatum(val),
     288                 :                                             ObjectIdGetDatum(InvalidOid),
     289                 :                                             Int32GetDatum(typmod));
     290                 : 
     291                 :                     intervalout =
     292               0 :                         DatumGetCString(DirectFunctionCall1(interval_out,
     293                 :                                                             interval));
     294               0 :                     appendStringInfo(&buf, "INTERVAL '%s'", intervalout);
     295                 :                 }
     296                 :                 else
     297                 :                 {
     298                 :                     /*
     299                 :                      * Plain string literal or identifier.  For quote mode,
     300                 :                      * quote it if it's not a vanilla identifier.
     301                 :                      */
     302 GNC       11370 :                     if (flags & GUC_LIST_QUOTE)
     303             867 :                         appendStringInfoString(&buf, quote_identifier(val));
     304                 :                     else
     305           10503 :                         appendStringInfoString(&buf, val);
     306                 :                 }
     307           11370 :                 break;
     308 UNC           0 :             default:
     309               0 :                 elog(ERROR, "unrecognized node type: %d",
     310                 :                      (int) nodeTag(&con->val));
     311                 :                 break;
     312                 :         }
     313                 :     }
     314                 : 
     315 GNC       18646 :     return buf.data;
     316                 : }
     317                 : 
     318                 : /*
     319                 :  * SetPGVariable - SET command exported as an easily-C-callable function.
     320                 :  *
     321                 :  * This provides access to SET TO value, as well as SET TO DEFAULT (expressed
     322                 :  * by passing args == NIL), but not SET FROM CURRENT functionality.
     323                 :  */
     324                 : void
     325            3841 : SetPGVariable(const char *name, List *args, bool is_local)
     326                 : {
     327            3841 :     char       *argstring = flatten_set_variable_args(name, args);
     328                 : 
     329                 :     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     330            3841 :     (void) set_config_option(name,
     331                 :                              argstring,
     332            3841 :                              (superuser() ? PGC_SUSET : PGC_USERSET),
     333                 :                              PGC_S_SESSION,
     334                 :                              is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
     335                 :                              true, 0, false);
     336            3831 : }
     337                 : 
     338                 : /*
     339                 :  * SET command wrapped as a SQL callable function.
     340                 :  */
     341                 : Datum
     342            1771 : set_config_by_name(PG_FUNCTION_ARGS)
     343                 : {
     344                 :     char       *name;
     345                 :     char       *value;
     346                 :     char       *new_value;
     347                 :     bool        is_local;
     348                 : 
     349            1771 :     if (PG_ARGISNULL(0))
     350 UNC           0 :         ereport(ERROR,
     351                 :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     352                 :                  errmsg("SET requires parameter name")));
     353                 : 
     354                 :     /* Get the GUC variable name */
     355 GNC        1771 :     name = TextDatumGetCString(PG_GETARG_DATUM(0));
     356                 : 
     357                 :     /* Get the desired value or set to NULL for a reset request */
     358            1771 :     if (PG_ARGISNULL(1))
     359 UNC           0 :         value = NULL;
     360                 :     else
     361 GNC        1771 :         value = TextDatumGetCString(PG_GETARG_DATUM(1));
     362                 : 
     363                 :     /*
     364                 :      * Get the desired state of is_local. Default to false if provided value
     365                 :      * is NULL
     366                 :      */
     367            1771 :     if (PG_ARGISNULL(2))
     368 UNC           0 :         is_local = false;
     369                 :     else
     370 GNC        1771 :         is_local = PG_GETARG_BOOL(2);
     371                 : 
     372                 :     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     373            1771 :     (void) set_config_option(name,
     374                 :                              value,
     375            1771 :                              (superuser() ? PGC_SUSET : PGC_USERSET),
     376                 :                              PGC_S_SESSION,
     377                 :                              is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
     378                 :                              true, 0, false);
     379                 : 
     380                 :     /* get the new current value */
     381            1770 :     new_value = GetConfigOptionByName(name, NULL, false);
     382                 : 
     383                 :     /* Convert return string to text */
     384            1770 :     PG_RETURN_TEXT_P(cstring_to_text(new_value));
     385                 : }
     386                 : 
     387                 : 
     388                 : /*
     389                 :  * SHOW command
     390                 :  */
     391                 : void
     392             817 : GetPGVariable(const char *name, DestReceiver *dest)
     393                 : {
     394             817 :     if (guc_name_compare(name, "all") == 0)
     395               2 :         ShowAllGUCConfig(dest);
     396                 :     else
     397             815 :         ShowGUCConfigOption(name, dest);
     398             817 : }
     399                 : 
     400                 : /*
     401                 :  * Get a tuple descriptor for SHOW's result
     402                 :  */
     403                 : TupleDesc
     404             381 : GetPGVariableResultDesc(const char *name)
     405                 : {
     406                 :     TupleDesc   tupdesc;
     407                 : 
     408             381 :     if (guc_name_compare(name, "all") == 0)
     409                 :     {
     410                 :         /* need a tuple descriptor representing three TEXT columns */
     411 UNC           0 :         tupdesc = CreateTemplateTupleDesc(3);
     412               0 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
     413                 :                            TEXTOID, -1, 0);
     414               0 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
     415                 :                            TEXTOID, -1, 0);
     416               0 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
     417                 :                            TEXTOID, -1, 0);
     418                 :     }
     419                 :     else
     420                 :     {
     421                 :         const char *varname;
     422                 : 
     423                 :         /* Get the canonical spelling of name */
     424 GNC         381 :         (void) GetConfigOptionByName(name, &varname, false);
     425                 : 
     426                 :         /* need a tuple descriptor representing a single TEXT column */
     427             368 :         tupdesc = CreateTemplateTupleDesc(1);
     428             368 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
     429                 :                            TEXTOID, -1, 0);
     430                 :     }
     431             368 :     return tupdesc;
     432                 : }
     433                 : 
     434                 : /*
     435                 :  * SHOW one variable
     436                 :  */
     437                 : static void
     438             815 : ShowGUCConfigOption(const char *name, DestReceiver *dest)
     439                 : {
     440                 :     TupOutputState *tstate;
     441                 :     TupleDesc   tupdesc;
     442                 :     const char *varname;
     443                 :     char       *value;
     444                 : 
     445                 :     /* Get the value and canonical spelling of name */
     446             815 :     value = GetConfigOptionByName(name, &varname, false);
     447                 : 
     448                 :     /* need a tuple descriptor representing a single TEXT column */
     449             815 :     tupdesc = CreateTemplateTupleDesc(1);
     450             815 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname,
     451                 :                               TEXTOID, -1, 0);
     452                 : 
     453                 :     /* prepare for projection of tuples */
     454             815 :     tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
     455                 : 
     456                 :     /* Send it */
     457             815 :     do_text_output_oneline(tstate, value);
     458                 : 
     459             815 :     end_tup_output(tstate);
     460             815 : }
     461                 : 
     462                 : /*
     463                 :  * SHOW ALL command
     464                 :  */
     465                 : static void
     466               2 : ShowAllGUCConfig(DestReceiver *dest)
     467                 : {
     468                 :     struct config_generic **guc_vars;
     469                 :     int         num_vars;
     470                 :     TupOutputState *tstate;
     471                 :     TupleDesc   tupdesc;
     472                 :     Datum       values[3];
     473               2 :     bool        isnull[3] = {false, false, false};
     474                 : 
     475                 :     /* collect the variables, in sorted order */
     476               2 :     guc_vars = get_guc_variables(&num_vars);
     477                 : 
     478                 :     /* need a tuple descriptor representing three TEXT columns */
     479               2 :     tupdesc = CreateTemplateTupleDesc(3);
     480               2 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "name",
     481                 :                               TEXTOID, -1, 0);
     482               2 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "setting",
     483                 :                               TEXTOID, -1, 0);
     484               2 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description",
     485                 :                               TEXTOID, -1, 0);
     486                 : 
     487                 :     /* prepare for projection of tuples */
     488               2 :     tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
     489                 : 
     490             738 :     for (int i = 0; i < num_vars; i++)
     491                 :     {
     492             736 :         struct config_generic *conf = guc_vars[i];
     493                 :         char       *setting;
     494                 : 
     495                 :         /* skip if marked NO_SHOW_ALL */
     496             736 :         if (conf->flags & GUC_NO_SHOW_ALL)
     497              12 :             continue;
     498                 : 
     499                 :         /* return only options visible to the current user */
     500             724 :         if (!ConfigOptionIsVisible(conf))
     501 UNC           0 :             continue;
     502                 : 
     503                 :         /* assign to the values array */
     504 GNC         724 :         values[0] = PointerGetDatum(cstring_to_text(conf->name));
     505                 : 
     506             724 :         setting = ShowGUCOption(conf, true);
     507             724 :         if (setting)
     508                 :         {
     509             724 :             values[1] = PointerGetDatum(cstring_to_text(setting));
     510             724 :             isnull[1] = false;
     511                 :         }
     512                 :         else
     513                 :         {
     514 UNC           0 :             values[1] = PointerGetDatum(NULL);
     515               0 :             isnull[1] = true;
     516                 :         }
     517                 : 
     518 GNC         724 :         if (conf->short_desc)
     519                 :         {
     520             724 :             values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
     521             724 :             isnull[2] = false;
     522                 :         }
     523                 :         else
     524                 :         {
     525 UNC           0 :             values[2] = PointerGetDatum(NULL);
     526               0 :             isnull[2] = true;
     527                 :         }
     528                 : 
     529                 :         /* send it to dest */
     530 GNC         724 :         do_tup_output(tstate, values, isnull);
     531                 : 
     532                 :         /* clean up */
     533             724 :         pfree(DatumGetPointer(values[0]));
     534             724 :         if (setting)
     535                 :         {
     536             724 :             pfree(setting);
     537             724 :             pfree(DatumGetPointer(values[1]));
     538                 :         }
     539             724 :         if (conf->short_desc)
     540             724 :             pfree(DatumGetPointer(values[2]));
     541                 :     }
     542                 : 
     543               2 :     end_tup_output(tstate);
     544               2 : }
     545                 : 
     546                 : /*
     547                 :  * Return some of the flags associated to the specified GUC in the shape of
     548                 :  * a text array, and NULL if it does not exist.  An empty array is returned
     549                 :  * if the GUC exists without any meaningful flags to show.
     550                 :  */
     551                 : Datum
     552            1832 : pg_settings_get_flags(PG_FUNCTION_ARGS)
     553                 : {
     554                 : #define MAX_GUC_FLAGS   6
     555            1832 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     556                 :     struct config_generic *record;
     557            1832 :     int         cnt = 0;
     558                 :     Datum       flags[MAX_GUC_FLAGS];
     559                 :     ArrayType  *a;
     560                 : 
     561            1832 :     record = find_option(varname, false, true, ERROR);
     562                 : 
     563                 :     /* return NULL if no such variable */
     564            1832 :     if (record == NULL)
     565               3 :         PG_RETURN_NULL();
     566                 : 
     567            1829 :     if (record->flags & GUC_EXPLAIN)
     568             290 :         flags[cnt++] = CStringGetTextDatum("EXPLAIN");
     569            1829 :     if (record->flags & GUC_NO_RESET)
     570              15 :         flags[cnt++] = CStringGetTextDatum("NO_RESET");
     571            1829 :     if (record->flags & GUC_NO_RESET_ALL)
     572              15 :         flags[cnt++] = CStringGetTextDatum("NO_RESET_ALL");
     573            1829 :     if (record->flags & GUC_NO_SHOW_ALL)
     574 UNC           0 :         flags[cnt++] = CStringGetTextDatum("NO_SHOW_ALL");
     575 GNC        1829 :     if (record->flags & GUC_NOT_IN_SAMPLE)
     576             245 :         flags[cnt++] = CStringGetTextDatum("NOT_IN_SAMPLE");
     577            1829 :     if (record->flags & GUC_RUNTIME_COMPUTED)
     578              25 :         flags[cnt++] = CStringGetTextDatum("RUNTIME_COMPUTED");
     579                 : 
     580            1829 :     Assert(cnt <= MAX_GUC_FLAGS);
     581                 : 
     582                 :     /* Returns the record as Datum */
     583            1829 :     a = construct_array_builtin(flags, cnt, TEXTOID);
     584            1829 :     PG_RETURN_ARRAYTYPE_P(a);
     585                 : }
     586                 : 
     587                 : /*
     588                 :  * Return whether or not the GUC variable is visible to the current user.
     589                 :  */
     590                 : bool
     591          403330 : ConfigOptionIsVisible(struct config_generic *conf)
     592                 : {
     593          403330 :     if ((conf->flags & GUC_SUPERUSER_ONLY) &&
     594           21787 :         !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
     595               1 :         return false;
     596                 :     else
     597          403329 :         return true;
     598                 : }
     599                 : 
     600                 : /*
     601                 :  * Extract fields to show in pg_settings for given variable.
     602                 :  */
     603                 : static void
     604          398869 : GetConfigOptionValues(struct config_generic *conf, const char **values)
     605                 : {
     606                 :     char        buffer[256];
     607                 : 
     608                 :     /* first get the generic attributes */
     609                 : 
     610                 :     /* name */
     611          398869 :     values[0] = conf->name;
     612                 : 
     613                 :     /* setting: use ShowGUCOption in order to avoid duplicating the logic */
     614          398869 :     values[1] = ShowGUCOption(conf, false);
     615                 : 
     616                 :     /* unit, if any (NULL is fine) */
     617          398869 :     values[2] = get_config_unit_name(conf->flags);
     618                 : 
     619                 :     /* group */
     620          398869 :     values[3] = _(config_group_names[conf->group]);
     621                 : 
     622                 :     /* short_desc */
     623          398869 :     values[4] = conf->short_desc != NULL ? _(conf->short_desc) : NULL;
     624                 : 
     625                 :     /* extra_desc */
     626          398869 :     values[5] = conf->long_desc != NULL ? _(conf->long_desc) : NULL;
     627                 : 
     628                 :     /* context */
     629          398869 :     values[6] = GucContext_Names[conf->context];
     630                 : 
     631                 :     /* vartype */
     632          398869 :     values[7] = config_type_names[conf->vartype];
     633                 : 
     634                 :     /* source */
     635          398869 :     values[8] = GucSource_Names[conf->source];
     636                 : 
     637                 :     /* now get the type specific attributes */
     638          398869 :     switch (conf->vartype)
     639                 :     {
     640          113029 :         case PGC_BOOL:
     641                 :             {
     642          113029 :                 struct config_bool *lconf = (struct config_bool *) conf;
     643                 : 
     644                 :                 /* min_val */
     645          113029 :                 values[9] = NULL;
     646                 : 
     647                 :                 /* max_val */
     648          113029 :                 values[10] = NULL;
     649                 : 
     650                 :                 /* enumvals */
     651          113029 :                 values[11] = NULL;
     652                 : 
     653                 :                 /* boot_val */
     654          113029 :                 values[12] = pstrdup(lconf->boot_val ? "on" : "off");
     655                 : 
     656                 :                 /* reset_val */
     657          113029 :                 values[13] = pstrdup(lconf->reset_val ? "on" : "off");
     658                 :             }
     659          113029 :             break;
     660                 : 
     661          140228 :         case PGC_INT:
     662                 :             {
     663          140228 :                 struct config_int *lconf = (struct config_int *) conf;
     664                 : 
     665                 :                 /* min_val */
     666          140228 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->min);
     667          140228 :                 values[9] = pstrdup(buffer);
     668                 : 
     669                 :                 /* max_val */
     670          140228 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->max);
     671          140228 :                 values[10] = pstrdup(buffer);
     672                 : 
     673                 :                 /* enumvals */
     674          140228 :                 values[11] = NULL;
     675                 : 
     676                 :                 /* boot_val */
     677          140228 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
     678          140228 :                 values[12] = pstrdup(buffer);
     679                 : 
     680                 :                 /* reset_val */
     681          140228 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
     682          140228 :                 values[13] = pstrdup(buffer);
     683                 :             }
     684          140228 :             break;
     685                 : 
     686           26088 :         case PGC_REAL:
     687                 :             {
     688           26088 :                 struct config_real *lconf = (struct config_real *) conf;
     689                 : 
     690                 :                 /* min_val */
     691           26088 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->min);
     692           26088 :                 values[9] = pstrdup(buffer);
     693                 : 
     694                 :                 /* max_val */
     695           26088 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->max);
     696           26088 :                 values[10] = pstrdup(buffer);
     697                 : 
     698                 :                 /* enumvals */
     699           26088 :                 values[11] = NULL;
     700                 : 
     701                 :                 /* boot_val */
     702           26088 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
     703           26088 :                 values[12] = pstrdup(buffer);
     704                 : 
     705                 :                 /* reset_val */
     706           26088 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
     707           26088 :                 values[13] = pstrdup(buffer);
     708                 :             }
     709           26088 :             break;
     710                 : 
     711           77143 :         case PGC_STRING:
     712                 :             {
     713           77143 :                 struct config_string *lconf = (struct config_string *) conf;
     714                 : 
     715                 :                 /* min_val */
     716           77143 :                 values[9] = NULL;
     717                 : 
     718                 :                 /* max_val */
     719           77143 :                 values[10] = NULL;
     720                 : 
     721                 :                 /* enumvals */
     722           77143 :                 values[11] = NULL;
     723                 : 
     724                 :                 /* boot_val */
     725           77143 :                 if (lconf->boot_val == NULL)
     726            6522 :                     values[12] = NULL;
     727                 :                 else
     728           70621 :                     values[12] = pstrdup(lconf->boot_val);
     729                 : 
     730                 :                 /* reset_val */
     731           77143 :                 if (lconf->reset_val == NULL)
     732            1087 :                     values[13] = NULL;
     733                 :                 else
     734           76056 :                     values[13] = pstrdup(lconf->reset_val);
     735                 :             }
     736           77143 :             break;
     737                 : 
     738           42381 :         case PGC_ENUM:
     739                 :             {
     740           42381 :                 struct config_enum *lconf = (struct config_enum *) conf;
     741                 : 
     742                 :                 /* min_val */
     743           42381 :                 values[9] = NULL;
     744                 : 
     745                 :                 /* max_val */
     746           42381 :                 values[10] = NULL;
     747                 : 
     748                 :                 /* enumvals */
     749                 : 
     750                 :                 /*
     751                 :                  * NOTE! enumvals with double quotes in them are not
     752                 :                  * supported!
     753                 :                  */
     754           42381 :                 values[11] = config_enum_get_options((struct config_enum *) conf,
     755                 :                                                      "{\"", "\"}", "\",\"");
     756                 : 
     757                 :                 /* boot_val */
     758           42381 :                 values[12] = pstrdup(config_enum_lookup_by_value(lconf,
     759                 :                                                                  lconf->boot_val));
     760                 : 
     761                 :                 /* reset_val */
     762           42381 :                 values[13] = pstrdup(config_enum_lookup_by_value(lconf,
     763                 :                                                                  lconf->reset_val));
     764                 :             }
     765           42381 :             break;
     766                 : 
     767 UNC           0 :         default:
     768                 :             {
     769                 :                 /*
     770                 :                  * should never get here, but in case we do, set 'em to NULL
     771                 :                  */
     772                 : 
     773                 :                 /* min_val */
     774               0 :                 values[9] = NULL;
     775                 : 
     776                 :                 /* max_val */
     777               0 :                 values[10] = NULL;
     778                 : 
     779                 :                 /* enumvals */
     780               0 :                 values[11] = NULL;
     781                 : 
     782                 :                 /* boot_val */
     783               0 :                 values[12] = NULL;
     784                 : 
     785                 :                 /* reset_val */
     786               0 :                 values[13] = NULL;
     787                 :             }
     788               0 :             break;
     789                 :     }
     790                 : 
     791                 :     /*
     792                 :      * If the setting came from a config file, set the source location. For
     793                 :      * security reasons, we don't show source file/line number for
     794                 :      * insufficiently-privileged users.
     795                 :      */
     796 GNC      429060 :     if (conf->source == PGC_S_FILE &&
     797           30191 :         has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
     798                 :     {
     799           30191 :         values[14] = conf->sourcefile;
     800           30191 :         snprintf(buffer, sizeof(buffer), "%d", conf->sourceline);
     801           30191 :         values[15] = pstrdup(buffer);
     802                 :     }
     803                 :     else
     804                 :     {
     805          368678 :         values[14] = NULL;
     806          368678 :         values[15] = NULL;
     807                 :     }
     808                 : 
     809          398869 :     values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f";
     810          398869 : }
     811                 : 
     812                 : /*
     813                 :  * show_config_by_name - equiv to SHOW X command but implemented as
     814                 :  * a function.
     815                 :  */
     816                 : Datum
     817             756 : show_config_by_name(PG_FUNCTION_ARGS)
     818                 : {
     819             756 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     820                 :     char       *varval;
     821                 : 
     822                 :     /* Get the value */
     823             756 :     varval = GetConfigOptionByName(varname, NULL, false);
     824                 : 
     825                 :     /* Convert to text */
     826             753 :     PG_RETURN_TEXT_P(cstring_to_text(varval));
     827                 : }
     828                 : 
     829                 : /*
     830                 :  * show_config_by_name_missing_ok - equiv to SHOW X command but implemented as
     831                 :  * a function.  If X does not exist, suppress the error and just return NULL
     832                 :  * if missing_ok is true.
     833                 :  */
     834                 : Datum
     835              12 : show_config_by_name_missing_ok(PG_FUNCTION_ARGS)
     836                 : {
     837              12 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     838              12 :     bool        missing_ok = PG_GETARG_BOOL(1);
     839                 :     char       *varval;
     840                 : 
     841                 :     /* Get the value */
     842              12 :     varval = GetConfigOptionByName(varname, NULL, missing_ok);
     843                 : 
     844                 :     /* return NULL if no such variable */
     845               9 :     if (varval == NULL)
     846               3 :         PG_RETURN_NULL();
     847                 : 
     848                 :     /* Convert to text */
     849               6 :     PG_RETURN_TEXT_P(cstring_to_text(varval));
     850                 : }
     851                 : 
     852                 : /*
     853                 :  * show_all_settings - equiv to SHOW ALL command but implemented as
     854                 :  * a Table Function.
     855                 :  */
     856                 : #define NUM_PG_SETTINGS_ATTS    17
     857                 : 
     858                 : Datum
     859          399956 : show_all_settings(PG_FUNCTION_ARGS)
     860                 : {
     861                 :     FuncCallContext *funcctx;
     862                 :     struct config_generic **guc_vars;
     863                 :     int         num_vars;
     864                 :     TupleDesc   tupdesc;
     865                 :     int         call_cntr;
     866                 :     int         max_calls;
     867                 :     AttInMetadata *attinmeta;
     868                 :     MemoryContext oldcontext;
     869                 : 
     870                 :     /* stuff done only on the first call of the function */
     871          399956 :     if (SRF_IS_FIRSTCALL())
     872                 :     {
     873                 :         /* create a function context for cross-call persistence */
     874            1087 :         funcctx = SRF_FIRSTCALL_INIT();
     875                 : 
     876                 :         /*
     877                 :          * switch to memory context appropriate for multiple function calls
     878                 :          */
     879            1087 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     880                 : 
     881                 :         /*
     882                 :          * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns
     883                 :          * of the appropriate types
     884                 :          */
     885            1087 :         tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS);
     886            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
     887                 :                            TEXTOID, -1, 0);
     888            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
     889                 :                            TEXTOID, -1, 0);
     890            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit",
     891                 :                            TEXTOID, -1, 0);
     892            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category",
     893                 :                            TEXTOID, -1, 0);
     894            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc",
     895                 :                            TEXTOID, -1, 0);
     896            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc",
     897                 :                            TEXTOID, -1, 0);
     898            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context",
     899                 :                            TEXTOID, -1, 0);
     900            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype",
     901                 :                            TEXTOID, -1, 0);
     902            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source",
     903                 :                            TEXTOID, -1, 0);
     904            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val",
     905                 :                            TEXTOID, -1, 0);
     906            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
     907                 :                            TEXTOID, -1, 0);
     908            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals",
     909                 :                            TEXTARRAYOID, -1, 0);
     910            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val",
     911                 :                            TEXTOID, -1, 0);
     912            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val",
     913                 :                            TEXTOID, -1, 0);
     914            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile",
     915                 :                            TEXTOID, -1, 0);
     916            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline",
     917                 :                            INT4OID, -1, 0);
     918            1087 :         TupleDescInitEntry(tupdesc, (AttrNumber) 17, "pending_restart",
     919                 :                            BOOLOID, -1, 0);
     920                 : 
     921                 :         /*
     922                 :          * Generate attribute metadata needed later to produce tuples from raw
     923                 :          * C strings
     924                 :          */
     925            1087 :         attinmeta = TupleDescGetAttInMetadata(tupdesc);
     926            1087 :         funcctx->attinmeta = attinmeta;
     927                 : 
     928                 :         /* collect the variables, in sorted order */
     929            1087 :         guc_vars = get_guc_variables(&num_vars);
     930                 : 
     931                 :         /* use user_fctx to remember the array location */
     932            1087 :         funcctx->user_fctx = guc_vars;
     933                 : 
     934                 :         /* total number of tuples to be returned */
     935            1087 :         funcctx->max_calls = num_vars;
     936                 : 
     937            1087 :         MemoryContextSwitchTo(oldcontext);
     938                 :     }
     939                 : 
     940                 :     /* stuff done on every call of the function */
     941          399956 :     funcctx = SRF_PERCALL_SETUP();
     942                 : 
     943          399956 :     guc_vars = (struct config_generic **) funcctx->user_fctx;
     944          399956 :     call_cntr = funcctx->call_cntr;
     945          399956 :     max_calls = funcctx->max_calls;
     946          399956 :     attinmeta = funcctx->attinmeta;
     947                 : 
     948          406487 :     while (call_cntr < max_calls)    /* do when there is more left to send */
     949                 :     {
     950          405400 :         struct config_generic *conf = guc_vars[call_cntr];
     951                 :         char       *values[NUM_PG_SETTINGS_ATTS];
     952                 :         HeapTuple   tuple;
     953                 :         Datum       result;
     954                 : 
     955                 :         /* skip if marked NO_SHOW_ALL or if not visible to current user */
     956          405400 :         if ((conf->flags & GUC_NO_SHOW_ALL) ||
     957          398869 :             !ConfigOptionIsVisible(conf))
     958                 :         {
     959            6531 :             call_cntr = ++funcctx->call_cntr;
     960            6531 :             continue;
     961                 :         }
     962                 : 
     963                 :         /* extract values for the current variable */
     964          398869 :         GetConfigOptionValues(conf, (const char **) values);
     965                 : 
     966                 :         /* build a tuple */
     967          398869 :         tuple = BuildTupleFromCStrings(attinmeta, values);
     968                 : 
     969                 :         /* make the tuple into a datum */
     970          398869 :         result = HeapTupleGetDatum(tuple);
     971                 : 
     972          398869 :         SRF_RETURN_NEXT(funcctx, result);
     973                 :     }
     974                 : 
     975                 :     /* do when there is no more left */
     976            1087 :     SRF_RETURN_DONE(funcctx);
     977                 : }
     978                 : 
     979                 : /*
     980                 :  * show_all_file_settings
     981                 :  *
     982                 :  * Returns a table of all parameter settings in all configuration files
     983                 :  * which includes the config file pathname, the line number, a sequence number
     984                 :  * indicating the order in which the settings were encountered, the parameter
     985                 :  * name and value, a bool showing if the value could be applied, and possibly
     986                 :  * an associated error message.  (For problems such as syntax errors, the
     987                 :  * parameter name/value might be NULL.)
     988                 :  *
     989                 :  * Note: no filtering is done here, instead we depend on the GRANT system
     990                 :  * to prevent unprivileged users from accessing this function or the view
     991                 :  * built on top of it.
     992                 :  */
     993                 : Datum
     994               3 : show_all_file_settings(PG_FUNCTION_ARGS)
     995                 : {
     996                 : #define NUM_PG_FILE_SETTINGS_ATTS 7
     997               3 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     998                 :     ConfigVariable *conf;
     999                 :     int         seqno;
    1000                 : 
    1001                 :     /* Scan the config files using current context as workspace */
    1002               3 :     conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3);
    1003                 : 
    1004                 :     /* Build a tuplestore to return our results in */
    1005               3 :     InitMaterializedSRF(fcinfo, 0);
    1006                 : 
    1007                 :     /* Process the results and create a tuplestore */
    1008              76 :     for (seqno = 1; conf != NULL; conf = conf->next, seqno++)
    1009                 :     {
    1010                 :         Datum       values[NUM_PG_FILE_SETTINGS_ATTS];
    1011                 :         bool        nulls[NUM_PG_FILE_SETTINGS_ATTS];
    1012                 : 
    1013              73 :         memset(values, 0, sizeof(values));
    1014              73 :         memset(nulls, 0, sizeof(nulls));
    1015                 : 
    1016                 :         /* sourcefile */
    1017              73 :         if (conf->filename)
    1018              73 :             values[0] = PointerGetDatum(cstring_to_text(conf->filename));
    1019                 :         else
    1020 UNC           0 :             nulls[0] = true;
    1021                 : 
    1022                 :         /* sourceline (not meaningful if no sourcefile) */
    1023 GNC          73 :         if (conf->filename)
    1024              73 :             values[1] = Int32GetDatum(conf->sourceline);
    1025                 :         else
    1026 UNC           0 :             nulls[1] = true;
    1027                 : 
    1028                 :         /* seqno */
    1029 GNC          73 :         values[2] = Int32GetDatum(seqno);
    1030                 : 
    1031                 :         /* name */
    1032              73 :         if (conf->name)
    1033              73 :             values[3] = PointerGetDatum(cstring_to_text(conf->name));
    1034                 :         else
    1035 UNC           0 :             nulls[3] = true;
    1036                 : 
    1037                 :         /* setting */
    1038 GNC          73 :         if (conf->value)
    1039              73 :             values[4] = PointerGetDatum(cstring_to_text(conf->value));
    1040                 :         else
    1041 UNC           0 :             nulls[4] = true;
    1042                 : 
    1043                 :         /* applied */
    1044 GNC          73 :         values[5] = BoolGetDatum(conf->applied);
    1045                 : 
    1046                 :         /* error */
    1047              73 :         if (conf->errmsg)
    1048 UNC           0 :             values[6] = PointerGetDatum(cstring_to_text(conf->errmsg));
    1049                 :         else
    1050 GNC          73 :             nulls[6] = true;
    1051                 : 
    1052                 :         /* shove row into tuplestore */
    1053              73 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    1054                 :     }
    1055                 : 
    1056               3 :     return (Datum) 0;
    1057                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a