2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2025, PostgreSQL Global Development Group
6 * src/bin/psql/variables.c
8 #include "postgres_fe.h"
11 #include "common/logging.h"
12 #include "variables.h"
15 * Check whether a variable's name is allowed.
17 * We allow any non-ASCII character, as well as ASCII letters, digits, and
18 * underscore. Keep this in sync with the definition of variable_char in
19 * psqlscan.l and psqlscanslash.l.
22 valid_variable_name(const char *name
)
24 const unsigned char *ptr
= (const unsigned char *) name
;
26 /* Mustn't be zero-length */
32 if (IS_HIGHBIT_SET(*ptr
) ||
33 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
34 "_0123456789", *ptr
) != NULL
)
44 * A "variable space" is represented by an otherwise-unused struct _variable
45 * that serves as list header.
47 * The list entries are kept in name order (according to strcmp). This
48 * is mainly to make the output of PrintVariables() more pleasing.
51 CreateVariableSpace(void)
53 struct _variable
*ptr
;
55 ptr
= pg_malloc(sizeof *ptr
);
58 ptr
->substitute_hook
= NULL
;
59 ptr
->assign_hook
= NULL
;
66 * Get string value of variable, or NULL if it's not defined.
68 * Note: result is valid until variable is next assigned to.
71 GetVariable(VariableSpace space
, const char *name
)
73 struct _variable
*current
;
78 for (current
= space
->next
; current
; current
= current
->next
)
80 int cmp
= strcmp(current
->name
, name
);
84 /* this is correct answer when value is NULL, too */
85 return current
->value
;
88 break; /* it's not there */
95 * Try to interpret "value" as a boolean value, and if successful,
96 * store it in *result. Otherwise don't clobber *result.
98 * Valid values are: true, false, yes, no, on, off, 1, 0; as well as unique
101 * "name" is the name of the variable we're assigning to, to use in error
102 * report if any. Pass name == NULL to suppress the error report.
104 * Return true when "value" is syntactically valid, false otherwise.
107 ParseVariableBool(const char *value
, const char *name
, bool *result
)
112 /* Treat "unset" as an empty string, which will lead to error below */
118 if (len
> 0 && pg_strncasecmp(value
, "true", len
) == 0)
120 else if (len
> 0 && pg_strncasecmp(value
, "false", len
) == 0)
122 else if (len
> 0 && pg_strncasecmp(value
, "yes", len
) == 0)
124 else if (len
> 0 && pg_strncasecmp(value
, "no", len
) == 0)
126 /* 'o' is not unique enough */
127 else if (pg_strncasecmp(value
, "on", (len
> 2 ? len
: 2)) == 0)
129 else if (pg_strncasecmp(value
, "off", (len
> 2 ? len
: 2)) == 0)
131 else if (pg_strcasecmp(value
, "1") == 0)
133 else if (pg_strcasecmp(value
, "0") == 0)
137 /* string is not recognized; don't clobber *result */
139 pg_log_error("unrecognized value \"%s\" for \"%s\": Boolean expected",
147 * Try to interpret "value" as an integer value, and if successful,
148 * store it in *result. Otherwise don't clobber *result.
150 * "name" is the name of the variable we're assigning to, to use in error
151 * report if any. Pass name == NULL to suppress the error report.
153 * Return true when "value" is syntactically valid, false otherwise.
156 ParseVariableNum(const char *value
, const char *name
, int *result
)
161 /* Treat "unset" as an empty string, which will lead to error below */
166 numval
= strtol(value
, &end
, 0);
167 if (errno
== 0 && *end
== '\0' && end
!= value
&& numval
== (int) numval
)
169 *result
= (int) numval
;
174 /* string is not recognized; don't clobber *result */
176 pg_log_error("invalid value \"%s\" for \"%s\": integer expected",
183 * Print values of all variables.
186 PrintVariables(VariableSpace space
)
188 struct _variable
*ptr
;
193 for (ptr
= space
->next
; ptr
; ptr
= ptr
->next
)
196 printf("%s = '%s'\n", ptr
->name
, ptr
->value
);
203 * Set the variable named "name" to value "value",
204 * or delete it if "value" is NULL.
206 * Returns true if successful, false if not; in the latter case a suitable
207 * error message has been printed, except for the unexpected case of
208 * space or name being NULL.
211 SetVariable(VariableSpace space
, const char *name
, const char *value
)
213 struct _variable
*current
,
219 if (!valid_variable_name(name
))
221 /* Deletion of non-existent variable is not an error */
224 pg_log_error("invalid variable name: \"%s\"", name
);
228 for (previous
= space
, current
= space
->next
;
230 previous
= current
, current
= current
->next
)
232 int cmp
= strcmp(current
->name
, name
);
237 * Found entry, so update, unless assign hook returns false.
239 * We must duplicate the passed value to start with. This
240 * simplifies the API for substitute hooks. Moreover, some assign
241 * hooks assume that the passed value has the same lifespan as the
242 * variable. Having to free the string again on failure is a
243 * small price to pay for keeping these APIs simple.
245 char *new_value
= value
? pg_strdup(value
) : NULL
;
248 if (current
->substitute_hook
)
249 new_value
= current
->substitute_hook(new_value
);
251 if (current
->assign_hook
)
252 confirmed
= current
->assign_hook(new_value
);
258 pg_free(current
->value
);
259 current
->value
= new_value
;
262 * If we deleted the value, and there are no hooks to
263 * remember, we can discard the variable altogether.
265 if (new_value
== NULL
&&
266 current
->substitute_hook
== NULL
&&
267 current
->assign_hook
== NULL
)
269 previous
->next
= current
->next
;
275 pg_free(new_value
); /* current->value is left unchanged */
280 break; /* it's not there */
283 /* not present, make new entry ... unless we were asked to delete */
286 current
= pg_malloc(sizeof *current
);
287 current
->name
= pg_strdup(name
);
288 current
->value
= pg_strdup(value
);
289 current
->substitute_hook
= NULL
;
290 current
->assign_hook
= NULL
;
291 current
->next
= previous
->next
;
292 previous
->next
= current
;
298 * Attach substitute and/or assign hook functions to the named variable.
299 * If you need only one hook, pass NULL for the other.
301 * If the variable doesn't already exist, create it with value NULL, just so
302 * we have a place to store the hook function(s). (The substitute hook might
303 * immediately change the NULL to something else; if not, this state is
304 * externally the same as the variable not being defined.)
306 * The substitute hook, if given, is immediately called on the variable's
307 * value. Then the assign hook, if given, is called on the variable's value.
308 * This is meant to let it update any derived psql state. If the assign hook
309 * doesn't like the current value, it will print a message to that effect,
310 * but we'll ignore it. Generally we do not expect any such failure here,
311 * because this should get called before any user-supplied value is assigned.
314 SetVariableHooks(VariableSpace space
, const char *name
,
315 VariableSubstituteHook shook
,
316 VariableAssignHook ahook
)
318 struct _variable
*current
,
324 if (!valid_variable_name(name
))
327 for (previous
= space
, current
= space
->next
;
329 previous
= current
, current
= current
->next
)
331 int cmp
= strcmp(current
->name
, name
);
335 /* found entry, so update */
336 current
->substitute_hook
= shook
;
337 current
->assign_hook
= ahook
;
339 current
->value
= (*shook
) (current
->value
);
341 (void) (*ahook
) (current
->value
);
345 break; /* it's not there */
348 /* not present, make new entry */
349 current
= pg_malloc(sizeof *current
);
350 current
->name
= pg_strdup(name
);
351 current
->value
= NULL
;
352 current
->substitute_hook
= shook
;
353 current
->assign_hook
= ahook
;
354 current
->next
= previous
->next
;
355 previous
->next
= current
;
357 current
->value
= (*shook
) (current
->value
);
359 (void) (*ahook
) (current
->value
);
363 * Return true iff the named variable has substitute and/or assign hook
367 VariableHasHook(VariableSpace space
, const char *name
)
369 struct _variable
*current
;
374 for (current
= space
->next
; current
; current
= current
->next
)
376 int cmp
= strcmp(current
->name
, name
);
379 return (current
->substitute_hook
!= NULL
||
380 current
->assign_hook
!= NULL
);
382 break; /* it's not there */
389 * Convenience function to set a variable's value to "on".
392 SetVariableBool(VariableSpace space
, const char *name
)
394 return SetVariable(space
, name
, "on");
398 * Attempt to delete variable.
400 * If unsuccessful, print a message and return "false".
401 * Deleting a nonexistent variable is not an error.
404 DeleteVariable(VariableSpace space
, const char *name
)
406 return SetVariable(space
, name
, NULL
);
410 * Emit error with suggestions for variables or commands
411 * accepting enum-style arguments.
412 * This function just exists to standardize the wording.
413 * suggestions should follow the format "fee, fi, fo, fum".
416 PsqlVarEnumError(const char *name
, const char *value
, const char *suggestions
)
418 pg_log_error("unrecognized value \"%s\" for \"%s\"\n"
419 "Available values are: %s.",
420 value
, name
, suggestions
);