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