PostgreSQL Source Code  git master
variables.c
Go to the documentation of this file.
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2024, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/variables.c
7  */
8 #include "postgres_fe.h"
9 
10 #include "common.h"
11 #include "common/logging.h"
12 #include "variables.h"
13 
14 /*
15  * Check whether a variable's name is allowed.
16  *
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.
20  */
21 static bool
23 {
24  const unsigned char *ptr = (const unsigned char *) name;
25 
26  /* Mustn't be zero-length */
27  if (*ptr == '\0')
28  return false;
29 
30  while (*ptr)
31  {
32  if (IS_HIGHBIT_SET(*ptr) ||
33  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
34  "_0123456789", *ptr) != NULL)
35  ptr++;
36  else
37  return false;
38  }
39 
40  return true;
41 }
42 
43 /*
44  * A "variable space" is represented by an otherwise-unused struct _variable
45  * that serves as list header.
46  *
47  * The list entries are kept in name order (according to strcmp). This
48  * is mainly to make the output of PrintVariables() more pleasing.
49  */
52 {
53  struct _variable *ptr;
54 
55  ptr = pg_malloc(sizeof *ptr);
56  ptr->name = NULL;
57  ptr->value = NULL;
58  ptr->substitute_hook = NULL;
59  ptr->assign_hook = NULL;
60  ptr->next = NULL;
61 
62  return ptr;
63 }
64 
65 /*
66  * Get string value of variable, or NULL if it's not defined.
67  *
68  * Note: result is valid until variable is next assigned to.
69  */
70 const char *
71 GetVariable(VariableSpace space, const char *name)
72 {
73  struct _variable *current;
74 
75  if (!space)
76  return NULL;
77 
78  for (current = space->next; current; current = current->next)
79  {
80  int cmp = strcmp(current->name, name);
81 
82  if (cmp == 0)
83  {
84  /* this is correct answer when value is NULL, too */
85  return current->value;
86  }
87  if (cmp > 0)
88  break; /* it's not there */
89  }
90 
91  return NULL;
92 }
93 
94 /*
95  * Try to interpret "value" as a boolean value, and if successful,
96  * store it in *result. Otherwise don't clobber *result.
97  *
98  * Valid values are: true, false, yes, no, on, off, 1, 0; as well as unique
99  * prefixes thereof.
100  *
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.
103  *
104  * Return true when "value" is syntactically valid, false otherwise.
105  */
106 bool
107 ParseVariableBool(const char *value, const char *name, bool *result)
108 {
109  size_t len;
110  bool valid = true;
111 
112  /* Treat "unset" as an empty string, which will lead to error below */
113  if (value == NULL)
114  value = "";
115 
116  len = strlen(value);
117 
118  if (len > 0 && pg_strncasecmp(value, "true", len) == 0)
119  *result = true;
120  else if (len > 0 && pg_strncasecmp(value, "false", len) == 0)
121  *result = false;
122  else if (len > 0 && pg_strncasecmp(value, "yes", len) == 0)
123  *result = true;
124  else if (len > 0 && pg_strncasecmp(value, "no", len) == 0)
125  *result = false;
126  /* 'o' is not unique enough */
127  else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
128  *result = true;
129  else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
130  *result = false;
131  else if (pg_strcasecmp(value, "1") == 0)
132  *result = true;
133  else if (pg_strcasecmp(value, "0") == 0)
134  *result = false;
135  else
136  {
137  /* string is not recognized; don't clobber *result */
138  if (name)
139  pg_log_error("unrecognized value \"%s\" for \"%s\": Boolean expected",
140  value, name);
141  valid = false;
142  }
143  return valid;
144 }
145 
146 /*
147  * Try to interpret "value" as an integer value, and if successful,
148  * store it in *result. Otherwise don't clobber *result.
149  *
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.
152  *
153  * Return true when "value" is syntactically valid, false otherwise.
154  */
155 bool
156 ParseVariableNum(const char *value, const char *name, int *result)
157 {
158  char *end;
159  long numval;
160 
161  /* Treat "unset" as an empty string, which will lead to error below */
162  if (value == NULL)
163  value = "";
164 
165  errno = 0;
166  numval = strtol(value, &end, 0);
167  if (errno == 0 && *end == '\0' && end != value && numval == (int) numval)
168  {
169  *result = (int) numval;
170  return true;
171  }
172  else
173  {
174  /* string is not recognized; don't clobber *result */
175  if (name)
176  pg_log_error("invalid value \"%s\" for \"%s\": integer expected",
177  value, name);
178  return false;
179  }
180 }
181 
182 /*
183  * Print values of all variables.
184  */
185 void
187 {
188  struct _variable *ptr;
189 
190  if (!space)
191  return;
192 
193  for (ptr = space->next; ptr; ptr = ptr->next)
194  {
195  if (ptr->value)
196  printf("%s = '%s'\n", ptr->name, ptr->value);
197  if (cancel_pressed)
198  break;
199  }
200 }
201 
202 /*
203  * Set the variable named "name" to value "value",
204  * or delete it if "value" is NULL.
205  *
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.
209  */
210 bool
211 SetVariable(VariableSpace space, const char *name, const char *value)
212 {
213  struct _variable *current,
214  *previous;
215 
216  if (!space || !name)
217  return false;
218 
220  {
221  /* Deletion of non-existent variable is not an error */
222  if (!value)
223  return true;
224  pg_log_error("invalid variable name: \"%s\"", name);
225  return false;
226  }
227 
228  for (previous = space, current = space->next;
229  current;
230  previous = current, current = current->next)
231  {
232  int cmp = strcmp(current->name, name);
233 
234  if (cmp == 0)
235  {
236  /*
237  * Found entry, so update, unless assign hook returns false.
238  *
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.
244  */
245  char *new_value = value ? pg_strdup(value) : NULL;
246  bool confirmed;
247 
248  if (current->substitute_hook)
249  new_value = current->substitute_hook(new_value);
250 
251  if (current->assign_hook)
252  confirmed = current->assign_hook(new_value);
253  else
254  confirmed = true;
255 
256  if (confirmed)
257  {
258  pg_free(current->value);
259  current->value = new_value;
260 
261  /*
262  * If we deleted the value, and there are no hooks to
263  * remember, we can discard the variable altogether.
264  */
265  if (new_value == NULL &&
266  current->substitute_hook == NULL &&
267  current->assign_hook == NULL)
268  {
269  previous->next = current->next;
270  free(current->name);
271  free(current);
272  }
273  }
274  else
275  pg_free(new_value); /* current->value is left unchanged */
276 
277  return confirmed;
278  }
279  if (cmp > 0)
280  break; /* it's not there */
281  }
282 
283  /* not present, make new entry ... unless we were asked to delete */
284  if (value)
285  {
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;
293  }
294  return true;
295 }
296 
297 /*
298  * Attach substitute and/or assign hook functions to the named variable.
299  * If you need only one hook, pass NULL for the other.
300  *
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.)
305  *
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.
312  */
313 void
316  VariableAssignHook ahook)
317 {
318  struct _variable *current,
319  *previous;
320 
321  if (!space || !name)
322  return;
323 
325  return;
326 
327  for (previous = space, current = space->next;
328  current;
329  previous = current, current = current->next)
330  {
331  int cmp = strcmp(current->name, name);
332 
333  if (cmp == 0)
334  {
335  /* found entry, so update */
336  current->substitute_hook = shook;
337  current->assign_hook = ahook;
338  if (shook)
339  current->value = (*shook) (current->value);
340  if (ahook)
341  (void) (*ahook) (current->value);
342  return;
343  }
344  if (cmp > 0)
345  break; /* it's not there */
346  }
347 
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;
356  if (shook)
357  current->value = (*shook) (current->value);
358  if (ahook)
359  (void) (*ahook) (current->value);
360 }
361 
362 /*
363  * Return true iff the named variable has substitute and/or assign hook
364  * functions.
365  */
366 bool
367 VariableHasHook(VariableSpace space, const char *name)
368 {
369  struct _variable *current;
370 
371  Assert(space);
372  Assert(name);
373 
374  for (current = space->next; current; current = current->next)
375  {
376  int cmp = strcmp(current->name, name);
377 
378  if (cmp == 0)
379  return (current->substitute_hook != NULL ||
380  current->assign_hook != NULL);
381  if (cmp > 0)
382  break; /* it's not there */
383  }
384 
385  return false;
386 }
387 
388 /*
389  * Convenience function to set a variable's value to "on".
390  */
391 bool
392 SetVariableBool(VariableSpace space, const char *name)
393 {
394  return SetVariable(space, name, "on");
395 }
396 
397 /*
398  * Attempt to delete variable.
399  *
400  * If unsuccessful, print a message and return "false".
401  * Deleting a nonexistent variable is not an error.
402  */
403 bool
404 DeleteVariable(VariableSpace space, const char *name)
405 {
406  return SetVariable(space, name, NULL);
407 }
408 
409 /*
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".
414  */
415 void
416 PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
417 {
418  pg_log_error("unrecognized value \"%s\" for \"%s\"\n"
419  "Available values are: %s.",
420  value, name, suggestions);
421 }
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1142
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
volatile sig_atomic_t cancel_pressed
Definition: print.c:43
#define free(a)
Definition: header.h:65
static struct @150 value
Assert(fmt[strlen(fmt) - 1] !='\n')
#define pg_log_error(...)
Definition: logging.h:106
const void size_t len
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define printf(...)
Definition: port.h:244
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
VariableSubstituteHook substitute_hook
Definition: variables.h:66
VariableAssignHook assign_hook
Definition: variables.h:67
struct _variable * next
Definition: variables.h:68
char * name
Definition: variables.h:64
char * value
Definition: variables.h:65
void PrintVariables(VariableSpace space)
Definition: variables.c:186
bool DeleteVariable(VariableSpace space, const char *name)
Definition: variables.c:404
void SetVariableHooks(VariableSpace space, const char *name, VariableSubstituteHook shook, VariableAssignHook ahook)
Definition: variables.c:314
void PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
Definition: variables.c:416
bool ParseVariableBool(const char *value, const char *name, bool *result)
Definition: variables.c:107
bool SetVariableBool(VariableSpace space, const char *name)
Definition: variables.c:392
bool ParseVariableNum(const char *value, const char *name, int *result)
Definition: variables.c:156
bool VariableHasHook(VariableSpace space, const char *name)
Definition: variables.c:367
bool SetVariable(VariableSpace space, const char *name, const char *value)
Definition: variables.c:211
static bool valid_variable_name(const char *name)
Definition: variables.c:22
const char * GetVariable(VariableSpace space, const char *name)
Definition: variables.c:71
VariableSpace CreateVariableSpace(void)
Definition: variables.c:51
char *(* VariableSubstituteHook)(char *newval)
Definition: variables.h:54
bool(* VariableAssignHook)(const char *newval)
Definition: variables.h:31
const char * name