Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  guc_funcs.c

  Sprache: C
 

/*--------------------------------------------------------------------
 *
 * guc_funcs.c
 *
 * SQL commands and SQL-accessible functions related to GUC variables.
 *
 *
 * Copyright (c) 2000-2025, PostgreSQL Global Development Group
 * Written by Peter Eisentraut <peter_e@gmx.net>.
 *
 * IDENTIFICATION
 *   src/backend/utils/misc/guc_funcs.c
 *
 *--------------------------------------------------------------------
 */

#include "postgres.h"

#include <sys/stat.h>
#include <unistd.h>

#include "access/xact.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_parameter_acl.h"
#include "funcapi.h"
#include "guc_internal.h"
#include "miscadmin.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc_tables.h"
#include "utils/snapmgr.h"

static char *flatten_set_variable_args(const char *name, List *args);
static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
static void ShowAllGUCConfig(DestReceiver *dest);


/*
 * SET command
 */

void
ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
{
 GucAction action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET;

 /*
  * Workers synchronize these parameters at the start of the parallel
  * operation; then, we block SET during the operation.
 */

 if (IsInParallelMode())
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
     errmsg("cannot set parameters during a parallel operation")));

 switch (stmt->kind)
 {
  case VAR_SET_VALUE:
  case VAR_SET_CURRENT:
   if (stmt->is_local)
    WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
   (void) set_config_option(stmt->name,
          ExtractSetVariableArgs(stmt),
          (superuser() ? PGC_SUSET : PGC_USERSET),
          PGC_S_SESSION,
          action, true0false);
   break;
  case VAR_SET_MULTI:

   /*
    * Special-case SQL syntaxes.  The TRANSACTION and SESSION
    * CHARACTERISTICS cases effectively set more than one variable
    * per statement.  TRANSACTION SNAPSHOT only takes one argument,
    * but we put it here anyway since it's a special case and not
    * related to any GUC variable.
 */

   if (strcmp(stmt->name, "TRANSACTION") == 0)
   {
    ListCell   *head;

    WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");

    foreach(head, stmt->args)
    {
     DefElem    *item = (DefElem *) lfirst(head);

     if (strcmp(item->defname, "transaction_isolation") == 0)
      SetPGVariable("transaction_isolation",
           list_make1(item->arg), stmt->is_local);
     else if (strcmp(item->defname, "transaction_read_only") == 0)
      SetPGVariable("transaction_read_only",
           list_make1(item->arg), stmt->is_local);
     else if (strcmp(item->defname, "transaction_deferrable") == 0)
      SetPGVariable("transaction_deferrable",
           list_make1(item->arg), stmt->is_local);
     else
      elog(ERROR, "unexpected SET TRANSACTION element: %s",
        item->defname);
    }
   }
   else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0)
   {
    ListCell   *head;

    foreach(head, stmt->args)
    {
     DefElem    *item = (DefElem *) lfirst(head);

     if (strcmp(item->defname, "transaction_isolation") == 0)
      SetPGVariable("default_transaction_isolation",
           list_make1(item->arg), stmt->is_local);
     else if (strcmp(item->defname, "transaction_read_only") == 0)
      SetPGVariable("default_transaction_read_only",
           list_make1(item->arg), stmt->is_local);
     else if (strcmp(item->defname, "transaction_deferrable") == 0)
      SetPGVariable("default_transaction_deferrable",
           list_make1(item->arg), stmt->is_local);
     else
      elog(ERROR, "unexpected SET SESSION element: %s",
        item->defname);
    }
   }
   else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT") == 0)
   {
    A_Const    *con = linitial_node(A_Const, stmt->args);

    if (stmt->is_local)
     ereport(ERROR,
       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
        errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented")));

    WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
    ImportSnapshot(strVal(&con->val));
   }
   else
    elog(ERROR, "unexpected SET MULTI element: %s",
      stmt->name);
   break;
  case VAR_SET_DEFAULT:
   if (stmt->is_local)
    WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
   /* fall through */
  case VAR_RESET:
   (void) set_config_option(stmt->name,
          NULL,
          (superuser() ? PGC_SUSET : PGC_USERSET),
          PGC_S_SESSION,
          action, true0false);
   break;
  case VAR_RESET_ALL:
   ResetAllOptions();
   break;
 }

 /* Invoke the post-alter hook for setting this GUC variable, by name. */
 InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, stmt->name,
         ACL_SET, stmt->kind, false);
}

/*
 * Get the value to assign for a VariableSetStmt, or NULL if it's RESET.
 * The result is palloc'd.
 *
 * This is exported for use by actions such as ALTER ROLE SET.
 */

char *
ExtractSetVariableArgs(VariableSetStmt *stmt)
{
 switch (stmt->kind)
 {
  case VAR_SET_VALUE:
   return flatten_set_variable_args(stmt->name, stmt->args);
  case VAR_SET_CURRENT:
   return GetConfigOptionByName(stmt->name, NULL, false);
  default:
   return NULL;
 }
}

/*
 * flatten_set_variable_args
 *  Given a parsenode List as emitted by the grammar for SET,
 *  convert to the flat string representation used by GUC.
 *
 * We need to be told the name of the variable the args are for, because
 * the flattening rules vary (ugh).
 *
 * The result is NULL if args is NIL (i.e., SET ... TO DEFAULT), otherwise
 * a palloc'd string.
 */

static char *
flatten_set_variable_args(const char *name, List *args)
{
 struct config_generic *record;
 int   flags;
 StringInfoData buf;
 ListCell   *l;

 /* Fast path if just DEFAULT */
 if (args == NIL)
  return NULL;

 /*
  * Get flags for the variable; if it's not known, use default flags.
  * (Caller might throw error later, but not our business to do so here.)
 */

 record = find_option(name, falsetrue, WARNING);
 if (record)
  flags = record->flags;
 else
  flags = 0;

 /* Complain if list input and non-list variable */
 if ((flags & GUC_LIST_INPUT) == 0 &&
  list_length(args) != 1)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("SET %s takes only one argument", name)));

 initStringInfo(&buf);

 /*
  * Each list member may be a plain A_Const node, or an A_Const within a
  * TypeCast; the latter case is supported only for ConstInterval arguments
  * (for SET TIME ZONE).
 */

 foreach(l, args)
 {
  Node    *arg = (Node *) lfirst(l);
  char    *val;
  TypeName   *typeName = NULL;
  A_Const    *con;

  if (l != list_head(args))
   appendStringInfoString(&buf, ", ");

  if (IsA(arg, TypeCast))
  {
   TypeCast   *tc = (TypeCast *) arg;

   arg = tc->arg;
   typeName = tc->typeName;
  }

  if (!IsA(arg, A_Const))
   elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg));
  con = (A_Const *) arg;

  switch (nodeTag(&con->val))
  {
   case T_Integer:
    appendStringInfo(&buf, "%d", intVal(&con->val));
    break;
   case T_Float:
    /* represented as a string, so just copy it */
    appendStringInfoString(&buf, castNode(Float, &con->val)->fval);
    break;
   case T_String:
    val = strVal(&con->val);
    if (typeName != NULL)
    {
     /*
      * Must be a ConstInterval argument for TIME ZONE. Coerce
      * to interval and back to normalize the value and account
      * for any typmod.
 */

     Oid   typoid;
     int32  typmod;
     Datum  interval;
     char    *intervalout;

     typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod);
     Assert(typoid == INTERVALOID);

     interval =
      DirectFunctionCall3(interval_in,
           CStringGetDatum(val),
           ObjectIdGetDatum(InvalidOid),
           Int32GetDatum(typmod));

     intervalout =
      DatumGetCString(DirectFunctionCall1(interval_out,
               interval));
     appendStringInfo(&buf, "INTERVAL '%s'", intervalout);
    }
    else
    {
     /*
      * Plain string literal or identifier.  For quote mode,
      * quote it if it's not a vanilla identifier.
 */

     if (flags & GUC_LIST_QUOTE)
      appendStringInfoString(&buf, quote_identifier(val));
     else
      appendStringInfoString(&buf, val);
    }
    break;
   default:
    elog(ERROR, "unrecognized node type: %d",
      (int) nodeTag(&con->val));
    break;
  }
 }

 return buf.data;
}

/*
 * SetPGVariable - SET command exported as an easily-C-callable function.
 *
 * This provides access to SET TO value, as well as SET TO DEFAULT (expressed
 * by passing args == NIL), but not SET FROM CURRENT functionality.
 */

void
SetPGVariable(const char *name, List *args, bool is_local)
{
 char    *argstring = flatten_set_variable_args(name, args);

 /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
 (void) set_config_option(name,
        argstring,
        (superuser() ? PGC_SUSET : PGC_USERSET),
        PGC_S_SESSION,
        is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
        true0false);
}

/*
 * SET command wrapped as a SQL callable function.
 */

Datum
set_config_by_name(PG_FUNCTION_ARGS)
{
 char    *name;
 char    *value;
 char    *new_value;
 bool  is_local;

 if (PG_ARGISNULL(0))
  ereport(ERROR,
    (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     errmsg("SET requires parameter name")));

 /* Get the GUC variable name */
 name = TextDatumGetCString(PG_GETARG_DATUM(0));

 /* Get the desired value or set to NULL for a reset request */
 if (PG_ARGISNULL(1))
  value = NULL;
 else
  value = TextDatumGetCString(PG_GETARG_DATUM(1));

 /*
  * Get the desired state of is_local. Default to false if provided value
  * is NULL
 */

 if (PG_ARGISNULL(2))
  is_local = false;
 else
  is_local = PG_GETARG_BOOL(2);

 /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
 (void) set_config_option(name,
        value,
        (superuser() ? PGC_SUSET : PGC_USERSET),
        PGC_S_SESSION,
        is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
        true0false);

 /* get the new current value */
 new_value = GetConfigOptionByName(name, NULL, false);

 /* Convert return string to text */
 PG_RETURN_TEXT_P(cstring_to_text(new_value));
}


/*
 * SHOW command
 */

void
GetPGVariable(const char *name, DestReceiver *dest)
{
 if (guc_name_compare(name, "all") == 0)
  ShowAllGUCConfig(dest);
 else
  ShowGUCConfigOption(name, dest);
}

/*
 * Get a tuple descriptor for SHOW's result
 */

TupleDesc
GetPGVariableResultDesc(const char *name)
{
 TupleDesc tupdesc;

 if (guc_name_compare(name, "all") == 0)
 {
  /* need a tuple descriptor representing three TEXT columns */
  tupdesc = CreateTemplateTupleDesc(3);
  TupleDescInitEntry(tupdesc, (AttrNumber) 1"name",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 2"setting",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 3"description",
         TEXTOID, -10);
 }
 else
 {
  const char *varname;

  /* Get the canonical spelling of name */
  (void) GetConfigOptionByName(name, &varname, false);

  /* need a tuple descriptor representing a single TEXT column */
  tupdesc = CreateTemplateTupleDesc(1);
  TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
         TEXTOID, -10);
 }
 return tupdesc;
}

/*
 * SHOW one variable
 */

static void
ShowGUCConfigOption(const char *name, DestReceiver *dest)
{
 TupOutputState *tstate;
 TupleDesc tupdesc;
 const char *varname;
 char    *value;

 /* Get the value and canonical spelling of name */
 value = GetConfigOptionByName(name, &varname, false);

 /* need a tuple descriptor representing a single TEXT column */
 tupdesc = CreateTemplateTupleDesc(1);
 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname,
         TEXTOID, -10);

 /* prepare for projection of tuples */
 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);

 /* Send it */
 do_text_output_oneline(tstate, value);

 end_tup_output(tstate);
}

/*
 * SHOW ALL command
 */

static void
ShowAllGUCConfig(DestReceiver *dest)
{
 struct config_generic **guc_vars;
 int   num_vars;
 TupOutputState *tstate;
 TupleDesc tupdesc;
 Datum  values[3];
 bool  isnull[3] = {falsefalsefalse};

 /* collect the variables, in sorted order */
 guc_vars = get_guc_variables(&num_vars);

 /* need a tuple descriptor representing three TEXT columns */
 tupdesc = CreateTemplateTupleDesc(3);
 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1"name",
         TEXTOID, -10);
 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2"setting",
         TEXTOID, -10);
 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3"description",
         TEXTOID, -10);

 /* prepare for projection of tuples */
 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);

 for (int i = 0; i < num_vars; i++)
 {
  struct config_generic *conf = guc_vars[i];
  char    *setting;

  /* skip if marked NO_SHOW_ALL */
  if (conf->flags & GUC_NO_SHOW_ALL)
   continue;

  /* return only options visible to the current user */
  if (!ConfigOptionIsVisible(conf))
   continue;

  /* assign to the values array */
  values[0] = PointerGetDatum(cstring_to_text(conf->name));

  setting = ShowGUCOption(conf, true);
  if (setting)
  {
   values[1] = PointerGetDatum(cstring_to_text(setting));
   isnull[1] = false;
  }
  else
  {
   values[1] = PointerGetDatum(NULL);
   isnull[1] = true;
  }

  if (conf->short_desc)
  {
   values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
   isnull[2] = false;
  }
  else
  {
   values[2] = PointerGetDatum(NULL);
   isnull[2] = true;
  }

  /* send it to dest */
  do_tup_output(tstate, values, isnull);

  /* clean up */
  pfree(DatumGetPointer(values[0]));
  if (setting)
  {
   pfree(setting);
   pfree(DatumGetPointer(values[1]));
  }
  if (conf->short_desc)
   pfree(DatumGetPointer(values[2]));
 }

 end_tup_output(tstate);
}

/*
 * Return some of the flags associated to the specified GUC in the shape of
 * a text array, and NULL if it does not exist.  An empty array is returned
 * if the GUC exists without any meaningful flags to show.
 */

Datum
pg_settings_get_flags(PG_FUNCTION_ARGS)
{
#define MAX_GUC_FLAGS 6
 char    *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
 struct config_generic *record;
 int   cnt = 0;
 Datum  flags[MAX_GUC_FLAGS];
 ArrayType  *a;

 record = find_option(varname, falsetrue, ERROR);

 /* return NULL if no such variable */
 if (record == NULL)
  PG_RETURN_NULL();

 if (record->flags & GUC_EXPLAIN)
  flags[cnt++] = CStringGetTextDatum("EXPLAIN");
 if (record->flags & GUC_NO_RESET)
  flags[cnt++] = CStringGetTextDatum("NO_RESET");
 if (record->flags & GUC_NO_RESET_ALL)
  flags[cnt++] = CStringGetTextDatum("NO_RESET_ALL");
 if (record->flags & GUC_NO_SHOW_ALL)
  flags[cnt++] = CStringGetTextDatum("NO_SHOW_ALL");
 if (record->flags & GUC_NOT_IN_SAMPLE)
  flags[cnt++] = CStringGetTextDatum("NOT_IN_SAMPLE");
 if (record->flags & GUC_RUNTIME_COMPUTED)
  flags[cnt++] = CStringGetTextDatum("RUNTIME_COMPUTED");

 Assert(cnt <= MAX_GUC_FLAGS);

 /* Returns the record as Datum */
 a = construct_array_builtin(flags, cnt, TEXTOID);
 PG_RETURN_ARRAYTYPE_P(a);
}

/*
 * Return whether or not the GUC variable is visible to the current user.
 */

bool
ConfigOptionIsVisible(struct config_generic *conf)
{
 if ((conf->flags & GUC_SUPERUSER_ONLY) &&
  !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
  return false;
 else
  return true;
}

/*
 * Extract fields to show in pg_settings for given variable.
 */

static void
GetConfigOptionValues(struct config_generic *conf, const char **values)
{
 char  buffer[256];

 /* first get the generic attributes */

 /* name */
 values[0] = conf->name;

 /* setting: use ShowGUCOption in order to avoid duplicating the logic */
 values[1] = ShowGUCOption(conf, false);

 /* unit, if any (NULL is fine) */
 values[2] = get_config_unit_name(conf->flags);

 /* group */
 values[3] = _(config_group_names[conf->group]);

 /* short_desc */
 values[4] = conf->short_desc != NULL ? _(conf->short_desc) : NULL;

 /* extra_desc */
 values[5] = conf->long_desc != NULL ? _(conf->long_desc) : NULL;

 /* context */
 values[6] = GucContext_Names[conf->context];

 /* vartype */
 values[7] = config_type_names[conf->vartype];

 /* source */
 values[8] = GucSource_Names[conf->source];

 /* now get the type specific attributes */
 switch (conf->vartype)
 {
  case PGC_BOOL:
   {
    struct config_bool *lconf = (struct config_bool *) conf;

    /* min_val */
    values[9] = NULL;

    /* max_val */
    values[10] = NULL;

    /* enumvals */
    values[11] = NULL;

    /* boot_val */
    values[12] = pstrdup(lconf->boot_val ? "on" : "off");

    /* reset_val */
    values[13] = pstrdup(lconf->reset_val ? "on" : "off");
   }
   break;

  case PGC_INT:
   {
    struct config_int *lconf = (struct config_int *) conf;

    /* min_val */
    snprintf(buffer, sizeof(buffer), "%d", lconf->min);
    values[9] = pstrdup(buffer);

    /* max_val */
    snprintf(buffer, sizeof(buffer), "%d", lconf->max);
    values[10] = pstrdup(buffer);

    /* enumvals */
    values[11] = NULL;

    /* boot_val */
    snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
    values[12] = pstrdup(buffer);

    /* reset_val */
    snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
    values[13] = pstrdup(buffer);
   }
   break;

  case PGC_REAL:
   {
    struct config_real *lconf = (struct config_real *) conf;

    /* min_val */
    snprintf(buffer, sizeof(buffer), "%g", lconf->min);
    values[9] = pstrdup(buffer);

    /* max_val */
    snprintf(buffer, sizeof(buffer), "%g", lconf->max);
    values[10] = pstrdup(buffer);

    /* enumvals */
    values[11] = NULL;

    /* boot_val */
    snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
    values[12] = pstrdup(buffer);

    /* reset_val */
    snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
    values[13] = pstrdup(buffer);
   }
   break;

  case PGC_STRING:
   {
    struct config_string *lconf = (struct config_string *) conf;

    /* min_val */
    values[9] = NULL;

    /* max_val */
    values[10] = NULL;

    /* enumvals */
    values[11] = NULL;

    /* boot_val */
    if (lconf->boot_val == NULL)
     values[12] = NULL;
    else
     values[12] = pstrdup(lconf->boot_val);

    /* reset_val */
    if (lconf->reset_val == NULL)
     values[13] = NULL;
    else
     values[13] = pstrdup(lconf->reset_val);
   }
   break;

  case PGC_ENUM:
   {
    struct config_enum *lconf = (struct config_enum *) conf;

    /* min_val */
    values[9] = NULL;

    /* max_val */
    values[10] = NULL;

    /* enumvals */

    /*
     * NOTE! enumvals with double quotes in them are not
     * supported!
 */

    values[11] = config_enum_get_options((struct config_enum *) conf,
              "{\"", "\"}""\",\"");

    /* boot_val */
    values[12] = pstrdup(config_enum_lookup_by_value(lconf,
                 lconf->boot_val));

    /* reset_val */
    values[13] = pstrdup(config_enum_lookup_by_value(lconf,
                 lconf->reset_val));
   }
   break;

  default:
   {
    /*
     * should never get here, but in case we do, set 'em to NULL
 */


    /* min_val */
    values[9] = NULL;

    /* max_val */
    values[10] = NULL;

    /* enumvals */
    values[11] = NULL;

    /* boot_val */
    values[12] = NULL;

    /* reset_val */
    values[13] = NULL;
   }
   break;
 }

 /*
  * If the setting came from a config file, set the source location. For
  * security reasons, we don't show source file/line number for
  * insufficiently-privileged users.
 */

 if (conf->source == PGC_S_FILE &&
  has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
 {
  values[14] = conf->sourcefile;
  snprintf(buffer, sizeof(buffer), "%d", conf->sourceline);
  values[15] = pstrdup(buffer);
 }
 else
 {
  values[14] = NULL;
  values[15] = NULL;
 }

 values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f";
}

/*
 * show_config_by_name - equiv to SHOW X command but implemented as
 * a function.
 */

Datum
show_config_by_name(PG_FUNCTION_ARGS)
{
 char    *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
 char    *varval;

 /* Get the value */
 varval = GetConfigOptionByName(varname, NULL, false);

 /* Convert to text */
 PG_RETURN_TEXT_P(cstring_to_text(varval));
}

/*
 * show_config_by_name_missing_ok - equiv to SHOW X command but implemented as
 * a function.  If X does not exist, suppress the error and just return NULL
 * if missing_ok is true.
 */

Datum
show_config_by_name_missing_ok(PG_FUNCTION_ARGS)
{
 char    *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
 bool  missing_ok = PG_GETARG_BOOL(1);
 char    *varval;

 /* Get the value */
 varval = GetConfigOptionByName(varname, NULL, missing_ok);

 /* return NULL if no such variable */
 if (varval == NULL)
  PG_RETURN_NULL();

 /* Convert to text */
 PG_RETURN_TEXT_P(cstring_to_text(varval));
}

/*
 * show_all_settings - equiv to SHOW ALL command but implemented as
 * a Table Function.
 */

#define NUM_PG_SETTINGS_ATTS 17

Datum
show_all_settings(PG_FUNCTION_ARGS)
{
 FuncCallContext *funcctx;
 struct config_generic **guc_vars;
 int   num_vars;
 TupleDesc tupdesc;
 int   call_cntr;
 int   max_calls;
 AttInMetadata *attinmeta;
 MemoryContext oldcontext;

 /* stuff done only on the first call of the function */
 if (SRF_IS_FIRSTCALL())
 {
  /* create a function context for cross-call persistence */
  funcctx = SRF_FIRSTCALL_INIT();

  /*
   * switch to memory context appropriate for multiple function calls
 */

  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

  /*
   * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns
   * of the appropriate types
 */

  tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS);
  TupleDescInitEntry(tupdesc, (AttrNumber) 1"name",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 2"setting",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 3"unit",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 4"category",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 5"short_desc",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 6"extra_desc",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 7"context",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 8"vartype",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 9"source",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 10"min_val",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 11"max_val",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 12"enumvals",
         TEXTARRAYOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 13"boot_val",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 14"reset_val",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 15"sourcefile",
         TEXTOID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 16"sourceline",
         INT4OID, -10);
  TupleDescInitEntry(tupdesc, (AttrNumber) 17"pending_restart",
         BOOLOID, -10);

  /*
   * Generate attribute metadata needed later to produce tuples from raw
   * C strings
 */

  attinmeta = TupleDescGetAttInMetadata(tupdesc);
  funcctx->attinmeta = attinmeta;

  /* collect the variables, in sorted order */
  guc_vars = get_guc_variables(&num_vars);

  /* use user_fctx to remember the array location */
  funcctx->user_fctx = guc_vars;

  /* total number of tuples to be returned */
  funcctx->max_calls = num_vars;

  MemoryContextSwitchTo(oldcontext);
 }

 /* stuff done on every call of the function */
 funcctx = SRF_PERCALL_SETUP();

 guc_vars = (struct config_generic **) funcctx->user_fctx;
 call_cntr = funcctx->call_cntr;
 max_calls = funcctx->max_calls;
 attinmeta = funcctx->attinmeta;

 while (call_cntr < max_calls) /* do when there is more left to send */
 {
  struct config_generic *conf = guc_vars[call_cntr];
  char    *values[NUM_PG_SETTINGS_ATTS];
  HeapTuple tuple;
  Datum  result;

  /* skip if marked NO_SHOW_ALL or if not visible to current user */
  if ((conf->flags & GUC_NO_SHOW_ALL) ||
   !ConfigOptionIsVisible(conf))
  {
   call_cntr = ++funcctx->call_cntr;
   continue;
  }

  /* extract values for the current variable */
  GetConfigOptionValues(conf, (const char **) values);

  /* build a tuple */
  tuple = BuildTupleFromCStrings(attinmeta, values);

  /* make the tuple into a datum */
  result = HeapTupleGetDatum(tuple);

  SRF_RETURN_NEXT(funcctx, result);
 }

 /* do when there is no more left */
 SRF_RETURN_DONE(funcctx);
}

/*
 * show_all_file_settings
 *
 * Returns a table of all parameter settings in all configuration files
 * which includes the config file pathname, the line number, a sequence number
 * indicating the order in which the settings were encountered, the parameter
 * name and value, a bool showing if the value could be applied, and possibly
 * an associated error message.  (For problems such as syntax errors, the
 * parameter name/value might be NULL.)
 *
 * Note: no filtering is done here, instead we depend on the GRANT system
 * to prevent unprivileged users from accessing this function or the view
 * built on top of it.
 */

Datum
show_all_file_settings(PG_FUNCTION_ARGS)
{
#define NUM_PG_FILE_SETTINGS_ATTS 7
 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 ConfigVariable *conf;
 int   seqno;

 /* Scan the config files using current context as workspace */
 conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3);

 /* Build a tuplestore to return our results in */
 InitMaterializedSRF(fcinfo, 0);

 /* Process the results and create a tuplestore */
 for (seqno = 1; conf != NULL; conf = conf->next, seqno++)
 {
  Datum  values[NUM_PG_FILE_SETTINGS_ATTS];
  bool  nulls[NUM_PG_FILE_SETTINGS_ATTS];

  memset(values, 0sizeof(values));
  memset(nulls, 0sizeof(nulls));

  /* sourcefile */
  if (conf->filename)
   values[0] = PointerGetDatum(cstring_to_text(conf->filename));
  else
   nulls[0] = true;

  /* sourceline (not meaningful if no sourcefile) */
  if (conf->filename)
   values[1] = Int32GetDatum(conf->sourceline);
  else
   nulls[1] = true;

  /* seqno */
  values[2] = Int32GetDatum(seqno);

  /* name */
  if (conf->name)
   values[3] = PointerGetDatum(cstring_to_text(conf->name));
  else
   nulls[3] = true;

  /* setting */
  if (conf->value)
   values[4] = PointerGetDatum(cstring_to_text(conf->value));
  else
   nulls[4] = true;

  /* applied */
  values[5] = BoolGetDatum(conf->applied);

  /* error */
  if (conf->errmsg)
   values[6] = PointerGetDatum(cstring_to_text(conf->errmsg));
  else
   nulls[6] = true;

  /* shove row into tuplestore */
  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 }

 return (Datum) 0;
}

Messung V0.5 in Prozent
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002