LCOV - code coverage report
Current view: top level - src/backend/utils/misc - guc_funcs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 322 373 86.3 %
Date: 2024-03-28 11:11:48 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       33800 : ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
      44             : {
      45       33800 :     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       33800 :     if (IsInParallelMode())
      52           0 :         ereport(ERROR,
      53             :                 (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
      54             :                  errmsg("cannot set parameters during a parallel operation")));
      55             : 
      56       33800 :     switch (stmt->kind)
      57             :     {
      58       29162 :         case VAR_SET_VALUE:
      59             :         case VAR_SET_CURRENT:
      60       29162 :             if (stmt->is_local)
      61        1098 :                 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
      62       58324 :             (void) set_config_option(stmt->name,
      63       29162 :                                      ExtractSetVariableArgs(stmt),
      64       29162 :                                      (superuser() ? PGC_SUSET : PGC_USERSET),
      65             :                                      PGC_S_SESSION,
      66             :                                      action, true, 0, false);
      67       29044 :             break;
      68         566 :         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         566 :             if (strcmp(stmt->name, "TRANSACTION") == 0)
      78             :             {
      79             :                 ListCell   *head;
      80             : 
      81         510 :                 WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
      82             : 
      83        1380 :                 foreach(head, stmt->args)
      84             :                 {
      85         890 :                     DefElem    *item = (DefElem *) lfirst(head);
      86             : 
      87         890 :                     if (strcmp(item->defname, "transaction_isolation") == 0)
      88         408 :                         SetPGVariable("transaction_isolation",
      89         408 :                                       list_make1(item->arg), stmt->is_local);
      90         482 :                     else if (strcmp(item->defname, "transaction_read_only") == 0)
      91         476 :                         SetPGVariable("transaction_read_only",
      92         476 :                                       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          56 :             else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0)
     102             :             {
     103             :                 ListCell   *head;
     104             : 
     105          24 :                 foreach(head, stmt->args)
     106             :                 {
     107          12 :                     DefElem    *item = (DefElem *) lfirst(head);
     108             : 
     109          12 :                     if (strcmp(item->defname, "transaction_isolation") == 0)
     110           0 :                         SetPGVariable("default_transaction_isolation",
     111           0 :                                       list_make1(item->arg), stmt->is_local);
     112          12 :                     else if (strcmp(item->defname, "transaction_read_only") == 0)
     113          12 :                         SetPGVariable("default_transaction_read_only",
     114          12 :                                       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         534 :             break;
     139         148 :         case VAR_SET_DEFAULT:
     140         148 :             if (stmt->is_local)
     141           2 :                 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
     142             :             /* fall through */
     143             :         case VAR_RESET:
     144        4072 :             (void) set_config_option(stmt->name,
     145             :                                      NULL,
     146        4072 :                                      (superuser() ? PGC_SUSET : PGC_USERSET),
     147             :                                      PGC_S_SESSION,
     148             :                                      action, true, 0, false);
     149        4042 :             break;
     150           0 :         case VAR_RESET_ALL:
     151           0 :             ResetAllOptions();
     152           0 :             break;
     153             :     }
     154             : 
     155             :     /* Invoke the post-alter hook for setting this GUC variable, by name. */
     156       33620 :     InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, stmt->name,
     157             :                                     ACL_SET, stmt->kind, false);
     158       33618 : }
     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       30500 : ExtractSetVariableArgs(VariableSetStmt *stmt)
     168             : {
     169       30500 :     switch (stmt->kind)
     170             :     {
     171       30472 :         case VAR_SET_VALUE:
     172       30472 :             return flatten_set_variable_args(stmt->name, stmt->args);
     173           0 :         case VAR_SET_CURRENT:
     174           0 :             return GetConfigOptionByName(stmt->name, NULL, false);
     175          28 :         default:
     176          28 :             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       38492 : 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       38492 :     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       38486 :     record = find_option(name, false, true, WARNING);
     208       38486 :     if (record)
     209       38424 :         flags = record->flags;
     210             :     else
     211          62 :         flags = 0;
     212             : 
     213             :     /* Complain if list input and non-list variable */
     214       75524 :     if ((flags & GUC_LIST_INPUT) == 0 &&
     215       37038 :         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       38486 :     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       77138 :     foreach(l, args)
     228             :     {
     229       38652 :         Node       *arg = (Node *) lfirst(l);
     230             :         char       *val;
     231       38652 :         TypeName   *typeName = NULL;
     232             :         A_Const    *con;
     233             : 
     234       38652 :         if (l != list_head(args))
     235         166 :             appendStringInfoString(&buf, ", ");
     236             : 
     237       38652 :         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       38652 :         if (!IsA(arg, A_Const))
     246           0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg));
     247       38652 :         con = (A_Const *) arg;
     248             : 
     249       38652 :         switch (nodeTag(&con->val))
     250             :         {
     251       15506 :             case T_Integer:
     252       15506 :                 appendStringInfo(&buf, "%d", intVal(&con->val));
     253       15506 :                 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       22928 :             case T_String:
     259       22928 :                 val = strVal(&con->val);
     260       22928 :                 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       22928 :                     if (flags & GUC_LIST_QUOTE)
     293         730 :                         appendStringInfoString(&buf, quote_identifier(val));
     294             :                     else
     295       22198 :                         appendStringInfoString(&buf, val);
     296             :                 }
     297       22928 :                 break;
     298           0 :             default:
     299           0 :                 elog(ERROR, "unrecognized node type: %d",
     300             :                      (int) nodeTag(&con->val));
     301             :                 break;
     302             :         }
     303             :     }
     304             : 
     305       38486 :     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        8020 : SetPGVariable(const char *name, List *args, bool is_local)
     316             : {
     317        8020 :     char       *argstring = flatten_set_variable_args(name, args);
     318             : 
     319             :     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     320        8020 :     (void) set_config_option(name,
     321             :                              argstring,
     322        8020 :                              (superuser() ? PGC_SUSET : PGC_USERSET),
     323             :                              PGC_S_SESSION,
     324             :                              is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
     325             :                              true, 0, false);
     326        8000 : }
     327             : 
     328             : /*
     329             :  * SET command wrapped as a SQL callable function.
     330             :  */
     331             : Datum
     332        4670 : set_config_by_name(PG_FUNCTION_ARGS)
     333             : {
     334             :     char       *name;
     335             :     char       *value;
     336             :     char       *new_value;
     337             :     bool        is_local;
     338             : 
     339        4670 :     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        4670 :     name = TextDatumGetCString(PG_GETARG_DATUM(0));
     346             : 
     347             :     /* Get the desired value or set to NULL for a reset request */
     348        4670 :     if (PG_ARGISNULL(1))
     349           0 :         value = NULL;
     350             :     else
     351        4670 :         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        4670 :     if (PG_ARGISNULL(2))
     358           0 :         is_local = false;
     359             :     else
     360        4670 :         is_local = PG_GETARG_BOOL(2);
     361             : 
     362             :     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     363        4670 :     (void) set_config_option(name,
     364             :                              value,
     365        4670 :                              (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        4668 :     new_value = GetConfigOptionByName(name, NULL, false);
     372             : 
     373             :     /* Convert return string to text */
     374        4668 :     PG_RETURN_TEXT_P(cstring_to_text(new_value));
     375             : }
     376             : 
     377             : 
     378             : /*
     379             :  * SHOW command
     380             :  */
     381             : void
     382        1798 : GetPGVariable(const char *name, DestReceiver *dest)
     383             : {
     384        1798 :     if (guc_name_compare(name, "all") == 0)
     385           4 :         ShowAllGUCConfig(dest);
     386             :     else
     387        1794 :         ShowGUCConfigOption(name, dest);
     388        1798 : }
     389             : 
     390             : /*
     391             :  * Get a tuple descriptor for SHOW's result
     392             :  */
     393             : TupleDesc
     394         816 : GetPGVariableResultDesc(const char *name)
     395             : {
     396             :     TupleDesc   tupdesc;
     397             : 
     398         816 :     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         816 :         (void) GetConfigOptionByName(name, &varname, false);
     415             : 
     416             :         /* need a tuple descriptor representing a single TEXT column */
     417         788 :         tupdesc = CreateTemplateTupleDesc(1);
     418         788 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
     419             :                            TEXTOID, -1, 0);
     420             :     }
     421         788 :     return tupdesc;
     422             : }
     423             : 
     424             : /*
     425             :  * SHOW one variable
     426             :  */
     427             : static void
     428        1794 : 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        1794 :     value = GetConfigOptionByName(name, &varname, false);
     437             : 
     438             :     /* need a tuple descriptor representing a single TEXT column */
     439        1794 :     tupdesc = CreateTemplateTupleDesc(1);
     440        1794 :     TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname,
     441             :                               TEXTOID, -1, 0);
     442             : 
     443             :     /* prepare for projection of tuples */
     444        1794 :     tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
     445             : 
     446             :     /* Send it */
     447        1794 :     do_text_output_oneline(tstate, value);
     448             : 
     449        1794 :     end_tup_output(tstate);
     450        1794 : }
     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        1538 :     for (int i = 0; i < num_vars; i++)
     481             :     {
     482        1534 :         struct config_generic *conf = guc_vars[i];
     483             :         char       *setting;
     484             : 
     485             :         /* skip if marked NO_SHOW_ALL */
     486        1534 :         if (conf->flags & GUC_NO_SHOW_ALL)
     487          24 :             continue;
     488             : 
     489             :         /* return only options visible to the current user */
     490        1510 :         if (!ConfigOptionIsVisible(conf))
     491           0 :             continue;
     492             : 
     493             :         /* assign to the values array */
     494        1510 :         values[0] = PointerGetDatum(cstring_to_text(conf->name));
     495             : 
     496        1510 :         setting = ShowGUCOption(conf, true);
     497        1510 :         if (setting)
     498             :         {
     499        1510 :             values[1] = PointerGetDatum(cstring_to_text(setting));
     500        1510 :             isnull[1] = false;
     501             :         }
     502             :         else
     503             :         {
     504           0 :             values[1] = PointerGetDatum(NULL);
     505           0 :             isnull[1] = true;
     506             :         }
     507             : 
     508        1510 :         if (conf->short_desc)
     509             :         {
     510        1510 :             values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
     511        1510 :             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        1510 :         do_tup_output(tstate, values, isnull);
     521             : 
     522             :         /* clean up */
     523        1510 :         pfree(DatumGetPointer(values[0]));
     524        1510 :         if (setting)
     525             :         {
     526        1510 :             pfree(setting);
     527        1510 :             pfree(DatumGetPointer(values[1]));
     528             :         }
     529        1510 :         if (conf->short_desc)
     530        1510 :             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        3794 : pg_settings_get_flags(PG_FUNCTION_ARGS)
     543             : {
     544             : #define MAX_GUC_FLAGS   6
     545        3794 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     546             :     struct config_generic *record;
     547        3794 :     int         cnt = 0;
     548             :     Datum       flags[MAX_GUC_FLAGS];
     549             :     ArrayType  *a;
     550             : 
     551        3794 :     record = find_option(varname, false, true, ERROR);
     552             : 
     553             :     /* return NULL if no such variable */
     554        3794 :     if (record == NULL)
     555           6 :         PG_RETURN_NULL();
     556             : 
     557        3788 :     if (record->flags & GUC_EXPLAIN)
     558         600 :         flags[cnt++] = CStringGetTextDatum("EXPLAIN");
     559        3788 :     if (record->flags & GUC_NO_RESET)
     560          30 :         flags[cnt++] = CStringGetTextDatum("NO_RESET");
     561        3788 :     if (record->flags & GUC_NO_RESET_ALL)
     562          30 :         flags[cnt++] = CStringGetTextDatum("NO_RESET_ALL");
     563        3788 :     if (record->flags & GUC_NO_SHOW_ALL)
     564           0 :         flags[cnt++] = CStringGetTextDatum("NO_SHOW_ALL");
     565        3788 :     if (record->flags & GUC_NOT_IN_SAMPLE)
     566         490 :         flags[cnt++] = CStringGetTextDatum("NOT_IN_SAMPLE");
     567        3788 :     if (record->flags & GUC_RUNTIME_COMPUTED)
     568          50 :         flags[cnt++] = CStringGetTextDatum("RUNTIME_COMPUTED");
     569             : 
     570             :     Assert(cnt <= MAX_GUC_FLAGS);
     571             : 
     572             :     /* Returns the record as Datum */
     573        3788 :     a = construct_array_builtin(flags, cnt, TEXTOID);
     574        3788 :     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     1482230 : ConfigOptionIsVisible(struct config_generic *conf)
     582             : {
     583     1482230 :     if ((conf->flags & GUC_SUPERUSER_ONLY) &&
     584       77570 :         !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
     585           2 :         return false;
     586             :     else
     587     1482228 :         return true;
     588             : }
     589             : 
     590             : /*
     591             :  * Extract fields to show in pg_settings for given variable.
     592             :  */
     593             : static void
     594     1471770 : GetConfigOptionValues(struct config_generic *conf, const char **values)
     595             : {
     596             :     char        buffer[256];
     597             : 
     598             :     /* first get the generic attributes */
     599             : 
     600             :     /* name */
     601     1471770 :     values[0] = conf->name;
     602             : 
     603             :     /* setting: use ShowGUCOption in order to avoid duplicating the logic */
     604     1471770 :     values[1] = ShowGUCOption(conf, false);
     605             : 
     606             :     /* unit, if any (NULL is fine) */
     607     1471770 :     values[2] = get_config_unit_name(conf->flags);
     608             : 
     609             :     /* group */
     610     1471770 :     values[3] = _(config_group_names[conf->group]);
     611             : 
     612             :     /* short_desc */
     613     1471770 :     values[4] = conf->short_desc != NULL ? _(conf->short_desc) : NULL;
     614             : 
     615             :     /* extra_desc */
     616     1471770 :     values[5] = conf->long_desc != NULL ? _(conf->long_desc) : NULL;
     617             : 
     618             :     /* context */
     619     1471770 :     values[6] = GucContext_Names[conf->context];
     620             : 
     621             :     /* vartype */
     622     1471770 :     values[7] = config_type_names[conf->vartype];
     623             : 
     624             :     /* source */
     625     1471770 :     values[8] = GucSource_Names[conf->source];
     626             : 
     627             :     /* now get the type specific attributes */
     628     1471770 :     switch (conf->vartype)
     629             :     {
     630      426012 :         case PGC_BOOL:
     631             :             {
     632      426012 :                 struct config_bool *lconf = (struct config_bool *) conf;
     633             : 
     634             :                 /* min_val */
     635      426012 :                 values[9] = NULL;
     636             : 
     637             :                 /* max_val */
     638      426012 :                 values[10] = NULL;
     639             : 
     640             :                 /* enumvals */
     641      426012 :                 values[11] = NULL;
     642             : 
     643             :                 /* boot_val */
     644      426012 :                 values[12] = pstrdup(lconf->boot_val ? "on" : "off");
     645             : 
     646             :                 /* reset_val */
     647      426012 :                 values[13] = pstrdup(lconf->reset_val ? "on" : "off");
     648             :             }
     649      426012 :             break;
     650             : 
     651      530750 :         case PGC_INT:
     652             :             {
     653      530750 :                 struct config_int *lconf = (struct config_int *) conf;
     654             : 
     655             :                 /* min_val */
     656      530750 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->min);
     657      530750 :                 values[9] = pstrdup(buffer);
     658             : 
     659             :                 /* max_val */
     660      530750 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->max);
     661      530750 :                 values[10] = pstrdup(buffer);
     662             : 
     663             :                 /* enumvals */
     664      530750 :                 values[11] = NULL;
     665             : 
     666             :                 /* boot_val */
     667      530750 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
     668      530750 :                 values[12] = pstrdup(buffer);
     669             : 
     670             :                 /* reset_val */
     671      530750 :                 snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
     672      530750 :                 values[13] = pstrdup(buffer);
     673             :             }
     674      530750 :             break;
     675             : 
     676       92976 :         case PGC_REAL:
     677             :             {
     678       92976 :                 struct config_real *lconf = (struct config_real *) conf;
     679             : 
     680             :                 /* min_val */
     681       92976 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->min);
     682       92976 :                 values[9] = pstrdup(buffer);
     683             : 
     684             :                 /* max_val */
     685       92976 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->max);
     686       92976 :                 values[10] = pstrdup(buffer);
     687             : 
     688             :                 /* enumvals */
     689       92976 :                 values[11] = NULL;
     690             : 
     691             :                 /* boot_val */
     692       92976 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
     693       92976 :                 values[12] = pstrdup(buffer);
     694             : 
     695             :                 /* reset_val */
     696       92976 :                 snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
     697       92976 :                 values[13] = pstrdup(buffer);
     698             :             }
     699       92976 :             break;
     700             : 
     701      271016 :         case PGC_STRING:
     702             :             {
     703      271016 :                 struct config_string *lconf = (struct config_string *) conf;
     704             : 
     705             :                 /* min_val */
     706      271016 :                 values[9] = NULL;
     707             : 
     708             :                 /* max_val */
     709      271016 :                 values[10] = NULL;
     710             : 
     711             :                 /* enumvals */
     712      271016 :                 values[11] = NULL;
     713             : 
     714             :                 /* boot_val */
     715      271016 :                 if (lconf->boot_val == NULL)
     716       23244 :                     values[12] = NULL;
     717             :                 else
     718      247772 :                     values[12] = pstrdup(lconf->boot_val);
     719             : 
     720             :                 /* reset_val */
     721      271016 :                 if (lconf->reset_val == NULL)
     722        3874 :                     values[13] = NULL;
     723             :                 else
     724      267142 :                     values[13] = pstrdup(lconf->reset_val);
     725             :             }
     726      271016 :             break;
     727             : 
     728      151016 :         case PGC_ENUM:
     729             :             {
     730      151016 :                 struct config_enum *lconf = (struct config_enum *) conf;
     731             : 
     732             :                 /* min_val */
     733      151016 :                 values[9] = NULL;
     734             : 
     735             :                 /* max_val */
     736      151016 :                 values[10] = NULL;
     737             : 
     738             :                 /* enumvals */
     739             : 
     740             :                 /*
     741             :                  * NOTE! enumvals with double quotes in them are not
     742             :                  * supported!
     743             :                  */
     744      151016 :                 values[11] = config_enum_get_options((struct config_enum *) conf,
     745             :                                                      "{\"", "\"}", "\",\"");
     746             : 
     747             :                 /* boot_val */
     748      151016 :                 values[12] = pstrdup(config_enum_lookup_by_value(lconf,
     749             :                                                                  lconf->boot_val));
     750             : 
     751             :                 /* reset_val */
     752      151016 :                 values[13] = pstrdup(config_enum_lookup_by_value(lconf,
     753             :                                                                  lconf->reset_val));
     754             :             }
     755      151016 :             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     1583508 :     if (conf->source == PGC_S_FILE &&
     787      111738 :         has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
     788             :     {
     789      111738 :         values[14] = conf->sourcefile;
     790      111738 :         snprintf(buffer, sizeof(buffer), "%d", conf->sourceline);
     791      111738 :         values[15] = pstrdup(buffer);
     792             :     }
     793             :     else
     794             :     {
     795     1360032 :         values[14] = NULL;
     796     1360032 :         values[15] = NULL;
     797             :     }
     798             : 
     799     1471770 :     values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f";
     800     1471770 : }
     801             : 
     802             : /*
     803             :  * show_config_by_name - equiv to SHOW X command but implemented as
     804             :  * a function.
     805             :  */
     806             : Datum
     807        1644 : show_config_by_name(PG_FUNCTION_ARGS)
     808             : {
     809        1644 :     char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
     810             :     char       *varval;
     811             : 
     812             :     /* Get the value */
     813        1644 :     varval = GetConfigOptionByName(varname, NULL, false);
     814             : 
     815             :     /* Convert to text */
     816        1638 :     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     1475644 : 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     1475644 :     if (SRF_IS_FIRSTCALL())
     862             :     {
     863             :         /* create a function context for cross-call persistence */
     864        3874 :         funcctx = SRF_FIRSTCALL_INIT();
     865             : 
     866             :         /*
     867             :          * switch to memory context appropriate for multiple function calls
     868             :          */
     869        3874 :         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        3874 :         tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS);
     876        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
     877             :                            TEXTOID, -1, 0);
     878        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
     879             :                            TEXTOID, -1, 0);
     880        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit",
     881             :                            TEXTOID, -1, 0);
     882        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category",
     883             :                            TEXTOID, -1, 0);
     884        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc",
     885             :                            TEXTOID, -1, 0);
     886        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc",
     887             :                            TEXTOID, -1, 0);
     888        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context",
     889             :                            TEXTOID, -1, 0);
     890        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype",
     891             :                            TEXTOID, -1, 0);
     892        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source",
     893             :                            TEXTOID, -1, 0);
     894        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val",
     895             :                            TEXTOID, -1, 0);
     896        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
     897             :                            TEXTOID, -1, 0);
     898        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals",
     899             :                            TEXTARRAYOID, -1, 0);
     900        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val",
     901             :                            TEXTOID, -1, 0);
     902        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val",
     903             :                            TEXTOID, -1, 0);
     904        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile",
     905             :                            TEXTOID, -1, 0);
     906        3874 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline",
     907             :                            INT4OID, -1, 0);
     908        3874 :         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        3874 :         attinmeta = TupleDescGetAttInMetadata(tupdesc);
     916        3874 :         funcctx->attinmeta = attinmeta;
     917             : 
     918             :         /* collect the variables, in sorted order */
     919        3874 :         guc_vars = get_guc_variables(&num_vars);
     920             : 
     921             :         /* use user_fctx to remember the array location */
     922        3874 :         funcctx->user_fctx = guc_vars;
     923             : 
     924             :         /* total number of tuples to be returned */
     925        3874 :         funcctx->max_calls = num_vars;
     926             : 
     927        3874 :         MemoryContextSwitchTo(oldcontext);
     928             :     }
     929             : 
     930             :     /* stuff done on every call of the function */
     931     1475644 :     funcctx = SRF_PERCALL_SETUP();
     932             : 
     933     1475644 :     guc_vars = (struct config_generic **) funcctx->user_fctx;
     934     1475644 :     call_cntr = funcctx->call_cntr;
     935     1475644 :     max_calls = funcctx->max_calls;
     936     1475644 :     attinmeta = funcctx->attinmeta;
     937             : 
     938     1498906 :     while (call_cntr < max_calls)    /* do when there is more left to send */
     939             :     {
     940     1495032 :         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     1495032 :         if ((conf->flags & GUC_NO_SHOW_ALL) ||
     947     1471770 :             !ConfigOptionIsVisible(conf))
     948             :         {
     949       23262 :             call_cntr = ++funcctx->call_cntr;
     950       23262 :             continue;
     951             :         }
     952             : 
     953             :         /* extract values for the current variable */
     954     1471770 :         GetConfigOptionValues(conf, (const char **) values);
     955             : 
     956             :         /* build a tuple */
     957     1471770 :         tuple = BuildTupleFromCStrings(attinmeta, values);
     958             : 
     959             :         /* make the tuple into a datum */
     960     1471770 :         result = HeapTupleGetDatum(tuple);
     961             : 
     962     1471770 :         SRF_RETURN_NEXT(funcctx, result);
     963             :     }
     964             : 
     965             :     /* do when there is no more left */
     966        3874 :     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         164 :     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         158 :         memset(values, 0, sizeof(values));
    1004         158 :         memset(nulls, 0, sizeof(nulls));
    1005             : 
    1006             :         /* sourcefile */
    1007         158 :         if (conf->filename)
    1008         158 :             values[0] = PointerGetDatum(cstring_to_text(conf->filename));
    1009             :         else
    1010           0 :             nulls[0] = true;
    1011             : 
    1012             :         /* sourceline (not meaningful if no sourcefile) */
    1013         158 :         if (conf->filename)
    1014         158 :             values[1] = Int32GetDatum(conf->sourceline);
    1015             :         else
    1016           0 :             nulls[1] = true;
    1017             : 
    1018             :         /* seqno */
    1019         158 :         values[2] = Int32GetDatum(seqno);
    1020             : 
    1021             :         /* name */
    1022         158 :         if (conf->name)
    1023         158 :             values[3] = PointerGetDatum(cstring_to_text(conf->name));
    1024             :         else
    1025           0 :             nulls[3] = true;
    1026             : 
    1027             :         /* setting */
    1028         158 :         if (conf->value)
    1029         158 :             values[4] = PointerGetDatum(cstring_to_text(conf->value));
    1030             :         else
    1031           0 :             nulls[4] = true;
    1032             : 
    1033             :         /* applied */
    1034         158 :         values[5] = BoolGetDatum(conf->applied);
    1035             : 
    1036             :         /* error */
    1037         158 :         if (conf->errmsg)
    1038           0 :             values[6] = PointerGetDatum(cstring_to_text(conf->errmsg));
    1039             :         else
    1040         158 :             nulls[6] = true;
    1041             : 
    1042             :         /* shove row into tuplestore */
    1043         158 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    1044             :     }
    1045             : 
    1046           6 :     return (Datum) 0;
    1047             : }

Generated by: LCOV version 1.14