Line data Source code
1 : /*
2 : * psql - the PostgreSQL interactive terminal
3 : *
4 : * Copyright (c) 2000-2017, 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 :
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
22 18068 : valid_variable_name(const char *name)
23 : {
24 18068 : const unsigned char *ptr = (const unsigned char *) name;
25 :
26 : /* Mustn't be zero-length */
27 18068 : if (*ptr == '\0')
28 0 : return false;
29 :
30 170287 : while (*ptr)
31 : {
32 268306 : if (IS_HIGHBIT_SET(*ptr) ||
33 134153 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
34 134153 : "_0123456789", *ptr) != NULL)
35 134151 : ptr++;
36 : else
37 2 : return false;
38 : }
39 :
40 18066 : 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 results of PrintVariables() more pleasing.
49 : */
50 : VariableSpace
51 185 : CreateVariableSpace(void)
52 : {
53 : struct _variable *ptr;
54 :
55 185 : ptr = pg_malloc(sizeof *ptr);
56 185 : ptr->name = NULL;
57 185 : ptr->value = NULL;
58 185 : ptr->substitute_hook = NULL;
59 185 : ptr->assign_hook = NULL;
60 185 : ptr->next = NULL;
61 :
62 185 : 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 106 : GetVariable(VariableSpace space, const char *name)
72 : {
73 : struct _variable *current;
74 :
75 106 : if (!space)
76 0 : return NULL;
77 :
78 1338 : for (current = space->next; current; current = current->next)
79 : {
80 1338 : int cmp = strcmp(current->name, name);
81 :
82 1338 : if (cmp == 0)
83 : {
84 : /* this is correct answer when value is NULL, too */
85 47 : return current->value;
86 : }
87 1291 : if (cmp > 0)
88 59 : break; /* it's not there */
89 : }
90 :
91 59 : 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 1706 : ParseVariableBool(const char *value, const char *name, bool *result)
108 : {
109 : size_t len;
110 1706 : bool valid = true;
111 :
112 : /* Treat "unset" as an empty string, which will lead to error below */
113 1706 : if (value == NULL)
114 0 : value = "";
115 :
116 1706 : len = strlen(value);
117 :
118 1706 : if (len > 0 && pg_strncasecmp(value, "true", len) == 0)
119 11 : *result = true;
120 1695 : else if (len > 0 && pg_strncasecmp(value, "false", len) == 0)
121 11 : *result = false;
122 1684 : else if (len > 0 && pg_strncasecmp(value, "yes", len) == 0)
123 1 : *result = true;
124 1683 : else if (len > 0 && pg_strncasecmp(value, "no", len) == 0)
125 1 : *result = false;
126 : /* 'o' is not unique enough */
127 1682 : else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
128 374 : *result = true;
129 1308 : else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
130 1303 : *result = false;
131 5 : else if (pg_strcasecmp(value, "1") == 0)
132 1 : *result = true;
133 4 : else if (pg_strcasecmp(value, "0") == 0)
134 1 : *result = false;
135 : else
136 : {
137 : /* string is not recognized; don't clobber *result */
138 3 : if (name)
139 2 : psql_error("unrecognized value \"%s\" for \"%s\": boolean expected\n",
140 : value, name);
141 3 : valid = false;
142 : }
143 1706 : 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 562 : 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 562 : if (value == NULL)
163 0 : value = "";
164 :
165 562 : errno = 0;
166 562 : numval = strtol(value, &end, 0);
167 562 : if (errno == 0 && *end == '\0' && end != value && numval == (int) numval)
168 : {
169 561 : *result = (int) numval;
170 561 : return true;
171 : }
172 : else
173 : {
174 : /* string is not recognized; don't clobber *result */
175 1 : if (name)
176 1 : psql_error("invalid value \"%s\" for \"%s\": integer expected\n",
177 : value, name);
178 1 : return false;
179 : }
180 : }
181 :
182 : /*
183 : * Print values of all variables.
184 : */
185 : void
186 0 : PrintVariables(VariableSpace space)
187 : {
188 : struct _variable *ptr;
189 :
190 0 : if (!space)
191 0 : return;
192 :
193 0 : for (ptr = space->next; ptr; ptr = ptr->next)
194 : {
195 0 : if (ptr->value)
196 0 : printf("%s = '%s'\n", ptr->name, ptr->value);
197 0 : if (cancel_pressed)
198 0 : 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 14553 : SetVariable(VariableSpace space, const char *name, const char *value)
212 : {
213 : struct _variable *current,
214 : *previous;
215 :
216 14553 : if (!space || !name)
217 0 : return false;
218 :
219 14553 : if (!valid_variable_name(name))
220 : {
221 : /* Deletion of non-existent variable is not an error */
222 2 : if (!value)
223 0 : return true;
224 2 : psql_error("invalid variable name: \"%s\"\n", name);
225 2 : return false;
226 : }
227 :
228 199897 : for (previous = space, current = space->next;
229 : current;
230 170795 : previous = current, current = current->next)
231 : {
232 185150 : int cmp = strcmp(current->name, name);
233 :
234 185150 : 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 13260 : char *new_value = value ? pg_strdup(value) : NULL;
246 : bool confirmed;
247 :
248 13260 : if (current->substitute_hook)
249 606 : new_value = (*current->substitute_hook) (new_value);
250 :
251 13260 : if (current->assign_hook)
252 1161 : confirmed = (*current->assign_hook) (new_value);
253 : else
254 12099 : confirmed = true;
255 :
256 13260 : if (confirmed)
257 : {
258 13257 : if (current->value)
259 12702 : pg_free(current->value);
260 13257 : current->value = new_value;
261 :
262 : /*
263 : * If we deleted the value, and there are no hooks to
264 : * remember, we can discard the variable altogether.
265 : */
266 13258 : if (new_value == NULL &&
267 2 : current->substitute_hook == NULL &&
268 1 : current->assign_hook == NULL)
269 : {
270 1 : previous->next = current->next;
271 1 : free(current->name);
272 1 : free(current);
273 : }
274 : }
275 3 : else if (new_value)
276 3 : pg_free(new_value); /* current->value is left unchanged */
277 :
278 13260 : return confirmed;
279 : }
280 171890 : if (cmp > 0)
281 1095 : break; /* it's not there */
282 : }
283 :
284 : /* not present, make new entry ... unless we were asked to delete */
285 1291 : if (value)
286 : {
287 1291 : current = pg_malloc(sizeof *current);
288 1291 : current->name = pg_strdup(name);
289 1291 : current->value = pg_strdup(value);
290 1291 : current->substitute_hook = NULL;
291 1291 : current->assign_hook = NULL;
292 1291 : current->next = previous->next;
293 1291 : previous->next = current;
294 : }
295 1291 : return true;
296 : }
297 :
298 : /*
299 : * Attach substitute and/or assign hook functions to the named variable.
300 : * If you need only one hook, pass NULL for the other.
301 : *
302 : * If the variable doesn't already exist, create it with value NULL, just so
303 : * we have a place to store the hook function(s). (The substitute hook might
304 : * immediately change the NULL to something else; if not, this state is
305 : * externally the same as the variable not being defined.)
306 : *
307 : * The substitute hook, if given, is immediately called on the variable's
308 : * value. Then the assign hook, if given, is called on the variable's value.
309 : * This is meant to let it update any derived psql state. If the assign hook
310 : * doesn't like the current value, it will print a message to that effect,
311 : * but we'll ignore it. Generally we do not expect any such failure here,
312 : * because this should get called before any user-supplied value is assigned.
313 : */
314 : void
315 3515 : SetVariableHooks(VariableSpace space, const char *name,
316 : VariableSubstituteHook shook,
317 : VariableAssignHook ahook)
318 : {
319 : struct _variable *current,
320 : *previous;
321 :
322 3515 : if (!space || !name)
323 0 : return;
324 :
325 3515 : if (!valid_variable_name(name))
326 0 : return;
327 :
328 26270 : for (previous = space, current = space->next;
329 : current;
330 19240 : previous = current, current = current->next)
331 : {
332 21645 : int cmp = strcmp(current->name, name);
333 :
334 21645 : if (cmp == 0)
335 : {
336 : /* found entry, so update */
337 0 : current->substitute_hook = shook;
338 0 : current->assign_hook = ahook;
339 0 : if (shook)
340 0 : current->value = (*shook) (current->value);
341 0 : if (ahook)
342 0 : (void) (*ahook) (current->value);
343 0 : return;
344 : }
345 21645 : if (cmp > 0)
346 2405 : break; /* it's not there */
347 : }
348 :
349 : /* not present, make new entry */
350 3515 : current = pg_malloc(sizeof *current);
351 3515 : current->name = pg_strdup(name);
352 3515 : current->value = NULL;
353 3515 : current->substitute_hook = shook;
354 3515 : current->assign_hook = ahook;
355 3515 : current->next = previous->next;
356 3515 : previous->next = current;
357 3515 : if (shook)
358 2775 : current->value = (*shook) (current->value);
359 3515 : if (ahook)
360 3515 : (void) (*ahook) (current->value);
361 : }
362 :
363 : /*
364 : * Convenience function to set a variable's value to "on".
365 : */
366 : bool
367 365 : SetVariableBool(VariableSpace space, const char *name)
368 : {
369 365 : return SetVariable(space, name, "on");
370 : }
371 :
372 : /*
373 : * Attempt to delete variable.
374 : *
375 : * If unsuccessful, print a message and return "false".
376 : * Deleting a nonexistent variable is not an error.
377 : */
378 : bool
379 0 : DeleteVariable(VariableSpace space, const char *name)
380 : {
381 0 : return SetVariable(space, name, NULL);
382 : }
383 :
384 : /*
385 : * Emit error with suggestions for variables or commands
386 : * accepting enum-style arguments.
387 : * This function just exists to standardize the wording.
388 : * suggestions should follow the format "fee, fi, fo, fum".
389 : */
390 : void
391 1 : PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
392 : {
393 1 : psql_error("unrecognized value \"%s\" for \"%s\"\nAvailable values are: %s.\n",
394 : value, name, suggestions);
395 1 : }
|