Line data Source code
1 : /*
2 : * psql - the PostgreSQL interactive terminal
3 : *
4 : * Copyright (c) 2000-2025, PostgreSQL Global Development Group
5 : *
6 : * src/bin/psql/command.c
7 : */
8 : #include "postgres_fe.h"
9 :
10 : #include <ctype.h>
11 : #include <time.h>
12 : #include <pwd.h>
13 : #include <utime.h>
14 : #ifndef WIN32
15 : #include <sys/stat.h> /* for stat() */
16 : #include <sys/time.h> /* for setitimer() */
17 : #include <fcntl.h> /* open() flags */
18 : #include <unistd.h> /* for geteuid(), getpid(), stat() */
19 : #else
20 : #include <win32.h>
21 : #include <io.h>
22 : #include <fcntl.h>
23 : #include <direct.h>
24 : #include <sys/stat.h> /* for stat() */
25 : #endif
26 :
27 : #include "catalog/pg_class_d.h"
28 : #include "command.h"
29 : #include "common.h"
30 : #include "common/logging.h"
31 : #include "common/string.h"
32 : #include "copy.h"
33 : #include "describe.h"
34 : #include "fe_utils/cancel.h"
35 : #include "fe_utils/print.h"
36 : #include "fe_utils/string_utils.h"
37 : #include "help.h"
38 : #include "input.h"
39 : #include "large_obj.h"
40 : #include "libpq/pqcomm.h"
41 : #include "mainloop.h"
42 : #include "pqexpbuffer.h"
43 : #include "psqlscanslash.h"
44 : #include "settings.h"
45 : #include "variables.h"
46 :
47 : /*
48 : * Editable database object types.
49 : */
50 : typedef enum EditableObjectType
51 : {
52 : EditableFunction,
53 : EditableView,
54 : } EditableObjectType;
55 :
56 : /* local function declarations */
57 : static backslashResult exec_command(const char *cmd,
58 : PsqlScanState scan_state,
59 : ConditionalStack cstack,
60 : PQExpBuffer query_buf,
61 : PQExpBuffer previous_buf);
62 : static backslashResult exec_command_a(PsqlScanState scan_state, bool active_branch);
63 : static backslashResult exec_command_bind(PsqlScanState scan_state, bool active_branch);
64 : static backslashResult exec_command_bind_named(PsqlScanState scan_state, bool active_branch,
65 : const char *cmd);
66 : static backslashResult exec_command_C(PsqlScanState scan_state, bool active_branch);
67 : static backslashResult exec_command_connect(PsqlScanState scan_state, bool active_branch);
68 : static backslashResult exec_command_cd(PsqlScanState scan_state, bool active_branch,
69 : const char *cmd);
70 : static backslashResult exec_command_close(PsqlScanState scan_state, bool active_branch,
71 : const char *cmd);
72 : static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch);
73 : static backslashResult exec_command_copy(PsqlScanState scan_state, bool active_branch);
74 : static backslashResult exec_command_copyright(PsqlScanState scan_state, bool active_branch);
75 : static backslashResult exec_command_crosstabview(PsqlScanState scan_state, bool active_branch);
76 : static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch,
77 : const char *cmd);
78 : static bool exec_command_dfo(PsqlScanState scan_state, const char *cmd,
79 : const char *pattern,
80 : bool show_verbose, bool show_system);
81 : static backslashResult exec_command_edit(PsqlScanState scan_state, bool active_branch,
82 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
83 : static backslashResult exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
84 : PQExpBuffer query_buf, bool is_func);
85 : static backslashResult exec_command_echo(PsqlScanState scan_state, bool active_branch,
86 : const char *cmd);
87 : static backslashResult exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
88 : PQExpBuffer query_buf);
89 : static backslashResult exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
90 : PQExpBuffer query_buf);
91 : static backslashResult exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
92 : PQExpBuffer query_buf);
93 : static backslashResult exec_command_encoding(PsqlScanState scan_state, bool active_branch);
94 : static backslashResult exec_command_errverbose(PsqlScanState scan_state, bool active_branch);
95 : static backslashResult exec_command_f(PsqlScanState scan_state, bool active_branch);
96 : static backslashResult exec_command_g(PsqlScanState scan_state, bool active_branch,
97 : const char *cmd);
98 : static backslashResult process_command_g_options(char *first_option,
99 : PsqlScanState scan_state,
100 : bool active_branch,
101 : const char *cmd);
102 : static backslashResult exec_command_gdesc(PsqlScanState scan_state, bool active_branch);
103 : static backslashResult exec_command_getenv(PsqlScanState scan_state, bool active_branch,
104 : const char *cmd);
105 : static backslashResult exec_command_gexec(PsqlScanState scan_state, bool active_branch);
106 : static backslashResult exec_command_gset(PsqlScanState scan_state, bool active_branch);
107 : static backslashResult exec_command_help(PsqlScanState scan_state, bool active_branch);
108 : static backslashResult exec_command_html(PsqlScanState scan_state, bool active_branch);
109 : static backslashResult exec_command_include(PsqlScanState scan_state, bool active_branch,
110 : const char *cmd);
111 : static backslashResult exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
112 : PQExpBuffer query_buf);
113 : static backslashResult exec_command_list(PsqlScanState scan_state, bool active_branch,
114 : const char *cmd);
115 : static backslashResult exec_command_lo(PsqlScanState scan_state, bool active_branch,
116 : const char *cmd);
117 : static backslashResult exec_command_out(PsqlScanState scan_state, bool active_branch);
118 : static backslashResult exec_command_print(PsqlScanState scan_state, bool active_branch,
119 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
120 : static backslashResult exec_command_parse(PsqlScanState scan_state, bool active_branch,
121 : const char *cmd);
122 : static backslashResult exec_command_password(PsqlScanState scan_state, bool active_branch);
123 : static backslashResult exec_command_prompt(PsqlScanState scan_state, bool active_branch,
124 : const char *cmd);
125 : static backslashResult exec_command_pset(PsqlScanState scan_state, bool active_branch);
126 : static backslashResult exec_command_quit(PsqlScanState scan_state, bool active_branch);
127 : static backslashResult exec_command_reset(PsqlScanState scan_state, bool active_branch,
128 : PQExpBuffer query_buf);
129 : static backslashResult exec_command_s(PsqlScanState scan_state, bool active_branch);
130 : static backslashResult exec_command_set(PsqlScanState scan_state, bool active_branch);
131 : static backslashResult exec_command_setenv(PsqlScanState scan_state, bool active_branch,
132 : const char *cmd);
133 : static backslashResult exec_command_sf_sv(PsqlScanState scan_state, bool active_branch,
134 : const char *cmd, bool is_func);
135 : static backslashResult exec_command_t(PsqlScanState scan_state, bool active_branch);
136 : static backslashResult exec_command_T(PsqlScanState scan_state, bool active_branch);
137 : static backslashResult exec_command_timing(PsqlScanState scan_state, bool active_branch);
138 : static backslashResult exec_command_unset(PsqlScanState scan_state, bool active_branch,
139 : const char *cmd);
140 : static backslashResult exec_command_write(PsqlScanState scan_state, bool active_branch,
141 : const char *cmd,
142 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
143 : static backslashResult exec_command_watch(PsqlScanState scan_state, bool active_branch,
144 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
145 : static backslashResult exec_command_x(PsqlScanState scan_state, bool active_branch);
146 : static backslashResult exec_command_z(PsqlScanState scan_state, bool active_branch,
147 : const char *cmd);
148 : static backslashResult exec_command_shell_escape(PsqlScanState scan_state, bool active_branch);
149 : static backslashResult exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch);
150 : static char *read_connect_arg(PsqlScanState scan_state);
151 : static PQExpBuffer gather_boolean_expression(PsqlScanState scan_state);
152 : static bool is_true_boolean_expression(PsqlScanState scan_state, const char *name);
153 : static void ignore_boolean_expression(PsqlScanState scan_state);
154 : static void ignore_slash_options(PsqlScanState scan_state);
155 : static void ignore_slash_filepipe(PsqlScanState scan_state);
156 : static void ignore_slash_whole_line(PsqlScanState scan_state);
157 : static bool is_branching_command(const char *cmd);
158 : static void save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
159 : PQExpBuffer query_buf);
160 : static void discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
161 : PQExpBuffer query_buf);
162 : static bool copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf);
163 : static bool do_connect(enum trivalue reuse_previous_specification,
164 : char *dbname, char *user, char *host, char *port);
165 : static void wait_until_connected(PGconn *conn);
166 : static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
167 : int lineno, bool discard_on_quit, bool *edited);
168 : static bool do_shell(const char *command);
169 : static bool do_watch(PQExpBuffer query_buf, double sleep, int iter, int min_rows);
170 : static bool lookup_object_oid(EditableObjectType obj_type, const char *desc,
171 : Oid *obj_oid);
172 : static bool get_create_object_cmd(EditableObjectType obj_type, Oid oid,
173 : PQExpBuffer buf);
174 : static int strip_lineno_from_objdesc(char *obj);
175 : static int count_lines_in_buf(PQExpBuffer buf);
176 : static void print_with_linenumbers(FILE *output, char *lines, bool is_func);
177 : static void minimal_error_message(PGresult *res);
178 :
179 : static void printSSLInfo(void);
180 : static void printGSSInfo(void);
181 : static bool printPsetInfo(const char *param, printQueryOpt *popt);
182 : static char *pset_value_string(const char *param, printQueryOpt *popt);
183 :
184 : #ifdef WIN32
185 : static void checkWin32Codepage(void);
186 : #endif
187 :
188 :
189 :
190 : /*----------
191 : * HandleSlashCmds:
192 : *
193 : * Handles all the different commands that start with '\'.
194 : * Ordinarily called by MainLoop().
195 : *
196 : * scan_state is a lexer working state that is set to continue scanning
197 : * just after the '\'. The lexer is advanced past the command and all
198 : * arguments on return.
199 : *
200 : * cstack is the current \if stack state. This will be examined, and
201 : * possibly modified by conditional commands.
202 : *
203 : * query_buf contains the query-so-far, which may be modified by
204 : * execution of the backslash command (for example, \r clears it).
205 : *
206 : * previous_buf contains the query most recently sent to the server
207 : * (empty if none yet). This should not be modified here, but some
208 : * commands copy its content into query_buf.
209 : *
210 : * query_buf and previous_buf will be NULL when executing a "-c"
211 : * command-line option.
212 : *
213 : * Returns a status code indicating what action is desired, see command.h.
214 : *----------
215 : */
216 :
217 : backslashResult
218 14018 : HandleSlashCmds(PsqlScanState scan_state,
219 : ConditionalStack cstack,
220 : PQExpBuffer query_buf,
221 : PQExpBuffer previous_buf)
222 : {
223 : backslashResult status;
224 : char *cmd;
225 : char *arg;
226 :
227 : Assert(scan_state != NULL);
228 : Assert(cstack != NULL);
229 :
230 : /* Parse off the command name */
231 14018 : cmd = psql_scan_slash_command(scan_state);
232 :
233 : /* And try to execute it */
234 14018 : status = exec_command(cmd, scan_state, cstack, query_buf, previous_buf);
235 :
236 14016 : if (status == PSQL_CMD_UNKNOWN)
237 : {
238 18 : pg_log_error("invalid command \\%s", cmd);
239 18 : if (pset.cur_cmd_interactive)
240 0 : pg_log_error_hint("Try \\? for help.");
241 18 : status = PSQL_CMD_ERROR;
242 : }
243 :
244 14016 : if (status != PSQL_CMD_ERROR)
245 : {
246 : /*
247 : * Eat any remaining arguments after a valid command. We want to
248 : * suppress evaluation of backticks in this situation, so transiently
249 : * push an inactive conditional-stack entry.
250 : */
251 12932 : bool active_branch = conditional_active(cstack);
252 :
253 12932 : conditional_stack_push(cstack, IFSTATE_IGNORED);
254 12962 : while ((arg = psql_scan_slash_option(scan_state,
255 : OT_NORMAL, NULL, false)))
256 : {
257 30 : if (active_branch)
258 30 : pg_log_warning("\\%s: extra argument \"%s\" ignored", cmd, arg);
259 30 : free(arg);
260 : }
261 12932 : conditional_stack_pop(cstack);
262 : }
263 : else
264 : {
265 : /* silently throw away rest of line after an erroneous command */
266 1090 : while ((arg = psql_scan_slash_option(scan_state,
267 : OT_WHOLE_LINE, NULL, false)))
268 6 : free(arg);
269 : }
270 :
271 : /* if there is a trailing \\, swallow it */
272 14016 : psql_scan_slash_command_end(scan_state);
273 :
274 14016 : free(cmd);
275 :
276 : /* some commands write to queryFout, so make sure output is sent */
277 14016 : fflush(pset.queryFout);
278 :
279 14016 : return status;
280 : }
281 :
282 :
283 : /*
284 : * Subroutine to actually try to execute a backslash command.
285 : *
286 : * The typical "success" result code is PSQL_CMD_SKIP_LINE, although some
287 : * commands return something else. Failure result code is PSQL_CMD_ERROR,
288 : * unless PSQL_CMD_UNKNOWN is more appropriate.
289 : */
290 : static backslashResult
291 14018 : exec_command(const char *cmd,
292 : PsqlScanState scan_state,
293 : ConditionalStack cstack,
294 : PQExpBuffer query_buf,
295 : PQExpBuffer previous_buf)
296 : {
297 : backslashResult status;
298 14018 : bool active_branch = conditional_active(cstack);
299 :
300 : /*
301 : * In interactive mode, warn when we're ignoring a command within a false
302 : * \if-branch. But we continue on, so as to parse and discard the right
303 : * amount of parameter text. Each individual backslash command subroutine
304 : * is responsible for doing nothing after discarding appropriate
305 : * arguments, if !active_branch.
306 : */
307 14018 : if (pset.cur_cmd_interactive && !active_branch &&
308 0 : !is_branching_command(cmd))
309 : {
310 0 : pg_log_warning("\\%s command ignored; use \\endif or Ctrl-C to exit current \\if block",
311 : cmd);
312 : }
313 :
314 14018 : if (strcmp(cmd, "a") == 0)
315 42 : status = exec_command_a(scan_state, active_branch);
316 13976 : else if (strcmp(cmd, "bind") == 0)
317 70 : status = exec_command_bind(scan_state, active_branch);
318 13906 : else if (strcmp(cmd, "bind_named") == 0)
319 96 : status = exec_command_bind_named(scan_state, active_branch, cmd);
320 13810 : else if (strcmp(cmd, "C") == 0)
321 6 : status = exec_command_C(scan_state, active_branch);
322 13804 : else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
323 330 : status = exec_command_connect(scan_state, active_branch);
324 13474 : else if (strcmp(cmd, "cd") == 0)
325 6 : status = exec_command_cd(scan_state, active_branch, cmd);
326 13468 : else if (strcmp(cmd, "close") == 0)
327 30 : status = exec_command_close(scan_state, active_branch, cmd);
328 13438 : else if (strcmp(cmd, "conninfo") == 0)
329 6 : status = exec_command_conninfo(scan_state, active_branch);
330 13432 : else if (pg_strcasecmp(cmd, "copy") == 0)
331 168 : status = exec_command_copy(scan_state, active_branch);
332 13264 : else if (strcmp(cmd, "copyright") == 0)
333 8 : status = exec_command_copyright(scan_state, active_branch);
334 13256 : else if (strcmp(cmd, "crosstabview") == 0)
335 138 : status = exec_command_crosstabview(scan_state, active_branch);
336 13118 : else if (cmd[0] == 'd')
337 6548 : status = exec_command_d(scan_state, active_branch, cmd);
338 6570 : else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
339 6 : status = exec_command_edit(scan_state, active_branch,
340 : query_buf, previous_buf);
341 6564 : else if (strcmp(cmd, "ef") == 0)
342 6 : status = exec_command_ef_ev(scan_state, active_branch, query_buf, true);
343 6558 : else if (strcmp(cmd, "ev") == 0)
344 6 : status = exec_command_ef_ev(scan_state, active_branch, query_buf, false);
345 6552 : else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0 ||
346 5694 : strcmp(cmd, "warn") == 0)
347 870 : status = exec_command_echo(scan_state, active_branch, cmd);
348 5682 : else if (strcmp(cmd, "elif") == 0)
349 48 : status = exec_command_elif(scan_state, cstack, query_buf);
350 5634 : else if (strcmp(cmd, "else") == 0)
351 132 : status = exec_command_else(scan_state, cstack, query_buf);
352 5502 : else if (strcmp(cmd, "endif") == 0)
353 180 : status = exec_command_endif(scan_state, cstack, query_buf);
354 5322 : else if (strcmp(cmd, "encoding") == 0)
355 6 : status = exec_command_encoding(scan_state, active_branch);
356 5316 : else if (strcmp(cmd, "errverbose") == 0)
357 14 : status = exec_command_errverbose(scan_state, active_branch);
358 5302 : else if (strcmp(cmd, "f") == 0)
359 6 : status = exec_command_f(scan_state, active_branch);
360 5296 : else if (strcmp(cmd, "g") == 0 || strcmp(cmd, "gx") == 0)
361 294 : status = exec_command_g(scan_state, active_branch, cmd);
362 5002 : else if (strcmp(cmd, "gdesc") == 0)
363 68 : status = exec_command_gdesc(scan_state, active_branch);
364 4934 : else if (strcmp(cmd, "getenv") == 0)
365 286 : status = exec_command_getenv(scan_state, active_branch, cmd);
366 4648 : else if (strcmp(cmd, "gexec") == 0)
367 52 : status = exec_command_gexec(scan_state, active_branch);
368 4596 : else if (strcmp(cmd, "gset") == 0)
369 732 : status = exec_command_gset(scan_state, active_branch);
370 3864 : else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
371 10 : status = exec_command_help(scan_state, active_branch);
372 3854 : else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
373 6 : status = exec_command_html(scan_state, active_branch);
374 3848 : else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0 ||
375 3842 : strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
376 12 : status = exec_command_include(scan_state, active_branch, cmd);
377 3836 : else if (strcmp(cmd, "if") == 0)
378 186 : status = exec_command_if(scan_state, cstack, query_buf);
379 3650 : else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
380 3644 : strcmp(cmd, "lx") == 0 || strcmp(cmd, "listx") == 0 ||
381 3644 : strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0 ||
382 3644 : strcmp(cmd, "lx+") == 0 || strcmp(cmd, "listx+") == 0 ||
383 3644 : strcmp(cmd, "l+x") == 0 || strcmp(cmd, "list+x") == 0)
384 6 : status = exec_command_list(scan_state, active_branch, cmd);
385 3644 : else if (strncmp(cmd, "lo_", 3) == 0)
386 62 : status = exec_command_lo(scan_state, active_branch, cmd);
387 3582 : else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
388 42 : status = exec_command_out(scan_state, active_branch);
389 3540 : else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
390 42 : status = exec_command_print(scan_state, active_branch,
391 : query_buf, previous_buf);
392 3498 : else if (strcmp(cmd, "parse") == 0)
393 42 : status = exec_command_parse(scan_state, active_branch, cmd);
394 3456 : else if (strcmp(cmd, "password") == 0)
395 8 : status = exec_command_password(scan_state, active_branch);
396 3448 : else if (strcmp(cmd, "prompt") == 0)
397 6 : status = exec_command_prompt(scan_state, active_branch, cmd);
398 3442 : else if (strcmp(cmd, "pset") == 0)
399 1740 : status = exec_command_pset(scan_state, active_branch);
400 1702 : else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
401 158 : status = exec_command_quit(scan_state, active_branch);
402 1544 : else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
403 84 : status = exec_command_reset(scan_state, active_branch, query_buf);
404 1460 : else if (strcmp(cmd, "s") == 0)
405 6 : status = exec_command_s(scan_state, active_branch);
406 1454 : else if (strcmp(cmd, "set") == 0)
407 938 : status = exec_command_set(scan_state, active_branch);
408 516 : else if (strcmp(cmd, "setenv") == 0)
409 18 : status = exec_command_setenv(scan_state, active_branch, cmd);
410 498 : else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
411 66 : status = exec_command_sf_sv(scan_state, active_branch, cmd, true);
412 432 : else if (strcmp(cmd, "sv") == 0 || strcmp(cmd, "sv+") == 0)
413 132 : status = exec_command_sf_sv(scan_state, active_branch, cmd, false);
414 300 : else if (strcmp(cmd, "t") == 0)
415 70 : status = exec_command_t(scan_state, active_branch);
416 230 : else if (strcmp(cmd, "T") == 0)
417 6 : status = exec_command_T(scan_state, active_branch);
418 224 : else if (strcmp(cmd, "timing") == 0)
419 10 : status = exec_command_timing(scan_state, active_branch);
420 214 : else if (strcmp(cmd, "unset") == 0)
421 38 : status = exec_command_unset(scan_state, active_branch, cmd);
422 176 : else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
423 12 : status = exec_command_write(scan_state, active_branch, cmd,
424 : query_buf, previous_buf);
425 164 : else if (strcmp(cmd, "watch") == 0)
426 28 : status = exec_command_watch(scan_state, active_branch,
427 : query_buf, previous_buf);
428 136 : else if (strcmp(cmd, "x") == 0)
429 76 : status = exec_command_x(scan_state, active_branch);
430 60 : else if (strcmp(cmd, "z") == 0 ||
431 36 : strcmp(cmd, "zS") == 0 || strcmp(cmd, "zx") == 0 ||
432 30 : strcmp(cmd, "zSx") == 0 || strcmp(cmd, "zxS") == 0)
433 30 : status = exec_command_z(scan_state, active_branch, cmd);
434 30 : else if (strcmp(cmd, "!") == 0)
435 6 : status = exec_command_shell_escape(scan_state, active_branch);
436 24 : else if (strcmp(cmd, "?") == 0)
437 6 : status = exec_command_slash_command_help(scan_state, active_branch);
438 : else
439 18 : status = PSQL_CMD_UNKNOWN;
440 :
441 : /*
442 : * All the commands that return PSQL_CMD_SEND want to execute previous_buf
443 : * if query_buf is empty. For convenience we implement that here, not in
444 : * the individual command subroutines.
445 : */
446 14016 : if (status == PSQL_CMD_SEND)
447 1290 : (void) copy_previous_query(query_buf, previous_buf);
448 :
449 14016 : return status;
450 : }
451 :
452 :
453 : /*
454 : * \a -- toggle field alignment
455 : *
456 : * This makes little sense but we keep it around.
457 : */
458 : static backslashResult
459 42 : exec_command_a(PsqlScanState scan_state, bool active_branch)
460 : {
461 42 : bool success = true;
462 :
463 42 : if (active_branch)
464 : {
465 36 : if (pset.popt.topt.format != PRINT_ALIGNED)
466 18 : success = do_pset("format", "aligned", &pset.popt, pset.quiet);
467 : else
468 18 : success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
469 : }
470 :
471 42 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
472 : }
473 :
474 : /*
475 : * \bind -- set query parameters
476 : */
477 : static backslashResult
478 70 : exec_command_bind(PsqlScanState scan_state, bool active_branch)
479 : {
480 70 : backslashResult status = PSQL_CMD_SKIP_LINE;
481 :
482 70 : if (active_branch)
483 : {
484 : char *opt;
485 64 : int nparams = 0;
486 64 : int nalloc = 0;
487 :
488 64 : clean_extended_state();
489 :
490 114 : while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false)))
491 : {
492 50 : nparams++;
493 50 : if (nparams > nalloc)
494 : {
495 50 : nalloc = nalloc ? nalloc * 2 : 1;
496 50 : pset.bind_params = pg_realloc_array(pset.bind_params, char *, nalloc);
497 : }
498 50 : pset.bind_params[nparams - 1] = opt;
499 : }
500 :
501 64 : pset.bind_nparams = nparams;
502 64 : pset.send_mode = PSQL_SEND_EXTENDED_QUERY_PARAMS;
503 : }
504 : else
505 6 : ignore_slash_options(scan_state);
506 :
507 70 : return status;
508 : }
509 :
510 : /*
511 : * \bind_named -- set query parameters for an existing prepared statement
512 : */
513 : static backslashResult
514 96 : exec_command_bind_named(PsqlScanState scan_state, bool active_branch,
515 : const char *cmd)
516 : {
517 96 : backslashResult status = PSQL_CMD_SKIP_LINE;
518 :
519 96 : if (active_branch)
520 : {
521 : char *opt;
522 90 : int nparams = 0;
523 90 : int nalloc = 0;
524 :
525 90 : clean_extended_state();
526 :
527 : /* get the mandatory prepared statement name */
528 90 : opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
529 90 : if (!opt)
530 : {
531 12 : pg_log_error("\\%s: missing required argument", cmd);
532 12 : status = PSQL_CMD_ERROR;
533 : }
534 : else
535 : {
536 78 : pset.stmtName = opt;
537 78 : pset.send_mode = PSQL_SEND_EXTENDED_QUERY_PREPARED;
538 :
539 : /* set of parameters */
540 168 : while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false)))
541 : {
542 90 : nparams++;
543 90 : if (nparams > nalloc)
544 : {
545 90 : nalloc = nalloc ? nalloc * 2 : 1;
546 90 : pset.bind_params = pg_realloc_array(pset.bind_params, char *, nalloc);
547 : }
548 90 : pset.bind_params[nparams - 1] = opt;
549 : }
550 78 : pset.bind_nparams = nparams;
551 : }
552 : }
553 : else
554 6 : ignore_slash_options(scan_state);
555 :
556 96 : return status;
557 : }
558 :
559 : /*
560 : * \C -- override table title (formerly change HTML caption)
561 : */
562 : static backslashResult
563 6 : exec_command_C(PsqlScanState scan_state, bool active_branch)
564 : {
565 6 : bool success = true;
566 :
567 6 : if (active_branch)
568 : {
569 0 : char *opt = psql_scan_slash_option(scan_state,
570 : OT_NORMAL, NULL, true);
571 :
572 0 : success = do_pset("title", opt, &pset.popt, pset.quiet);
573 0 : free(opt);
574 : }
575 : else
576 6 : ignore_slash_options(scan_state);
577 :
578 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
579 : }
580 :
581 : /*
582 : * \c or \connect -- connect to database using the specified parameters.
583 : *
584 : * \c [-reuse-previous=BOOL] dbname user host port
585 : *
586 : * Specifying a parameter as '-' is equivalent to omitting it. Examples:
587 : *
588 : * \c - - hst Connect to current database on current port of
589 : * host "hst" as current user.
590 : * \c - usr - prt Connect to current database on port "prt" of current host
591 : * as user "usr".
592 : * \c dbs Connect to database "dbs" on current port of current host
593 : * as current user.
594 : */
595 : static backslashResult
596 330 : exec_command_connect(PsqlScanState scan_state, bool active_branch)
597 : {
598 330 : bool success = true;
599 :
600 330 : if (active_branch)
601 : {
602 : static const char prefix[] = "-reuse-previous=";
603 : char *opt1,
604 : *opt2,
605 : *opt3,
606 : *opt4;
607 324 : enum trivalue reuse_previous = TRI_DEFAULT;
608 :
609 324 : opt1 = read_connect_arg(scan_state);
610 324 : if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0)
611 : {
612 : bool on_off;
613 :
614 22 : success = ParseVariableBool(opt1 + sizeof(prefix) - 1,
615 : "-reuse-previous",
616 : &on_off);
617 22 : if (success)
618 : {
619 22 : reuse_previous = on_off ? TRI_YES : TRI_NO;
620 22 : free(opt1);
621 22 : opt1 = read_connect_arg(scan_state);
622 : }
623 : }
624 :
625 324 : if (success) /* give up if reuse_previous was invalid */
626 : {
627 324 : opt2 = read_connect_arg(scan_state);
628 324 : opt3 = read_connect_arg(scan_state);
629 324 : opt4 = read_connect_arg(scan_state);
630 :
631 324 : success = do_connect(reuse_previous, opt1, opt2, opt3, opt4);
632 :
633 324 : free(opt2);
634 324 : free(opt3);
635 324 : free(opt4);
636 : }
637 324 : free(opt1);
638 : }
639 : else
640 6 : ignore_slash_options(scan_state);
641 :
642 330 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
643 : }
644 :
645 : /*
646 : * \cd -- change directory
647 : */
648 : static backslashResult
649 6 : exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
650 : {
651 6 : bool success = true;
652 :
653 6 : if (active_branch)
654 : {
655 0 : char *opt = psql_scan_slash_option(scan_state,
656 : OT_NORMAL, NULL, true);
657 : char *dir;
658 :
659 0 : if (opt)
660 0 : dir = opt;
661 : else
662 : {
663 : #ifndef WIN32
664 : /* This should match get_home_path() */
665 0 : dir = getenv("HOME");
666 0 : if (dir == NULL || dir[0] == '\0')
667 : {
668 0 : uid_t user_id = geteuid();
669 : struct passwd *pw;
670 :
671 0 : errno = 0; /* clear errno before call */
672 0 : pw = getpwuid(user_id);
673 0 : if (pw)
674 0 : dir = pw->pw_dir;
675 : else
676 : {
677 0 : pg_log_error("could not get home directory for user ID %ld: %s",
678 : (long) user_id,
679 : errno ? strerror(errno) : _("user does not exist"));
680 0 : success = false;
681 : }
682 : }
683 : #else /* WIN32 */
684 :
685 : /*
686 : * On Windows, 'cd' without arguments prints the current
687 : * directory, so if someone wants to code this here instead...
688 : */
689 : dir = "/";
690 : #endif /* WIN32 */
691 : }
692 :
693 0 : if (success &&
694 0 : chdir(dir) < 0)
695 : {
696 0 : pg_log_error("\\%s: could not change directory to \"%s\": %m",
697 : cmd, dir);
698 0 : success = false;
699 : }
700 :
701 0 : free(opt);
702 : }
703 : else
704 6 : ignore_slash_options(scan_state);
705 :
706 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
707 : }
708 :
709 : /*
710 : * \close -- close a previously prepared statement
711 : */
712 : static backslashResult
713 30 : exec_command_close(PsqlScanState scan_state, bool active_branch, const char *cmd)
714 : {
715 30 : backslashResult status = PSQL_CMD_SKIP_LINE;
716 :
717 30 : if (active_branch)
718 : {
719 24 : char *opt = psql_scan_slash_option(scan_state,
720 : OT_NORMAL, NULL, false);
721 :
722 24 : clean_extended_state();
723 :
724 24 : if (!opt)
725 : {
726 6 : pg_log_error("\\%s: missing required argument", cmd);
727 6 : status = PSQL_CMD_ERROR;
728 : }
729 : else
730 : {
731 18 : pset.stmtName = opt;
732 18 : pset.send_mode = PSQL_SEND_EXTENDED_CLOSE;
733 18 : status = PSQL_CMD_SEND;
734 : }
735 : }
736 : else
737 6 : ignore_slash_options(scan_state);
738 :
739 30 : return status;
740 : }
741 :
742 : /*
743 : * \conninfo -- display information about the current connection
744 : */
745 : static backslashResult
746 6 : exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
747 : {
748 6 : if (active_branch)
749 : {
750 0 : char *db = PQdb(pset.db);
751 :
752 0 : if (db == NULL)
753 0 : printf(_("You are currently not connected to a database.\n"));
754 : else
755 : {
756 0 : char *host = PQhost(pset.db);
757 0 : char *hostaddr = PQhostaddr(pset.db);
758 :
759 0 : if (is_unixsock_path(host))
760 : {
761 : /* hostaddr overrides host */
762 0 : if (hostaddr && *hostaddr)
763 0 : printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
764 : db, PQuser(pset.db), hostaddr, PQport(pset.db));
765 : else
766 0 : printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
767 : db, PQuser(pset.db), host, PQport(pset.db));
768 : }
769 : else
770 : {
771 0 : if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
772 0 : printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
773 : db, PQuser(pset.db), host, hostaddr, PQport(pset.db));
774 : else
775 0 : printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
776 : db, PQuser(pset.db), host, PQport(pset.db));
777 : }
778 0 : printSSLInfo();
779 0 : printGSSInfo();
780 : }
781 : }
782 :
783 6 : return PSQL_CMD_SKIP_LINE;
784 : }
785 :
786 : /*
787 : * \copy -- run a COPY command
788 : */
789 : static backslashResult
790 168 : exec_command_copy(PsqlScanState scan_state, bool active_branch)
791 : {
792 168 : bool success = true;
793 :
794 168 : if (active_branch)
795 : {
796 162 : char *opt = psql_scan_slash_option(scan_state,
797 : OT_WHOLE_LINE, NULL, false);
798 :
799 162 : success = do_copy(opt);
800 162 : free(opt);
801 : }
802 : else
803 6 : ignore_slash_whole_line(scan_state);
804 :
805 168 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
806 : }
807 :
808 : /*
809 : * \copyright -- print copyright notice
810 : */
811 : static backslashResult
812 8 : exec_command_copyright(PsqlScanState scan_state, bool active_branch)
813 : {
814 8 : if (active_branch)
815 2 : print_copyright();
816 :
817 8 : return PSQL_CMD_SKIP_LINE;
818 : }
819 :
820 : /*
821 : * \crosstabview -- execute a query and display result in crosstab
822 : */
823 : static backslashResult
824 138 : exec_command_crosstabview(PsqlScanState scan_state, bool active_branch)
825 : {
826 138 : backslashResult status = PSQL_CMD_SKIP_LINE;
827 :
828 138 : if (active_branch)
829 : {
830 : int i;
831 :
832 660 : for (i = 0; i < lengthof(pset.ctv_args); i++)
833 528 : pset.ctv_args[i] = psql_scan_slash_option(scan_state,
834 : OT_NORMAL, NULL, true);
835 132 : pset.crosstab_flag = true;
836 132 : status = PSQL_CMD_SEND;
837 : }
838 : else
839 6 : ignore_slash_options(scan_state);
840 :
841 138 : return status;
842 : }
843 :
844 : /*
845 : * \d* commands
846 : */
847 : static backslashResult
848 6548 : exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
849 : {
850 6548 : backslashResult status = PSQL_CMD_SKIP_LINE;
851 6548 : bool success = true;
852 :
853 6548 : if (active_branch)
854 : {
855 : char *pattern;
856 : bool show_verbose,
857 : show_system;
858 : unsigned short int save_expanded;
859 :
860 : /* We don't do SQLID reduction on the pattern yet */
861 6542 : pattern = psql_scan_slash_option(scan_state,
862 : OT_NORMAL, NULL, true);
863 :
864 6542 : show_verbose = strchr(cmd, '+') ? true : false;
865 6542 : show_system = strchr(cmd, 'S') ? true : false;
866 :
867 : /*
868 : * The 'x' option turns expanded mode on for this command only. This
869 : * is allowed in all \d* commands, except \d by itself, since \dx is a
870 : * separate command. So the 'x' option cannot appear immediately after
871 : * \d, but it can appear after \d followed by other options.
872 : */
873 6542 : save_expanded = pset.popt.topt.expanded;
874 6542 : if (cmd[1] != '\0' && strchr(&cmd[2], 'x'))
875 24 : pset.popt.topt.expanded = 1;
876 :
877 6542 : switch (cmd[1])
878 : {
879 3758 : case '\0':
880 : case '+':
881 : case 'S':
882 3758 : if (pattern)
883 3740 : success = describeTableDetails(pattern, show_verbose, show_system);
884 : else
885 : /* standard listing of interesting things */
886 18 : success = listTables("tvmsE", NULL, show_verbose, show_system);
887 3758 : break;
888 222 : case 'A':
889 : {
890 222 : char *pattern2 = NULL;
891 :
892 222 : if (pattern && cmd[2] != '\0' && cmd[2] != '+' && cmd[2] != 'x')
893 144 : pattern2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true);
894 :
895 222 : switch (cmd[2])
896 : {
897 78 : case '\0':
898 : case '+':
899 : case 'x':
900 78 : success = describeAccessMethods(pattern, show_verbose);
901 78 : break;
902 30 : case 'c':
903 30 : success = listOperatorClasses(pattern, pattern2, show_verbose);
904 30 : break;
905 36 : case 'f':
906 36 : success = listOperatorFamilies(pattern, pattern2, show_verbose);
907 36 : break;
908 36 : case 'o':
909 36 : success = listOpFamilyOperators(pattern, pattern2, show_verbose);
910 36 : break;
911 42 : case 'p':
912 42 : success = listOpFamilyFunctions(pattern, pattern2, show_verbose);
913 42 : break;
914 0 : default:
915 0 : status = PSQL_CMD_UNKNOWN;
916 0 : break;
917 : }
918 :
919 222 : free(pattern2);
920 : }
921 222 : break;
922 48 : case 'a':
923 48 : success = describeAggregates(pattern, show_verbose, show_system);
924 48 : break;
925 24 : case 'b':
926 24 : success = describeTablespaces(pattern, show_verbose);
927 24 : break;
928 54 : case 'c':
929 54 : if (strncmp(cmd, "dconfig", 7) == 0)
930 12 : success = describeConfigurationParameters(pattern,
931 : show_verbose,
932 : show_system);
933 : else
934 42 : success = listConversions(pattern,
935 : show_verbose,
936 : show_system);
937 54 : break;
938 42 : case 'C':
939 42 : success = listCasts(pattern, show_verbose);
940 42 : break;
941 78 : case 'd':
942 78 : if (strncmp(cmd, "ddp", 3) == 0)
943 36 : success = listDefaultACLs(pattern);
944 : else
945 42 : success = objectDescription(pattern, show_system);
946 78 : break;
947 60 : case 'D':
948 60 : success = listDomains(pattern, show_verbose, show_system);
949 60 : break;
950 298 : case 'f': /* function subsystem */
951 298 : switch (cmd[2])
952 : {
953 298 : case '\0':
954 : case '+':
955 : case 'S':
956 : case 'a':
957 : case 'n':
958 : case 'p':
959 : case 't':
960 : case 'w':
961 : case 'x':
962 298 : success = exec_command_dfo(scan_state, cmd, pattern,
963 : show_verbose, show_system);
964 298 : break;
965 0 : default:
966 0 : status = PSQL_CMD_UNKNOWN;
967 0 : break;
968 : }
969 298 : break;
970 24 : case 'g':
971 : /* no longer distinct from \du */
972 24 : success = describeRoles(pattern, show_verbose, show_system);
973 24 : break;
974 6 : case 'l':
975 6 : success = listLargeObjects(show_verbose);
976 6 : break;
977 30 : case 'L':
978 30 : success = listLanguages(pattern, show_verbose, show_system);
979 30 : break;
980 24 : case 'n':
981 24 : success = listSchemas(pattern, show_verbose, show_system);
982 24 : break;
983 62 : case 'o':
984 62 : success = exec_command_dfo(scan_state, cmd, pattern,
985 : show_verbose, show_system);
986 62 : break;
987 42 : case 'O':
988 42 : success = listCollations(pattern, show_verbose, show_system);
989 42 : break;
990 72 : case 'p':
991 72 : success = permissionsList(pattern, show_system);
992 72 : break;
993 108 : case 'P':
994 : {
995 108 : switch (cmd[2])
996 : {
997 108 : case '\0':
998 : case '+':
999 : case 't':
1000 : case 'i':
1001 : case 'n':
1002 : case 'x':
1003 108 : success = listPartitionedTables(&cmd[2], pattern, show_verbose);
1004 108 : break;
1005 0 : default:
1006 0 : status = PSQL_CMD_UNKNOWN;
1007 0 : break;
1008 : }
1009 : }
1010 108 : break;
1011 68 : case 'T':
1012 68 : success = describeTypes(pattern, show_verbose, show_system);
1013 68 : break;
1014 294 : case 't':
1015 : case 'v':
1016 : case 'm':
1017 : case 'i':
1018 : case 's':
1019 : case 'E':
1020 294 : success = listTables(&cmd[1], pattern, show_verbose, show_system);
1021 294 : break;
1022 32 : case 'r':
1023 32 : if (cmd[2] == 'd' && cmd[3] == 's')
1024 26 : {
1025 26 : char *pattern2 = NULL;
1026 :
1027 26 : if (pattern)
1028 24 : pattern2 = psql_scan_slash_option(scan_state,
1029 : OT_NORMAL, NULL, true);
1030 26 : success = listDbRoleSettings(pattern, pattern2);
1031 :
1032 26 : free(pattern2);
1033 : }
1034 6 : else if (cmd[2] == 'g')
1035 6 : success = describeRoleGrants(pattern, show_system);
1036 : else
1037 0 : status = PSQL_CMD_UNKNOWN;
1038 32 : break;
1039 528 : case 'R':
1040 528 : switch (cmd[2])
1041 : {
1042 378 : case 'p':
1043 378 : if (show_verbose)
1044 330 : success = describePublications(pattern);
1045 : else
1046 48 : success = listPublications(pattern);
1047 378 : break;
1048 150 : case 's':
1049 150 : success = describeSubscriptions(pattern, show_verbose);
1050 150 : break;
1051 0 : default:
1052 0 : status = PSQL_CMD_UNKNOWN;
1053 : }
1054 528 : break;
1055 6 : case 'u':
1056 6 : success = describeRoles(pattern, show_verbose, show_system);
1057 6 : break;
1058 168 : case 'F': /* text search subsystem */
1059 168 : switch (cmd[2])
1060 : {
1061 42 : case '\0':
1062 : case '+':
1063 : case 'x':
1064 42 : success = listTSConfigs(pattern, show_verbose);
1065 42 : break;
1066 42 : case 'p':
1067 42 : success = listTSParsers(pattern, show_verbose);
1068 42 : break;
1069 42 : case 'd':
1070 42 : success = listTSDictionaries(pattern, show_verbose);
1071 42 : break;
1072 42 : case 't':
1073 42 : success = listTSTemplates(pattern, show_verbose);
1074 42 : break;
1075 0 : default:
1076 0 : status = PSQL_CMD_UNKNOWN;
1077 0 : break;
1078 : }
1079 168 : break;
1080 312 : case 'e': /* SQL/MED subsystem */
1081 312 : switch (cmd[2])
1082 : {
1083 120 : case 's':
1084 120 : success = listForeignServers(pattern, show_verbose);
1085 120 : break;
1086 60 : case 'u':
1087 60 : success = listUserMappings(pattern, show_verbose);
1088 60 : break;
1089 114 : case 'w':
1090 114 : success = listForeignDataWrappers(pattern, show_verbose);
1091 114 : break;
1092 18 : case 't':
1093 18 : success = listForeignTables(pattern, show_verbose);
1094 18 : break;
1095 0 : default:
1096 0 : status = PSQL_CMD_UNKNOWN;
1097 0 : break;
1098 : }
1099 312 : break;
1100 56 : case 'x': /* Extensions */
1101 56 : if (show_verbose)
1102 32 : success = listExtensionContents(pattern);
1103 : else
1104 24 : success = listExtensions(pattern);
1105 56 : break;
1106 102 : case 'X': /* Extended Statistics */
1107 102 : success = listExtendedStats(pattern);
1108 102 : break;
1109 24 : case 'y': /* Event Triggers */
1110 24 : success = listEventTriggers(pattern, show_verbose);
1111 24 : break;
1112 0 : default:
1113 0 : status = PSQL_CMD_UNKNOWN;
1114 : }
1115 :
1116 : /* Restore original expanded mode */
1117 6542 : pset.popt.topt.expanded = save_expanded;
1118 :
1119 6542 : free(pattern);
1120 : }
1121 : else
1122 6 : ignore_slash_options(scan_state);
1123 :
1124 6548 : if (!success)
1125 914 : status = PSQL_CMD_ERROR;
1126 :
1127 6548 : return status;
1128 : }
1129 :
1130 : /* \df and \do; messy enough to split out of exec_command_d */
1131 : static bool
1132 360 : exec_command_dfo(PsqlScanState scan_state, const char *cmd,
1133 : const char *pattern,
1134 : bool show_verbose, bool show_system)
1135 : {
1136 : bool success;
1137 : char *arg_patterns[FUNC_MAX_ARGS];
1138 360 : int num_arg_patterns = 0;
1139 :
1140 : /* Collect argument-type patterns too */
1141 360 : if (pattern) /* otherwise it was just \df or \do */
1142 : {
1143 : char *ap;
1144 :
1145 440 : while ((ap = psql_scan_slash_option(scan_state,
1146 : OT_NORMAL, NULL, true)) != NULL)
1147 : {
1148 84 : arg_patterns[num_arg_patterns++] = ap;
1149 84 : if (num_arg_patterns >= FUNC_MAX_ARGS)
1150 0 : break; /* protect limited-size array */
1151 : }
1152 : }
1153 :
1154 360 : if (cmd[1] == 'f')
1155 298 : success = describeFunctions(&cmd[2], pattern,
1156 : arg_patterns, num_arg_patterns,
1157 : show_verbose, show_system);
1158 : else
1159 62 : success = describeOperators(pattern,
1160 : arg_patterns, num_arg_patterns,
1161 : show_verbose, show_system);
1162 :
1163 444 : while (--num_arg_patterns >= 0)
1164 84 : free(arg_patterns[num_arg_patterns]);
1165 :
1166 360 : return success;
1167 : }
1168 :
1169 : /*
1170 : * \e or \edit -- edit the current query buffer, or edit a file and
1171 : * make it the query buffer
1172 : */
1173 : static backslashResult
1174 6 : exec_command_edit(PsqlScanState scan_state, bool active_branch,
1175 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
1176 : {
1177 6 : backslashResult status = PSQL_CMD_SKIP_LINE;
1178 :
1179 6 : if (active_branch)
1180 : {
1181 0 : if (!query_buf)
1182 : {
1183 0 : pg_log_error("no query buffer");
1184 0 : status = PSQL_CMD_ERROR;
1185 : }
1186 : else
1187 : {
1188 : char *fname;
1189 0 : char *ln = NULL;
1190 0 : int lineno = -1;
1191 :
1192 0 : fname = psql_scan_slash_option(scan_state,
1193 : OT_NORMAL, NULL, true);
1194 0 : if (fname)
1195 : {
1196 : /* try to get separate lineno arg */
1197 0 : ln = psql_scan_slash_option(scan_state,
1198 : OT_NORMAL, NULL, true);
1199 0 : if (ln == NULL)
1200 : {
1201 : /* only one arg; maybe it is lineno not fname */
1202 0 : if (fname[0] &&
1203 0 : strspn(fname, "0123456789") == strlen(fname))
1204 : {
1205 : /* all digits, so assume it is lineno */
1206 0 : ln = fname;
1207 0 : fname = NULL;
1208 : }
1209 : }
1210 : }
1211 0 : if (ln)
1212 : {
1213 0 : lineno = atoi(ln);
1214 0 : if (lineno < 1)
1215 : {
1216 0 : pg_log_error("invalid line number: %s", ln);
1217 0 : status = PSQL_CMD_ERROR;
1218 : }
1219 : }
1220 0 : if (status != PSQL_CMD_ERROR)
1221 : {
1222 : bool discard_on_quit;
1223 :
1224 0 : expand_tilde(&fname);
1225 0 : if (fname)
1226 : {
1227 0 : canonicalize_path(fname);
1228 : /* Always clear buffer if the file isn't modified */
1229 0 : discard_on_quit = true;
1230 : }
1231 : else
1232 : {
1233 : /*
1234 : * If query_buf is empty, recall previous query for
1235 : * editing. But in that case, the query buffer should be
1236 : * emptied if editing doesn't modify the file.
1237 : */
1238 0 : discard_on_quit = copy_previous_query(query_buf,
1239 : previous_buf);
1240 : }
1241 :
1242 0 : if (do_edit(fname, query_buf, lineno, discard_on_quit, NULL))
1243 0 : status = PSQL_CMD_NEWEDIT;
1244 : else
1245 0 : status = PSQL_CMD_ERROR;
1246 : }
1247 :
1248 : /*
1249 : * On error while editing or if specifying an incorrect line
1250 : * number, reset the query buffer.
1251 : */
1252 0 : if (status == PSQL_CMD_ERROR)
1253 0 : resetPQExpBuffer(query_buf);
1254 :
1255 0 : free(fname);
1256 0 : free(ln);
1257 : }
1258 : }
1259 : else
1260 6 : ignore_slash_options(scan_state);
1261 :
1262 6 : return status;
1263 : }
1264 :
1265 : /*
1266 : * \ef/\ev -- edit the named function/view, or
1267 : * present a blank CREATE FUNCTION/VIEW template if no argument is given
1268 : */
1269 : static backslashResult
1270 12 : exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
1271 : PQExpBuffer query_buf, bool is_func)
1272 : {
1273 12 : backslashResult status = PSQL_CMD_SKIP_LINE;
1274 :
1275 12 : if (active_branch)
1276 : {
1277 0 : char *obj_desc = psql_scan_slash_option(scan_state,
1278 : OT_WHOLE_LINE,
1279 : NULL, true);
1280 0 : int lineno = -1;
1281 :
1282 0 : if (!query_buf)
1283 : {
1284 0 : pg_log_error("no query buffer");
1285 0 : status = PSQL_CMD_ERROR;
1286 : }
1287 : else
1288 : {
1289 0 : Oid obj_oid = InvalidOid;
1290 0 : EditableObjectType eot = is_func ? EditableFunction : EditableView;
1291 :
1292 0 : lineno = strip_lineno_from_objdesc(obj_desc);
1293 0 : if (lineno == 0)
1294 : {
1295 : /* error already reported */
1296 0 : status = PSQL_CMD_ERROR;
1297 : }
1298 0 : else if (!obj_desc)
1299 : {
1300 : /* set up an empty command to fill in */
1301 0 : resetPQExpBuffer(query_buf);
1302 0 : if (is_func)
1303 0 : appendPQExpBufferStr(query_buf,
1304 : "CREATE FUNCTION ( )\n"
1305 : " RETURNS \n"
1306 : " LANGUAGE \n"
1307 : " -- common options: IMMUTABLE STABLE STRICT SECURITY DEFINER\n"
1308 : "AS $function$\n"
1309 : "\n$function$\n");
1310 : else
1311 0 : appendPQExpBufferStr(query_buf,
1312 : "CREATE VIEW AS\n"
1313 : " SELECT \n"
1314 : " -- something...\n");
1315 : }
1316 0 : else if (!lookup_object_oid(eot, obj_desc, &obj_oid))
1317 : {
1318 : /* error already reported */
1319 0 : status = PSQL_CMD_ERROR;
1320 : }
1321 0 : else if (!get_create_object_cmd(eot, obj_oid, query_buf))
1322 : {
1323 : /* error already reported */
1324 0 : status = PSQL_CMD_ERROR;
1325 : }
1326 0 : else if (is_func && lineno > 0)
1327 : {
1328 : /*
1329 : * lineno "1" should correspond to the first line of the
1330 : * function body. We expect that pg_get_functiondef() will
1331 : * emit that on a line beginning with "AS ", "BEGIN ", or
1332 : * "RETURN ", and that there can be no such line before the
1333 : * real start of the function body. Increment lineno by the
1334 : * number of lines before that line, so that it becomes
1335 : * relative to the first line of the function definition.
1336 : */
1337 0 : const char *lines = query_buf->data;
1338 :
1339 0 : while (*lines != '\0')
1340 : {
1341 0 : if (strncmp(lines, "AS ", 3) == 0 ||
1342 0 : strncmp(lines, "BEGIN ", 6) == 0 ||
1343 0 : strncmp(lines, "RETURN ", 7) == 0)
1344 : break;
1345 0 : lineno++;
1346 : /* find start of next line */
1347 0 : lines = strchr(lines, '\n');
1348 0 : if (!lines)
1349 0 : break;
1350 0 : lines++;
1351 : }
1352 : }
1353 : }
1354 :
1355 0 : if (status != PSQL_CMD_ERROR)
1356 : {
1357 0 : bool edited = false;
1358 :
1359 0 : if (!do_edit(NULL, query_buf, lineno, true, &edited))
1360 0 : status = PSQL_CMD_ERROR;
1361 0 : else if (!edited)
1362 0 : puts(_("No changes"));
1363 : else
1364 0 : status = PSQL_CMD_NEWEDIT;
1365 : }
1366 :
1367 : /*
1368 : * On error while doing object lookup or while editing, or if
1369 : * specifying an incorrect line number, reset the query buffer.
1370 : */
1371 0 : if (status == PSQL_CMD_ERROR)
1372 0 : resetPQExpBuffer(query_buf);
1373 :
1374 0 : free(obj_desc);
1375 : }
1376 : else
1377 12 : ignore_slash_whole_line(scan_state);
1378 :
1379 12 : return status;
1380 : }
1381 :
1382 : /*
1383 : * \echo, \qecho, and \warn -- echo arguments to stdout, query output, or stderr
1384 : */
1385 : static backslashResult
1386 870 : exec_command_echo(PsqlScanState scan_state, bool active_branch, const char *cmd)
1387 : {
1388 870 : if (active_branch)
1389 : {
1390 : char *value;
1391 : char quoted;
1392 732 : bool no_newline = false;
1393 732 : bool first = true;
1394 : FILE *fout;
1395 :
1396 732 : if (strcmp(cmd, "qecho") == 0)
1397 30 : fout = pset.queryFout;
1398 702 : else if (strcmp(cmd, "warn") == 0)
1399 12 : fout = stderr;
1400 : else
1401 690 : fout = stdout;
1402 :
1403 2090 : while ((value = psql_scan_slash_option(scan_state,
1404 : OT_NORMAL, "ed, false)))
1405 : {
1406 1358 : if (first && !no_newline && !quoted && strcmp(value, "-n") == 0)
1407 6 : no_newline = true;
1408 : else
1409 : {
1410 1352 : if (first)
1411 732 : first = false;
1412 : else
1413 620 : fputc(' ', fout);
1414 1352 : fputs(value, fout);
1415 : }
1416 1358 : free(value);
1417 : }
1418 732 : if (!no_newline)
1419 726 : fputs("\n", fout);
1420 : }
1421 : else
1422 138 : ignore_slash_options(scan_state);
1423 :
1424 870 : return PSQL_CMD_SKIP_LINE;
1425 : }
1426 :
1427 : /*
1428 : * \encoding -- set/show client side encoding
1429 : */
1430 : static backslashResult
1431 6 : exec_command_encoding(PsqlScanState scan_state, bool active_branch)
1432 : {
1433 6 : if (active_branch)
1434 : {
1435 0 : char *encoding = psql_scan_slash_option(scan_state,
1436 : OT_NORMAL, NULL, false);
1437 :
1438 0 : if (!encoding)
1439 : {
1440 : /* show encoding */
1441 0 : puts(pg_encoding_to_char(pset.encoding));
1442 : }
1443 : else
1444 : {
1445 : /* set encoding */
1446 0 : if (PQsetClientEncoding(pset.db, encoding) == -1)
1447 0 : pg_log_error("%s: invalid encoding name or conversion procedure not found", encoding);
1448 : else
1449 : {
1450 : /* save encoding info into psql internal data */
1451 0 : pset.encoding = PQclientEncoding(pset.db);
1452 0 : pset.popt.topt.encoding = pset.encoding;
1453 0 : SetVariable(pset.vars, "ENCODING",
1454 : pg_encoding_to_char(pset.encoding));
1455 : }
1456 0 : free(encoding);
1457 : }
1458 : }
1459 : else
1460 6 : ignore_slash_options(scan_state);
1461 :
1462 6 : return PSQL_CMD_SKIP_LINE;
1463 : }
1464 :
1465 : /*
1466 : * \errverbose -- display verbose message from last failed query
1467 : */
1468 : static backslashResult
1469 14 : exec_command_errverbose(PsqlScanState scan_state, bool active_branch)
1470 : {
1471 14 : if (active_branch)
1472 : {
1473 8 : if (pset.last_error_result)
1474 : {
1475 : char *msg;
1476 :
1477 6 : msg = PQresultVerboseErrorMessage(pset.last_error_result,
1478 : PQERRORS_VERBOSE,
1479 : PQSHOW_CONTEXT_ALWAYS);
1480 6 : if (msg)
1481 : {
1482 6 : pg_log_error("%s", msg);
1483 6 : PQfreemem(msg);
1484 : }
1485 : else
1486 0 : puts(_("out of memory"));
1487 : }
1488 : else
1489 2 : puts(_("There is no previous error."));
1490 : }
1491 :
1492 14 : return PSQL_CMD_SKIP_LINE;
1493 : }
1494 :
1495 : /*
1496 : * \f -- change field separator
1497 : */
1498 : static backslashResult
1499 6 : exec_command_f(PsqlScanState scan_state, bool active_branch)
1500 : {
1501 6 : bool success = true;
1502 :
1503 6 : if (active_branch)
1504 : {
1505 0 : char *fname = psql_scan_slash_option(scan_state,
1506 : OT_NORMAL, NULL, false);
1507 :
1508 0 : success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
1509 0 : free(fname);
1510 : }
1511 : else
1512 6 : ignore_slash_options(scan_state);
1513 :
1514 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1515 : }
1516 :
1517 : /*
1518 : * \g [(pset-option[=pset-value] ...)] [filename/shell-command]
1519 : * \gx [(pset-option[=pset-value] ...)] [filename/shell-command]
1520 : *
1521 : * Send the current query. If pset options are specified, they are made
1522 : * active just for this query. If a filename or pipe command is given,
1523 : * the query output goes there. \gx implicitly sets "expanded=on" along
1524 : * with any other pset options that are specified.
1525 : */
1526 : static backslashResult
1527 294 : exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd)
1528 : {
1529 294 : backslashResult status = PSQL_CMD_SKIP_LINE;
1530 : char *fname;
1531 :
1532 : /*
1533 : * Because the option processing for this is fairly complicated, we do it
1534 : * and then decide whether the branch is active.
1535 : */
1536 294 : fname = psql_scan_slash_option(scan_state,
1537 : OT_FILEPIPE, NULL, false);
1538 :
1539 294 : if (fname && fname[0] == '(')
1540 : {
1541 : /* Consume pset options through trailing ')' ... */
1542 12 : status = process_command_g_options(fname + 1, scan_state,
1543 : active_branch, cmd);
1544 12 : free(fname);
1545 : /* ... and again attempt to scan the filename. */
1546 12 : fname = psql_scan_slash_option(scan_state,
1547 : OT_FILEPIPE, NULL, false);
1548 : }
1549 :
1550 294 : if (status == PSQL_CMD_SKIP_LINE && active_branch)
1551 : {
1552 270 : if (!fname)
1553 238 : pset.gfname = NULL;
1554 : else
1555 : {
1556 32 : expand_tilde(&fname);
1557 32 : pset.gfname = pg_strdup(fname);
1558 : }
1559 270 : if (strcmp(cmd, "gx") == 0)
1560 : {
1561 : /* save settings if not done already, then force expanded=on */
1562 30 : if (pset.gsavepopt == NULL)
1563 24 : pset.gsavepopt = savePsetInfo(&pset.popt);
1564 30 : pset.popt.topt.expanded = 1;
1565 : }
1566 270 : status = PSQL_CMD_SEND;
1567 : }
1568 :
1569 294 : free(fname);
1570 :
1571 294 : return status;
1572 : }
1573 :
1574 : /*
1575 : * Process parenthesized pset options for \g
1576 : *
1577 : * Note: okay to modify first_option, but not to free it; caller does that
1578 : */
1579 : static backslashResult
1580 12 : process_command_g_options(char *first_option, PsqlScanState scan_state,
1581 : bool active_branch, const char *cmd)
1582 : {
1583 12 : bool success = true;
1584 12 : bool found_r_paren = false;
1585 :
1586 : do
1587 : {
1588 : char *option;
1589 : size_t optlen;
1590 :
1591 : /* If not first time through, collect a new option */
1592 18 : if (first_option)
1593 12 : option = first_option;
1594 : else
1595 : {
1596 6 : option = psql_scan_slash_option(scan_state,
1597 : OT_NORMAL, NULL, false);
1598 6 : if (!option)
1599 : {
1600 0 : if (active_branch)
1601 : {
1602 0 : pg_log_error("\\%s: missing right parenthesis", cmd);
1603 0 : success = false;
1604 : }
1605 0 : break;
1606 : }
1607 : }
1608 :
1609 : /* Check for terminating right paren, and remove it from string */
1610 18 : optlen = strlen(option);
1611 18 : if (optlen > 0 && option[optlen - 1] == ')')
1612 : {
1613 12 : option[--optlen] = '\0';
1614 12 : found_r_paren = true;
1615 : }
1616 :
1617 : /* If there was anything besides parentheses, parse/execute it */
1618 18 : if (optlen > 0)
1619 : {
1620 : /* We can have either "name" or "name=value" */
1621 18 : char *valptr = strchr(option, '=');
1622 :
1623 18 : if (valptr)
1624 18 : *valptr++ = '\0';
1625 18 : if (active_branch)
1626 : {
1627 : /* save settings if not done already, then apply option */
1628 18 : if (pset.gsavepopt == NULL)
1629 12 : pset.gsavepopt = savePsetInfo(&pset.popt);
1630 18 : success &= do_pset(option, valptr, &pset.popt, true);
1631 : }
1632 : }
1633 :
1634 : /* Clean up after this option. We should not free first_option. */
1635 18 : if (first_option)
1636 12 : first_option = NULL;
1637 : else
1638 6 : free(option);
1639 18 : } while (!found_r_paren);
1640 :
1641 : /* If we failed after already changing some options, undo side-effects */
1642 12 : if (!success && active_branch && pset.gsavepopt)
1643 : {
1644 0 : restorePsetInfo(&pset.popt, pset.gsavepopt);
1645 0 : pset.gsavepopt = NULL;
1646 : }
1647 :
1648 12 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1649 : }
1650 :
1651 : /*
1652 : * \gdesc -- describe query result
1653 : */
1654 : static backslashResult
1655 68 : exec_command_gdesc(PsqlScanState scan_state, bool active_branch)
1656 : {
1657 68 : backslashResult status = PSQL_CMD_SKIP_LINE;
1658 :
1659 68 : if (active_branch)
1660 : {
1661 68 : pset.gdesc_flag = true;
1662 68 : status = PSQL_CMD_SEND;
1663 : }
1664 :
1665 68 : return status;
1666 : }
1667 :
1668 : /*
1669 : * \getenv -- set variable from environment variable
1670 : */
1671 : static backslashResult
1672 286 : exec_command_getenv(PsqlScanState scan_state, bool active_branch,
1673 : const char *cmd)
1674 : {
1675 286 : bool success = true;
1676 :
1677 286 : if (active_branch)
1678 : {
1679 286 : char *myvar = psql_scan_slash_option(scan_state,
1680 : OT_NORMAL, NULL, false);
1681 286 : char *envvar = psql_scan_slash_option(scan_state,
1682 : OT_NORMAL, NULL, false);
1683 :
1684 286 : if (!myvar || !envvar)
1685 : {
1686 0 : pg_log_error("\\%s: missing required argument", cmd);
1687 0 : success = false;
1688 : }
1689 : else
1690 : {
1691 286 : char *envval = getenv(envvar);
1692 :
1693 286 : if (envval && !SetVariable(pset.vars, myvar, envval))
1694 0 : success = false;
1695 : }
1696 286 : free(myvar);
1697 286 : free(envvar);
1698 : }
1699 : else
1700 0 : ignore_slash_options(scan_state);
1701 :
1702 286 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1703 : }
1704 :
1705 : /*
1706 : * \gexec -- send query and execute each field of result
1707 : */
1708 : static backslashResult
1709 52 : exec_command_gexec(PsqlScanState scan_state, bool active_branch)
1710 : {
1711 52 : backslashResult status = PSQL_CMD_SKIP_LINE;
1712 :
1713 52 : if (active_branch)
1714 : {
1715 46 : pset.gexec_flag = true;
1716 46 : status = PSQL_CMD_SEND;
1717 : }
1718 :
1719 52 : return status;
1720 : }
1721 :
1722 : /*
1723 : * \gset [prefix] -- send query and store result into variables
1724 : */
1725 : static backslashResult
1726 732 : exec_command_gset(PsqlScanState scan_state, bool active_branch)
1727 : {
1728 732 : backslashResult status = PSQL_CMD_SKIP_LINE;
1729 :
1730 732 : if (active_branch)
1731 : {
1732 726 : char *prefix = psql_scan_slash_option(scan_state,
1733 : OT_NORMAL, NULL, false);
1734 :
1735 726 : if (prefix)
1736 96 : pset.gset_prefix = prefix;
1737 : else
1738 : {
1739 : /* we must set a non-NULL prefix to trigger storing */
1740 630 : pset.gset_prefix = pg_strdup("");
1741 : }
1742 : /* gset_prefix is freed later */
1743 726 : status = PSQL_CMD_SEND;
1744 : }
1745 : else
1746 6 : ignore_slash_options(scan_state);
1747 :
1748 732 : return status;
1749 : }
1750 :
1751 : /*
1752 : * \help [topic] -- print help about SQL commands
1753 : */
1754 : static backslashResult
1755 10 : exec_command_help(PsqlScanState scan_state, bool active_branch)
1756 : {
1757 10 : if (active_branch)
1758 : {
1759 4 : char *opt = psql_scan_slash_option(scan_state,
1760 : OT_WHOLE_LINE, NULL, true);
1761 :
1762 4 : helpSQL(opt, pset.popt.topt.pager);
1763 4 : free(opt);
1764 : }
1765 : else
1766 6 : ignore_slash_whole_line(scan_state);
1767 :
1768 10 : return PSQL_CMD_SKIP_LINE;
1769 : }
1770 :
1771 : /*
1772 : * \H and \html -- toggle HTML formatting
1773 : */
1774 : static backslashResult
1775 6 : exec_command_html(PsqlScanState scan_state, bool active_branch)
1776 : {
1777 6 : bool success = true;
1778 :
1779 6 : if (active_branch)
1780 : {
1781 0 : if (pset.popt.topt.format != PRINT_HTML)
1782 0 : success = do_pset("format", "html", &pset.popt, pset.quiet);
1783 : else
1784 0 : success = do_pset("format", "aligned", &pset.popt, pset.quiet);
1785 : }
1786 :
1787 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1788 : }
1789 :
1790 : /*
1791 : * \i and \ir -- include a file
1792 : */
1793 : static backslashResult
1794 12 : exec_command_include(PsqlScanState scan_state, bool active_branch, const char *cmd)
1795 : {
1796 12 : bool success = true;
1797 :
1798 12 : if (active_branch)
1799 : {
1800 0 : char *fname = psql_scan_slash_option(scan_state,
1801 : OT_NORMAL, NULL, true);
1802 :
1803 0 : if (!fname)
1804 : {
1805 0 : pg_log_error("\\%s: missing required argument", cmd);
1806 0 : success = false;
1807 : }
1808 : else
1809 : {
1810 : bool include_relative;
1811 :
1812 0 : include_relative = (strcmp(cmd, "ir") == 0
1813 0 : || strcmp(cmd, "include_relative") == 0);
1814 0 : expand_tilde(&fname);
1815 0 : success = (process_file(fname, include_relative) == EXIT_SUCCESS);
1816 0 : free(fname);
1817 : }
1818 : }
1819 : else
1820 12 : ignore_slash_options(scan_state);
1821 :
1822 12 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1823 : }
1824 :
1825 : /*
1826 : * \if <expr> -- beginning of an \if..\endif block
1827 : *
1828 : * <expr> is parsed as a boolean expression. Invalid expressions will emit a
1829 : * warning and be treated as false. Statements that follow a false expression
1830 : * will be parsed but ignored. Note that in the case where an \if statement
1831 : * is itself within an inactive section of a block, then the entire inner
1832 : * \if..\endif block will be parsed but ignored.
1833 : */
1834 : static backslashResult
1835 186 : exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
1836 : PQExpBuffer query_buf)
1837 : {
1838 186 : if (conditional_active(cstack))
1839 : {
1840 : /*
1841 : * First, push a new active stack entry; this ensures that the lexer
1842 : * will perform variable substitution and backtick evaluation while
1843 : * scanning the expression. (That should happen anyway, since we know
1844 : * we're in an active outer branch, but let's be sure.)
1845 : */
1846 180 : conditional_stack_push(cstack, IFSTATE_TRUE);
1847 :
1848 : /* Remember current query state in case we need to restore later */
1849 180 : save_query_text_state(scan_state, cstack, query_buf);
1850 :
1851 : /*
1852 : * Evaluate the expression; if it's false, change to inactive state.
1853 : */
1854 180 : if (!is_true_boolean_expression(scan_state, "\\if expression"))
1855 108 : conditional_stack_poke(cstack, IFSTATE_FALSE);
1856 : }
1857 : else
1858 : {
1859 : /*
1860 : * We're within an inactive outer branch, so this entire \if block
1861 : * will be ignored. We don't want to evaluate the expression, so push
1862 : * the "ignored" stack state before scanning it.
1863 : */
1864 6 : conditional_stack_push(cstack, IFSTATE_IGNORED);
1865 :
1866 : /* Remember current query state in case we need to restore later */
1867 6 : save_query_text_state(scan_state, cstack, query_buf);
1868 :
1869 6 : ignore_boolean_expression(scan_state);
1870 : }
1871 :
1872 186 : return PSQL_CMD_SKIP_LINE;
1873 : }
1874 :
1875 : /*
1876 : * \elif <expr> -- alternative branch in an \if..\endif block
1877 : *
1878 : * <expr> is evaluated the same as in \if <expr>.
1879 : */
1880 : static backslashResult
1881 48 : exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
1882 : PQExpBuffer query_buf)
1883 : {
1884 48 : bool success = true;
1885 :
1886 48 : switch (conditional_stack_peek(cstack))
1887 : {
1888 6 : case IFSTATE_TRUE:
1889 :
1890 : /*
1891 : * Just finished active branch of this \if block. Update saved
1892 : * state so we will keep whatever data was put in query_buf by the
1893 : * active branch.
1894 : */
1895 6 : save_query_text_state(scan_state, cstack, query_buf);
1896 :
1897 : /*
1898 : * Discard \elif expression and ignore the rest until \endif.
1899 : * Switch state before reading expression to ensure proper lexer
1900 : * behavior.
1901 : */
1902 6 : conditional_stack_poke(cstack, IFSTATE_IGNORED);
1903 6 : ignore_boolean_expression(scan_state);
1904 6 : break;
1905 24 : case IFSTATE_FALSE:
1906 :
1907 : /*
1908 : * Discard any query text added by the just-skipped branch.
1909 : */
1910 24 : discard_query_text(scan_state, cstack, query_buf);
1911 :
1912 : /*
1913 : * Have not yet found a true expression in this \if block, so this
1914 : * might be the first. We have to change state before examining
1915 : * the expression, or the lexer won't do the right thing.
1916 : */
1917 24 : conditional_stack_poke(cstack, IFSTATE_TRUE);
1918 24 : if (!is_true_boolean_expression(scan_state, "\\elif expression"))
1919 18 : conditional_stack_poke(cstack, IFSTATE_FALSE);
1920 24 : break;
1921 6 : case IFSTATE_IGNORED:
1922 :
1923 : /*
1924 : * Discard any query text added by the just-skipped branch.
1925 : */
1926 6 : discard_query_text(scan_state, cstack, query_buf);
1927 :
1928 : /*
1929 : * Skip expression and move on. Either the \if block already had
1930 : * an active section, or whole block is being skipped.
1931 : */
1932 6 : ignore_boolean_expression(scan_state);
1933 6 : break;
1934 6 : case IFSTATE_ELSE_TRUE:
1935 : case IFSTATE_ELSE_FALSE:
1936 6 : pg_log_error("\\elif: cannot occur after \\else");
1937 6 : success = false;
1938 6 : break;
1939 6 : case IFSTATE_NONE:
1940 : /* no \if to elif from */
1941 6 : pg_log_error("\\elif: no matching \\if");
1942 6 : success = false;
1943 6 : break;
1944 : }
1945 :
1946 48 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1947 : }
1948 :
1949 : /*
1950 : * \else -- final alternative in an \if..\endif block
1951 : *
1952 : * Statements within an \else branch will only be executed if
1953 : * all previous \if and \elif expressions evaluated to false
1954 : * and the block was not itself being ignored.
1955 : */
1956 : static backslashResult
1957 132 : exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
1958 : PQExpBuffer query_buf)
1959 : {
1960 132 : bool success = true;
1961 :
1962 132 : switch (conditional_stack_peek(cstack))
1963 : {
1964 60 : case IFSTATE_TRUE:
1965 :
1966 : /*
1967 : * Just finished active branch of this \if block. Update saved
1968 : * state so we will keep whatever data was put in query_buf by the
1969 : * active branch.
1970 : */
1971 60 : save_query_text_state(scan_state, cstack, query_buf);
1972 :
1973 : /* Now skip the \else branch */
1974 60 : conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
1975 60 : break;
1976 48 : case IFSTATE_FALSE:
1977 :
1978 : /*
1979 : * Discard any query text added by the just-skipped branch.
1980 : */
1981 48 : discard_query_text(scan_state, cstack, query_buf);
1982 :
1983 : /*
1984 : * We've not found any true \if or \elif expression, so execute
1985 : * the \else branch.
1986 : */
1987 48 : conditional_stack_poke(cstack, IFSTATE_ELSE_TRUE);
1988 48 : break;
1989 12 : case IFSTATE_IGNORED:
1990 :
1991 : /*
1992 : * Discard any query text added by the just-skipped branch.
1993 : */
1994 12 : discard_query_text(scan_state, cstack, query_buf);
1995 :
1996 : /*
1997 : * Either we previously processed the active branch of this \if,
1998 : * or the whole \if block is being skipped. Either way, skip the
1999 : * \else branch.
2000 : */
2001 12 : conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
2002 12 : break;
2003 6 : case IFSTATE_ELSE_TRUE:
2004 : case IFSTATE_ELSE_FALSE:
2005 6 : pg_log_error("\\else: cannot occur after \\else");
2006 6 : success = false;
2007 6 : break;
2008 6 : case IFSTATE_NONE:
2009 : /* no \if to else from */
2010 6 : pg_log_error("\\else: no matching \\if");
2011 6 : success = false;
2012 6 : break;
2013 : }
2014 :
2015 132 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2016 : }
2017 :
2018 : /*
2019 : * \endif -- ends an \if...\endif block
2020 : */
2021 : static backslashResult
2022 180 : exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
2023 : PQExpBuffer query_buf)
2024 : {
2025 180 : bool success = true;
2026 :
2027 180 : switch (conditional_stack_peek(cstack))
2028 : {
2029 48 : case IFSTATE_TRUE:
2030 : case IFSTATE_ELSE_TRUE:
2031 : /* Close the \if block, keeping the query text */
2032 48 : success = conditional_stack_pop(cstack);
2033 : Assert(success);
2034 48 : break;
2035 126 : case IFSTATE_FALSE:
2036 : case IFSTATE_IGNORED:
2037 : case IFSTATE_ELSE_FALSE:
2038 :
2039 : /*
2040 : * Discard any query text added by the just-skipped branch.
2041 : */
2042 126 : discard_query_text(scan_state, cstack, query_buf);
2043 :
2044 : /* Close the \if block */
2045 126 : success = conditional_stack_pop(cstack);
2046 : Assert(success);
2047 126 : break;
2048 6 : case IFSTATE_NONE:
2049 : /* no \if to end */
2050 6 : pg_log_error("\\endif: no matching \\if");
2051 6 : success = false;
2052 6 : break;
2053 : }
2054 :
2055 180 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2056 : }
2057 :
2058 : /*
2059 : * \l -- list databases
2060 : */
2061 : static backslashResult
2062 6 : exec_command_list(PsqlScanState scan_state, bool active_branch, const char *cmd)
2063 : {
2064 6 : bool success = true;
2065 :
2066 6 : if (active_branch)
2067 : {
2068 : char *pattern;
2069 : bool show_verbose;
2070 : unsigned short int save_expanded;
2071 :
2072 0 : pattern = psql_scan_slash_option(scan_state,
2073 : OT_NORMAL, NULL, true);
2074 :
2075 0 : show_verbose = strchr(cmd, '+') ? true : false;
2076 :
2077 : /* if 'x' option specified, force expanded mode */
2078 0 : save_expanded = pset.popt.topt.expanded;
2079 0 : if (strchr(cmd, 'x'))
2080 0 : pset.popt.topt.expanded = 1;
2081 :
2082 0 : success = listAllDbs(pattern, show_verbose);
2083 :
2084 : /* restore original expanded mode */
2085 0 : pset.popt.topt.expanded = save_expanded;
2086 :
2087 0 : free(pattern);
2088 : }
2089 : else
2090 6 : ignore_slash_options(scan_state);
2091 :
2092 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2093 : }
2094 :
2095 : /*
2096 : * \lo_* -- large object operations
2097 : */
2098 : static backslashResult
2099 62 : exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
2100 : {
2101 62 : backslashResult status = PSQL_CMD_SKIP_LINE;
2102 62 : bool success = true;
2103 :
2104 62 : if (active_branch)
2105 : {
2106 : char *opt1,
2107 : *opt2;
2108 :
2109 56 : opt1 = psql_scan_slash_option(scan_state,
2110 : OT_NORMAL, NULL, true);
2111 56 : opt2 = psql_scan_slash_option(scan_state,
2112 : OT_NORMAL, NULL, true);
2113 :
2114 56 : if (strcmp(cmd + 3, "export") == 0)
2115 : {
2116 6 : if (!opt2)
2117 : {
2118 0 : pg_log_error("\\%s: missing required argument", cmd);
2119 0 : success = false;
2120 : }
2121 : else
2122 : {
2123 6 : expand_tilde(&opt2);
2124 6 : success = do_lo_export(opt1, opt2);
2125 : }
2126 : }
2127 :
2128 50 : else if (strcmp(cmd + 3, "import") == 0)
2129 : {
2130 14 : if (!opt1)
2131 : {
2132 0 : pg_log_error("\\%s: missing required argument", cmd);
2133 0 : success = false;
2134 : }
2135 : else
2136 : {
2137 14 : expand_tilde(&opt1);
2138 14 : success = do_lo_import(opt1, opt2);
2139 : }
2140 : }
2141 :
2142 36 : else if (strncmp(cmd + 3, "list", 4) == 0)
2143 : {
2144 : bool show_verbose;
2145 : unsigned short int save_expanded;
2146 :
2147 12 : show_verbose = strchr(cmd, '+') ? true : false;
2148 :
2149 : /* if 'x' option specified, force expanded mode */
2150 12 : save_expanded = pset.popt.topt.expanded;
2151 12 : if (strchr(cmd, 'x'))
2152 0 : pset.popt.topt.expanded = 1;
2153 :
2154 12 : success = listLargeObjects(show_verbose);
2155 :
2156 : /* restore original expanded mode */
2157 12 : pset.popt.topt.expanded = save_expanded;
2158 : }
2159 :
2160 24 : else if (strcmp(cmd + 3, "unlink") == 0)
2161 : {
2162 24 : if (!opt1)
2163 : {
2164 0 : pg_log_error("\\%s: missing required argument", cmd);
2165 0 : success = false;
2166 : }
2167 : else
2168 24 : success = do_lo_unlink(opt1);
2169 : }
2170 :
2171 : else
2172 0 : status = PSQL_CMD_UNKNOWN;
2173 :
2174 56 : free(opt1);
2175 56 : free(opt2);
2176 : }
2177 : else
2178 6 : ignore_slash_options(scan_state);
2179 :
2180 62 : if (!success)
2181 0 : status = PSQL_CMD_ERROR;
2182 :
2183 62 : return status;
2184 : }
2185 :
2186 : /*
2187 : * \o -- set query output
2188 : */
2189 : static backslashResult
2190 42 : exec_command_out(PsqlScanState scan_state, bool active_branch)
2191 : {
2192 42 : bool success = true;
2193 :
2194 42 : if (active_branch)
2195 : {
2196 36 : char *fname = psql_scan_slash_option(scan_state,
2197 : OT_FILEPIPE, NULL, true);
2198 :
2199 36 : expand_tilde(&fname);
2200 36 : success = setQFout(fname);
2201 36 : free(fname);
2202 : }
2203 : else
2204 6 : ignore_slash_filepipe(scan_state);
2205 :
2206 42 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2207 : }
2208 :
2209 : /*
2210 : * \p -- print the current query buffer
2211 : */
2212 : static backslashResult
2213 42 : exec_command_print(PsqlScanState scan_state, bool active_branch,
2214 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
2215 : {
2216 42 : if (active_branch)
2217 : {
2218 : /*
2219 : * We want to print the same thing \g would execute, but not to change
2220 : * the query buffer state; so we can't use copy_previous_query().
2221 : * Also, beware of possibility that buffer pointers are NULL.
2222 : */
2223 36 : if (query_buf && query_buf->len > 0)
2224 18 : puts(query_buf->data);
2225 18 : else if (previous_buf && previous_buf->len > 0)
2226 18 : puts(previous_buf->data);
2227 0 : else if (!pset.quiet)
2228 0 : puts(_("Query buffer is empty."));
2229 36 : fflush(stdout);
2230 : }
2231 :
2232 42 : return PSQL_CMD_SKIP_LINE;
2233 : }
2234 :
2235 : /*
2236 : * \parse -- parse query
2237 : */
2238 : static backslashResult
2239 42 : exec_command_parse(PsqlScanState scan_state, bool active_branch,
2240 : const char *cmd)
2241 : {
2242 42 : backslashResult status = PSQL_CMD_SKIP_LINE;
2243 :
2244 42 : if (active_branch)
2245 : {
2246 36 : char *opt = psql_scan_slash_option(scan_state,
2247 : OT_NORMAL, NULL, false);
2248 :
2249 36 : clean_extended_state();
2250 :
2251 36 : if (!opt)
2252 : {
2253 6 : pg_log_error("\\%s: missing required argument", cmd);
2254 6 : status = PSQL_CMD_ERROR;
2255 : }
2256 : else
2257 : {
2258 30 : pset.stmtName = opt;
2259 30 : pset.send_mode = PSQL_SEND_EXTENDED_PARSE;
2260 30 : status = PSQL_CMD_SEND;
2261 : }
2262 : }
2263 : else
2264 6 : ignore_slash_options(scan_state);
2265 :
2266 42 : return status;
2267 : }
2268 :
2269 : /*
2270 : * \password -- set user password
2271 : */
2272 : static backslashResult
2273 8 : exec_command_password(PsqlScanState scan_state, bool active_branch)
2274 : {
2275 8 : bool success = true;
2276 :
2277 8 : if (active_branch)
2278 : {
2279 2 : char *user = psql_scan_slash_option(scan_state,
2280 : OT_SQLID, NULL, true);
2281 2 : char *pw1 = NULL;
2282 2 : char *pw2 = NULL;
2283 : PQExpBufferData buf;
2284 : PromptInterruptContext prompt_ctx;
2285 :
2286 2 : if (user == NULL)
2287 : {
2288 : /* By default, the command applies to CURRENT_USER */
2289 : PGresult *res;
2290 :
2291 0 : res = PSQLexec("SELECT CURRENT_USER");
2292 0 : if (!res)
2293 0 : return PSQL_CMD_ERROR;
2294 :
2295 0 : user = pg_strdup(PQgetvalue(res, 0, 0));
2296 0 : PQclear(res);
2297 : }
2298 :
2299 : /* Set up to let SIGINT cancel simple_prompt_extended() */
2300 2 : prompt_ctx.jmpbuf = sigint_interrupt_jmp;
2301 2 : prompt_ctx.enabled = &sigint_interrupt_enabled;
2302 2 : prompt_ctx.canceled = false;
2303 :
2304 2 : initPQExpBuffer(&buf);
2305 2 : printfPQExpBuffer(&buf, _("Enter new password for user \"%s\": "), user);
2306 :
2307 2 : pw1 = simple_prompt_extended(buf.data, false, &prompt_ctx);
2308 2 : if (!prompt_ctx.canceled)
2309 2 : pw2 = simple_prompt_extended("Enter it again: ", false, &prompt_ctx);
2310 :
2311 2 : if (prompt_ctx.canceled)
2312 : {
2313 : /* fail silently */
2314 0 : success = false;
2315 : }
2316 2 : else if (strcmp(pw1, pw2) != 0)
2317 : {
2318 0 : pg_log_error("Passwords didn't match.");
2319 0 : success = false;
2320 : }
2321 : else
2322 : {
2323 2 : PGresult *res = PQchangePassword(pset.db, user, pw1);
2324 :
2325 2 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
2326 : {
2327 0 : pg_log_info("%s", PQerrorMessage(pset.db));
2328 0 : success = false;
2329 : }
2330 :
2331 2 : PQclear(res);
2332 : }
2333 :
2334 2 : free(user);
2335 2 : free(pw1);
2336 2 : free(pw2);
2337 2 : termPQExpBuffer(&buf);
2338 : }
2339 : else
2340 6 : ignore_slash_options(scan_state);
2341 :
2342 8 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2343 : }
2344 :
2345 : /*
2346 : * \prompt -- prompt and set variable
2347 : */
2348 : static backslashResult
2349 6 : exec_command_prompt(PsqlScanState scan_state, bool active_branch,
2350 : const char *cmd)
2351 : {
2352 6 : bool success = true;
2353 :
2354 6 : if (active_branch)
2355 : {
2356 : char *opt,
2357 0 : *prompt_text = NULL;
2358 : char *arg1,
2359 : *arg2;
2360 :
2361 0 : arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
2362 0 : arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
2363 :
2364 0 : if (!arg1)
2365 : {
2366 0 : pg_log_error("\\%s: missing required argument", cmd);
2367 0 : success = false;
2368 : }
2369 : else
2370 : {
2371 : char *result;
2372 : PromptInterruptContext prompt_ctx;
2373 :
2374 : /* Set up to let SIGINT cancel simple_prompt_extended() */
2375 0 : prompt_ctx.jmpbuf = sigint_interrupt_jmp;
2376 0 : prompt_ctx.enabled = &sigint_interrupt_enabled;
2377 0 : prompt_ctx.canceled = false;
2378 :
2379 0 : if (arg2)
2380 : {
2381 0 : prompt_text = arg1;
2382 0 : opt = arg2;
2383 : }
2384 : else
2385 0 : opt = arg1;
2386 :
2387 0 : if (!pset.inputfile)
2388 : {
2389 0 : result = simple_prompt_extended(prompt_text, true, &prompt_ctx);
2390 : }
2391 : else
2392 : {
2393 0 : if (prompt_text)
2394 : {
2395 0 : fputs(prompt_text, stdout);
2396 0 : fflush(stdout);
2397 : }
2398 0 : result = gets_fromFile(stdin);
2399 0 : if (!result)
2400 : {
2401 0 : pg_log_error("\\%s: could not read value for variable",
2402 : cmd);
2403 0 : success = false;
2404 : }
2405 : }
2406 :
2407 0 : if (prompt_ctx.canceled ||
2408 0 : (result && !SetVariable(pset.vars, opt, result)))
2409 0 : success = false;
2410 :
2411 0 : free(result);
2412 0 : free(prompt_text);
2413 0 : free(opt);
2414 : }
2415 : }
2416 : else
2417 6 : ignore_slash_options(scan_state);
2418 :
2419 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2420 : }
2421 :
2422 : /*
2423 : * \pset -- set printing parameters
2424 : */
2425 : static backslashResult
2426 1740 : exec_command_pset(PsqlScanState scan_state, bool active_branch)
2427 : {
2428 1740 : bool success = true;
2429 :
2430 1740 : if (active_branch)
2431 : {
2432 1728 : char *opt0 = psql_scan_slash_option(scan_state,
2433 : OT_NORMAL, NULL, false);
2434 1728 : char *opt1 = psql_scan_slash_option(scan_state,
2435 : OT_NORMAL, NULL, false);
2436 :
2437 1728 : if (!opt0)
2438 : {
2439 : /* list all variables */
2440 :
2441 : int i;
2442 : static const char *const my_list[] = {
2443 : "border", "columns", "csv_fieldsep", "expanded", "fieldsep",
2444 : "fieldsep_zero", "footer", "format", "linestyle", "null",
2445 : "numericlocale", "pager", "pager_min_lines",
2446 : "recordsep", "recordsep_zero",
2447 : "tableattr", "title", "tuples_only",
2448 : "unicode_border_linestyle",
2449 : "unicode_column_linestyle",
2450 : "unicode_header_linestyle",
2451 : "xheader_width",
2452 : NULL
2453 : };
2454 :
2455 138 : for (i = 0; my_list[i] != NULL; i++)
2456 : {
2457 132 : char *val = pset_value_string(my_list[i], &pset.popt);
2458 :
2459 132 : printf("%-24s %s\n", my_list[i], val);
2460 132 : free(val);
2461 : }
2462 :
2463 6 : success = true;
2464 : }
2465 : else
2466 1722 : success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
2467 :
2468 1728 : free(opt0);
2469 1728 : free(opt1);
2470 : }
2471 : else
2472 12 : ignore_slash_options(scan_state);
2473 :
2474 1740 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2475 : }
2476 :
2477 : /*
2478 : * \q or \quit -- exit psql
2479 : */
2480 : static backslashResult
2481 158 : exec_command_quit(PsqlScanState scan_state, bool active_branch)
2482 : {
2483 158 : backslashResult status = PSQL_CMD_SKIP_LINE;
2484 :
2485 158 : if (active_branch)
2486 98 : status = PSQL_CMD_TERMINATE;
2487 :
2488 158 : return status;
2489 : }
2490 :
2491 : /*
2492 : * \r -- reset (clear) the query buffer
2493 : */
2494 : static backslashResult
2495 84 : exec_command_reset(PsqlScanState scan_state, bool active_branch,
2496 : PQExpBuffer query_buf)
2497 : {
2498 84 : if (active_branch)
2499 : {
2500 78 : resetPQExpBuffer(query_buf);
2501 78 : psql_scan_reset(scan_state);
2502 78 : if (!pset.quiet)
2503 60 : puts(_("Query buffer reset (cleared)."));
2504 : }
2505 :
2506 84 : return PSQL_CMD_SKIP_LINE;
2507 : }
2508 :
2509 : /*
2510 : * \s -- save history in a file or show it on the screen
2511 : */
2512 : static backslashResult
2513 6 : exec_command_s(PsqlScanState scan_state, bool active_branch)
2514 : {
2515 6 : bool success = true;
2516 :
2517 6 : if (active_branch)
2518 : {
2519 0 : char *fname = psql_scan_slash_option(scan_state,
2520 : OT_NORMAL, NULL, true);
2521 :
2522 0 : expand_tilde(&fname);
2523 0 : success = printHistory(fname, pset.popt.topt.pager);
2524 0 : if (success && !pset.quiet && fname)
2525 0 : printf(_("Wrote history to file \"%s\".\n"), fname);
2526 0 : if (!fname)
2527 0 : putchar('\n');
2528 0 : free(fname);
2529 : }
2530 : else
2531 6 : ignore_slash_options(scan_state);
2532 :
2533 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2534 : }
2535 :
2536 : /*
2537 : * \set -- set variable
2538 : */
2539 : static backslashResult
2540 938 : exec_command_set(PsqlScanState scan_state, bool active_branch)
2541 : {
2542 938 : bool success = true;
2543 :
2544 938 : if (active_branch)
2545 : {
2546 932 : char *opt0 = psql_scan_slash_option(scan_state,
2547 : OT_NORMAL, NULL, false);
2548 :
2549 932 : if (!opt0)
2550 : {
2551 : /* list all variables */
2552 0 : PrintVariables(pset.vars);
2553 0 : success = true;
2554 : }
2555 : else
2556 : {
2557 : /*
2558 : * Set variable to the concatenation of the arguments.
2559 : */
2560 : char *newval;
2561 : char *opt;
2562 :
2563 932 : opt = psql_scan_slash_option(scan_state,
2564 : OT_NORMAL, NULL, false);
2565 932 : newval = pg_strdup(opt ? opt : "");
2566 932 : free(opt);
2567 :
2568 1412 : while ((opt = psql_scan_slash_option(scan_state,
2569 : OT_NORMAL, NULL, false)))
2570 : {
2571 480 : newval = pg_realloc(newval, strlen(newval) + strlen(opt) + 1);
2572 480 : strcat(newval, opt);
2573 480 : free(opt);
2574 : }
2575 :
2576 932 : if (!SetVariable(pset.vars, opt0, newval))
2577 24 : success = false;
2578 :
2579 932 : free(newval);
2580 : }
2581 932 : free(opt0);
2582 : }
2583 : else
2584 6 : ignore_slash_options(scan_state);
2585 :
2586 938 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2587 : }
2588 :
2589 : /*
2590 : * \setenv -- set environment variable
2591 : */
2592 : static backslashResult
2593 18 : exec_command_setenv(PsqlScanState scan_state, bool active_branch,
2594 : const char *cmd)
2595 : {
2596 18 : bool success = true;
2597 :
2598 18 : if (active_branch)
2599 : {
2600 12 : char *envvar = psql_scan_slash_option(scan_state,
2601 : OT_NORMAL, NULL, false);
2602 12 : char *envval = psql_scan_slash_option(scan_state,
2603 : OT_NORMAL, NULL, false);
2604 :
2605 12 : if (!envvar)
2606 : {
2607 0 : pg_log_error("\\%s: missing required argument", cmd);
2608 0 : success = false;
2609 : }
2610 12 : else if (strchr(envvar, '=') != NULL)
2611 : {
2612 0 : pg_log_error("\\%s: environment variable name must not contain \"=\"",
2613 : cmd);
2614 0 : success = false;
2615 : }
2616 12 : else if (!envval)
2617 : {
2618 : /* No argument - unset the environment variable */
2619 6 : unsetenv(envvar);
2620 6 : success = true;
2621 : }
2622 : else
2623 : {
2624 : /* Set variable to the value of the next argument */
2625 6 : setenv(envvar, envval, 1);
2626 6 : success = true;
2627 : }
2628 12 : free(envvar);
2629 12 : free(envval);
2630 : }
2631 : else
2632 6 : ignore_slash_options(scan_state);
2633 :
2634 18 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2635 : }
2636 :
2637 : /*
2638 : * \sf/\sv -- show a function/view's source code
2639 : */
2640 : static backslashResult
2641 198 : exec_command_sf_sv(PsqlScanState scan_state, bool active_branch,
2642 : const char *cmd, bool is_func)
2643 : {
2644 198 : backslashResult status = PSQL_CMD_SKIP_LINE;
2645 :
2646 198 : if (active_branch)
2647 : {
2648 186 : bool show_linenumbers = (strchr(cmd, '+') != NULL);
2649 : PQExpBuffer buf;
2650 : char *obj_desc;
2651 186 : Oid obj_oid = InvalidOid;
2652 186 : EditableObjectType eot = is_func ? EditableFunction : EditableView;
2653 :
2654 186 : buf = createPQExpBuffer();
2655 186 : obj_desc = psql_scan_slash_option(scan_state,
2656 : OT_WHOLE_LINE, NULL, true);
2657 186 : if (!obj_desc)
2658 : {
2659 0 : if (is_func)
2660 0 : pg_log_error("function name is required");
2661 : else
2662 0 : pg_log_error("view name is required");
2663 0 : status = PSQL_CMD_ERROR;
2664 : }
2665 186 : else if (!lookup_object_oid(eot, obj_desc, &obj_oid))
2666 : {
2667 : /* error already reported */
2668 0 : status = PSQL_CMD_ERROR;
2669 : }
2670 186 : else if (!get_create_object_cmd(eot, obj_oid, buf))
2671 : {
2672 : /* error already reported */
2673 0 : status = PSQL_CMD_ERROR;
2674 : }
2675 : else
2676 : {
2677 : FILE *output;
2678 : bool is_pager;
2679 :
2680 : /* Select output stream: stdout, pager, or file */
2681 186 : if (pset.queryFout == stdout)
2682 : {
2683 : /* count lines in function to see if pager is needed */
2684 186 : int lineno = count_lines_in_buf(buf);
2685 :
2686 186 : output = PageOutput(lineno, &(pset.popt.topt));
2687 186 : is_pager = true;
2688 : }
2689 : else
2690 : {
2691 : /* use previously set output file, without pager */
2692 0 : output = pset.queryFout;
2693 0 : is_pager = false;
2694 : }
2695 :
2696 186 : if (show_linenumbers)
2697 : {
2698 : /* add line numbers */
2699 18 : print_with_linenumbers(output, buf->data, is_func);
2700 : }
2701 : else
2702 : {
2703 : /* just send the definition to output */
2704 168 : fputs(buf->data, output);
2705 : }
2706 :
2707 186 : if (is_pager)
2708 186 : ClosePager(output);
2709 : }
2710 :
2711 186 : free(obj_desc);
2712 186 : destroyPQExpBuffer(buf);
2713 : }
2714 : else
2715 12 : ignore_slash_whole_line(scan_state);
2716 :
2717 198 : return status;
2718 : }
2719 :
2720 : /*
2721 : * \t -- turn off table headers and row count
2722 : */
2723 : static backslashResult
2724 70 : exec_command_t(PsqlScanState scan_state, bool active_branch)
2725 : {
2726 70 : bool success = true;
2727 :
2728 70 : if (active_branch)
2729 : {
2730 64 : char *opt = psql_scan_slash_option(scan_state,
2731 : OT_NORMAL, NULL, true);
2732 :
2733 64 : success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
2734 64 : free(opt);
2735 : }
2736 : else
2737 6 : ignore_slash_options(scan_state);
2738 :
2739 70 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2740 : }
2741 :
2742 : /*
2743 : * \T -- define html <table ...> attributes
2744 : */
2745 : static backslashResult
2746 6 : exec_command_T(PsqlScanState scan_state, bool active_branch)
2747 : {
2748 6 : bool success = true;
2749 :
2750 6 : if (active_branch)
2751 : {
2752 0 : char *value = psql_scan_slash_option(scan_state,
2753 : OT_NORMAL, NULL, false);
2754 :
2755 0 : success = do_pset("tableattr", value, &pset.popt, pset.quiet);
2756 0 : free(value);
2757 : }
2758 : else
2759 6 : ignore_slash_options(scan_state);
2760 :
2761 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2762 : }
2763 :
2764 : /*
2765 : * \timing -- enable/disable timing of queries
2766 : */
2767 : static backslashResult
2768 10 : exec_command_timing(PsqlScanState scan_state, bool active_branch)
2769 : {
2770 10 : bool success = true;
2771 :
2772 10 : if (active_branch)
2773 : {
2774 4 : char *opt = psql_scan_slash_option(scan_state,
2775 : OT_NORMAL, NULL, false);
2776 :
2777 4 : if (opt)
2778 4 : success = ParseVariableBool(opt, "\\timing", &pset.timing);
2779 : else
2780 0 : pset.timing = !pset.timing;
2781 4 : if (!pset.quiet)
2782 : {
2783 0 : if (pset.timing)
2784 0 : puts(_("Timing is on."));
2785 : else
2786 0 : puts(_("Timing is off."));
2787 : }
2788 4 : free(opt);
2789 : }
2790 : else
2791 6 : ignore_slash_options(scan_state);
2792 :
2793 10 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2794 : }
2795 :
2796 : /*
2797 : * \unset -- unset variable
2798 : */
2799 : static backslashResult
2800 38 : exec_command_unset(PsqlScanState scan_state, bool active_branch,
2801 : const char *cmd)
2802 : {
2803 38 : bool success = true;
2804 :
2805 38 : if (active_branch)
2806 : {
2807 32 : char *opt = psql_scan_slash_option(scan_state,
2808 : OT_NORMAL, NULL, false);
2809 :
2810 32 : if (!opt)
2811 : {
2812 0 : pg_log_error("\\%s: missing required argument", cmd);
2813 0 : success = false;
2814 : }
2815 32 : else if (!SetVariable(pset.vars, opt, NULL))
2816 0 : success = false;
2817 :
2818 32 : free(opt);
2819 : }
2820 : else
2821 6 : ignore_slash_options(scan_state);
2822 :
2823 38 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2824 : }
2825 :
2826 : /*
2827 : * \w -- write query buffer to file
2828 : */
2829 : static backslashResult
2830 12 : exec_command_write(PsqlScanState scan_state, bool active_branch,
2831 : const char *cmd,
2832 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
2833 : {
2834 12 : backslashResult status = PSQL_CMD_SKIP_LINE;
2835 :
2836 12 : if (active_branch)
2837 : {
2838 0 : char *fname = psql_scan_slash_option(scan_state,
2839 : OT_FILEPIPE, NULL, true);
2840 0 : FILE *fd = NULL;
2841 0 : bool is_pipe = false;
2842 :
2843 0 : if (!query_buf)
2844 : {
2845 0 : pg_log_error("no query buffer");
2846 0 : status = PSQL_CMD_ERROR;
2847 : }
2848 : else
2849 : {
2850 0 : if (!fname)
2851 : {
2852 0 : pg_log_error("\\%s: missing required argument", cmd);
2853 0 : status = PSQL_CMD_ERROR;
2854 : }
2855 : else
2856 : {
2857 0 : expand_tilde(&fname);
2858 0 : if (fname[0] == '|')
2859 : {
2860 0 : is_pipe = true;
2861 0 : fflush(NULL);
2862 0 : disable_sigpipe_trap();
2863 0 : fd = popen(&fname[1], "w");
2864 : }
2865 : else
2866 : {
2867 0 : canonicalize_path(fname);
2868 0 : fd = fopen(fname, "w");
2869 : }
2870 0 : if (!fd)
2871 : {
2872 0 : pg_log_error("%s: %m", fname);
2873 0 : status = PSQL_CMD_ERROR;
2874 : }
2875 : }
2876 : }
2877 :
2878 0 : if (fd)
2879 : {
2880 : int result;
2881 :
2882 : /*
2883 : * We want to print the same thing \g would execute, but not to
2884 : * change the query buffer state; so we can't use
2885 : * copy_previous_query(). Also, beware of possibility that buffer
2886 : * pointers are NULL.
2887 : */
2888 0 : if (query_buf && query_buf->len > 0)
2889 0 : fprintf(fd, "%s\n", query_buf->data);
2890 0 : else if (previous_buf && previous_buf->len > 0)
2891 0 : fprintf(fd, "%s\n", previous_buf->data);
2892 :
2893 0 : if (is_pipe)
2894 : {
2895 0 : result = pclose(fd);
2896 :
2897 0 : if (result != 0)
2898 : {
2899 0 : pg_log_error("%s: %s", fname, wait_result_to_str(result));
2900 0 : status = PSQL_CMD_ERROR;
2901 : }
2902 0 : SetShellResultVariables(result);
2903 : }
2904 : else
2905 : {
2906 0 : result = fclose(fd);
2907 :
2908 0 : if (result == EOF)
2909 : {
2910 0 : pg_log_error("%s: %m", fname);
2911 0 : status = PSQL_CMD_ERROR;
2912 : }
2913 : }
2914 : }
2915 :
2916 0 : if (is_pipe)
2917 0 : restore_sigpipe_trap();
2918 :
2919 0 : free(fname);
2920 : }
2921 : else
2922 12 : ignore_slash_filepipe(scan_state);
2923 :
2924 12 : return status;
2925 : }
2926 :
2927 : /*
2928 : * \watch -- execute a query every N seconds.
2929 : * Optionally, stop after M iterations.
2930 : */
2931 : static backslashResult
2932 28 : exec_command_watch(PsqlScanState scan_state, bool active_branch,
2933 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
2934 : {
2935 28 : bool success = true;
2936 :
2937 28 : if (active_branch)
2938 : {
2939 22 : bool have_sleep = false;
2940 22 : bool have_iter = false;
2941 22 : bool have_min_rows = false;
2942 22 : double sleep = 2;
2943 22 : int iter = 0;
2944 22 : int min_rows = 0;
2945 :
2946 : /*
2947 : * Parse arguments. We allow either an unlabeled interval or
2948 : * "name=value", where name is from the set ('i', 'interval', 'c',
2949 : * 'count', 'm', 'min_rows').
2950 : */
2951 56 : while (success)
2952 : {
2953 42 : char *opt = psql_scan_slash_option(scan_state,
2954 : OT_NORMAL, NULL, true);
2955 : char *valptr;
2956 : char *opt_end;
2957 :
2958 42 : if (!opt)
2959 8 : break; /* no more arguments */
2960 :
2961 34 : valptr = strchr(opt, '=');
2962 34 : if (valptr)
2963 : {
2964 : /* Labeled argument */
2965 22 : valptr++;
2966 22 : if (strncmp("i=", opt, strlen("i=")) == 0 ||
2967 16 : strncmp("interval=", opt, strlen("interval=")) == 0)
2968 : {
2969 6 : if (have_sleep)
2970 : {
2971 0 : pg_log_error("\\watch: interval value is specified more than once");
2972 0 : success = false;
2973 : }
2974 : else
2975 : {
2976 6 : have_sleep = true;
2977 6 : errno = 0;
2978 6 : sleep = strtod(valptr, &opt_end);
2979 6 : if (sleep < 0 || *opt_end || errno == ERANGE)
2980 : {
2981 0 : pg_log_error("\\watch: incorrect interval value \"%s\"", valptr);
2982 0 : success = false;
2983 : }
2984 : }
2985 : }
2986 16 : else if (strncmp("c=", opt, strlen("c=")) == 0 ||
2987 8 : strncmp("count=", opt, strlen("count=")) == 0)
2988 : {
2989 8 : if (have_iter)
2990 : {
2991 2 : pg_log_error("\\watch: iteration count is specified more than once");
2992 2 : success = false;
2993 : }
2994 : else
2995 : {
2996 6 : have_iter = true;
2997 6 : errno = 0;
2998 6 : iter = strtoint(valptr, &opt_end, 10);
2999 6 : if (iter <= 0 || *opt_end || errno == ERANGE)
3000 : {
3001 0 : pg_log_error("\\watch: incorrect iteration count \"%s\"", valptr);
3002 0 : success = false;
3003 : }
3004 : }
3005 : }
3006 8 : else if (strncmp("m=", opt, strlen("m=")) == 0 ||
3007 2 : strncmp("min_rows=", opt, strlen("min_rows=")) == 0)
3008 : {
3009 8 : if (have_min_rows)
3010 : {
3011 2 : pg_log_error("\\watch: minimum row count specified more than once");
3012 2 : success = false;
3013 : }
3014 : else
3015 : {
3016 6 : have_min_rows = true;
3017 6 : errno = 0;
3018 6 : min_rows = strtoint(valptr, &opt_end, 10);
3019 6 : if (min_rows <= 0 || *opt_end || errno == ERANGE)
3020 : {
3021 2 : pg_log_error("\\watch: incorrect minimum row count \"%s\"", valptr);
3022 2 : success = false;
3023 : }
3024 : }
3025 : }
3026 : else
3027 : {
3028 0 : pg_log_error("\\watch: unrecognized parameter \"%s\"", opt);
3029 0 : success = false;
3030 : }
3031 : }
3032 : else
3033 : {
3034 : /* Unlabeled argument: take it as interval */
3035 12 : if (have_sleep)
3036 : {
3037 2 : pg_log_error("\\watch: interval value is specified more than once");
3038 2 : success = false;
3039 : }
3040 : else
3041 : {
3042 10 : have_sleep = true;
3043 10 : errno = 0;
3044 10 : sleep = strtod(opt, &opt_end);
3045 10 : if (sleep < 0 || *opt_end || errno == ERANGE)
3046 : {
3047 6 : pg_log_error("\\watch: incorrect interval value \"%s\"", opt);
3048 6 : success = false;
3049 : }
3050 : }
3051 : }
3052 :
3053 34 : free(opt);
3054 : }
3055 :
3056 : /* If we parsed arguments successfully, do the command */
3057 22 : if (success)
3058 : {
3059 : /* If query_buf is empty, recall and execute previous query */
3060 8 : (void) copy_previous_query(query_buf, previous_buf);
3061 :
3062 8 : success = do_watch(query_buf, sleep, iter, min_rows);
3063 : }
3064 :
3065 : /* Reset the query buffer as though for \r */
3066 20 : resetPQExpBuffer(query_buf);
3067 20 : psql_scan_reset(scan_state);
3068 : }
3069 : else
3070 6 : ignore_slash_options(scan_state);
3071 :
3072 26 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
3073 : }
3074 :
3075 : /*
3076 : * \x -- set or toggle expanded table representation
3077 : */
3078 : static backslashResult
3079 76 : exec_command_x(PsqlScanState scan_state, bool active_branch)
3080 : {
3081 76 : bool success = true;
3082 :
3083 76 : if (active_branch)
3084 : {
3085 70 : char *opt = psql_scan_slash_option(scan_state,
3086 : OT_NORMAL, NULL, true);
3087 :
3088 70 : success = do_pset("expanded", opt, &pset.popt, pset.quiet);
3089 70 : free(opt);
3090 : }
3091 : else
3092 6 : ignore_slash_options(scan_state);
3093 :
3094 76 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
3095 : }
3096 :
3097 : /*
3098 : * \z -- list table privileges (equivalent to \dp)
3099 : */
3100 : static backslashResult
3101 30 : exec_command_z(PsqlScanState scan_state, bool active_branch, const char *cmd)
3102 : {
3103 30 : bool success = true;
3104 :
3105 30 : if (active_branch)
3106 : {
3107 : char *pattern;
3108 : bool show_system;
3109 : unsigned short int save_expanded;
3110 :
3111 24 : pattern = psql_scan_slash_option(scan_state,
3112 : OT_NORMAL, NULL, true);
3113 :
3114 24 : show_system = strchr(cmd, 'S') ? true : false;
3115 :
3116 : /* if 'x' option specified, force expanded mode */
3117 24 : save_expanded = pset.popt.topt.expanded;
3118 24 : if (strchr(cmd, 'x'))
3119 6 : pset.popt.topt.expanded = 1;
3120 :
3121 24 : success = permissionsList(pattern, show_system);
3122 :
3123 : /* restore original expanded mode */
3124 24 : pset.popt.topt.expanded = save_expanded;
3125 :
3126 24 : free(pattern);
3127 : }
3128 : else
3129 6 : ignore_slash_options(scan_state);
3130 :
3131 30 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
3132 : }
3133 :
3134 : /*
3135 : * \! -- execute shell command
3136 : */
3137 : static backslashResult
3138 6 : exec_command_shell_escape(PsqlScanState scan_state, bool active_branch)
3139 : {
3140 6 : bool success = true;
3141 :
3142 6 : if (active_branch)
3143 : {
3144 0 : char *opt = psql_scan_slash_option(scan_state,
3145 : OT_WHOLE_LINE, NULL, false);
3146 :
3147 0 : success = do_shell(opt);
3148 0 : free(opt);
3149 : }
3150 : else
3151 6 : ignore_slash_whole_line(scan_state);
3152 :
3153 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
3154 : }
3155 :
3156 : /*
3157 : * \? -- print help about backslash commands
3158 : */
3159 : static backslashResult
3160 6 : exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch)
3161 : {
3162 6 : if (active_branch)
3163 : {
3164 0 : char *opt0 = psql_scan_slash_option(scan_state,
3165 : OT_NORMAL, NULL, false);
3166 :
3167 0 : if (!opt0 || strcmp(opt0, "commands") == 0)
3168 0 : slashUsage(pset.popt.topt.pager);
3169 0 : else if (strcmp(opt0, "options") == 0)
3170 0 : usage(pset.popt.topt.pager);
3171 0 : else if (strcmp(opt0, "variables") == 0)
3172 0 : helpVariables(pset.popt.topt.pager);
3173 : else
3174 0 : slashUsage(pset.popt.topt.pager);
3175 :
3176 0 : free(opt0);
3177 : }
3178 : else
3179 6 : ignore_slash_options(scan_state);
3180 :
3181 6 : return PSQL_CMD_SKIP_LINE;
3182 : }
3183 :
3184 :
3185 : /*
3186 : * Read and interpret an argument to the \connect slash command.
3187 : *
3188 : * Returns a malloc'd string, or NULL if no/empty argument.
3189 : */
3190 : static char *
3191 1318 : read_connect_arg(PsqlScanState scan_state)
3192 : {
3193 : char *result;
3194 : char quote;
3195 :
3196 : /*
3197 : * Ideally we should treat the arguments as SQL identifiers. But for
3198 : * backwards compatibility with 7.2 and older pg_dump files, we have to
3199 : * take unquoted arguments verbatim (don't downcase them). For now,
3200 : * double-quoted arguments may be stripped of double quotes (as if SQL
3201 : * identifiers). By 7.4 or so, pg_dump files can be expected to
3202 : * double-quote all mixed-case \connect arguments, and then we can get rid
3203 : * of OT_SQLIDHACK.
3204 : */
3205 1318 : result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, "e, true);
3206 :
3207 1318 : if (!result)
3208 1054 : return NULL;
3209 :
3210 264 : if (quote)
3211 24 : return result;
3212 :
3213 240 : if (*result == '\0' || strcmp(result, "-") == 0)
3214 : {
3215 200 : free(result);
3216 200 : return NULL;
3217 : }
3218 :
3219 40 : return result;
3220 : }
3221 :
3222 : /*
3223 : * Read a boolean expression, return it as a PQExpBuffer string.
3224 : *
3225 : * Note: anything more or less than one token will certainly fail to be
3226 : * parsed by ParseVariableBool, so we don't worry about complaining here.
3227 : * This routine's return data structure will need to be rethought anyway
3228 : * to support likely future extensions such as "\if defined VARNAME".
3229 : */
3230 : static PQExpBuffer
3231 222 : gather_boolean_expression(PsqlScanState scan_state)
3232 : {
3233 222 : PQExpBuffer exp_buf = createPQExpBuffer();
3234 222 : int num_options = 0;
3235 : char *value;
3236 :
3237 : /* collect all arguments for the conditional command into exp_buf */
3238 456 : while ((value = psql_scan_slash_option(scan_state,
3239 : OT_NORMAL, NULL, false)) != NULL)
3240 : {
3241 : /* add spaces between tokens */
3242 234 : if (num_options > 0)
3243 12 : appendPQExpBufferChar(exp_buf, ' ');
3244 234 : appendPQExpBufferStr(exp_buf, value);
3245 234 : num_options++;
3246 234 : free(value);
3247 : }
3248 :
3249 222 : return exp_buf;
3250 : }
3251 :
3252 : /*
3253 : * Read a boolean expression, return true if the expression
3254 : * was a valid boolean expression that evaluated to true.
3255 : * Otherwise return false.
3256 : *
3257 : * Note: conditional stack's top state must be active, else lexer will
3258 : * fail to expand variables and backticks.
3259 : */
3260 : static bool
3261 204 : is_true_boolean_expression(PsqlScanState scan_state, const char *name)
3262 : {
3263 204 : PQExpBuffer buf = gather_boolean_expression(scan_state);
3264 204 : bool value = false;
3265 204 : bool success = ParseVariableBool(buf->data, name, &value);
3266 :
3267 204 : destroyPQExpBuffer(buf);
3268 204 : return success && value;
3269 : }
3270 :
3271 : /*
3272 : * Read a boolean expression, but do nothing with it.
3273 : *
3274 : * Note: conditional stack's top state must be INACTIVE, else lexer will
3275 : * expand variables and backticks, which we do not want here.
3276 : */
3277 : static void
3278 18 : ignore_boolean_expression(PsqlScanState scan_state)
3279 : {
3280 18 : PQExpBuffer buf = gather_boolean_expression(scan_state);
3281 :
3282 18 : destroyPQExpBuffer(buf);
3283 18 : }
3284 :
3285 : /*
3286 : * Read and discard "normal" slash command options.
3287 : *
3288 : * This should be used for inactive-branch processing of any slash command
3289 : * that eats one or more OT_NORMAL, OT_SQLID, or OT_SQLIDHACK parameters.
3290 : * We don't need to worry about exactly how many it would eat, since the
3291 : * cleanup logic in HandleSlashCmds would silently discard any extras anyway.
3292 : */
3293 : static void
3294 330 : ignore_slash_options(PsqlScanState scan_state)
3295 : {
3296 : char *arg;
3297 :
3298 792 : while ((arg = psql_scan_slash_option(scan_state,
3299 : OT_NORMAL, NULL, false)) != NULL)
3300 462 : free(arg);
3301 330 : }
3302 :
3303 : /*
3304 : * Read and discard FILEPIPE slash command argument.
3305 : *
3306 : * This *MUST* be used for inactive-branch processing of any slash command
3307 : * that takes an OT_FILEPIPE option. Otherwise we might consume a different
3308 : * amount of option text in active and inactive cases.
3309 : */
3310 : static void
3311 18 : ignore_slash_filepipe(PsqlScanState scan_state)
3312 : {
3313 18 : char *arg = psql_scan_slash_option(scan_state,
3314 : OT_FILEPIPE, NULL, false);
3315 :
3316 18 : free(arg);
3317 18 : }
3318 :
3319 : /*
3320 : * Read and discard whole-line slash command argument.
3321 : *
3322 : * This *MUST* be used for inactive-branch processing of any slash command
3323 : * that takes an OT_WHOLE_LINE option. Otherwise we might consume a different
3324 : * amount of option text in active and inactive cases.
3325 : *
3326 : * Note: although callers might pass "semicolon" as either true or false,
3327 : * we need not duplicate that here, since it doesn't affect the amount of
3328 : * input text consumed.
3329 : */
3330 : static void
3331 42 : ignore_slash_whole_line(PsqlScanState scan_state)
3332 : {
3333 42 : char *arg = psql_scan_slash_option(scan_state,
3334 : OT_WHOLE_LINE, NULL, false);
3335 :
3336 42 : free(arg);
3337 42 : }
3338 :
3339 : /*
3340 : * Return true if the command given is a branching command.
3341 : */
3342 : static bool
3343 0 : is_branching_command(const char *cmd)
3344 : {
3345 0 : return (strcmp(cmd, "if") == 0 ||
3346 0 : strcmp(cmd, "elif") == 0 ||
3347 0 : strcmp(cmd, "else") == 0 ||
3348 0 : strcmp(cmd, "endif") == 0);
3349 : }
3350 :
3351 : /*
3352 : * Prepare to possibly restore query buffer to its current state
3353 : * (cf. discard_query_text).
3354 : *
3355 : * We need to remember the length of the query buffer, and the lexer's
3356 : * notion of the parenthesis nesting depth.
3357 : */
3358 : static void
3359 252 : save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
3360 : PQExpBuffer query_buf)
3361 : {
3362 252 : if (query_buf)
3363 252 : conditional_stack_set_query_len(cstack, query_buf->len);
3364 252 : conditional_stack_set_paren_depth(cstack,
3365 : psql_scan_get_paren_depth(scan_state));
3366 252 : }
3367 :
3368 : /*
3369 : * Discard any query text absorbed during an inactive conditional branch.
3370 : *
3371 : * We must discard data that was appended to query_buf during an inactive
3372 : * \if branch. We don't have to do anything there if there's no query_buf.
3373 : *
3374 : * Also, reset the lexer state to the same paren depth there was before.
3375 : * (The rest of its state doesn't need attention, since we could not be
3376 : * inside a comment or literal or partial token.)
3377 : */
3378 : static void
3379 216 : discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
3380 : PQExpBuffer query_buf)
3381 : {
3382 216 : if (query_buf)
3383 : {
3384 216 : int new_len = conditional_stack_get_query_len(cstack);
3385 :
3386 : Assert(new_len >= 0 && new_len <= query_buf->len);
3387 216 : query_buf->len = new_len;
3388 216 : query_buf->data[new_len] = '\0';
3389 : }
3390 216 : psql_scan_set_paren_depth(scan_state,
3391 : conditional_stack_get_paren_depth(cstack));
3392 216 : }
3393 :
3394 : /*
3395 : * If query_buf is empty, copy previous_buf into it.
3396 : *
3397 : * This is used by various slash commands for which re-execution of a
3398 : * previous query is a common usage. For convenience, we allow the
3399 : * case of query_buf == NULL (and do nothing).
3400 : *
3401 : * Returns "true" if the previous query was copied into the query
3402 : * buffer, else "false".
3403 : */
3404 : static bool
3405 1298 : copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
3406 : {
3407 1298 : if (query_buf && query_buf->len == 0)
3408 : {
3409 192 : appendPQExpBufferStr(query_buf, previous_buf->data);
3410 192 : return true;
3411 : }
3412 1106 : return false;
3413 : }
3414 :
3415 : /*
3416 : * Ask the user for a password; 'username' is the username the
3417 : * password is for, if one has been explicitly specified.
3418 : * Returns a malloc'd string.
3419 : * If 'canceled' is provided, *canceled will be set to true if the prompt
3420 : * is canceled via SIGINT, and to false otherwise.
3421 : */
3422 : static char *
3423 0 : prompt_for_password(const char *username, bool *canceled)
3424 : {
3425 : char *result;
3426 : PromptInterruptContext prompt_ctx;
3427 :
3428 : /* Set up to let SIGINT cancel simple_prompt_extended() */
3429 0 : prompt_ctx.jmpbuf = sigint_interrupt_jmp;
3430 0 : prompt_ctx.enabled = &sigint_interrupt_enabled;
3431 0 : prompt_ctx.canceled = false;
3432 :
3433 0 : if (username == NULL || username[0] == '\0')
3434 0 : result = simple_prompt_extended("Password: ", false, &prompt_ctx);
3435 : else
3436 : {
3437 : char *prompt_text;
3438 :
3439 0 : prompt_text = psprintf(_("Password for user %s: "), username);
3440 0 : result = simple_prompt_extended(prompt_text, false, &prompt_ctx);
3441 0 : free(prompt_text);
3442 : }
3443 :
3444 0 : if (canceled)
3445 0 : *canceled = prompt_ctx.canceled;
3446 :
3447 0 : return result;
3448 : }
3449 :
3450 : static bool
3451 48 : param_is_newly_set(const char *old_val, const char *new_val)
3452 : {
3453 48 : if (new_val == NULL)
3454 0 : return false;
3455 :
3456 48 : if (old_val == NULL || strcmp(old_val, new_val) != 0)
3457 0 : return true;
3458 :
3459 48 : return false;
3460 : }
3461 :
3462 : /*
3463 : * do_connect -- handler for \connect
3464 : *
3465 : * Connects to a database with given parameters. If we are told to re-use
3466 : * parameters, parameters from the previous connection are used where the
3467 : * command's own options do not supply a value. Otherwise, libpq defaults
3468 : * are used.
3469 : *
3470 : * In interactive mode, if connection fails with the given parameters,
3471 : * the old connection will be kept.
3472 : */
3473 : static bool
3474 324 : do_connect(enum trivalue reuse_previous_specification,
3475 : char *dbname, char *user, char *host, char *port)
3476 : {
3477 324 : PGconn *o_conn = pset.db,
3478 324 : *n_conn = NULL;
3479 : PQconninfoOption *cinfo;
3480 324 : int nconnopts = 0;
3481 324 : bool same_host = false;
3482 324 : char *password = NULL;
3483 : char *client_encoding;
3484 324 : bool success = true;
3485 324 : bool keep_password = true;
3486 : bool has_connection_string;
3487 : bool reuse_previous;
3488 :
3489 324 : has_connection_string = dbname ?
3490 324 : recognized_connection_string(dbname) : false;
3491 :
3492 : /* Complain if we have additional arguments after a connection string. */
3493 324 : if (has_connection_string && (user || host || port))
3494 : {
3495 0 : pg_log_error("Do not give user, host, or port separately when using a connection string");
3496 0 : return false;
3497 : }
3498 :
3499 324 : switch (reuse_previous_specification)
3500 : {
3501 22 : case TRI_YES:
3502 22 : reuse_previous = true;
3503 22 : break;
3504 0 : case TRI_NO:
3505 0 : reuse_previous = false;
3506 0 : break;
3507 302 : default:
3508 302 : reuse_previous = !has_connection_string;
3509 302 : break;
3510 : }
3511 :
3512 : /*
3513 : * If we intend to re-use connection parameters, collect them out of the
3514 : * old connection, then replace individual values as necessary. (We may
3515 : * need to resort to looking at pset.dead_conn, if the connection died
3516 : * previously.) Otherwise, obtain a PQconninfoOption array containing
3517 : * libpq's defaults, and modify that. Note this function assumes that
3518 : * PQconninfo, PQconndefaults, and PQconninfoParse will all produce arrays
3519 : * containing the same options in the same order.
3520 : */
3521 324 : if (reuse_previous)
3522 : {
3523 324 : if (o_conn)
3524 324 : cinfo = PQconninfo(o_conn);
3525 0 : else if (pset.dead_conn)
3526 0 : cinfo = PQconninfo(pset.dead_conn);
3527 : else
3528 : {
3529 : /* This is reachable after a non-interactive \connect failure */
3530 0 : pg_log_error("No database connection exists to re-use parameters from");
3531 0 : return false;
3532 : }
3533 : }
3534 : else
3535 0 : cinfo = PQconndefaults();
3536 :
3537 324 : if (cinfo)
3538 : {
3539 324 : if (has_connection_string)
3540 : {
3541 : /* Parse the connstring and insert values into cinfo */
3542 : PQconninfoOption *replcinfo;
3543 : char *errmsg;
3544 :
3545 22 : replcinfo = PQconninfoParse(dbname, &errmsg);
3546 22 : if (replcinfo)
3547 : {
3548 : PQconninfoOption *ci;
3549 : PQconninfoOption *replci;
3550 22 : bool have_password = false;
3551 :
3552 22 : for (ci = cinfo, replci = replcinfo;
3553 968 : ci->keyword && replci->keyword;
3554 946 : ci++, replci++)
3555 : {
3556 : Assert(strcmp(ci->keyword, replci->keyword) == 0);
3557 : /* Insert value from connstring if one was provided */
3558 946 : if (replci->val)
3559 : {
3560 : /*
3561 : * We know that both val strings were allocated by
3562 : * libpq, so the least messy way to avoid memory leaks
3563 : * is to swap them.
3564 : */
3565 28 : char *swap = replci->val;
3566 :
3567 28 : replci->val = ci->val;
3568 28 : ci->val = swap;
3569 :
3570 : /*
3571 : * Check whether connstring provides options affecting
3572 : * password re-use. While any change in user, host,
3573 : * hostaddr, or port causes us to ignore the old
3574 : * connection's password, we don't force that for
3575 : * dbname, since passwords aren't database-specific.
3576 : */
3577 28 : if (replci->val == NULL ||
3578 28 : strcmp(ci->val, replci->val) != 0)
3579 : {
3580 28 : if (strcmp(replci->keyword, "user") == 0 ||
3581 22 : strcmp(replci->keyword, "host") == 0 ||
3582 22 : strcmp(replci->keyword, "hostaddr") == 0 ||
3583 22 : strcmp(replci->keyword, "port") == 0)
3584 6 : keep_password = false;
3585 : }
3586 : /* Also note whether connstring contains a password. */
3587 28 : if (strcmp(replci->keyword, "password") == 0)
3588 0 : have_password = true;
3589 : }
3590 918 : else if (!reuse_previous)
3591 : {
3592 : /*
3593 : * When we have a connstring and are not re-using
3594 : * parameters, swap *all* entries, even those not set
3595 : * by the connstring. This avoids absorbing
3596 : * environment-dependent defaults from the result of
3597 : * PQconndefaults(). We don't want to do that because
3598 : * they'd override service-file entries if the
3599 : * connstring specifies a service parameter, whereas
3600 : * the priority should be the other way around. libpq
3601 : * can certainly recompute any defaults we don't pass
3602 : * here. (In this situation, it's a bit wasteful to
3603 : * have called PQconndefaults() at all, but not doing
3604 : * so would require yet another major code path here.)
3605 : */
3606 0 : replci->val = ci->val;
3607 0 : ci->val = NULL;
3608 : }
3609 : }
3610 : Assert(ci->keyword == NULL && replci->keyword == NULL);
3611 :
3612 : /* While here, determine how many option slots there are */
3613 22 : nconnopts = ci - cinfo;
3614 :
3615 22 : PQconninfoFree(replcinfo);
3616 :
3617 : /*
3618 : * If the connstring contains a password, tell the loop below
3619 : * that we may use it, regardless of other settings (i.e.,
3620 : * cinfo's password is no longer an "old" password).
3621 : */
3622 22 : if (have_password)
3623 0 : keep_password = true;
3624 :
3625 : /* Don't let code below try to inject dbname into params. */
3626 22 : dbname = NULL;
3627 : }
3628 : else
3629 : {
3630 : /* PQconninfoParse failed */
3631 0 : if (errmsg)
3632 : {
3633 0 : pg_log_error("%s", errmsg);
3634 0 : PQfreemem(errmsg);
3635 : }
3636 : else
3637 0 : pg_log_error("out of memory");
3638 0 : success = false;
3639 : }
3640 : }
3641 : else
3642 : {
3643 : /*
3644 : * If dbname isn't a connection string, then we'll inject it and
3645 : * the other parameters into the keyword array below. (We can't
3646 : * easily insert them into the cinfo array because of memory
3647 : * management issues: PQconninfoFree would misbehave on Windows.)
3648 : * However, to avoid dependencies on the order in which parameters
3649 : * appear in the array, make a preliminary scan to set
3650 : * keep_password and same_host correctly.
3651 : *
3652 : * While any change in user, host, or port causes us to ignore the
3653 : * old connection's password, we don't force that for dbname,
3654 : * since passwords aren't database-specific.
3655 : */
3656 : PQconninfoOption *ci;
3657 :
3658 13288 : for (ci = cinfo; ci->keyword; ci++)
3659 : {
3660 12986 : if (user && strcmp(ci->keyword, "user") == 0)
3661 : {
3662 8 : if (!(ci->val && strcmp(user, ci->val) == 0))
3663 8 : keep_password = false;
3664 : }
3665 12978 : else if (host && strcmp(ci->keyword, "host") == 0)
3666 : {
3667 0 : if (ci->val && strcmp(host, ci->val) == 0)
3668 0 : same_host = true;
3669 : else
3670 0 : keep_password = false;
3671 : }
3672 12978 : else if (port && strcmp(ci->keyword, "port") == 0)
3673 : {
3674 0 : if (!(ci->val && strcmp(port, ci->val) == 0))
3675 0 : keep_password = false;
3676 : }
3677 : }
3678 :
3679 : /* While here, determine how many option slots there are */
3680 302 : nconnopts = ci - cinfo;
3681 : }
3682 : }
3683 : else
3684 : {
3685 : /* We failed to create the cinfo structure */
3686 0 : pg_log_error("out of memory");
3687 0 : success = false;
3688 : }
3689 :
3690 : /*
3691 : * If the user asked to be prompted for a password, ask for one now. If
3692 : * not, use the password from the old connection, provided the username
3693 : * etc have not changed. Otherwise, try to connect without a password
3694 : * first, and then ask for a password if needed.
3695 : *
3696 : * XXX: this behavior leads to spurious connection attempts recorded in
3697 : * the postmaster's log. But libpq offers no API that would let us obtain
3698 : * a password and then continue with the first connection attempt.
3699 : */
3700 324 : if (pset.getPassword == TRI_YES && success)
3701 : {
3702 0 : bool canceled = false;
3703 :
3704 : /*
3705 : * If a connstring or URI is provided, we don't know which username
3706 : * will be used, since we haven't dug that out of the connstring.
3707 : * Don't risk issuing a misleading prompt. As in startup.c, it does
3708 : * not seem worth working harder, since this getPassword setting is
3709 : * normally only used in noninteractive cases.
3710 : */
3711 0 : password = prompt_for_password(has_connection_string ? NULL : user,
3712 : &canceled);
3713 0 : success = !canceled;
3714 : }
3715 :
3716 : /*
3717 : * Consider whether to force client_encoding to "auto" (overriding
3718 : * anything in the connection string). We do so if we have a terminal
3719 : * connection and there is no PGCLIENTENCODING environment setting.
3720 : */
3721 324 : if (pset.notty || getenv("PGCLIENTENCODING"))
3722 324 : client_encoding = NULL;
3723 : else
3724 0 : client_encoding = "auto";
3725 :
3726 : /* Loop till we have a connection or fail, which we might've already */
3727 324 : while (success)
3728 : {
3729 324 : const char **keywords = pg_malloc((nconnopts + 1) * sizeof(*keywords));
3730 324 : const char **values = pg_malloc((nconnopts + 1) * sizeof(*values));
3731 324 : int paramnum = 0;
3732 : PQconninfoOption *ci;
3733 :
3734 : /*
3735 : * Copy non-default settings into the PQconnectdbParams parameter
3736 : * arrays; but inject any values specified old-style, as well as any
3737 : * interactively-obtained password, and a couple of fields we want to
3738 : * set forcibly.
3739 : *
3740 : * If you change this code, see also the initial-connection code in
3741 : * main().
3742 : */
3743 14256 : for (ci = cinfo; ci->keyword; ci++)
3744 : {
3745 13932 : keywords[paramnum] = ci->keyword;
3746 :
3747 13932 : if (dbname && strcmp(ci->keyword, "dbname") == 0)
3748 12 : values[paramnum++] = dbname;
3749 13920 : else if (user && strcmp(ci->keyword, "user") == 0)
3750 8 : values[paramnum++] = user;
3751 13912 : else if (host && strcmp(ci->keyword, "host") == 0)
3752 0 : values[paramnum++] = host;
3753 13912 : else if (host && !same_host && strcmp(ci->keyword, "hostaddr") == 0)
3754 : {
3755 : /* If we're changing the host value, drop any old hostaddr */
3756 0 : values[paramnum++] = NULL;
3757 : }
3758 13912 : else if (port && strcmp(ci->keyword, "port") == 0)
3759 0 : values[paramnum++] = port;
3760 : /* If !keep_password, we unconditionally drop old password */
3761 13912 : else if ((password || !keep_password) &&
3762 594 : strcmp(ci->keyword, "password") == 0)
3763 14 : values[paramnum++] = password;
3764 13898 : else if (strcmp(ci->keyword, "fallback_application_name") == 0)
3765 324 : values[paramnum++] = pset.progname;
3766 13574 : else if (client_encoding &&
3767 0 : strcmp(ci->keyword, "client_encoding") == 0)
3768 0 : values[paramnum++] = client_encoding;
3769 13574 : else if (ci->val)
3770 6160 : values[paramnum++] = ci->val;
3771 : /* else, don't bother making libpq parse this keyword */
3772 : }
3773 : /* add array terminator */
3774 324 : keywords[paramnum] = NULL;
3775 324 : values[paramnum] = NULL;
3776 :
3777 : /* Note we do not want libpq to re-expand the dbname parameter */
3778 324 : n_conn = PQconnectStartParams(keywords, values, false);
3779 :
3780 324 : pg_free(keywords);
3781 324 : pg_free(values);
3782 :
3783 324 : wait_until_connected(n_conn);
3784 324 : if (PQstatus(n_conn) == CONNECTION_OK)
3785 324 : break;
3786 :
3787 : /*
3788 : * Connection attempt failed; either retry the connection attempt with
3789 : * a new password, or give up.
3790 : */
3791 0 : if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
3792 : {
3793 0 : bool canceled = false;
3794 :
3795 : /*
3796 : * Prompt for password using the username we actually connected
3797 : * with --- it might've come out of "dbname" rather than "user".
3798 : */
3799 0 : password = prompt_for_password(PQuser(n_conn), &canceled);
3800 0 : PQfinish(n_conn);
3801 0 : n_conn = NULL;
3802 0 : success = !canceled;
3803 0 : continue;
3804 : }
3805 :
3806 : /*
3807 : * We'll report the error below ... unless n_conn is NULL, indicating
3808 : * that libpq didn't have enough memory to make a PGconn.
3809 : */
3810 0 : if (n_conn == NULL)
3811 0 : pg_log_error("out of memory");
3812 :
3813 0 : success = false;
3814 : } /* end retry loop */
3815 :
3816 : /* Release locally allocated data, whether we succeeded or not */
3817 324 : pg_free(password);
3818 324 : PQconninfoFree(cinfo);
3819 :
3820 324 : if (!success)
3821 : {
3822 : /*
3823 : * Failed to connect to the database. In interactive mode, keep the
3824 : * previous connection to the DB; in scripting mode, close our
3825 : * previous connection as well.
3826 : */
3827 0 : if (pset.cur_cmd_interactive)
3828 : {
3829 0 : if (n_conn)
3830 : {
3831 0 : pg_log_info("%s", PQerrorMessage(n_conn));
3832 0 : PQfinish(n_conn);
3833 : }
3834 :
3835 : /* pset.db is left unmodified */
3836 0 : if (o_conn)
3837 0 : pg_log_info("Previous connection kept");
3838 : }
3839 : else
3840 : {
3841 0 : if (n_conn)
3842 : {
3843 0 : pg_log_error("\\connect: %s", PQerrorMessage(n_conn));
3844 0 : PQfinish(n_conn);
3845 : }
3846 :
3847 0 : if (o_conn)
3848 : {
3849 : /*
3850 : * Transition to having no connection.
3851 : *
3852 : * Unlike CheckConnection(), we close the old connection
3853 : * immediately to prevent its parameters from being re-used.
3854 : * This is so that a script cannot accidentally reuse
3855 : * parameters it did not expect to. Otherwise, the state
3856 : * cleanup should be the same as in CheckConnection().
3857 : */
3858 0 : PQfinish(o_conn);
3859 0 : pset.db = NULL;
3860 0 : ResetCancelConn();
3861 0 : UnsyncVariables();
3862 : }
3863 :
3864 : /* On the same reasoning, release any dead_conn to prevent reuse */
3865 0 : if (pset.dead_conn)
3866 : {
3867 0 : PQfinish(pset.dead_conn);
3868 0 : pset.dead_conn = NULL;
3869 : }
3870 : }
3871 :
3872 0 : return false;
3873 : }
3874 :
3875 : /*
3876 : * Replace the old connection with the new one, and update
3877 : * connection-dependent variables. Keep the resynchronization logic in
3878 : * sync with CheckConnection().
3879 : */
3880 324 : PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
3881 324 : pset.db = n_conn;
3882 324 : SyncVariables();
3883 324 : connection_warnings(false); /* Must be after SyncVariables */
3884 :
3885 : /* Tell the user about the new connection */
3886 324 : if (!pset.quiet)
3887 : {
3888 48 : if (!o_conn ||
3889 48 : param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
3890 24 : param_is_newly_set(PQport(o_conn), PQport(pset.db)))
3891 0 : {
3892 0 : char *connhost = PQhost(pset.db);
3893 0 : char *hostaddr = PQhostaddr(pset.db);
3894 :
3895 0 : if (is_unixsock_path(connhost))
3896 : {
3897 : /* hostaddr overrides connhost */
3898 0 : if (hostaddr && *hostaddr)
3899 0 : printf(_("You are now connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
3900 : PQdb(pset.db), PQuser(pset.db), hostaddr, PQport(pset.db));
3901 : else
3902 0 : printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
3903 : PQdb(pset.db), PQuser(pset.db), connhost, PQport(pset.db));
3904 : }
3905 : else
3906 : {
3907 0 : if (hostaddr && *hostaddr && strcmp(connhost, hostaddr) != 0)
3908 0 : printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
3909 : PQdb(pset.db), PQuser(pset.db), connhost, hostaddr, PQport(pset.db));
3910 : else
3911 0 : printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
3912 : PQdb(pset.db), PQuser(pset.db), connhost, PQport(pset.db));
3913 : }
3914 : }
3915 : else
3916 24 : printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
3917 : PQdb(pset.db), PQuser(pset.db));
3918 : }
3919 :
3920 : /* Drop no-longer-needed connection(s) */
3921 324 : if (o_conn)
3922 324 : PQfinish(o_conn);
3923 324 : if (pset.dead_conn)
3924 : {
3925 0 : PQfinish(pset.dead_conn);
3926 0 : pset.dead_conn = NULL;
3927 : }
3928 :
3929 324 : return true;
3930 : }
3931 :
3932 : /*
3933 : * Processes the connection sequence described by PQconnectStartParams(). Don't
3934 : * worry about reporting errors in this function. Our caller will check the
3935 : * connection's status, and report appropriately.
3936 : */
3937 : static void
3938 324 : wait_until_connected(PGconn *conn)
3939 : {
3940 324 : bool forRead = false;
3941 :
3942 : while (true)
3943 336 : {
3944 : int rc;
3945 : int sock;
3946 : pg_usec_time_t end_time;
3947 :
3948 : /*
3949 : * On every iteration of the connection sequence, let's check if the
3950 : * user has requested a cancellation.
3951 : */
3952 660 : if (cancel_pressed)
3953 0 : break;
3954 :
3955 : /*
3956 : * Do not assume that the socket remains the same across
3957 : * PQconnectPoll() calls.
3958 : */
3959 660 : sock = PQsocket(conn);
3960 660 : if (sock == -1)
3961 0 : break;
3962 :
3963 : /*
3964 : * If the user sends SIGINT between the cancel_pressed check, and
3965 : * polling of the socket, it will not be recognized. Instead, we will
3966 : * just wait until the next step in the connection sequence or
3967 : * forever, which might require users to send SIGTERM or SIGQUIT.
3968 : *
3969 : * Some solutions would include the "self-pipe trick," using
3970 : * pselect(2) and ppoll(2), or using a timeout.
3971 : *
3972 : * The self-pipe trick requires a bit of code to setup. pselect(2) and
3973 : * ppoll(2) are not on all the platforms we support. The simplest
3974 : * solution happens to just be adding a timeout, so let's wait for 1
3975 : * second and check cancel_pressed again.
3976 : */
3977 660 : end_time = PQgetCurrentTimeUSec() + 1000000;
3978 660 : rc = PQsocketPoll(sock, forRead, !forRead, end_time);
3979 660 : if (rc == -1)
3980 0 : return;
3981 :
3982 660 : switch (PQconnectPoll(conn))
3983 : {
3984 324 : case PGRES_POLLING_OK:
3985 : case PGRES_POLLING_FAILED:
3986 324 : return;
3987 336 : case PGRES_POLLING_READING:
3988 336 : forRead = true;
3989 336 : continue;
3990 0 : case PGRES_POLLING_WRITING:
3991 0 : forRead = false;
3992 0 : continue;
3993 : case PGRES_POLLING_ACTIVE:
3994 : pg_unreachable();
3995 : }
3996 : }
3997 : }
3998 :
3999 : void
4000 328 : connection_warnings(bool in_startup)
4001 : {
4002 328 : if (!pset.quiet && !pset.notty)
4003 : {
4004 4 : int client_ver = PG_VERSION_NUM;
4005 : char cverbuf[32];
4006 : char sverbuf[32];
4007 :
4008 4 : if (pset.sversion != client_ver)
4009 : {
4010 : const char *server_version;
4011 :
4012 : /* Try to get full text form, might include "devel" etc */
4013 0 : server_version = PQparameterStatus(pset.db, "server_version");
4014 : /* Otherwise fall back on pset.sversion */
4015 0 : if (!server_version)
4016 : {
4017 0 : formatPGVersionNumber(pset.sversion, true,
4018 : sverbuf, sizeof(sverbuf));
4019 0 : server_version = sverbuf;
4020 : }
4021 :
4022 0 : printf(_("%s (%s, server %s)\n"),
4023 : pset.progname, PG_VERSION, server_version);
4024 : }
4025 : /* For version match, only print psql banner on startup. */
4026 4 : else if (in_startup)
4027 4 : printf("%s (%s)\n", pset.progname, PG_VERSION);
4028 :
4029 : /*
4030 : * Warn if server's major version is newer than ours, or if server
4031 : * predates our support cutoff (currently 9.2).
4032 : */
4033 4 : if (pset.sversion / 100 > client_ver / 100 ||
4034 4 : pset.sversion < 90200)
4035 0 : printf(_("WARNING: %s major version %s, server major version %s.\n"
4036 : " Some psql features might not work.\n"),
4037 : pset.progname,
4038 : formatPGVersionNumber(client_ver, false,
4039 : cverbuf, sizeof(cverbuf)),
4040 : formatPGVersionNumber(pset.sversion, false,
4041 : sverbuf, sizeof(sverbuf)));
4042 :
4043 : #ifdef WIN32
4044 : if (in_startup)
4045 : checkWin32Codepage();
4046 : #endif
4047 4 : printSSLInfo();
4048 4 : printGSSInfo();
4049 : }
4050 328 : }
4051 :
4052 :
4053 : /*
4054 : * printSSLInfo
4055 : *
4056 : * Prints information about the current SSL connection, if SSL is in use
4057 : */
4058 : static void
4059 4 : printSSLInfo(void)
4060 : {
4061 : const char *protocol;
4062 : const char *cipher;
4063 : const char *compression;
4064 : const char *alpn;
4065 :
4066 4 : if (!PQsslInUse(pset.db))
4067 4 : return; /* no SSL */
4068 :
4069 0 : protocol = PQsslAttribute(pset.db, "protocol");
4070 0 : cipher = PQsslAttribute(pset.db, "cipher");
4071 0 : compression = PQsslAttribute(pset.db, "compression");
4072 0 : alpn = PQsslAttribute(pset.db, "alpn");
4073 :
4074 0 : printf(_("SSL connection (protocol: %s, cipher: %s, compression: %s, ALPN: %s)\n"),
4075 : protocol ? protocol : _("unknown"),
4076 : cipher ? cipher : _("unknown"),
4077 : (compression && strcmp(compression, "off") != 0) ? _("on") : _("off"),
4078 : (alpn && alpn[0] != '\0') ? alpn : _("none"));
4079 : }
4080 :
4081 : /*
4082 : * printGSSInfo
4083 : *
4084 : * Prints information about the current GSSAPI connection, if GSSAPI encryption is in use
4085 : */
4086 : static void
4087 4 : printGSSInfo(void)
4088 : {
4089 4 : if (!PQgssEncInUse(pset.db))
4090 4 : return; /* no GSSAPI encryption in use */
4091 :
4092 0 : printf(_("GSSAPI-encrypted connection\n"));
4093 : }
4094 :
4095 :
4096 : /*
4097 : * checkWin32Codepage
4098 : *
4099 : * Prints a warning when win32 console codepage differs from Windows codepage
4100 : */
4101 : #ifdef WIN32
4102 : static void
4103 : checkWin32Codepage(void)
4104 : {
4105 : unsigned int wincp,
4106 : concp;
4107 :
4108 : wincp = GetACP();
4109 : concp = GetConsoleCP();
4110 : if (wincp != concp)
4111 : {
4112 : printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
4113 : " 8-bit characters might not work correctly. See psql reference\n"
4114 : " page \"Notes for Windows users\" for details.\n"),
4115 : concp, wincp);
4116 : }
4117 : }
4118 : #endif
4119 :
4120 :
4121 : /*
4122 : * SyncVariables
4123 : *
4124 : * Make psql's internal variables agree with connection state upon
4125 : * establishing a new connection.
4126 : */
4127 : void
4128 16380 : SyncVariables(void)
4129 : {
4130 : char vbuf[32];
4131 : const char *server_version;
4132 :
4133 : /* get stuff from connection */
4134 16380 : pset.encoding = PQclientEncoding(pset.db);
4135 16380 : pset.popt.topt.encoding = pset.encoding;
4136 16380 : pset.sversion = PQserverVersion(pset.db);
4137 :
4138 16380 : SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
4139 16380 : SetVariable(pset.vars, "SERVICE", PQservice(pset.db));
4140 16380 : SetVariable(pset.vars, "USER", PQuser(pset.db));
4141 16380 : SetVariable(pset.vars, "HOST", PQhost(pset.db));
4142 16380 : SetVariable(pset.vars, "PORT", PQport(pset.db));
4143 16380 : SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
4144 :
4145 : /* this bit should match connection_warnings(): */
4146 : /* Try to get full text form of version, might include "devel" etc */
4147 16380 : server_version = PQparameterStatus(pset.db, "server_version");
4148 : /* Otherwise fall back on pset.sversion */
4149 16380 : if (!server_version)
4150 : {
4151 0 : formatPGVersionNumber(pset.sversion, true, vbuf, sizeof(vbuf));
4152 0 : server_version = vbuf;
4153 : }
4154 16380 : SetVariable(pset.vars, "SERVER_VERSION_NAME", server_version);
4155 :
4156 16380 : snprintf(vbuf, sizeof(vbuf), "%d", pset.sversion);
4157 16380 : SetVariable(pset.vars, "SERVER_VERSION_NUM", vbuf);
4158 :
4159 : /* send stuff to it, too */
4160 16380 : PQsetErrorVerbosity(pset.db, pset.verbosity);
4161 16380 : PQsetErrorContextVisibility(pset.db, pset.show_context);
4162 16380 : }
4163 :
4164 : /*
4165 : * UnsyncVariables
4166 : *
4167 : * Clear variables that should be not be set when there is no connection.
4168 : */
4169 : void
4170 0 : UnsyncVariables(void)
4171 : {
4172 0 : SetVariable(pset.vars, "DBNAME", NULL);
4173 0 : SetVariable(pset.vars, "SERVICE", NULL);
4174 0 : SetVariable(pset.vars, "USER", NULL);
4175 0 : SetVariable(pset.vars, "HOST", NULL);
4176 0 : SetVariable(pset.vars, "PORT", NULL);
4177 0 : SetVariable(pset.vars, "ENCODING", NULL);
4178 0 : SetVariable(pset.vars, "SERVER_VERSION_NAME", NULL);
4179 0 : SetVariable(pset.vars, "SERVER_VERSION_NUM", NULL);
4180 0 : }
4181 :
4182 :
4183 : /*
4184 : * helper for do_edit(): actually invoke the editor
4185 : *
4186 : * Returns true on success, false if we failed to invoke the editor or
4187 : * it returned nonzero status. (An error message is printed for failed-
4188 : * to-invoke cases, but not if the editor returns nonzero status.)
4189 : */
4190 : static bool
4191 0 : editFile(const char *fname, int lineno)
4192 : {
4193 : const char *editorName;
4194 0 : const char *editor_lineno_arg = NULL;
4195 : char *sys;
4196 : int result;
4197 :
4198 : Assert(fname != NULL);
4199 :
4200 : /* Find an editor to use */
4201 0 : editorName = getenv("PSQL_EDITOR");
4202 0 : if (!editorName)
4203 0 : editorName = getenv("EDITOR");
4204 0 : if (!editorName)
4205 0 : editorName = getenv("VISUAL");
4206 0 : if (!editorName)
4207 0 : editorName = DEFAULT_EDITOR;
4208 :
4209 : /* Get line number argument, if we need it. */
4210 0 : if (lineno > 0)
4211 : {
4212 0 : editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
4213 : #ifdef DEFAULT_EDITOR_LINENUMBER_ARG
4214 0 : if (!editor_lineno_arg)
4215 0 : editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
4216 : #endif
4217 0 : if (!editor_lineno_arg)
4218 : {
4219 0 : pg_log_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number");
4220 0 : return false;
4221 : }
4222 : }
4223 :
4224 : /*
4225 : * On Unix the EDITOR value should *not* be quoted, since it might include
4226 : * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
4227 : * if necessary. But this policy is not very workable on Windows, due to
4228 : * severe brain damage in their command shell plus the fact that standard
4229 : * program paths include spaces.
4230 : */
4231 : #ifndef WIN32
4232 0 : if (lineno > 0)
4233 0 : sys = psprintf("exec %s %s%d '%s'",
4234 : editorName, editor_lineno_arg, lineno, fname);
4235 : else
4236 0 : sys = psprintf("exec %s '%s'",
4237 : editorName, fname);
4238 : #else
4239 : if (lineno > 0)
4240 : sys = psprintf("\"%s\" %s%d \"%s\"",
4241 : editorName, editor_lineno_arg, lineno, fname);
4242 : else
4243 : sys = psprintf("\"%s\" \"%s\"",
4244 : editorName, fname);
4245 : #endif
4246 0 : fflush(NULL);
4247 0 : result = system(sys);
4248 0 : if (result == -1)
4249 0 : pg_log_error("could not start editor \"%s\"", editorName);
4250 0 : else if (result == 127)
4251 0 : pg_log_error("could not start /bin/sh");
4252 0 : free(sys);
4253 :
4254 0 : return result == 0;
4255 : }
4256 :
4257 :
4258 : /*
4259 : * do_edit -- handler for \e
4260 : *
4261 : * If you do not specify a filename, the current query buffer will be copied
4262 : * into a temporary file.
4263 : *
4264 : * After this function is done, the resulting file will be copied back into the
4265 : * query buffer. As an exception to this, the query buffer will be emptied
4266 : * if the file was not modified (or the editor failed) and the caller passes
4267 : * "discard_on_quit" = true.
4268 : *
4269 : * If "edited" isn't NULL, *edited will be set to true if the query buffer
4270 : * is successfully replaced.
4271 : */
4272 : static bool
4273 0 : do_edit(const char *filename_arg, PQExpBuffer query_buf,
4274 : int lineno, bool discard_on_quit, bool *edited)
4275 : {
4276 : char fnametmp[MAXPGPATH];
4277 0 : FILE *stream = NULL;
4278 : const char *fname;
4279 0 : bool error = false;
4280 : int fd;
4281 : struct stat before,
4282 : after;
4283 :
4284 0 : if (filename_arg)
4285 0 : fname = filename_arg;
4286 : else
4287 : {
4288 : /* make a temp file to edit */
4289 : #ifndef WIN32
4290 0 : const char *tmpdir = getenv("TMPDIR");
4291 :
4292 0 : if (!tmpdir)
4293 0 : tmpdir = "/tmp";
4294 : #else
4295 : char tmpdir[MAXPGPATH];
4296 : int ret;
4297 :
4298 : ret = GetTempPath(MAXPGPATH, tmpdir);
4299 : if (ret == 0 || ret > MAXPGPATH)
4300 : {
4301 : pg_log_error("could not locate temporary directory: %s",
4302 : !ret ? strerror(errno) : "");
4303 : return false;
4304 : }
4305 : #endif
4306 :
4307 : /*
4308 : * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
4309 : * current directory to the supplied path unless we use only
4310 : * backslashes, so we do that.
4311 : */
4312 : #ifndef WIN32
4313 0 : snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
4314 0 : "/", (int) getpid());
4315 : #else
4316 : snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
4317 : "" /* trailing separator already present */ , (int) getpid());
4318 : #endif
4319 :
4320 0 : fname = (const char *) fnametmp;
4321 :
4322 0 : fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
4323 0 : if (fd != -1)
4324 0 : stream = fdopen(fd, "w");
4325 :
4326 0 : if (fd == -1 || !stream)
4327 : {
4328 0 : pg_log_error("could not open temporary file \"%s\": %m", fname);
4329 0 : error = true;
4330 : }
4331 : else
4332 : {
4333 0 : unsigned int ql = query_buf->len;
4334 :
4335 : /* force newline-termination of what we send to editor */
4336 0 : if (ql > 0 && query_buf->data[ql - 1] != '\n')
4337 : {
4338 0 : appendPQExpBufferChar(query_buf, '\n');
4339 0 : ql++;
4340 : }
4341 :
4342 0 : if (fwrite(query_buf->data, 1, ql, stream) != ql)
4343 : {
4344 0 : pg_log_error("%s: %m", fname);
4345 :
4346 0 : if (fclose(stream) != 0)
4347 0 : pg_log_error("%s: %m", fname);
4348 :
4349 0 : if (remove(fname) != 0)
4350 0 : pg_log_error("%s: %m", fname);
4351 :
4352 0 : error = true;
4353 : }
4354 0 : else if (fclose(stream) != 0)
4355 : {
4356 0 : pg_log_error("%s: %m", fname);
4357 0 : if (remove(fname) != 0)
4358 0 : pg_log_error("%s: %m", fname);
4359 0 : error = true;
4360 : }
4361 : else
4362 : {
4363 : struct utimbuf ut;
4364 :
4365 : /*
4366 : * Try to set the file modification time of the temporary file
4367 : * a few seconds in the past. Otherwise, the low granularity
4368 : * (one second, or even worse on some filesystems) that we can
4369 : * portably measure with stat(2) could lead us to not
4370 : * recognize a modification, if the user typed very quickly.
4371 : *
4372 : * This is a rather unlikely race condition, so don't error
4373 : * out if the utime(2) call fails --- that would make the cure
4374 : * worse than the disease.
4375 : */
4376 0 : ut.modtime = ut.actime = time(NULL) - 2;
4377 0 : (void) utime(fname, &ut);
4378 : }
4379 : }
4380 : }
4381 :
4382 0 : if (!error && stat(fname, &before) != 0)
4383 : {
4384 0 : pg_log_error("%s: %m", fname);
4385 0 : error = true;
4386 : }
4387 :
4388 : /* call editor */
4389 0 : if (!error)
4390 0 : error = !editFile(fname, lineno);
4391 :
4392 0 : if (!error && stat(fname, &after) != 0)
4393 : {
4394 0 : pg_log_error("%s: %m", fname);
4395 0 : error = true;
4396 : }
4397 :
4398 : /* file was edited if the size or modification time has changed */
4399 0 : if (!error &&
4400 0 : (before.st_size != after.st_size ||
4401 0 : before.st_mtime != after.st_mtime))
4402 : {
4403 0 : stream = fopen(fname, PG_BINARY_R);
4404 0 : if (!stream)
4405 : {
4406 0 : pg_log_error("%s: %m", fname);
4407 0 : error = true;
4408 : }
4409 : else
4410 : {
4411 : /* read file back into query_buf */
4412 : char line[1024];
4413 :
4414 0 : resetPQExpBuffer(query_buf);
4415 0 : while (fgets(line, sizeof(line), stream) != NULL)
4416 0 : appendPQExpBufferStr(query_buf, line);
4417 :
4418 0 : if (ferror(stream))
4419 : {
4420 0 : pg_log_error("%s: %m", fname);
4421 0 : error = true;
4422 0 : resetPQExpBuffer(query_buf);
4423 : }
4424 0 : else if (edited)
4425 : {
4426 0 : *edited = true;
4427 : }
4428 :
4429 0 : fclose(stream);
4430 : }
4431 : }
4432 : else
4433 : {
4434 : /*
4435 : * If the file was not modified, and the caller requested it, discard
4436 : * the query buffer.
4437 : */
4438 0 : if (discard_on_quit)
4439 0 : resetPQExpBuffer(query_buf);
4440 : }
4441 :
4442 : /* remove temp file */
4443 0 : if (!filename_arg)
4444 : {
4445 0 : if (remove(fname) == -1)
4446 : {
4447 0 : pg_log_error("%s: %m", fname);
4448 0 : error = true;
4449 : }
4450 : }
4451 :
4452 0 : return !error;
4453 : }
4454 :
4455 :
4456 :
4457 : /*
4458 : * process_file
4459 : *
4460 : * Reads commands from filename and passes them to the main processing loop.
4461 : * Handler for \i and \ir, but can be used for other things as well. Returns
4462 : * MainLoop() error code.
4463 : *
4464 : * If use_relative_path is true and filename is not an absolute path, then open
4465 : * the file from where the currently processed file (if any) is located.
4466 : */
4467 : int
4468 15554 : process_file(char *filename, bool use_relative_path)
4469 : {
4470 : FILE *fd;
4471 : int result;
4472 : char *oldfilename;
4473 : char relpath[MAXPGPATH];
4474 :
4475 15554 : if (!filename)
4476 : {
4477 4284 : fd = stdin;
4478 4284 : filename = NULL;
4479 : }
4480 11270 : else if (strcmp(filename, "-") != 0)
4481 : {
4482 30 : canonicalize_path(filename);
4483 :
4484 : /*
4485 : * If we were asked to resolve the pathname relative to the location
4486 : * of the currently executing script, and there is one, and this is a
4487 : * relative pathname, then prepend all but the last pathname component
4488 : * of the current script to this pathname.
4489 : */
4490 30 : if (use_relative_path && pset.inputfile &&
4491 0 : !is_absolute_path(filename) && !has_drive_prefix(filename))
4492 : {
4493 0 : strlcpy(relpath, pset.inputfile, sizeof(relpath));
4494 0 : get_parent_directory(relpath);
4495 0 : join_path_components(relpath, relpath, filename);
4496 0 : canonicalize_path(relpath);
4497 :
4498 0 : filename = relpath;
4499 : }
4500 :
4501 30 : fd = fopen(filename, PG_BINARY_R);
4502 :
4503 30 : if (!fd)
4504 : {
4505 0 : pg_log_error("%s: %m", filename);
4506 0 : return EXIT_FAILURE;
4507 : }
4508 : }
4509 : else
4510 : {
4511 11240 : fd = stdin;
4512 11240 : filename = "<stdin>"; /* for future error messages */
4513 : }
4514 :
4515 15554 : oldfilename = pset.inputfile;
4516 15554 : pset.inputfile = filename;
4517 :
4518 15554 : pg_logging_config(pset.inputfile ? 0 : PG_LOG_FLAG_TERSE);
4519 :
4520 15554 : result = MainLoop(fd);
4521 :
4522 15534 : if (fd != stdin)
4523 30 : fclose(fd);
4524 :
4525 15534 : pset.inputfile = oldfilename;
4526 :
4527 15534 : pg_logging_config(pset.inputfile ? 0 : PG_LOG_FLAG_TERSE);
4528 :
4529 15534 : return result;
4530 : }
4531 :
4532 :
4533 :
4534 : static const char *
4535 6 : _align2string(enum printFormat in)
4536 : {
4537 6 : switch (in)
4538 : {
4539 0 : case PRINT_NOTHING:
4540 0 : return "nothing";
4541 : break;
4542 6 : case PRINT_ALIGNED:
4543 6 : return "aligned";
4544 : break;
4545 0 : case PRINT_ASCIIDOC:
4546 0 : return "asciidoc";
4547 : break;
4548 0 : case PRINT_CSV:
4549 0 : return "csv";
4550 : break;
4551 0 : case PRINT_HTML:
4552 0 : return "html";
4553 : break;
4554 0 : case PRINT_LATEX:
4555 0 : return "latex";
4556 : break;
4557 0 : case PRINT_LATEX_LONGTABLE:
4558 0 : return "latex-longtable";
4559 : break;
4560 0 : case PRINT_TROFF_MS:
4561 0 : return "troff-ms";
4562 : break;
4563 0 : case PRINT_UNALIGNED:
4564 0 : return "unaligned";
4565 : break;
4566 0 : case PRINT_WRAPPED:
4567 0 : return "wrapped";
4568 : break;
4569 : }
4570 0 : return "unknown";
4571 : }
4572 :
4573 : /*
4574 : * Parse entered Unicode linestyle. If ok, update *linestyle and return
4575 : * true, else return false.
4576 : */
4577 : static bool
4578 0 : set_unicode_line_style(const char *value, size_t vallen,
4579 : unicode_linestyle *linestyle)
4580 : {
4581 0 : if (pg_strncasecmp("single", value, vallen) == 0)
4582 0 : *linestyle = UNICODE_LINESTYLE_SINGLE;
4583 0 : else if (pg_strncasecmp("double", value, vallen) == 0)
4584 0 : *linestyle = UNICODE_LINESTYLE_DOUBLE;
4585 : else
4586 0 : return false;
4587 0 : return true;
4588 : }
4589 :
4590 : static const char *
4591 18 : _unicode_linestyle2string(int linestyle)
4592 : {
4593 18 : switch (linestyle)
4594 : {
4595 18 : case UNICODE_LINESTYLE_SINGLE:
4596 18 : return "single";
4597 : break;
4598 0 : case UNICODE_LINESTYLE_DOUBLE:
4599 0 : return "double";
4600 : break;
4601 : }
4602 0 : return "unknown";
4603 : }
4604 :
4605 : /*
4606 : * do_pset
4607 : *
4608 : * Performs the assignment "param = value", where value could be NULL;
4609 : * for some params that has an effect such as inversion, for others
4610 : * it does nothing.
4611 : *
4612 : * Adjusts the state of the formatting options at *popt. (In practice that
4613 : * is always pset.popt, but maybe someday it could be different.)
4614 : *
4615 : * If successful and quiet is false, then invokes printPsetInfo() to report
4616 : * the change.
4617 : *
4618 : * Returns true if successful, else false (eg for invalid param or value).
4619 : */
4620 : bool
4621 1914 : do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
4622 : {
4623 1914 : size_t vallen = 0;
4624 :
4625 : Assert(param != NULL);
4626 :
4627 1914 : if (value)
4628 1784 : vallen = strlen(value);
4629 :
4630 : /* set format */
4631 1914 : if (strcmp(param, "format") == 0)
4632 : {
4633 : static const struct fmt
4634 : {
4635 : const char *name;
4636 : enum printFormat number;
4637 : } formats[] =
4638 : {
4639 : /* remember to update error message below when adding more */
4640 : {"aligned", PRINT_ALIGNED},
4641 : {"asciidoc", PRINT_ASCIIDOC},
4642 : {"csv", PRINT_CSV},
4643 : {"html", PRINT_HTML},
4644 : {"latex", PRINT_LATEX},
4645 : {"troff-ms", PRINT_TROFF_MS},
4646 : {"unaligned", PRINT_UNALIGNED},
4647 : {"wrapped", PRINT_WRAPPED}
4648 : };
4649 :
4650 614 : if (!value)
4651 : ;
4652 : else
4653 : {
4654 614 : int match_pos = -1;
4655 :
4656 5484 : for (int i = 0; i < lengthof(formats); i++)
4657 : {
4658 4876 : if (pg_strncasecmp(formats[i].name, value, vallen) == 0)
4659 : {
4660 614 : if (match_pos < 0)
4661 608 : match_pos = i;
4662 : else
4663 : {
4664 6 : pg_log_error("\\pset: ambiguous abbreviation \"%s\" matches both \"%s\" and \"%s\"",
4665 : value,
4666 : formats[match_pos].name, formats[i].name);
4667 6 : return false;
4668 : }
4669 : }
4670 : }
4671 608 : if (match_pos >= 0)
4672 602 : popt->topt.format = formats[match_pos].number;
4673 6 : else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
4674 : {
4675 : /*
4676 : * We must treat latex-longtable specially because latex is a
4677 : * prefix of it; if both were in the table above, we'd think
4678 : * "latex" is ambiguous.
4679 : */
4680 6 : popt->topt.format = PRINT_LATEX_LONGTABLE;
4681 : }
4682 : else
4683 : {
4684 0 : pg_log_error("\\pset: allowed formats are aligned, asciidoc, csv, html, latex, latex-longtable, troff-ms, unaligned, wrapped");
4685 0 : return false;
4686 : }
4687 : }
4688 : }
4689 :
4690 : /* set table line style */
4691 1300 : else if (strcmp(param, "linestyle") == 0)
4692 : {
4693 30 : if (!value)
4694 : ;
4695 30 : else if (pg_strncasecmp("ascii", value, vallen) == 0)
4696 18 : popt->topt.line_style = &pg_asciiformat;
4697 12 : else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
4698 12 : popt->topt.line_style = &pg_asciiformat_old;
4699 0 : else if (pg_strncasecmp("unicode", value, vallen) == 0)
4700 0 : popt->topt.line_style = &pg_utf8format;
4701 : else
4702 : {
4703 0 : pg_log_error("\\pset: allowed line styles are ascii, old-ascii, unicode");
4704 0 : return false;
4705 : }
4706 : }
4707 :
4708 : /* set unicode border line style */
4709 1270 : else if (strcmp(param, "unicode_border_linestyle") == 0)
4710 : {
4711 0 : if (!value)
4712 : ;
4713 0 : else if (set_unicode_line_style(value, vallen,
4714 : &popt->topt.unicode_border_linestyle))
4715 0 : refresh_utf8format(&(popt->topt));
4716 : else
4717 : {
4718 0 : pg_log_error("\\pset: allowed Unicode border line styles are single, double");
4719 0 : return false;
4720 : }
4721 : }
4722 :
4723 : /* set unicode column line style */
4724 1270 : else if (strcmp(param, "unicode_column_linestyle") == 0)
4725 : {
4726 0 : if (!value)
4727 : ;
4728 0 : else if (set_unicode_line_style(value, vallen,
4729 : &popt->topt.unicode_column_linestyle))
4730 0 : refresh_utf8format(&(popt->topt));
4731 : else
4732 : {
4733 0 : pg_log_error("\\pset: allowed Unicode column line styles are single, double");
4734 0 : return false;
4735 : }
4736 : }
4737 :
4738 : /* set unicode header line style */
4739 1270 : else if (strcmp(param, "unicode_header_linestyle") == 0)
4740 : {
4741 0 : if (!value)
4742 : ;
4743 0 : else if (set_unicode_line_style(value, vallen,
4744 : &popt->topt.unicode_header_linestyle))
4745 0 : refresh_utf8format(&(popt->topt));
4746 : else
4747 : {
4748 0 : pg_log_error("\\pset: allowed Unicode header line styles are single, double");
4749 0 : return false;
4750 : }
4751 : }
4752 :
4753 : /* set border style/width */
4754 1270 : else if (strcmp(param, "border") == 0)
4755 : {
4756 402 : if (value)
4757 402 : popt->topt.border = atoi(value);
4758 : }
4759 :
4760 : /* set expanded/vertical mode */
4761 868 : else if (strcmp(param, "x") == 0 ||
4762 868 : strcmp(param, "expanded") == 0 ||
4763 538 : strcmp(param, "vertical") == 0)
4764 : {
4765 330 : if (value && pg_strcasecmp(value, "auto") == 0)
4766 0 : popt->topt.expanded = 2;
4767 330 : else if (value)
4768 : {
4769 : bool on_off;
4770 :
4771 260 : if (ParseVariableBool(value, NULL, &on_off))
4772 260 : popt->topt.expanded = on_off ? 1 : 0;
4773 : else
4774 : {
4775 0 : PsqlVarEnumError(param, value, "on, off, auto");
4776 0 : return false;
4777 : }
4778 : }
4779 : else
4780 70 : popt->topt.expanded = !popt->topt.expanded;
4781 : }
4782 :
4783 : /* header line width in expanded mode */
4784 538 : else if (strcmp(param, "xheader_width") == 0)
4785 : {
4786 0 : if (!value)
4787 : ;
4788 0 : else if (pg_strcasecmp(value, "full") == 0)
4789 0 : popt->topt.expanded_header_width_type = PRINT_XHEADER_FULL;
4790 0 : else if (pg_strcasecmp(value, "column") == 0)
4791 0 : popt->topt.expanded_header_width_type = PRINT_XHEADER_COLUMN;
4792 0 : else if (pg_strcasecmp(value, "page") == 0)
4793 0 : popt->topt.expanded_header_width_type = PRINT_XHEADER_PAGE;
4794 : else
4795 : {
4796 0 : int intval = atoi(value);
4797 :
4798 0 : if (intval == 0)
4799 : {
4800 0 : pg_log_error("\\pset: allowed xheader_width values are \"%s\" (default), \"%s\", \"%s\", or a number specifying the exact width", "full", "column", "page");
4801 0 : return false;
4802 : }
4803 :
4804 0 : popt->topt.expanded_header_width_type = PRINT_XHEADER_EXACT_WIDTH;
4805 0 : popt->topt.expanded_header_exact_width = intval;
4806 : }
4807 : }
4808 :
4809 : /* field separator for CSV format */
4810 538 : else if (strcmp(param, "csv_fieldsep") == 0)
4811 : {
4812 60 : if (value)
4813 : {
4814 : /* CSV separator has to be a one-byte character */
4815 60 : if (strlen(value) != 1)
4816 : {
4817 18 : pg_log_error("\\pset: csv_fieldsep must be a single one-byte character");
4818 18 : return false;
4819 : }
4820 42 : if (value[0] == '"' || value[0] == '\n' || value[0] == '\r')
4821 : {
4822 18 : pg_log_error("\\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return");
4823 18 : return false;
4824 : }
4825 24 : popt->topt.csvFieldSep[0] = value[0];
4826 : }
4827 : }
4828 :
4829 : /* locale-aware numeric output */
4830 478 : else if (strcmp(param, "numericlocale") == 0)
4831 : {
4832 12 : if (value)
4833 12 : return ParseVariableBool(value, param, &popt->topt.numericLocale);
4834 : else
4835 0 : popt->topt.numericLocale = !popt->topt.numericLocale;
4836 : }
4837 :
4838 : /* null display */
4839 466 : else if (strcmp(param, "null") == 0)
4840 : {
4841 78 : if (value)
4842 : {
4843 78 : free(popt->nullPrint);
4844 78 : popt->nullPrint = pg_strdup(value);
4845 : }
4846 : }
4847 :
4848 : /* field separator for unaligned text */
4849 388 : else if (strcmp(param, "fieldsep") == 0)
4850 : {
4851 6 : if (value)
4852 : {
4853 6 : free(popt->topt.fieldSep.separator);
4854 6 : popt->topt.fieldSep.separator = pg_strdup(value);
4855 6 : popt->topt.fieldSep.separator_zero = false;
4856 : }
4857 : }
4858 :
4859 382 : else if (strcmp(param, "fieldsep_zero") == 0)
4860 : {
4861 0 : free(popt->topt.fieldSep.separator);
4862 0 : popt->topt.fieldSep.separator = NULL;
4863 0 : popt->topt.fieldSep.separator_zero = true;
4864 : }
4865 :
4866 : /* record separator for unaligned text */
4867 382 : else if (strcmp(param, "recordsep") == 0)
4868 : {
4869 0 : if (value)
4870 : {
4871 0 : free(popt->topt.recordSep.separator);
4872 0 : popt->topt.recordSep.separator = pg_strdup(value);
4873 0 : popt->topt.recordSep.separator_zero = false;
4874 : }
4875 : }
4876 :
4877 382 : else if (strcmp(param, "recordsep_zero") == 0)
4878 : {
4879 0 : free(popt->topt.recordSep.separator);
4880 0 : popt->topt.recordSep.separator = NULL;
4881 0 : popt->topt.recordSep.separator_zero = true;
4882 : }
4883 :
4884 : /* toggle between full and tuples-only format */
4885 382 : else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
4886 : {
4887 280 : if (value)
4888 244 : return ParseVariableBool(value, param, &popt->topt.tuples_only);
4889 : else
4890 36 : popt->topt.tuples_only = !popt->topt.tuples_only;
4891 : }
4892 :
4893 : /* set title override */
4894 102 : else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
4895 : {
4896 6 : free(popt->title);
4897 6 : if (!value)
4898 0 : popt->title = NULL;
4899 : else
4900 6 : popt->title = pg_strdup(value);
4901 : }
4902 :
4903 : /* set HTML table tag options */
4904 96 : else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
4905 : {
4906 48 : free(popt->topt.tableAttr);
4907 48 : if (!value)
4908 24 : popt->topt.tableAttr = NULL;
4909 : else
4910 24 : popt->topt.tableAttr = pg_strdup(value);
4911 : }
4912 :
4913 : /* toggle use of pager */
4914 48 : else if (strcmp(param, "pager") == 0)
4915 : {
4916 0 : if (value && pg_strcasecmp(value, "always") == 0)
4917 0 : popt->topt.pager = 2;
4918 0 : else if (value)
4919 : {
4920 : bool on_off;
4921 :
4922 0 : if (!ParseVariableBool(value, NULL, &on_off))
4923 : {
4924 0 : PsqlVarEnumError(param, value, "on, off, always");
4925 0 : return false;
4926 : }
4927 0 : popt->topt.pager = on_off ? 1 : 0;
4928 : }
4929 0 : else if (popt->topt.pager == 1)
4930 0 : popt->topt.pager = 0;
4931 : else
4932 0 : popt->topt.pager = 1;
4933 : }
4934 :
4935 : /* set minimum lines for pager use */
4936 48 : else if (strcmp(param, "pager_min_lines") == 0)
4937 : {
4938 0 : if (value &&
4939 0 : !ParseVariableNum(value, "pager_min_lines", &popt->topt.pager_min_lines))
4940 0 : return false;
4941 : }
4942 :
4943 : /* disable "(x rows)" footer */
4944 48 : else if (strcmp(param, "footer") == 0)
4945 : {
4946 0 : if (value)
4947 0 : return ParseVariableBool(value, param, &popt->topt.default_footer);
4948 : else
4949 0 : popt->topt.default_footer = !popt->topt.default_footer;
4950 : }
4951 :
4952 : /* set border style/width */
4953 48 : else if (strcmp(param, "columns") == 0)
4954 : {
4955 48 : if (value)
4956 48 : popt->topt.columns = atoi(value);
4957 : }
4958 : else
4959 : {
4960 0 : pg_log_error("\\pset: unknown option: %s", param);
4961 0 : return false;
4962 : }
4963 :
4964 1616 : if (!quiet)
4965 0 : printPsetInfo(param, &pset.popt);
4966 :
4967 1616 : return true;
4968 : }
4969 :
4970 : /*
4971 : * printPsetInfo: print the state of the "param" formatting parameter in popt.
4972 : */
4973 : static bool
4974 0 : printPsetInfo(const char *param, printQueryOpt *popt)
4975 : {
4976 : Assert(param != NULL);
4977 :
4978 : /* show border style/width */
4979 0 : if (strcmp(param, "border") == 0)
4980 0 : printf(_("Border style is %d.\n"), popt->topt.border);
4981 :
4982 : /* show the target width for the wrapped format */
4983 0 : else if (strcmp(param, "columns") == 0)
4984 : {
4985 0 : if (!popt->topt.columns)
4986 0 : printf(_("Target width is unset.\n"));
4987 : else
4988 0 : printf(_("Target width is %d.\n"), popt->topt.columns);
4989 : }
4990 :
4991 : /* show expanded/vertical mode */
4992 0 : else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
4993 : {
4994 0 : if (popt->topt.expanded == 1)
4995 0 : printf(_("Expanded display is on.\n"));
4996 0 : else if (popt->topt.expanded == 2)
4997 0 : printf(_("Expanded display is used automatically.\n"));
4998 : else
4999 0 : printf(_("Expanded display is off.\n"));
5000 : }
5001 :
5002 : /* show xheader width value */
5003 0 : else if (strcmp(param, "xheader_width") == 0)
5004 : {
5005 0 : if (popt->topt.expanded_header_width_type == PRINT_XHEADER_FULL)
5006 0 : printf(_("Expanded header width is \"%s\".\n"), "full");
5007 0 : else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_COLUMN)
5008 0 : printf(_("Expanded header width is \"%s\".\n"), "column");
5009 0 : else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_PAGE)
5010 0 : printf(_("Expanded header width is \"%s\".\n"), "page");
5011 0 : else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
5012 0 : printf(_("Expanded header width is %d.\n"), popt->topt.expanded_header_exact_width);
5013 : }
5014 :
5015 : /* show field separator for CSV format */
5016 0 : else if (strcmp(param, "csv_fieldsep") == 0)
5017 : {
5018 0 : printf(_("Field separator for CSV is \"%s\".\n"),
5019 : popt->topt.csvFieldSep);
5020 : }
5021 :
5022 : /* show field separator for unaligned text */
5023 0 : else if (strcmp(param, "fieldsep") == 0)
5024 : {
5025 0 : if (popt->topt.fieldSep.separator_zero)
5026 0 : printf(_("Field separator is zero byte.\n"));
5027 : else
5028 0 : printf(_("Field separator is \"%s\".\n"),
5029 : popt->topt.fieldSep.separator);
5030 : }
5031 :
5032 0 : else if (strcmp(param, "fieldsep_zero") == 0)
5033 : {
5034 0 : printf(_("Field separator is zero byte.\n"));
5035 : }
5036 :
5037 : /* show disable "(x rows)" footer */
5038 0 : else if (strcmp(param, "footer") == 0)
5039 : {
5040 0 : if (popt->topt.default_footer)
5041 0 : printf(_("Default footer is on.\n"));
5042 : else
5043 0 : printf(_("Default footer is off.\n"));
5044 : }
5045 :
5046 : /* show format */
5047 0 : else if (strcmp(param, "format") == 0)
5048 : {
5049 0 : printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
5050 : }
5051 :
5052 : /* show table line style */
5053 0 : else if (strcmp(param, "linestyle") == 0)
5054 : {
5055 0 : printf(_("Line style is %s.\n"),
5056 : get_line_style(&popt->topt)->name);
5057 : }
5058 :
5059 : /* show null display */
5060 0 : else if (strcmp(param, "null") == 0)
5061 : {
5062 0 : printf(_("Null display is \"%s\".\n"),
5063 : popt->nullPrint ? popt->nullPrint : "");
5064 : }
5065 :
5066 : /* show locale-aware numeric output */
5067 0 : else if (strcmp(param, "numericlocale") == 0)
5068 : {
5069 0 : if (popt->topt.numericLocale)
5070 0 : printf(_("Locale-adjusted numeric output is on.\n"));
5071 : else
5072 0 : printf(_("Locale-adjusted numeric output is off.\n"));
5073 : }
5074 :
5075 : /* show toggle use of pager */
5076 0 : else if (strcmp(param, "pager") == 0)
5077 : {
5078 0 : if (popt->topt.pager == 1)
5079 0 : printf(_("Pager is used for long output.\n"));
5080 0 : else if (popt->topt.pager == 2)
5081 0 : printf(_("Pager is always used.\n"));
5082 : else
5083 0 : printf(_("Pager usage is off.\n"));
5084 : }
5085 :
5086 : /* show minimum lines for pager use */
5087 0 : else if (strcmp(param, "pager_min_lines") == 0)
5088 : {
5089 0 : printf(ngettext("Pager won't be used for less than %d line.\n",
5090 : "Pager won't be used for less than %d lines.\n",
5091 : popt->topt.pager_min_lines),
5092 : popt->topt.pager_min_lines);
5093 : }
5094 :
5095 : /* show record separator for unaligned text */
5096 0 : else if (strcmp(param, "recordsep") == 0)
5097 : {
5098 0 : if (popt->topt.recordSep.separator_zero)
5099 0 : printf(_("Record separator is zero byte.\n"));
5100 0 : else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
5101 0 : printf(_("Record separator is <newline>.\n"));
5102 : else
5103 0 : printf(_("Record separator is \"%s\".\n"),
5104 : popt->topt.recordSep.separator);
5105 : }
5106 :
5107 0 : else if (strcmp(param, "recordsep_zero") == 0)
5108 : {
5109 0 : printf(_("Record separator is zero byte.\n"));
5110 : }
5111 :
5112 : /* show HTML table tag options */
5113 0 : else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
5114 : {
5115 0 : if (popt->topt.tableAttr)
5116 0 : printf(_("Table attributes are \"%s\".\n"),
5117 : popt->topt.tableAttr);
5118 : else
5119 0 : printf(_("Table attributes unset.\n"));
5120 : }
5121 :
5122 : /* show title override */
5123 0 : else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
5124 : {
5125 0 : if (popt->title)
5126 0 : printf(_("Title is \"%s\".\n"), popt->title);
5127 : else
5128 0 : printf(_("Title is unset.\n"));
5129 : }
5130 :
5131 : /* show toggle between full and tuples-only format */
5132 0 : else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
5133 : {
5134 0 : if (popt->topt.tuples_only)
5135 0 : printf(_("Tuples only is on.\n"));
5136 : else
5137 0 : printf(_("Tuples only is off.\n"));
5138 : }
5139 :
5140 : /* Unicode style formatting */
5141 0 : else if (strcmp(param, "unicode_border_linestyle") == 0)
5142 : {
5143 0 : printf(_("Unicode border line style is \"%s\".\n"),
5144 : _unicode_linestyle2string(popt->topt.unicode_border_linestyle));
5145 : }
5146 :
5147 0 : else if (strcmp(param, "unicode_column_linestyle") == 0)
5148 : {
5149 0 : printf(_("Unicode column line style is \"%s\".\n"),
5150 : _unicode_linestyle2string(popt->topt.unicode_column_linestyle));
5151 : }
5152 :
5153 0 : else if (strcmp(param, "unicode_header_linestyle") == 0)
5154 : {
5155 0 : printf(_("Unicode header line style is \"%s\".\n"),
5156 : _unicode_linestyle2string(popt->topt.unicode_header_linestyle));
5157 : }
5158 :
5159 : else
5160 : {
5161 0 : pg_log_error("\\pset: unknown option: %s", param);
5162 0 : return false;
5163 : }
5164 :
5165 0 : return true;
5166 : }
5167 :
5168 : /*
5169 : * savePsetInfo: make a malloc'd copy of the data in *popt.
5170 : *
5171 : * Possibly this should be somewhere else, but it's a bit specific to psql.
5172 : */
5173 : printQueryOpt *
5174 36 : savePsetInfo(const printQueryOpt *popt)
5175 : {
5176 : printQueryOpt *save;
5177 :
5178 36 : save = (printQueryOpt *) pg_malloc(sizeof(printQueryOpt));
5179 :
5180 : /* Flat-copy all the scalar fields, then duplicate sub-structures. */
5181 36 : memcpy(save, popt, sizeof(printQueryOpt));
5182 :
5183 : /* topt.line_style points to const data that need not be duplicated */
5184 36 : if (popt->topt.fieldSep.separator)
5185 36 : save->topt.fieldSep.separator = pg_strdup(popt->topt.fieldSep.separator);
5186 36 : if (popt->topt.recordSep.separator)
5187 36 : save->topt.recordSep.separator = pg_strdup(popt->topt.recordSep.separator);
5188 36 : if (popt->topt.tableAttr)
5189 0 : save->topt.tableAttr = pg_strdup(popt->topt.tableAttr);
5190 36 : if (popt->nullPrint)
5191 0 : save->nullPrint = pg_strdup(popt->nullPrint);
5192 36 : if (popt->title)
5193 0 : save->title = pg_strdup(popt->title);
5194 :
5195 : /*
5196 : * footers and translate_columns are never set in psql's print settings,
5197 : * so we needn't write code to duplicate them.
5198 : */
5199 : Assert(popt->footers == NULL);
5200 : Assert(popt->translate_columns == NULL);
5201 :
5202 36 : return save;
5203 : }
5204 :
5205 : /*
5206 : * restorePsetInfo: restore *popt from the previously-saved copy *save,
5207 : * then free *save.
5208 : */
5209 : void
5210 36 : restorePsetInfo(printQueryOpt *popt, printQueryOpt *save)
5211 : {
5212 : /* Free all the old data we're about to overwrite the pointers to. */
5213 :
5214 : /* topt.line_style points to const data that need not be duplicated */
5215 36 : free(popt->topt.fieldSep.separator);
5216 36 : free(popt->topt.recordSep.separator);
5217 36 : free(popt->topt.tableAttr);
5218 36 : free(popt->nullPrint);
5219 36 : free(popt->title);
5220 :
5221 : /*
5222 : * footers and translate_columns are never set in psql's print settings,
5223 : * so we needn't write code to duplicate them.
5224 : */
5225 : Assert(popt->footers == NULL);
5226 : Assert(popt->translate_columns == NULL);
5227 :
5228 : /* Now we may flat-copy all the fields, including pointers. */
5229 36 : memcpy(popt, save, sizeof(printQueryOpt));
5230 :
5231 : /* Lastly, free "save" ... but its sub-structures now belong to popt. */
5232 36 : free(save);
5233 36 : }
5234 :
5235 : static const char *
5236 36 : pset_bool_string(bool val)
5237 : {
5238 36 : return val ? "on" : "off";
5239 : }
5240 :
5241 :
5242 : static char *
5243 24 : pset_quoted_string(const char *str)
5244 : {
5245 24 : char *ret = pg_malloc(strlen(str) * 2 + 3);
5246 24 : char *r = ret;
5247 :
5248 24 : *r++ = '\'';
5249 :
5250 42 : for (; *str; str++)
5251 : {
5252 18 : if (*str == '\n')
5253 : {
5254 6 : *r++ = '\\';
5255 6 : *r++ = 'n';
5256 : }
5257 12 : else if (*str == '\'')
5258 : {
5259 0 : *r++ = '\\';
5260 0 : *r++ = '\'';
5261 : }
5262 : else
5263 12 : *r++ = *str;
5264 : }
5265 :
5266 24 : *r++ = '\'';
5267 24 : *r = '\0';
5268 :
5269 24 : return ret;
5270 : }
5271 :
5272 :
5273 : /*
5274 : * Return a malloc'ed string for the \pset value.
5275 : *
5276 : * Note that for some string parameters, print.c distinguishes between unset
5277 : * and empty string, but for others it doesn't. This function should produce
5278 : * output that produces the correct setting when fed back into \pset.
5279 : */
5280 : static char *
5281 132 : pset_value_string(const char *param, printQueryOpt *popt)
5282 : {
5283 : Assert(param != NULL);
5284 :
5285 132 : if (strcmp(param, "border") == 0)
5286 6 : return psprintf("%d", popt->topt.border);
5287 126 : else if (strcmp(param, "columns") == 0)
5288 6 : return psprintf("%d", popt->topt.columns);
5289 120 : else if (strcmp(param, "csv_fieldsep") == 0)
5290 6 : return pset_quoted_string(popt->topt.csvFieldSep);
5291 114 : else if (strcmp(param, "expanded") == 0)
5292 12 : return pstrdup(popt->topt.expanded == 2
5293 : ? "auto"
5294 6 : : pset_bool_string(popt->topt.expanded));
5295 108 : else if (strcmp(param, "fieldsep") == 0)
5296 6 : return pset_quoted_string(popt->topt.fieldSep.separator
5297 : ? popt->topt.fieldSep.separator
5298 : : "");
5299 102 : else if (strcmp(param, "fieldsep_zero") == 0)
5300 6 : return pstrdup(pset_bool_string(popt->topt.fieldSep.separator_zero));
5301 96 : else if (strcmp(param, "footer") == 0)
5302 6 : return pstrdup(pset_bool_string(popt->topt.default_footer));
5303 90 : else if (strcmp(param, "format") == 0)
5304 6 : return pstrdup(_align2string(popt->topt.format));
5305 84 : else if (strcmp(param, "linestyle") == 0)
5306 6 : return pstrdup(get_line_style(&popt->topt)->name);
5307 78 : else if (strcmp(param, "null") == 0)
5308 6 : return pset_quoted_string(popt->nullPrint
5309 : ? popt->nullPrint
5310 : : "");
5311 72 : else if (strcmp(param, "numericlocale") == 0)
5312 6 : return pstrdup(pset_bool_string(popt->topt.numericLocale));
5313 66 : else if (strcmp(param, "pager") == 0)
5314 6 : return psprintf("%d", popt->topt.pager);
5315 60 : else if (strcmp(param, "pager_min_lines") == 0)
5316 6 : return psprintf("%d", popt->topt.pager_min_lines);
5317 54 : else if (strcmp(param, "recordsep") == 0)
5318 6 : return pset_quoted_string(popt->topt.recordSep.separator
5319 : ? popt->topt.recordSep.separator
5320 : : "");
5321 48 : else if (strcmp(param, "recordsep_zero") == 0)
5322 6 : return pstrdup(pset_bool_string(popt->topt.recordSep.separator_zero));
5323 42 : else if (strcmp(param, "tableattr") == 0)
5324 6 : return popt->topt.tableAttr ? pset_quoted_string(popt->topt.tableAttr) : pstrdup("");
5325 36 : else if (strcmp(param, "title") == 0)
5326 6 : return popt->title ? pset_quoted_string(popt->title) : pstrdup("");
5327 30 : else if (strcmp(param, "tuples_only") == 0)
5328 6 : return pstrdup(pset_bool_string(popt->topt.tuples_only));
5329 24 : else if (strcmp(param, "unicode_border_linestyle") == 0)
5330 6 : return pstrdup(_unicode_linestyle2string(popt->topt.unicode_border_linestyle));
5331 18 : else if (strcmp(param, "unicode_column_linestyle") == 0)
5332 6 : return pstrdup(_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
5333 12 : else if (strcmp(param, "unicode_header_linestyle") == 0)
5334 6 : return pstrdup(_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
5335 6 : else if (strcmp(param, "xheader_width") == 0)
5336 : {
5337 6 : if (popt->topt.expanded_header_width_type == PRINT_XHEADER_FULL)
5338 6 : return pstrdup("full");
5339 0 : else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_COLUMN)
5340 0 : return pstrdup("column");
5341 0 : else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_PAGE)
5342 0 : return pstrdup("page");
5343 : else
5344 : {
5345 : /* must be PRINT_XHEADER_EXACT_WIDTH */
5346 : char wbuff[32];
5347 :
5348 0 : snprintf(wbuff, sizeof(wbuff), "%d",
5349 : popt->topt.expanded_header_exact_width);
5350 0 : return pstrdup(wbuff);
5351 : }
5352 : }
5353 : else
5354 0 : return pstrdup("ERROR");
5355 : }
5356 :
5357 :
5358 :
5359 : #ifndef WIN32
5360 : #define DEFAULT_SHELL "/bin/sh"
5361 : #else
5362 : /*
5363 : * CMD.EXE is in different places in different Win32 releases so we
5364 : * have to rely on the path to find it.
5365 : */
5366 : #define DEFAULT_SHELL "cmd.exe"
5367 : #endif
5368 :
5369 : static bool
5370 0 : do_shell(const char *command)
5371 : {
5372 : int result;
5373 :
5374 0 : fflush(NULL);
5375 0 : if (!command)
5376 : {
5377 : char *sys;
5378 : const char *shellName;
5379 :
5380 0 : shellName = getenv("SHELL");
5381 : #ifdef WIN32
5382 : if (shellName == NULL)
5383 : shellName = getenv("COMSPEC");
5384 : #endif
5385 0 : if (shellName == NULL)
5386 0 : shellName = DEFAULT_SHELL;
5387 :
5388 : /* See EDITOR handling comment for an explanation */
5389 : #ifndef WIN32
5390 0 : sys = psprintf("exec %s", shellName);
5391 : #else
5392 : sys = psprintf("\"%s\"", shellName);
5393 : #endif
5394 0 : result = system(sys);
5395 0 : free(sys);
5396 : }
5397 : else
5398 0 : result = system(command);
5399 :
5400 0 : SetShellResultVariables(result);
5401 :
5402 0 : if (result == 127 || result == -1)
5403 : {
5404 0 : pg_log_error("\\!: failed");
5405 0 : return false;
5406 : }
5407 0 : return true;
5408 : }
5409 :
5410 : /*
5411 : * do_watch -- handler for \watch
5412 : *
5413 : * We break this out of exec_command to avoid having to plaster "volatile"
5414 : * onto a bunch of exec_command's variables to silence stupider compilers.
5415 : *
5416 : * "sleep" is the amount of time to sleep during each loop, measured in
5417 : * seconds. The internals of this function should use "sleep_ms" for
5418 : * precise sleep time calculations.
5419 : */
5420 : static bool
5421 8 : do_watch(PQExpBuffer query_buf, double sleep, int iter, int min_rows)
5422 : {
5423 8 : long sleep_ms = (long) (sleep * 1000);
5424 8 : printQueryOpt myopt = pset.popt;
5425 : const char *strftime_fmt;
5426 : const char *user_title;
5427 : char *title;
5428 8 : const char *pagerprog = NULL;
5429 8 : FILE *pagerpipe = NULL;
5430 : int title_len;
5431 8 : int res = 0;
5432 8 : bool done = false;
5433 : #ifndef WIN32
5434 : sigset_t sigalrm_sigchld_sigint;
5435 : sigset_t sigalrm_sigchld;
5436 : sigset_t sigint;
5437 : struct itimerval interval;
5438 : #endif
5439 :
5440 8 : if (!query_buf || query_buf->len <= 0)
5441 : {
5442 0 : pg_log_error("\\watch cannot be used with an empty query");
5443 0 : return false;
5444 : }
5445 :
5446 : #ifndef WIN32
5447 8 : sigemptyset(&sigalrm_sigchld_sigint);
5448 8 : sigaddset(&sigalrm_sigchld_sigint, SIGCHLD);
5449 8 : sigaddset(&sigalrm_sigchld_sigint, SIGALRM);
5450 8 : sigaddset(&sigalrm_sigchld_sigint, SIGINT);
5451 :
5452 8 : sigemptyset(&sigalrm_sigchld);
5453 8 : sigaddset(&sigalrm_sigchld, SIGCHLD);
5454 8 : sigaddset(&sigalrm_sigchld, SIGALRM);
5455 :
5456 8 : sigemptyset(&sigint);
5457 8 : sigaddset(&sigint, SIGINT);
5458 :
5459 : /*
5460 : * Block SIGALRM and SIGCHLD before we start the timer and the pager (if
5461 : * configured), to avoid races. sigwait() will receive them.
5462 : */
5463 8 : sigprocmask(SIG_BLOCK, &sigalrm_sigchld, NULL);
5464 :
5465 : /*
5466 : * Set a timer to interrupt sigwait() so we can run the query at the
5467 : * requested intervals.
5468 : */
5469 8 : interval.it_value.tv_sec = sleep_ms / 1000;
5470 8 : interval.it_value.tv_usec = (sleep_ms % 1000) * 1000;
5471 8 : interval.it_interval = interval.it_value;
5472 8 : if (setitimer(ITIMER_REAL, &interval, NULL) < 0)
5473 : {
5474 0 : pg_log_error("could not set timer: %m");
5475 0 : done = true;
5476 : }
5477 : #endif
5478 :
5479 : /*
5480 : * For \watch, we ignore the size of the result and always use the pager
5481 : * as long as we're talking to a terminal and "\pset pager" is enabled.
5482 : * However, we'll only use the pager identified by PSQL_WATCH_PAGER. We
5483 : * ignore the regular PSQL_PAGER or PAGER environment variables, because
5484 : * traditional pagers probably won't be very useful for showing a stream
5485 : * of results.
5486 : */
5487 : #ifndef WIN32
5488 8 : pagerprog = getenv("PSQL_WATCH_PAGER");
5489 : /* if variable is empty or all-white-space, don't use pager */
5490 8 : if (pagerprog && strspn(pagerprog, " \t\r\n") == strlen(pagerprog))
5491 0 : pagerprog = NULL;
5492 : #endif
5493 8 : if (pagerprog && myopt.topt.pager &&
5494 0 : isatty(fileno(stdin)) && isatty(fileno(stdout)))
5495 : {
5496 0 : fflush(NULL);
5497 0 : disable_sigpipe_trap();
5498 0 : pagerpipe = popen(pagerprog, "w");
5499 :
5500 0 : if (!pagerpipe)
5501 : /* silently proceed without pager */
5502 0 : restore_sigpipe_trap();
5503 : }
5504 :
5505 : /*
5506 : * Choose format for timestamps. We might eventually make this a \pset
5507 : * option. In the meantime, using a variable for the format suppresses
5508 : * overly-anal-retentive gcc warnings about %c being Y2K sensitive.
5509 : */
5510 8 : strftime_fmt = "%c";
5511 :
5512 : /*
5513 : * Set up rendering options, in particular, disable the pager unless
5514 : * PSQL_WATCH_PAGER was successfully launched.
5515 : */
5516 8 : if (!pagerpipe)
5517 8 : myopt.topt.pager = 0;
5518 :
5519 : /*
5520 : * If there's a title in the user configuration, make sure we have room
5521 : * for it in the title buffer. Allow 128 bytes for the timestamp plus 128
5522 : * bytes for the rest.
5523 : */
5524 8 : user_title = myopt.title;
5525 8 : title_len = (user_title ? strlen(user_title) : 0) + 256;
5526 8 : title = pg_malloc(title_len);
5527 :
5528 : /* Loop to run query and then sleep awhile */
5529 36 : while (!done)
5530 : {
5531 : time_t timer;
5532 : char timebuf[128];
5533 :
5534 : /*
5535 : * Prepare title for output. Note that we intentionally include a
5536 : * newline at the end of the title; this is somewhat historical but it
5537 : * makes for reasonably nicely formatted output in simple cases.
5538 : */
5539 36 : timer = time(NULL);
5540 36 : strftime(timebuf, sizeof(timebuf), strftime_fmt, localtime(&timer));
5541 :
5542 36 : if (user_title)
5543 0 : snprintf(title, title_len, _("%s\t%s (every %gs)\n"),
5544 : user_title, timebuf, sleep_ms / 1000.0);
5545 : else
5546 36 : snprintf(title, title_len, _("%s (every %gs)\n"),
5547 : timebuf, sleep_ms / 1000.0);
5548 36 : myopt.title = title;
5549 :
5550 : /* Run the query and print out the result */
5551 36 : res = PSQLexecWatch(query_buf->data, &myopt, pagerpipe, min_rows);
5552 :
5553 : /*
5554 : * PSQLexecWatch handles the case where we can no longer repeat the
5555 : * query, and returns 0 or -1.
5556 : */
5557 34 : if (res <= 0)
5558 6 : break;
5559 :
5560 : /* If we have iteration count, check that it's not exceeded yet */
5561 32 : if (iter && (--iter <= 0))
5562 4 : break;
5563 :
5564 : /* Quit if error on pager pipe (probably pager has quit) */
5565 28 : if (pagerpipe && ferror(pagerpipe))
5566 0 : break;
5567 :
5568 : /* Tight loop, no wait needed */
5569 28 : if (sleep_ms == 0)
5570 4 : continue;
5571 :
5572 : #ifdef WIN32
5573 :
5574 : /*
5575 : * Wait a while before running the query again. Break the sleep into
5576 : * short intervals (at most 1s); that's probably unnecessary since
5577 : * pg_usleep is interruptible on Windows, but it's cheap insurance.
5578 : */
5579 : for (long i = sleep_ms; i > 0;)
5580 : {
5581 : long s = Min(i, 1000L);
5582 :
5583 : pg_usleep(s * 1000L);
5584 : if (cancel_pressed)
5585 : {
5586 : done = true;
5587 : break;
5588 : }
5589 : i -= s;
5590 : }
5591 : #else
5592 : /* sigwait() will handle SIGINT. */
5593 24 : sigprocmask(SIG_BLOCK, &sigint, NULL);
5594 24 : if (cancel_pressed)
5595 0 : done = true;
5596 :
5597 : /* Wait for SIGINT, SIGCHLD or SIGALRM. */
5598 24 : while (!done)
5599 : {
5600 : int signal_received;
5601 :
5602 24 : errno = sigwait(&sigalrm_sigchld_sigint, &signal_received);
5603 24 : if (errno != 0)
5604 : {
5605 : /* Some other signal arrived? */
5606 0 : if (errno == EINTR)
5607 0 : continue;
5608 : else
5609 : {
5610 0 : pg_log_error("could not wait for signals: %m");
5611 0 : done = true;
5612 24 : break;
5613 : }
5614 : }
5615 : /* On ^C or pager exit, it's time to stop running the query. */
5616 24 : if (signal_received == SIGINT || signal_received == SIGCHLD)
5617 0 : done = true;
5618 : /* Otherwise, we must have SIGALRM. Time to run the query again. */
5619 24 : break;
5620 : }
5621 :
5622 : /* Unblock SIGINT so that slow queries can be interrupted. */
5623 24 : sigprocmask(SIG_UNBLOCK, &sigint, NULL);
5624 : #endif
5625 : }
5626 :
5627 6 : if (pagerpipe)
5628 : {
5629 0 : pclose(pagerpipe);
5630 0 : restore_sigpipe_trap();
5631 : }
5632 : else
5633 : {
5634 : /*
5635 : * If the terminal driver echoed "^C", libedit/libreadline might be
5636 : * confused about the cursor position. Therefore, inject a newline
5637 : * before the next prompt is displayed. We only do this when not
5638 : * using a pager, because pagers are expected to restore the screen to
5639 : * a sane state on exit.
5640 : */
5641 6 : fprintf(stdout, "\n");
5642 6 : fflush(stdout);
5643 : }
5644 :
5645 : #ifndef WIN32
5646 : /* Disable the interval timer. */
5647 6 : memset(&interval, 0, sizeof(interval));
5648 6 : setitimer(ITIMER_REAL, &interval, NULL);
5649 : /* Unblock SIGINT, SIGCHLD and SIGALRM. */
5650 6 : sigprocmask(SIG_UNBLOCK, &sigalrm_sigchld_sigint, NULL);
5651 : #endif
5652 :
5653 6 : pg_free(title);
5654 6 : return (res >= 0);
5655 : }
5656 :
5657 : /*
5658 : * a little code borrowed from PSQLexec() to manage ECHO_HIDDEN output.
5659 : * returns true unless we have ECHO_HIDDEN_NOEXEC.
5660 : */
5661 : static bool
5662 372 : echo_hidden_command(const char *query)
5663 : {
5664 372 : if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
5665 : {
5666 0 : printf(_("/******** QUERY *********/\n"
5667 : "%s\n"
5668 : "/************************/\n\n"), query);
5669 0 : fflush(stdout);
5670 0 : if (pset.logfile)
5671 : {
5672 0 : fprintf(pset.logfile,
5673 0 : _("/******** QUERY *********/\n"
5674 : "%s\n"
5675 : "/************************/\n\n"), query);
5676 0 : fflush(pset.logfile);
5677 : }
5678 :
5679 0 : if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
5680 0 : return false;
5681 : }
5682 372 : return true;
5683 : }
5684 :
5685 : /*
5686 : * Look up the object identified by obj_type and desc. If successful,
5687 : * store its OID in *obj_oid and return true, else return false.
5688 : *
5689 : * Note that we'll fail if the object doesn't exist OR if there are multiple
5690 : * matching candidates OR if there's something syntactically wrong with the
5691 : * object description; unfortunately it can be hard to tell the difference.
5692 : */
5693 : static bool
5694 186 : lookup_object_oid(EditableObjectType obj_type, const char *desc,
5695 : Oid *obj_oid)
5696 : {
5697 186 : bool result = true;
5698 186 : PQExpBuffer query = createPQExpBuffer();
5699 : PGresult *res;
5700 :
5701 186 : switch (obj_type)
5702 : {
5703 60 : case EditableFunction:
5704 :
5705 : /*
5706 : * We have a function description, e.g. "x" or "x(int)". Issue a
5707 : * query to retrieve the function's OID using a cast to regproc or
5708 : * regprocedure (as appropriate).
5709 : */
5710 60 : appendPQExpBufferStr(query, "SELECT ");
5711 60 : appendStringLiteralConn(query, desc, pset.db);
5712 60 : appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
5713 60 : strchr(desc, '(') ? "regprocedure" : "regproc");
5714 60 : break;
5715 :
5716 126 : case EditableView:
5717 :
5718 : /*
5719 : * Convert view name (possibly schema-qualified) to OID. Note:
5720 : * this code doesn't check if the relation is actually a view.
5721 : * We'll detect that in get_create_object_cmd().
5722 : */
5723 126 : appendPQExpBufferStr(query, "SELECT ");
5724 126 : appendStringLiteralConn(query, desc, pset.db);
5725 126 : appendPQExpBufferStr(query, "::pg_catalog.regclass::pg_catalog.oid");
5726 126 : break;
5727 : }
5728 :
5729 186 : if (!echo_hidden_command(query->data))
5730 : {
5731 0 : destroyPQExpBuffer(query);
5732 0 : return false;
5733 : }
5734 186 : res = PQexec(pset.db, query->data);
5735 186 : if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
5736 186 : *obj_oid = atooid(PQgetvalue(res, 0, 0));
5737 : else
5738 : {
5739 0 : minimal_error_message(res);
5740 0 : result = false;
5741 : }
5742 :
5743 186 : PQclear(res);
5744 186 : destroyPQExpBuffer(query);
5745 :
5746 186 : return result;
5747 : }
5748 :
5749 : /*
5750 : * Construct a "CREATE OR REPLACE ..." command that describes the specified
5751 : * database object. If successful, the result is stored in buf.
5752 : */
5753 : static bool
5754 186 : get_create_object_cmd(EditableObjectType obj_type, Oid oid,
5755 : PQExpBuffer buf)
5756 : {
5757 186 : bool result = true;
5758 186 : PQExpBuffer query = createPQExpBuffer();
5759 : PGresult *res;
5760 :
5761 186 : switch (obj_type)
5762 : {
5763 60 : case EditableFunction:
5764 60 : printfPQExpBuffer(query,
5765 : "SELECT pg_catalog.pg_get_functiondef(%u)",
5766 : oid);
5767 60 : break;
5768 :
5769 126 : case EditableView:
5770 :
5771 : /*
5772 : * pg_get_viewdef() just prints the query, so we must prepend
5773 : * CREATE for ourselves. We must fully qualify the view name to
5774 : * ensure the right view gets replaced. Also, check relation kind
5775 : * to be sure it's a view.
5776 : *
5777 : * Starting with PG 9.4, views may have WITH [LOCAL|CASCADED]
5778 : * CHECK OPTION. These are not part of the view definition
5779 : * returned by pg_get_viewdef() and so need to be retrieved
5780 : * separately. Materialized views (introduced in 9.3) may have
5781 : * arbitrary storage parameter reloptions.
5782 : */
5783 126 : if (pset.sversion >= 90400)
5784 : {
5785 126 : printfPQExpBuffer(query,
5786 : "SELECT nspname, relname, relkind, "
5787 : "pg_catalog.pg_get_viewdef(c.oid, true), "
5788 : "pg_catalog.array_remove(pg_catalog.array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5789 : "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5790 : "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption "
5791 : "FROM pg_catalog.pg_class c "
5792 : "LEFT JOIN pg_catalog.pg_namespace n "
5793 : "ON c.relnamespace = n.oid WHERE c.oid = %u",
5794 : oid);
5795 : }
5796 : else
5797 : {
5798 0 : printfPQExpBuffer(query,
5799 : "SELECT nspname, relname, relkind, "
5800 : "pg_catalog.pg_get_viewdef(c.oid, true), "
5801 : "c.reloptions AS reloptions, "
5802 : "NULL AS checkoption "
5803 : "FROM pg_catalog.pg_class c "
5804 : "LEFT JOIN pg_catalog.pg_namespace n "
5805 : "ON c.relnamespace = n.oid WHERE c.oid = %u",
5806 : oid);
5807 : }
5808 126 : break;
5809 : }
5810 :
5811 186 : if (!echo_hidden_command(query->data))
5812 : {
5813 0 : destroyPQExpBuffer(query);
5814 0 : return false;
5815 : }
5816 186 : res = PQexec(pset.db, query->data);
5817 186 : if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
5818 : {
5819 186 : resetPQExpBuffer(buf);
5820 186 : switch (obj_type)
5821 : {
5822 60 : case EditableFunction:
5823 60 : appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
5824 60 : break;
5825 :
5826 126 : case EditableView:
5827 : {
5828 126 : char *nspname = PQgetvalue(res, 0, 0);
5829 126 : char *relname = PQgetvalue(res, 0, 1);
5830 126 : char *relkind = PQgetvalue(res, 0, 2);
5831 126 : char *viewdef = PQgetvalue(res, 0, 3);
5832 126 : char *reloptions = PQgetvalue(res, 0, 4);
5833 126 : char *checkoption = PQgetvalue(res, 0, 5);
5834 :
5835 : /*
5836 : * If the backend ever supports CREATE OR REPLACE
5837 : * MATERIALIZED VIEW, allow that here; but as of today it
5838 : * does not, so editing a matview definition in this way
5839 : * is impossible.
5840 : */
5841 126 : switch (relkind[0])
5842 : {
5843 : #ifdef NOT_USED
5844 : case RELKIND_MATVIEW:
5845 : appendPQExpBufferStr(buf, "CREATE OR REPLACE MATERIALIZED VIEW ");
5846 : break;
5847 : #endif
5848 126 : case RELKIND_VIEW:
5849 126 : appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
5850 126 : break;
5851 0 : default:
5852 0 : pg_log_error("\"%s.%s\" is not a view",
5853 : nspname, relname);
5854 0 : result = false;
5855 0 : break;
5856 : }
5857 126 : appendPQExpBuffer(buf, "%s.", fmtId(nspname));
5858 126 : appendPQExpBufferStr(buf, fmtId(relname));
5859 :
5860 : /* reloptions, if not an empty array "{}" */
5861 126 : if (reloptions != NULL && strlen(reloptions) > 2)
5862 : {
5863 0 : appendPQExpBufferStr(buf, "\n WITH (");
5864 0 : if (!appendReloptionsArray(buf, reloptions, "",
5865 : pset.encoding,
5866 0 : standard_strings()))
5867 : {
5868 0 : pg_log_error("could not parse reloptions array");
5869 0 : result = false;
5870 : }
5871 0 : appendPQExpBufferChar(buf, ')');
5872 : }
5873 :
5874 : /* View definition from pg_get_viewdef (a SELECT query) */
5875 126 : appendPQExpBuffer(buf, " AS\n%s", viewdef);
5876 :
5877 : /* Get rid of the semicolon that pg_get_viewdef appends */
5878 126 : if (buf->len > 0 && buf->data[buf->len - 1] == ';')
5879 126 : buf->data[--(buf->len)] = '\0';
5880 :
5881 : /* WITH [LOCAL|CASCADED] CHECK OPTION */
5882 126 : if (checkoption && checkoption[0] != '\0')
5883 0 : appendPQExpBuffer(buf, "\n WITH %s CHECK OPTION",
5884 : checkoption);
5885 : }
5886 126 : break;
5887 : }
5888 : /* Make sure result ends with a newline */
5889 186 : if (buf->len > 0 && buf->data[buf->len - 1] != '\n')
5890 126 : appendPQExpBufferChar(buf, '\n');
5891 : }
5892 : else
5893 : {
5894 0 : minimal_error_message(res);
5895 0 : result = false;
5896 : }
5897 :
5898 186 : PQclear(res);
5899 186 : destroyPQExpBuffer(query);
5900 :
5901 186 : return result;
5902 : }
5903 :
5904 : /*
5905 : * If the given argument of \ef or \ev ends with a line number, delete the line
5906 : * number from the argument string and return it as an integer. (We need
5907 : * this kluge because we're too lazy to parse \ef's function or \ev's view
5908 : * argument carefully --- we just slop it up in OT_WHOLE_LINE mode.)
5909 : *
5910 : * Returns -1 if no line number is present, 0 on error, or a positive value
5911 : * on success.
5912 : */
5913 : static int
5914 0 : strip_lineno_from_objdesc(char *obj)
5915 : {
5916 : char *c;
5917 : int lineno;
5918 :
5919 0 : if (!obj || obj[0] == '\0')
5920 0 : return -1;
5921 :
5922 0 : c = obj + strlen(obj) - 1;
5923 :
5924 : /*
5925 : * This business of parsing backwards is dangerous as can be in a
5926 : * multibyte environment: there is no reason to believe that we are
5927 : * looking at the first byte of a character, nor are we necessarily
5928 : * working in a "safe" encoding. Fortunately the bitpatterns we are
5929 : * looking for are unlikely to occur as non-first bytes, but beware of
5930 : * trying to expand the set of cases that can be recognized. We must
5931 : * guard the <ctype.h> macros by using isascii() first, too.
5932 : */
5933 :
5934 : /* skip trailing whitespace */
5935 0 : while (c > obj && isascii((unsigned char) *c) && isspace((unsigned char) *c))
5936 0 : c--;
5937 :
5938 : /* must have a digit as last non-space char */
5939 0 : if (c == obj || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
5940 0 : return -1;
5941 :
5942 : /* find start of digit string */
5943 0 : while (c > obj && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
5944 0 : c--;
5945 :
5946 : /* digits must be separated from object name by space or closing paren */
5947 : /* notice also that we are not allowing an empty object name ... */
5948 0 : if (c == obj || !isascii((unsigned char) *c) ||
5949 0 : !(isspace((unsigned char) *c) || *c == ')'))
5950 0 : return -1;
5951 :
5952 : /* parse digit string */
5953 0 : c++;
5954 0 : lineno = atoi(c);
5955 0 : if (lineno < 1)
5956 : {
5957 0 : pg_log_error("invalid line number: %s", c);
5958 0 : return 0;
5959 : }
5960 :
5961 : /* strip digit string from object name */
5962 0 : *c = '\0';
5963 :
5964 0 : return lineno;
5965 : }
5966 :
5967 : /*
5968 : * Count number of lines in the buffer.
5969 : * This is used to test if pager is needed or not.
5970 : */
5971 : static int
5972 186 : count_lines_in_buf(PQExpBuffer buf)
5973 : {
5974 186 : int lineno = 0;
5975 186 : const char *lines = buf->data;
5976 :
5977 2896 : while (*lines != '\0')
5978 : {
5979 2710 : lineno++;
5980 : /* find start of next line */
5981 2710 : lines = strchr(lines, '\n');
5982 2710 : if (!lines)
5983 0 : break;
5984 2710 : lines++;
5985 : }
5986 :
5987 186 : return lineno;
5988 : }
5989 :
5990 : /*
5991 : * Write text at *lines to output with line numbers.
5992 : *
5993 : * For functions, lineno "1" should correspond to the first line of the
5994 : * function body; lines before that are unnumbered. We expect that
5995 : * pg_get_functiondef() will emit that on a line beginning with "AS ",
5996 : * "BEGIN ", or "RETURN ", and that there can be no such line before
5997 : * the real start of the function body.
5998 : *
5999 : * Caution: this scribbles on *lines.
6000 : */
6001 : static void
6002 18 : print_with_linenumbers(FILE *output, char *lines, bool is_func)
6003 : {
6004 18 : bool in_header = is_func;
6005 18 : int lineno = 0;
6006 :
6007 192 : while (*lines != '\0')
6008 : {
6009 : char *eol;
6010 :
6011 174 : if (in_header &&
6012 90 : (strncmp(lines, "AS ", 3) == 0 ||
6013 90 : strncmp(lines, "BEGIN ", 6) == 0 ||
6014 78 : strncmp(lines, "RETURN ", 7) == 0))
6015 18 : in_header = false;
6016 :
6017 : /* increment lineno only for body's lines */
6018 174 : if (!in_header)
6019 102 : lineno++;
6020 :
6021 : /* find and mark end of current line */
6022 174 : eol = strchr(lines, '\n');
6023 174 : if (eol != NULL)
6024 174 : *eol = '\0';
6025 :
6026 : /* show current line as appropriate */
6027 174 : if (in_header)
6028 72 : fprintf(output, " %s\n", lines);
6029 : else
6030 102 : fprintf(output, "%-7d %s\n", lineno, lines);
6031 :
6032 : /* advance to next line, if any */
6033 174 : if (eol == NULL)
6034 0 : break;
6035 174 : lines = ++eol;
6036 : }
6037 18 : }
6038 :
6039 : /*
6040 : * Report just the primary error; this is to avoid cluttering the output
6041 : * with, for instance, a redisplay of the internally generated query
6042 : */
6043 : static void
6044 0 : minimal_error_message(PGresult *res)
6045 : {
6046 : PQExpBuffer msg;
6047 : const char *fld;
6048 :
6049 0 : msg = createPQExpBuffer();
6050 :
6051 0 : fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
6052 0 : if (fld)
6053 0 : printfPQExpBuffer(msg, "%s: ", fld);
6054 : else
6055 0 : printfPQExpBuffer(msg, "ERROR: ");
6056 0 : fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
6057 0 : if (fld)
6058 0 : appendPQExpBufferStr(msg, fld);
6059 : else
6060 0 : appendPQExpBufferStr(msg, "(not available)");
6061 0 : appendPQExpBufferChar(msg, '\n');
6062 :
6063 0 : pg_log_error("%s", msg->data);
6064 :
6065 0 : destroyPQExpBuffer(msg);
6066 0 : }
|