Code review for patch to show definition of index columns in \d on index.
[PostgreSQL.git] / src / bin / psql / startup.c
blob429e5d906505d2da0b1bd3b5ba3294859c97d20a
1 /*
2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2009, PostgreSQL Global Development Group
6 * $PostgreSQL$
7 */
8 #include "postgres_fe.h"
10 #include <sys/types.h>
12 #ifndef WIN32
13 #include <unistd.h>
14 #else /* WIN32 */
15 #include <io.h>
16 #include <win32.h>
17 #endif /* WIN32 */
19 #include "getopt_long.h"
21 #include <locale.h>
23 #include "command.h"
24 #include "common.h"
25 #include "describe.h"
26 #include "help.h"
27 #include "input.h"
28 #include "mainloop.h"
29 #include "settings.h"
34 * Global psql options
36 PsqlSettings pset;
38 #ifndef WIN32
39 #define SYSPSQLRC "psqlrc"
40 #define PSQLRC ".psqlrc"
41 #else
42 #define SYSPSQLRC "psqlrc"
43 #define PSQLRC "psqlrc.conf"
44 #endif
47 * Structures to pass information between the option parsing routine
48 * and the main function
50 enum _actions
52 ACT_NOTHING = 0,
53 ACT_SINGLE_SLASH,
54 ACT_LIST_DB,
55 ACT_SINGLE_QUERY,
56 ACT_FILE
59 struct adhoc_opts
61 char *dbname;
62 char *host;
63 char *port;
64 char *username;
65 char *logfilename;
66 enum _actions action;
67 char *action_string;
68 bool no_readline;
69 bool no_psqlrc;
70 bool single_txn;
73 static void parse_psql_options(int argc, char *argv[],
74 struct adhoc_opts * options);
75 static void process_psqlrc(char *argv0);
76 static void process_psqlrc_file(char *filename);
77 static void showVersion(void);
78 static void EstablishVariableSpace(void);
82 * main
85 int
86 main(int argc, char *argv[])
88 struct adhoc_opts options;
89 int successResult;
90 char *password = NULL;
91 char *password_prompt = NULL;
92 bool new_pass;
94 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
96 if (argc > 1)
98 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
100 usage();
101 exit(EXIT_SUCCESS);
103 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
105 showVersion();
106 exit(EXIT_SUCCESS);
110 #ifdef WIN32
111 setvbuf(stderr, NULL, _IONBF, 0);
112 #endif
114 setup_cancel_handler();
116 pset.progname = get_progname(argv[0]);
118 pset.db = NULL;
119 setDecimalLocale();
120 pset.encoding = PQenv2encoding();
121 pset.queryFout = stdout;
122 pset.queryFoutPipe = false;
123 pset.cur_cmd_source = stdin;
124 pset.cur_cmd_interactive = false;
126 /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
127 pset.popt.topt.format = PRINT_ALIGNED;
128 pset.popt.topt.border = 1;
129 pset.popt.topt.pager = 1;
130 pset.popt.topt.start_table = true;
131 pset.popt.topt.stop_table = true;
132 pset.popt.default_footer = true;
133 /* We must get COLUMNS here before readline() sets it */
134 pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
136 pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
138 pset.getPassword = TRI_DEFAULT;
140 EstablishVariableSpace();
142 SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
144 /* Default values for variables */
145 SetVariableBool(pset.vars, "AUTOCOMMIT");
146 SetVariable(pset.vars, "VERBOSITY", "default");
147 SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
148 SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
149 SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
151 parse_psql_options(argc, argv, &options);
153 if (!pset.popt.topt.fieldSep)
154 pset.popt.topt.fieldSep = pg_strdup(DEFAULT_FIELD_SEP);
155 if (!pset.popt.topt.recordSep)
156 pset.popt.topt.recordSep = pg_strdup(DEFAULT_RECORD_SEP);
158 if (options.username == NULL)
159 password_prompt = pg_strdup(_("Password: "));
160 else
162 password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
163 strlen(options.username) + 1);
164 sprintf(password_prompt, _("Password for user %s: "),
165 options.username);
168 if (pset.getPassword == TRI_YES)
169 password = simple_prompt(password_prompt, 100, false);
171 /* loop until we have a password if requested by backend */
174 new_pass = false;
175 pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
176 options.action == ACT_LIST_DB && options.dbname == NULL ?
177 "postgres" : options.dbname,
178 options.username, password);
180 if (PQstatus(pset.db) == CONNECTION_BAD &&
181 PQconnectionNeedsPassword(pset.db) &&
182 password == NULL &&
183 pset.getPassword != TRI_NO)
185 PQfinish(pset.db);
186 password = simple_prompt(password_prompt, 100, false);
187 new_pass = true;
189 } while (new_pass);
191 free(password);
192 free(password_prompt);
194 if (PQstatus(pset.db) == CONNECTION_BAD)
196 fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
197 PQfinish(pset.db);
198 exit(EXIT_BADCONN);
201 PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
203 SyncVariables();
205 if (options.action == ACT_LIST_DB)
207 int success = listAllDbs(false);
209 PQfinish(pset.db);
210 exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
213 if (options.logfilename)
215 pset.logfile = fopen(options.logfilename, "a");
216 if (!pset.logfile)
217 fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
218 pset.progname, options.logfilename, strerror(errno));
222 * Now find something to do
226 * process file given by -f
228 if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
230 if (!options.no_psqlrc)
231 process_psqlrc(argv[0]);
233 successResult = process_file(options.action_string, options.single_txn);
237 * process slash command if one was given to -c
239 else if (options.action == ACT_SINGLE_SLASH)
241 PsqlScanState scan_state;
243 if (pset.echo == PSQL_ECHO_ALL)
244 puts(options.action_string);
246 scan_state = psql_scan_create();
247 psql_scan_setup(scan_state,
248 options.action_string,
249 strlen(options.action_string));
251 successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
252 ? EXIT_SUCCESS : EXIT_FAILURE;
254 psql_scan_destroy(scan_state);
258 * If the query given to -c was a normal one, send it
260 else if (options.action == ACT_SINGLE_QUERY)
262 if (pset.echo == PSQL_ECHO_ALL)
263 puts(options.action_string);
265 successResult = SendQuery(options.action_string)
266 ? EXIT_SUCCESS : EXIT_FAILURE;
270 * or otherwise enter interactive main loop
272 else
274 if (!options.no_psqlrc)
275 process_psqlrc(argv[0]);
277 connection_warnings();
278 if (!pset.quiet && !pset.notty)
279 printf(_("Type \"help\" for help.\n\n"));
280 if (!pset.notty)
281 initializeInput(options.no_readline ? 0 : 1);
282 if (options.action_string) /* -f - was used */
283 pset.inputfile = "<stdin>";
285 successResult = MainLoop(stdin);
288 /* clean up */
289 if (pset.logfile)
290 fclose(pset.logfile);
291 PQfinish(pset.db);
292 setQFout(NULL);
294 return successResult;
299 * Parse command line options
302 static void
303 parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
305 static struct option long_options[] =
307 {"echo-all", no_argument, NULL, 'a'},
308 {"no-align", no_argument, NULL, 'A'},
309 {"command", required_argument, NULL, 'c'},
310 {"dbname", required_argument, NULL, 'd'},
311 {"echo-queries", no_argument, NULL, 'e'},
312 {"echo-hidden", no_argument, NULL, 'E'},
313 {"file", required_argument, NULL, 'f'},
314 {"field-separator", required_argument, NULL, 'F'},
315 {"host", required_argument, NULL, 'h'},
316 {"html", no_argument, NULL, 'H'},
317 {"list", no_argument, NULL, 'l'},
318 {"log-file", required_argument, NULL, 'L'},
319 {"no-readline", no_argument, NULL, 'n'},
320 {"single-transaction", no_argument, NULL, '1'},
321 {"output", required_argument, NULL, 'o'},
322 {"port", required_argument, NULL, 'p'},
323 {"pset", required_argument, NULL, 'P'},
324 {"quiet", no_argument, NULL, 'q'},
325 {"record-separator", required_argument, NULL, 'R'},
326 {"single-step", no_argument, NULL, 's'},
327 {"single-line", no_argument, NULL, 'S'},
328 {"tuples-only", no_argument, NULL, 't'},
329 {"table-attr", required_argument, NULL, 'T'},
330 {"username", required_argument, NULL, 'U'},
331 {"set", required_argument, NULL, 'v'},
332 {"variable", required_argument, NULL, 'v'},
333 {"version", no_argument, NULL, 'V'},
334 {"no-password", no_argument, NULL, 'w'},
335 {"password", no_argument, NULL, 'W'},
336 {"expanded", no_argument, NULL, 'x'},
337 {"no-psqlrc", no_argument, NULL, 'X'},
338 {"help", no_argument, NULL, '?'},
339 {NULL, 0, NULL, 0}
342 int optindex;
343 extern char *optarg;
344 extern int optind;
345 int c;
347 memset(options, 0, sizeof *options);
349 while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxX?1",
350 long_options, &optindex)) != -1)
352 switch (c)
354 case 'a':
355 SetVariable(pset.vars, "ECHO", "all");
356 break;
357 case 'A':
358 pset.popt.topt.format = PRINT_UNALIGNED;
359 break;
360 case 'c':
361 options->action_string = optarg;
362 if (optarg[0] == '\\')
364 options->action = ACT_SINGLE_SLASH;
365 options->action_string++;
367 else
368 options->action = ACT_SINGLE_QUERY;
369 break;
370 case 'd':
371 options->dbname = optarg;
372 break;
373 case 'e':
374 SetVariable(pset.vars, "ECHO", "queries");
375 break;
376 case 'E':
377 SetVariableBool(pset.vars, "ECHO_HIDDEN");
378 break;
379 case 'f':
380 options->action = ACT_FILE;
381 options->action_string = optarg;
382 break;
383 case 'F':
384 pset.popt.topt.fieldSep = pg_strdup(optarg);
385 break;
386 case 'h':
387 options->host = optarg;
388 break;
389 case 'H':
390 pset.popt.topt.format = PRINT_HTML;
391 break;
392 case 'l':
393 options->action = ACT_LIST_DB;
394 break;
395 case 'L':
396 options->logfilename = optarg;
397 break;
398 case 'n':
399 options->no_readline = true;
400 break;
401 case 'o':
402 setQFout(optarg);
403 break;
404 case 'p':
405 options->port = optarg;
406 break;
407 case 'P':
409 char *value;
410 char *equal_loc;
411 bool result;
413 value = pg_strdup(optarg);
414 equal_loc = strchr(value, '=');
415 if (!equal_loc)
416 result = do_pset(value, NULL, &pset.popt, true);
417 else
419 *equal_loc = '\0';
420 result = do_pset(value, equal_loc + 1, &pset.popt, true);
423 if (!result)
425 fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
426 exit(EXIT_FAILURE);
429 free(value);
430 break;
432 case 'q':
433 SetVariableBool(pset.vars, "QUIET");
434 break;
435 case 'R':
436 pset.popt.topt.recordSep = pg_strdup(optarg);
437 break;
438 case 's':
439 SetVariableBool(pset.vars, "SINGLESTEP");
440 break;
441 case 'S':
442 SetVariableBool(pset.vars, "SINGLELINE");
443 break;
444 case 't':
445 pset.popt.topt.tuples_only = true;
446 break;
447 case 'T':
448 pset.popt.topt.tableAttr = pg_strdup(optarg);
449 break;
450 case 'U':
451 options->username = optarg;
452 break;
453 case 'v':
455 char *value;
456 char *equal_loc;
458 value = pg_strdup(optarg);
459 equal_loc = strchr(value, '=');
460 if (!equal_loc)
462 if (!DeleteVariable(pset.vars, value))
464 fprintf(stderr, _("%s: could not delete variable \"%s\"\n"),
465 pset.progname, value);
466 exit(EXIT_FAILURE);
469 else
471 *equal_loc = '\0';
472 if (!SetVariable(pset.vars, value, equal_loc + 1))
474 fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
475 pset.progname, value);
476 exit(EXIT_FAILURE);
480 free(value);
481 break;
483 case 'V':
484 showVersion();
485 exit(EXIT_SUCCESS);
486 case 'w':
487 pset.getPassword = TRI_NO;
488 break;
489 case 'W':
490 pset.getPassword = TRI_YES;
491 break;
492 case 'x':
493 pset.popt.topt.expanded = true;
494 break;
495 case 'X':
496 options->no_psqlrc = true;
497 break;
498 case '1':
499 options->single_txn = true;
500 break;
501 case '?':
502 /* Actual help option given */
503 if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
505 usage();
506 exit(EXIT_SUCCESS);
508 /* unknown option reported by getopt */
509 else
511 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
512 pset.progname);
513 exit(EXIT_FAILURE);
515 break;
516 default:
517 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
518 pset.progname);
519 exit(EXIT_FAILURE);
520 break;
525 * if we still have arguments, use it as the database name and username
527 while (argc - optind >= 1)
529 if (!options->dbname)
530 options->dbname = argv[optind];
531 else if (!options->username)
532 options->username = argv[optind];
533 else if (!pset.quiet)
534 fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
535 pset.progname, argv[optind]);
537 optind++;
543 * Load .psqlrc file, if found.
545 static void
546 process_psqlrc(char *argv0)
548 char home[MAXPGPATH];
549 char rc_file[MAXPGPATH];
550 char my_exec_path[MAXPGPATH];
551 char etc_path[MAXPGPATH];
553 find_my_exec(argv0, my_exec_path);
554 get_etc_path(my_exec_path, etc_path);
556 snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
557 process_psqlrc_file(rc_file);
559 if (get_home_path(home))
561 snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
562 process_psqlrc_file(rc_file);
568 static void
569 process_psqlrc_file(char *filename)
571 char *psqlrc;
573 #if defined(WIN32) && (!defined(__MINGW32__))
574 #define R_OK 4
575 #endif
577 psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
578 sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
580 if (access(psqlrc, R_OK) == 0)
581 (void) process_file(psqlrc, false);
582 else if (access(filename, R_OK) == 0)
583 (void) process_file(filename, false);
584 free(psqlrc);
589 /* showVersion
591 * This output format is intended to match GNU standards.
593 static void
594 showVersion(void)
596 puts("psql (PostgreSQL) " PG_VERSION);
598 #if defined(USE_READLINE)
599 puts(_("contains support for command-line editing"));
600 #endif
606 * Assign hooks for psql variables.
608 * This isn't an amazingly good place for them, but neither is anywhere else.
611 static void
612 autocommit_hook(const char *newval)
614 pset.autocommit = ParseVariableBool(newval);
617 static void
618 on_error_stop_hook(const char *newval)
620 pset.on_error_stop = ParseVariableBool(newval);
623 static void
624 quiet_hook(const char *newval)
626 pset.quiet = ParseVariableBool(newval);
629 static void
630 singleline_hook(const char *newval)
632 pset.singleline = ParseVariableBool(newval);
635 static void
636 singlestep_hook(const char *newval)
638 pset.singlestep = ParseVariableBool(newval);
641 static void
642 fetch_count_hook(const char *newval)
644 pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
647 static void
648 echo_hook(const char *newval)
650 if (newval == NULL)
651 pset.echo = PSQL_ECHO_NONE;
652 else if (strcmp(newval, "queries") == 0)
653 pset.echo = PSQL_ECHO_QUERIES;
654 else if (strcmp(newval, "all") == 0)
655 pset.echo = PSQL_ECHO_ALL;
656 else
657 pset.echo = PSQL_ECHO_NONE;
660 static void
661 echo_hidden_hook(const char *newval)
663 if (newval == NULL)
664 pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
665 else if (strcmp(newval, "noexec") == 0)
666 pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
667 else if (pg_strcasecmp(newval, "off") == 0)
668 pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
669 else
670 pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
673 static void
674 on_error_rollback_hook(const char *newval)
676 if (newval == NULL)
677 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
678 else if (pg_strcasecmp(newval, "interactive") == 0)
679 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
680 else if (pg_strcasecmp(newval, "off") == 0)
681 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
682 else
683 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
686 static void
687 histcontrol_hook(const char *newval)
689 if (newval == NULL)
690 pset.histcontrol = hctl_none;
691 else if (strcmp(newval, "ignorespace") == 0)
692 pset.histcontrol = hctl_ignorespace;
693 else if (strcmp(newval, "ignoredups") == 0)
694 pset.histcontrol = hctl_ignoredups;
695 else if (strcmp(newval, "ignoreboth") == 0)
696 pset.histcontrol = hctl_ignoreboth;
697 else
698 pset.histcontrol = hctl_none;
701 static void
702 prompt1_hook(const char *newval)
704 pset.prompt1 = newval ? newval : "";
707 static void
708 prompt2_hook(const char *newval)
710 pset.prompt2 = newval ? newval : "";
713 static void
714 prompt3_hook(const char *newval)
716 pset.prompt3 = newval ? newval : "";
719 static void
720 verbosity_hook(const char *newval)
722 if (newval == NULL)
723 pset.verbosity = PQERRORS_DEFAULT;
724 else if (strcmp(newval, "default") == 0)
725 pset.verbosity = PQERRORS_DEFAULT;
726 else if (strcmp(newval, "terse") == 0)
727 pset.verbosity = PQERRORS_TERSE;
728 else if (strcmp(newval, "verbose") == 0)
729 pset.verbosity = PQERRORS_VERBOSE;
730 else
731 pset.verbosity = PQERRORS_DEFAULT;
733 if (pset.db)
734 PQsetErrorVerbosity(pset.db, pset.verbosity);
738 static void
739 EstablishVariableSpace(void)
741 pset.vars = CreateVariableSpace();
743 SetVariableAssignHook(pset.vars, "AUTOCOMMIT", autocommit_hook);
744 SetVariableAssignHook(pset.vars, "ON_ERROR_STOP", on_error_stop_hook);
745 SetVariableAssignHook(pset.vars, "QUIET", quiet_hook);
746 SetVariableAssignHook(pset.vars, "SINGLELINE", singleline_hook);
747 SetVariableAssignHook(pset.vars, "SINGLESTEP", singlestep_hook);
748 SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
749 SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
750 SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
751 SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
752 SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
753 SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
754 SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);
755 SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook);
756 SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook);