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