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

Generated by: LCOV version 2.0-1