2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2008, 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], "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 /* This is obsolete and should be removed sometime. */
144 #ifdef PSQL_ALWAYS_GET_PASSWORDS
145 pset
.getPassword
= true;
147 pset
.getPassword
= false;
150 EstablishVariableSpace();
152 SetVariable(pset
.vars
, "VERSION", PG_VERSION_STR
);
154 /* Default values for variables */
155 SetVariableBool(pset
.vars
, "AUTOCOMMIT");
156 SetVariable(pset
.vars
, "VERBOSITY", "default");
157 SetVariable(pset
.vars
, "PROMPT1", DEFAULT_PROMPT1
);
158 SetVariable(pset
.vars
, "PROMPT2", DEFAULT_PROMPT2
);
159 SetVariable(pset
.vars
, "PROMPT3", DEFAULT_PROMPT3
);
161 parse_psql_options(argc
, argv
, &options
);
163 if (!pset
.popt
.topt
.fieldSep
)
164 pset
.popt
.topt
.fieldSep
= pg_strdup(DEFAULT_FIELD_SEP
);
165 if (!pset
.popt
.topt
.recordSep
)
166 pset
.popt
.topt
.recordSep
= pg_strdup(DEFAULT_RECORD_SEP
);
168 if (options
.username
== NULL
)
169 password_prompt
= pg_strdup(_("Password: "));
172 password_prompt
= malloc(strlen(_("Password for user %s: ")) - 2 +
173 strlen(options
.username
) + 1);
174 sprintf(password_prompt
, _("Password for user %s: "),
178 if (pset
.getPassword
)
179 password
= simple_prompt(password_prompt
, 100, false);
181 /* loop until we have a password if requested by backend */
185 pset
.db
= PQsetdbLogin(options
.host
, options
.port
, NULL
, NULL
,
186 options
.action
== ACT_LIST_DB
&& options
.dbname
== NULL
?
187 "postgres" : options
.dbname
,
188 options
.username
, password
);
190 if (PQstatus(pset
.db
) == CONNECTION_BAD
&&
191 PQconnectionNeedsPassword(pset
.db
) &&
196 password
= simple_prompt(password_prompt
, 100, false);
202 free(password_prompt
);
204 if (PQstatus(pset
.db
) == CONNECTION_BAD
)
206 fprintf(stderr
, "%s: %s", pset
.progname
, PQerrorMessage(pset
.db
));
211 PQsetNoticeProcessor(pset
.db
, NoticeProcessor
, NULL
);
215 if (options
.action
== ACT_LIST_DB
)
217 int success
= listAllDbs(false);
220 exit(success
? EXIT_SUCCESS
: EXIT_FAILURE
);
223 if (options
.logfilename
)
225 pset
.logfile
= fopen(options
.logfilename
, "a");
227 fprintf(stderr
, _("%s: could not open log file \"%s\": %s\n"),
228 pset
.progname
, options
.logfilename
, strerror(errno
));
232 * Now find something to do
236 * process file given by -f
238 if (options
.action
== ACT_FILE
&& strcmp(options
.action_string
, "-") != 0)
240 if (!options
.no_psqlrc
)
241 process_psqlrc(argv
[0]);
243 successResult
= process_file(options
.action_string
, options
.single_txn
);
247 * process slash command if one was given to -c
249 else if (options
.action
== ACT_SINGLE_SLASH
)
251 PsqlScanState scan_state
;
253 if (pset
.echo
== PSQL_ECHO_ALL
)
254 puts(options
.action_string
);
256 scan_state
= psql_scan_create();
257 psql_scan_setup(scan_state
,
258 options
.action_string
,
259 strlen(options
.action_string
));
261 successResult
= HandleSlashCmds(scan_state
, NULL
) != PSQL_CMD_ERROR
262 ? EXIT_SUCCESS
: EXIT_FAILURE
;
264 psql_scan_destroy(scan_state
);
268 * If the query given to -c was a normal one, send it
270 else if (options
.action
== ACT_SINGLE_QUERY
)
272 if (pset
.echo
== PSQL_ECHO_ALL
)
273 puts(options
.action_string
);
275 successResult
= SendQuery(options
.action_string
)
276 ? EXIT_SUCCESS
: EXIT_FAILURE
;
280 * or otherwise enter interactive main loop
284 if (!options
.no_psqlrc
)
285 process_psqlrc(argv
[0]);
287 connection_warnings();
288 if (!pset
.quiet
&& !pset
.notty
)
289 printf(_("Type \"help\" for help.\n\n"));
291 initializeInput(options
.no_readline
? 0 : 1);
292 if (options
.action_string
) /* -f - was used */
293 pset
.inputfile
= "<stdin>";
295 successResult
= MainLoop(stdin
);
300 fclose(pset
.logfile
);
304 return successResult
;
309 * Parse command line options
313 parse_psql_options(int argc
, char *argv
[], struct adhoc_opts
* options
)
315 static struct option long_options
[] =
317 {"echo-all", no_argument
, NULL
, 'a'},
318 {"no-align", no_argument
, NULL
, 'A'},
319 {"command", required_argument
, NULL
, 'c'},
320 {"dbname", required_argument
, NULL
, 'd'},
321 {"echo-queries", no_argument
, NULL
, 'e'},
322 {"echo-hidden", no_argument
, NULL
, 'E'},
323 {"file", required_argument
, NULL
, 'f'},
324 {"field-separator", required_argument
, NULL
, 'F'},
325 {"host", required_argument
, NULL
, 'h'},
326 {"html", no_argument
, NULL
, 'H'},
327 {"list", no_argument
, NULL
, 'l'},
328 {"log-file", required_argument
, NULL
, 'L'},
329 {"no-readline", no_argument
, NULL
, 'n'},
330 {"single-transaction", no_argument
, NULL
, '1'},
331 {"output", required_argument
, NULL
, 'o'},
332 {"port", required_argument
, NULL
, 'p'},
333 {"pset", required_argument
, NULL
, 'P'},
334 {"quiet", no_argument
, NULL
, 'q'},
335 {"record-separator", required_argument
, NULL
, 'R'},
336 {"single-step", no_argument
, NULL
, 's'},
337 {"single-line", no_argument
, NULL
, 'S'},
338 {"tuples-only", no_argument
, NULL
, 't'},
339 {"table-attr", required_argument
, NULL
, 'T'},
340 {"username", required_argument
, NULL
, 'U'},
341 {"set", required_argument
, NULL
, 'v'},
342 {"variable", required_argument
, NULL
, 'v'},
343 {"version", no_argument
, NULL
, 'V'},
344 {"password", no_argument
, NULL
, 'W'},
345 {"expanded", no_argument
, NULL
, 'x'},
346 {"no-psqlrc", no_argument
, NULL
, 'X'},
347 {"help", no_argument
, NULL
, '?'},
356 memset(options
, 0, sizeof *options
);
358 while ((c
= getopt_long(argc
, argv
, "aAc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VWxX?1",
359 long_options
, &optindex
)) != -1)
364 SetVariable(pset
.vars
, "ECHO", "all");
367 pset
.popt
.topt
.format
= PRINT_UNALIGNED
;
370 options
->action_string
= optarg
;
371 if (optarg
[0] == '\\')
373 options
->action
= ACT_SINGLE_SLASH
;
374 options
->action_string
++;
377 options
->action
= ACT_SINGLE_QUERY
;
380 options
->dbname
= optarg
;
383 SetVariable(pset
.vars
, "ECHO", "queries");
386 SetVariableBool(pset
.vars
, "ECHO_HIDDEN");
389 options
->action
= ACT_FILE
;
390 options
->action_string
= optarg
;
393 pset
.popt
.topt
.fieldSep
= pg_strdup(optarg
);
396 options
->host
= optarg
;
399 pset
.popt
.topt
.format
= PRINT_HTML
;
402 options
->action
= ACT_LIST_DB
;
405 options
->logfilename
= optarg
;
408 options
->no_readline
= true;
414 options
->port
= optarg
;
422 value
= pg_strdup(optarg
);
423 equal_loc
= strchr(value
, '=');
425 result
= do_pset(value
, NULL
, &pset
.popt
, true);
429 result
= do_pset(value
, equal_loc
+ 1, &pset
.popt
, true);
434 fprintf(stderr
, _("%s: could not set printing parameter \"%s\"\n"), pset
.progname
, value
);
442 SetVariableBool(pset
.vars
, "QUIET");
445 pset
.popt
.topt
.recordSep
= pg_strdup(optarg
);
448 SetVariableBool(pset
.vars
, "SINGLESTEP");
451 SetVariableBool(pset
.vars
, "SINGLELINE");
454 pset
.popt
.topt
.tuples_only
= true;
457 pset
.popt
.topt
.tableAttr
= pg_strdup(optarg
);
460 options
->username
= optarg
;
467 value
= pg_strdup(optarg
);
468 equal_loc
= strchr(value
, '=');
471 if (!DeleteVariable(pset
.vars
, value
))
473 fprintf(stderr
, _("%s: could not delete variable \"%s\"\n"),
474 pset
.progname
, value
);
481 if (!SetVariable(pset
.vars
, value
, equal_loc
+ 1))
483 fprintf(stderr
, _("%s: could not set variable \"%s\"\n"),
484 pset
.progname
, value
);
496 pset
.getPassword
= true;
499 pset
.popt
.topt
.expanded
= true;
502 options
->no_psqlrc
= true;
505 options
->single_txn
= true;
508 /* Actual help option given */
509 if (strcmp(argv
[optind
- 1], "-?") == 0 || strcmp(argv
[optind
- 1], "--help") == 0)
514 /* unknown option reported by getopt */
517 fprintf(stderr
, _("Try \"%s --help\" for more information.\n"),
523 fprintf(stderr
, _("Try \"%s --help\" for more information.\n"),
531 * if we still have arguments, use it as the database name and username
533 while (argc
- optind
>= 1)
535 if (!options
->dbname
)
536 options
->dbname
= argv
[optind
];
537 else if (!options
->username
)
538 options
->username
= argv
[optind
];
539 else if (!pset
.quiet
)
540 fprintf(stderr
, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
541 pset
.progname
, argv
[optind
]);
549 * Load .psqlrc file, if found.
552 process_psqlrc(char *argv0
)
554 char home
[MAXPGPATH
];
555 char rc_file
[MAXPGPATH
];
556 char my_exec_path
[MAXPGPATH
];
557 char etc_path
[MAXPGPATH
];
559 find_my_exec(argv0
, my_exec_path
);
560 get_etc_path(my_exec_path
, etc_path
);
562 snprintf(rc_file
, MAXPGPATH
, "%s/%s", etc_path
, SYSPSQLRC
);
563 process_psqlrc_file(rc_file
);
565 if (get_home_path(home
))
567 snprintf(rc_file
, MAXPGPATH
, "%s/%s", home
, PSQLRC
);
568 process_psqlrc_file(rc_file
);
575 process_psqlrc_file(char *filename
)
579 #if defined(WIN32) && (!defined(__MINGW32__))
583 psqlrc
= pg_malloc(strlen(filename
) + 1 + strlen(PG_VERSION
) + 1);
584 sprintf(psqlrc
, "%s-%s", filename
, PG_VERSION
);
586 if (access(psqlrc
, R_OK
) == 0)
587 (void) process_file(psqlrc
, false);
588 else if (access(filename
, R_OK
) == 0)
589 (void) process_file(filename
, false);
597 * This output format is intended to match GNU standards.
602 puts("psql (PostgreSQL) " PG_VERSION
);
604 #if defined(USE_READLINE)
605 puts(_("contains support for command-line editing"));
612 * Assign hooks for psql variables.
614 * This isn't an amazingly good place for them, but neither is anywhere else.
618 autocommit_hook(const char *newval
)
620 pset
.autocommit
= ParseVariableBool(newval
);
624 on_error_stop_hook(const char *newval
)
626 pset
.on_error_stop
= ParseVariableBool(newval
);
630 quiet_hook(const char *newval
)
632 pset
.quiet
= ParseVariableBool(newval
);
636 singleline_hook(const char *newval
)
638 pset
.singleline
= ParseVariableBool(newval
);
642 singlestep_hook(const char *newval
)
644 pset
.singlestep
= ParseVariableBool(newval
);
648 fetch_count_hook(const char *newval
)
650 pset
.fetch_count
= ParseVariableNum(newval
, -1, -1, false);
654 echo_hook(const char *newval
)
657 pset
.echo
= PSQL_ECHO_NONE
;
658 else if (strcmp(newval
, "queries") == 0)
659 pset
.echo
= PSQL_ECHO_QUERIES
;
660 else if (strcmp(newval
, "all") == 0)
661 pset
.echo
= PSQL_ECHO_ALL
;
663 pset
.echo
= PSQL_ECHO_NONE
;
667 echo_hidden_hook(const char *newval
)
670 pset
.echo_hidden
= PSQL_ECHO_HIDDEN_OFF
;
671 else if (strcmp(newval
, "noexec") == 0)
672 pset
.echo_hidden
= PSQL_ECHO_HIDDEN_NOEXEC
;
673 else if (pg_strcasecmp(newval
, "off") == 0)
674 pset
.echo_hidden
= PSQL_ECHO_HIDDEN_OFF
;
676 pset
.echo_hidden
= PSQL_ECHO_HIDDEN_ON
;
680 on_error_rollback_hook(const char *newval
)
683 pset
.on_error_rollback
= PSQL_ERROR_ROLLBACK_OFF
;
684 else if (pg_strcasecmp(newval
, "interactive") == 0)
685 pset
.on_error_rollback
= PSQL_ERROR_ROLLBACK_INTERACTIVE
;
686 else if (pg_strcasecmp(newval
, "off") == 0)
687 pset
.on_error_rollback
= PSQL_ERROR_ROLLBACK_OFF
;
689 pset
.on_error_rollback
= PSQL_ERROR_ROLLBACK_ON
;
693 histcontrol_hook(const char *newval
)
696 pset
.histcontrol
= hctl_none
;
697 else if (strcmp(newval
, "ignorespace") == 0)
698 pset
.histcontrol
= hctl_ignorespace
;
699 else if (strcmp(newval
, "ignoredups") == 0)
700 pset
.histcontrol
= hctl_ignoredups
;
701 else if (strcmp(newval
, "ignoreboth") == 0)
702 pset
.histcontrol
= hctl_ignoreboth
;
704 pset
.histcontrol
= hctl_none
;
708 prompt1_hook(const char *newval
)
710 pset
.prompt1
= newval
? newval
: "";
714 prompt2_hook(const char *newval
)
716 pset
.prompt2
= newval
? newval
: "";
720 prompt3_hook(const char *newval
)
722 pset
.prompt3
= newval
? newval
: "";
726 verbosity_hook(const char *newval
)
729 pset
.verbosity
= PQERRORS_DEFAULT
;
730 else if (strcmp(newval
, "default") == 0)
731 pset
.verbosity
= PQERRORS_DEFAULT
;
732 else if (strcmp(newval
, "terse") == 0)
733 pset
.verbosity
= PQERRORS_TERSE
;
734 else if (strcmp(newval
, "verbose") == 0)
735 pset
.verbosity
= PQERRORS_VERBOSE
;
737 pset
.verbosity
= PQERRORS_DEFAULT
;
740 PQsetErrorVerbosity(pset
.db
, pset
.verbosity
);
745 EstablishVariableSpace(void)
747 pset
.vars
= CreateVariableSpace();
749 SetVariableAssignHook(pset
.vars
, "AUTOCOMMIT", autocommit_hook
);
750 SetVariableAssignHook(pset
.vars
, "ON_ERROR_STOP", on_error_stop_hook
);
751 SetVariableAssignHook(pset
.vars
, "QUIET", quiet_hook
);
752 SetVariableAssignHook(pset
.vars
, "SINGLELINE", singleline_hook
);
753 SetVariableAssignHook(pset
.vars
, "SINGLESTEP", singlestep_hook
);
754 SetVariableAssignHook(pset
.vars
, "FETCH_COUNT", fetch_count_hook
);
755 SetVariableAssignHook(pset
.vars
, "ECHO", echo_hook
);
756 SetVariableAssignHook(pset
.vars
, "ECHO_HIDDEN", echo_hidden_hook
);
757 SetVariableAssignHook(pset
.vars
, "ON_ERROR_ROLLBACK", on_error_rollback_hook
);
758 SetVariableAssignHook(pset
.vars
, "HISTCONTROL", histcontrol_hook
);
759 SetVariableAssignHook(pset
.vars
, "PROMPT1", prompt1_hook
);
760 SetVariableAssignHook(pset
.vars
, "PROMPT2", prompt2_hook
);
761 SetVariableAssignHook(pset
.vars
, "PROMPT3", prompt3_hook
);
762 SetVariableAssignHook(pset
.vars
, "VERBOSITY", verbosity_hook
);