Line data Source code
1 : /*
2 : * psql - the PostgreSQL interactive terminal
3 : *
4 : * Copyright (c) 2000-2017, PostgreSQL Global Development Group
5 : *
6 : * src/bin/psql/command.c
7 : */
8 : #include "postgres_fe.h"
9 : #include "command.h"
10 :
11 : #include <ctype.h>
12 : #include <time.h>
13 : #include <pwd.h>
14 : #ifndef WIN32
15 : #include <sys/stat.h> /* for stat() */
16 : #include <fcntl.h> /* open() flags */
17 : #include <unistd.h> /* for geteuid(), getpid(), stat() */
18 : #else
19 : #include <win32.h>
20 : #include <io.h>
21 : #include <fcntl.h>
22 : #include <direct.h>
23 : #include <sys/stat.h> /* for stat() */
24 : #endif
25 :
26 : #include "catalog/pg_class.h"
27 : #include "portability/instr_time.h"
28 :
29 : #include "libpq-fe.h"
30 : #include "pqexpbuffer.h"
31 : #include "fe_utils/string_utils.h"
32 :
33 : #include "common.h"
34 : #include "copy.h"
35 : #include "crosstabview.h"
36 : #include "describe.h"
37 : #include "help.h"
38 : #include "input.h"
39 : #include "large_obj.h"
40 : #include "mainloop.h"
41 : #include "fe_utils/print.h"
42 : #include "psqlscanslash.h"
43 : #include "settings.h"
44 : #include "variables.h"
45 :
46 : /*
47 : * Editable database object types.
48 : */
49 : typedef enum EditableObjectType
50 : {
51 : EditableFunction,
52 : EditableView
53 : } EditableObjectType;
54 :
55 : /* local function declarations */
56 : static backslashResult exec_command(const char *cmd,
57 : PsqlScanState scan_state,
58 : ConditionalStack cstack,
59 : PQExpBuffer query_buf,
60 : PQExpBuffer previous_buf);
61 : static backslashResult exec_command_a(PsqlScanState scan_state, bool active_branch);
62 : static backslashResult exec_command_C(PsqlScanState scan_state, bool active_branch);
63 : static backslashResult exec_command_connect(PsqlScanState scan_state, bool active_branch);
64 : static backslashResult exec_command_cd(PsqlScanState scan_state, bool active_branch,
65 : const char *cmd);
66 : static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch);
67 : static backslashResult exec_command_copy(PsqlScanState scan_state, bool active_branch);
68 : static backslashResult exec_command_copyright(PsqlScanState scan_state, bool active_branch);
69 : static backslashResult exec_command_crosstabview(PsqlScanState scan_state, bool active_branch);
70 : static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch,
71 : const char *cmd);
72 : static backslashResult exec_command_edit(PsqlScanState scan_state, bool active_branch,
73 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
74 : static backslashResult exec_command_ef(PsqlScanState scan_state, bool active_branch,
75 : PQExpBuffer query_buf);
76 : static backslashResult exec_command_ev(PsqlScanState scan_state, bool active_branch,
77 : PQExpBuffer query_buf);
78 : static backslashResult exec_command_echo(PsqlScanState scan_state, bool active_branch,
79 : const char *cmd);
80 : static backslashResult exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
81 : PQExpBuffer query_buf);
82 : static backslashResult exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
83 : PQExpBuffer query_buf);
84 : static backslashResult exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
85 : PQExpBuffer query_buf);
86 : static backslashResult exec_command_encoding(PsqlScanState scan_state, bool active_branch);
87 : static backslashResult exec_command_errverbose(PsqlScanState scan_state, bool active_branch);
88 : static backslashResult exec_command_f(PsqlScanState scan_state, bool active_branch);
89 : static backslashResult exec_command_g(PsqlScanState scan_state, bool active_branch,
90 : const char *cmd);
91 : static backslashResult exec_command_gexec(PsqlScanState scan_state, bool active_branch);
92 : static backslashResult exec_command_gset(PsqlScanState scan_state, bool active_branch);
93 : static backslashResult exec_command_help(PsqlScanState scan_state, bool active_branch);
94 : static backslashResult exec_command_html(PsqlScanState scan_state, bool active_branch);
95 : static backslashResult exec_command_include(PsqlScanState scan_state, bool active_branch,
96 : const char *cmd);
97 : static backslashResult exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
98 : PQExpBuffer query_buf);
99 : static backslashResult exec_command_list(PsqlScanState scan_state, bool active_branch,
100 : const char *cmd);
101 : static backslashResult exec_command_lo(PsqlScanState scan_state, bool active_branch,
102 : const char *cmd);
103 : static backslashResult exec_command_out(PsqlScanState scan_state, bool active_branch);
104 : static backslashResult exec_command_print(PsqlScanState scan_state, bool active_branch,
105 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
106 : static backslashResult exec_command_password(PsqlScanState scan_state, bool active_branch);
107 : static backslashResult exec_command_prompt(PsqlScanState scan_state, bool active_branch,
108 : const char *cmd);
109 : static backslashResult exec_command_pset(PsqlScanState scan_state, bool active_branch);
110 : static backslashResult exec_command_quit(PsqlScanState scan_state, bool active_branch);
111 : static backslashResult exec_command_reset(PsqlScanState scan_state, bool active_branch,
112 : PQExpBuffer query_buf);
113 : static backslashResult exec_command_s(PsqlScanState scan_state, bool active_branch);
114 : static backslashResult exec_command_set(PsqlScanState scan_state, bool active_branch);
115 : static backslashResult exec_command_setenv(PsqlScanState scan_state, bool active_branch,
116 : const char *cmd);
117 : static backslashResult exec_command_sf(PsqlScanState scan_state, bool active_branch,
118 : const char *cmd);
119 : static backslashResult exec_command_sv(PsqlScanState scan_state, bool active_branch,
120 : const char *cmd);
121 : static backslashResult exec_command_t(PsqlScanState scan_state, bool active_branch);
122 : static backslashResult exec_command_T(PsqlScanState scan_state, bool active_branch);
123 : static backslashResult exec_command_timing(PsqlScanState scan_state, bool active_branch);
124 : static backslashResult exec_command_unset(PsqlScanState scan_state, bool active_branch,
125 : const char *cmd);
126 : static backslashResult exec_command_write(PsqlScanState scan_state, bool active_branch,
127 : const char *cmd,
128 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
129 : static backslashResult exec_command_watch(PsqlScanState scan_state, bool active_branch,
130 : PQExpBuffer query_buf, PQExpBuffer previous_buf);
131 : static backslashResult exec_command_x(PsqlScanState scan_state, bool active_branch);
132 : static backslashResult exec_command_z(PsqlScanState scan_state, bool active_branch);
133 : static backslashResult exec_command_shell_escape(PsqlScanState scan_state, bool active_branch);
134 : static backslashResult exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch);
135 : static char *read_connect_arg(PsqlScanState scan_state);
136 : static PQExpBuffer gather_boolean_expression(PsqlScanState scan_state);
137 : static bool is_true_boolean_expression(PsqlScanState scan_state, const char *name);
138 : static void ignore_boolean_expression(PsqlScanState scan_state);
139 : static void ignore_slash_options(PsqlScanState scan_state);
140 : static void ignore_slash_filepipe(PsqlScanState scan_state);
141 : static void ignore_slash_whole_line(PsqlScanState scan_state);
142 : static bool is_branching_command(const char *cmd);
143 : static void save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
144 : PQExpBuffer query_buf);
145 : static void discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
146 : PQExpBuffer query_buf);
147 : static void copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf);
148 : static bool do_connect(enum trivalue reuse_previous_specification,
149 : char *dbname, char *user, char *host, char *port);
150 : static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
151 : int lineno, bool *edited);
152 : static bool do_shell(const char *command);
153 : static bool do_watch(PQExpBuffer query_buf, double sleep);
154 : static bool lookup_object_oid(EditableObjectType obj_type, const char *desc,
155 : Oid *obj_oid);
156 : static bool get_create_object_cmd(EditableObjectType obj_type, Oid oid,
157 : PQExpBuffer buf);
158 : static int strip_lineno_from_objdesc(char *obj);
159 : static int count_lines_in_buf(PQExpBuffer buf);
160 : static void print_with_linenumbers(FILE *output, char *lines,
161 : const char *header_keyword);
162 : static void minimal_error_message(PGresult *res);
163 :
164 : static void printSSLInfo(void);
165 : static bool printPsetInfo(const char *param, struct printQueryOpt *popt);
166 : static char *pset_value_string(const char *param, struct printQueryOpt *popt);
167 :
168 : #ifdef WIN32
169 : static void checkWin32Codepage(void);
170 : #endif
171 :
172 :
173 :
174 : /*----------
175 : * HandleSlashCmds:
176 : *
177 : * Handles all the different commands that start with '\'.
178 : * Ordinarily called by MainLoop().
179 : *
180 : * scan_state is a lexer working state that is set to continue scanning
181 : * just after the '\'. The lexer is advanced past the command and all
182 : * arguments on return.
183 : *
184 : * cstack is the current \if stack state. This will be examined, and
185 : * possibly modified by conditional commands.
186 : *
187 : * query_buf contains the query-so-far, which may be modified by
188 : * execution of the backslash command (for example, \r clears it).
189 : *
190 : * previous_buf contains the query most recently sent to the server
191 : * (empty if none yet). This should not be modified here, but some
192 : * commands copy its content into query_buf.
193 : *
194 : * query_buf and previous_buf will be NULL when executing a "-c"
195 : * command-line option.
196 : *
197 : * Returns a status code indicating what action is desired, see command.h.
198 : *----------
199 : */
200 :
201 : backslashResult
202 785 : HandleSlashCmds(PsqlScanState scan_state,
203 : ConditionalStack cstack,
204 : PQExpBuffer query_buf,
205 : PQExpBuffer previous_buf)
206 : {
207 : backslashResult status;
208 : char *cmd;
209 : char *arg;
210 :
211 785 : Assert(scan_state != NULL);
212 785 : Assert(cstack != NULL);
213 :
214 : /* Parse off the command name */
215 785 : cmd = psql_scan_slash_command(scan_state);
216 :
217 : /* And try to execute it */
218 785 : status = exec_command(cmd, scan_state, cstack, query_buf, previous_buf);
219 :
220 785 : if (status == PSQL_CMD_UNKNOWN)
221 : {
222 0 : if (pset.cur_cmd_interactive)
223 0 : psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
224 : else
225 0 : psql_error("invalid command \\%s\n", cmd);
226 0 : status = PSQL_CMD_ERROR;
227 : }
228 :
229 785 : if (status != PSQL_CMD_ERROR)
230 : {
231 : /*
232 : * Eat any remaining arguments after a valid command. We want to
233 : * suppress evaluation of backticks in this situation, so transiently
234 : * push an inactive conditional-stack entry.
235 : */
236 773 : bool active_branch = conditional_active(cstack);
237 :
238 773 : conditional_stack_push(cstack, IFSTATE_IGNORED);
239 1550 : while ((arg = psql_scan_slash_option(scan_state,
240 : OT_NORMAL, NULL, false)))
241 : {
242 4 : if (active_branch)
243 4 : psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
244 4 : free(arg);
245 : }
246 773 : conditional_stack_pop(cstack);
247 : }
248 : else
249 : {
250 : /* silently throw away rest of line after an erroneous command */
251 24 : while ((arg = psql_scan_slash_option(scan_state,
252 : OT_WHOLE_LINE, NULL, false)))
253 0 : free(arg);
254 : }
255 :
256 : /* if there is a trailing \\, swallow it */
257 785 : psql_scan_slash_command_end(scan_state);
258 :
259 785 : free(cmd);
260 :
261 : /* some commands write to queryFout, so make sure output is sent */
262 785 : fflush(pset.queryFout);
263 :
264 785 : return status;
265 : }
266 :
267 :
268 : /*
269 : * Subroutine to actually try to execute a backslash command.
270 : *
271 : * The typical "success" result code is PSQL_CMD_SKIP_LINE, although some
272 : * commands return something else. Failure results are PSQL_CMD_ERROR,
273 : * unless PSQL_CMD_UNKNOWN is more appropriate.
274 : */
275 : static backslashResult
276 785 : exec_command(const char *cmd,
277 : PsqlScanState scan_state,
278 : ConditionalStack cstack,
279 : PQExpBuffer query_buf,
280 : PQExpBuffer previous_buf)
281 : {
282 : backslashResult status;
283 785 : bool active_branch = conditional_active(cstack);
284 :
285 : /*
286 : * In interactive mode, warn when we're ignoring a command within a false
287 : * \if-branch. But we continue on, so as to parse and discard the right
288 : * amount of parameter text. Each individual backslash command subroutine
289 : * is responsible for doing nothing after discarding appropriate
290 : * arguments, if !active_branch.
291 : */
292 785 : if (pset.cur_cmd_interactive && !active_branch &&
293 0 : !is_branching_command(cmd))
294 : {
295 0 : psql_error("\\%s command ignored; use \\endif or Ctrl-C to exit current \\if block\n",
296 : cmd);
297 : }
298 :
299 785 : if (strcmp(cmd, "a") == 0)
300 7 : status = exec_command_a(scan_state, active_branch);
301 778 : else if (strcmp(cmd, "C") == 0)
302 1 : status = exec_command_C(scan_state, active_branch);
303 777 : else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
304 34 : status = exec_command_connect(scan_state, active_branch);
305 743 : else if (strcmp(cmd, "cd") == 0)
306 1 : status = exec_command_cd(scan_state, active_branch, cmd);
307 742 : else if (strcmp(cmd, "conninfo") == 0)
308 1 : status = exec_command_conninfo(scan_state, active_branch);
309 741 : else if (pg_strcasecmp(cmd, "copy") == 0)
310 12 : status = exec_command_copy(scan_state, active_branch);
311 729 : else if (strcmp(cmd, "copyright") == 0)
312 1 : status = exec_command_copyright(scan_state, active_branch);
313 728 : else if (strcmp(cmd, "crosstabview") == 0)
314 22 : status = exec_command_crosstabview(scan_state, active_branch);
315 706 : else if (cmd[0] == 'd')
316 302 : status = exec_command_d(scan_state, active_branch, cmd);
317 404 : else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
318 1 : status = exec_command_edit(scan_state, active_branch,
319 : query_buf, previous_buf);
320 403 : else if (strcmp(cmd, "ef") == 0)
321 1 : status = exec_command_ef(scan_state, active_branch, query_buf);
322 402 : else if (strcmp(cmd, "ev") == 0)
323 1 : status = exec_command_ev(scan_state, active_branch, query_buf);
324 401 : else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
325 41 : status = exec_command_echo(scan_state, active_branch, cmd);
326 360 : else if (strcmp(cmd, "elif") == 0)
327 6 : status = exec_command_elif(scan_state, cstack, query_buf);
328 354 : else if (strcmp(cmd, "else") == 0)
329 18 : status = exec_command_else(scan_state, cstack, query_buf);
330 336 : else if (strcmp(cmd, "endif") == 0)
331 17 : status = exec_command_endif(scan_state, cstack, query_buf);
332 319 : else if (strcmp(cmd, "encoding") == 0)
333 1 : status = exec_command_encoding(scan_state, active_branch);
334 318 : else if (strcmp(cmd, "errverbose") == 0)
335 1 : status = exec_command_errverbose(scan_state, active_branch);
336 317 : else if (strcmp(cmd, "f") == 0)
337 0 : status = exec_command_f(scan_state, active_branch);
338 317 : else if (strcmp(cmd, "g") == 0 || strcmp(cmd, "gx") == 0)
339 14 : status = exec_command_g(scan_state, active_branch, cmd);
340 303 : else if (strcmp(cmd, "gexec") == 0)
341 3 : status = exec_command_gexec(scan_state, active_branch);
342 300 : else if (strcmp(cmd, "gset") == 0)
343 20 : status = exec_command_gset(scan_state, active_branch);
344 280 : else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
345 1 : status = exec_command_help(scan_state, active_branch);
346 279 : else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
347 0 : status = exec_command_html(scan_state, active_branch);
348 558 : else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0 ||
349 558 : strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
350 0 : status = exec_command_include(scan_state, active_branch, cmd);
351 279 : else if (strcmp(cmd, "if") == 0)
352 16 : status = exec_command_if(scan_state, cstack, query_buf);
353 526 : else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
354 526 : strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
355 0 : status = exec_command_list(scan_state, active_branch, cmd);
356 263 : else if (strncmp(cmd, "lo_", 3) == 0)
357 6 : status = exec_command_lo(scan_state, active_branch, cmd);
358 257 : else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
359 1 : status = exec_command_out(scan_state, active_branch);
360 256 : else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
361 7 : status = exec_command_print(scan_state, active_branch,
362 : query_buf, previous_buf);
363 249 : else if (strcmp(cmd, "password") == 0)
364 1 : status = exec_command_password(scan_state, active_branch);
365 248 : else if (strcmp(cmd, "prompt") == 0)
366 1 : status = exec_command_prompt(scan_state, active_branch, cmd);
367 247 : else if (strcmp(cmd, "pset") == 0)
368 152 : status = exec_command_pset(scan_state, active_branch);
369 95 : else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
370 1 : status = exec_command_quit(scan_state, active_branch);
371 94 : else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
372 4 : status = exec_command_reset(scan_state, active_branch, query_buf);
373 90 : else if (strcmp(cmd, "s") == 0)
374 1 : status = exec_command_s(scan_state, active_branch);
375 89 : else if (strcmp(cmd, "set") == 0)
376 64 : status = exec_command_set(scan_state, active_branch);
377 25 : else if (strcmp(cmd, "setenv") == 0)
378 1 : status = exec_command_setenv(scan_state, active_branch, cmd);
379 24 : else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
380 1 : status = exec_command_sf(scan_state, active_branch, cmd);
381 23 : else if (strcmp(cmd, "sv") == 0 || strcmp(cmd, "sv+") == 0)
382 2 : status = exec_command_sv(scan_state, active_branch, cmd);
383 21 : else if (strcmp(cmd, "t") == 0)
384 7 : status = exec_command_t(scan_state, active_branch);
385 14 : else if (strcmp(cmd, "T") == 0)
386 1 : status = exec_command_T(scan_state, active_branch);
387 13 : else if (strcmp(cmd, "timing") == 0)
388 1 : status = exec_command_timing(scan_state, active_branch);
389 12 : else if (strcmp(cmd, "unset") == 0)
390 5 : status = exec_command_unset(scan_state, active_branch, cmd);
391 7 : else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
392 2 : status = exec_command_write(scan_state, active_branch, cmd,
393 : query_buf, previous_buf);
394 5 : else if (strcmp(cmd, "watch") == 0)
395 1 : status = exec_command_watch(scan_state, active_branch,
396 : query_buf, previous_buf);
397 4 : else if (strcmp(cmd, "x") == 0)
398 1 : status = exec_command_x(scan_state, active_branch);
399 3 : else if (strcmp(cmd, "z") == 0)
400 2 : status = exec_command_z(scan_state, active_branch);
401 1 : else if (strcmp(cmd, "!") == 0)
402 1 : status = exec_command_shell_escape(scan_state, active_branch);
403 0 : else if (strcmp(cmd, "?") == 0)
404 0 : status = exec_command_slash_command_help(scan_state, active_branch);
405 : else
406 0 : status = PSQL_CMD_UNKNOWN;
407 :
408 : /*
409 : * All the commands that return PSQL_CMD_SEND want to execute previous_buf
410 : * if query_buf is empty. For convenience we implement that here, not in
411 : * the individual command subroutines.
412 : */
413 785 : if (status == PSQL_CMD_SEND)
414 56 : copy_previous_query(query_buf, previous_buf);
415 :
416 785 : return status;
417 : }
418 :
419 :
420 : /*
421 : * \a -- toggle field alignment
422 : *
423 : * This makes little sense but we keep it around.
424 : */
425 : static backslashResult
426 7 : exec_command_a(PsqlScanState scan_state, bool active_branch)
427 : {
428 7 : bool success = true;
429 :
430 7 : if (active_branch)
431 : {
432 6 : if (pset.popt.topt.format != PRINT_ALIGNED)
433 3 : success = do_pset("format", "aligned", &pset.popt, pset.quiet);
434 : else
435 3 : success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
436 : }
437 :
438 7 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
439 : }
440 :
441 : /*
442 : * \C -- override table title (formerly change HTML caption)
443 : */
444 : static backslashResult
445 1 : exec_command_C(PsqlScanState scan_state, bool active_branch)
446 : {
447 1 : bool success = true;
448 :
449 1 : if (active_branch)
450 : {
451 0 : char *opt = psql_scan_slash_option(scan_state,
452 : OT_NORMAL, NULL, true);
453 :
454 0 : success = do_pset("title", opt, &pset.popt, pset.quiet);
455 0 : free(opt);
456 : }
457 : else
458 1 : ignore_slash_options(scan_state);
459 :
460 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
461 : }
462 :
463 : /*
464 : * \c or \connect -- connect to database using the specified parameters.
465 : *
466 : * \c [-reuse-previous=BOOL] dbname user host port
467 : *
468 : * Specifying a parameter as '-' is equivalent to omitting it. Examples:
469 : *
470 : * \c - - hst Connect to current database on current port of
471 : * host "hst" as current user.
472 : * \c - usr - prt Connect to current database on port "prt" of current host
473 : * as user "usr".
474 : * \c dbs Connect to database "dbs" on current port of current host
475 : * as current user.
476 : */
477 : static backslashResult
478 34 : exec_command_connect(PsqlScanState scan_state, bool active_branch)
479 : {
480 34 : bool success = true;
481 :
482 34 : if (active_branch)
483 : {
484 : static const char prefix[] = "-reuse-previous=";
485 : char *opt1,
486 : *opt2,
487 : *opt3,
488 : *opt4;
489 33 : enum trivalue reuse_previous = TRI_DEFAULT;
490 :
491 33 : opt1 = read_connect_arg(scan_state);
492 33 : if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0)
493 : {
494 : bool on_off;
495 :
496 0 : success = ParseVariableBool(opt1 + sizeof(prefix) - 1,
497 : "-reuse-previous",
498 : &on_off);
499 0 : if (success)
500 : {
501 0 : reuse_previous = on_off ? TRI_YES : TRI_NO;
502 0 : free(opt1);
503 0 : opt1 = read_connect_arg(scan_state);
504 : }
505 : }
506 :
507 33 : if (success) /* give up if reuse_previous was invalid */
508 : {
509 33 : opt2 = read_connect_arg(scan_state);
510 33 : opt3 = read_connect_arg(scan_state);
511 33 : opt4 = read_connect_arg(scan_state);
512 :
513 33 : success = do_connect(reuse_previous, opt1, opt2, opt3, opt4);
514 :
515 33 : free(opt2);
516 33 : free(opt3);
517 33 : free(opt4);
518 : }
519 33 : free(opt1);
520 : }
521 : else
522 1 : ignore_slash_options(scan_state);
523 :
524 34 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
525 : }
526 :
527 : /*
528 : * \cd -- change directory
529 : */
530 : static backslashResult
531 1 : exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
532 : {
533 1 : bool success = true;
534 :
535 1 : if (active_branch)
536 : {
537 0 : char *opt = psql_scan_slash_option(scan_state,
538 : OT_NORMAL, NULL, true);
539 : char *dir;
540 :
541 0 : if (opt)
542 0 : dir = opt;
543 : else
544 : {
545 : #ifndef WIN32
546 : struct passwd *pw;
547 0 : uid_t user_id = geteuid();
548 :
549 0 : errno = 0; /* clear errno before call */
550 0 : pw = getpwuid(user_id);
551 0 : if (!pw)
552 : {
553 0 : psql_error("could not get home directory for user ID %ld: %s\n",
554 : (long) user_id,
555 0 : errno ? strerror(errno) : _("user does not exist"));
556 0 : exit(EXIT_FAILURE);
557 : }
558 0 : dir = pw->pw_dir;
559 : #else /* WIN32 */
560 :
561 : /*
562 : * On Windows, 'cd' without arguments prints the current
563 : * directory, so if someone wants to code this here instead...
564 : */
565 : dir = "/";
566 : #endif /* WIN32 */
567 : }
568 :
569 0 : if (chdir(dir) == -1)
570 : {
571 0 : psql_error("\\%s: could not change directory to \"%s\": %s\n",
572 0 : cmd, dir, strerror(errno));
573 0 : success = false;
574 : }
575 :
576 0 : if (opt)
577 0 : free(opt);
578 : }
579 : else
580 1 : ignore_slash_options(scan_state);
581 :
582 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
583 : }
584 :
585 : /*
586 : * \conninfo -- display information about the current connection
587 : */
588 : static backslashResult
589 1 : exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
590 : {
591 1 : if (active_branch)
592 : {
593 0 : char *db = PQdb(pset.db);
594 :
595 0 : if (db == NULL)
596 0 : printf(_("You are currently not connected to a database.\n"));
597 : else
598 : {
599 : char *host;
600 : PQconninfoOption *connOptions;
601 : PQconninfoOption *option;
602 :
603 0 : host = PQhost(pset.db);
604 : /* A usable "hostaddr" overrides the basic sense of host. */
605 0 : connOptions = PQconninfo(pset.db);
606 0 : if (connOptions == NULL)
607 : {
608 0 : psql_error("out of memory\n");
609 0 : exit(EXIT_FAILURE);
610 : }
611 0 : for (option = connOptions; option && option->keyword; option++)
612 0 : if (strcmp(option->keyword, "hostaddr") == 0)
613 : {
614 0 : if (option->val != NULL && option->val[0] != '\0')
615 0 : host = option->val;
616 0 : break;
617 : }
618 :
619 : /* If the host is an absolute path, the connection is via socket */
620 0 : if (is_absolute_path(host))
621 0 : printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
622 0 : db, PQuser(pset.db), host, PQport(pset.db));
623 : else
624 0 : printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
625 0 : db, PQuser(pset.db), host, PQport(pset.db));
626 0 : printSSLInfo();
627 :
628 0 : PQconninfoFree(connOptions);
629 : }
630 : }
631 :
632 1 : return PSQL_CMD_SKIP_LINE;
633 : }
634 :
635 : /*
636 : * \copy -- run a COPY command
637 : */
638 : static backslashResult
639 12 : exec_command_copy(PsqlScanState scan_state, bool active_branch)
640 : {
641 12 : bool success = true;
642 :
643 12 : if (active_branch)
644 : {
645 11 : char *opt = psql_scan_slash_option(scan_state,
646 : OT_WHOLE_LINE, NULL, false);
647 :
648 11 : success = do_copy(opt);
649 11 : free(opt);
650 : }
651 : else
652 1 : ignore_slash_whole_line(scan_state);
653 :
654 12 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
655 : }
656 :
657 : /*
658 : * \copyright -- print copyright notice
659 : */
660 : static backslashResult
661 1 : exec_command_copyright(PsqlScanState scan_state, bool active_branch)
662 : {
663 1 : if (active_branch)
664 0 : print_copyright();
665 :
666 1 : return PSQL_CMD_SKIP_LINE;
667 : }
668 :
669 : /*
670 : * \crosstabview -- execute a query and display results in crosstab
671 : */
672 : static backslashResult
673 22 : exec_command_crosstabview(PsqlScanState scan_state, bool active_branch)
674 : {
675 22 : backslashResult status = PSQL_CMD_SKIP_LINE;
676 :
677 22 : if (active_branch)
678 : {
679 : int i;
680 :
681 110 : for (i = 0; i < lengthof(pset.ctv_args); i++)
682 88 : pset.ctv_args[i] = psql_scan_slash_option(scan_state,
683 : OT_NORMAL, NULL, true);
684 22 : pset.crosstab_flag = true;
685 22 : status = PSQL_CMD_SEND;
686 : }
687 : else
688 0 : ignore_slash_options(scan_state);
689 :
690 22 : return status;
691 : }
692 :
693 : /*
694 : * \d* commands
695 : */
696 : static backslashResult
697 302 : exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
698 : {
699 302 : backslashResult status = PSQL_CMD_SKIP_LINE;
700 302 : bool success = true;
701 :
702 302 : if (active_branch)
703 : {
704 : char *pattern;
705 : bool show_verbose,
706 : show_system;
707 :
708 : /* We don't do SQLID reduction on the pattern yet */
709 301 : pattern = psql_scan_slash_option(scan_state,
710 : OT_NORMAL, NULL, true);
711 :
712 301 : show_verbose = strchr(cmd, '+') ? true : false;
713 301 : show_system = strchr(cmd, 'S') ? true : false;
714 :
715 301 : switch (cmd[1])
716 : {
717 : case '\0':
718 : case '+':
719 : case 'S':
720 240 : if (pattern)
721 240 : success = describeTableDetails(pattern, show_verbose, show_system);
722 : else
723 : /* standard listing of interesting things */
724 0 : success = listTables("tvmsE", NULL, show_verbose, show_system);
725 240 : break;
726 : case 'A':
727 0 : success = describeAccessMethods(pattern, show_verbose);
728 0 : break;
729 : case 'a':
730 1 : success = describeAggregates(pattern, show_verbose, show_system);
731 1 : break;
732 : case 'b':
733 0 : success = describeTablespaces(pattern, show_verbose);
734 0 : break;
735 : case 'c':
736 0 : success = listConversions(pattern, show_verbose, show_system);
737 0 : break;
738 : case 'C':
739 0 : success = listCasts(pattern, show_verbose);
740 0 : break;
741 : case 'd':
742 0 : if (strncmp(cmd, "ddp", 3) == 0)
743 0 : success = listDefaultACLs(pattern);
744 : else
745 0 : success = objectDescription(pattern, show_system);
746 0 : break;
747 : case 'D':
748 0 : success = listDomains(pattern, show_verbose, show_system);
749 0 : break;
750 : case 'f': /* function subsystem */
751 2 : switch (cmd[2])
752 : {
753 : case '\0':
754 : case '+':
755 : case 'S':
756 : case 'a':
757 : case 'n':
758 : case 't':
759 : case 'w':
760 2 : success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
761 2 : break;
762 : default:
763 0 : status = PSQL_CMD_UNKNOWN;
764 0 : break;
765 : }
766 2 : break;
767 : case 'g':
768 : /* no longer distinct from \du */
769 0 : success = describeRoles(pattern, show_verbose, show_system);
770 0 : break;
771 : case 'l':
772 0 : success = do_lo_list();
773 0 : break;
774 : case 'L':
775 0 : success = listLanguages(pattern, show_verbose, show_system);
776 0 : break;
777 : case 'n':
778 0 : success = listSchemas(pattern, show_verbose, show_system);
779 0 : break;
780 : case 'o':
781 0 : success = describeOperators(pattern, show_verbose, show_system);
782 0 : break;
783 : case 'O':
784 0 : success = listCollations(pattern, show_verbose, show_system);
785 0 : break;
786 : case 'p':
787 4 : success = permissionsList(pattern);
788 4 : break;
789 : case 'T':
790 0 : success = describeTypes(pattern, show_verbose, show_system);
791 0 : break;
792 : case 't':
793 : case 'v':
794 : case 'm':
795 : case 'i':
796 : case 's':
797 : case 'E':
798 1 : success = listTables(&cmd[1], pattern, show_verbose, show_system);
799 1 : break;
800 : case 'r':
801 0 : if (cmd[2] == 'd' && cmd[3] == 's')
802 0 : {
803 0 : char *pattern2 = NULL;
804 :
805 0 : if (pattern)
806 0 : pattern2 = psql_scan_slash_option(scan_state,
807 : OT_NORMAL, NULL, true);
808 0 : success = listDbRoleSettings(pattern, pattern2);
809 :
810 0 : if (pattern2)
811 0 : free(pattern2);
812 : }
813 : else
814 0 : status = PSQL_CMD_UNKNOWN;
815 0 : break;
816 : case 'R':
817 15 : switch (cmd[2])
818 : {
819 : case 'p':
820 10 : if (show_verbose)
821 6 : success = describePublications(pattern);
822 : else
823 4 : success = listPublications(pattern);
824 10 : break;
825 : case 's':
826 5 : success = describeSubscriptions(pattern, show_verbose);
827 5 : break;
828 : default:
829 0 : status = PSQL_CMD_UNKNOWN;
830 : }
831 15 : break;
832 : case 'u':
833 0 : success = describeRoles(pattern, show_verbose, show_system);
834 0 : break;
835 : case 'F': /* text search subsystem */
836 0 : switch (cmd[2])
837 : {
838 : case '\0':
839 : case '+':
840 0 : success = listTSConfigs(pattern, show_verbose);
841 0 : break;
842 : case 'p':
843 0 : success = listTSParsers(pattern, show_verbose);
844 0 : break;
845 : case 'd':
846 0 : success = listTSDictionaries(pattern, show_verbose);
847 0 : break;
848 : case 't':
849 0 : success = listTSTemplates(pattern, show_verbose);
850 0 : break;
851 : default:
852 0 : status = PSQL_CMD_UNKNOWN;
853 0 : break;
854 : }
855 0 : break;
856 : case 'e': /* SQL/MED subsystem */
857 38 : switch (cmd[2])
858 : {
859 : case 's':
860 12 : success = listForeignServers(pattern, show_verbose);
861 12 : break;
862 : case 'u':
863 10 : success = listUserMappings(pattern, show_verbose);
864 10 : break;
865 : case 'w':
866 15 : success = listForeignDataWrappers(pattern, show_verbose);
867 15 : break;
868 : case 't':
869 1 : success = listForeignTables(pattern, show_verbose);
870 1 : break;
871 : default:
872 0 : status = PSQL_CMD_UNKNOWN;
873 0 : break;
874 : }
875 38 : break;
876 : case 'x': /* Extensions */
877 0 : if (show_verbose)
878 0 : success = listExtensionContents(pattern);
879 : else
880 0 : success = listExtensions(pattern);
881 0 : break;
882 : case 'y': /* Event Triggers */
883 0 : success = listEventTriggers(pattern, show_verbose);
884 0 : break;
885 : default:
886 0 : status = PSQL_CMD_UNKNOWN;
887 : }
888 :
889 301 : if (pattern)
890 255 : free(pattern);
891 : }
892 : else
893 1 : ignore_slash_options(scan_state);
894 :
895 302 : if (!success)
896 2 : status = PSQL_CMD_ERROR;
897 :
898 302 : return status;
899 : }
900 :
901 : /*
902 : * \e or \edit -- edit the current query buffer, or edit a file and
903 : * make it the query buffer
904 : */
905 : static backslashResult
906 1 : exec_command_edit(PsqlScanState scan_state, bool active_branch,
907 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
908 : {
909 1 : backslashResult status = PSQL_CMD_SKIP_LINE;
910 :
911 1 : if (active_branch)
912 : {
913 0 : if (!query_buf)
914 : {
915 0 : psql_error("no query buffer\n");
916 0 : status = PSQL_CMD_ERROR;
917 : }
918 : else
919 : {
920 : char *fname;
921 0 : char *ln = NULL;
922 0 : int lineno = -1;
923 :
924 0 : fname = psql_scan_slash_option(scan_state,
925 : OT_NORMAL, NULL, true);
926 0 : if (fname)
927 : {
928 : /* try to get separate lineno arg */
929 0 : ln = psql_scan_slash_option(scan_state,
930 : OT_NORMAL, NULL, true);
931 0 : if (ln == NULL)
932 : {
933 : /* only one arg; maybe it is lineno not fname */
934 0 : if (fname[0] &&
935 0 : strspn(fname, "0123456789") == strlen(fname))
936 : {
937 : /* all digits, so assume it is lineno */
938 0 : ln = fname;
939 0 : fname = NULL;
940 : }
941 : }
942 : }
943 0 : if (ln)
944 : {
945 0 : lineno = atoi(ln);
946 0 : if (lineno < 1)
947 : {
948 0 : psql_error("invalid line number: %s\n", ln);
949 0 : status = PSQL_CMD_ERROR;
950 : }
951 : }
952 0 : if (status != PSQL_CMD_ERROR)
953 : {
954 0 : expand_tilde(&fname);
955 0 : if (fname)
956 0 : canonicalize_path(fname);
957 :
958 : /* If query_buf is empty, recall previous query for editing */
959 0 : copy_previous_query(query_buf, previous_buf);
960 :
961 0 : if (do_edit(fname, query_buf, lineno, NULL))
962 0 : status = PSQL_CMD_NEWEDIT;
963 : else
964 0 : status = PSQL_CMD_ERROR;
965 : }
966 0 : if (fname)
967 0 : free(fname);
968 0 : if (ln)
969 0 : free(ln);
970 : }
971 : }
972 : else
973 1 : ignore_slash_options(scan_state);
974 :
975 1 : return status;
976 : }
977 :
978 : /*
979 : * \ef -- edit the named function, or present a blank CREATE FUNCTION
980 : * template if no argument is given
981 : */
982 : static backslashResult
983 1 : exec_command_ef(PsqlScanState scan_state, bool active_branch,
984 : PQExpBuffer query_buf)
985 : {
986 1 : backslashResult status = PSQL_CMD_SKIP_LINE;
987 :
988 1 : if (active_branch)
989 : {
990 0 : char *func = psql_scan_slash_option(scan_state,
991 : OT_WHOLE_LINE, NULL, true);
992 0 : int lineno = -1;
993 :
994 0 : if (pset.sversion < 80400)
995 : {
996 : char sverbuf[32];
997 :
998 0 : psql_error("The server (version %s) does not support editing function source.\n",
999 : formatPGVersionNumber(pset.sversion, false,
1000 : sverbuf, sizeof(sverbuf)));
1001 0 : status = PSQL_CMD_ERROR;
1002 : }
1003 0 : else if (!query_buf)
1004 : {
1005 0 : psql_error("no query buffer\n");
1006 0 : status = PSQL_CMD_ERROR;
1007 : }
1008 : else
1009 : {
1010 0 : Oid foid = InvalidOid;
1011 :
1012 0 : lineno = strip_lineno_from_objdesc(func);
1013 0 : if (lineno == 0)
1014 : {
1015 : /* error already reported */
1016 0 : status = PSQL_CMD_ERROR;
1017 : }
1018 0 : else if (!func)
1019 : {
1020 : /* set up an empty command to fill in */
1021 0 : printfPQExpBuffer(query_buf,
1022 : "CREATE FUNCTION ( )\n"
1023 : " RETURNS \n"
1024 : " LANGUAGE \n"
1025 : " -- common options: IMMUTABLE STABLE STRICT SECURITY DEFINER\n"
1026 : "AS $function$\n"
1027 : "\n$function$\n");
1028 : }
1029 0 : else if (!lookup_object_oid(EditableFunction, func, &foid))
1030 : {
1031 : /* error already reported */
1032 0 : status = PSQL_CMD_ERROR;
1033 : }
1034 0 : else if (!get_create_object_cmd(EditableFunction, foid, query_buf))
1035 : {
1036 : /* error already reported */
1037 0 : status = PSQL_CMD_ERROR;
1038 : }
1039 0 : else if (lineno > 0)
1040 : {
1041 : /*
1042 : * lineno "1" should correspond to the first line of the
1043 : * function body. We expect that pg_get_functiondef() will
1044 : * emit that on a line beginning with "AS ", and that there
1045 : * can be no such line before the real start of the function
1046 : * body. Increment lineno by the number of lines before that
1047 : * line, so that it becomes relative to the first line of the
1048 : * function definition.
1049 : */
1050 0 : const char *lines = query_buf->data;
1051 :
1052 0 : while (*lines != '\0')
1053 : {
1054 0 : if (strncmp(lines, "AS ", 3) == 0)
1055 0 : break;
1056 0 : lineno++;
1057 : /* find start of next line */
1058 0 : lines = strchr(lines, '\n');
1059 0 : if (!lines)
1060 0 : break;
1061 0 : lines++;
1062 : }
1063 : }
1064 : }
1065 :
1066 0 : if (status != PSQL_CMD_ERROR)
1067 : {
1068 0 : bool edited = false;
1069 :
1070 0 : if (!do_edit(NULL, query_buf, lineno, &edited))
1071 0 : status = PSQL_CMD_ERROR;
1072 0 : else if (!edited)
1073 0 : puts(_("No changes"));
1074 : else
1075 0 : status = PSQL_CMD_NEWEDIT;
1076 : }
1077 :
1078 0 : if (func)
1079 0 : free(func);
1080 : }
1081 : else
1082 1 : ignore_slash_whole_line(scan_state);
1083 :
1084 1 : return status;
1085 : }
1086 :
1087 : /*
1088 : * \ev -- edit the named view, or present a blank CREATE VIEW
1089 : * template if no argument is given
1090 : */
1091 : static backslashResult
1092 1 : exec_command_ev(PsqlScanState scan_state, bool active_branch,
1093 : PQExpBuffer query_buf)
1094 : {
1095 1 : backslashResult status = PSQL_CMD_SKIP_LINE;
1096 :
1097 1 : if (active_branch)
1098 : {
1099 0 : char *view = psql_scan_slash_option(scan_state,
1100 : OT_WHOLE_LINE, NULL, true);
1101 0 : int lineno = -1;
1102 :
1103 0 : if (pset.sversion < 70400)
1104 : {
1105 : char sverbuf[32];
1106 :
1107 0 : psql_error("The server (version %s) does not support editing view definitions.\n",
1108 : formatPGVersionNumber(pset.sversion, false,
1109 : sverbuf, sizeof(sverbuf)));
1110 0 : status = PSQL_CMD_ERROR;
1111 : }
1112 0 : else if (!query_buf)
1113 : {
1114 0 : psql_error("no query buffer\n");
1115 0 : status = PSQL_CMD_ERROR;
1116 : }
1117 : else
1118 : {
1119 0 : Oid view_oid = InvalidOid;
1120 :
1121 0 : lineno = strip_lineno_from_objdesc(view);
1122 0 : if (lineno == 0)
1123 : {
1124 : /* error already reported */
1125 0 : status = PSQL_CMD_ERROR;
1126 : }
1127 0 : else if (!view)
1128 : {
1129 : /* set up an empty command to fill in */
1130 0 : printfPQExpBuffer(query_buf,
1131 : "CREATE VIEW AS\n"
1132 : " SELECT \n"
1133 : " -- something...\n");
1134 : }
1135 0 : else if (!lookup_object_oid(EditableView, view, &view_oid))
1136 : {
1137 : /* error already reported */
1138 0 : status = PSQL_CMD_ERROR;
1139 : }
1140 0 : else if (!get_create_object_cmd(EditableView, view_oid, query_buf))
1141 : {
1142 : /* error already reported */
1143 0 : status = PSQL_CMD_ERROR;
1144 : }
1145 : }
1146 :
1147 0 : if (status != PSQL_CMD_ERROR)
1148 : {
1149 0 : bool edited = false;
1150 :
1151 0 : if (!do_edit(NULL, query_buf, lineno, &edited))
1152 0 : status = PSQL_CMD_ERROR;
1153 0 : else if (!edited)
1154 0 : puts(_("No changes"));
1155 : else
1156 0 : status = PSQL_CMD_NEWEDIT;
1157 : }
1158 :
1159 0 : if (view)
1160 0 : free(view);
1161 : }
1162 : else
1163 1 : ignore_slash_whole_line(scan_state);
1164 :
1165 1 : return status;
1166 : }
1167 :
1168 : /*
1169 : * \echo and \qecho -- echo arguments to stdout or query output
1170 : */
1171 : static backslashResult
1172 41 : exec_command_echo(PsqlScanState scan_state, bool active_branch, const char *cmd)
1173 : {
1174 41 : if (active_branch)
1175 : {
1176 : char *value;
1177 : char quoted;
1178 23 : bool no_newline = false;
1179 23 : bool first = true;
1180 : FILE *fout;
1181 :
1182 23 : if (strcmp(cmd, "qecho") == 0)
1183 0 : fout = pset.queryFout;
1184 : else
1185 23 : fout = stdout;
1186 :
1187 77 : while ((value = psql_scan_slash_option(scan_state,
1188 : OT_NORMAL, "ed, false)))
1189 : {
1190 31 : if (!quoted && strcmp(value, "-n") == 0)
1191 0 : no_newline = true;
1192 : else
1193 : {
1194 31 : if (first)
1195 23 : first = false;
1196 : else
1197 8 : fputc(' ', fout);
1198 31 : fputs(value, fout);
1199 : }
1200 31 : free(value);
1201 : }
1202 23 : if (!no_newline)
1203 23 : fputs("\n", fout);
1204 : }
1205 : else
1206 18 : ignore_slash_options(scan_state);
1207 :
1208 41 : return PSQL_CMD_SKIP_LINE;
1209 : }
1210 :
1211 : /*
1212 : * \encoding -- set/show client side encoding
1213 : */
1214 : static backslashResult
1215 1 : exec_command_encoding(PsqlScanState scan_state, bool active_branch)
1216 : {
1217 1 : if (active_branch)
1218 : {
1219 0 : char *encoding = psql_scan_slash_option(scan_state,
1220 : OT_NORMAL, NULL, false);
1221 :
1222 0 : if (!encoding)
1223 : {
1224 : /* show encoding */
1225 0 : puts(pg_encoding_to_char(pset.encoding));
1226 : }
1227 : else
1228 : {
1229 : /* set encoding */
1230 0 : if (PQsetClientEncoding(pset.db, encoding) == -1)
1231 0 : psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
1232 : else
1233 : {
1234 : /* save encoding info into psql internal data */
1235 0 : pset.encoding = PQclientEncoding(pset.db);
1236 0 : pset.popt.topt.encoding = pset.encoding;
1237 0 : SetVariable(pset.vars, "ENCODING",
1238 : pg_encoding_to_char(pset.encoding));
1239 : }
1240 0 : free(encoding);
1241 : }
1242 : }
1243 : else
1244 1 : ignore_slash_options(scan_state);
1245 :
1246 1 : return PSQL_CMD_SKIP_LINE;
1247 : }
1248 :
1249 : /*
1250 : * \errverbose -- display verbose message from last failed query
1251 : */
1252 : static backslashResult
1253 1 : exec_command_errverbose(PsqlScanState scan_state, bool active_branch)
1254 : {
1255 1 : if (active_branch)
1256 : {
1257 0 : if (pset.last_error_result)
1258 : {
1259 : char *msg;
1260 :
1261 0 : msg = PQresultVerboseErrorMessage(pset.last_error_result,
1262 : PQERRORS_VERBOSE,
1263 : PQSHOW_CONTEXT_ALWAYS);
1264 0 : if (msg)
1265 : {
1266 0 : psql_error("%s", msg);
1267 0 : PQfreemem(msg);
1268 : }
1269 : else
1270 0 : puts(_("out of memory"));
1271 : }
1272 : else
1273 0 : puts(_("There is no previous error."));
1274 : }
1275 :
1276 1 : return PSQL_CMD_SKIP_LINE;
1277 : }
1278 :
1279 : /*
1280 : * \f -- change field separator
1281 : */
1282 : static backslashResult
1283 0 : exec_command_f(PsqlScanState scan_state, bool active_branch)
1284 : {
1285 0 : bool success = true;
1286 :
1287 0 : if (active_branch)
1288 : {
1289 0 : char *fname = psql_scan_slash_option(scan_state,
1290 : OT_NORMAL, NULL, false);
1291 :
1292 0 : success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
1293 0 : free(fname);
1294 : }
1295 : else
1296 0 : ignore_slash_options(scan_state);
1297 :
1298 0 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1299 : }
1300 :
1301 : /*
1302 : * \g [filename] -- send query, optionally with output to file/pipe
1303 : * \gx [filename] -- same as \g, with expanded mode forced
1304 : */
1305 : static backslashResult
1306 14 : exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd)
1307 : {
1308 14 : backslashResult status = PSQL_CMD_SKIP_LINE;
1309 :
1310 14 : if (active_branch)
1311 : {
1312 12 : char *fname = psql_scan_slash_option(scan_state,
1313 : OT_FILEPIPE, NULL, false);
1314 :
1315 12 : if (!fname)
1316 12 : pset.gfname = NULL;
1317 : else
1318 : {
1319 0 : expand_tilde(&fname);
1320 0 : pset.gfname = pg_strdup(fname);
1321 : }
1322 12 : free(fname);
1323 12 : if (strcmp(cmd, "gx") == 0)
1324 4 : pset.g_expanded = true;
1325 12 : status = PSQL_CMD_SEND;
1326 : }
1327 : else
1328 2 : ignore_slash_filepipe(scan_state);
1329 :
1330 14 : return status;
1331 : }
1332 :
1333 : /*
1334 : * \gexec -- send query and execute each field of result
1335 : */
1336 : static backslashResult
1337 3 : exec_command_gexec(PsqlScanState scan_state, bool active_branch)
1338 : {
1339 3 : backslashResult status = PSQL_CMD_SKIP_LINE;
1340 :
1341 3 : if (active_branch)
1342 : {
1343 2 : pset.gexec_flag = true;
1344 2 : status = PSQL_CMD_SEND;
1345 : }
1346 :
1347 3 : return status;
1348 : }
1349 :
1350 : /*
1351 : * \gset [prefix] -- send query and store result into variables
1352 : */
1353 : static backslashResult
1354 20 : exec_command_gset(PsqlScanState scan_state, bool active_branch)
1355 : {
1356 20 : backslashResult status = PSQL_CMD_SKIP_LINE;
1357 :
1358 20 : if (active_branch)
1359 : {
1360 20 : char *prefix = psql_scan_slash_option(scan_state,
1361 : OT_NORMAL, NULL, false);
1362 :
1363 20 : if (prefix)
1364 7 : pset.gset_prefix = prefix;
1365 : else
1366 : {
1367 : /* we must set a non-NULL prefix to trigger storing */
1368 13 : pset.gset_prefix = pg_strdup("");
1369 : }
1370 : /* gset_prefix is freed later */
1371 20 : status = PSQL_CMD_SEND;
1372 : }
1373 : else
1374 0 : ignore_slash_options(scan_state);
1375 :
1376 20 : return status;
1377 : }
1378 :
1379 : /*
1380 : * \help [topic] -- print help about SQL commands
1381 : */
1382 : static backslashResult
1383 1 : exec_command_help(PsqlScanState scan_state, bool active_branch)
1384 : {
1385 1 : if (active_branch)
1386 : {
1387 0 : char *opt = psql_scan_slash_option(scan_state,
1388 : OT_WHOLE_LINE, NULL, false);
1389 : size_t len;
1390 :
1391 : /* strip any trailing spaces and semicolons */
1392 0 : if (opt)
1393 : {
1394 0 : len = strlen(opt);
1395 0 : while (len > 0 &&
1396 0 : (isspace((unsigned char) opt[len - 1])
1397 0 : || opt[len - 1] == ';'))
1398 0 : opt[--len] = '\0';
1399 : }
1400 :
1401 0 : helpSQL(opt, pset.popt.topt.pager);
1402 0 : free(opt);
1403 : }
1404 : else
1405 1 : ignore_slash_whole_line(scan_state);
1406 :
1407 1 : return PSQL_CMD_SKIP_LINE;
1408 : }
1409 :
1410 : /*
1411 : * \H and \html -- toggle HTML formatting
1412 : */
1413 : static backslashResult
1414 0 : exec_command_html(PsqlScanState scan_state, bool active_branch)
1415 : {
1416 0 : bool success = true;
1417 :
1418 0 : if (active_branch)
1419 : {
1420 0 : if (pset.popt.topt.format != PRINT_HTML)
1421 0 : success = do_pset("format", "html", &pset.popt, pset.quiet);
1422 : else
1423 0 : success = do_pset("format", "aligned", &pset.popt, pset.quiet);
1424 : }
1425 :
1426 0 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1427 : }
1428 :
1429 : /*
1430 : * \i and \ir -- include a file
1431 : */
1432 : static backslashResult
1433 0 : exec_command_include(PsqlScanState scan_state, bool active_branch, const char *cmd)
1434 : {
1435 0 : bool success = true;
1436 :
1437 0 : if (active_branch)
1438 : {
1439 0 : char *fname = psql_scan_slash_option(scan_state,
1440 : OT_NORMAL, NULL, true);
1441 :
1442 0 : if (!fname)
1443 : {
1444 0 : psql_error("\\%s: missing required argument\n", cmd);
1445 0 : success = false;
1446 : }
1447 : else
1448 : {
1449 : bool include_relative;
1450 :
1451 0 : include_relative = (strcmp(cmd, "ir") == 0
1452 0 : || strcmp(cmd, "include_relative") == 0);
1453 0 : expand_tilde(&fname);
1454 0 : success = (process_file(fname, include_relative) == EXIT_SUCCESS);
1455 0 : free(fname);
1456 : }
1457 : }
1458 : else
1459 0 : ignore_slash_options(scan_state);
1460 :
1461 0 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1462 : }
1463 :
1464 : /*
1465 : * \if <expr> -- beginning of an \if..\endif block
1466 : *
1467 : * <expr> is parsed as a boolean expression. Invalid expressions will emit a
1468 : * warning and be treated as false. Statements that follow a false expression
1469 : * will be parsed but ignored. Note that in the case where an \if statement
1470 : * is itself within an inactive section of a block, then the entire inner
1471 : * \if..\endif block will be parsed but ignored.
1472 : */
1473 : static backslashResult
1474 16 : exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
1475 : PQExpBuffer query_buf)
1476 : {
1477 16 : if (conditional_active(cstack))
1478 : {
1479 : /*
1480 : * First, push a new active stack entry; this ensures that the lexer
1481 : * will perform variable substitution and backtick evaluation while
1482 : * scanning the expression. (That should happen anyway, since we know
1483 : * we're in an active outer branch, but let's be sure.)
1484 : */
1485 15 : conditional_stack_push(cstack, IFSTATE_TRUE);
1486 :
1487 : /* Remember current query state in case we need to restore later */
1488 15 : save_query_text_state(scan_state, cstack, query_buf);
1489 :
1490 : /*
1491 : * Evaluate the expression; if it's false, change to inactive state.
1492 : */
1493 15 : if (!is_true_boolean_expression(scan_state, "\\if expression"))
1494 7 : conditional_stack_poke(cstack, IFSTATE_FALSE);
1495 : }
1496 : else
1497 : {
1498 : /*
1499 : * We're within an inactive outer branch, so this entire \if block
1500 : * will be ignored. We don't want to evaluate the expression, so push
1501 : * the "ignored" stack state before scanning it.
1502 : */
1503 1 : conditional_stack_push(cstack, IFSTATE_IGNORED);
1504 :
1505 : /* Remember current query state in case we need to restore later */
1506 1 : save_query_text_state(scan_state, cstack, query_buf);
1507 :
1508 1 : ignore_boolean_expression(scan_state);
1509 : }
1510 :
1511 16 : return PSQL_CMD_SKIP_LINE;
1512 : }
1513 :
1514 : /*
1515 : * \elif <expr> -- alternative branch in an \if..\endif block
1516 : *
1517 : * <expr> is evaluated the same as in \if <expr>.
1518 : */
1519 : static backslashResult
1520 6 : exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
1521 : PQExpBuffer query_buf)
1522 : {
1523 6 : bool success = true;
1524 :
1525 6 : switch (conditional_stack_peek(cstack))
1526 : {
1527 : case IFSTATE_TRUE:
1528 :
1529 : /*
1530 : * Just finished active branch of this \if block. Update saved
1531 : * state so we will keep whatever data was put in query_buf by the
1532 : * active branch.
1533 : */
1534 0 : save_query_text_state(scan_state, cstack, query_buf);
1535 :
1536 : /*
1537 : * Discard \elif expression and ignore the rest until \endif.
1538 : * Switch state before reading expression to ensure proper lexer
1539 : * behavior.
1540 : */
1541 0 : conditional_stack_poke(cstack, IFSTATE_IGNORED);
1542 0 : ignore_boolean_expression(scan_state);
1543 0 : break;
1544 : case IFSTATE_FALSE:
1545 :
1546 : /*
1547 : * Discard any query text added by the just-skipped branch.
1548 : */
1549 4 : discard_query_text(scan_state, cstack, query_buf);
1550 :
1551 : /*
1552 : * Have not yet found a true expression in this \if block, so this
1553 : * might be the first. We have to change state before examining
1554 : * the expression, or the lexer won't do the right thing.
1555 : */
1556 4 : conditional_stack_poke(cstack, IFSTATE_TRUE);
1557 4 : if (!is_true_boolean_expression(scan_state, "\\elif expression"))
1558 3 : conditional_stack_poke(cstack, IFSTATE_FALSE);
1559 4 : break;
1560 : case IFSTATE_IGNORED:
1561 :
1562 : /*
1563 : * Discard any query text added by the just-skipped branch.
1564 : */
1565 0 : discard_query_text(scan_state, cstack, query_buf);
1566 :
1567 : /*
1568 : * Skip expression and move on. Either the \if block already had
1569 : * an active section, or whole block is being skipped.
1570 : */
1571 0 : ignore_boolean_expression(scan_state);
1572 0 : break;
1573 : case IFSTATE_ELSE_TRUE:
1574 : case IFSTATE_ELSE_FALSE:
1575 1 : psql_error("\\elif: cannot occur after \\else\n");
1576 1 : success = false;
1577 1 : break;
1578 : case IFSTATE_NONE:
1579 : /* no \if to elif from */
1580 1 : psql_error("\\elif: no matching \\if\n");
1581 1 : success = false;
1582 1 : break;
1583 : }
1584 :
1585 6 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1586 : }
1587 :
1588 : /*
1589 : * \else -- final alternative in an \if..\endif block
1590 : *
1591 : * Statements within an \else branch will only be executed if
1592 : * all previous \if and \elif expressions evaluated to false
1593 : * and the block was not itself being ignored.
1594 : */
1595 : static backslashResult
1596 18 : exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
1597 : PQExpBuffer query_buf)
1598 : {
1599 18 : bool success = true;
1600 :
1601 18 : switch (conditional_stack_peek(cstack))
1602 : {
1603 : case IFSTATE_TRUE:
1604 :
1605 : /*
1606 : * Just finished active branch of this \if block. Update saved
1607 : * state so we will keep whatever data was put in query_buf by the
1608 : * active branch.
1609 : */
1610 9 : save_query_text_state(scan_state, cstack, query_buf);
1611 :
1612 : /* Now skip the \else branch */
1613 9 : conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
1614 9 : break;
1615 : case IFSTATE_FALSE:
1616 :
1617 : /*
1618 : * Discard any query text added by the just-skipped branch.
1619 : */
1620 6 : discard_query_text(scan_state, cstack, query_buf);
1621 :
1622 : /*
1623 : * We've not found any true \if or \elif expression, so execute
1624 : * the \else branch.
1625 : */
1626 6 : conditional_stack_poke(cstack, IFSTATE_ELSE_TRUE);
1627 6 : break;
1628 : case IFSTATE_IGNORED:
1629 :
1630 : /*
1631 : * Discard any query text added by the just-skipped branch.
1632 : */
1633 1 : discard_query_text(scan_state, cstack, query_buf);
1634 :
1635 : /*
1636 : * Either we previously processed the active branch of this \if,
1637 : * or the whole \if block is being skipped. Either way, skip the
1638 : * \else branch.
1639 : */
1640 1 : conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
1641 1 : break;
1642 : case IFSTATE_ELSE_TRUE:
1643 : case IFSTATE_ELSE_FALSE:
1644 1 : psql_error("\\else: cannot occur after \\else\n");
1645 1 : success = false;
1646 1 : break;
1647 : case IFSTATE_NONE:
1648 : /* no \if to else from */
1649 1 : psql_error("\\else: no matching \\if\n");
1650 1 : success = false;
1651 1 : break;
1652 : }
1653 :
1654 18 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1655 : }
1656 :
1657 : /*
1658 : * \endif -- ends an \if...\endif block
1659 : */
1660 : static backslashResult
1661 17 : exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
1662 : PQExpBuffer query_buf)
1663 : {
1664 17 : bool success = true;
1665 :
1666 17 : switch (conditional_stack_peek(cstack))
1667 : {
1668 : case IFSTATE_TRUE:
1669 : case IFSTATE_ELSE_TRUE:
1670 : /* Close the \if block, keeping the query text */
1671 6 : success = conditional_stack_pop(cstack);
1672 6 : Assert(success);
1673 6 : break;
1674 : case IFSTATE_FALSE:
1675 : case IFSTATE_IGNORED:
1676 : case IFSTATE_ELSE_FALSE:
1677 :
1678 : /*
1679 : * Discard any query text added by the just-skipped branch.
1680 : */
1681 10 : discard_query_text(scan_state, cstack, query_buf);
1682 :
1683 : /* Close the \if block */
1684 10 : success = conditional_stack_pop(cstack);
1685 10 : Assert(success);
1686 10 : break;
1687 : case IFSTATE_NONE:
1688 : /* no \if to end */
1689 1 : psql_error("\\endif: no matching \\if\n");
1690 1 : success = false;
1691 1 : break;
1692 : }
1693 :
1694 17 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1695 : }
1696 :
1697 : /*
1698 : * \l -- list databases
1699 : */
1700 : static backslashResult
1701 0 : exec_command_list(PsqlScanState scan_state, bool active_branch, const char *cmd)
1702 : {
1703 0 : bool success = true;
1704 :
1705 0 : if (active_branch)
1706 : {
1707 : char *pattern;
1708 : bool show_verbose;
1709 :
1710 0 : pattern = psql_scan_slash_option(scan_state,
1711 : OT_NORMAL, NULL, true);
1712 :
1713 0 : show_verbose = strchr(cmd, '+') ? true : false;
1714 :
1715 0 : success = listAllDbs(pattern, show_verbose);
1716 :
1717 0 : if (pattern)
1718 0 : free(pattern);
1719 : }
1720 : else
1721 0 : ignore_slash_options(scan_state);
1722 :
1723 0 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1724 : }
1725 :
1726 : /*
1727 : * \lo_* -- large object operations
1728 : */
1729 : static backslashResult
1730 6 : exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
1731 : {
1732 6 : backslashResult status = PSQL_CMD_SKIP_LINE;
1733 6 : bool success = true;
1734 :
1735 6 : if (active_branch)
1736 : {
1737 : char *opt1,
1738 : *opt2;
1739 :
1740 6 : opt1 = psql_scan_slash_option(scan_state,
1741 : OT_NORMAL, NULL, true);
1742 6 : opt2 = psql_scan_slash_option(scan_state,
1743 : OT_NORMAL, NULL, true);
1744 :
1745 6 : if (strcmp(cmd + 3, "export") == 0)
1746 : {
1747 1 : if (!opt2)
1748 : {
1749 0 : psql_error("\\%s: missing required argument\n", cmd);
1750 0 : success = false;
1751 : }
1752 : else
1753 : {
1754 1 : expand_tilde(&opt2);
1755 1 : success = do_lo_export(opt1, opt2);
1756 : }
1757 : }
1758 :
1759 5 : else if (strcmp(cmd + 3, "import") == 0)
1760 : {
1761 2 : if (!opt1)
1762 : {
1763 0 : psql_error("\\%s: missing required argument\n", cmd);
1764 0 : success = false;
1765 : }
1766 : else
1767 : {
1768 2 : expand_tilde(&opt1);
1769 2 : success = do_lo_import(opt1, opt2);
1770 : }
1771 : }
1772 :
1773 3 : else if (strcmp(cmd + 3, "list") == 0)
1774 0 : success = do_lo_list();
1775 :
1776 3 : else if (strcmp(cmd + 3, "unlink") == 0)
1777 : {
1778 3 : if (!opt1)
1779 : {
1780 0 : psql_error("\\%s: missing required argument\n", cmd);
1781 0 : success = false;
1782 : }
1783 : else
1784 3 : success = do_lo_unlink(opt1);
1785 : }
1786 :
1787 : else
1788 0 : status = PSQL_CMD_UNKNOWN;
1789 :
1790 6 : free(opt1);
1791 6 : free(opt2);
1792 : }
1793 : else
1794 0 : ignore_slash_options(scan_state);
1795 :
1796 6 : if (!success)
1797 0 : status = PSQL_CMD_ERROR;
1798 :
1799 6 : return status;
1800 : }
1801 :
1802 : /*
1803 : * \o -- set query output
1804 : */
1805 : static backslashResult
1806 1 : exec_command_out(PsqlScanState scan_state, bool active_branch)
1807 : {
1808 1 : bool success = true;
1809 :
1810 1 : if (active_branch)
1811 : {
1812 0 : char *fname = psql_scan_slash_option(scan_state,
1813 : OT_FILEPIPE, NULL, true);
1814 :
1815 0 : expand_tilde(&fname);
1816 0 : success = setQFout(fname);
1817 0 : free(fname);
1818 : }
1819 : else
1820 1 : ignore_slash_filepipe(scan_state);
1821 :
1822 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1823 : }
1824 :
1825 : /*
1826 : * \p -- print the current query buffer
1827 : */
1828 : static backslashResult
1829 7 : exec_command_print(PsqlScanState scan_state, bool active_branch,
1830 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
1831 : {
1832 7 : if (active_branch)
1833 : {
1834 : /*
1835 : * We want to print the same thing \g would execute, but not to change
1836 : * the query buffer state; so we can't use copy_previous_query().
1837 : * Also, beware of possibility that buffer pointers are NULL.
1838 : */
1839 6 : if (query_buf && query_buf->len > 0)
1840 3 : puts(query_buf->data);
1841 3 : else if (previous_buf && previous_buf->len > 0)
1842 3 : puts(previous_buf->data);
1843 0 : else if (!pset.quiet)
1844 0 : puts(_("Query buffer is empty."));
1845 6 : fflush(stdout);
1846 : }
1847 :
1848 7 : return PSQL_CMD_SKIP_LINE;
1849 : }
1850 :
1851 : /*
1852 : * \password -- set user password
1853 : */
1854 : static backslashResult
1855 1 : exec_command_password(PsqlScanState scan_state, bool active_branch)
1856 : {
1857 1 : bool success = true;
1858 :
1859 1 : if (active_branch)
1860 : {
1861 0 : char *opt0 = psql_scan_slash_option(scan_state,
1862 : OT_SQLID, NULL, true);
1863 : char pw1[100];
1864 : char pw2[100];
1865 :
1866 0 : simple_prompt("Enter new password: ", pw1, sizeof(pw1), false);
1867 0 : simple_prompt("Enter it again: ", pw2, sizeof(pw2), false);
1868 :
1869 0 : if (strcmp(pw1, pw2) != 0)
1870 : {
1871 0 : psql_error("Passwords didn't match.\n");
1872 0 : success = false;
1873 : }
1874 : else
1875 : {
1876 : char *user;
1877 : char *encrypted_password;
1878 :
1879 0 : if (opt0)
1880 0 : user = opt0;
1881 : else
1882 0 : user = PQuser(pset.db);
1883 :
1884 0 : encrypted_password = PQencryptPasswordConn(pset.db, pw1, user, NULL);
1885 :
1886 0 : if (!encrypted_password)
1887 : {
1888 0 : psql_error("%s", PQerrorMessage(pset.db));
1889 0 : success = false;
1890 : }
1891 : else
1892 : {
1893 : PQExpBufferData buf;
1894 : PGresult *res;
1895 :
1896 0 : initPQExpBuffer(&buf);
1897 0 : printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
1898 : fmtId(user));
1899 0 : appendStringLiteralConn(&buf, encrypted_password, pset.db);
1900 0 : res = PSQLexec(buf.data);
1901 0 : termPQExpBuffer(&buf);
1902 0 : if (!res)
1903 0 : success = false;
1904 : else
1905 0 : PQclear(res);
1906 0 : PQfreemem(encrypted_password);
1907 : }
1908 : }
1909 :
1910 0 : if (opt0)
1911 0 : free(opt0);
1912 : }
1913 : else
1914 1 : ignore_slash_options(scan_state);
1915 :
1916 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1917 : }
1918 :
1919 : /*
1920 : * \prompt -- prompt and set variable
1921 : */
1922 : static backslashResult
1923 1 : exec_command_prompt(PsqlScanState scan_state, bool active_branch,
1924 : const char *cmd)
1925 : {
1926 1 : bool success = true;
1927 :
1928 1 : if (active_branch)
1929 : {
1930 : char *opt,
1931 0 : *prompt_text = NULL;
1932 : char *arg1,
1933 : *arg2;
1934 :
1935 0 : arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
1936 0 : arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
1937 :
1938 0 : if (!arg1)
1939 : {
1940 0 : psql_error("\\%s: missing required argument\n", cmd);
1941 0 : success = false;
1942 : }
1943 : else
1944 : {
1945 : char *result;
1946 :
1947 0 : if (arg2)
1948 : {
1949 0 : prompt_text = arg1;
1950 0 : opt = arg2;
1951 : }
1952 : else
1953 0 : opt = arg1;
1954 :
1955 0 : if (!pset.inputfile)
1956 : {
1957 0 : result = (char *) pg_malloc(4096);
1958 0 : simple_prompt(prompt_text, result, 4096, true);
1959 : }
1960 : else
1961 : {
1962 0 : if (prompt_text)
1963 : {
1964 0 : fputs(prompt_text, stdout);
1965 0 : fflush(stdout);
1966 : }
1967 0 : result = gets_fromFile(stdin);
1968 0 : if (!result)
1969 : {
1970 0 : psql_error("\\%s: could not read value for variable\n",
1971 : cmd);
1972 0 : success = false;
1973 : }
1974 : }
1975 :
1976 0 : if (result &&
1977 0 : !SetVariable(pset.vars, opt, result))
1978 0 : success = false;
1979 :
1980 0 : if (result)
1981 0 : free(result);
1982 0 : if (prompt_text)
1983 0 : free(prompt_text);
1984 0 : free(opt);
1985 : }
1986 : }
1987 : else
1988 1 : ignore_slash_options(scan_state);
1989 :
1990 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1991 : }
1992 :
1993 : /*
1994 : * \pset -- set printing parameters
1995 : */
1996 : static backslashResult
1997 152 : exec_command_pset(PsqlScanState scan_state, bool active_branch)
1998 : {
1999 152 : bool success = true;
2000 :
2001 152 : if (active_branch)
2002 : {
2003 150 : char *opt0 = psql_scan_slash_option(scan_state,
2004 : OT_NORMAL, NULL, false);
2005 150 : char *opt1 = psql_scan_slash_option(scan_state,
2006 : OT_NORMAL, NULL, false);
2007 :
2008 150 : if (!opt0)
2009 : {
2010 : /* list all variables */
2011 :
2012 : int i;
2013 : static const char *const my_list[] = {
2014 : "border", "columns", "expanded", "fieldsep", "fieldsep_zero",
2015 : "footer", "format", "linestyle", "null",
2016 : "numericlocale", "pager", "pager_min_lines",
2017 : "recordsep", "recordsep_zero",
2018 : "tableattr", "title", "tuples_only",
2019 : "unicode_border_linestyle",
2020 : "unicode_column_linestyle",
2021 : "unicode_header_linestyle",
2022 : NULL
2023 : };
2024 :
2025 21 : for (i = 0; my_list[i] != NULL; i++)
2026 : {
2027 20 : char *val = pset_value_string(my_list[i], &pset.popt);
2028 :
2029 20 : printf("%-24s %s\n", my_list[i], val);
2030 20 : free(val);
2031 : }
2032 :
2033 1 : success = true;
2034 : }
2035 : else
2036 149 : success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
2037 :
2038 150 : free(opt0);
2039 150 : free(opt1);
2040 : }
2041 : else
2042 2 : ignore_slash_options(scan_state);
2043 :
2044 152 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2045 : }
2046 :
2047 : /*
2048 : * \q or \quit -- exit psql
2049 : */
2050 : static backslashResult
2051 1 : exec_command_quit(PsqlScanState scan_state, bool active_branch)
2052 : {
2053 1 : backslashResult status = PSQL_CMD_SKIP_LINE;
2054 :
2055 1 : if (active_branch)
2056 0 : status = PSQL_CMD_TERMINATE;
2057 :
2058 1 : return status;
2059 : }
2060 :
2061 : /*
2062 : * \r -- reset (clear) the query buffer
2063 : */
2064 : static backslashResult
2065 4 : exec_command_reset(PsqlScanState scan_state, bool active_branch,
2066 : PQExpBuffer query_buf)
2067 : {
2068 4 : if (active_branch)
2069 : {
2070 3 : resetPQExpBuffer(query_buf);
2071 3 : psql_scan_reset(scan_state);
2072 3 : if (!pset.quiet)
2073 0 : puts(_("Query buffer reset (cleared)."));
2074 : }
2075 :
2076 4 : return PSQL_CMD_SKIP_LINE;
2077 : }
2078 :
2079 : /*
2080 : * \s -- save history in a file or show it on the screen
2081 : */
2082 : static backslashResult
2083 1 : exec_command_s(PsqlScanState scan_state, bool active_branch)
2084 : {
2085 1 : bool success = true;
2086 :
2087 1 : if (active_branch)
2088 : {
2089 0 : char *fname = psql_scan_slash_option(scan_state,
2090 : OT_NORMAL, NULL, true);
2091 :
2092 0 : expand_tilde(&fname);
2093 0 : success = printHistory(fname, pset.popt.topt.pager);
2094 0 : if (success && !pset.quiet && fname)
2095 0 : printf(_("Wrote history to file \"%s\".\n"), fname);
2096 0 : if (!fname)
2097 0 : putchar('\n');
2098 0 : free(fname);
2099 : }
2100 : else
2101 1 : ignore_slash_options(scan_state);
2102 :
2103 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2104 : }
2105 :
2106 : /*
2107 : * \set -- set variable
2108 : */
2109 : static backslashResult
2110 64 : exec_command_set(PsqlScanState scan_state, bool active_branch)
2111 : {
2112 64 : bool success = true;
2113 :
2114 64 : if (active_branch)
2115 : {
2116 63 : char *opt0 = psql_scan_slash_option(scan_state,
2117 : OT_NORMAL, NULL, false);
2118 :
2119 63 : if (!opt0)
2120 : {
2121 : /* list all variables */
2122 0 : PrintVariables(pset.vars);
2123 0 : success = true;
2124 : }
2125 : else
2126 : {
2127 : /*
2128 : * Set variable to the concatenation of the arguments.
2129 : */
2130 : char *newval;
2131 : char *opt;
2132 :
2133 63 : opt = psql_scan_slash_option(scan_state,
2134 : OT_NORMAL, NULL, false);
2135 63 : newval = pg_strdup(opt ? opt : "");
2136 63 : free(opt);
2137 :
2138 126 : while ((opt = psql_scan_slash_option(scan_state,
2139 : OT_NORMAL, NULL, false)))
2140 : {
2141 0 : newval = pg_realloc(newval, strlen(newval) + strlen(opt) + 1);
2142 0 : strcat(newval, opt);
2143 0 : free(opt);
2144 : }
2145 :
2146 63 : if (!SetVariable(pset.vars, opt0, newval))
2147 4 : success = false;
2148 :
2149 63 : free(newval);
2150 : }
2151 63 : free(opt0);
2152 : }
2153 : else
2154 1 : ignore_slash_options(scan_state);
2155 :
2156 64 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2157 : }
2158 :
2159 : /*
2160 : * \setenv -- set environment variable
2161 : */
2162 : static backslashResult
2163 1 : exec_command_setenv(PsqlScanState scan_state, bool active_branch,
2164 : const char *cmd)
2165 : {
2166 1 : bool success = true;
2167 :
2168 1 : if (active_branch)
2169 : {
2170 0 : char *envvar = psql_scan_slash_option(scan_state,
2171 : OT_NORMAL, NULL, false);
2172 0 : char *envval = psql_scan_slash_option(scan_state,
2173 : OT_NORMAL, NULL, false);
2174 :
2175 0 : if (!envvar)
2176 : {
2177 0 : psql_error("\\%s: missing required argument\n", cmd);
2178 0 : success = false;
2179 : }
2180 0 : else if (strchr(envvar, '=') != NULL)
2181 : {
2182 0 : psql_error("\\%s: environment variable name must not contain \"=\"\n",
2183 : cmd);
2184 0 : success = false;
2185 : }
2186 0 : else if (!envval)
2187 : {
2188 : /* No argument - unset the environment variable */
2189 0 : unsetenv(envvar);
2190 0 : success = true;
2191 : }
2192 : else
2193 : {
2194 : /* Set variable to the value of the next argument */
2195 : char *newval;
2196 :
2197 0 : newval = psprintf("%s=%s", envvar, envval);
2198 0 : putenv(newval);
2199 0 : success = true;
2200 :
2201 : /*
2202 : * Do not free newval here, it will screw up the environment if
2203 : * you do. See putenv man page for details. That means we leak a
2204 : * bit of memory here, but not enough to worry about.
2205 : */
2206 : }
2207 0 : free(envvar);
2208 0 : free(envval);
2209 : }
2210 : else
2211 1 : ignore_slash_options(scan_state);
2212 :
2213 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2214 : }
2215 :
2216 : /*
2217 : * \sf -- show a function's source code
2218 : */
2219 : static backslashResult
2220 1 : exec_command_sf(PsqlScanState scan_state, bool active_branch, const char *cmd)
2221 : {
2222 1 : backslashResult status = PSQL_CMD_SKIP_LINE;
2223 :
2224 1 : if (active_branch)
2225 : {
2226 0 : bool show_linenumbers = (strcmp(cmd, "sf+") == 0);
2227 : PQExpBuffer func_buf;
2228 : char *func;
2229 0 : Oid foid = InvalidOid;
2230 :
2231 0 : func_buf = createPQExpBuffer();
2232 0 : func = psql_scan_slash_option(scan_state,
2233 : OT_WHOLE_LINE, NULL, true);
2234 0 : if (pset.sversion < 80400)
2235 : {
2236 : char sverbuf[32];
2237 :
2238 0 : psql_error("The server (version %s) does not support showing function source.\n",
2239 : formatPGVersionNumber(pset.sversion, false,
2240 : sverbuf, sizeof(sverbuf)));
2241 0 : status = PSQL_CMD_ERROR;
2242 : }
2243 0 : else if (!func)
2244 : {
2245 0 : psql_error("function name is required\n");
2246 0 : status = PSQL_CMD_ERROR;
2247 : }
2248 0 : else if (!lookup_object_oid(EditableFunction, func, &foid))
2249 : {
2250 : /* error already reported */
2251 0 : status = PSQL_CMD_ERROR;
2252 : }
2253 0 : else if (!get_create_object_cmd(EditableFunction, foid, func_buf))
2254 : {
2255 : /* error already reported */
2256 0 : status = PSQL_CMD_ERROR;
2257 : }
2258 : else
2259 : {
2260 : FILE *output;
2261 : bool is_pager;
2262 :
2263 : /* Select output stream: stdout, pager, or file */
2264 0 : if (pset.queryFout == stdout)
2265 : {
2266 : /* count lines in function to see if pager is needed */
2267 0 : int lineno = count_lines_in_buf(func_buf);
2268 :
2269 0 : output = PageOutput(lineno, &(pset.popt.topt));
2270 0 : is_pager = true;
2271 : }
2272 : else
2273 : {
2274 : /* use previously set output file, without pager */
2275 0 : output = pset.queryFout;
2276 0 : is_pager = false;
2277 : }
2278 :
2279 0 : if (show_linenumbers)
2280 : {
2281 : /*
2282 : * lineno "1" should correspond to the first line of the
2283 : * function body. We expect that pg_get_functiondef() will
2284 : * emit that on a line beginning with "AS ", and that there
2285 : * can be no such line before the real start of the function
2286 : * body.
2287 : */
2288 0 : print_with_linenumbers(output, func_buf->data, "AS ");
2289 : }
2290 : else
2291 : {
2292 : /* just send the function definition to output */
2293 0 : fputs(func_buf->data, output);
2294 : }
2295 :
2296 0 : if (is_pager)
2297 0 : ClosePager(output);
2298 : }
2299 :
2300 0 : if (func)
2301 0 : free(func);
2302 0 : destroyPQExpBuffer(func_buf);
2303 : }
2304 : else
2305 1 : ignore_slash_whole_line(scan_state);
2306 :
2307 1 : return status;
2308 : }
2309 :
2310 : /*
2311 : * \sv -- show a view's source code
2312 : */
2313 : static backslashResult
2314 2 : exec_command_sv(PsqlScanState scan_state, bool active_branch, const char *cmd)
2315 : {
2316 2 : backslashResult status = PSQL_CMD_SKIP_LINE;
2317 :
2318 2 : if (active_branch)
2319 : {
2320 1 : bool show_linenumbers = (strcmp(cmd, "sv+") == 0);
2321 : PQExpBuffer view_buf;
2322 : char *view;
2323 1 : Oid view_oid = InvalidOid;
2324 :
2325 1 : view_buf = createPQExpBuffer();
2326 1 : view = psql_scan_slash_option(scan_state,
2327 : OT_WHOLE_LINE, NULL, true);
2328 1 : if (pset.sversion < 70400)
2329 : {
2330 : char sverbuf[32];
2331 :
2332 0 : psql_error("The server (version %s) does not support showing view definitions.\n",
2333 : formatPGVersionNumber(pset.sversion, false,
2334 : sverbuf, sizeof(sverbuf)));
2335 0 : status = PSQL_CMD_ERROR;
2336 : }
2337 1 : else if (!view)
2338 : {
2339 0 : psql_error("view name is required\n");
2340 0 : status = PSQL_CMD_ERROR;
2341 : }
2342 1 : else if (!lookup_object_oid(EditableView, view, &view_oid))
2343 : {
2344 : /* error already reported */
2345 0 : status = PSQL_CMD_ERROR;
2346 : }
2347 1 : else if (!get_create_object_cmd(EditableView, view_oid, view_buf))
2348 : {
2349 : /* error already reported */
2350 0 : status = PSQL_CMD_ERROR;
2351 : }
2352 : else
2353 : {
2354 : FILE *output;
2355 : bool is_pager;
2356 :
2357 : /* Select output stream: stdout, pager, or file */
2358 1 : if (pset.queryFout == stdout)
2359 : {
2360 : /* count lines in view to see if pager is needed */
2361 1 : int lineno = count_lines_in_buf(view_buf);
2362 :
2363 1 : output = PageOutput(lineno, &(pset.popt.topt));
2364 1 : is_pager = true;
2365 : }
2366 : else
2367 : {
2368 : /* use previously set output file, without pager */
2369 0 : output = pset.queryFout;
2370 0 : is_pager = false;
2371 : }
2372 :
2373 1 : if (show_linenumbers)
2374 : {
2375 : /* add line numbers, numbering all lines */
2376 0 : print_with_linenumbers(output, view_buf->data, NULL);
2377 : }
2378 : else
2379 : {
2380 : /* just send the view definition to output */
2381 1 : fputs(view_buf->data, output);
2382 : }
2383 :
2384 1 : if (is_pager)
2385 1 : ClosePager(output);
2386 : }
2387 :
2388 1 : if (view)
2389 1 : free(view);
2390 1 : destroyPQExpBuffer(view_buf);
2391 : }
2392 : else
2393 1 : ignore_slash_whole_line(scan_state);
2394 :
2395 2 : return status;
2396 : }
2397 :
2398 : /*
2399 : * \t -- turn off table headers and row count
2400 : */
2401 : static backslashResult
2402 7 : exec_command_t(PsqlScanState scan_state, bool active_branch)
2403 : {
2404 7 : bool success = true;
2405 :
2406 7 : if (active_branch)
2407 : {
2408 6 : char *opt = psql_scan_slash_option(scan_state,
2409 : OT_NORMAL, NULL, true);
2410 :
2411 6 : success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
2412 6 : free(opt);
2413 : }
2414 : else
2415 1 : ignore_slash_options(scan_state);
2416 :
2417 7 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2418 : }
2419 :
2420 : /*
2421 : * \T -- define html <table ...> attributes
2422 : */
2423 : static backslashResult
2424 1 : exec_command_T(PsqlScanState scan_state, bool active_branch)
2425 : {
2426 1 : bool success = true;
2427 :
2428 1 : if (active_branch)
2429 : {
2430 0 : char *value = psql_scan_slash_option(scan_state,
2431 : OT_NORMAL, NULL, false);
2432 :
2433 0 : success = do_pset("tableattr", value, &pset.popt, pset.quiet);
2434 0 : free(value);
2435 : }
2436 : else
2437 1 : ignore_slash_options(scan_state);
2438 :
2439 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2440 : }
2441 :
2442 : /*
2443 : * \timing -- enable/disable timing of queries
2444 : */
2445 : static backslashResult
2446 1 : exec_command_timing(PsqlScanState scan_state, bool active_branch)
2447 : {
2448 1 : bool success = true;
2449 :
2450 1 : if (active_branch)
2451 : {
2452 0 : char *opt = psql_scan_slash_option(scan_state,
2453 : OT_NORMAL, NULL, false);
2454 :
2455 0 : if (opt)
2456 0 : success = ParseVariableBool(opt, "\\timing", &pset.timing);
2457 : else
2458 0 : pset.timing = !pset.timing;
2459 0 : if (!pset.quiet)
2460 : {
2461 0 : if (pset.timing)
2462 0 : puts(_("Timing is on."));
2463 : else
2464 0 : puts(_("Timing is off."));
2465 : }
2466 0 : free(opt);
2467 : }
2468 : else
2469 1 : ignore_slash_options(scan_state);
2470 :
2471 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2472 : }
2473 :
2474 : /*
2475 : * \unset -- unset variable
2476 : */
2477 : static backslashResult
2478 5 : exec_command_unset(PsqlScanState scan_state, bool active_branch,
2479 : const char *cmd)
2480 : {
2481 5 : bool success = true;
2482 :
2483 5 : if (active_branch)
2484 : {
2485 4 : char *opt = psql_scan_slash_option(scan_state,
2486 : OT_NORMAL, NULL, false);
2487 :
2488 4 : if (!opt)
2489 : {
2490 0 : psql_error("\\%s: missing required argument\n", cmd);
2491 0 : success = false;
2492 : }
2493 4 : else if (!SetVariable(pset.vars, opt, NULL))
2494 0 : success = false;
2495 :
2496 4 : free(opt);
2497 : }
2498 : else
2499 1 : ignore_slash_options(scan_state);
2500 :
2501 5 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2502 : }
2503 :
2504 : /*
2505 : * \w -- write query buffer to file
2506 : */
2507 : static backslashResult
2508 2 : exec_command_write(PsqlScanState scan_state, bool active_branch,
2509 : const char *cmd,
2510 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
2511 : {
2512 2 : backslashResult status = PSQL_CMD_SKIP_LINE;
2513 :
2514 2 : if (active_branch)
2515 : {
2516 0 : char *fname = psql_scan_slash_option(scan_state,
2517 : OT_FILEPIPE, NULL, true);
2518 0 : FILE *fd = NULL;
2519 0 : bool is_pipe = false;
2520 :
2521 0 : if (!query_buf)
2522 : {
2523 0 : psql_error("no query buffer\n");
2524 0 : status = PSQL_CMD_ERROR;
2525 : }
2526 : else
2527 : {
2528 0 : if (!fname)
2529 : {
2530 0 : psql_error("\\%s: missing required argument\n", cmd);
2531 0 : status = PSQL_CMD_ERROR;
2532 : }
2533 : else
2534 : {
2535 0 : expand_tilde(&fname);
2536 0 : if (fname[0] == '|')
2537 : {
2538 0 : is_pipe = true;
2539 0 : disable_sigpipe_trap();
2540 0 : fd = popen(&fname[1], "w");
2541 : }
2542 : else
2543 : {
2544 0 : canonicalize_path(fname);
2545 0 : fd = fopen(fname, "w");
2546 : }
2547 0 : if (!fd)
2548 : {
2549 0 : psql_error("%s: %s\n", fname, strerror(errno));
2550 0 : status = PSQL_CMD_ERROR;
2551 : }
2552 : }
2553 : }
2554 :
2555 0 : if (fd)
2556 : {
2557 : int result;
2558 :
2559 : /*
2560 : * We want to print the same thing \g would execute, but not to
2561 : * change the query buffer state; so we can't use
2562 : * copy_previous_query(). Also, beware of possibility that buffer
2563 : * pointers are NULL.
2564 : */
2565 0 : if (query_buf && query_buf->len > 0)
2566 0 : fprintf(fd, "%s\n", query_buf->data);
2567 0 : else if (previous_buf && previous_buf->len > 0)
2568 0 : fprintf(fd, "%s\n", previous_buf->data);
2569 :
2570 0 : if (is_pipe)
2571 0 : result = pclose(fd);
2572 : else
2573 0 : result = fclose(fd);
2574 :
2575 0 : if (result == EOF)
2576 : {
2577 0 : psql_error("%s: %s\n", fname, strerror(errno));
2578 0 : status = PSQL_CMD_ERROR;
2579 : }
2580 : }
2581 :
2582 0 : if (is_pipe)
2583 0 : restore_sigpipe_trap();
2584 :
2585 0 : free(fname);
2586 : }
2587 : else
2588 2 : ignore_slash_filepipe(scan_state);
2589 :
2590 2 : return status;
2591 : }
2592 :
2593 : /*
2594 : * \watch -- execute a query every N seconds
2595 : */
2596 : static backslashResult
2597 1 : exec_command_watch(PsqlScanState scan_state, bool active_branch,
2598 : PQExpBuffer query_buf, PQExpBuffer previous_buf)
2599 : {
2600 1 : bool success = true;
2601 :
2602 1 : if (active_branch)
2603 : {
2604 0 : char *opt = psql_scan_slash_option(scan_state,
2605 : OT_NORMAL, NULL, true);
2606 0 : double sleep = 2;
2607 :
2608 : /* Convert optional sleep-length argument */
2609 0 : if (opt)
2610 : {
2611 0 : sleep = strtod(opt, NULL);
2612 0 : if (sleep <= 0)
2613 0 : sleep = 1;
2614 0 : free(opt);
2615 : }
2616 :
2617 : /* If query_buf is empty, recall and execute previous query */
2618 0 : copy_previous_query(query_buf, previous_buf);
2619 :
2620 0 : success = do_watch(query_buf, sleep);
2621 :
2622 : /* Reset the query buffer as though for \r */
2623 0 : resetPQExpBuffer(query_buf);
2624 0 : psql_scan_reset(scan_state);
2625 : }
2626 : else
2627 1 : ignore_slash_options(scan_state);
2628 :
2629 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2630 : }
2631 :
2632 : /*
2633 : * \x -- set or toggle expanded table representation
2634 : */
2635 : static backslashResult
2636 1 : exec_command_x(PsqlScanState scan_state, bool active_branch)
2637 : {
2638 1 : bool success = true;
2639 :
2640 1 : if (active_branch)
2641 : {
2642 0 : char *opt = psql_scan_slash_option(scan_state,
2643 : OT_NORMAL, NULL, true);
2644 :
2645 0 : success = do_pset("expanded", opt, &pset.popt, pset.quiet);
2646 0 : free(opt);
2647 : }
2648 : else
2649 1 : ignore_slash_options(scan_state);
2650 :
2651 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2652 : }
2653 :
2654 : /*
2655 : * \z -- list table privileges (equivalent to \dp)
2656 : */
2657 : static backslashResult
2658 2 : exec_command_z(PsqlScanState scan_state, bool active_branch)
2659 : {
2660 2 : bool success = true;
2661 :
2662 2 : if (active_branch)
2663 : {
2664 2 : char *pattern = psql_scan_slash_option(scan_state,
2665 : OT_NORMAL, NULL, true);
2666 :
2667 2 : success = permissionsList(pattern);
2668 2 : if (pattern)
2669 2 : free(pattern);
2670 : }
2671 : else
2672 0 : ignore_slash_options(scan_state);
2673 :
2674 2 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2675 : }
2676 :
2677 : /*
2678 : * \! -- execute shell command
2679 : */
2680 : static backslashResult
2681 1 : exec_command_shell_escape(PsqlScanState scan_state, bool active_branch)
2682 : {
2683 1 : bool success = true;
2684 :
2685 1 : if (active_branch)
2686 : {
2687 0 : char *opt = psql_scan_slash_option(scan_state,
2688 : OT_WHOLE_LINE, NULL, false);
2689 :
2690 0 : success = do_shell(opt);
2691 0 : free(opt);
2692 : }
2693 : else
2694 1 : ignore_slash_whole_line(scan_state);
2695 :
2696 1 : return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2697 : }
2698 :
2699 : /*
2700 : * \? -- print help about backslash commands
2701 : */
2702 : static backslashResult
2703 0 : exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch)
2704 : {
2705 0 : if (active_branch)
2706 : {
2707 0 : char *opt0 = psql_scan_slash_option(scan_state,
2708 : OT_NORMAL, NULL, false);
2709 :
2710 0 : if (!opt0 || strcmp(opt0, "commands") == 0)
2711 0 : slashUsage(pset.popt.topt.pager);
2712 0 : else if (strcmp(opt0, "options") == 0)
2713 0 : usage(pset.popt.topt.pager);
2714 0 : else if (strcmp(opt0, "variables") == 0)
2715 0 : helpVariables(pset.popt.topt.pager);
2716 : else
2717 0 : slashUsage(pset.popt.topt.pager);
2718 :
2719 0 : if (opt0)
2720 0 : free(opt0);
2721 : }
2722 : else
2723 0 : ignore_slash_options(scan_state);
2724 :
2725 0 : return PSQL_CMD_SKIP_LINE;
2726 : }
2727 :
2728 :
2729 : /*
2730 : * Read and interpret an argument to the \connect slash command.
2731 : *
2732 : * Returns a malloc'd string, or NULL if no/empty argument.
2733 : */
2734 : static char *
2735 132 : read_connect_arg(PsqlScanState scan_state)
2736 : {
2737 : char *result;
2738 : char quote;
2739 :
2740 : /*
2741 : * Ideally we should treat the arguments as SQL identifiers. But for
2742 : * backwards compatibility with 7.2 and older pg_dump files, we have to
2743 : * take unquoted arguments verbatim (don't downcase them). For now,
2744 : * double-quoted arguments may be stripped of double quotes (as if SQL
2745 : * identifiers). By 7.4 or so, pg_dump files can be expected to
2746 : * double-quote all mixed-case \connect arguments, and then we can get rid
2747 : * of OT_SQLIDHACK.
2748 : */
2749 132 : result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, "e, true);
2750 :
2751 132 : if (!result)
2752 108 : return NULL;
2753 :
2754 24 : if (quote)
2755 0 : return result;
2756 :
2757 24 : if (*result == '\0' || strcmp(result, "-") == 0)
2758 : {
2759 24 : free(result);
2760 24 : return NULL;
2761 : }
2762 :
2763 0 : return result;
2764 : }
2765 :
2766 : /*
2767 : * Read a boolean expression, return it as a PQExpBuffer string.
2768 : *
2769 : * Note: anything more or less than one token will certainly fail to be
2770 : * parsed by ParseVariableBool, so we don't worry about complaining here.
2771 : * This routine's return data structure will need to be rethought anyway
2772 : * to support likely future extensions such as "\if defined VARNAME".
2773 : */
2774 : static PQExpBuffer
2775 20 : gather_boolean_expression(PsqlScanState scan_state)
2776 : {
2777 20 : PQExpBuffer exp_buf = createPQExpBuffer();
2778 20 : int num_options = 0;
2779 : char *value;
2780 :
2781 : /* collect all arguments for the conditional command into exp_buf */
2782 62 : while ((value = psql_scan_slash_option(scan_state,
2783 : OT_NORMAL, NULL, false)) != NULL)
2784 : {
2785 : /* add spaces between tokens */
2786 22 : if (num_options > 0)
2787 2 : appendPQExpBufferChar(exp_buf, ' ');
2788 22 : appendPQExpBufferStr(exp_buf, value);
2789 22 : num_options++;
2790 22 : free(value);
2791 : }
2792 :
2793 20 : return exp_buf;
2794 : }
2795 :
2796 : /*
2797 : * Read a boolean expression, return true if the expression
2798 : * was a valid boolean expression that evaluated to true.
2799 : * Otherwise return false.
2800 : *
2801 : * Note: conditional stack's top state must be active, else lexer will
2802 : * fail to expand variables and backticks.
2803 : */
2804 : static bool
2805 19 : is_true_boolean_expression(PsqlScanState scan_state, const char *name)
2806 : {
2807 19 : PQExpBuffer buf = gather_boolean_expression(scan_state);
2808 19 : bool value = false;
2809 19 : bool success = ParseVariableBool(buf->data, name, &value);
2810 :
2811 19 : destroyPQExpBuffer(buf);
2812 19 : return success && value;
2813 : }
2814 :
2815 : /*
2816 : * Read a boolean expression, but do nothing with it.
2817 : *
2818 : * Note: conditional stack's top state must be INACTIVE, else lexer will
2819 : * expand variables and backticks, which we do not want here.
2820 : */
2821 : static void
2822 1 : ignore_boolean_expression(PsqlScanState scan_state)
2823 : {
2824 1 : PQExpBuffer buf = gather_boolean_expression(scan_state);
2825 :
2826 1 : destroyPQExpBuffer(buf);
2827 1 : }
2828 :
2829 : /*
2830 : * Read and discard "normal" slash command options.
2831 : *
2832 : * This should be used for inactive-branch processing of any slash command
2833 : * that eats one or more OT_NORMAL, OT_SQLID, or OT_SQLIDHACK parameters.
2834 : * We don't need to worry about exactly how many it would eat, since the
2835 : * cleanup logic in HandleSlashCmds would silently discard any extras anyway.
2836 : */
2837 : static void
2838 37 : ignore_slash_options(PsqlScanState scan_state)
2839 : {
2840 : char *arg;
2841 :
2842 136 : while ((arg = psql_scan_slash_option(scan_state,
2843 : OT_NORMAL, NULL, false)) != NULL)
2844 62 : free(arg);
2845 37 : }
2846 :
2847 : /*
2848 : * Read and discard FILEPIPE slash command argument.
2849 : *
2850 : * This *MUST* be used for inactive-branch processing of any slash command
2851 : * that takes an OT_FILEPIPE option. Otherwise we might consume a different
2852 : * amount of option text in active and inactive cases.
2853 : */
2854 : static void
2855 5 : ignore_slash_filepipe(PsqlScanState scan_state)
2856 : {
2857 5 : char *arg = psql_scan_slash_option(scan_state,
2858 : OT_FILEPIPE, NULL, false);
2859 :
2860 5 : if (arg)
2861 5 : free(arg);
2862 5 : }
2863 :
2864 : /*
2865 : * Read and discard whole-line slash command argument.
2866 : *
2867 : * This *MUST* be used for inactive-branch processing of any slash command
2868 : * that takes an OT_WHOLE_LINE option. Otherwise we might consume a different
2869 : * amount of option text in active and inactive cases.
2870 : */
2871 : static void
2872 7 : ignore_slash_whole_line(PsqlScanState scan_state)
2873 : {
2874 7 : char *arg = psql_scan_slash_option(scan_state,
2875 : OT_WHOLE_LINE, NULL, false);
2876 :
2877 7 : if (arg)
2878 7 : free(arg);
2879 7 : }
2880 :
2881 : /*
2882 : * Return true if the command given is a branching command.
2883 : */
2884 : static bool
2885 0 : is_branching_command(const char *cmd)
2886 : {
2887 0 : return (strcmp(cmd, "if") == 0 ||
2888 0 : strcmp(cmd, "elif") == 0 ||
2889 0 : strcmp(cmd, "else") == 0 ||
2890 0 : strcmp(cmd, "endif") == 0);
2891 : }
2892 :
2893 : /*
2894 : * Prepare to possibly restore query buffer to its current state
2895 : * (cf. discard_query_text).
2896 : *
2897 : * We need to remember the length of the query buffer, and the lexer's
2898 : * notion of the parenthesis nesting depth.
2899 : */
2900 : static void
2901 25 : save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
2902 : PQExpBuffer query_buf)
2903 : {
2904 25 : if (query_buf)
2905 25 : conditional_stack_set_query_len(cstack, query_buf->len);
2906 25 : conditional_stack_set_paren_depth(cstack,
2907 : psql_scan_get_paren_depth(scan_state));
2908 25 : }
2909 :
2910 : /*
2911 : * Discard any query text absorbed during an inactive conditional branch.
2912 : *
2913 : * We must discard data that was appended to query_buf during an inactive
2914 : * \if branch. We don't have to do anything there if there's no query_buf.
2915 : *
2916 : * Also, reset the lexer state to the same paren depth there was before.
2917 : * (The rest of its state doesn't need attention, since we could not be
2918 : * inside a comment or literal or partial token.)
2919 : */
2920 : static void
2921 21 : discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
2922 : PQExpBuffer query_buf)
2923 : {
2924 21 : if (query_buf)
2925 : {
2926 21 : int new_len = conditional_stack_get_query_len(cstack);
2927 :
2928 21 : Assert(new_len >= 0 && new_len <= query_buf->len);
2929 21 : query_buf->len = new_len;
2930 21 : query_buf->data[new_len] = '\0';
2931 : }
2932 21 : psql_scan_set_paren_depth(scan_state,
2933 : conditional_stack_get_paren_depth(cstack));
2934 21 : }
2935 :
2936 : /*
2937 : * If query_buf is empty, copy previous_buf into it.
2938 : *
2939 : * This is used by various slash commands for which re-execution of a
2940 : * previous query is a common usage. For convenience, we allow the
2941 : * case of query_buf == NULL (and do nothing).
2942 : */
2943 : static void
2944 56 : copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
2945 : {
2946 56 : if (query_buf && query_buf->len == 0)
2947 8 : appendPQExpBufferStr(query_buf, previous_buf->data);
2948 56 : }
2949 :
2950 : /*
2951 : * Ask the user for a password; 'username' is the username the
2952 : * password is for, if one has been explicitly specified. Returns a
2953 : * malloc'd string.
2954 : */
2955 : static char *
2956 0 : prompt_for_password(const char *username)
2957 : {
2958 : char buf[100];
2959 :
2960 0 : if (username == NULL)
2961 0 : simple_prompt("Password: ", buf, sizeof(buf), false);
2962 : else
2963 : {
2964 : char *prompt_text;
2965 :
2966 0 : prompt_text = psprintf(_("Password for user %s: "), username);
2967 0 : simple_prompt(prompt_text, buf, sizeof(buf), false);
2968 0 : free(prompt_text);
2969 : }
2970 0 : return pg_strdup(buf);
2971 : }
2972 :
2973 : static bool
2974 0 : param_is_newly_set(const char *old_val, const char *new_val)
2975 : {
2976 0 : if (new_val == NULL)
2977 0 : return false;
2978 :
2979 0 : if (old_val == NULL || strcmp(old_val, new_val) != 0)
2980 0 : return true;
2981 :
2982 0 : return false;
2983 : }
2984 :
2985 : /*
2986 : * do_connect -- handler for \connect
2987 : *
2988 : * Connects to a database with given parameters. Absent an established
2989 : * connection, all parameters are required. Given -reuse-previous=off or a
2990 : * connection string without -reuse-previous=on, NULL values will pass through
2991 : * to PQconnectdbParams(), so the libpq defaults will be used. Otherwise, NULL
2992 : * values will be replaced with the ones in the current connection.
2993 : *
2994 : * In interactive mode, if connection fails with the given parameters,
2995 : * the old connection will be kept.
2996 : */
2997 : static bool
2998 33 : do_connect(enum trivalue reuse_previous_specification,
2999 : char *dbname, char *user, char *host, char *port)
3000 : {
3001 33 : PGconn *o_conn = pset.db,
3002 : *n_conn;
3003 33 : char *password = NULL;
3004 : bool keep_password;
3005 : bool has_connection_string;
3006 : bool reuse_previous;
3007 : PQExpBufferData connstr;
3008 :
3009 33 : if (!o_conn && (!dbname || !user || !host || !port))
3010 : {
3011 : /*
3012 : * We don't know the supplied connection parameters and don't want to
3013 : * connect to the wrong database by using defaults, so require all
3014 : * parameters to be specified.
3015 : */
3016 0 : psql_error("All connection parameters must be supplied because no "
3017 : "database connection exists\n");
3018 0 : return false;
3019 : }
3020 :
3021 33 : has_connection_string = dbname ?
3022 : recognized_connection_string(dbname) : false;
3023 33 : switch (reuse_previous_specification)
3024 : {
3025 : case TRI_YES:
3026 0 : reuse_previous = true;
3027 0 : break;
3028 : case TRI_NO:
3029 0 : reuse_previous = false;
3030 0 : break;
3031 : default:
3032 33 : reuse_previous = !has_connection_string;
3033 33 : break;
3034 : }
3035 : /* Silently ignore arguments subsequent to a connection string. */
3036 33 : if (has_connection_string)
3037 : {
3038 0 : user = NULL;
3039 0 : host = NULL;
3040 0 : port = NULL;
3041 : }
3042 :
3043 : /* grab missing values from the old connection */
3044 33 : if (!user && reuse_previous)
3045 33 : user = PQuser(o_conn);
3046 33 : if (!host && reuse_previous)
3047 33 : host = PQhost(o_conn);
3048 33 : if (!port && reuse_previous)
3049 33 : port = PQport(o_conn);
3050 :
3051 : /*
3052 : * Any change in the parameters read above makes us discard the password.
3053 : * We also discard it if we're to use a conninfo rather than the
3054 : * positional syntax.
3055 : */
3056 33 : if (has_connection_string)
3057 0 : keep_password = false;
3058 : else
3059 33 : keep_password =
3060 33 : (user && PQuser(o_conn) && strcmp(user, PQuser(o_conn)) == 0) &&
3061 99 : (host && PQhost(o_conn) && strcmp(host, PQhost(o_conn)) == 0) &&
3062 33 : (port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0);
3063 :
3064 : /*
3065 : * Grab missing dbname from old connection. No password discard if this
3066 : * changes: passwords aren't (usually) database-specific.
3067 : */
3068 33 : if (!dbname && reuse_previous)
3069 : {
3070 33 : initPQExpBuffer(&connstr);
3071 33 : appendPQExpBuffer(&connstr, "dbname=");
3072 33 : appendConnStrVal(&connstr, PQdb(o_conn));
3073 33 : dbname = connstr.data;
3074 : /* has_connection_string=true would be a dead store */
3075 : }
3076 : else
3077 0 : connstr.data = NULL;
3078 :
3079 : /*
3080 : * If the user asked to be prompted for a password, ask for one now. If
3081 : * not, use the password from the old connection, provided the username
3082 : * etc have not changed. Otherwise, try to connect without a password
3083 : * first, and then ask for a password if needed.
3084 : *
3085 : * XXX: this behavior leads to spurious connection attempts recorded in
3086 : * the postmaster's log. But libpq offers no API that would let us obtain
3087 : * a password and then continue with the first connection attempt.
3088 : */
3089 33 : if (pset.getPassword == TRI_YES)
3090 : {
3091 0 : password = prompt_for_password(user);
3092 : }
3093 33 : else if (o_conn && keep_password)
3094 : {
3095 33 : password = PQpass(o_conn);
3096 33 : if (password && *password)
3097 0 : password = pg_strdup(password);
3098 : else
3099 33 : password = NULL;
3100 : }
3101 :
3102 : while (true)
3103 : {
3104 : #define PARAMS_ARRAY_SIZE 8
3105 33 : const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
3106 33 : const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
3107 33 : int paramnum = -1;
3108 :
3109 33 : keywords[++paramnum] = "host";
3110 33 : values[paramnum] = host;
3111 33 : keywords[++paramnum] = "port";
3112 33 : values[paramnum] = port;
3113 33 : keywords[++paramnum] = "user";
3114 33 : values[paramnum] = user;
3115 :
3116 : /*
3117 : * Position in the array matters when the dbname is a connection
3118 : * string, because settings in a connection string override earlier
3119 : * array entries only. Thus, user= in the connection string always
3120 : * takes effect, but client_encoding= often will not.
3121 : *
3122 : * If you change this code, also change the initial-connection code in
3123 : * main(). For no good reason, a connection string password= takes
3124 : * precedence in main() but not here.
3125 : */
3126 33 : keywords[++paramnum] = "dbname";
3127 33 : values[paramnum] = dbname;
3128 33 : keywords[++paramnum] = "password";
3129 33 : values[paramnum] = password;
3130 33 : keywords[++paramnum] = "fallback_application_name";
3131 33 : values[paramnum] = pset.progname;
3132 33 : keywords[++paramnum] = "client_encoding";
3133 33 : values[paramnum] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
3134 :
3135 : /* add array terminator */
3136 33 : keywords[++paramnum] = NULL;
3137 33 : values[paramnum] = NULL;
3138 :
3139 33 : n_conn = PQconnectdbParams(keywords, values, true);
3140 :
3141 33 : pg_free(keywords);
3142 33 : pg_free(values);
3143 :
3144 : /* We can immediately discard the password -- no longer needed */
3145 33 : if (password)
3146 0 : pg_free(password);
3147 :
3148 33 : if (PQstatus(n_conn) == CONNECTION_OK)
3149 33 : break;
3150 :
3151 : /*
3152 : * Connection attempt failed; either retry the connection attempt with
3153 : * a new password, or give up.
3154 : */
3155 0 : if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
3156 : {
3157 0 : PQfinish(n_conn);
3158 0 : password = prompt_for_password(user);
3159 0 : continue;
3160 : }
3161 :
3162 : /*
3163 : * Failed to connect to the database. In interactive mode, keep the
3164 : * previous connection to the DB; in scripting mode, close our
3165 : * previous connection as well.
3166 : */
3167 0 : if (pset.cur_cmd_interactive)
3168 : {
3169 0 : psql_error("%s", PQerrorMessage(n_conn));
3170 :
3171 : /* pset.db is left unmodified */
3172 0 : if (o_conn)
3173 0 : psql_error("Previous connection kept\n");
3174 : }
3175 : else
3176 : {
3177 0 : psql_error("\\connect: %s", PQerrorMessage(n_conn));
3178 0 : if (o_conn)
3179 : {
3180 0 : PQfinish(o_conn);
3181 0 : pset.db = NULL;
3182 : }
3183 : }
3184 :
3185 0 : PQfinish(n_conn);
3186 0 : if (connstr.data)
3187 0 : termPQExpBuffer(&connstr);
3188 0 : return false;
3189 0 : }
3190 33 : if (connstr.data)
3191 33 : termPQExpBuffer(&connstr);
3192 :
3193 : /*
3194 : * Replace the old connection with the new one, and update
3195 : * connection-dependent variables.
3196 : */
3197 33 : PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
3198 33 : pset.db = n_conn;
3199 33 : SyncVariables();
3200 33 : connection_warnings(false); /* Must be after SyncVariables */
3201 :
3202 : /* Tell the user about the new connection */
3203 33 : if (!pset.quiet)
3204 : {
3205 0 : if (!o_conn ||
3206 0 : param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
3207 0 : param_is_newly_set(PQport(o_conn), PQport(pset.db)))
3208 0 : {
3209 0 : char *host = PQhost(pset.db);
3210 :
3211 : /* If the host is an absolute path, the connection is via socket */
3212 0 : if (is_absolute_path(host))
3213 0 : printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
3214 0 : PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3215 : else
3216 0 : printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
3217 0 : PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3218 : }
3219 : else
3220 0 : printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
3221 0 : PQdb(pset.db), PQuser(pset.db));
3222 : }
3223 :
3224 33 : if (o_conn)
3225 33 : PQfinish(o_conn);
3226 33 : return true;
3227 : }
3228 :
3229 :
3230 : void
3231 33 : connection_warnings(bool in_startup)
3232 : {
3233 33 : if (!pset.quiet && !pset.notty)
3234 : {
3235 0 : int client_ver = PG_VERSION_NUM;
3236 : char cverbuf[32];
3237 : char sverbuf[32];
3238 :
3239 0 : if (pset.sversion != client_ver)
3240 : {
3241 : const char *server_version;
3242 :
3243 : /* Try to get full text form, might include "devel" etc */
3244 0 : server_version = PQparameterStatus(pset.db, "server_version");
3245 : /* Otherwise fall back on pset.sversion */
3246 0 : if (!server_version)
3247 : {
3248 0 : formatPGVersionNumber(pset.sversion, true,
3249 : sverbuf, sizeof(sverbuf));
3250 0 : server_version = sverbuf;
3251 : }
3252 :
3253 0 : printf(_("%s (%s, server %s)\n"),
3254 : pset.progname, PG_VERSION, server_version);
3255 : }
3256 : /* For version match, only print psql banner on startup. */
3257 0 : else if (in_startup)
3258 0 : printf("%s (%s)\n", pset.progname, PG_VERSION);
3259 :
3260 0 : if (pset.sversion / 100 > client_ver / 100)
3261 0 : printf(_("WARNING: %s major version %s, server major version %s.\n"
3262 : " Some psql features might not work.\n"),
3263 : pset.progname,
3264 : formatPGVersionNumber(client_ver, false,
3265 : cverbuf, sizeof(cverbuf)),
3266 : formatPGVersionNumber(pset.sversion, false,
3267 : sverbuf, sizeof(sverbuf)));
3268 :
3269 : #ifdef WIN32
3270 : checkWin32Codepage();
3271 : #endif
3272 0 : printSSLInfo();
3273 : }
3274 33 : }
3275 :
3276 :
3277 : /*
3278 : * printSSLInfo
3279 : *
3280 : * Prints information about the current SSL connection, if SSL is in use
3281 : */
3282 : static void
3283 0 : printSSLInfo(void)
3284 : {
3285 : const char *protocol;
3286 : const char *cipher;
3287 : const char *bits;
3288 : const char *compression;
3289 :
3290 0 : if (!PQsslInUse(pset.db))
3291 0 : return; /* no SSL */
3292 :
3293 0 : protocol = PQsslAttribute(pset.db, "protocol");
3294 0 : cipher = PQsslAttribute(pset.db, "cipher");
3295 0 : bits = PQsslAttribute(pset.db, "key_bits");
3296 0 : compression = PQsslAttribute(pset.db, "compression");
3297 :
3298 0 : printf(_("SSL connection (protocol: %s, cipher: %s, bits: %s, compression: %s)\n"),
3299 : protocol ? protocol : _("unknown"),
3300 : cipher ? cipher : _("unknown"),
3301 : bits ? bits : _("unknown"),
3302 0 : (compression && strcmp(compression, "off") != 0) ? _("on") : _("off"));
3303 : }
3304 :
3305 :
3306 : /*
3307 : * checkWin32Codepage
3308 : *
3309 : * Prints a warning when win32 console codepage differs from Windows codepage
3310 : */
3311 : #ifdef WIN32
3312 : static void
3313 : checkWin32Codepage(void)
3314 : {
3315 : unsigned int wincp,
3316 : concp;
3317 :
3318 : wincp = GetACP();
3319 : concp = GetConsoleCP();
3320 : if (wincp != concp)
3321 : {
3322 : printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
3323 : " 8-bit characters might not work correctly. See psql reference\n"
3324 : " page \"Notes for Windows users\" for details.\n"),
3325 : concp, wincp);
3326 : }
3327 : }
3328 : #endif
3329 :
3330 :
3331 : /*
3332 : * SyncVariables
3333 : *
3334 : * Make psql's internal variables agree with connection state upon
3335 : * establishing a new connection.
3336 : */
3337 : void
3338 216 : SyncVariables(void)
3339 : {
3340 : /* get stuff from connection */
3341 216 : pset.encoding = PQclientEncoding(pset.db);
3342 216 : pset.popt.topt.encoding = pset.encoding;
3343 216 : pset.sversion = PQserverVersion(pset.db);
3344 :
3345 216 : SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
3346 216 : SetVariable(pset.vars, "USER", PQuser(pset.db));
3347 216 : SetVariable(pset.vars, "HOST", PQhost(pset.db));
3348 216 : SetVariable(pset.vars, "PORT", PQport(pset.db));
3349 216 : SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
3350 :
3351 : /* send stuff to it, too */
3352 216 : PQsetErrorVerbosity(pset.db, pset.verbosity);
3353 216 : PQsetErrorContextVisibility(pset.db, pset.show_context);
3354 216 : }
3355 :
3356 : /*
3357 : * UnsyncVariables
3358 : *
3359 : * Clear variables that should be not be set when there is no connection.
3360 : */
3361 : void
3362 0 : UnsyncVariables(void)
3363 : {
3364 0 : SetVariable(pset.vars, "DBNAME", NULL);
3365 0 : SetVariable(pset.vars, "USER", NULL);
3366 0 : SetVariable(pset.vars, "HOST", NULL);
3367 0 : SetVariable(pset.vars, "PORT", NULL);
3368 0 : SetVariable(pset.vars, "ENCODING", NULL);
3369 0 : }
3370 :
3371 :
3372 : /*
3373 : * do_edit -- handler for \e
3374 : *
3375 : * If you do not specify a filename, the current query buffer will be copied
3376 : * into a temporary one.
3377 : */
3378 : static bool
3379 0 : editFile(const char *fname, int lineno)
3380 : {
3381 : const char *editorName;
3382 0 : const char *editor_lineno_arg = NULL;
3383 : char *sys;
3384 : int result;
3385 :
3386 0 : Assert(fname != NULL);
3387 :
3388 : /* Find an editor to use */
3389 0 : editorName = getenv("PSQL_EDITOR");
3390 0 : if (!editorName)
3391 0 : editorName = getenv("EDITOR");
3392 0 : if (!editorName)
3393 0 : editorName = getenv("VISUAL");
3394 0 : if (!editorName)
3395 0 : editorName = DEFAULT_EDITOR;
3396 :
3397 : /* Get line number argument, if we need it. */
3398 0 : if (lineno > 0)
3399 : {
3400 0 : editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
3401 : #ifdef DEFAULT_EDITOR_LINENUMBER_ARG
3402 0 : if (!editor_lineno_arg)
3403 0 : editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
3404 : #endif
3405 0 : if (!editor_lineno_arg)
3406 : {
3407 0 : psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
3408 0 : return false;
3409 : }
3410 : }
3411 :
3412 : /*
3413 : * On Unix the EDITOR value should *not* be quoted, since it might include
3414 : * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
3415 : * if necessary. But this policy is not very workable on Windows, due to
3416 : * severe brain damage in their command shell plus the fact that standard
3417 : * program paths include spaces.
3418 : */
3419 : #ifndef WIN32
3420 0 : if (lineno > 0)
3421 0 : sys = psprintf("exec %s %s%d '%s'",
3422 : editorName, editor_lineno_arg, lineno, fname);
3423 : else
3424 0 : sys = psprintf("exec %s '%s'",
3425 : editorName, fname);
3426 : #else
3427 : if (lineno > 0)
3428 : sys = psprintf("\"%s\" %s%d \"%s\"",
3429 : editorName, editor_lineno_arg, lineno, fname);
3430 : else
3431 : sys = psprintf("\"%s\" \"%s\"",
3432 : editorName, fname);
3433 : #endif
3434 0 : result = system(sys);
3435 0 : if (result == -1)
3436 0 : psql_error("could not start editor \"%s\"\n", editorName);
3437 0 : else if (result == 127)
3438 0 : psql_error("could not start /bin/sh\n");
3439 0 : free(sys);
3440 :
3441 0 : return result == 0;
3442 : }
3443 :
3444 :
3445 : /* call this one */
3446 : static bool
3447 0 : do_edit(const char *filename_arg, PQExpBuffer query_buf,
3448 : int lineno, bool *edited)
3449 : {
3450 : char fnametmp[MAXPGPATH];
3451 0 : FILE *stream = NULL;
3452 : const char *fname;
3453 0 : bool error = false;
3454 : int fd;
3455 :
3456 : struct stat before,
3457 : after;
3458 :
3459 0 : if (filename_arg)
3460 0 : fname = filename_arg;
3461 : else
3462 : {
3463 : /* make a temp file to edit */
3464 : #ifndef WIN32
3465 0 : const char *tmpdir = getenv("TMPDIR");
3466 :
3467 0 : if (!tmpdir)
3468 0 : tmpdir = "/tmp";
3469 : #else
3470 : char tmpdir[MAXPGPATH];
3471 : int ret;
3472 :
3473 : ret = GetTempPath(MAXPGPATH, tmpdir);
3474 : if (ret == 0 || ret > MAXPGPATH)
3475 : {
3476 : psql_error("could not locate temporary directory: %s\n",
3477 : !ret ? strerror(errno) : "");
3478 : return false;
3479 : }
3480 :
3481 : /*
3482 : * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
3483 : * current directory to the supplied path unless we use only
3484 : * backslashes, so we do that.
3485 : */
3486 : #endif
3487 : #ifndef WIN32
3488 0 : snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
3489 : "/", (int) getpid());
3490 : #else
3491 : snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
3492 : "" /* trailing separator already present */ , (int) getpid());
3493 : #endif
3494 :
3495 0 : fname = (const char *) fnametmp;
3496 :
3497 0 : fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
3498 0 : if (fd != -1)
3499 0 : stream = fdopen(fd, "w");
3500 :
3501 0 : if (fd == -1 || !stream)
3502 : {
3503 0 : psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
3504 0 : error = true;
3505 : }
3506 : else
3507 : {
3508 0 : unsigned int ql = query_buf->len;
3509 :
3510 0 : if (ql == 0 || query_buf->data[ql - 1] != '\n')
3511 : {
3512 0 : appendPQExpBufferChar(query_buf, '\n');
3513 0 : ql++;
3514 : }
3515 :
3516 0 : if (fwrite(query_buf->data, 1, ql, stream) != ql)
3517 : {
3518 0 : psql_error("%s: %s\n", fname, strerror(errno));
3519 :
3520 0 : if (fclose(stream) != 0)
3521 0 : psql_error("%s: %s\n", fname, strerror(errno));
3522 :
3523 0 : if (remove(fname) != 0)
3524 0 : psql_error("%s: %s\n", fname, strerror(errno));
3525 :
3526 0 : error = true;
3527 : }
3528 0 : else if (fclose(stream) != 0)
3529 : {
3530 0 : psql_error("%s: %s\n", fname, strerror(errno));
3531 0 : if (remove(fname) != 0)
3532 0 : psql_error("%s: %s\n", fname, strerror(errno));
3533 0 : error = true;
3534 : }
3535 : }
3536 : }
3537 :
3538 0 : if (!error && stat(fname, &before) != 0)
3539 : {
3540 0 : psql_error("%s: %s\n", fname, strerror(errno));
3541 0 : error = true;
3542 : }
3543 :
3544 : /* call editor */
3545 0 : if (!error)
3546 0 : error = !editFile(fname, lineno);
3547 :
3548 0 : if (!error && stat(fname, &after) != 0)
3549 : {
3550 0 : psql_error("%s: %s\n", fname, strerror(errno));
3551 0 : error = true;
3552 : }
3553 :
3554 0 : if (!error && before.st_mtime != after.st_mtime)
3555 : {
3556 0 : stream = fopen(fname, PG_BINARY_R);
3557 0 : if (!stream)
3558 : {
3559 0 : psql_error("%s: %s\n", fname, strerror(errno));
3560 0 : error = true;
3561 : }
3562 : else
3563 : {
3564 : /* read file back into query_buf */
3565 : char line[1024];
3566 :
3567 0 : resetPQExpBuffer(query_buf);
3568 0 : while (fgets(line, sizeof(line), stream) != NULL)
3569 0 : appendPQExpBufferStr(query_buf, line);
3570 :
3571 0 : if (ferror(stream))
3572 : {
3573 0 : psql_error("%s: %s\n", fname, strerror(errno));
3574 0 : error = true;
3575 : }
3576 0 : else if (edited)
3577 : {
3578 0 : *edited = true;
3579 : }
3580 :
3581 0 : fclose(stream);
3582 : }
3583 : }
3584 :
3585 : /* remove temp file */
3586 0 : if (!filename_arg)
3587 : {
3588 0 : if (remove(fname) == -1)
3589 : {
3590 0 : psql_error("%s: %s\n", fname, strerror(errno));
3591 0 : error = true;
3592 : }
3593 : }
3594 :
3595 0 : return !error;
3596 : }
3597 :
3598 :
3599 :
3600 : /*
3601 : * process_file
3602 : *
3603 : * Reads commands from filename and passes them to the main processing loop.
3604 : * Handler for \i and \ir, but can be used for other things as well. Returns
3605 : * MainLoop() error code.
3606 : *
3607 : * If use_relative_path is true and filename is not an absolute path, then open
3608 : * the file from where the currently processed file (if any) is located.
3609 : */
3610 : int
3611 181 : process_file(char *filename, bool use_relative_path)
3612 : {
3613 : FILE *fd;
3614 : int result;
3615 : char *oldfilename;
3616 : char relpath[MAXPGPATH];
3617 :
3618 181 : if (!filename)
3619 : {
3620 181 : fd = stdin;
3621 181 : filename = NULL;
3622 : }
3623 0 : else if (strcmp(filename, "-") != 0)
3624 : {
3625 0 : canonicalize_path(filename);
3626 :
3627 : /*
3628 : * If we were asked to resolve the pathname relative to the location
3629 : * of the currently executing script, and there is one, and this is a
3630 : * relative pathname, then prepend all but the last pathname component
3631 : * of the current script to this pathname.
3632 : */
3633 0 : if (use_relative_path && pset.inputfile &&
3634 0 : !is_absolute_path(filename) && !has_drive_prefix(filename))
3635 : {
3636 0 : strlcpy(relpath, pset.inputfile, sizeof(relpath));
3637 0 : get_parent_directory(relpath);
3638 0 : join_path_components(relpath, relpath, filename);
3639 0 : canonicalize_path(relpath);
3640 :
3641 0 : filename = relpath;
3642 : }
3643 :
3644 0 : fd = fopen(filename, PG_BINARY_R);
3645 :
3646 0 : if (!fd)
3647 : {
3648 0 : psql_error("%s: %s\n", filename, strerror(errno));
3649 0 : return EXIT_FAILURE;
3650 : }
3651 : }
3652 : else
3653 : {
3654 0 : fd = stdin;
3655 0 : filename = "<stdin>"; /* for future error messages */
3656 : }
3657 :
3658 181 : oldfilename = pset.inputfile;
3659 181 : pset.inputfile = filename;
3660 :
3661 181 : result = MainLoop(fd);
3662 :
3663 181 : if (fd != stdin)
3664 0 : fclose(fd);
3665 :
3666 181 : pset.inputfile = oldfilename;
3667 181 : return result;
3668 : }
3669 :
3670 :
3671 :
3672 : static const char *
3673 1 : _align2string(enum printFormat in)
3674 : {
3675 1 : switch (in)
3676 : {
3677 : case PRINT_NOTHING:
3678 0 : return "nothing";
3679 : break;
3680 : case PRINT_UNALIGNED:
3681 0 : return "unaligned";
3682 : break;
3683 : case PRINT_ALIGNED:
3684 1 : return "aligned";
3685 : break;
3686 : case PRINT_WRAPPED:
3687 0 : return "wrapped";
3688 : break;
3689 : case PRINT_HTML:
3690 0 : return "html";
3691 : break;
3692 : case PRINT_ASCIIDOC:
3693 0 : return "asciidoc";
3694 : break;
3695 : case PRINT_LATEX:
3696 0 : return "latex";
3697 : break;
3698 : case PRINT_LATEX_LONGTABLE:
3699 0 : return "latex-longtable";
3700 : break;
3701 : case PRINT_TROFF_MS:
3702 0 : return "troff-ms";
3703 : break;
3704 : }
3705 0 : return "unknown";
3706 : }
3707 :
3708 : /*
3709 : * Parse entered Unicode linestyle. If ok, update *linestyle and return
3710 : * true, else return false.
3711 : */
3712 : static bool
3713 0 : set_unicode_line_style(const char *value, size_t vallen,
3714 : unicode_linestyle *linestyle)
3715 : {
3716 0 : if (pg_strncasecmp("single", value, vallen) == 0)
3717 0 : *linestyle = UNICODE_LINESTYLE_SINGLE;
3718 0 : else if (pg_strncasecmp("double", value, vallen) == 0)
3719 0 : *linestyle = UNICODE_LINESTYLE_DOUBLE;
3720 : else
3721 0 : return false;
3722 0 : return true;
3723 : }
3724 :
3725 : static const char *
3726 3 : _unicode_linestyle2string(int linestyle)
3727 : {
3728 3 : switch (linestyle)
3729 : {
3730 : case UNICODE_LINESTYLE_SINGLE:
3731 3 : return "single";
3732 : break;
3733 : case UNICODE_LINESTYLE_DOUBLE:
3734 0 : return "double";
3735 : break;
3736 : }
3737 0 : return "unknown";
3738 : }
3739 :
3740 : /*
3741 : * do_pset
3742 : *
3743 : */
3744 : bool
3745 161 : do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
3746 : {
3747 161 : size_t vallen = 0;
3748 :
3749 161 : Assert(param != NULL);
3750 :
3751 161 : if (value)
3752 155 : vallen = strlen(value);
3753 :
3754 : /* set format */
3755 161 : if (strcmp(param, "format") == 0)
3756 : {
3757 89 : if (!value)
3758 : ;
3759 89 : else if (pg_strncasecmp("unaligned", value, vallen) == 0)
3760 30 : popt->topt.format = PRINT_UNALIGNED;
3761 59 : else if (pg_strncasecmp("aligned", value, vallen) == 0)
3762 31 : popt->topt.format = PRINT_ALIGNED;
3763 28 : else if (pg_strncasecmp("wrapped", value, vallen) == 0)
3764 27 : popt->topt.format = PRINT_WRAPPED;
3765 1 : else if (pg_strncasecmp("html", value, vallen) == 0)
3766 0 : popt->topt.format = PRINT_HTML;
3767 1 : else if (pg_strncasecmp("asciidoc", value, vallen) == 0)
3768 1 : popt->topt.format = PRINT_ASCIIDOC;
3769 0 : else if (pg_strncasecmp("latex", value, vallen) == 0)
3770 0 : popt->topt.format = PRINT_LATEX;
3771 0 : else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
3772 0 : popt->topt.format = PRINT_LATEX_LONGTABLE;
3773 0 : else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
3774 0 : popt->topt.format = PRINT_TROFF_MS;
3775 : else
3776 : {
3777 0 : psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms\n");
3778 0 : return false;
3779 : }
3780 : }
3781 :
3782 : /* set table line style */
3783 72 : else if (strcmp(param, "linestyle") == 0)
3784 : {
3785 5 : if (!value)
3786 : ;
3787 5 : else if (pg_strncasecmp("ascii", value, vallen) == 0)
3788 3 : popt->topt.line_style = &pg_asciiformat;
3789 2 : else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
3790 2 : popt->topt.line_style = &pg_asciiformat_old;
3791 0 : else if (pg_strncasecmp("unicode", value, vallen) == 0)
3792 0 : popt->topt.line_style = &pg_utf8format;
3793 : else
3794 : {
3795 0 : psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
3796 0 : return false;
3797 : }
3798 : }
3799 :
3800 : /* set unicode border line style */
3801 67 : else if (strcmp(param, "unicode_border_linestyle") == 0)
3802 : {
3803 0 : if (!value)
3804 : ;
3805 0 : else if (set_unicode_line_style(value, vallen,
3806 : &popt->topt.unicode_border_linestyle))
3807 0 : refresh_utf8format(&(popt->topt));
3808 : else
3809 : {
3810 0 : psql_error("\\pset: allowed Unicode border line styles are single, double\n");
3811 0 : return false;
3812 : }
3813 : }
3814 :
3815 : /* set unicode column line style */
3816 67 : else if (strcmp(param, "unicode_column_linestyle") == 0)
3817 : {
3818 0 : if (!value)
3819 : ;
3820 0 : else if (set_unicode_line_style(value, vallen,
3821 : &popt->topt.unicode_column_linestyle))
3822 0 : refresh_utf8format(&(popt->topt));
3823 : else
3824 : {
3825 0 : psql_error("\\pset: allowed Unicode column line styles are single, double\n");
3826 0 : return false;
3827 : }
3828 : }
3829 :
3830 : /* set unicode header line style */
3831 67 : else if (strcmp(param, "unicode_header_linestyle") == 0)
3832 : {
3833 0 : if (!value)
3834 : ;
3835 0 : else if (set_unicode_line_style(value, vallen,
3836 : &popt->topt.unicode_header_linestyle))
3837 0 : refresh_utf8format(&(popt->topt));
3838 : else
3839 : {
3840 0 : psql_error("\\pset: allowed Unicode header line styles are single, double\n");
3841 0 : return false;
3842 : }
3843 : }
3844 :
3845 : /* set border style/width */
3846 67 : else if (strcmp(param, "border") == 0)
3847 : {
3848 34 : if (value)
3849 34 : popt->topt.border = atoi(value);
3850 : }
3851 :
3852 : /* set expanded/vertical mode */
3853 66 : else if (strcmp(param, "x") == 0 ||
3854 54 : strcmp(param, "expanded") == 0 ||
3855 21 : strcmp(param, "vertical") == 0)
3856 : {
3857 24 : if (value && pg_strcasecmp(value, "auto") == 0)
3858 0 : popt->topt.expanded = 2;
3859 12 : else if (value)
3860 : {
3861 : bool on_off;
3862 :
3863 12 : if (ParseVariableBool(value, NULL, &on_off))
3864 12 : popt->topt.expanded = on_off ? 1 : 0;
3865 : else
3866 : {
3867 0 : PsqlVarEnumError(param, value, "on, off, auto");
3868 0 : return false;
3869 : }
3870 : }
3871 : else
3872 0 : popt->topt.expanded = !popt->topt.expanded;
3873 : }
3874 :
3875 : /* locale-aware numeric output */
3876 21 : else if (strcmp(param, "numericlocale") == 0)
3877 : {
3878 0 : if (value)
3879 0 : return ParseVariableBool(value, param, &popt->topt.numericLocale);
3880 : else
3881 0 : popt->topt.numericLocale = !popt->topt.numericLocale;
3882 : }
3883 :
3884 : /* null display */
3885 21 : else if (strcmp(param, "null") == 0)
3886 : {
3887 6 : if (value)
3888 : {
3889 6 : free(popt->nullPrint);
3890 6 : popt->nullPrint = pg_strdup(value);
3891 : }
3892 : }
3893 :
3894 : /* field separator for unaligned text */
3895 15 : else if (strcmp(param, "fieldsep") == 0)
3896 : {
3897 1 : if (value)
3898 : {
3899 1 : free(popt->topt.fieldSep.separator);
3900 1 : popt->topt.fieldSep.separator = pg_strdup(value);
3901 1 : popt->topt.fieldSep.separator_zero = false;
3902 : }
3903 : }
3904 :
3905 14 : else if (strcmp(param, "fieldsep_zero") == 0)
3906 : {
3907 0 : free(popt->topt.fieldSep.separator);
3908 0 : popt->topt.fieldSep.separator = NULL;
3909 0 : popt->topt.fieldSep.separator_zero = true;
3910 : }
3911 :
3912 : /* record separator for unaligned text */
3913 14 : else if (strcmp(param, "recordsep") == 0)
3914 : {
3915 0 : if (value)
3916 : {
3917 0 : free(popt->topt.recordSep.separator);
3918 0 : popt->topt.recordSep.separator = pg_strdup(value);
3919 0 : popt->topt.recordSep.separator_zero = false;
3920 : }
3921 : }
3922 :
3923 14 : else if (strcmp(param, "recordsep_zero") == 0)
3924 : {
3925 0 : free(popt->topt.recordSep.separator);
3926 0 : popt->topt.recordSep.separator = NULL;
3927 0 : popt->topt.recordSep.separator_zero = true;
3928 : }
3929 :
3930 : /* toggle between full and tuples-only format */
3931 14 : else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
3932 : {
3933 12 : if (value)
3934 0 : return ParseVariableBool(value, param, &popt->topt.tuples_only);
3935 : else
3936 6 : popt->topt.tuples_only = !popt->topt.tuples_only;
3937 : }
3938 :
3939 : /* set title override */
3940 8 : else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
3941 : {
3942 0 : free(popt->title);
3943 0 : if (!value)
3944 0 : popt->title = NULL;
3945 : else
3946 0 : popt->title = pg_strdup(value);
3947 : }
3948 :
3949 : /* set HTML table tag options */
3950 8 : else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
3951 : {
3952 0 : free(popt->topt.tableAttr);
3953 0 : if (!value)
3954 0 : popt->topt.tableAttr = NULL;
3955 : else
3956 0 : popt->topt.tableAttr = pg_strdup(value);
3957 : }
3958 :
3959 : /* toggle use of pager */
3960 8 : else if (strcmp(param, "pager") == 0)
3961 : {
3962 0 : if (value && pg_strcasecmp(value, "always") == 0)
3963 0 : popt->topt.pager = 2;
3964 0 : else if (value)
3965 : {
3966 : bool on_off;
3967 :
3968 0 : if (!ParseVariableBool(value, NULL, &on_off))
3969 : {
3970 0 : PsqlVarEnumError(param, value, "on, off, always");
3971 0 : return false;
3972 : }
3973 0 : popt->topt.pager = on_off ? 1 : 0;
3974 : }
3975 0 : else if (popt->topt.pager == 1)
3976 0 : popt->topt.pager = 0;
3977 : else
3978 0 : popt->topt.pager = 1;
3979 : }
3980 :
3981 : /* set minimum lines for pager use */
3982 8 : else if (strcmp(param, "pager_min_lines") == 0)
3983 : {
3984 0 : if (value)
3985 0 : popt->topt.pager_min_lines = atoi(value);
3986 : }
3987 :
3988 : /* disable "(x rows)" footer */
3989 8 : else if (strcmp(param, "footer") == 0)
3990 : {
3991 0 : if (value)
3992 0 : return ParseVariableBool(value, param, &popt->topt.default_footer);
3993 : else
3994 0 : popt->topt.default_footer = !popt->topt.default_footer;
3995 : }
3996 :
3997 : /* set border style/width */
3998 8 : else if (strcmp(param, "columns") == 0)
3999 : {
4000 8 : if (value)
4001 8 : popt->topt.columns = atoi(value);
4002 : }
4003 : else
4004 : {
4005 0 : psql_error("\\pset: unknown option: %s\n", param);
4006 0 : return false;
4007 : }
4008 :
4009 161 : if (!quiet)
4010 0 : printPsetInfo(param, &pset.popt);
4011 :
4012 161 : return true;
4013 : }
4014 :
4015 :
4016 : static bool
4017 0 : printPsetInfo(const char *param, struct printQueryOpt *popt)
4018 : {
4019 0 : Assert(param != NULL);
4020 :
4021 : /* show border style/width */
4022 0 : if (strcmp(param, "border") == 0)
4023 0 : printf(_("Border style is %d.\n"), popt->topt.border);
4024 :
4025 : /* show the target width for the wrapped format */
4026 0 : else if (strcmp(param, "columns") == 0)
4027 : {
4028 0 : if (!popt->topt.columns)
4029 0 : printf(_("Target width is unset.\n"));
4030 : else
4031 0 : printf(_("Target width is %d.\n"), popt->topt.columns);
4032 : }
4033 :
4034 : /* show expanded/vertical mode */
4035 0 : else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
4036 : {
4037 0 : if (popt->topt.expanded == 1)
4038 0 : printf(_("Expanded display is on.\n"));
4039 0 : else if (popt->topt.expanded == 2)
4040 0 : printf(_("Expanded display is used automatically.\n"));
4041 : else
4042 0 : printf(_("Expanded display is off.\n"));
4043 : }
4044 :
4045 : /* show field separator for unaligned text */
4046 0 : else if (strcmp(param, "fieldsep") == 0)
4047 : {
4048 0 : if (popt->topt.fieldSep.separator_zero)
4049 0 : printf(_("Field separator is zero byte.\n"));
4050 : else
4051 0 : printf(_("Field separator is \"%s\".\n"),
4052 : popt->topt.fieldSep.separator);
4053 : }
4054 :
4055 0 : else if (strcmp(param, "fieldsep_zero") == 0)
4056 : {
4057 0 : printf(_("Field separator is zero byte.\n"));
4058 : }
4059 :
4060 : /* show disable "(x rows)" footer */
4061 0 : else if (strcmp(param, "footer") == 0)
4062 : {
4063 0 : if (popt->topt.default_footer)
4064 0 : printf(_("Default footer is on.\n"));
4065 : else
4066 0 : printf(_("Default footer is off.\n"));
4067 : }
4068 :
4069 : /* show format */
4070 0 : else if (strcmp(param, "format") == 0)
4071 : {
4072 0 : printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
4073 : }
4074 :
4075 : /* show table line style */
4076 0 : else if (strcmp(param, "linestyle") == 0)
4077 : {
4078 0 : printf(_("Line style is %s.\n"),
4079 0 : get_line_style(&popt->topt)->name);
4080 : }
4081 :
4082 : /* show null display */
4083 0 : else if (strcmp(param, "null") == 0)
4084 : {
4085 0 : printf(_("Null display is \"%s\".\n"),
4086 0 : popt->nullPrint ? popt->nullPrint : "");
4087 : }
4088 :
4089 : /* show locale-aware numeric output */
4090 0 : else if (strcmp(param, "numericlocale") == 0)
4091 : {
4092 0 : if (popt->topt.numericLocale)
4093 0 : printf(_("Locale-adjusted numeric output is on.\n"));
4094 : else
4095 0 : printf(_("Locale-adjusted numeric output is off.\n"));
4096 : }
4097 :
4098 : /* show toggle use of pager */
4099 0 : else if (strcmp(param, "pager") == 0)
4100 : {
4101 0 : if (popt->topt.pager == 1)
4102 0 : printf(_("Pager is used for long output.\n"));
4103 0 : else if (popt->topt.pager == 2)
4104 0 : printf(_("Pager is always used.\n"));
4105 : else
4106 0 : printf(_("Pager usage is off.\n"));
4107 : }
4108 :
4109 : /* show minimum lines for pager use */
4110 0 : else if (strcmp(param, "pager_min_lines") == 0)
4111 : {
4112 0 : printf(ngettext("Pager won't be used for less than %d line.\n",
4113 : "Pager won't be used for less than %d lines.\n",
4114 : popt->topt.pager_min_lines),
4115 : popt->topt.pager_min_lines);
4116 : }
4117 :
4118 : /* show record separator for unaligned text */
4119 0 : else if (strcmp(param, "recordsep") == 0)
4120 : {
4121 0 : if (popt->topt.recordSep.separator_zero)
4122 0 : printf(_("Record separator is zero byte.\n"));
4123 0 : else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
4124 0 : printf(_("Record separator is <newline>.\n"));
4125 : else
4126 0 : printf(_("Record separator is \"%s\".\n"),
4127 : popt->topt.recordSep.separator);
4128 : }
4129 :
4130 0 : else if (strcmp(param, "recordsep_zero") == 0)
4131 : {
4132 0 : printf(_("Record separator is zero byte.\n"));
4133 : }
4134 :
4135 : /* show HTML table tag options */
4136 0 : else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
4137 : {
4138 0 : if (popt->topt.tableAttr)
4139 0 : printf(_("Table attributes are \"%s\".\n"),
4140 : popt->topt.tableAttr);
4141 : else
4142 0 : printf(_("Table attributes unset.\n"));
4143 : }
4144 :
4145 : /* show title override */
4146 0 : else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
4147 : {
4148 0 : if (popt->title)
4149 0 : printf(_("Title is \"%s\".\n"), popt->title);
4150 : else
4151 0 : printf(_("Title is unset.\n"));
4152 : }
4153 :
4154 : /* show toggle between full and tuples-only format */
4155 0 : else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
4156 : {
4157 0 : if (popt->topt.tuples_only)
4158 0 : printf(_("Tuples only is on.\n"));
4159 : else
4160 0 : printf(_("Tuples only is off.\n"));
4161 : }
4162 :
4163 : /* Unicode style formatting */
4164 0 : else if (strcmp(param, "unicode_border_linestyle") == 0)
4165 : {
4166 0 : printf(_("Unicode border line style is \"%s\".\n"),
4167 0 : _unicode_linestyle2string(popt->topt.unicode_border_linestyle));
4168 : }
4169 :
4170 0 : else if (strcmp(param, "unicode_column_linestyle") == 0)
4171 : {
4172 0 : printf(_("Unicode column line style is \"%s\".\n"),
4173 0 : _unicode_linestyle2string(popt->topt.unicode_column_linestyle));
4174 : }
4175 :
4176 0 : else if (strcmp(param, "unicode_header_linestyle") == 0)
4177 : {
4178 0 : printf(_("Unicode header line style is \"%s\".\n"),
4179 0 : _unicode_linestyle2string(popt->topt.unicode_header_linestyle));
4180 : }
4181 :
4182 : else
4183 : {
4184 0 : psql_error("\\pset: unknown option: %s\n", param);
4185 0 : return false;
4186 : }
4187 :
4188 0 : return true;
4189 : }
4190 :
4191 :
4192 : static const char *
4193 6 : pset_bool_string(bool val)
4194 : {
4195 6 : return val ? "on" : "off";
4196 : }
4197 :
4198 :
4199 : static char *
4200 3 : pset_quoted_string(const char *str)
4201 : {
4202 3 : char *ret = pg_malloc(strlen(str) * 2 + 3);
4203 3 : char *r = ret;
4204 :
4205 3 : *r++ = '\'';
4206 :
4207 5 : for (; *str; str++)
4208 : {
4209 2 : if (*str == '\n')
4210 : {
4211 1 : *r++ = '\\';
4212 1 : *r++ = 'n';
4213 : }
4214 1 : else if (*str == '\'')
4215 : {
4216 0 : *r++ = '\\';
4217 0 : *r++ = '\'';
4218 : }
4219 : else
4220 1 : *r++ = *str;
4221 : }
4222 :
4223 3 : *r++ = '\'';
4224 3 : *r = '\0';
4225 :
4226 3 : return ret;
4227 : }
4228 :
4229 :
4230 : /*
4231 : * Return a malloc'ed string for the \pset value.
4232 : *
4233 : * Note that for some string parameters, print.c distinguishes between unset
4234 : * and empty string, but for others it doesn't. This function should produce
4235 : * output that produces the correct setting when fed back into \pset.
4236 : */
4237 : static char *
4238 20 : pset_value_string(const char *param, struct printQueryOpt *popt)
4239 : {
4240 20 : Assert(param != NULL);
4241 :
4242 20 : if (strcmp(param, "border") == 0)
4243 1 : return psprintf("%d", popt->topt.border);
4244 19 : else if (strcmp(param, "columns") == 0)
4245 1 : return psprintf("%d", popt->topt.columns);
4246 18 : else if (strcmp(param, "expanded") == 0)
4247 2 : return pstrdup(popt->topt.expanded == 2
4248 : ? "auto"
4249 1 : : pset_bool_string(popt->topt.expanded));
4250 17 : else if (strcmp(param, "fieldsep") == 0)
4251 1 : return pset_quoted_string(popt->topt.fieldSep.separator
4252 : ? popt->topt.fieldSep.separator
4253 : : "");
4254 16 : else if (strcmp(param, "fieldsep_zero") == 0)
4255 1 : return pstrdup(pset_bool_string(popt->topt.fieldSep.separator_zero));
4256 15 : else if (strcmp(param, "footer") == 0)
4257 1 : return pstrdup(pset_bool_string(popt->topt.default_footer));
4258 14 : else if (strcmp(param, "format") == 0)
4259 1 : return psprintf("%s", _align2string(popt->topt.format));
4260 13 : else if (strcmp(param, "linestyle") == 0)
4261 1 : return psprintf("%s", get_line_style(&popt->topt)->name);
4262 12 : else if (strcmp(param, "null") == 0)
4263 1 : return pset_quoted_string(popt->nullPrint
4264 : ? popt->nullPrint
4265 : : "");
4266 11 : else if (strcmp(param, "numericlocale") == 0)
4267 1 : return pstrdup(pset_bool_string(popt->topt.numericLocale));
4268 10 : else if (strcmp(param, "pager") == 0)
4269 1 : return psprintf("%d", popt->topt.pager);
4270 9 : else if (strcmp(param, "pager_min_lines") == 0)
4271 1 : return psprintf("%d", popt->topt.pager_min_lines);
4272 8 : else if (strcmp(param, "recordsep") == 0)
4273 1 : return pset_quoted_string(popt->topt.recordSep.separator
4274 : ? popt->topt.recordSep.separator
4275 : : "");
4276 7 : else if (strcmp(param, "recordsep_zero") == 0)
4277 1 : return pstrdup(pset_bool_string(popt->topt.recordSep.separator_zero));
4278 6 : else if (strcmp(param, "tableattr") == 0)
4279 1 : return popt->topt.tableAttr ? pset_quoted_string(popt->topt.tableAttr) : pstrdup("");
4280 5 : else if (strcmp(param, "title") == 0)
4281 1 : return popt->title ? pset_quoted_string(popt->title) : pstrdup("");
4282 4 : else if (strcmp(param, "tuples_only") == 0)
4283 1 : return pstrdup(pset_bool_string(popt->topt.tuples_only));
4284 3 : else if (strcmp(param, "unicode_border_linestyle") == 0)
4285 1 : return pstrdup(_unicode_linestyle2string(popt->topt.unicode_border_linestyle));
4286 2 : else if (strcmp(param, "unicode_column_linestyle") == 0)
4287 1 : return pstrdup(_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
4288 1 : else if (strcmp(param, "unicode_header_linestyle") == 0)
4289 1 : return pstrdup(_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
4290 : else
4291 0 : return pstrdup("ERROR");
4292 : }
4293 :
4294 :
4295 :
4296 : #ifndef WIN32
4297 : #define DEFAULT_SHELL "/bin/sh"
4298 : #else
4299 : /*
4300 : * CMD.EXE is in different places in different Win32 releases so we
4301 : * have to rely on the path to find it.
4302 : */
4303 : #define DEFAULT_SHELL "cmd.exe"
4304 : #endif
4305 :
4306 : static bool
4307 0 : do_shell(const char *command)
4308 : {
4309 : int result;
4310 :
4311 0 : if (!command)
4312 : {
4313 : char *sys;
4314 : const char *shellName;
4315 :
4316 0 : shellName = getenv("SHELL");
4317 : #ifdef WIN32
4318 : if (shellName == NULL)
4319 : shellName = getenv("COMSPEC");
4320 : #endif
4321 0 : if (shellName == NULL)
4322 0 : shellName = DEFAULT_SHELL;
4323 :
4324 : /* See EDITOR handling comment for an explanation */
4325 : #ifndef WIN32
4326 0 : sys = psprintf("exec %s", shellName);
4327 : #else
4328 : sys = psprintf("\"%s\"", shellName);
4329 : #endif
4330 0 : result = system(sys);
4331 0 : free(sys);
4332 : }
4333 : else
4334 0 : result = system(command);
4335 :
4336 0 : if (result == 127 || result == -1)
4337 : {
4338 0 : psql_error("\\!: failed\n");
4339 0 : return false;
4340 : }
4341 0 : return true;
4342 : }
4343 :
4344 : /*
4345 : * do_watch -- handler for \watch
4346 : *
4347 : * We break this out of exec_command to avoid having to plaster "volatile"
4348 : * onto a bunch of exec_command's variables to silence stupider compilers.
4349 : */
4350 : static bool
4351 0 : do_watch(PQExpBuffer query_buf, double sleep)
4352 : {
4353 0 : long sleep_ms = (long) (sleep * 1000);
4354 0 : printQueryOpt myopt = pset.popt;
4355 : const char *strftime_fmt;
4356 : const char *user_title;
4357 : char *title;
4358 : int title_len;
4359 0 : int res = 0;
4360 :
4361 0 : if (!query_buf || query_buf->len <= 0)
4362 : {
4363 0 : psql_error(_("\\watch cannot be used with an empty query\n"));
4364 0 : return false;
4365 : }
4366 :
4367 : /*
4368 : * Choose format for timestamps. We might eventually make this a \pset
4369 : * option. In the meantime, using a variable for the format suppresses
4370 : * overly-anal-retentive gcc warnings about %c being Y2K sensitive.
4371 : */
4372 0 : strftime_fmt = "%c";
4373 :
4374 : /*
4375 : * Set up rendering options, in particular, disable the pager, because
4376 : * nobody wants to be prompted while watching the output of 'watch'.
4377 : */
4378 0 : myopt.topt.pager = 0;
4379 :
4380 : /*
4381 : * If there's a title in the user configuration, make sure we have room
4382 : * for it in the title buffer. Allow 128 bytes for the timestamp plus 128
4383 : * bytes for the rest.
4384 : */
4385 0 : user_title = myopt.title;
4386 0 : title_len = (user_title ? strlen(user_title) : 0) + 256;
4387 0 : title = pg_malloc(title_len);
4388 :
4389 : for (;;)
4390 : {
4391 : time_t timer;
4392 : char timebuf[128];
4393 : long i;
4394 :
4395 : /*
4396 : * Prepare title for output. Note that we intentionally include a
4397 : * newline at the end of the title; this is somewhat historical but it
4398 : * makes for reasonably nicely formatted output in simple cases.
4399 : */
4400 0 : timer = time(NULL);
4401 0 : strftime(timebuf, sizeof(timebuf), strftime_fmt, localtime(&timer));
4402 :
4403 0 : if (user_title)
4404 0 : snprintf(title, title_len, _("%s\t%s (every %gs)\n"),
4405 : user_title, timebuf, sleep);
4406 : else
4407 0 : snprintf(title, title_len, _("%s (every %gs)\n"),
4408 : timebuf, sleep);
4409 0 : myopt.title = title;
4410 :
4411 : /* Run the query and print out the results */
4412 0 : res = PSQLexecWatch(query_buf->data, &myopt);
4413 :
4414 : /*
4415 : * PSQLexecWatch handles the case where we can no longer repeat the
4416 : * query, and returns 0 or -1.
4417 : */
4418 0 : if (res <= 0)
4419 0 : break;
4420 :
4421 : /*
4422 : * Set up cancellation of 'watch' via SIGINT. We redo this each time
4423 : * through the loop since it's conceivable something inside
4424 : * PSQLexecWatch could change sigint_interrupt_jmp.
4425 : */
4426 0 : if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
4427 0 : break;
4428 :
4429 : /*
4430 : * Enable 'watch' cancellations and wait a while before running the
4431 : * query again. Break the sleep into short intervals (at most 1s)
4432 : * since pg_usleep isn't interruptible on some platforms.
4433 : */
4434 0 : sigint_interrupt_enabled = true;
4435 0 : i = sleep_ms;
4436 0 : while (i > 0)
4437 : {
4438 0 : long s = Min(i, 1000L);
4439 :
4440 0 : pg_usleep(s * 1000L);
4441 0 : if (cancel_pressed)
4442 0 : break;
4443 0 : i -= s;
4444 : }
4445 0 : sigint_interrupt_enabled = false;
4446 0 : }
4447 :
4448 0 : pg_free(title);
4449 0 : return (res >= 0);
4450 : }
4451 :
4452 : /*
4453 : * a little code borrowed from PSQLexec() to manage ECHO_HIDDEN output.
4454 : * returns true unless we have ECHO_HIDDEN_NOEXEC.
4455 : */
4456 : static bool
4457 2 : echo_hidden_command(const char *query)
4458 : {
4459 2 : if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
4460 : {
4461 0 : printf(_("********* QUERY **********\n"
4462 : "%s\n"
4463 : "**************************\n\n"), query);
4464 0 : fflush(stdout);
4465 0 : if (pset.logfile)
4466 : {
4467 0 : fprintf(pset.logfile,
4468 : _("********* QUERY **********\n"
4469 : "%s\n"
4470 : "**************************\n\n"), query);
4471 0 : fflush(pset.logfile);
4472 : }
4473 :
4474 0 : if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
4475 0 : return false;
4476 : }
4477 2 : return true;
4478 : }
4479 :
4480 : /*
4481 : * Look up the object identified by obj_type and desc. If successful,
4482 : * store its OID in *obj_oid and return TRUE, else return FALSE.
4483 : *
4484 : * Note that we'll fail if the object doesn't exist OR if there are multiple
4485 : * matching candidates OR if there's something syntactically wrong with the
4486 : * object description; unfortunately it can be hard to tell the difference.
4487 : */
4488 : static bool
4489 1 : lookup_object_oid(EditableObjectType obj_type, const char *desc,
4490 : Oid *obj_oid)
4491 : {
4492 1 : bool result = true;
4493 1 : PQExpBuffer query = createPQExpBuffer();
4494 : PGresult *res;
4495 :
4496 1 : switch (obj_type)
4497 : {
4498 : case EditableFunction:
4499 :
4500 : /*
4501 : * We have a function description, e.g. "x" or "x(int)". Issue a
4502 : * query to retrieve the function's OID using a cast to regproc or
4503 : * regprocedure (as appropriate).
4504 : */
4505 0 : appendPQExpBufferStr(query, "SELECT ");
4506 0 : appendStringLiteralConn(query, desc, pset.db);
4507 0 : appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
4508 0 : strchr(desc, '(') ? "regprocedure" : "regproc");
4509 0 : break;
4510 :
4511 : case EditableView:
4512 :
4513 : /*
4514 : * Convert view name (possibly schema-qualified) to OID. Note:
4515 : * this code doesn't check if the relation is actually a view.
4516 : * We'll detect that in get_create_object_cmd().
4517 : */
4518 1 : appendPQExpBufferStr(query, "SELECT ");
4519 1 : appendStringLiteralConn(query, desc, pset.db);
4520 1 : appendPQExpBuffer(query, "::pg_catalog.regclass::pg_catalog.oid");
4521 1 : break;
4522 : }
4523 :
4524 1 : if (!echo_hidden_command(query->data))
4525 : {
4526 0 : destroyPQExpBuffer(query);
4527 0 : return false;
4528 : }
4529 1 : res = PQexec(pset.db, query->data);
4530 1 : if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
4531 1 : *obj_oid = atooid(PQgetvalue(res, 0, 0));
4532 : else
4533 : {
4534 0 : minimal_error_message(res);
4535 0 : result = false;
4536 : }
4537 :
4538 1 : PQclear(res);
4539 1 : destroyPQExpBuffer(query);
4540 :
4541 1 : return result;
4542 : }
4543 :
4544 : /*
4545 : * Construct a "CREATE OR REPLACE ..." command that describes the specified
4546 : * database object. If successful, the result is stored in buf.
4547 : */
4548 : static bool
4549 1 : get_create_object_cmd(EditableObjectType obj_type, Oid oid,
4550 : PQExpBuffer buf)
4551 : {
4552 1 : bool result = true;
4553 1 : PQExpBuffer query = createPQExpBuffer();
4554 : PGresult *res;
4555 :
4556 1 : switch (obj_type)
4557 : {
4558 : case EditableFunction:
4559 0 : printfPQExpBuffer(query,
4560 : "SELECT pg_catalog.pg_get_functiondef(%u)",
4561 : oid);
4562 0 : break;
4563 :
4564 : case EditableView:
4565 :
4566 : /*
4567 : * pg_get_viewdef() just prints the query, so we must prepend
4568 : * CREATE for ourselves. We must fully qualify the view name to
4569 : * ensure the right view gets replaced. Also, check relation kind
4570 : * to be sure it's a view.
4571 : *
4572 : * Starting with 9.2, views may have reloptions (security_barrier)
4573 : * and from 9.4 onwards they may also have WITH [LOCAL|CASCADED]
4574 : * CHECK OPTION. These are not part of the view definition
4575 : * returned by pg_get_viewdef() and so need to be retrieved
4576 : * separately. Materialized views (introduced in 9.3) may have
4577 : * arbitrary storage parameter reloptions.
4578 : */
4579 1 : if (pset.sversion >= 90400)
4580 : {
4581 1 : printfPQExpBuffer(query,
4582 : "SELECT nspname, relname, relkind, "
4583 : "pg_catalog.pg_get_viewdef(c.oid, true), "
4584 : "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
4585 : "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4586 : "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption "
4587 : "FROM pg_catalog.pg_class c "
4588 : "LEFT JOIN pg_catalog.pg_namespace n "
4589 : "ON c.relnamespace = n.oid WHERE c.oid = %u",
4590 : oid);
4591 : }
4592 0 : else if (pset.sversion >= 90200)
4593 : {
4594 0 : printfPQExpBuffer(query,
4595 : "SELECT nspname, relname, relkind, "
4596 : "pg_catalog.pg_get_viewdef(c.oid, true), "
4597 : "c.reloptions AS reloptions, "
4598 : "NULL AS checkoption "
4599 : "FROM pg_catalog.pg_class c "
4600 : "LEFT JOIN pg_catalog.pg_namespace n "
4601 : "ON c.relnamespace = n.oid WHERE c.oid = %u",
4602 : oid);
4603 : }
4604 : else
4605 : {
4606 0 : printfPQExpBuffer(query,
4607 : "SELECT nspname, relname, relkind, "
4608 : "pg_catalog.pg_get_viewdef(c.oid, true), "
4609 : "NULL AS reloptions, "
4610 : "NULL AS checkoption "
4611 : "FROM pg_catalog.pg_class c "
4612 : "LEFT JOIN pg_catalog.pg_namespace n "
4613 : "ON c.relnamespace = n.oid WHERE c.oid = %u",
4614 : oid);
4615 : }
4616 1 : break;
4617 : }
4618 :
4619 1 : if (!echo_hidden_command(query->data))
4620 : {
4621 0 : destroyPQExpBuffer(query);
4622 0 : return false;
4623 : }
4624 1 : res = PQexec(pset.db, query->data);
4625 1 : if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
4626 : {
4627 1 : resetPQExpBuffer(buf);
4628 1 : switch (obj_type)
4629 : {
4630 : case EditableFunction:
4631 0 : appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
4632 0 : break;
4633 :
4634 : case EditableView:
4635 : {
4636 1 : char *nspname = PQgetvalue(res, 0, 0);
4637 1 : char *relname = PQgetvalue(res, 0, 1);
4638 1 : char *relkind = PQgetvalue(res, 0, 2);
4639 1 : char *viewdef = PQgetvalue(res, 0, 3);
4640 1 : char *reloptions = PQgetvalue(res, 0, 4);
4641 1 : char *checkoption = PQgetvalue(res, 0, 5);
4642 :
4643 : /*
4644 : * If the backend ever supports CREATE OR REPLACE
4645 : * MATERIALIZED VIEW, allow that here; but as of today it
4646 : * does not, so editing a matview definition in this way
4647 : * is impossible.
4648 : */
4649 1 : switch (relkind[0])
4650 : {
4651 : #ifdef NOT_USED
4652 : case RELKIND_MATVIEW:
4653 : appendPQExpBufferStr(buf, "CREATE OR REPLACE MATERIALIZED VIEW ");
4654 : break;
4655 : #endif
4656 : case RELKIND_VIEW:
4657 1 : appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
4658 1 : break;
4659 : default:
4660 0 : psql_error("\"%s.%s\" is not a view\n",
4661 : nspname, relname);
4662 0 : result = false;
4663 0 : break;
4664 : }
4665 1 : appendPQExpBuffer(buf, "%s.", fmtId(nspname));
4666 1 : appendPQExpBufferStr(buf, fmtId(relname));
4667 :
4668 : /* reloptions, if not an empty array "{}" */
4669 1 : if (reloptions != NULL && strlen(reloptions) > 2)
4670 : {
4671 0 : appendPQExpBufferStr(buf, "\n WITH (");
4672 0 : if (!appendReloptionsArray(buf, reloptions, "",
4673 : pset.encoding,
4674 0 : standard_strings()))
4675 : {
4676 0 : psql_error("could not parse reloptions array\n");
4677 0 : result = false;
4678 : }
4679 0 : appendPQExpBufferChar(buf, ')');
4680 : }
4681 :
4682 : /* View definition from pg_get_viewdef (a SELECT query) */
4683 1 : appendPQExpBuffer(buf, " AS\n%s", viewdef);
4684 :
4685 : /* Get rid of the semicolon that pg_get_viewdef appends */
4686 1 : if (buf->len > 0 && buf->data[buf->len - 1] == ';')
4687 1 : buf->data[--(buf->len)] = '\0';
4688 :
4689 : /* WITH [LOCAL|CASCADED] CHECK OPTION */
4690 1 : if (checkoption && checkoption[0] != '\0')
4691 0 : appendPQExpBuffer(buf, "\n WITH %s CHECK OPTION",
4692 : checkoption);
4693 : }
4694 1 : break;
4695 : }
4696 : /* Make sure result ends with a newline */
4697 2 : if (buf->len > 0 && buf->data[buf->len - 1] != '\n')
4698 1 : appendPQExpBufferChar(buf, '\n');
4699 : }
4700 : else
4701 : {
4702 0 : minimal_error_message(res);
4703 0 : result = false;
4704 : }
4705 :
4706 1 : PQclear(res);
4707 1 : destroyPQExpBuffer(query);
4708 :
4709 1 : return result;
4710 : }
4711 :
4712 : /*
4713 : * If the given argument of \ef or \ev ends with a line number, delete the line
4714 : * number from the argument string and return it as an integer. (We need
4715 : * this kluge because we're too lazy to parse \ef's function or \ev's view
4716 : * argument carefully --- we just slop it up in OT_WHOLE_LINE mode.)
4717 : *
4718 : * Returns -1 if no line number is present, 0 on error, or a positive value
4719 : * on success.
4720 : */
4721 : static int
4722 0 : strip_lineno_from_objdesc(char *obj)
4723 : {
4724 : char *c;
4725 : int lineno;
4726 :
4727 0 : if (!obj || obj[0] == '\0')
4728 0 : return -1;
4729 :
4730 0 : c = obj + strlen(obj) - 1;
4731 :
4732 : /*
4733 : * This business of parsing backwards is dangerous as can be in a
4734 : * multibyte environment: there is no reason to believe that we are
4735 : * looking at the first byte of a character, nor are we necessarily
4736 : * working in a "safe" encoding. Fortunately the bitpatterns we are
4737 : * looking for are unlikely to occur as non-first bytes, but beware of
4738 : * trying to expand the set of cases that can be recognized. We must
4739 : * guard the <ctype.h> macros by using isascii() first, too.
4740 : */
4741 :
4742 : /* skip trailing whitespace */
4743 0 : while (c > obj && isascii((unsigned char) *c) && isspace((unsigned char) *c))
4744 0 : c--;
4745 :
4746 : /* must have a digit as last non-space char */
4747 0 : if (c == obj || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
4748 0 : return -1;
4749 :
4750 : /* find start of digit string */
4751 0 : while (c > obj && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
4752 0 : c--;
4753 :
4754 : /* digits must be separated from object name by space or closing paren */
4755 : /* notice also that we are not allowing an empty object name ... */
4756 0 : if (c == obj || !isascii((unsigned char) *c) ||
4757 0 : !(isspace((unsigned char) *c) || *c == ')'))
4758 0 : return -1;
4759 :
4760 : /* parse digit string */
4761 0 : c++;
4762 0 : lineno = atoi(c);
4763 0 : if (lineno < 1)
4764 : {
4765 0 : psql_error("invalid line number: %s\n", c);
4766 0 : return 0;
4767 : }
4768 :
4769 : /* strip digit string from object name */
4770 0 : *c = '\0';
4771 :
4772 0 : return lineno;
4773 : }
4774 :
4775 : /*
4776 : * Count number of lines in the buffer.
4777 : * This is used to test if pager is needed or not.
4778 : */
4779 : static int
4780 1 : count_lines_in_buf(PQExpBuffer buf)
4781 : {
4782 1 : int lineno = 0;
4783 1 : const char *lines = buf->data;
4784 :
4785 14 : while (*lines != '\0')
4786 : {
4787 12 : lineno++;
4788 : /* find start of next line */
4789 12 : lines = strchr(lines, '\n');
4790 12 : if (!lines)
4791 0 : break;
4792 12 : lines++;
4793 : }
4794 :
4795 1 : return lineno;
4796 : }
4797 :
4798 : /*
4799 : * Write text at *lines to output with line numbers.
4800 : *
4801 : * If header_keyword isn't NULL, then line 1 should be the first line beginning
4802 : * with header_keyword; lines before that are unnumbered.
4803 : *
4804 : * Caution: this scribbles on *lines.
4805 : */
4806 : static void
4807 0 : print_with_linenumbers(FILE *output, char *lines,
4808 : const char *header_keyword)
4809 : {
4810 0 : bool in_header = (header_keyword != NULL);
4811 0 : size_t header_sz = in_header ? strlen(header_keyword) : 0;
4812 0 : int lineno = 0;
4813 :
4814 0 : while (*lines != '\0')
4815 : {
4816 : char *eol;
4817 :
4818 0 : if (in_header && strncmp(lines, header_keyword, header_sz) == 0)
4819 0 : in_header = false;
4820 :
4821 : /* increment lineno only for body's lines */
4822 0 : if (!in_header)
4823 0 : lineno++;
4824 :
4825 : /* find and mark end of current line */
4826 0 : eol = strchr(lines, '\n');
4827 0 : if (eol != NULL)
4828 0 : *eol = '\0';
4829 :
4830 : /* show current line as appropriate */
4831 0 : if (in_header)
4832 0 : fprintf(output, " %s\n", lines);
4833 : else
4834 0 : fprintf(output, "%-7d %s\n", lineno, lines);
4835 :
4836 : /* advance to next line, if any */
4837 0 : if (eol == NULL)
4838 0 : break;
4839 0 : lines = ++eol;
4840 : }
4841 0 : }
4842 :
4843 : /*
4844 : * Report just the primary error; this is to avoid cluttering the output
4845 : * with, for instance, a redisplay of the internally generated query
4846 : */
4847 : static void
4848 0 : minimal_error_message(PGresult *res)
4849 : {
4850 : PQExpBuffer msg;
4851 : const char *fld;
4852 :
4853 0 : msg = createPQExpBuffer();
4854 :
4855 0 : fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
4856 0 : if (fld)
4857 0 : printfPQExpBuffer(msg, "%s: ", fld);
4858 : else
4859 0 : printfPQExpBuffer(msg, "ERROR: ");
4860 0 : fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
4861 0 : if (fld)
4862 0 : appendPQExpBufferStr(msg, fld);
4863 : else
4864 0 : appendPQExpBufferStr(msg, "(not available)");
4865 0 : appendPQExpBufferChar(msg, '\n');
4866 :
4867 0 : psql_error("%s", msg->data);
4868 :
4869 0 : destroyPQExpBuffer(msg);
4870 0 : }
|