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