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