Line data Source code
1 : /*
2 : * psql - the PostgreSQL interactive terminal
3 : *
4 : * Copyright (c) 2000-2021, PostgreSQL Global Development Group
5 : *
6 : * src/bin/psql/startup.c
7 : */
8 : #include "postgres_fe.h"
9 :
10 : #ifndef WIN32
11 : #include <unistd.h>
12 : #else /* WIN32 */
13 : #include <io.h>
14 : #include <win32.h>
15 : #endif /* WIN32 */
16 :
17 : #include "command.h"
18 : #include "common.h"
19 : #include "common/logging.h"
20 : #include "common/string.h"
21 : #include "describe.h"
22 : #include "fe_utils/print.h"
23 : #include "getopt_long.h"
24 : #include "help.h"
25 : #include "input.h"
26 : #include "mainloop.h"
27 : #include "settings.h"
28 :
29 : /*
30 : * Global psql options
31 : */
32 : PsqlSettings pset;
33 :
34 : #ifndef WIN32
35 : #define SYSPSQLRC "psqlrc"
36 : #define PSQLRC ".psqlrc"
37 : #else
38 : #define SYSPSQLRC "psqlrc"
39 : #define PSQLRC "psqlrc.conf"
40 : #endif
41 :
42 : /*
43 : * Structures to pass information between the option parsing routine
44 : * and the main function
45 : */
46 : enum _actions
47 : {
48 : ACT_SINGLE_QUERY,
49 : ACT_SINGLE_SLASH,
50 : ACT_FILE
51 : };
52 :
53 : typedef struct SimpleActionListCell
54 : {
55 : struct SimpleActionListCell *next;
56 : enum _actions action;
57 : char *val;
58 : } SimpleActionListCell;
59 :
60 : typedef struct SimpleActionList
61 : {
62 : SimpleActionListCell *head;
63 : SimpleActionListCell *tail;
64 : } SimpleActionList;
65 :
66 : struct adhoc_opts
67 : {
68 : char *dbname;
69 : char *host;
70 : char *port;
71 : char *username;
72 : char *logfilename;
73 : bool no_readline;
74 : bool no_psqlrc;
75 : bool single_txn;
76 : bool list_dbs;
77 : SimpleActionList actions;
78 : };
79 :
80 : static void parse_psql_options(int argc, char *argv[],
81 : struct adhoc_opts *options);
82 : static void simple_action_list_append(SimpleActionList *list,
83 : enum _actions action, const char *val);
84 : static void process_psqlrc(char *argv0);
85 : static void process_psqlrc_file(char *filename);
86 : static void showVersion(void);
87 : static void EstablishVariableSpace(void);
88 :
89 : #define NOPAGER 0
90 :
91 : static void
92 30826 : log_pre_callback(void)
93 : {
94 30826 : if (pset.queryFout && pset.queryFout != stdout)
95 0 : fflush(pset.queryFout);
96 30826 : }
97 :
98 : static void
99 30826 : log_locus_callback(const char **filename, uint64 *lineno)
100 : {
101 30826 : if (pset.inputfile)
102 : {
103 348 : *filename = pset.inputfile;
104 348 : *lineno = pset.lineno;
105 : }
106 : else
107 : {
108 30478 : *filename = NULL;
109 30478 : *lineno = 0;
110 : }
111 30826 : }
112 :
113 : /*
114 : *
115 : * main
116 : *
117 : */
118 : int
119 6028 : main(int argc, char *argv[])
120 : {
121 : struct adhoc_opts options;
122 : int successResult;
123 6028 : char *password = NULL;
124 : bool new_pass;
125 :
126 6028 : pg_logging_init(argv[0]);
127 6028 : pg_logging_set_pre_callback(log_pre_callback);
128 6028 : pg_logging_set_locus_callback(log_locus_callback);
129 6028 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
130 :
131 6028 : if (argc > 1)
132 : {
133 6028 : if ((strcmp(argv[1], "-?") == 0) || (argc == 2 && (strcmp(argv[1], "--help") == 0)))
134 : {
135 0 : usage(NOPAGER);
136 0 : exit(EXIT_SUCCESS);
137 : }
138 6028 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
139 : {
140 0 : showVersion();
141 0 : exit(EXIT_SUCCESS);
142 : }
143 : }
144 :
145 6028 : pset.progname = get_progname(argv[0]);
146 :
147 6028 : pset.db = NULL;
148 6028 : pset.dead_conn = NULL;
149 6028 : setDecimalLocale();
150 6028 : pset.encoding = PQenv2encoding();
151 6028 : pset.queryFout = stdout;
152 6028 : pset.queryFoutPipe = false;
153 6028 : pset.copyStream = NULL;
154 6028 : pset.last_error_result = NULL;
155 6028 : pset.cur_cmd_source = stdin;
156 6028 : pset.cur_cmd_interactive = false;
157 :
158 : /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
159 6028 : pset.popt.topt.format = PRINT_ALIGNED;
160 6028 : pset.popt.topt.border = 1;
161 6028 : pset.popt.topt.pager = 1;
162 6028 : pset.popt.topt.pager_min_lines = 0;
163 6028 : pset.popt.topt.start_table = true;
164 6028 : pset.popt.topt.stop_table = true;
165 6028 : pset.popt.topt.default_footer = true;
166 :
167 6028 : pset.popt.topt.csvFieldSep[0] = DEFAULT_CSV_FIELD_SEP;
168 6028 : pset.popt.topt.csvFieldSep[1] = '\0';
169 :
170 6028 : pset.popt.topt.unicode_border_linestyle = UNICODE_LINESTYLE_SINGLE;
171 6028 : pset.popt.topt.unicode_column_linestyle = UNICODE_LINESTYLE_SINGLE;
172 6028 : pset.popt.topt.unicode_header_linestyle = UNICODE_LINESTYLE_SINGLE;
173 :
174 6028 : refresh_utf8format(&(pset.popt.topt));
175 :
176 : /* We must get COLUMNS here before readline() sets it */
177 6028 : pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
178 :
179 6028 : pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
180 :
181 6028 : pset.getPassword = TRI_DEFAULT;
182 :
183 6028 : EstablishVariableSpace();
184 :
185 : /* Create variables showing psql version number */
186 6028 : SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
187 6028 : SetVariable(pset.vars, "VERSION_NAME", PG_VERSION);
188 6028 : SetVariable(pset.vars, "VERSION_NUM", CppAsString2(PG_VERSION_NUM));
189 :
190 : /* Initialize variables for last error */
191 6028 : SetVariable(pset.vars, "LAST_ERROR_MESSAGE", "");
192 6028 : SetVariable(pset.vars, "LAST_ERROR_SQLSTATE", "00000");
193 :
194 : /* Default values for variables (that don't match the result of \unset) */
195 6028 : SetVariableBool(pset.vars, "AUTOCOMMIT");
196 6028 : SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
197 6028 : SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
198 6028 : SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
199 :
200 6028 : parse_psql_options(argc, argv, &options);
201 :
202 : /*
203 : * If no action was specified and we're in non-interactive mode, treat it
204 : * as if the user had specified "-f -". This lets single-transaction mode
205 : * work in this case.
206 : */
207 6028 : if (options.actions.head == NULL && pset.notty)
208 1728 : simple_action_list_append(&options.actions, ACT_FILE, NULL);
209 :
210 : /* Bail out if -1 was specified but will be ignored. */
211 6028 : if (options.single_txn && options.actions.head == NULL)
212 : {
213 0 : pg_log_fatal("-1 can only be used in non-interactive mode");
214 0 : exit(EXIT_FAILURE);
215 : }
216 :
217 6028 : if (!pset.popt.topt.fieldSep.separator &&
218 6024 : !pset.popt.topt.fieldSep.separator_zero)
219 : {
220 6024 : pset.popt.topt.fieldSep.separator = pg_strdup(DEFAULT_FIELD_SEP);
221 6024 : pset.popt.topt.fieldSep.separator_zero = false;
222 : }
223 6028 : if (!pset.popt.topt.recordSep.separator &&
224 6028 : !pset.popt.topt.recordSep.separator_zero)
225 : {
226 6028 : pset.popt.topt.recordSep.separator = pg_strdup(DEFAULT_RECORD_SEP);
227 6028 : pset.popt.topt.recordSep.separator_zero = false;
228 : }
229 :
230 6028 : if (pset.getPassword == TRI_YES)
231 : {
232 : /*
233 : * We can't be sure yet of the username that will be used, so don't
234 : * offer a potentially wrong one. Typical uses of this option are
235 : * noninteractive anyway.
236 : */
237 0 : password = simple_prompt("Password: ", false);
238 : }
239 :
240 : /* loop until we have a password if requested by backend */
241 : do
242 : {
243 : #define PARAMS_ARRAY_SIZE 8
244 6028 : const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
245 6028 : const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
246 :
247 6028 : keywords[0] = "host";
248 6028 : values[0] = options.host;
249 6028 : keywords[1] = "port";
250 6028 : values[1] = options.port;
251 6028 : keywords[2] = "user";
252 6028 : values[2] = options.username;
253 6028 : keywords[3] = "password";
254 6028 : values[3] = password;
255 6028 : keywords[4] = "dbname"; /* see do_connect() */
256 0 : values[4] = (options.list_dbs && options.dbname == NULL) ?
257 6028 : "postgres" : options.dbname;
258 6028 : keywords[5] = "fallback_application_name";
259 6028 : values[5] = pset.progname;
260 6028 : keywords[6] = "client_encoding";
261 6028 : values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
262 6028 : keywords[7] = NULL;
263 6028 : values[7] = NULL;
264 :
265 6028 : new_pass = false;
266 6028 : pset.db = PQconnectdbParams(keywords, values, true);
267 6028 : free(keywords);
268 6028 : free(values);
269 :
270 6408 : if (PQstatus(pset.db) == CONNECTION_BAD &&
271 382 : PQconnectionNeedsPassword(pset.db) &&
272 2 : !password &&
273 2 : pset.getPassword != TRI_NO)
274 : {
275 : /*
276 : * Before closing the old PGconn, extract the user name that was
277 : * actually connected with --- it might've come out of a URI or
278 : * connstring "database name" rather than options.username.
279 : */
280 0 : const char *realusername = PQuser(pset.db);
281 : char *password_prompt;
282 :
283 0 : if (realusername && realusername[0])
284 0 : password_prompt = psprintf(_("Password for user %s: "),
285 : realusername);
286 : else
287 0 : password_prompt = pg_strdup(_("Password: "));
288 0 : PQfinish(pset.db);
289 :
290 0 : password = simple_prompt(password_prompt, false);
291 0 : free(password_prompt);
292 0 : new_pass = true;
293 : }
294 6028 : } while (new_pass);
295 :
296 6028 : if (PQstatus(pset.db) == CONNECTION_BAD)
297 : {
298 380 : pg_log_error("%s", PQerrorMessage(pset.db));
299 380 : PQfinish(pset.db);
300 380 : exit(EXIT_BADCONN);
301 : }
302 :
303 5648 : psql_setup_cancel_handler();
304 :
305 5648 : PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
306 :
307 5648 : SyncVariables();
308 :
309 5648 : if (options.list_dbs)
310 : {
311 : int success;
312 :
313 0 : if (!options.no_psqlrc)
314 0 : process_psqlrc(argv[0]);
315 :
316 0 : success = listAllDbs(NULL, false);
317 0 : PQfinish(pset.db);
318 0 : exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
319 : }
320 :
321 5648 : if (options.logfilename)
322 : {
323 0 : pset.logfile = fopen(options.logfilename, "a");
324 0 : if (!pset.logfile)
325 : {
326 0 : pg_log_fatal("could not open log file \"%s\": %m",
327 : options.logfilename);
328 0 : exit(EXIT_FAILURE);
329 : }
330 : }
331 :
332 5648 : if (!options.no_psqlrc)
333 0 : process_psqlrc(argv[0]);
334 :
335 : /*
336 : * If any actions were given by user, process them in the order in which
337 : * they were specified. Note single_txn is only effective in this mode.
338 : */
339 5648 : if (options.actions.head != NULL)
340 : {
341 : PGresult *res;
342 : SimpleActionListCell *cell;
343 :
344 5646 : successResult = EXIT_SUCCESS; /* silence compiler */
345 :
346 5646 : if (options.single_txn)
347 : {
348 0 : if ((res = PSQLexec("BEGIN")) == NULL)
349 : {
350 0 : if (pset.on_error_stop)
351 : {
352 0 : successResult = EXIT_USER;
353 0 : goto error;
354 : }
355 : }
356 : else
357 0 : PQclear(res);
358 : }
359 :
360 11274 : for (cell = options.actions.head; cell; cell = cell->next)
361 : {
362 5670 : if (cell->action == ACT_SINGLE_QUERY)
363 : {
364 1684 : pg_logging_config(PG_LOG_FLAG_TERSE);
365 :
366 1684 : if (pset.echo == PSQL_ECHO_ALL)
367 0 : puts(cell->val);
368 :
369 1684 : successResult = SendQuery(cell->val)
370 1682 : ? EXIT_SUCCESS : EXIT_FAILURE;
371 : }
372 3986 : else if (cell->action == ACT_SINGLE_SLASH)
373 : {
374 : PsqlScanState scan_state;
375 : ConditionalStack cond_stack;
376 :
377 0 : pg_logging_config(PG_LOG_FLAG_TERSE);
378 :
379 0 : if (pset.echo == PSQL_ECHO_ALL)
380 0 : puts(cell->val);
381 :
382 0 : scan_state = psql_scan_create(&psqlscan_callbacks);
383 0 : psql_scan_setup(scan_state,
384 0 : cell->val, strlen(cell->val),
385 0 : pset.encoding, standard_strings());
386 0 : cond_stack = conditional_stack_create();
387 0 : psql_scan_set_passthrough(scan_state, (void *) cond_stack);
388 :
389 0 : successResult = HandleSlashCmds(scan_state,
390 : cond_stack,
391 : NULL,
392 : NULL) != PSQL_CMD_ERROR
393 0 : ? EXIT_SUCCESS : EXIT_FAILURE;
394 :
395 0 : psql_scan_destroy(scan_state);
396 0 : conditional_stack_destroy(cond_stack);
397 : }
398 3986 : else if (cell->action == ACT_FILE)
399 : {
400 3986 : successResult = process_file(cell->val, false);
401 : }
402 : else
403 : {
404 : /* should never come here */
405 : Assert(false);
406 : }
407 :
408 5660 : if (successResult != EXIT_SUCCESS && pset.on_error_stop)
409 32 : break;
410 : }
411 :
412 5636 : if (options.single_txn)
413 : {
414 0 : if ((res = PSQLexec("COMMIT")) == NULL)
415 : {
416 0 : if (pset.on_error_stop)
417 : {
418 0 : successResult = EXIT_USER;
419 0 : goto error;
420 : }
421 : }
422 : else
423 0 : PQclear(res);
424 : }
425 :
426 5636 : error:
427 : ;
428 : }
429 :
430 : /*
431 : * or otherwise enter interactive main loop
432 : */
433 : else
434 : {
435 2 : pg_logging_config(PG_LOG_FLAG_TERSE);
436 2 : connection_warnings(true);
437 2 : if (!pset.quiet)
438 2 : printf(_("Type \"help\" for help.\n\n"));
439 2 : initializeInput(options.no_readline ? 0 : 1);
440 2 : successResult = MainLoop(stdin);
441 : }
442 :
443 : /* clean up */
444 5638 : if (pset.logfile)
445 0 : fclose(pset.logfile);
446 5638 : if (pset.db)
447 5638 : PQfinish(pset.db);
448 5638 : if (pset.dead_conn)
449 0 : PQfinish(pset.dead_conn);
450 5638 : setQFout(NULL);
451 :
452 5638 : return successResult;
453 : }
454 :
455 :
456 : /*
457 : * Parse command line options
458 : */
459 :
460 : static void
461 6028 : parse_psql_options(int argc, char *argv[], struct adhoc_opts *options)
462 : {
463 : static struct option long_options[] =
464 : {
465 : {"echo-all", no_argument, NULL, 'a'},
466 : {"no-align", no_argument, NULL, 'A'},
467 : {"command", required_argument, NULL, 'c'},
468 : {"dbname", required_argument, NULL, 'd'},
469 : {"echo-queries", no_argument, NULL, 'e'},
470 : {"echo-errors", no_argument, NULL, 'b'},
471 : {"echo-hidden", no_argument, NULL, 'E'},
472 : {"file", required_argument, NULL, 'f'},
473 : {"field-separator", required_argument, NULL, 'F'},
474 : {"field-separator-zero", no_argument, NULL, 'z'},
475 : {"host", required_argument, NULL, 'h'},
476 : {"html", no_argument, NULL, 'H'},
477 : {"list", no_argument, NULL, 'l'},
478 : {"log-file", required_argument, NULL, 'L'},
479 : {"no-readline", no_argument, NULL, 'n'},
480 : {"single-transaction", no_argument, NULL, '1'},
481 : {"output", required_argument, NULL, 'o'},
482 : {"port", required_argument, NULL, 'p'},
483 : {"pset", required_argument, NULL, 'P'},
484 : {"quiet", no_argument, NULL, 'q'},
485 : {"record-separator", required_argument, NULL, 'R'},
486 : {"record-separator-zero", no_argument, NULL, '0'},
487 : {"single-step", no_argument, NULL, 's'},
488 : {"single-line", no_argument, NULL, 'S'},
489 : {"tuples-only", no_argument, NULL, 't'},
490 : {"table-attr", required_argument, NULL, 'T'},
491 : {"username", required_argument, NULL, 'U'},
492 : {"set", required_argument, NULL, 'v'},
493 : {"variable", required_argument, NULL, 'v'},
494 : {"version", no_argument, NULL, 'V'},
495 : {"no-password", no_argument, NULL, 'w'},
496 : {"password", no_argument, NULL, 'W'},
497 : {"expanded", no_argument, NULL, 'x'},
498 : {"no-psqlrc", no_argument, NULL, 'X'},
499 : {"help", optional_argument, NULL, 1},
500 : {"csv", no_argument, NULL, 2},
501 : {NULL, 0, NULL, 0}
502 : };
503 :
504 : int optindex;
505 : int c;
506 :
507 6028 : memset(options, 0, sizeof *options);
508 :
509 38614 : while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
510 : long_options, &optindex)) != -1)
511 : {
512 32586 : switch (c)
513 : {
514 1306 : case 'a':
515 1306 : SetVariable(pset.vars, "ECHO", "all");
516 1306 : break;
517 3756 : case 'A':
518 3756 : pset.popt.topt.format = PRINT_UNALIGNED;
519 3756 : break;
520 0 : case 'b':
521 0 : SetVariable(pset.vars, "ECHO", "errors");
522 0 : break;
523 1766 : case 'c':
524 1766 : if (optarg[0] == '\\')
525 0 : simple_action_list_append(&options->actions,
526 : ACT_SINGLE_SLASH,
527 0 : optarg + 1);
528 : else
529 1766 : simple_action_list_append(&options->actions,
530 : ACT_SINGLE_QUERY,
531 : optarg);
532 1766 : break;
533 5284 : case 'd':
534 5284 : options->dbname = pg_strdup(optarg);
535 5284 : break;
536 2 : case 'e':
537 2 : SetVariable(pset.vars, "ECHO", "queries");
538 2 : break;
539 0 : case 'E':
540 0 : SetVariableBool(pset.vars, "ECHO_HIDDEN");
541 0 : break;
542 2576 : case 'f':
543 2576 : simple_action_list_append(&options->actions,
544 : ACT_FILE,
545 : optarg);
546 2576 : break;
547 4 : case 'F':
548 4 : pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
549 4 : pset.popt.topt.fieldSep.separator_zero = false;
550 4 : break;
551 2 : case 'h':
552 2 : options->host = pg_strdup(optarg);
553 2 : break;
554 0 : case 'H':
555 0 : pset.popt.topt.format = PRINT_HTML;
556 0 : break;
557 0 : case 'l':
558 0 : options->list_dbs = true;
559 0 : break;
560 0 : case 'L':
561 0 : options->logfilename = pg_strdup(optarg);
562 0 : break;
563 0 : case 'n':
564 0 : options->no_readline = true;
565 0 : break;
566 0 : case 'o':
567 0 : if (!setQFout(optarg))
568 0 : exit(EXIT_FAILURE);
569 0 : break;
570 4 : case 'p':
571 4 : options->port = pg_strdup(optarg);
572 4 : break;
573 4 : case 'P':
574 : {
575 : char *value;
576 : char *equal_loc;
577 : bool result;
578 :
579 4 : value = pg_strdup(optarg);
580 4 : equal_loc = strchr(value, '=');
581 4 : if (!equal_loc)
582 0 : result = do_pset(value, NULL, &pset.popt, true);
583 : else
584 : {
585 4 : *equal_loc = '\0';
586 4 : result = do_pset(value, equal_loc + 1, &pset.popt, true);
587 : }
588 :
589 4 : if (!result)
590 : {
591 0 : pg_log_fatal("could not set printing parameter \"%s\"", value);
592 0 : exit(EXIT_FAILURE);
593 : }
594 :
595 4 : free(value);
596 4 : break;
597 : }
598 4110 : case 'q':
599 4110 : SetVariableBool(pset.vars, "QUIET");
600 4110 : break;
601 0 : case 'R':
602 0 : pset.popt.topt.recordSep.separator = pg_strdup(optarg);
603 0 : pset.popt.topt.recordSep.separator_zero = false;
604 0 : break;
605 0 : case 's':
606 0 : SetVariableBool(pset.vars, "SINGLESTEP");
607 0 : break;
608 0 : case 'S':
609 0 : SetVariableBool(pset.vars, "SINGLELINE");
610 0 : break;
611 3748 : case 't':
612 3748 : pset.popt.topt.tuples_only = true;
613 3748 : break;
614 0 : case 'T':
615 0 : pset.popt.topt.tableAttr = pg_strdup(optarg);
616 0 : break;
617 100 : case 'U':
618 100 : options->username = pg_strdup(optarg);
619 100 : break;
620 3870 : case 'v':
621 : {
622 : char *value;
623 : char *equal_loc;
624 :
625 3870 : value = pg_strdup(optarg);
626 3870 : equal_loc = strchr(value, '=');
627 3870 : if (!equal_loc)
628 : {
629 0 : if (!DeleteVariable(pset.vars, value))
630 0 : exit(EXIT_FAILURE); /* error already printed */
631 : }
632 : else
633 : {
634 3870 : *equal_loc = '\0';
635 3870 : if (!SetVariable(pset.vars, value, equal_loc + 1))
636 0 : exit(EXIT_FAILURE); /* error already printed */
637 : }
638 :
639 3870 : free(value);
640 3870 : break;
641 : }
642 0 : case 'V':
643 0 : showVersion();
644 0 : exit(EXIT_SUCCESS);
645 26 : case 'w':
646 26 : pset.getPassword = TRI_NO;
647 26 : break;
648 0 : case 'W':
649 0 : pset.getPassword = TRI_YES;
650 0 : break;
651 0 : case 'x':
652 0 : pset.popt.topt.expanded = true;
653 0 : break;
654 6028 : case 'X':
655 6028 : options->no_psqlrc = true;
656 6028 : break;
657 0 : case 'z':
658 0 : pset.popt.topt.fieldSep.separator_zero = true;
659 0 : break;
660 0 : case '0':
661 0 : pset.popt.topt.recordSep.separator_zero = true;
662 0 : break;
663 0 : case '1':
664 0 : options->single_txn = true;
665 0 : break;
666 0 : case '?':
667 0 : if (optind <= argc &&
668 0 : strcmp(argv[optind - 1], "-?") == 0)
669 : {
670 : /* actual help option given */
671 0 : usage(NOPAGER);
672 0 : exit(EXIT_SUCCESS);
673 : }
674 : else
675 : {
676 : /* getopt error (unknown option or missing argument) */
677 0 : goto unknown_option;
678 : }
679 : break;
680 0 : case 1:
681 : {
682 0 : if (!optarg || strcmp(optarg, "options") == 0)
683 0 : usage(NOPAGER);
684 0 : else if (optarg && strcmp(optarg, "commands") == 0)
685 0 : slashUsage(NOPAGER);
686 0 : else if (optarg && strcmp(optarg, "variables") == 0)
687 0 : helpVariables(NOPAGER);
688 : else
689 0 : goto unknown_option;
690 :
691 0 : exit(EXIT_SUCCESS);
692 : }
693 : break;
694 0 : case 2:
695 0 : pset.popt.topt.format = PRINT_CSV;
696 0 : break;
697 : default:
698 0 : unknown_option:
699 0 : fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
700 : pset.progname);
701 0 : exit(EXIT_FAILURE);
702 : break;
703 : }
704 : }
705 :
706 : /*
707 : * if we still have arguments, use it as the database name and username
708 : */
709 6788 : while (argc - optind >= 1)
710 : {
711 760 : if (!options->dbname)
712 760 : options->dbname = argv[optind];
713 0 : else if (!options->username)
714 0 : options->username = argv[optind];
715 0 : else if (!pset.quiet)
716 0 : pg_log_warning("extra command-line argument \"%s\" ignored",
717 : argv[optind]);
718 :
719 760 : optind++;
720 : }
721 6028 : }
722 :
723 :
724 : /*
725 : * Append a new item to the end of the SimpleActionList.
726 : * Note that "val" is copied if it's not NULL.
727 : */
728 : static void
729 6070 : simple_action_list_append(SimpleActionList *list,
730 : enum _actions action, const char *val)
731 : {
732 : SimpleActionListCell *cell;
733 :
734 6070 : cell = (SimpleActionListCell *) pg_malloc(sizeof(SimpleActionListCell));
735 :
736 6070 : cell->next = NULL;
737 6070 : cell->action = action;
738 6070 : if (val)
739 4342 : cell->val = pg_strdup(val);
740 : else
741 1728 : cell->val = NULL;
742 :
743 6070 : if (list->tail)
744 44 : list->tail->next = cell;
745 : else
746 6026 : list->head = cell;
747 6070 : list->tail = cell;
748 6070 : }
749 :
750 :
751 : /*
752 : * Load .psqlrc file, if found.
753 : */
754 : static void
755 0 : process_psqlrc(char *argv0)
756 : {
757 : char home[MAXPGPATH];
758 : char rc_file[MAXPGPATH];
759 : char my_exec_path[MAXPGPATH];
760 : char etc_path[MAXPGPATH];
761 0 : char *envrc = getenv("PSQLRC");
762 :
763 0 : if (find_my_exec(argv0, my_exec_path) < 0)
764 : {
765 0 : pg_log_fatal("could not find own program executable");
766 0 : exit(EXIT_FAILURE);
767 : }
768 :
769 0 : get_etc_path(my_exec_path, etc_path);
770 :
771 0 : snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
772 0 : process_psqlrc_file(rc_file);
773 :
774 0 : if (envrc != NULL && strlen(envrc) > 0)
775 0 : {
776 : /* might need to free() this */
777 0 : char *envrc_alloc = pstrdup(envrc);
778 :
779 0 : expand_tilde(&envrc_alloc);
780 0 : process_psqlrc_file(envrc_alloc);
781 : }
782 0 : else if (get_home_path(home))
783 : {
784 0 : snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
785 0 : process_psqlrc_file(rc_file);
786 : }
787 0 : }
788 :
789 :
790 :
791 : static void
792 0 : process_psqlrc_file(char *filename)
793 : {
794 : char *psqlrc_minor,
795 : *psqlrc_major;
796 :
797 : #if defined(WIN32) && (!defined(__MINGW32__))
798 : #define R_OK 4
799 : #endif
800 :
801 0 : psqlrc_minor = psprintf("%s-%s", filename, PG_VERSION);
802 0 : psqlrc_major = psprintf("%s-%s", filename, PG_MAJORVERSION);
803 :
804 : /* check for minor version first, then major, then no version */
805 0 : if (access(psqlrc_minor, R_OK) == 0)
806 0 : (void) process_file(psqlrc_minor, false);
807 0 : else if (access(psqlrc_major, R_OK) == 0)
808 0 : (void) process_file(psqlrc_major, false);
809 0 : else if (access(filename, R_OK) == 0)
810 0 : (void) process_file(filename, false);
811 :
812 0 : free(psqlrc_minor);
813 0 : free(psqlrc_major);
814 0 : }
815 :
816 :
817 :
818 : /* showVersion
819 : *
820 : * This output format is intended to match GNU standards.
821 : */
822 : static void
823 0 : showVersion(void)
824 : {
825 0 : puts("psql (PostgreSQL) " PG_VERSION);
826 0 : }
827 :
828 :
829 :
830 : /*
831 : * Substitute hooks and assign hooks for psql variables.
832 : *
833 : * This isn't an amazingly good place for them, but neither is anywhere else.
834 : *
835 : * By policy, every special variable that controls any psql behavior should
836 : * have one or both hooks, even if they're just no-ops. This ensures that
837 : * the variable will remain present in variables.c's list even when unset,
838 : * which ensures that it's known to tab completion.
839 : */
840 :
841 : static char *
842 62300 : bool_substitute_hook(char *newval)
843 : {
844 62300 : if (newval == NULL)
845 : {
846 : /* "\unset FOO" becomes "\set FOO off" */
847 48228 : newval = pg_strdup("off");
848 : }
849 14072 : else if (newval[0] == '\0')
850 : {
851 : /* "\set FOO" becomes "\set FOO on" */
852 4 : pg_free(newval);
853 4 : newval = pg_strdup("on");
854 : }
855 62300 : return newval;
856 : }
857 :
858 : static bool
859 12060 : autocommit_hook(const char *newval)
860 : {
861 12060 : return ParseVariableBool(newval, "AUTOCOMMIT", &pset.autocommit);
862 : }
863 :
864 : static bool
865 8592 : on_error_stop_hook(const char *newval)
866 : {
867 8592 : return ParseVariableBool(newval, "ON_ERROR_STOP", &pset.on_error_stop);
868 : }
869 :
870 : static bool
871 10178 : quiet_hook(const char *newval)
872 : {
873 10178 : return ParseVariableBool(newval, "QUIET", &pset.quiet);
874 : }
875 :
876 : static bool
877 6028 : singleline_hook(const char *newval)
878 : {
879 6028 : return ParseVariableBool(newval, "SINGLELINE", &pset.singleline);
880 : }
881 :
882 : static bool
883 6028 : singlestep_hook(const char *newval)
884 : {
885 6028 : return ParseVariableBool(newval, "SINGLESTEP", &pset.singlestep);
886 : }
887 :
888 : static char *
889 6064 : fetch_count_substitute_hook(char *newval)
890 : {
891 6064 : if (newval == NULL)
892 6044 : newval = pg_strdup("0");
893 6064 : return newval;
894 : }
895 :
896 : static bool
897 6064 : fetch_count_hook(const char *newval)
898 : {
899 6064 : return ParseVariableNum(newval, "FETCH_COUNT", &pset.fetch_count);
900 : }
901 :
902 : static bool
903 6028 : histfile_hook(const char *newval)
904 : {
905 : /*
906 : * Someday we might try to validate the filename, but for now, this is
907 : * just a placeholder to ensure HISTFILE is known to tab completion.
908 : */
909 6028 : return true;
910 : }
911 :
912 : static char *
913 6028 : histsize_substitute_hook(char *newval)
914 : {
915 6028 : if (newval == NULL)
916 6028 : newval = pg_strdup("500");
917 6028 : return newval;
918 : }
919 :
920 : static bool
921 6028 : histsize_hook(const char *newval)
922 : {
923 6028 : return ParseVariableNum(newval, "HISTSIZE", &pset.histsize);
924 : }
925 :
926 : static char *
927 6028 : ignoreeof_substitute_hook(char *newval)
928 : {
929 : int dummy;
930 :
931 : /*
932 : * This tries to mimic the behavior of bash, to wit "If set, the value is
933 : * the number of consecutive EOF characters which must be typed as the
934 : * first characters on an input line before bash exits. If the variable
935 : * exists but does not have a numeric value, or has no value, the default
936 : * value is 10. If it does not exist, EOF signifies the end of input to
937 : * the shell." Unlike bash, however, we insist on the stored value
938 : * actually being a valid integer.
939 : */
940 6028 : if (newval == NULL)
941 6028 : newval = pg_strdup("0");
942 0 : else if (!ParseVariableNum(newval, NULL, &dummy))
943 0 : newval = pg_strdup("10");
944 6028 : return newval;
945 : }
946 :
947 : static bool
948 6028 : ignoreeof_hook(const char *newval)
949 : {
950 6028 : return ParseVariableNum(newval, "IGNOREEOF", &pset.ignoreeof);
951 : }
952 :
953 : static char *
954 7352 : echo_substitute_hook(char *newval)
955 : {
956 7352 : if (newval == NULL)
957 6028 : newval = pg_strdup("none");
958 7352 : return newval;
959 : }
960 :
961 : static bool
962 7352 : echo_hook(const char *newval)
963 : {
964 : Assert(newval != NULL); /* else substitute hook messed up */
965 7352 : if (pg_strcasecmp(newval, "queries") == 0)
966 2 : pset.echo = PSQL_ECHO_QUERIES;
967 7350 : else if (pg_strcasecmp(newval, "errors") == 0)
968 0 : pset.echo = PSQL_ECHO_ERRORS;
969 7350 : else if (pg_strcasecmp(newval, "all") == 0)
970 1314 : pset.echo = PSQL_ECHO_ALL;
971 6036 : else if (pg_strcasecmp(newval, "none") == 0)
972 6036 : pset.echo = PSQL_ECHO_NONE;
973 : else
974 : {
975 0 : PsqlVarEnumError("ECHO", newval, "none, errors, queries, all");
976 0 : return false;
977 : }
978 7352 : return true;
979 : }
980 :
981 : static bool
982 6028 : echo_hidden_hook(const char *newval)
983 : {
984 : Assert(newval != NULL); /* else substitute hook messed up */
985 6028 : if (pg_strcasecmp(newval, "noexec") == 0)
986 0 : pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
987 : else
988 : {
989 : bool on_off;
990 :
991 6028 : if (ParseVariableBool(newval, NULL, &on_off))
992 6028 : pset.echo_hidden = on_off ? PSQL_ECHO_HIDDEN_ON : PSQL_ECHO_HIDDEN_OFF;
993 : else
994 : {
995 0 : PsqlVarEnumError("ECHO_HIDDEN", newval, "on, off, noexec");
996 0 : return false;
997 : }
998 : }
999 6028 : return true;
1000 : }
1001 :
1002 : static bool
1003 6044 : on_error_rollback_hook(const char *newval)
1004 : {
1005 : Assert(newval != NULL); /* else substitute hook messed up */
1006 6044 : if (pg_strcasecmp(newval, "interactive") == 0)
1007 0 : pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
1008 : else
1009 : {
1010 : bool on_off;
1011 :
1012 6044 : if (ParseVariableBool(newval, NULL, &on_off))
1013 6040 : pset.on_error_rollback = on_off ? PSQL_ERROR_ROLLBACK_ON : PSQL_ERROR_ROLLBACK_OFF;
1014 : else
1015 : {
1016 4 : PsqlVarEnumError("ON_ERROR_ROLLBACK", newval, "on, off, interactive");
1017 4 : return false;
1018 : }
1019 : }
1020 6040 : return true;
1021 : }
1022 :
1023 : static char *
1024 6028 : comp_keyword_case_substitute_hook(char *newval)
1025 : {
1026 6028 : if (newval == NULL)
1027 6028 : newval = pg_strdup("preserve-upper");
1028 6028 : return newval;
1029 : }
1030 :
1031 : static bool
1032 6028 : comp_keyword_case_hook(const char *newval)
1033 : {
1034 : Assert(newval != NULL); /* else substitute hook messed up */
1035 6028 : if (pg_strcasecmp(newval, "preserve-upper") == 0)
1036 6028 : pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
1037 0 : else if (pg_strcasecmp(newval, "preserve-lower") == 0)
1038 0 : pset.comp_case = PSQL_COMP_CASE_PRESERVE_LOWER;
1039 0 : else if (pg_strcasecmp(newval, "upper") == 0)
1040 0 : pset.comp_case = PSQL_COMP_CASE_UPPER;
1041 0 : else if (pg_strcasecmp(newval, "lower") == 0)
1042 0 : pset.comp_case = PSQL_COMP_CASE_LOWER;
1043 : else
1044 : {
1045 0 : PsqlVarEnumError("COMP_KEYWORD_CASE", newval,
1046 : "lower, upper, preserve-lower, preserve-upper");
1047 0 : return false;
1048 : }
1049 6028 : return true;
1050 : }
1051 :
1052 : static char *
1053 6028 : histcontrol_substitute_hook(char *newval)
1054 : {
1055 6028 : if (newval == NULL)
1056 6028 : newval = pg_strdup("none");
1057 6028 : return newval;
1058 : }
1059 :
1060 : static bool
1061 6028 : histcontrol_hook(const char *newval)
1062 : {
1063 : Assert(newval != NULL); /* else substitute hook messed up */
1064 6028 : if (pg_strcasecmp(newval, "ignorespace") == 0)
1065 0 : pset.histcontrol = hctl_ignorespace;
1066 6028 : else if (pg_strcasecmp(newval, "ignoredups") == 0)
1067 0 : pset.histcontrol = hctl_ignoredups;
1068 6028 : else if (pg_strcasecmp(newval, "ignoreboth") == 0)
1069 0 : pset.histcontrol = hctl_ignoreboth;
1070 6028 : else if (pg_strcasecmp(newval, "none") == 0)
1071 6028 : pset.histcontrol = hctl_none;
1072 : else
1073 : {
1074 0 : PsqlVarEnumError("HISTCONTROL", newval,
1075 : "none, ignorespace, ignoredups, ignoreboth");
1076 0 : return false;
1077 : }
1078 6028 : return true;
1079 : }
1080 :
1081 : static bool
1082 12056 : prompt1_hook(const char *newval)
1083 : {
1084 12056 : pset.prompt1 = newval ? newval : "";
1085 12056 : return true;
1086 : }
1087 :
1088 : static bool
1089 12056 : prompt2_hook(const char *newval)
1090 : {
1091 12056 : pset.prompt2 = newval ? newval : "";
1092 12056 : return true;
1093 : }
1094 :
1095 : static bool
1096 12056 : prompt3_hook(const char *newval)
1097 : {
1098 12056 : pset.prompt3 = newval ? newval : "";
1099 12056 : return true;
1100 : }
1101 :
1102 : static char *
1103 6092 : verbosity_substitute_hook(char *newval)
1104 : {
1105 6092 : if (newval == NULL)
1106 6028 : newval = pg_strdup("default");
1107 6092 : return newval;
1108 : }
1109 :
1110 : static bool
1111 6092 : verbosity_hook(const char *newval)
1112 : {
1113 : Assert(newval != NULL); /* else substitute hook messed up */
1114 6092 : if (pg_strcasecmp(newval, "default") == 0)
1115 6050 : pset.verbosity = PQERRORS_DEFAULT;
1116 42 : else if (pg_strcasecmp(newval, "verbose") == 0)
1117 0 : pset.verbosity = PQERRORS_VERBOSE;
1118 42 : else if (pg_strcasecmp(newval, "terse") == 0)
1119 30 : pset.verbosity = PQERRORS_TERSE;
1120 12 : else if (pg_strcasecmp(newval, "sqlstate") == 0)
1121 12 : pset.verbosity = PQERRORS_SQLSTATE;
1122 : else
1123 : {
1124 0 : PsqlVarEnumError("VERBOSITY", newval, "default, verbose, terse, sqlstate");
1125 0 : return false;
1126 : }
1127 :
1128 6092 : if (pset.db)
1129 64 : PQsetErrorVerbosity(pset.db, pset.verbosity);
1130 6092 : return true;
1131 : }
1132 :
1133 : static char *
1134 6066 : show_context_substitute_hook(char *newval)
1135 : {
1136 6066 : if (newval == NULL)
1137 6030 : newval = pg_strdup("errors");
1138 6066 : return newval;
1139 : }
1140 :
1141 : static bool
1142 6066 : show_context_hook(const char *newval)
1143 : {
1144 : Assert(newval != NULL); /* else substitute hook messed up */
1145 6066 : if (pg_strcasecmp(newval, "never") == 0)
1146 16 : pset.show_context = PQSHOW_CONTEXT_NEVER;
1147 6050 : else if (pg_strcasecmp(newval, "errors") == 0)
1148 6042 : pset.show_context = PQSHOW_CONTEXT_ERRORS;
1149 8 : else if (pg_strcasecmp(newval, "always") == 0)
1150 8 : pset.show_context = PQSHOW_CONTEXT_ALWAYS;
1151 : else
1152 : {
1153 0 : PsqlVarEnumError("SHOW_CONTEXT", newval, "never, errors, always");
1154 0 : return false;
1155 : }
1156 :
1157 6066 : if (pset.db)
1158 38 : PQsetErrorContextVisibility(pset.db, pset.show_context);
1159 6066 : return true;
1160 : }
1161 :
1162 : static bool
1163 7342 : hide_tableam_hook(const char *newval)
1164 : {
1165 7342 : return ParseVariableBool(newval, "HIDE_TABLEAM", &pset.hide_tableam);
1166 : }
1167 :
1168 : static void
1169 6028 : EstablishVariableSpace(void)
1170 : {
1171 6028 : pset.vars = CreateVariableSpace();
1172 :
1173 6028 : SetVariableHooks(pset.vars, "AUTOCOMMIT",
1174 : bool_substitute_hook,
1175 : autocommit_hook);
1176 6028 : SetVariableHooks(pset.vars, "ON_ERROR_STOP",
1177 : bool_substitute_hook,
1178 : on_error_stop_hook);
1179 6028 : SetVariableHooks(pset.vars, "QUIET",
1180 : bool_substitute_hook,
1181 : quiet_hook);
1182 6028 : SetVariableHooks(pset.vars, "SINGLELINE",
1183 : bool_substitute_hook,
1184 : singleline_hook);
1185 6028 : SetVariableHooks(pset.vars, "SINGLESTEP",
1186 : bool_substitute_hook,
1187 : singlestep_hook);
1188 6028 : SetVariableHooks(pset.vars, "FETCH_COUNT",
1189 : fetch_count_substitute_hook,
1190 : fetch_count_hook);
1191 6028 : SetVariableHooks(pset.vars, "HISTFILE",
1192 : NULL,
1193 : histfile_hook);
1194 6028 : SetVariableHooks(pset.vars, "HISTSIZE",
1195 : histsize_substitute_hook,
1196 : histsize_hook);
1197 6028 : SetVariableHooks(pset.vars, "IGNOREEOF",
1198 : ignoreeof_substitute_hook,
1199 : ignoreeof_hook);
1200 6028 : SetVariableHooks(pset.vars, "ECHO",
1201 : echo_substitute_hook,
1202 : echo_hook);
1203 6028 : SetVariableHooks(pset.vars, "ECHO_HIDDEN",
1204 : bool_substitute_hook,
1205 : echo_hidden_hook);
1206 6028 : SetVariableHooks(pset.vars, "ON_ERROR_ROLLBACK",
1207 : bool_substitute_hook,
1208 : on_error_rollback_hook);
1209 6028 : SetVariableHooks(pset.vars, "COMP_KEYWORD_CASE",
1210 : comp_keyword_case_substitute_hook,
1211 : comp_keyword_case_hook);
1212 6028 : SetVariableHooks(pset.vars, "HISTCONTROL",
1213 : histcontrol_substitute_hook,
1214 : histcontrol_hook);
1215 6028 : SetVariableHooks(pset.vars, "PROMPT1",
1216 : NULL,
1217 : prompt1_hook);
1218 6028 : SetVariableHooks(pset.vars, "PROMPT2",
1219 : NULL,
1220 : prompt2_hook);
1221 6028 : SetVariableHooks(pset.vars, "PROMPT3",
1222 : NULL,
1223 : prompt3_hook);
1224 6028 : SetVariableHooks(pset.vars, "VERBOSITY",
1225 : verbosity_substitute_hook,
1226 : verbosity_hook);
1227 6028 : SetVariableHooks(pset.vars, "SHOW_CONTEXT",
1228 : show_context_substitute_hook,
1229 : show_context_hook);
1230 6028 : SetVariableHooks(pset.vars, "HIDE_TABLEAM",
1231 : bool_substitute_hook,
1232 : hide_tableam_hook);
1233 6028 : }
|