LCOV - code coverage report
Current view: top level - src/backend/utils/misc - guc_funcs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 336 382 88.0 %
Date: 2025-11-13 06:18:16 Functions: 16 16 100.0 %
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-2025, 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       38492 : ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
      44             : {
      45       38492 :     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       38492 :     if (IsInParallelMode())
      52           0 :         ereport(ERROR,
      53             :                 (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
      54             :                  errmsg("cannot set parameters during a parallel operation")));
      55             : 
      56       38492 :     switch (stmt->kind)
      57             :     {
      58       32946 :         case VAR_SET_VALUE:
      59             :         case VAR_SET_CURRENT:
      60       32946 :             if (stmt->is_local)
      61        1320 :                 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
      62       65886 :             (void) set_config_option(stmt->name,
      63       32946 :                                      ExtractSetVariableArgs(stmt),
      64       32946 :                                      (superuser() ? PGC_SUSET : PGC_USERSET),
      65             :                                      PGC_S_SESSION,
      66             :                                      action, true, 0, false);
      67       32816 :             break;
      68         642 :         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         642 :             if (strcmp(stmt->name, "TRANSACTION") == 0)
      78             :             {
      79             :                 ListCell   *head;
      80             : 
      81         580 :                 WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
      82             : 
      83        1590 :                 foreach(head, stmt->args)
      84             :                 {
      85        1030 :                     DefElem    *item = (DefElem *) lfirst(head);
      86             : 
      87        1030 :                     if (strcmp(item->defname, "transaction_isolation") == 0)
      88         478 :                         SetPGVariable("transaction_isolation",
      89         478 :                                       list_make1(item->arg), stmt->is_local);
      90         552 :                     else if (strcmp(item->defname, "transaction_read_only") == 0)
      91         546 :                         SetPGVariable("transaction_read_only",
      92         546 :                                       list_make1(item->arg), stmt->is_local);
      93           6 :                     else if (strcmp(item->defname, "transaction_deferrable") == 0)
      94           6 :                         SetPGVariable("transaction_deferrable",
      95           6 :                                       list_make1(item->arg), stmt->is_local);
      96             :                     else
      97           0 :                         elog(ERROR, "unexpected SET TRANSACTION element: %s",
      98             :                              item->defname);
      99             :                 }
     100             :             }
     101          62 :             else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0)
     102             :             {
     103             :                 ListCell   *head;
     104             : 
     105          40 :                 foreach(head, stmt->args)
     106             :                 {
     107          22 :                     DefElem    *item = (DefElem *) lfirst(head);
     108             : 
     109          22 :                     if (strcmp(item->defname, "transaction_isolation") == 0)
     110           0 :                         SetPGVariable("default_transaction_isolation",
     111           0 :                                       list_make1(item->arg), stmt->is_local);
     112          22 :                     else if (strcmp(item->defname, "transaction_read_only") == 0)
     113          22 :                         SetPGVariable("default_transaction_read_only",
     114          22 :                                       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          44 :             else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT") == 0)
     124             :             {
     125          44 :                 A_Const    *con = linitial_node(A_Const, stmt->args);
     126             : 
     127          44 :                 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          44 :                 WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
     133          44 :                 ImportSnapshot(strVal(&con->val));
     134             :             }
     135             :             else
     136           0 :                 elog(ERROR, "unexpected SET MULTI element: %s",
     137             :                      stmt->name);
     138         610 :             break;
     139         166 :         case VAR_SET_DEFAULT:
     140         166 :             if (stmt->is_local)
     141           6 :                 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
     142             :             /* fall through */
     143             :         case VAR_RESET:
     144        4892 :             (void) set_config_option(stmt->name,
     145             :                                      NULL,
     146        4892 :                                      (superuser() ? PGC_SUSET : PGC_USERSET),
     147             :                                      PGC_S_SESSION,
     148             :                                      action, true, 0, false);
     149        4862 :             break;
     150          12 :         case VAR_RESET_ALL:
     151          12 :             ResetAllOptions();
     152          12 :             break;
     153             :     }
     154             : 
     155             :     /* Invoke the post-alter hook for setting this GUC variable, by name. */
     156       38300 :     InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, stmt->name,
     157             :                                     ACL_SET, stmt->kind, false);
     158       38298 : }
     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       34558 : ExtractSetVariableArgs(VariableSetStmt *stmt)
     168             : {
     169       34558 :     switch (stmt->kind)
     170             :     {
     171       34512 :         case VAR_SET_VALUE:
     172       34512 :             return flatten_set_variable_args(stmt->name, stmt->args);
     173           4 :         case VAR_SET_CURRENT:
     174           4 :             return GetConfigOptionByName(stmt->name, NULL, false);
     175          42 :         default:
     176          42 :             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       43054 : 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       43054 :     if (args == NIL)
     201           6 :         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       43048 :     record = find_option(name, false, true, WARNING);
     208       43048 :     if (record)
     209       42982 :         flags = record->flags;
     210             :     else
     211          66 :         flags = 0;
     212             : 
     213             :     /*
     214             :      * Handle special cases for list input.
     215             :      */
     216       43048 :     if (flags & GUC_LIST_INPUT)
     217             :     {
     218             :         /* NULL represents an empty list. */
     219        1752 :         if (list_length(args) == 1)
     220             :         {
     221        1600 :             Node       *arg = (Node *) linitial(args);
     222             : 
     223        1600 :             if (IsA(arg, A_Const) &&
     224        1600 :                 ((A_Const *) arg)->isnull)
     225          14 :                 return pstrdup("");
     226             :         }
     227             :     }
     228             :     else
     229             :     {
     230             :         /* Complain if list input and non-list variable. */
     231       41296 :         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       43034 :     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       86262 :     foreach(l, args)
     245             :     {
     246       43234 :         Node       *arg = (Node *) lfirst(l);
     247             :         char       *val;
     248       43234 :         TypeName   *typeName = NULL;
     249             :         A_Const    *con;
     250             : 
     251       43234 :         if (l != list_head(args))
     252         200 :             appendStringInfoString(&buf, ", ");
     253             : 
     254       43234 :         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       43234 :         if (!IsA(arg, A_Const))
     263           0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg));
     264       43234 :         con = (A_Const *) arg;
     265             : 
     266             :         /* Complain if NULL is used with a non-list variable. */
     267       43234 :         if (con->isnull)
     268           6 :             ereport(ERROR,
     269             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     270             :                      errmsg("NULL is an invalid value for %s", name)));
     271             : 
     272       43228 :         switch (nodeTag(&con->val))
     273             :         {
     274       16888 :             case T_Integer:
     275       16888 :                 appendStringInfo(&buf, "%d", intVal(&con->val));
     276       16888 :                 break;
     277         218 :             case T_Float:
     278             :                 /* represented as a string, so just copy it */
     279         218 :                 appendStringInfoString(&buf, castNode(Float, &con->val)->fval);
     280         218 :                 break;
     281       26122 :             case T_String:
     282       26122 :                 val = strVal(&con->val);
     283       26122 :                 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       26122 :                     if (flags & GUC_LIST_QUOTE)
     319         924 :                         appendStringInfoString(&buf, quote_identifier(val));
     320             :                     else
     321       25198 :                         appendStringInfoString(&buf, val);
     322             :                 }
     323       26122 :                 break;
     324           0 :             default:
     325           0 :                 elog(ERROR, "unrecognized node type: %d",
     326             :                      (int) nodeTag(&con->val));
     327             :                 break;
     328             :         }
     329             :     }
     330             : 
     331       43028 :     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        8542 : SetPGVariable(const char *name, List *args, bool is_local)
     342             : {
     343        8542 :     char       *argstring = flatten_set_variable_args(name, args);
     344             : 
     345             :     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     346        8542 :     (void) set_config_option(name,
     347             :                              argstring,
     348        8542 :                              (superuser() ? PGC_SUSET : PGC_USERSET),
     349             :                              PGC_S_SESSION,
     350             :                              is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
     351             :                              true, 0, false);
     352        8522 : }
     353             : 
     354             : /*
     355             :  * SET command wrapped as a SQL callable function.
     356             :  */
     357             : Datum
     358        7352 : set_config_by_name(PG_FUNCTION_ARGS)
     359             : {
     360             :     char       *name;
     361             :     char       *value;
     362             :     char       *new_value;
     363             :     bool        is_local;
     364             : 
     365        7352 :     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        7352 :     name = TextDatumGetCString(PG_GETARG_DATUM(0));
     372             : 
     373             :     /* Get the desired value or set to NULL for a reset request */
     374        7352 :     if (PG_ARGISNULL(1))
     375           0 :         value = NULL;
     376             :     else
     377        7352 :         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        7352 :     if (PG_ARGISNULL(2))
     384           0 :         is_local = false;
     385             :     else
     386        7352 :         is_local = PG_GETARG_BOOL(2);
     387             : 
     388             :     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     389        7352 :     (void) set_config_option(name,
     390             :                              value,
     391        7352 :                              (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        7350 :     new_value = GetConfigOptionByName(name, NULL, false);
     398             : 
     399             :     /* Convert return string to text */
     400        7350 :     PG_RETURN_TEXT_P(cstring_to_text(new_value));
     401             : }
     402             : 
     403             : 
     404             : /*
     405             :  * SHOW command
     406             :  */
     407             : void
     408        2018 : GetPGVariable(const char *name, DestReceiver *dest)
     409             : {
     410        2018 :     if (guc_name_compare(name, "all") == 0)
     411           4 :         ShowAllGUCConfig(dest);
     412             :     else
     413        2014 :         ShowGUCConfigOption(name, dest);
     414        2018 : }
     415             : 
     416             : /*
     417             :  * Get a tuple descriptor for SHOW's result
     418             :  */
     419             : TupleDesc
     420         902 : GetPGVariableResultDesc(const char *name)
     421             : {
     422             :     TupleDesc   tupdesc;
     423             : 
     424         902 :     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         902 :         (void) GetConfigOptionByName(name, &varname, false);
     441             : 
     442             :         /* need a tuple descriptor representing a single TEXT column */
     443         874 :         tupdesc = CreateTemplateTupleDesc(1);
     444         874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
     445             :                            TEXTOID, -1, 0);
     446             :     }
     447         874 :     return tupdesc;
     448             : }
     449             : 
     450             : /*
     451             :  * SHOW one variable
     452             :  */
     453             : static void
     454        2014 : 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        2014 :     value = GetConfigOptionByName(name, &varname, false);
     463             : 
     464             :     /* need a tuple descriptor representing a single TEXT column */
     465        2014 :     tupdesc = CreateTemplateTupleDesc(1);
     466        2014 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname,
     467             :                               TEXTOID, -1, 0);
     468             : 
     469             :     /* prepare for projection of tuples */
     470        2014 :     tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
     471             : 
     472             :     /* Send it */
     473        2014 :     do_text_output_oneline(tstate, value);
     474             : 
     475        2014 :     end_tup_output(tstate);
     476        2014 : }
     477             : 
     478             : /*
     479             :  * SHOW ALL command
     480             :  */
     481             : static void
     482           4 : 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           4 :     bool        isnull[3] = {false, false, false};
     490             : 
     491             :     /* collect the variables, in sorted order */
     492           4 :     guc_vars = get_guc_variables(&num_vars);
     493             : 
     494             :     /* need a tuple descriptor representing three TEXT columns */
     495           4 :     tupdesc = CreateTemplateTupleDesc(3);
     496           4 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "name",
     497             :                               TEXTOID, -1, 0);
     498           4 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "setting",
     499             :                               TEXTOID, -1, 0);
     500           4 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description",
     501             :                               TEXTOID, -1, 0);
     502             : 
     503             :     /* prepare for projection of tuples */
     504           4 :     tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
     505             : 
     506        1654 :     for (int i = 0; i < num_vars; i++)
     507             :     {
     508        1650 :         struct config_generic *conf = guc_vars[i];
     509             :         char       *setting;
     510             : 
     511             :         /* skip if marked NO_SHOW_ALL */
     512        1650 :         if (conf->flags & GUC_NO_SHOW_ALL)
     513          24 :             continue;
     514             : 
     515             :         /* return only options visible to the current user */
     516        1626 :         if (!ConfigOptionIsVisible(conf))
     517           0 :             continue;
     518             : 
     519             :         /* assign to the values array */
     520        1626 :         values[0] = PointerGetDatum(cstring_to_text(conf->name));
     521             : 
     522        1626 :         setting = ShowGUCOption(conf, true);
     523        1626 :         if (setting)
     524             :         {
     525        1626 :             values[1] = PointerGetDatum(cstring_to_text(setting));
     526        1626 :             isnull[1] = false;
     527             :         }
     528             :         else
     529             :         {
     530           0 :             values[1] = PointerGetDatum(NULL);
     531           0 :             isnull[1] = true;
     532             :         }
     533             : 
     534        1626 :         if (conf->short_desc)
     535             :         {
     536        1626 :             values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
     537        1626 :             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        1626 :         do_tup_output(tstate, values, isnull);
     547             : 
     548             :         /* clean up */
     549        1626 :         pfree(DatumGetPointer(values[0]));
     550        1626 :         if (setting)
     551             :         {
     552        1626 :             pfree(setting);
     553        1626 :             pfree(DatumGetPointer(values[1]));
     554             :         }
     555        1626 :         if (conf->short_desc)
     556        1626 :             pfree(DatumGetPointer(values[2]));
     557             :     }
     558             : 
     559           4 :     end_tup_output(tstate);
     560           4 : }
     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        4084 : pg_settings_get_flags(PG_FUNCTION_ARGS)
     569             : {
     570             : #define MAX_GUC_FLAGS   6
     571        4084 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     572             :     struct config_generic *record;
     573        4084 :     int         cnt = 0;
     574             :     Datum       flags[MAX_GUC_FLAGS];
     575             :     ArrayType  *a;
     576             : 
     577        4084 :     record = find_option(varname, false, true, ERROR);
     578             : 
     579             :     /* return NULL if no such variable */
     580        4084 :     if (record == NULL)
     581           6 :         PG_RETURN_NULL();
     582             : 
     583        4078 :     if (record->flags & GUC_EXPLAIN)
     584         630 :         flags[cnt++] = CStringGetTextDatum("EXPLAIN");
     585        4078 :     if (record->flags & GUC_NO_RESET)
     586          30 :         flags[cnt++] = CStringGetTextDatum("NO_RESET");
     587        4078 :     if (record->flags & GUC_NO_RESET_ALL)
     588          30 :         flags[cnt++] = CStringGetTextDatum("NO_RESET_ALL");
     589        4078 :     if (record->flags & GUC_NO_SHOW_ALL)
     590           0 :         flags[cnt++] = CStringGetTextDatum("NO_SHOW_ALL");
     591        4078 :     if (record->flags & GUC_NOT_IN_SAMPLE)
     592         530 :         flags[cnt++] = CStringGetTextDatum("NOT_IN_SAMPLE");
     593        4078 :     if (record->flags & GUC_RUNTIME_COMPUTED)
     594          60 :         flags[cnt++] = CStringGetTextDatum("RUNTIME_COMPUTED");
     595             : 
     596             :     Assert(cnt <= MAX_GUC_FLAGS);
     597             : 
     598             :     /* Returns the record as Datum */
     599        4078 :     a = construct_array_builtin(flags, cnt, TEXTOID);
     600        4078 :     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     1426762 : ConfigOptionIsVisible(const struct config_generic *conf)
     608             : {
     609     1426762 :     if ((conf->flags & GUC_SUPERUSER_ONLY) &&
     610       79690 :         !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
     611         278 :         return false;
     612             :     else
     613     1426484 :         return true;
     614             : }
     615             : 
     616             : /*
     617             :  * Extract fields to show in pg_settings for given variable.
     618             :  */
     619             : static void
     620     1412504 : 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     1412504 :     values[0] = conf->name;
     628             : 
     629             :     /* setting: use ShowGUCOption in order to avoid duplicating the logic */
     630     1412504 :     values[1] = ShowGUCOption(conf, false);
     631             : 
     632             :     /* unit, if any (NULL is fine) */
     633     1412504 :     values[2] = get_config_unit_name(conf->flags);
     634             : 
     635             :     /* group */
     636     1412504 :     values[3] = _(config_group_names[conf->group]);
     637             : 
     638             :     /* short_desc */
     639     1412504 :     values[4] = conf->short_desc != NULL ? _(conf->short_desc) : NULL;
     640             : 
     641             :     /* extra_desc */
     642     1412504 :     values[5] = conf->long_desc != NULL ? _(conf->long_desc) : NULL;
     643             : 
     644             :     /* context */
     645     1412504 :     values[6] = GucContext_Names[conf->context];
     646             : 
     647             :     /* vartype */
     648     1412504 :     values[7] = config_type_names[conf->vartype];
     649             : 
     650             :     /* source */
     651     1412504 :     values[8] = GucSource_Names[conf->source];
     652             : 
     653             :     /* now get the type specific attributes */
     654     1412504 :     switch (conf->vartype)
     655             :     {
     656      414286 :         case PGC_BOOL:
     657             :             {
     658      414286 :                 const struct config_bool *lconf = &conf->_bool;
     659             : 
     660             :                 /* min_val */
     661      414286 :                 values[9] = NULL;
     662             : 
     663             :                 /* max_val */
     664      414286 :                 values[10] = NULL;
     665             : 
     666             :                 /* enumvals */
     667      414286 :                 values[11] = NULL;
     668             : 
     669             :                 /* boot_val */
     670      414286 :                 values[12] = pstrdup(lconf->boot_val ? "on" : "off");
     671             : 
     672             :                 /* reset_val */
     673      414286 :                 values[13] = pstrdup(lconf->reset_val ? "on" : "off");
     674             :             }
     675      414286 :             break;
     676             : 
     677      508650 :         case PGC_INT:
     678             :             {
     679      508650 :                 const struct config_int *lconf = &conf->_int;
     680             : 
     681             :                 /* min_val */
     682      508650 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->min);
     683      508650 :                 values[9] = pstrdup(buffer);
     684             : 
     685             :                 /* max_val */
     686      508650 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->max);
     687      508650 :                 values[10] = pstrdup(buffer);
     688             : 
     689             :                 /* enumvals */
     690      508650 :                 values[11] = NULL;
     691             : 
     692             :                 /* boot_val */
     693      508650 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
     694      508650 :                 values[12] = pstrdup(buffer);
     695             : 
     696             :                 /* reset_val */
     697      508650 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
     698      508650 :                 values[13] = pstrdup(buffer);
     699             :             }
     700      508650 :             break;
     701             : 
     702       89960 :         case PGC_REAL:
     703             :             {
     704       89960 :                 const struct config_real *lconf = &conf->_real;
     705             : 
     706             :                 /* min_val */
     707       89960 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->min);
     708       89960 :                 values[9] = pstrdup(buffer);
     709             : 
     710             :                 /* max_val */
     711       89960 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->max);
     712       89960 :                 values[10] = pstrdup(buffer);
     713             : 
     714             :                 /* enumvals */
     715       89960 :                 values[11] = NULL;
     716             : 
     717             :                 /* boot_val */
     718       89960 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
     719       89960 :                 values[12] = pstrdup(buffer);
     720             : 
     721             :                 /* reset_val */
     722       89960 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
     723       89960 :                 values[13] = pstrdup(buffer);
     724             :             }
     725       89960 :             break;
     726             : 
     727      258244 :         case PGC_STRING:
     728             :             {
     729      258244 :                 const struct config_string *lconf = &conf->_string;
     730             : 
     731             :                 /* min_val */
     732      258244 :                 values[9] = NULL;
     733             : 
     734             :                 /* max_val */
     735      258244 :                 values[10] = NULL;
     736             : 
     737             :                 /* enumvals */
     738      258244 :                 values[11] = NULL;
     739             : 
     740             :                 /* boot_val */
     741      258244 :                 if (lconf->boot_val == NULL)
     742       20700 :                     values[12] = NULL;
     743             :                 else
     744      237544 :                     values[12] = pstrdup(lconf->boot_val);
     745             : 
     746             :                 /* reset_val */
     747      258244 :                 if (lconf->reset_val == NULL)
     748        3448 :                     values[13] = NULL;
     749             :                 else
     750      254796 :                     values[13] = pstrdup(lconf->reset_val);
     751             :             }
     752      258244 :             break;
     753             : 
     754      141364 :         case PGC_ENUM:
     755             :             {
     756      141364 :                 const struct config_enum *lconf = &conf->_enum;
     757             : 
     758             :                 /* min_val */
     759      141364 :                 values[9] = NULL;
     760             : 
     761             :                 /* max_val */
     762      141364 :                 values[10] = NULL;
     763             : 
     764             :                 /* enumvals */
     765             : 
     766             :                 /*
     767             :                  * NOTE! enumvals with double quotes in them are not
     768             :                  * supported!
     769             :                  */
     770      141364 :                 values[11] = config_enum_get_options(lconf,
     771             :                                                      "{\"", "\"}", "\",\"");
     772             : 
     773             :                 /* boot_val */
     774      141364 :                 values[12] = pstrdup(config_enum_lookup_by_value(conf,
     775      141364 :                                                                  lconf->boot_val));
     776             : 
     777             :                 /* reset_val */
     778      141364 :                 values[13] = pstrdup(config_enum_lookup_by_value(conf,
     779      141364 :                                                                  lconf->reset_val));
     780             :             }
     781      141364 :             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     1513246 :     if (conf->source == PGC_S_FILE &&
     813      100742 :         has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
     814             :     {
     815      100466 :         values[14] = conf->sourcefile;
     816      100466 :         snprintf(buffer, sizeof(buffer), "%d", conf->sourceline);
     817      100466 :         values[15] = pstrdup(buffer);
     818             :     }
     819             :     else
     820             :     {
     821     1312038 :         values[14] = NULL;
     822     1312038 :         values[15] = NULL;
     823             :     }
     824             : 
     825     1412504 :     values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f";
     826     1412504 : }
     827             : 
     828             : /*
     829             :  * show_config_by_name - equiv to SHOW X command but implemented as
     830             :  * a function.
     831             :  */
     832             : Datum
     833        2058 : show_config_by_name(PG_FUNCTION_ARGS)
     834             : {
     835        2058 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     836             :     char       *varval;
     837             : 
     838             :     /* Get the value */
     839        2058 :     varval = GetConfigOptionByName(varname, NULL, false);
     840             : 
     841             :     /* Convert to text */
     842        2052 :     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          24 : show_config_by_name_missing_ok(PG_FUNCTION_ARGS)
     852             : {
     853          24 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     854          24 :     bool        missing_ok = PG_GETARG_BOOL(1);
     855             :     char       *varval;
     856             : 
     857             :     /* Get the value */
     858          24 :     varval = GetConfigOptionByName(varname, NULL, missing_ok);
     859             : 
     860             :     /* return NULL if no such variable */
     861          18 :     if (varval == NULL)
     862           6 :         PG_RETURN_NULL();
     863             : 
     864             :     /* Convert to text */
     865          12 :     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     1415964 : 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     1415964 :     if (SRF_IS_FIRSTCALL())
     888             :     {
     889             :         /* create a function context for cross-call persistence */
     890        3460 :         funcctx = SRF_FIRSTCALL_INIT();
     891             : 
     892             :         /*
     893             :          * switch to memory context appropriate for multiple function calls
     894             :          */
     895        3460 :         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        3460 :         tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS);
     902        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
     903             :                            TEXTOID, -1, 0);
     904        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
     905             :                            TEXTOID, -1, 0);
     906        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit",
     907             :                            TEXTOID, -1, 0);
     908        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category",
     909             :                            TEXTOID, -1, 0);
     910        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc",
     911             :                            TEXTOID, -1, 0);
     912        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc",
     913             :                            TEXTOID, -1, 0);
     914        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context",
     915             :                            TEXTOID, -1, 0);
     916        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype",
     917             :                            TEXTOID, -1, 0);
     918        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source",
     919             :                            TEXTOID, -1, 0);
     920        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val",
     921             :                            TEXTOID, -1, 0);
     922        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
     923             :                            TEXTOID, -1, 0);
     924        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals",
     925             :                            TEXTARRAYOID, -1, 0);
     926        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val",
     927             :                            TEXTOID, -1, 0);
     928        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val",
     929             :                            TEXTOID, -1, 0);
     930        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile",
     931             :                            TEXTOID, -1, 0);
     932        3460 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline",
     933             :                            INT4OID, -1, 0);
     934        3460 :         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        3460 :         attinmeta = TupleDescGetAttInMetadata(tupdesc);
     942        3460 :         funcctx->attinmeta = attinmeta;
     943             : 
     944             :         /* collect the variables, in sorted order */
     945        3460 :         guc_vars = get_guc_variables(&num_vars);
     946             : 
     947             :         /* use user_fctx to remember the array location */
     948        3460 :         funcctx->user_fctx = guc_vars;
     949             : 
     950             :         /* total number of tuples to be returned */
     951        3460 :         funcctx->max_calls = num_vars;
     952             : 
     953        3460 :         MemoryContextSwitchTo(oldcontext);
     954             :     }
     955             : 
     956             :     /* stuff done on every call of the function */
     957     1415964 :     funcctx = SRF_PERCALL_SETUP();
     958             : 
     959     1415964 :     guc_vars = (struct config_generic **) funcctx->user_fctx;
     960     1415964 :     call_cntr = funcctx->call_cntr;
     961     1415964 :     max_calls = funcctx->max_calls;
     962     1415964 :     attinmeta = funcctx->attinmeta;
     963             : 
     964     1437018 :     while (call_cntr < max_calls)    /* do when there is more left to send */
     965             :     {
     966     1433558 :         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     1433558 :         if ((conf->flags & GUC_NO_SHOW_ALL) ||
     973     1412780 :             !ConfigOptionIsVisible(conf))
     974             :         {
     975       21054 :             call_cntr = ++funcctx->call_cntr;
     976       21054 :             continue;
     977             :         }
     978             : 
     979             :         /* extract values for the current variable */
     980     1412504 :         GetConfigOptionValues(conf, (const char **) values);
     981             : 
     982             :         /* build a tuple */
     983     1412504 :         tuple = BuildTupleFromCStrings(attinmeta, values);
     984             : 
     985             :         /* make the tuple into a datum */
     986     1412504 :         result = HeapTupleGetDatum(tuple);
     987             : 
     988     1412504 :         SRF_RETURN_NEXT(funcctx, result);
     989             :     }
     990             : 
     991             :     /* do when there is no more left */
     992        3460 :     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           6 : show_all_file_settings(PG_FUNCTION_ARGS)
    1011             : {
    1012             : #define NUM_PG_FILE_SETTINGS_ATTS 7
    1013           6 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1014             :     ConfigVariable *conf;
    1015             : 
    1016             :     /* Scan the config files using current context as workspace */
    1017           6 :     conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3);
    1018             : 
    1019             :     /* Build a tuplestore to return our results in */
    1020           6 :     InitMaterializedSRF(fcinfo, 0);
    1021             : 
    1022             :     /* Process the results and create a tuplestore */
    1023         178 :     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         172 :         memset(values, 0, sizeof(values));
    1029         172 :         memset(nulls, 0, sizeof(nulls));
    1030             : 
    1031             :         /* sourcefile */
    1032         172 :         if (conf->filename)
    1033         172 :             values[0] = PointerGetDatum(cstring_to_text(conf->filename));
    1034             :         else
    1035           0 :             nulls[0] = true;
    1036             : 
    1037             :         /* sourceline (not meaningful if no sourcefile) */
    1038         172 :         if (conf->filename)
    1039         172 :             values[1] = Int32GetDatum(conf->sourceline);
    1040             :         else
    1041           0 :             nulls[1] = true;
    1042             : 
    1043             :         /* seqno */
    1044         172 :         values[2] = Int32GetDatum(seqno);
    1045             : 
    1046             :         /* name */
    1047         172 :         if (conf->name)
    1048         172 :             values[3] = PointerGetDatum(cstring_to_text(conf->name));
    1049             :         else
    1050           0 :             nulls[3] = true;
    1051             : 
    1052             :         /* setting */
    1053         172 :         if (conf->value)
    1054         172 :             values[4] = PointerGetDatum(cstring_to_text(conf->value));
    1055             :         else
    1056           0 :             nulls[4] = true;
    1057             : 
    1058             :         /* applied */
    1059         172 :         values[5] = BoolGetDatum(conf->applied);
    1060             : 
    1061             :         /* error */
    1062         172 :         if (conf->errmsg)
    1063           0 :             values[6] = PointerGetDatum(cstring_to_text(conf->errmsg));
    1064             :         else
    1065         172 :             nulls[6] = true;
    1066             : 
    1067             :         /* shove row into tuplestore */
    1068         172 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    1069             :     }
    1070             : 
    1071           6 :     return (Datum) 0;
    1072             : }

Generated by: LCOV version 1.16