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