2
* psql - the PostgreSQL interactive terminal
4
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
8
#include "postgres_fe.h"
10
#include <sys/types.h>
19
#include "getopt_long.h"
21
#ifndef HAVE_INT_OPTRESET
44
#define SYSPSQLRC "psqlrc"
45
#define PSQLRC ".psqlrc"
47
#define SYSPSQLRC "psqlrc"
48
#define PSQLRC "psqlrc.conf"
52
* Structures to pass information between the option parsing routine
53
* and the main function
78
static void parse_psql_options(int argc, char *argv[],
79
struct adhoc_opts * options);
80
static void process_psqlrc(char *argv0);
81
static void process_psqlrc_file(char *filename);
82
static void showVersion(void);
83
static void EstablishVariableSpace(void);
91
main(int argc, char *argv[])
93
struct adhoc_opts options;
95
char *password = NULL;
96
char *password_prompt = NULL;
99
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
103
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
108
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
116
setvbuf(stderr, NULL, _IONBF, 0);
119
setup_cancel_handler();
121
pset.progname = get_progname(argv[0]);
125
pset.encoding = PQenv2encoding();
126
pset.queryFout = stdout;
127
pset.queryFoutPipe = false;
128
pset.cur_cmd_source = stdin;
129
pset.cur_cmd_interactive = false;
131
/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
132
pset.popt.topt.format = PRINT_ALIGNED;
133
pset.popt.topt.border = 1;
134
pset.popt.topt.pager = 1;
135
pset.popt.topt.start_table = true;
136
pset.popt.topt.stop_table = true;
137
pset.popt.default_footer = true;
138
/* We must get COLUMNS here before readline() sets it */
139
pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
141
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
143
pset.getPassword = TRI_DEFAULT;
145
EstablishVariableSpace();
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
parse_psql_options(argc, argv, &options);
158
if (!pset.popt.topt.fieldSep)
159
pset.popt.topt.fieldSep = pg_strdup(DEFAULT_FIELD_SEP);
160
if (!pset.popt.topt.recordSep)
161
pset.popt.topt.recordSep = pg_strdup(DEFAULT_RECORD_SEP);
163
if (options.username == NULL)
164
password_prompt = pg_strdup(_("Password: "));
167
password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
168
strlen(options.username) + 1);
169
sprintf(password_prompt, _("Password for user %s: "),
173
if (pset.getPassword == TRI_YES)
174
password = simple_prompt(password_prompt, 100, false);
176
/* loop until we have a password if requested by backend */
180
pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
181
options.action == ACT_LIST_DB && options.dbname == NULL ?
182
"postgres" : options.dbname,
183
options.username, password);
185
if (PQstatus(pset.db) == CONNECTION_BAD &&
186
PQconnectionNeedsPassword(pset.db) &&
188
pset.getPassword != TRI_NO)
191
password = simple_prompt(password_prompt, 100, false);
197
free(password_prompt);
199
if (PQstatus(pset.db) == CONNECTION_BAD)
201
fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
206
PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
210
if (options.action == ACT_LIST_DB)
212
int success = listAllDbs(false);
215
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
218
if (options.logfilename)
220
pset.logfile = fopen(options.logfilename, "a");
222
fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
223
pset.progname, options.logfilename, strerror(errno));
227
* Now find something to do
231
* process file given by -f
233
if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
235
if (!options.no_psqlrc)
236
process_psqlrc(argv[0]);
238
successResult = process_file(options.action_string, options.single_txn);
242
* process slash command if one was given to -c
244
else if (options.action == ACT_SINGLE_SLASH)
246
PsqlScanState scan_state;
248
if (pset.echo == PSQL_ECHO_ALL)
249
puts(options.action_string);
251
scan_state = psql_scan_create();
252
psql_scan_setup(scan_state,
253
options.action_string,
254
strlen(options.action_string));
256
successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
257
? EXIT_SUCCESS : EXIT_FAILURE;
259
psql_scan_destroy(scan_state);
263
* If the query given to -c was a normal one, send it
265
else if (options.action == ACT_SINGLE_QUERY)
267
if (pset.echo == PSQL_ECHO_ALL)
268
puts(options.action_string);
270
successResult = SendQuery(options.action_string)
271
? EXIT_SUCCESS : EXIT_FAILURE;
275
* or otherwise enter interactive main loop
279
if (!options.no_psqlrc)
280
process_psqlrc(argv[0]);
282
connection_warnings();
283
if (!pset.quiet && !pset.notty)
284
printf(_("Type \"help\" for help.\n\n"));
286
initializeInput(options.no_readline ? 0 : 1);
287
if (options.action_string) /* -f - was used */
288
pset.inputfile = "<stdin>";
290
successResult = MainLoop(stdin);
295
fclose(pset.logfile);
299
return successResult;
304
* Parse command line options
308
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
310
static struct option long_options[] =
312
{"echo-all", no_argument, NULL, 'a'},
313
{"no-align", no_argument, NULL, 'A'},
314
{"command", required_argument, NULL, 'c'},
315
{"dbname", required_argument, NULL, 'd'},
316
{"echo-queries", no_argument, NULL, 'e'},
317
{"echo-hidden", no_argument, NULL, 'E'},
318
{"file", required_argument, NULL, 'f'},
319
{"field-separator", required_argument, NULL, 'F'},
320
{"host", required_argument, NULL, 'h'},
321
{"html", no_argument, NULL, 'H'},
322
{"list", no_argument, NULL, 'l'},
323
{"log-file", required_argument, NULL, 'L'},
324
{"no-readline", no_argument, NULL, 'n'},
325
{"single-transaction", no_argument, NULL, '1'},
326
{"output", required_argument, NULL, 'o'},
327
{"port", required_argument, NULL, 'p'},
328
{"pset", required_argument, NULL, 'P'},
329
{"quiet", no_argument, NULL, 'q'},
330
{"record-separator", required_argument, NULL, 'R'},
331
{"single-step", no_argument, NULL, 's'},
332
{"single-line", no_argument, NULL, 'S'},
333
{"tuples-only", no_argument, NULL, 't'},
334
{"table-attr", required_argument, NULL, 'T'},
335
{"username", required_argument, NULL, 'U'},
336
{"set", required_argument, NULL, 'v'},
337
{"variable", required_argument, NULL, 'v'},
338
{"version", no_argument, NULL, 'V'},
339
{"no-password", no_argument, NULL, 'w'},
340
{"password", no_argument, NULL, 'W'},
341
{"expanded", no_argument, NULL, 'x'},
342
{"no-psqlrc", no_argument, NULL, 'X'},
343
{"help", no_argument, NULL, '?'},
352
memset(options, 0, sizeof *options);
354
while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxX?1",
355
long_options, &optindex)) != -1)
360
SetVariable(pset.vars, "ECHO", "all");
363
pset.popt.topt.format = PRINT_UNALIGNED;
366
options->action_string = optarg;
367
if (optarg[0] == '\\')
369
options->action = ACT_SINGLE_SLASH;
370
options->action_string++;
373
options->action = ACT_SINGLE_QUERY;
376
options->dbname = optarg;
379
SetVariable(pset.vars, "ECHO", "queries");
382
SetVariableBool(pset.vars, "ECHO_HIDDEN");
385
options->action = ACT_FILE;
386
options->action_string = optarg;
389
pset.popt.topt.fieldSep = pg_strdup(optarg);
392
options->host = optarg;
395
pset.popt.topt.format = PRINT_HTML;
398
options->action = ACT_LIST_DB;
401
options->logfilename = optarg;
404
options->no_readline = true;
410
options->port = optarg;
418
value = pg_strdup(optarg);
419
equal_loc = strchr(value, '=');
421
result = do_pset(value, NULL, &pset.popt, true);
425
result = do_pset(value, equal_loc + 1, &pset.popt, true);
430
fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
438
SetVariableBool(pset.vars, "QUIET");
441
pset.popt.topt.recordSep = pg_strdup(optarg);
444
SetVariableBool(pset.vars, "SINGLESTEP");
447
SetVariableBool(pset.vars, "SINGLELINE");
450
pset.popt.topt.tuples_only = true;
453
pset.popt.topt.tableAttr = pg_strdup(optarg);
456
options->username = optarg;
463
value = pg_strdup(optarg);
464
equal_loc = strchr(value, '=');
467
if (!DeleteVariable(pset.vars, value))
469
fprintf(stderr, _("%s: could not delete variable \"%s\"\n"),
470
pset.progname, value);
477
if (!SetVariable(pset.vars, value, equal_loc + 1))
479
fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
480
pset.progname, value);
492
pset.getPassword = TRI_NO;
495
pset.getPassword = TRI_YES;
498
pset.popt.topt.expanded = true;
501
options->no_psqlrc = true;
504
options->single_txn = true;
507
/* Actual help option given */
508
if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
513
/* unknown option reported by getopt */
516
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
522
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
530
* if we still have arguments, use it as the database name and username
532
while (argc - optind >= 1)
534
if (!options->dbname)
535
options->dbname = argv[optind];
536
else if (!options->username)
537
options->username = argv[optind];
538
else if (!pset.quiet)
539
fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
540
pset.progname, argv[optind]);
548
* Load .psqlrc file, if found.
551
process_psqlrc(char *argv0)
553
char home[MAXPGPATH];
554
char rc_file[MAXPGPATH];
555
char my_exec_path[MAXPGPATH];
556
char etc_path[MAXPGPATH];
558
find_my_exec(argv0, my_exec_path);
559
get_etc_path(my_exec_path, etc_path);
561
snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
562
process_psqlrc_file(rc_file);
564
if (get_home_path(home))
566
snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
567
process_psqlrc_file(rc_file);
574
process_psqlrc_file(char *filename)
578
#if defined(WIN32) && (!defined(__MINGW32__))
582
psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
583
sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
585
if (access(psqlrc, R_OK) == 0)
586
(void) process_file(psqlrc, false);
587
else if (access(filename, R_OK) == 0)
588
(void) process_file(filename, false);
596
* This output format is intended to match GNU standards.
601
puts("psql (PostgreSQL) " PG_VERSION);
603
#if defined(USE_READLINE)
604
puts(_("contains support for command-line editing"));
611
* Assign hooks for psql variables.
613
* This isn't an amazingly good place for them, but neither is anywhere else.
617
autocommit_hook(const char *newval)
619
pset.autocommit = ParseVariableBool(newval);
623
on_error_stop_hook(const char *newval)
625
pset.on_error_stop = ParseVariableBool(newval);
629
quiet_hook(const char *newval)
631
pset.quiet = ParseVariableBool(newval);
635
singleline_hook(const char *newval)
637
pset.singleline = ParseVariableBool(newval);
641
singlestep_hook(const char *newval)
643
pset.singlestep = ParseVariableBool(newval);
647
fetch_count_hook(const char *newval)
649
pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
653
echo_hook(const char *newval)
656
pset.echo = PSQL_ECHO_NONE;
657
else if (strcmp(newval, "queries") == 0)
658
pset.echo = PSQL_ECHO_QUERIES;
659
else if (strcmp(newval, "all") == 0)
660
pset.echo = PSQL_ECHO_ALL;
662
pset.echo = PSQL_ECHO_NONE;
666
echo_hidden_hook(const char *newval)
669
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
670
else if (strcmp(newval, "noexec") == 0)
671
pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
672
else if (pg_strcasecmp(newval, "off") == 0)
673
pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
675
pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
679
on_error_rollback_hook(const char *newval)
682
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
683
else if (pg_strcasecmp(newval, "interactive") == 0)
684
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
685
else if (pg_strcasecmp(newval, "off") == 0)
686
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
688
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
692
histcontrol_hook(const char *newval)
695
pset.histcontrol = hctl_none;
696
else if (strcmp(newval, "ignorespace") == 0)
697
pset.histcontrol = hctl_ignorespace;
698
else if (strcmp(newval, "ignoredups") == 0)
699
pset.histcontrol = hctl_ignoredups;
700
else if (strcmp(newval, "ignoreboth") == 0)
701
pset.histcontrol = hctl_ignoreboth;
703
pset.histcontrol = hctl_none;
707
prompt1_hook(const char *newval)
709
pset.prompt1 = newval ? newval : "";
713
prompt2_hook(const char *newval)
715
pset.prompt2 = newval ? newval : "";
719
prompt3_hook(const char *newval)
721
pset.prompt3 = newval ? newval : "";
725
verbosity_hook(const char *newval)
728
pset.verbosity = PQERRORS_DEFAULT;
729
else if (strcmp(newval, "default") == 0)
730
pset.verbosity = PQERRORS_DEFAULT;
731
else if (strcmp(newval, "terse") == 0)
732
pset.verbosity = PQERRORS_TERSE;
733
else if (strcmp(newval, "verbose") == 0)
734
pset.verbosity = PQERRORS_VERBOSE;
736
pset.verbosity = PQERRORS_DEFAULT;
739
PQsetErrorVerbosity(pset.db, pset.verbosity);
744
EstablishVariableSpace(void)
746
pset.vars = CreateVariableSpace();
748
SetVariableAssignHook(pset.vars, "AUTOCOMMIT", autocommit_hook);
749
SetVariableAssignHook(pset.vars, "ON_ERROR_STOP", on_error_stop_hook);
750
SetVariableAssignHook(pset.vars, "QUIET", quiet_hook);
751
SetVariableAssignHook(pset.vars, "SINGLELINE", singleline_hook);
752
SetVariableAssignHook(pset.vars, "SINGLESTEP", singlestep_hook);
753
SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
754
SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
755
SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
756
SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
757
SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
758
SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
759
SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);
760
SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook);
761
SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook);