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-2019, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/variables.c
7  */
8 #include "postgres_fe.h"
9 
10 #include "common.h"
11 #include "variables.h"
12 
13 #include "common/logging.h"
14 
15 
16 /*
17  * Check whether a variable's name is allowed.
18  *
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.
22  */
23 static bool
25 {
26  const unsigned char *ptr = (const unsigned char *) name;
27 
28  /* Mustn't be zero-length */
29  if (*ptr == '\0')
30  return false;
31 
32  while (*ptr)
33  {
34  if (IS_HIGHBIT_SET(*ptr) ||
35  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
36  "_0123456789", *ptr) != NULL)
37  ptr++;
38  else
39  return false;
40  }
41 
42  return true;
43 }
44 
45 /*
46  * A "variable space" is represented by an otherwise-unused struct _variable
47  * that serves as list header.
48  *
49  * The list entries are kept in name order (according to strcmp). This
50  * is mainly to make the results of PrintVariables() more pleasing.
51  */
54 {
55  struct _variable *ptr;
56 
57  ptr = pg_malloc(sizeof *ptr);
58  ptr->name = NULL;
59  ptr->value = NULL;
60  ptr->substitute_hook = NULL;
61  ptr->assign_hook = NULL;
62  ptr->next = NULL;
63 
64  return ptr;
65 }
66 
67 /*
68  * Get string value of variable, or NULL if it's not defined.
69  *
70  * Note: result is valid until variable is next assigned to.
71  */
72 const char *
73 GetVariable(VariableSpace space, const char *name)
74 {
75  struct _variable *current;
76 
77  if (!space)
78  return NULL;
79 
80  for (current = space->next; current; current = current->next)
81  {
82  int cmp = strcmp(current->name, name);
83 
84  if (cmp == 0)
85  {
86  /* this is correct answer when value is NULL, too */
87  return current->value;
88  }
89  if (cmp > 0)
90  break; /* it's not there */
91  }
92 
93  return NULL;
94 }
95 
96 /*
97  * Try to interpret "value" as a boolean value, and if successful,
98  * store it in *result. Otherwise don't clobber *result.
99  *
100  * Valid values are: true, false, yes, no, on, off, 1, 0; as well as unique
101  * prefixes thereof.
102  *
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.
105  *
106  * Return true when "value" is syntactically valid, false otherwise.
107  */
108 bool
109 ParseVariableBool(const char *value, const char *name, bool *result)
110 {
111  size_t len;
112  bool valid = true;
113 
114  /* Treat "unset" as an empty string, which will lead to error below */
115  if (value == NULL)
116  value = "";
117 
118  len = strlen(value);
119 
120  if (len > 0 && pg_strncasecmp(value, "true", len) == 0)
121  *result = true;
122  else if (len > 0 && pg_strncasecmp(value, "false", len) == 0)
123  *result = false;
124  else if (len > 0 && pg_strncasecmp(value, "yes", len) == 0)
125  *result = true;
126  else if (len > 0 && pg_strncasecmp(value, "no", len) == 0)
127  *result = false;
128  /* 'o' is not unique enough */
129  else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
130  *result = true;
131  else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
132  *result = false;
133  else if (pg_strcasecmp(value, "1") == 0)
134  *result = true;
135  else if (pg_strcasecmp(value, "0") == 0)
136  *result = false;
137  else
138  {
139  /* string is not recognized; don't clobber *result */
140  if (name)
141  pg_log_error("unrecognized value \"%s\" for \"%s\": Boolean expected",
142  value, name);
143  valid = false;
144  }
145  return valid;
146 }
147 
148 /*
149  * Try to interpret "value" as an integer value, and if successful,
150  * store it in *result. Otherwise don't clobber *result.
151  *
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.
154  *
155  * Return true when "value" is syntactically valid, false otherwise.
156  */
157 bool
158 ParseVariableNum(const char *value, const char *name, int *result)
159 {
160  char *end;
161  long numval;
162 
163  /* Treat "unset" as an empty string, which will lead to error below */
164  if (value == NULL)
165  value = "";
166 
167  errno = 0;
168  numval = strtol(value, &end, 0);
169  if (errno == 0 && *end == '\0' && end != value && numval == (int) numval)
170  {
171  *result = (int) numval;
172  return true;
173  }
174  else
175  {
176  /* string is not recognized; don't clobber *result */
177  if (name)
178  pg_log_error("invalid value \"%s\" for \"%s\": integer expected",
179  value, name);
180  return false;
181  }
182 }
183 
184 /*
185  * Print values of all variables.
186  */
187 void
189 {
190  struct _variable *ptr;
191 
192  if (!space)
193  return;
194 
195  for (ptr = space->next; ptr; ptr = ptr->next)
196  {
197  if (ptr->value)
198  printf("%s = '%s'\n", ptr->name, ptr->value);
199  if (cancel_pressed)
200  break;
201  }
202 }
203 
204 /*
205  * Set the variable named "name" to value "value",
206  * or delete it if "value" is NULL.
207  *
208  * Returns true if successful, false if not; in the latter case a suitable
209  * error message has been printed, except for the unexpected case of
210  * space or name being NULL.
211  */
212 bool
213 SetVariable(VariableSpace space, const char *name, const char *value)
214 {
215  struct _variable *current,
216  *previous;
217 
218  if (!space || !name)
219  return false;
220 
221  if (!valid_variable_name(name))
222  {
223  /* Deletion of non-existent variable is not an error */
224  if (!value)
225  return true;
226  pg_log_error("invalid variable name: \"%s\"", name);
227  return false;
228  }
229 
230  for (previous = space, current = space->next;
231  current;
232  previous = current, current = current->next)
233  {
234  int cmp = strcmp(current->name, name);
235 
236  if (cmp == 0)
237  {
238  /*
239  * Found entry, so update, unless assign hook returns false.
240  *
241  * We must duplicate the passed value to start with. This
242  * simplifies the API for substitute hooks. Moreover, some assign
243  * hooks assume that the passed value has the same lifespan as the
244  * variable. Having to free the string again on failure is a
245  * small price to pay for keeping these APIs simple.
246  */
247  char *new_value = value ? pg_strdup(value) : NULL;
248  bool confirmed;
249 
250  if (current->substitute_hook)
251  new_value = current->substitute_hook(new_value);
252 
253  if (current->assign_hook)
254  confirmed = current->assign_hook(new_value);
255  else
256  confirmed = true;
257 
258  if (confirmed)
259  {
260  if (current->value)
261  pg_free(current->value);
262  current->value = new_value;
263 
264  /*
265  * If we deleted the value, and there are no hooks to
266  * remember, we can discard the variable altogether.
267  */
268  if (new_value == NULL &&
269  current->substitute_hook == NULL &&
270  current->assign_hook == NULL)
271  {
272  previous->next = current->next;
273  free(current->name);
274  free(current);
275  }
276  }
277  else if (new_value)
278  pg_free(new_value); /* current->value is left unchanged */
279 
280  return confirmed;
281  }
282  if (cmp > 0)
283  break; /* it's not there */
284  }
285 
286  /* not present, make new entry ... unless we were asked to delete */
287  if (value)
288  {
289  current = pg_malloc(sizeof *current);
290  current->name = pg_strdup(name);
291  current->value = pg_strdup(value);
292  current->substitute_hook = NULL;
293  current->assign_hook = NULL;
294  current->next = previous->next;
295  previous->next = current;
296  }
297  return true;
298 }
299 
300 /*
301  * Attach substitute and/or assign hook functions to the named variable.
302  * If you need only one hook, pass NULL for the other.
303  *
304  * If the variable doesn't already exist, create it with value NULL, just so
305  * we have a place to store the hook function(s). (The substitute hook might
306  * immediately change the NULL to something else; if not, this state is
307  * externally the same as the variable not being defined.)
308  *
309  * The substitute hook, if given, is immediately called on the variable's
310  * value. Then the assign hook, if given, is called on the variable's value.
311  * This is meant to let it update any derived psql state. If the assign hook
312  * doesn't like the current value, it will print a message to that effect,
313  * but we'll ignore it. Generally we do not expect any such failure here,
314  * because this should get called before any user-supplied value is assigned.
315  */
316 void
319  VariableAssignHook ahook)
320 {
321  struct _variable *current,
322  *previous;
323 
324  if (!space || !name)
325  return;
326 
327  if (!valid_variable_name(name))
328  return;
329 
330  for (previous = space, current = space->next;
331  current;
332  previous = current, current = current->next)
333  {
334  int cmp = strcmp(current->name, name);
335 
336  if (cmp == 0)
337  {
338  /* found entry, so update */
339  current->substitute_hook = shook;
340  current->assign_hook = ahook;
341  if (shook)
342  current->value = (*shook) (current->value);
343  if (ahook)
344  (void) (*ahook) (current->value);
345  return;
346  }
347  if (cmp > 0)
348  break; /* it's not there */
349  }
350 
351  /* not present, make new entry */
352  current = pg_malloc(sizeof *current);
353  current->name = pg_strdup(name);
354  current->value = NULL;
355  current->substitute_hook = shook;
356  current->assign_hook = ahook;
357  current->next = previous->next;
358  previous->next = current;
359  if (shook)
360  current->value = (*shook) (current->value);
361  if (ahook)
362  (void) (*ahook) (current->value);
363 }
364 
365 /*
366  * Convenience function to set a variable's value to "on".
367  */
368 bool
369 SetVariableBool(VariableSpace space, const char *name)
370 {
371  return SetVariable(space, name, "on");
372 }
373 
374 /*
375  * Attempt to delete variable.
376  *
377  * If unsuccessful, print a message and return "false".
378  * Deleting a nonexistent variable is not an error.
379  */
380 bool
381 DeleteVariable(VariableSpace space, const char *name)
382 {
383  return SetVariable(space, name, NULL);
384 }
385 
386 /*
387  * Emit error with suggestions for variables or commands
388  * accepting enum-style arguments.
389  * This function just exists to standardize the wording.
390  * suggestions should follow the format "fee, fi, fo, fum".
391  */
392 void
393 PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
394 {
395  pg_log_error("unrecognized value \"%s\" for \"%s\"\n"
396  "Available values are: %s.",
397  value, name, suggestions);
398 }
bool ParseVariableNum(const char *value, const char *name, int *result)
Definition: variables.c:158
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define pg_log_error(...)
Definition: logging.h:79
char *(* VariableSubstituteHook)(char *newval)
Definition: variables.h:54
void PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
Definition: variables.c:393
static struct @145 value
bool SetVariableBool(VariableSpace space, const char *name)
Definition: variables.c:369
#define printf(...)
Definition: port.h:198
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
void PrintVariables(VariableSpace space)
Definition: variables.c:188
bool(* VariableAssignHook)(const char *newval)
Definition: variables.h:31
volatile bool cancel_pressed
Definition: print.c:46
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
VariableSpace CreateVariableSpace(void)
Definition: variables.c:53
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1075
bool DeleteVariable(VariableSpace space, const char *name)
Definition: variables.c:381
VariableAssignHook assign_hook
Definition: variables.h:67
static bool valid_variable_name(const char *name)
Definition: variables.c:24
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
struct _variable * next
Definition: variables.h:68
const char * GetVariable(VariableSpace space, const char *name)
Definition: variables.c:73
void SetVariableHooks(VariableSpace space, const char *name, VariableSubstituteHook shook, VariableAssignHook ahook)
Definition: variables.c:317
#define free(a)
Definition: header.h:65
char * name
Definition: variables.h:64
bool SetVariable(VariableSpace space, const char *name, const char *value)
Definition: variables.c:213
VariableSubstituteHook substitute_hook
Definition: variables.h:66
void pg_free(void *ptr)
Definition: fe_memutils.c:105
const char * name
Definition: encode.c:521
bool ParseVariableBool(const char *value, const char *name, bool *result)
Definition: variables.c:109
char * value
Definition: variables.h:65
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742