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

Generated by: LCOV version 1.14