LCOV - code coverage report
Current view: top level - src/backend/utils/misc - guc_funcs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 88.0 % 382 336
Test Date: 2026-03-03 04:14:52 Functions: 100.0 % 16 16
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1