2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2004, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.105 2004/11/01 19:21:50 momjian Exp $
8 #include "postgres_fe.h"
10 #include <sys/types.h>
19 #include "getopt_long.h"
37 #include "variables.h"
39 #include "mb/pg_wchar.h"
46 #define SYSPSQLRC "psqlrc"
47 #define PSQLRC ".psqlrc"
50 * Structures to pass information between the option parsing routine
51 * and the main function
74 static void parse_psql_options(int argc, char *argv[],
75 struct adhoc_opts * options);
76 static void process_psqlrc(char *argv0);
77 static void process_psqlrc_file(char *filename);
78 static void showVersion(void);
81 static void printSSLInfo(void);
86 checkWin32Codepage(void);
95 main(int argc, char *argv[])
97 struct adhoc_opts options;
100 char *username = NULL;
101 char *password = NULL;
104 set_pglocale_pgservice(argv[0], "psql");
106 pset.progname = get_progname(argv[0]);
110 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
115 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
123 setvbuf(stderr, NULL, _IONBF, 0);
126 pset.cur_cmd_source = stdin;
127 pset.cur_cmd_interactive = false;
128 pset.encoding = PQenv2encoding();
130 pset.vars = CreateVariableSpace();
133 fprintf(stderr, gettext("%s: out of memory\n"), pset.progname);
136 pset.popt.topt.format = PRINT_ALIGNED;
137 pset.queryFout = stdout;
138 pset.popt.topt.border = 1;
139 pset.popt.topt.pager = 1;
140 pset.popt.default_footer = true;
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 pset.verbosity = PQERRORS_DEFAULT;
153 pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
155 /* This is obsolete and should be removed sometime. */
156 #ifdef PSQL_ALWAYS_GET_PASSWORDS
157 pset.getPassword = true;
159 pset.getPassword = false;
162 #ifndef HAVE_UNIX_SOCKETS
163 /* default to localhost on platforms without unix sockets */
164 options.host = "localhost";
167 parse_psql_options(argc, argv, &options);
169 if (!pset.popt.topt.fieldSep)
170 pset.popt.topt.fieldSep = pg_strdup(DEFAULT_FIELD_SEP);
171 if (!pset.popt.topt.recordSep)
172 pset.popt.topt.recordSep = pg_strdup(DEFAULT_RECORD_SEP);
174 if (options.username)
177 * The \001 is a hack to support the deprecated -u option which
178 * issues a username prompt. The recommended option is -U followed
179 * by the name on the command line.
181 if (strcmp(options.username, "\001") == 0)
182 username = simple_prompt("User name: ", 100, true);
184 username = pg_strdup(options.username);
187 if (pset.getPassword)
188 password = simple_prompt("Password: ", 100, false);
190 /* loop until we have a password if requested by backend */
194 pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
195 options.action == ACT_LIST_DB ? "template1" : options.dbname,
198 if (PQstatus(pset.db) == CONNECTION_BAD &&
199 strcmp(PQerrorMessage(pset.db), PQnoPasswordSupplied) == 0 &&
206 password = simple_prompt("Password: ", 100, false);
213 if (PQstatus(pset.db) == CONNECTION_BAD)
215 fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
220 PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
224 /* Grab the backend server version */
225 pset.sversion = PQserverVersion(pset.db);
227 if (options.action == ACT_LIST_DB)
229 int success = listAllDbs(false);
232 exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
236 * Now find something to do
240 * process file given by -f
242 if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
244 if (!options.no_psqlrc)
245 process_psqlrc(argv[0]);
247 successResult = process_file(options.action_string);
251 * process slash command if one was given to -c
253 else if (options.action == ACT_SINGLE_SLASH)
255 PsqlScanState scan_state;
257 if (VariableEquals(pset.vars, "ECHO", "all"))
258 puts(options.action_string);
260 scan_state = psql_scan_create();
261 psql_scan_setup(scan_state,
262 options.action_string,
263 strlen(options.action_string));
265 successResult = HandleSlashCmds(scan_state, NULL) != CMD_ERROR
266 ? EXIT_SUCCESS : EXIT_FAILURE;
268 psql_scan_destroy(scan_state);
272 * If the query given to -c was a normal one, send it
274 else if (options.action == ACT_SINGLE_QUERY)
276 if (VariableEquals(pset.vars, "ECHO", "all"))
277 puts(options.action_string);
279 successResult = SendQuery(options.action_string)
280 ? EXIT_SUCCESS : EXIT_FAILURE;
284 * or otherwise enter interactive main loop
288 if (!options.no_psqlrc)
289 process_psqlrc(argv[0]);
291 if (!QUIET() && !pset.notty)
293 printf(gettext("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"
294 "Type: \\copyright for distribution terms\n"
295 " \\h for help with SQL commands\n"
296 " \\? for help with psql commands\n"
297 " \\g or terminate with semicolon to execute query\n"
299 pset.progname, PG_VERSION);
304 checkWin32Codepage();
309 initializeInput(options.no_readline ? 0 : 1);
310 if (options.action_string) /* -f - was used */
311 pset.inputfile = "<stdin>";
313 successResult = MainLoop(stdin);
320 return successResult;
326 * Parse command line options
330 parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
332 static struct option long_options[] =
334 {"echo-all", no_argument, NULL, 'a'},
335 {"no-align", no_argument, NULL, 'A'},
336 {"command", required_argument, NULL, 'c'},
337 {"dbname", required_argument, NULL, 'd'},
338 {"echo-queries", no_argument, NULL, 'e'},
339 {"echo-hidden", no_argument, NULL, 'E'},
340 {"file", required_argument, NULL, 'f'},
341 {"field-separator", required_argument, NULL, 'F'},
342 {"host", required_argument, NULL, 'h'},
343 {"html", no_argument, NULL, 'H'},
344 {"list", no_argument, NULL, 'l'},
345 {"no-readline", no_argument, NULL, 'n'},
346 {"output", required_argument, NULL, 'o'},
347 {"port", required_argument, NULL, 'p'},
348 {"pset", required_argument, NULL, 'P'},
349 {"quiet", no_argument, NULL, 'q'},
350 {"record-separator", required_argument, NULL, 'R'},
351 {"single-step", no_argument, NULL, 's'},
352 {"single-line", no_argument, NULL, 'S'},
353 {"tuples-only", no_argument, NULL, 't'},
354 {"table-attr", required_argument, NULL, 'T'},
355 {"username", required_argument, NULL, 'U'},
356 {"set", required_argument, NULL, 'v'},
357 {"variable", required_argument, NULL, 'v'},
358 {"version", no_argument, NULL, 'V'},
359 {"password", no_argument, NULL, 'W'},
360 {"expanded", no_argument, NULL, 'x'},
361 {"no-psqlrc", no_argument, NULL, 'X'},
362 {"help", no_argument, NULL, '?'},
370 bool used_old_u_option = false;
372 memset(options, 0, sizeof *options);
374 while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:Hlno:p:P:qR:sStT:uU:v:VWxX?",
375 long_options, &optindex)) != -1)
380 SetVariable(pset.vars, "ECHO", "all");
383 pset.popt.topt.format = PRINT_UNALIGNED;
386 options->action_string = optarg;
387 if (optarg[0] == '\\')
389 options->action = ACT_SINGLE_SLASH;
390 options->action_string++;
393 options->action = ACT_SINGLE_QUERY;
396 options->dbname = optarg;
399 SetVariable(pset.vars, "ECHO", "queries");
402 SetVariableBool(pset.vars, "ECHO_HIDDEN");
405 options->action = ACT_FILE;
406 options->action_string = optarg;
409 pset.popt.topt.fieldSep = pg_strdup(optarg);
412 options->host = optarg;
415 pset.popt.topt.format = PRINT_HTML;
418 options->action = ACT_LIST_DB;
421 options->no_readline = true;
427 options->port = optarg;
435 value = pg_strdup(optarg);
436 equal_loc = strchr(value, '=');
438 result = do_pset(value, NULL, &pset.popt, true);
442 result = do_pset(value, equal_loc + 1, &pset.popt, true);
447 fprintf(stderr, gettext("%s: couldn't set printing parameter \"%s\"\n"), pset.progname, value);
455 SetVariableBool(pset.vars, "QUIET");
458 pset.popt.topt.recordSep = pg_strdup(optarg);
461 SetVariableBool(pset.vars, "SINGLESTEP");
464 SetVariableBool(pset.vars, "SINGLELINE");
467 pset.popt.topt.tuples_only = true;
470 pset.popt.topt.tableAttr = pg_strdup(optarg);
473 pset.getPassword = true;
474 options->username = "\001"; /* hopefully nobody has
476 /* this option is out */
477 used_old_u_option = true;
480 options->username = optarg;
487 value = pg_strdup(optarg);
488 equal_loc = strchr(value, '=');
491 if (!DeleteVariable(pset.vars, value))
493 fprintf(stderr, gettext("%s: could not delete variable \"%s\"\n"),
494 pset.progname, value);
501 if (!SetVariable(pset.vars, value, equal_loc + 1))
503 fprintf(stderr, gettext("%s: could not set variable \"%s\"\n"),
504 pset.progname, value);
516 pset.getPassword = true;
519 pset.popt.topt.expanded = true;
522 options->no_psqlrc = true;
525 /* Actual help option given */
526 if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
531 /* unknown option reported by getopt */
534 fprintf(stderr, gettext("Try \"%s --help\" for more information.\n"),
540 fprintf(stderr, gettext("Try \"%s --help\" for more information.\n"),
548 * if we still have arguments, use it as the database name and
551 while (argc - optind >= 1)
553 if (!options->dbname)
554 options->dbname = argv[optind];
555 else if (!options->username)
556 options->username = argv[optind];
558 fprintf(stderr, gettext("%s: warning: extra command-line argument \"%s\" ignored\n"),
559 pset.progname, argv[optind]);
564 if (used_old_u_option && !QUIET())
565 fprintf(stderr, gettext("%s: Warning: The -u option is deprecated. Use -U.\n"), pset.progname);
571 * Load .psqlrc file, if found.
574 process_psqlrc(char *argv0)
577 char home[MAXPGPATH];
578 char global_file[MAXPGPATH];
579 char my_exec_path[MAXPGPATH];
580 char etc_path[MAXPGPATH];
582 find_my_exec(argv0, my_exec_path);
583 get_etc_path(my_exec_path, etc_path);
585 snprintf(global_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
586 process_psqlrc_file(global_file);
588 if (get_home_path(home))
590 psqlrc = pg_malloc(strlen(home) + 1 + strlen(PSQLRC) + 1);
591 sprintf(psqlrc, "%s/%s", home, PSQLRC);
592 process_psqlrc_file(psqlrc);
600 process_psqlrc_file(char *filename)
604 #if defined(WIN32) && (!defined(__MINGW32__))
608 psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
609 sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
611 if (access(psqlrc, R_OK) == 0)
612 process_file(psqlrc);
613 else if (access(filename, R_OK) == 0)
614 process_file(filename);
622 * This output format is intended to match GNU standards.
627 puts("psql (PostgreSQL) " PG_VERSION);
629 #if defined(USE_READLINE)
630 puts(gettext("contains support for command-line editing"));
639 * Prints information about the current SSL connection, if SSL is in use
648 ssl = PQgetssl(pset.db);
652 SSL_get_cipher_bits(ssl, &sslbits);
653 printf(gettext("SSL connection (cipher: %s, bits: %i)\n\n"),
654 SSL_get_cipher(ssl), sslbits);
663 * Prints a warning when win32 console codepage differs from Windows codepage
667 checkWin32Codepage(void)
673 concp = GetConsoleCP();
676 printf("Warning: Console codepage (%u) differs from windows codepage (%u)\n"
677 " 8-bit characters will not work correctly. See PostgreSQL\n"
678 " documentation \"Installation on Windows\" for details.\n\n",