2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2025, PostgreSQL Global Development Group
6 * src/bin/psql/variables.c
17 * Check whether a variable's name is allowed.
19 * We allow any non-ASCII character, as well as ASCII letters, digits, and
20 * underscore. Keep this in sync with the definition of variable_char in
21 * psqlscan.l and psqlscanslash.l.
26 const unsigned char *ptr = (
const unsigned char *)
name;
28 /* Mustn't be zero-length */
35 strchr(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
36 "_0123456789", *ptr) != NULL)
46 * A "variable space" is represented by an otherwise-unused struct _variable
47 * that serves as list header.
49 * The list entries are kept in name order (according to strcmp). This
50 * is mainly to make the output of PrintVariables() more pleasing.
68 * Get string value of variable, or NULL if it's not defined.
70 * Note: result is valid until variable is next assigned to.
80 for (current = space->
next; current; current = current->
next)
86 /* this is correct answer when value is NULL, too */
87 return current->
value;
90 break;
/* it's not there */
97 * Try to interpret "value" as a boolean value, and if successful,
98 * store it in *result. Otherwise don't clobber *result.
100 * Valid values are: true, false, yes, no, on, off, 1, 0; as well as unique
103 * "name" is the name of the variable we're assigning to, to use in error
104 * report if any. Pass name == NULL to suppress the error report.
106 * Return true when "value" is syntactically valid, false otherwise.
114 /* Treat "unset" as an empty string, which will lead to error below */
128 /* 'o' is not unique enough */
139 /* string is not recognized; don't clobber *result */
141 pg_log_error(
"unrecognized value \"%s\" for \"%s\": Boolean expected",
149 * Try to interpret "value" as an integer value, and if successful,
150 * store it in *result. Otherwise don't clobber *result.
152 * "name" is the name of the variable we're assigning to, to use in error
153 * report if any. Pass name == NULL to suppress the error report.
155 * Return true when "value" is syntactically valid, false otherwise.
163 /* Treat "unset" as an empty string, which will lead to error below */
168 numval = strtol(
value, &end, 0);
169 if (errno == 0 && *end ==
'0円' && end !=
value && numval == (
int) numval)
171 *result = (int) numval;
176 /* string is not recognized; don't clobber *result */
178 pg_log_error(
"invalid value \"%s\" for \"%s\": integer expected",
185 * Try to interpret "value" as a double value, and if successful store it in
186 * *result. If unsuccessful, *result isn't clobbered. "name" is the variable
187 * which is being assigned, the value of which is only used to produce a good
188 * error message. Pass NULL as the name to suppress the error message. The
189 * value must be within the range [min,max] in order to be considered valid.
191 * Returns true, with *result containing the interpreted value, if "value" is
192 * syntactically valid, else false (with *result unchanged).
201 * Empty-string input has historically been treated differently by strtod
202 * on various platforms, so handle that by specifically checking for it.
212 dblval = strtod(
value, &end);
213 if (errno == 0 && *end ==
'0円' && end !=
value)
218 pg_log_error(
"invalid value \"%s\" for variable \"%s\": must be greater than %.2f",
222 else if (dblval > max)
225 pg_log_error(
"invalid value \"%s\" for variable \"%s\": must be less than %.2f",
233 * Cater for platforms which treat values which aren't zero, but that are
234 * too close to zero to have full precision, by checking for zero or real
235 * out-of-range values.
237 else if ((errno == ERANGE) &&
238 (dblval == 0.0 || dblval >= HUGE_VAL || dblval <= -HUGE_VAL))
253 * Print values of all variables.
263 for (ptr = space->
next; ptr; ptr = ptr->
next)
273 * Set the variable named "name" to value "value",
274 * or delete it if "value" is NULL.
276 * Returns true if successful, false if not; in the latter case a suitable
277 * error message has been printed, except for the unexpected case of
278 * space or name being NULL.
291 /* Deletion of non-existent variable is not an error */
298 for (previous = space, current = space->
next;
300 previous = current, current = current->
next)
307 * Found entry, so update, unless assign hook returns false.
309 * We must duplicate the passed value to start with. This
310 * simplifies the API for substitute hooks. Moreover, some assign
311 * hooks assume that the passed value has the same lifespan as the
312 * variable. Having to free the string again on failure is a
313 * small price to pay for keeping these APIs simple.
329 current->
value = new_value;
332 * If we deleted the value, and there are no hooks to
333 * remember, we can discard the variable altogether.
335 if (new_value == NULL &&
345 pg_free(new_value);
/* current->value is left unchanged */
350 break;
/* it's not there */
353 /* not present, make new entry ... unless we were asked to delete */
362 previous->
next = current;
368 * Attach substitute and/or assign hook functions to the named variable.
369 * If you need only one hook, pass NULL for the other.
371 * If the variable doesn't already exist, create it with value NULL, just so
372 * we have a place to store the hook function(s). (The substitute hook might
373 * immediately change the NULL to something else; if not, this state is
374 * externally the same as the variable not being defined.)
376 * The substitute hook, if given, is immediately called on the variable's
377 * value. Then the assign hook, if given, is called on the variable's value.
378 * This is meant to let it update any derived psql state. If the assign hook
379 * doesn't like the current value, it will print a message to that effect,
380 * but we'll ignore it. Generally we do not expect any such failure here,
381 * because this should get called before any user-supplied value is assigned.
397 for (previous = space, current = space->
next;
399 previous = current, current = current->
next)
405 /* found entry, so update */
411 (void) (*ahook) (current->
value);
415 break;
/* it's not there */
418 /* not present, make new entry */
421 current->
value = NULL;
425 previous->
next = current;
429 (void) (*ahook) (current->
value);
433 * Return true iff the named variable has substitute and/or assign hook
444 for (current = space->
next; current; current = current->
next)
452 break;
/* it's not there */
459 * Convenience function to set a variable's value to "on".
468 * Attempt to delete variable.
470 * If unsuccessful, print a message and return "false".
471 * Deleting a nonexistent variable is not an error.
480 * Emit error with suggestions for variables or commands
481 * accepting enum-style arguments.
482 * This function just exists to standardize the wording.
483 * suggestions should follow the format "fee, fi, fo, fum".
489 "Available values are: %s.",
#define IS_HIGHBIT_SET(ch)
void * pg_malloc(size_t size)
char * pg_strdup(const char *in)
volatile sig_atomic_t cancel_pressed
Assert(PointerIsAligned(start, uint64))
#define pg_log_error(...)
int pg_strcasecmp(const char *s1, const char *s2)
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
static int cmp(const chr *x, const chr *y, size_t len)
VariableSubstituteHook substitute_hook
VariableAssignHook assign_hook
void PrintVariables(VariableSpace space)
bool DeleteVariable(VariableSpace space, const char *name)
void SetVariableHooks(VariableSpace space, const char *name, VariableSubstituteHook shook, VariableAssignHook ahook)
void PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
bool ParseVariableBool(const char *value, const char *name, bool *result)
bool ParseVariableDouble(const char *value, const char *name, double *result, double min, double max)
bool SetVariableBool(VariableSpace space, const char *name)
bool ParseVariableNum(const char *value, const char *name, int *result)
bool VariableHasHook(VariableSpace space, const char *name)
bool SetVariable(VariableSpace space, const char *name, const char *value)
static bool valid_variable_name(const char *name)
const char * GetVariable(VariableSpace space, const char *name)
VariableSpace CreateVariableSpace(void)
char *(* VariableSubstituteHook)(char *newval)
bool(* VariableAssignHook)(const char *newval)