Now that we have non-Latin1 SGML detection, restore Latin1 chars
[pgsql.git] / src / backend / utils / misc / guc_funcs.c
blob9c9edd3d2f500292530d9558d77224c81688cd0c
1 /*--------------------------------------------------------------------
3 * guc_funcs.c
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>.
11 * IDENTIFICATION
12 * src/backend/utils/misc/guc_funcs.c
14 *--------------------------------------------------------------------
16 #include "postgres.h"
18 #include <sys/stat.h>
19 #include <unistd.h>
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"
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);
40 * SET command
42 void
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())
52 ereport(ERROR,
53 (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
54 errmsg("cannot set parameters during a parallel operation")));
56 switch (stmt->kind)
58 case VAR_SET_VALUE:
59 case VAR_SET_CURRENT:
60 if (stmt->is_local)
61 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
62 (void) set_config_option(stmt->name,
63 ExtractSetVariableArgs(stmt),
64 (superuser() ? PGC_SUSET : PGC_USERSET),
65 PGC_S_SESSION,
66 action, true, 0, false);
67 break;
68 case VAR_SET_MULTI:
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)
79 ListCell *head;
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);
96 else
97 elog(ERROR, "unexpected SET TRANSACTION element: %s",
98 item->defname);
101 else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0)
103 ListCell *head;
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);
118 else
119 elog(ERROR, "unexpected SET SESSION element: %s",
120 item->defname);
123 else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT") == 0)
125 A_Const *con = linitial_node(A_Const, stmt->args);
127 if (stmt->is_local)
128 ereport(ERROR,
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));
135 else
136 elog(ERROR, "unexpected SET MULTI element: %s",
137 stmt->name);
138 break;
139 case VAR_SET_DEFAULT:
140 if (stmt->is_local)
141 WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
142 /* fall through */
143 case VAR_RESET:
144 (void) set_config_option(stmt->name,
145 NULL,
146 (superuser() ? PGC_SUSET : PGC_USERSET),
147 PGC_S_SESSION,
148 action, true, 0, false);
149 break;
150 case VAR_RESET_ALL:
151 ResetAllOptions();
152 break;
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.
166 char *
167 ExtractSetVariableArgs(VariableSetStmt *stmt)
169 switch (stmt->kind)
171 case VAR_SET_VALUE:
172 return flatten_set_variable_args(stmt->name, stmt->args);
173 case VAR_SET_CURRENT:
174 return GetConfigOptionByName(stmt->name, NULL, false);
175 default:
176 return NULL;
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
189 * a palloc'd string.
191 static char *
192 flatten_set_variable_args(const char *name, List *args)
194 struct config_generic *record;
195 int flags;
196 StringInfoData buf;
197 ListCell *l;
199 /* Fast path if just DEFAULT */
200 if (args == NIL)
201 return NULL;
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);
208 if (record)
209 flags = record->flags;
210 else
211 flags = 0;
213 /* Complain if list input and non-list variable */
214 if ((flags & GUC_LIST_INPUT) == 0 &&
215 list_length(args) != 1)
216 ereport(ERROR,
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).
227 foreach(l, args)
229 Node *arg = (Node *) lfirst(l);
230 char *val;
231 TypeName *typeName = NULL;
232 A_Const *con;
234 if (l != list_head(args))
235 appendStringInfoString(&buf, ", ");
237 if (IsA(arg, TypeCast))
239 TypeCast *tc = (TypeCast *) arg;
241 arg = tc->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))
251 case T_Integer:
252 appendStringInfo(&buf, "%d", intVal(&con->val));
253 break;
254 case T_Float:
255 /* represented as a string, so just copy it */
256 appendStringInfoString(&buf, castNode(Float, &con->val)->fval);
257 break;
258 case T_String:
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
265 * for any typmod.
267 Oid typoid;
268 int32 typmod;
269 Datum interval;
270 char *intervalout;
272 typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod);
273 Assert(typoid == INTERVALOID);
275 interval =
276 DirectFunctionCall3(interval_in,
277 CStringGetDatum(val),
278 ObjectIdGetDatum(InvalidOid),
279 Int32GetDatum(typmod));
281 intervalout =
282 DatumGetCString(DirectFunctionCall1(interval_out,
283 interval));
284 appendStringInfo(&buf, "INTERVAL '%s'", intervalout);
286 else
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));
294 else
295 appendStringInfoString(&buf, val);
297 break;
298 default:
299 elog(ERROR, "unrecognized node type: %d",
300 (int) nodeTag(&con->val));
301 break;
305 return buf.data;
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.
314 void
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,
321 argstring,
322 (superuser() ? PGC_SUSET : PGC_USERSET),
323 PGC_S_SESSION,
324 is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
325 true, 0, false);
329 * SET command wrapped as a SQL callable function.
331 Datum
332 set_config_by_name(PG_FUNCTION_ARGS)
334 char *name;
335 char *value;
336 char *new_value;
337 bool is_local;
339 if (PG_ARGISNULL(0))
340 ereport(ERROR,
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 */
348 if (PG_ARGISNULL(1))
349 value = NULL;
350 else
351 value = TextDatumGetCString(PG_GETARG_DATUM(1));
354 * Get the desired state of is_local. Default to false if provided value
355 * is NULL
357 if (PG_ARGISNULL(2))
358 is_local = false;
359 else
360 is_local = PG_GETARG_BOOL(2);
362 /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
363 (void) set_config_option(name,
364 value,
365 (superuser() ? PGC_SUSET : PGC_USERSET),
366 PGC_S_SESSION,
367 is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
368 true, 0, false);
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));
379 * SHOW command
381 void
382 GetPGVariable(const char *name, DestReceiver *dest)
384 if (guc_name_compare(name, "all") == 0)
385 ShowAllGUCConfig(dest);
386 else
387 ShowGUCConfigOption(name, dest);
391 * Get a tuple descriptor for SHOW's result
393 TupleDesc
394 GetPGVariableResultDesc(const char *name)
396 TupleDesc tupdesc;
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",
403 TEXTOID, -1, 0);
404 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
405 TEXTOID, -1, 0);
406 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
407 TEXTOID, -1, 0);
409 else
411 const char *varname;
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,
419 TEXTOID, -1, 0);
421 return tupdesc;
425 * SHOW one variable
427 static void
428 ShowGUCConfigOption(const char *name, DestReceiver *dest)
430 TupOutputState *tstate;
431 TupleDesc tupdesc;
432 const char *varname;
433 char *value;
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,
441 TEXTOID, -1, 0);
443 /* prepare for projection of tuples */
444 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
446 /* Send it */
447 do_text_output_oneline(tstate, value);
449 end_tup_output(tstate);
453 * SHOW ALL command
455 static void
456 ShowAllGUCConfig(DestReceiver *dest)
458 struct config_generic **guc_vars;
459 int num_vars;
460 TupOutputState *tstate;
461 TupleDesc tupdesc;
462 Datum values[3];
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",
471 TEXTOID, -1, 0);
472 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "setting",
473 TEXTOID, -1, 0);
474 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description",
475 TEXTOID, -1, 0);
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];
483 char *setting;
485 /* skip if marked NO_SHOW_ALL */
486 if (conf->flags & GUC_NO_SHOW_ALL)
487 continue;
489 /* return only options visible to the current user */
490 if (!ConfigOptionIsVisible(conf))
491 continue;
493 /* assign to the values array */
494 values[0] = PointerGetDatum(cstring_to_text(conf->name));
496 setting = ShowGUCOption(conf, true);
497 if (setting)
499 values[1] = PointerGetDatum(cstring_to_text(setting));
500 isnull[1] = false;
502 else
504 values[1] = PointerGetDatum(NULL);
505 isnull[1] = true;
508 if (conf->short_desc)
510 values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
511 isnull[2] = false;
513 else
515 values[2] = PointerGetDatum(NULL);
516 isnull[2] = true;
519 /* send it to dest */
520 do_tup_output(tstate, values, isnull);
522 /* clean up */
523 pfree(DatumGetPointer(values[0]));
524 if (setting)
526 pfree(setting);
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.
541 Datum
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;
547 int cnt = 0;
548 Datum flags[MAX_GUC_FLAGS];
549 ArrayType *a;
551 record = find_option(varname, false, true, ERROR);
553 /* return NULL if no such variable */
554 if (record == NULL)
555 PG_RETURN_NULL();
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.
580 bool
581 ConfigOptionIsVisible(struct config_generic *conf)
583 if ((conf->flags & GUC_SUPERUSER_ONLY) &&
584 !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
585 return false;
586 else
587 return true;
591 * Extract fields to show in pg_settings for given variable.
593 static void
594 GetConfigOptionValues(struct config_generic *conf, const char **values)
596 char buffer[256];
598 /* first get the generic attributes */
600 /* name */
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);
609 /* group */
610 values[3] = _(config_group_names[conf->group]);
612 /* short_desc */
613 values[4] = conf->short_desc != NULL ? _(conf->short_desc) : NULL;
615 /* extra_desc */
616 values[5] = conf->long_desc != NULL ? _(conf->long_desc) : NULL;
618 /* context */
619 values[6] = GucContext_Names[conf->context];
621 /* vartype */
622 values[7] = config_type_names[conf->vartype];
624 /* source */
625 values[8] = GucSource_Names[conf->source];
627 /* now get the type specific attributes */
628 switch (conf->vartype)
630 case PGC_BOOL:
632 struct config_bool *lconf = (struct config_bool *) conf;
634 /* min_val */
635 values[9] = NULL;
637 /* max_val */
638 values[10] = NULL;
640 /* enumvals */
641 values[11] = NULL;
643 /* boot_val */
644 values[12] = pstrdup(lconf->boot_val ? "on" : "off");
646 /* reset_val */
647 values[13] = pstrdup(lconf->reset_val ? "on" : "off");
649 break;
651 case PGC_INT:
653 struct config_int *lconf = (struct config_int *) conf;
655 /* min_val */
656 snprintf(buffer, sizeof(buffer), "%d", lconf->min);
657 values[9] = pstrdup(buffer);
659 /* max_val */
660 snprintf(buffer, sizeof(buffer), "%d", lconf->max);
661 values[10] = pstrdup(buffer);
663 /* enumvals */
664 values[11] = NULL;
666 /* boot_val */
667 snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
668 values[12] = pstrdup(buffer);
670 /* reset_val */
671 snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
672 values[13] = pstrdup(buffer);
674 break;
676 case PGC_REAL:
678 struct config_real *lconf = (struct config_real *) conf;
680 /* min_val */
681 snprintf(buffer, sizeof(buffer), "%g", lconf->min);
682 values[9] = pstrdup(buffer);
684 /* max_val */
685 snprintf(buffer, sizeof(buffer), "%g", lconf->max);
686 values[10] = pstrdup(buffer);
688 /* enumvals */
689 values[11] = NULL;
691 /* boot_val */
692 snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
693 values[12] = pstrdup(buffer);
695 /* reset_val */
696 snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
697 values[13] = pstrdup(buffer);
699 break;
701 case PGC_STRING:
703 struct config_string *lconf = (struct config_string *) conf;
705 /* min_val */
706 values[9] = NULL;
708 /* max_val */
709 values[10] = NULL;
711 /* enumvals */
712 values[11] = NULL;
714 /* boot_val */
715 if (lconf->boot_val == NULL)
716 values[12] = NULL;
717 else
718 values[12] = pstrdup(lconf->boot_val);
720 /* reset_val */
721 if (lconf->reset_val == NULL)
722 values[13] = NULL;
723 else
724 values[13] = pstrdup(lconf->reset_val);
726 break;
728 case PGC_ENUM:
730 struct config_enum *lconf = (struct config_enum *) conf;
732 /* min_val */
733 values[9] = NULL;
735 /* max_val */
736 values[10] = NULL;
738 /* enumvals */
741 * NOTE! enumvals with double quotes in them are not
742 * supported!
744 values[11] = config_enum_get_options((struct config_enum *) conf,
745 "{\"", "\"}", "\",\"");
747 /* boot_val */
748 values[12] = pstrdup(config_enum_lookup_by_value(lconf,
749 lconf->boot_val));
751 /* reset_val */
752 values[13] = pstrdup(config_enum_lookup_by_value(lconf,
753 lconf->reset_val));
755 break;
757 default:
760 * should never get here, but in case we do, set 'em to NULL
763 /* min_val */
764 values[9] = NULL;
766 /* max_val */
767 values[10] = NULL;
769 /* enumvals */
770 values[11] = NULL;
772 /* boot_val */
773 values[12] = NULL;
775 /* reset_val */
776 values[13] = NULL;
778 break;
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);
793 else
795 values[14] = NULL;
796 values[15] = NULL;
799 values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f";
803 * show_config_by_name - equiv to SHOW X command but implemented as
804 * a function.
806 Datum
807 show_config_by_name(PG_FUNCTION_ARGS)
809 char *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
810 char *varval;
812 /* Get the value */
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.
824 Datum
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);
829 char *varval;
831 /* Get the value */
832 varval = GetConfigOptionByName(varname, NULL, missing_ok);
834 /* return NULL if no such variable */
835 if (varval == NULL)
836 PG_RETURN_NULL();
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
844 * a Table Function.
846 #define NUM_PG_SETTINGS_ATTS 17
848 Datum
849 show_all_settings(PG_FUNCTION_ARGS)
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;
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",
877 TEXTOID, -1, 0);
878 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
879 TEXTOID, -1, 0);
880 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit",
881 TEXTOID, -1, 0);
882 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category",
883 TEXTOID, -1, 0);
884 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc",
885 TEXTOID, -1, 0);
886 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc",
887 TEXTOID, -1, 0);
888 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context",
889 TEXTOID, -1, 0);
890 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype",
891 TEXTOID, -1, 0);
892 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source",
893 TEXTOID, -1, 0);
894 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val",
895 TEXTOID, -1, 0);
896 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
897 TEXTOID, -1, 0);
898 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals",
899 TEXTARRAYOID, -1, 0);
900 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val",
901 TEXTOID, -1, 0);
902 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val",
903 TEXTOID, -1, 0);
904 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile",
905 TEXTOID, -1, 0);
906 TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline",
907 INT4OID, -1, 0);
908 TupleDescInitEntry(tupdesc, (AttrNumber) 17, "pending_restart",
909 BOOLOID, -1, 0);
912 * Generate attribute metadata needed later to produce tuples from raw
913 * C strings
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];
942 HeapTuple tuple;
943 Datum result;
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;
950 continue;
953 /* extract values for the current variable */
954 GetConfigOptionValues(conf, (const char **) values);
956 /* build a tuple */
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.
983 Datum
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;
989 int seqno;
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));
1006 /* sourcefile */
1007 if (conf->filename)
1008 values[0] = PointerGetDatum(cstring_to_text(conf->filename));
1009 else
1010 nulls[0] = true;
1012 /* sourceline (not meaningful if no sourcefile) */
1013 if (conf->filename)
1014 values[1] = Int32GetDatum(conf->sourceline);
1015 else
1016 nulls[1] = true;
1018 /* seqno */
1019 values[2] = Int32GetDatum(seqno);
1021 /* name */
1022 if (conf->name)
1023 values[3] = PointerGetDatum(cstring_to_text(conf->name));
1024 else
1025 nulls[3] = true;
1027 /* setting */
1028 if (conf->value)
1029 values[4] = PointerGetDatum(cstring_to_text(conf->value));
1030 else
1031 nulls[4] = true;
1033 /* applied */
1034 values[5] = BoolGetDatum(conf->applied);
1036 /* error */
1037 if (conf->errmsg)
1038 values[6] = PointerGetDatum(cstring_to_text(conf->errmsg));
1039 else
1040 nulls[6] = true;
1042 /* shove row into tuplestore */
1043 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1046 return (Datum) 0;