2
* psql - the PostgreSQL interactive terminal
4
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
6
* $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.112 2005-01-17 10:00:05 petere Exp $
8
#include "postgres_fe.h"
10
#include <sys/types.h>
19
#include "getopt_long.h"
21
#ifndef HAVE_INT_OPTRESET
37
#include "variables.h"
39
#include "mb/pg_wchar.h"
47
#define SYSPSQLRC "psqlrc"
48
#define PSQLRC ".psqlrc"
50
#define SYSPSQLRC "psqlrc"
51
#define PSQLRC "psqlrc.conf"
55
* Structures to pass information between the option parsing routine
56
* and the main function
79
static void parse_psql_options(int argc, char *argv[],
80
struct adhoc_opts * options);
81
static void process_psqlrc(char *argv0);
82
static void process_psqlrc_file(char *filename);
83
static void showVersion(void);
86
static void printSSLInfo(void);
91
checkWin32Codepage(void);
100
main(int argc, char *argv[])
102
struct adhoc_opts options;
105
char *username = NULL;
106
char *password = NULL;
109
set_pglocale_pgservice(argv[0], "psql");
111
pset.progname = get_progname(argv[0]);
115
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
120
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
128
setvbuf(stderr, NULL, _IONBF, 0);
131
pset.cur_cmd_source = stdin;
132
pset.cur_cmd_interactive = false;
133
pset.encoding = PQenv2encoding();
135
pset.vars = CreateVariableSpace();
138
fprintf(stderr, gettext("%s: out of memory\n"), pset.progname);
141
pset.popt.topt.format = PRINT_ALIGNED;
142
pset.queryFout = stdout;
143
pset.popt.topt.border = 1;
144
pset.popt.topt.pager = 1;
145
pset.popt.default_footer = true;
147
SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
149
/* Default values for variables */
150
SetVariableBool(pset.vars, "AUTOCOMMIT");
151
SetVariable(pset.vars, "VERBOSITY", "default");
152
SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
153
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
154
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
156
pset.verbosity = PQERRORS_DEFAULT;
158
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
160
/* This is obsolete and should be removed sometime. */
161
#ifdef PSQL_ALWAYS_GET_PASSWORDS
162
pset.getPassword = true;
164
pset.getPassword = false;
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)
576
char home[MAXPGPATH];
577
char rc_file[MAXPGPATH];
578
char my_exec_path[MAXPGPATH];
579
char etc_path[MAXPGPATH];
581
find_my_exec(argv0, my_exec_path);
582
get_etc_path(my_exec_path, etc_path);
584
snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
585
process_psqlrc_file(rc_file);
587
if (get_home_path(home))
589
snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
590
process_psqlrc_file(rc_file);
597
process_psqlrc_file(char *filename)
601
#if defined(WIN32) && (!defined(__MINGW32__))
605
psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
606
sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
608
if (access(psqlrc, R_OK) == 0)
609
process_file(psqlrc);
610
else if (access(filename, R_OK) == 0)
611
process_file(filename);
619
* This output format is intended to match GNU standards.
624
puts("psql (PostgreSQL) " PG_VERSION);
626
#if defined(USE_READLINE)
627
puts(gettext("contains support for command-line editing"));
636
* Prints information about the current SSL connection, if SSL is in use
645
ssl = PQgetssl(pset.db);
649
SSL_get_cipher_bits(ssl, &sslbits);
650
printf(gettext("SSL connection (cipher: %s, bits: %i)\n\n"),
651
SSL_get_cipher(ssl), sslbits);
660
* Prints a warning when win32 console codepage differs from Windows codepage
664
checkWin32Codepage(void)
670
concp = GetConsoleCP();
673
printf(gettext("Warning: Console code page (%u) differs from Windows code page (%u)\n"
674
" 8-bit characters may not work correctly. See psql reference\n"
675
" page \"Notes for Windows users\" for details.\n\n"),