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