1 /*--------------------------------------------------------------------
5 * SQL commands and SQL-accessible functions related to GUC variables.
8 * Copyright (c) 2000-2024, PostgreSQL Global Development Group
9 * Written by Peter Eisentraut <peter_e@gmx.net>.
12 * src/backend/utils/misc/guc_funcs.c
14 *--------------------------------------------------------------------
21 #include "access/xact.h"
22 #include "catalog/objectaccess.h"
23 #include "catalog/pg_authid.h"
24 #include "catalog/pg_parameter_acl.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"
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
);
43 ExecSetVariableStmt(VariableSetStmt
*stmt
, bool isTopLevel
)
45 GucAction action
= stmt
->is_local
? GUC_ACTION_LOCAL
: GUC_ACTION_SET
;
48 * Workers synchronize these parameters at the start of the parallel
49 * operation; then, we block SET during the operation.
51 if (IsInParallelMode())
53 (errcode(ERRCODE_INVALID_TRANSACTION_STATE
),
54 errmsg("cannot set parameters during a parallel operation")));
61 WarnNoTransactionBlock(isTopLevel
, "SET LOCAL");
62 (void) set_config_option(stmt
->name
,
63 ExtractSetVariableArgs(stmt
),
64 (superuser() ? PGC_SUSET
: PGC_USERSET
),
66 action
, true, 0, false);
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.
77 if (strcmp(stmt
->name
, "TRANSACTION") == 0)
81 WarnNoTransactionBlock(isTopLevel
, "SET TRANSACTION");
83 foreach(head
, stmt
->args
)
85 DefElem
*item
= (DefElem
*) lfirst(head
);
87 if (strcmp(item
->defname
, "transaction_isolation") == 0)
88 SetPGVariable("transaction_isolation",
89 list_make1(item
->arg
), stmt
->is_local
);
90 else if (strcmp(item
->defname
, "transaction_read_only") == 0)
91 SetPGVariable("transaction_read_only",
92 list_make1(item
->arg
), stmt
->is_local
);
93 else if (strcmp(item
->defname
, "transaction_deferrable") == 0)
94 SetPGVariable("transaction_deferrable",
95 list_make1(item
->arg
), stmt
->is_local
);
97 elog(ERROR
, "unexpected SET TRANSACTION element: %s",
101 else if (strcmp(stmt
->name
, "SESSION CHARACTERISTICS") == 0)
105 foreach(head
, stmt
->args
)
107 DefElem
*item
= (DefElem
*) lfirst(head
);
109 if (strcmp(item
->defname
, "transaction_isolation") == 0)
110 SetPGVariable("default_transaction_isolation",
111 list_make1(item
->arg
), stmt
->is_local
);
112 else if (strcmp(item
->defname
, "transaction_read_only") == 0)
113 SetPGVariable("default_transaction_read_only",
114 list_make1(item
->arg
), stmt
->is_local
);
115 else if (strcmp(item
->defname
, "transaction_deferrable") == 0)
116 SetPGVariable("default_transaction_deferrable",
117 list_make1(item
->arg
), stmt
->is_local
);
119 elog(ERROR
, "unexpected SET SESSION element: %s",
123 else if (strcmp(stmt
->name
, "TRANSACTION SNAPSHOT") == 0)
125 A_Const
*con
= linitial_node(A_Const
, stmt
->args
);
129 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
130 errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented")));
132 WarnNoTransactionBlock(isTopLevel
, "SET TRANSACTION");
133 ImportSnapshot(strVal(&con
->val
));
136 elog(ERROR
, "unexpected SET MULTI element: %s",
139 case VAR_SET_DEFAULT
:
141 WarnNoTransactionBlock(isTopLevel
, "SET LOCAL");
144 (void) set_config_option(stmt
->name
,
146 (superuser() ? PGC_SUSET
: PGC_USERSET
),
148 action
, true, 0, false);
155 /* Invoke the post-alter hook for setting this GUC variable, by name. */
156 InvokeObjectPostAlterHookArgStr(ParameterAclRelationId
, stmt
->name
,
157 ACL_SET
, stmt
->kind
, false);
161 * Get the value to assign for a VariableSetStmt, or NULL if it's RESET.
162 * The result is palloc'd.
164 * This is exported for use by actions such as ALTER ROLE SET.
167 ExtractSetVariableArgs(VariableSetStmt
*stmt
)
172 return flatten_set_variable_args(stmt
->name
, stmt
->args
);
173 case VAR_SET_CURRENT
:
174 return GetConfigOptionByName(stmt
->name
, NULL
, false);
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.
185 * We need to be told the name of the variable the args are for, because
186 * the flattening rules vary (ugh).
188 * The result is NULL if args is NIL (i.e., SET ... TO DEFAULT), otherwise
192 flatten_set_variable_args(const char *name
, List
*args
)
194 struct config_generic
*record
;
199 /* Fast path if just DEFAULT */
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.)
207 record
= find_option(name
, false, true, WARNING
);
209 flags
= record
->flags
;
213 /* Complain if list input and non-list variable */
214 if ((flags
& GUC_LIST_INPUT
) == 0 &&
215 list_length(args
) != 1)
217 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
218 errmsg("SET %s takes only one argument", name
)));
220 initStringInfo(&buf
);
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).
229 Node
*arg
= (Node
*) lfirst(l
);
231 TypeName
*typeName
= NULL
;
234 if (l
!= list_head(args
))
235 appendStringInfoString(&buf
, ", ");
237 if (IsA(arg
, TypeCast
))
239 TypeCast
*tc
= (TypeCast
*) arg
;
242 typeName
= tc
->typeName
;
245 if (!IsA(arg
, A_Const
))
246 elog(ERROR
, "unrecognized node type: %d", (int) nodeTag(arg
));
247 con
= (A_Const
*) arg
;
249 switch (nodeTag(&con
->val
))
252 appendStringInfo(&buf
, "%d", intVal(&con
->val
));
255 /* represented as a string, so just copy it */
256 appendStringInfoString(&buf
, castNode(Float
, &con
->val
)->fval
);
259 val
= strVal(&con
->val
);
260 if (typeName
!= NULL
)
263 * Must be a ConstInterval argument for TIME ZONE. Coerce
264 * to interval and back to normalize the value and account
272 typenameTypeIdAndMod(NULL
, typeName
, &typoid
, &typmod
);
273 Assert(typoid
== INTERVALOID
);
276 DirectFunctionCall3(interval_in
,
277 CStringGetDatum(val
),
278 ObjectIdGetDatum(InvalidOid
),
279 Int32GetDatum(typmod
));
282 DatumGetCString(DirectFunctionCall1(interval_out
,
284 appendStringInfo(&buf
, "INTERVAL '%s'", intervalout
);
289 * Plain string literal or identifier. For quote mode,
290 * quote it if it's not a vanilla identifier.
292 if (flags
& GUC_LIST_QUOTE
)
293 appendStringInfoString(&buf
, quote_identifier(val
));
295 appendStringInfoString(&buf
, val
);
299 elog(ERROR
, "unrecognized node type: %d",
300 (int) nodeTag(&con
->val
));
309 * SetPGVariable - SET command exported as an easily-C-callable function.
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.
315 SetPGVariable(const char *name
, List
*args
, bool is_local
)
317 char *argstring
= flatten_set_variable_args(name
, args
);
319 /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
320 (void) set_config_option(name
,
322 (superuser() ? PGC_SUSET
: PGC_USERSET
),
324 is_local
? GUC_ACTION_LOCAL
: GUC_ACTION_SET
,
329 * SET command wrapped as a SQL callable function.
332 set_config_by_name(PG_FUNCTION_ARGS
)
341 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED
),
342 errmsg("SET requires parameter name")));
344 /* Get the GUC variable name */
345 name
= TextDatumGetCString(PG_GETARG_DATUM(0));
347 /* Get the desired value or set to NULL for a reset request */
351 value
= TextDatumGetCString(PG_GETARG_DATUM(1));
354 * Get the desired state of is_local. Default to false if provided value
360 is_local
= PG_GETARG_BOOL(2);
362 /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
363 (void) set_config_option(name
,
365 (superuser() ? PGC_SUSET
: PGC_USERSET
),
367 is_local
? GUC_ACTION_LOCAL
: GUC_ACTION_SET
,
370 /* get the new current value */
371 new_value
= GetConfigOptionByName(name
, NULL
, false);
373 /* Convert return string to text */
374 PG_RETURN_TEXT_P(cstring_to_text(new_value
));
382 GetPGVariable(const char *name
, DestReceiver
*dest
)
384 if (guc_name_compare(name
, "all") == 0)
385 ShowAllGUCConfig(dest
);
387 ShowGUCConfigOption(name
, dest
);
391 * Get a tuple descriptor for SHOW's result
394 GetPGVariableResultDesc(const char *name
)
398 if (guc_name_compare(name
, "all") == 0)
400 /* need a tuple descriptor representing three TEXT columns */
401 tupdesc
= CreateTemplateTupleDesc(3);
402 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "name",
404 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "setting",
406 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "description",
413 /* Get the canonical spelling of name */
414 (void) GetConfigOptionByName(name
, &varname
, false);
416 /* need a tuple descriptor representing a single TEXT column */
417 tupdesc
= CreateTemplateTupleDesc(1);
418 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, varname
,
428 ShowGUCConfigOption(const char *name
, DestReceiver
*dest
)
430 TupOutputState
*tstate
;
435 /* Get the value and canonical spelling of name */
436 value
= GetConfigOptionByName(name
, &varname
, false);
438 /* need a tuple descriptor representing a single TEXT column */
439 tupdesc
= CreateTemplateTupleDesc(1);
440 TupleDescInitBuiltinEntry(tupdesc
, (AttrNumber
) 1, varname
,
443 /* prepare for projection of tuples */
444 tstate
= begin_tup_output_tupdesc(dest
, tupdesc
, &TTSOpsVirtual
);
447 do_text_output_oneline(tstate
, value
);
449 end_tup_output(tstate
);
456 ShowAllGUCConfig(DestReceiver
*dest
)
458 struct config_generic
**guc_vars
;
460 TupOutputState
*tstate
;
463 bool isnull
[3] = {false, false, false};
465 /* collect the variables, in sorted order */
466 guc_vars
= get_guc_variables(&num_vars
);
468 /* need a tuple descriptor representing three TEXT columns */
469 tupdesc
= CreateTemplateTupleDesc(3);
470 TupleDescInitBuiltinEntry(tupdesc
, (AttrNumber
) 1, "name",
472 TupleDescInitBuiltinEntry(tupdesc
, (AttrNumber
) 2, "setting",
474 TupleDescInitBuiltinEntry(tupdesc
, (AttrNumber
) 3, "description",
477 /* prepare for projection of tuples */
478 tstate
= begin_tup_output_tupdesc(dest
, tupdesc
, &TTSOpsVirtual
);
480 for (int i
= 0; i
< num_vars
; i
++)
482 struct config_generic
*conf
= guc_vars
[i
];
485 /* skip if marked NO_SHOW_ALL */
486 if (conf
->flags
& GUC_NO_SHOW_ALL
)
489 /* return only options visible to the current user */
490 if (!ConfigOptionIsVisible(conf
))
493 /* assign to the values array */
494 values
[0] = PointerGetDatum(cstring_to_text(conf
->name
));
496 setting
= ShowGUCOption(conf
, true);
499 values
[1] = PointerGetDatum(cstring_to_text(setting
));
504 values
[1] = PointerGetDatum(NULL
);
508 if (conf
->short_desc
)
510 values
[2] = PointerGetDatum(cstring_to_text(conf
->short_desc
));
515 values
[2] = PointerGetDatum(NULL
);
519 /* send it to dest */
520 do_tup_output(tstate
, values
, isnull
);
523 pfree(DatumGetPointer(values
[0]));
527 pfree(DatumGetPointer(values
[1]));
529 if (conf
->short_desc
)
530 pfree(DatumGetPointer(values
[2]));
533 end_tup_output(tstate
);
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.
542 pg_settings_get_flags(PG_FUNCTION_ARGS
)
544 #define MAX_GUC_FLAGS 6
545 char *varname
= TextDatumGetCString(PG_GETARG_DATUM(0));
546 struct config_generic
*record
;
548 Datum flags
[MAX_GUC_FLAGS
];
551 record
= find_option(varname
, false, true, ERROR
);
553 /* return NULL if no such variable */
557 if (record
->flags
& GUC_EXPLAIN
)
558 flags
[cnt
++] = CStringGetTextDatum("EXPLAIN");
559 if (record
->flags
& GUC_NO_RESET
)
560 flags
[cnt
++] = CStringGetTextDatum("NO_RESET");
561 if (record
->flags
& GUC_NO_RESET_ALL
)
562 flags
[cnt
++] = CStringGetTextDatum("NO_RESET_ALL");
563 if (record
->flags
& GUC_NO_SHOW_ALL
)
564 flags
[cnt
++] = CStringGetTextDatum("NO_SHOW_ALL");
565 if (record
->flags
& GUC_NOT_IN_SAMPLE
)
566 flags
[cnt
++] = CStringGetTextDatum("NOT_IN_SAMPLE");
567 if (record
->flags
& GUC_RUNTIME_COMPUTED
)
568 flags
[cnt
++] = CStringGetTextDatum("RUNTIME_COMPUTED");
570 Assert(cnt
<= MAX_GUC_FLAGS
);
572 /* Returns the record as Datum */
573 a
= construct_array_builtin(flags
, cnt
, TEXTOID
);
574 PG_RETURN_ARRAYTYPE_P(a
);
578 * Return whether or not the GUC variable is visible to the current user.
581 ConfigOptionIsVisible(struct config_generic
*conf
)
583 if ((conf
->flags
& GUC_SUPERUSER_ONLY
) &&
584 !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS
))
591 * Extract fields to show in pg_settings for given variable.
594 GetConfigOptionValues(struct config_generic
*conf
, const char **values
)
598 /* first get the generic attributes */
601 values
[0] = conf
->name
;
603 /* setting: use ShowGUCOption in order to avoid duplicating the logic */
604 values
[1] = ShowGUCOption(conf
, false);
606 /* unit, if any (NULL is fine) */
607 values
[2] = get_config_unit_name(conf
->flags
);
610 values
[3] = _(config_group_names
[conf
->group
]);
613 values
[4] = conf
->short_desc
!= NULL
? _(conf
->short_desc
) : NULL
;
616 values
[5] = conf
->long_desc
!= NULL
? _(conf
->long_desc
) : NULL
;
619 values
[6] = GucContext_Names
[conf
->context
];
622 values
[7] = config_type_names
[conf
->vartype
];
625 values
[8] = GucSource_Names
[conf
->source
];
627 /* now get the type specific attributes */
628 switch (conf
->vartype
)
632 struct config_bool
*lconf
= (struct config_bool
*) conf
;
644 values
[12] = pstrdup(lconf
->boot_val
? "on" : "off");
647 values
[13] = pstrdup(lconf
->reset_val
? "on" : "off");
653 struct config_int
*lconf
= (struct config_int
*) conf
;
656 snprintf(buffer
, sizeof(buffer
), "%d", lconf
->min
);
657 values
[9] = pstrdup(buffer
);
660 snprintf(buffer
, sizeof(buffer
), "%d", lconf
->max
);
661 values
[10] = pstrdup(buffer
);
667 snprintf(buffer
, sizeof(buffer
), "%d", lconf
->boot_val
);
668 values
[12] = pstrdup(buffer
);
671 snprintf(buffer
, sizeof(buffer
), "%d", lconf
->reset_val
);
672 values
[13] = pstrdup(buffer
);
678 struct config_real
*lconf
= (struct config_real
*) conf
;
681 snprintf(buffer
, sizeof(buffer
), "%g", lconf
->min
);
682 values
[9] = pstrdup(buffer
);
685 snprintf(buffer
, sizeof(buffer
), "%g", lconf
->max
);
686 values
[10] = pstrdup(buffer
);
692 snprintf(buffer
, sizeof(buffer
), "%g", lconf
->boot_val
);
693 values
[12] = pstrdup(buffer
);
696 snprintf(buffer
, sizeof(buffer
), "%g", lconf
->reset_val
);
697 values
[13] = pstrdup(buffer
);
703 struct config_string
*lconf
= (struct config_string
*) conf
;
715 if (lconf
->boot_val
== NULL
)
718 values
[12] = pstrdup(lconf
->boot_val
);
721 if (lconf
->reset_val
== NULL
)
724 values
[13] = pstrdup(lconf
->reset_val
);
730 struct config_enum
*lconf
= (struct config_enum
*) conf
;
741 * NOTE! enumvals with double quotes in them are not
744 values
[11] = config_enum_get_options((struct config_enum
*) conf
,
745 "{\"", "\"}", "\",\"");
748 values
[12] = pstrdup(config_enum_lookup_by_value(lconf
,
752 values
[13] = pstrdup(config_enum_lookup_by_value(lconf
,
760 * should never get here, but in case we do, set 'em to NULL
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.
786 if (conf
->source
== PGC_S_FILE
&&
787 has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS
))
789 values
[14] = conf
->sourcefile
;
790 snprintf(buffer
, sizeof(buffer
), "%d", conf
->sourceline
);
791 values
[15] = pstrdup(buffer
);
799 values
[16] = (conf
->status
& GUC_PENDING_RESTART
) ? "t" : "f";
803 * show_config_by_name - equiv to SHOW X command but implemented as
807 show_config_by_name(PG_FUNCTION_ARGS
)
809 char *varname
= TextDatumGetCString(PG_GETARG_DATUM(0));
813 varval
= GetConfigOptionByName(varname
, NULL
, false);
815 /* Convert to text */
816 PG_RETURN_TEXT_P(cstring_to_text(varval
));
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.
825 show_config_by_name_missing_ok(PG_FUNCTION_ARGS
)
827 char *varname
= TextDatumGetCString(PG_GETARG_DATUM(0));
828 bool missing_ok
= PG_GETARG_BOOL(1);
832 varval
= GetConfigOptionByName(varname
, NULL
, missing_ok
);
834 /* return NULL if no such variable */
838 /* Convert to text */
839 PG_RETURN_TEXT_P(cstring_to_text(varval
));
843 * show_all_settings - equiv to SHOW ALL command but implemented as
846 #define NUM_PG_SETTINGS_ATTS 17
849 show_all_settings(PG_FUNCTION_ARGS
)
851 FuncCallContext
*funcctx
;
852 struct config_generic
**guc_vars
;
857 AttInMetadata
*attinmeta
;
858 MemoryContext oldcontext
;
860 /* stuff done only on the first call of the function */
861 if (SRF_IS_FIRSTCALL())
863 /* create a function context for cross-call persistence */
864 funcctx
= SRF_FIRSTCALL_INIT();
867 * switch to memory context appropriate for multiple function calls
869 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
872 * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns
873 * of the appropriate types
875 tupdesc
= CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS
);
876 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "name",
878 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "setting",
880 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "unit",
882 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "category",
884 TupleDescInitEntry(tupdesc
, (AttrNumber
) 5, "short_desc",
886 TupleDescInitEntry(tupdesc
, (AttrNumber
) 6, "extra_desc",
888 TupleDescInitEntry(tupdesc
, (AttrNumber
) 7, "context",
890 TupleDescInitEntry(tupdesc
, (AttrNumber
) 8, "vartype",
892 TupleDescInitEntry(tupdesc
, (AttrNumber
) 9, "source",
894 TupleDescInitEntry(tupdesc
, (AttrNumber
) 10, "min_val",
896 TupleDescInitEntry(tupdesc
, (AttrNumber
) 11, "max_val",
898 TupleDescInitEntry(tupdesc
, (AttrNumber
) 12, "enumvals",
899 TEXTARRAYOID
, -1, 0);
900 TupleDescInitEntry(tupdesc
, (AttrNumber
) 13, "boot_val",
902 TupleDescInitEntry(tupdesc
, (AttrNumber
) 14, "reset_val",
904 TupleDescInitEntry(tupdesc
, (AttrNumber
) 15, "sourcefile",
906 TupleDescInitEntry(tupdesc
, (AttrNumber
) 16, "sourceline",
908 TupleDescInitEntry(tupdesc
, (AttrNumber
) 17, "pending_restart",
912 * Generate attribute metadata needed later to produce tuples from raw
915 attinmeta
= TupleDescGetAttInMetadata(tupdesc
);
916 funcctx
->attinmeta
= attinmeta
;
918 /* collect the variables, in sorted order */
919 guc_vars
= get_guc_variables(&num_vars
);
921 /* use user_fctx to remember the array location */
922 funcctx
->user_fctx
= guc_vars
;
924 /* total number of tuples to be returned */
925 funcctx
->max_calls
= num_vars
;
927 MemoryContextSwitchTo(oldcontext
);
930 /* stuff done on every call of the function */
931 funcctx
= SRF_PERCALL_SETUP();
933 guc_vars
= (struct config_generic
**) funcctx
->user_fctx
;
934 call_cntr
= funcctx
->call_cntr
;
935 max_calls
= funcctx
->max_calls
;
936 attinmeta
= funcctx
->attinmeta
;
938 while (call_cntr
< max_calls
) /* do when there is more left to send */
940 struct config_generic
*conf
= guc_vars
[call_cntr
];
941 char *values
[NUM_PG_SETTINGS_ATTS
];
945 /* skip if marked NO_SHOW_ALL or if not visible to current user */
946 if ((conf
->flags
& GUC_NO_SHOW_ALL
) ||
947 !ConfigOptionIsVisible(conf
))
949 call_cntr
= ++funcctx
->call_cntr
;
953 /* extract values for the current variable */
954 GetConfigOptionValues(conf
, (const char **) values
);
957 tuple
= BuildTupleFromCStrings(attinmeta
, values
);
959 /* make the tuple into a datum */
960 result
= HeapTupleGetDatum(tuple
);
962 SRF_RETURN_NEXT(funcctx
, result
);
965 /* do when there is no more left */
966 SRF_RETURN_DONE(funcctx
);
970 * show_all_file_settings
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.)
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.
984 show_all_file_settings(PG_FUNCTION_ARGS
)
986 #define NUM_PG_FILE_SETTINGS_ATTS 7
987 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
988 ConfigVariable
*conf
;
991 /* Scan the config files using current context as workspace */
992 conf
= ProcessConfigFileInternal(PGC_SIGHUP
, false, DEBUG3
);
994 /* Build a tuplestore to return our results in */
995 InitMaterializedSRF(fcinfo
, 0);
997 /* Process the results and create a tuplestore */
998 for (seqno
= 1; conf
!= NULL
; conf
= conf
->next
, seqno
++)
1000 Datum values
[NUM_PG_FILE_SETTINGS_ATTS
];
1001 bool nulls
[NUM_PG_FILE_SETTINGS_ATTS
];
1003 memset(values
, 0, sizeof(values
));
1004 memset(nulls
, 0, sizeof(nulls
));
1008 values
[0] = PointerGetDatum(cstring_to_text(conf
->filename
));
1012 /* sourceline (not meaningful if no sourcefile) */
1014 values
[1] = Int32GetDatum(conf
->sourceline
);
1019 values
[2] = Int32GetDatum(seqno
);
1023 values
[3] = PointerGetDatum(cstring_to_text(conf
->name
));
1029 values
[4] = PointerGetDatum(cstring_to_text(conf
->value
));
1034 values
[5] = BoolGetDatum(conf
->applied
);
1038 values
[6] = PointerGetDatum(cstring_to_text(conf
->errmsg
));
1042 /* shove row into tuplestore */
1043 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
, values
, nulls
);