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