]> granicus.if.org Git - postgresql/blob - src/bin/psql/startup.c
Add new ECHO mode 'errors' that displays only failed commands in psql.
[postgresql] / src / bin / psql / startup.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2014, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/startup.c
7  */
8 #include "postgres_fe.h"
9
10 #include <sys/types.h>
11
12 #ifndef WIN32
13 #include <unistd.h>
14 #else                                                   /* WIN32 */
15 #include <io.h>
16 #include <win32.h>
17 #endif   /* WIN32 */
18
19 #include "getopt_long.h"
20
21 #include <locale.h>
22
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"
30
31
32
33 /*
34  * Global psql options
35  */
36 PsqlSettings pset;
37
38 #ifndef WIN32
39 #define SYSPSQLRC       "psqlrc"
40 #define PSQLRC          ".psqlrc"
41 #else
42 #define SYSPSQLRC       "psqlrc"
43 #define PSQLRC          "psqlrc.conf"
44 #endif
45
46 /*
47  * Structures to pass information between the option parsing routine
48  * and the main function
49  */
50 enum _actions
51 {
52         ACT_NOTHING = 0,
53         ACT_SINGLE_SLASH,
54         ACT_LIST_DB,
55         ACT_SINGLE_QUERY,
56         ACT_FILE
57 };
58
59 struct adhoc_opts
60 {
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;
71 };
72
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);
79
80 /*
81  *
82  * main
83  *
84  */
85 int
86 main(int argc, char *argv[])
87 {
88         struct adhoc_opts options;
89         int                     successResult;
90         char       *password = NULL;
91         char       *password_prompt = NULL;
92         bool            new_pass;
93
94         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
95
96         if (argc > 1)
97         {
98                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
99                 {
100                         usage();
101                         exit(EXIT_SUCCESS);
102                 }
103                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
104                 {
105                         showVersion();
106                         exit(EXIT_SUCCESS);
107                 }
108         }
109
110 #ifdef WIN32
111         setvbuf(stderr, NULL, _IONBF, 0);
112 #endif
113
114         pset.progname = get_progname(argv[0]);
115
116         pset.db = NULL;
117         setDecimalLocale();
118         pset.encoding = PQenv2encoding();
119         pset.queryFout = stdout;
120         pset.queryFoutPipe = false;
121         pset.copyStream = NULL;
122         pset.cur_cmd_source = stdin;
123         pset.cur_cmd_interactive = false;
124
125         /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
126         pset.popt.topt.format = PRINT_ALIGNED;
127         pset.popt.topt.border = 1;
128         pset.popt.topt.pager = 1;
129         pset.popt.topt.start_table = true;
130         pset.popt.topt.stop_table = true;
131         pset.popt.topt.default_footer = true;
132         /* We must get COLUMNS here before readline() sets it */
133         pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
134
135         pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
136
137         pset.getPassword = TRI_DEFAULT;
138
139         EstablishVariableSpace();
140
141         SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
142
143         /* Default values for variables */
144         SetVariableBool(pset.vars, "AUTOCOMMIT");
145         SetVariable(pset.vars, "VERBOSITY", "default");
146         SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
147         SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
148         SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
149
150         parse_psql_options(argc, argv, &options);
151
152         /*
153          * If no action was specified and we're in non-interactive mode, treat it
154          * as if the user had specified "-f -".  This lets single-transaction mode
155          * work in this case.
156          */
157         if (options.action == ACT_NOTHING && pset.notty)
158         {
159                 options.action = ACT_FILE;
160                 options.action_string = NULL;
161         }
162
163         /* Bail out if -1 was specified but will be ignored. */
164         if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
165         {
166                 fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
167                 exit(EXIT_FAILURE);
168         }
169
170         if (!pset.popt.topt.fieldSep.separator &&
171                 !pset.popt.topt.fieldSep.separator_zero)
172         {
173                 pset.popt.topt.fieldSep.separator = pg_strdup(DEFAULT_FIELD_SEP);
174                 pset.popt.topt.fieldSep.separator_zero = false;
175         }
176         if (!pset.popt.topt.recordSep.separator &&
177                 !pset.popt.topt.recordSep.separator_zero)
178         {
179                 pset.popt.topt.recordSep.separator = pg_strdup(DEFAULT_RECORD_SEP);
180                 pset.popt.topt.recordSep.separator_zero = false;
181         }
182
183         if (options.username == NULL)
184                 password_prompt = pg_strdup(_("Password: "));
185         else
186                 password_prompt = psprintf(_("Password for user %s: "),
187                                                                    options.username);
188
189         if (pset.getPassword == TRI_YES)
190                 password = simple_prompt(password_prompt, 100, false);
191
192         /* loop until we have a password if requested by backend */
193         do
194         {
195 #define PARAMS_ARRAY_SIZE       8
196                 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
197                 const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
198
199                 keywords[0] = "host";
200                 values[0] = options.host;
201                 keywords[1] = "port";
202                 values[1] = options.port;
203                 keywords[2] = "user";
204                 values[2] = options.username;
205                 keywords[3] = "password";
206                 values[3] = password;
207                 keywords[4] = "dbname";
208                 values[4] = (options.action == ACT_LIST_DB &&
209                                          options.dbname == NULL) ?
210                         "postgres" : options.dbname;
211                 keywords[5] = "fallback_application_name";
212                 values[5] = pset.progname;
213                 keywords[6] = "client_encoding";
214                 values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
215                 keywords[7] = NULL;
216                 values[7] = NULL;
217
218                 new_pass = false;
219                 pset.db = PQconnectdbParams(keywords, values, true);
220                 free(keywords);
221                 free(values);
222
223                 if (PQstatus(pset.db) == CONNECTION_BAD &&
224                         PQconnectionNeedsPassword(pset.db) &&
225                         password == NULL &&
226                         pset.getPassword != TRI_NO)
227                 {
228                         PQfinish(pset.db);
229                         password = simple_prompt(password_prompt, 100, false);
230                         new_pass = true;
231                 }
232         } while (new_pass);
233
234         free(password);
235         free(password_prompt);
236
237         if (PQstatus(pset.db) == CONNECTION_BAD)
238         {
239                 fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
240                 PQfinish(pset.db);
241                 exit(EXIT_BADCONN);
242         }
243
244         setup_cancel_handler();
245
246         PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
247
248         SyncVariables();
249
250         if (options.action == ACT_LIST_DB)
251         {
252                 int                     success;
253
254                 if (!options.no_psqlrc)
255                         process_psqlrc(argv[0]);
256
257                 success = listAllDbs(NULL, false);
258                 PQfinish(pset.db);
259                 exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
260         }
261
262         if (options.logfilename)
263         {
264                 pset.logfile = fopen(options.logfilename, "a");
265                 if (!pset.logfile)
266                         fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
267                                         pset.progname, options.logfilename, strerror(errno));
268         }
269
270         /*
271          * Now find something to do
272          */
273
274         /*
275          * process file given by -f
276          */
277         if (options.action == ACT_FILE)
278         {
279                 if (!options.no_psqlrc)
280                         process_psqlrc(argv[0]);
281
282                 successResult = process_file(options.action_string, options.single_txn, false);
283         }
284
285         /*
286          * process slash command if one was given to -c
287          */
288         else if (options.action == ACT_SINGLE_SLASH)
289         {
290                 PsqlScanState scan_state;
291
292                 if (pset.echo == PSQL_ECHO_ALL)
293                         puts(options.action_string);
294
295                 scan_state = psql_scan_create();
296                 psql_scan_setup(scan_state,
297                                                 options.action_string,
298                                                 strlen(options.action_string));
299
300                 successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
301                         ? EXIT_SUCCESS : EXIT_FAILURE;
302
303                 psql_scan_destroy(scan_state);
304         }
305
306         /*
307          * If the query given to -c was a normal one, send it
308          */
309         else if (options.action == ACT_SINGLE_QUERY)
310         {
311                 if (pset.echo == PSQL_ECHO_ALL)
312                         puts(options.action_string);
313
314                 successResult = SendQuery(options.action_string)
315                         ? EXIT_SUCCESS : EXIT_FAILURE;
316         }
317
318         /*
319          * or otherwise enter interactive main loop
320          */
321         else
322         {
323                 if (!options.no_psqlrc)
324                         process_psqlrc(argv[0]);
325
326                 connection_warnings(true);
327                 if (!pset.quiet)
328                         printf(_("Type \"help\" for help.\n\n"));
329                 initializeInput(options.no_readline ? 0 : 1);
330                 successResult = MainLoop(stdin);
331         }
332
333         /* clean up */
334         if (pset.logfile)
335                 fclose(pset.logfile);
336         PQfinish(pset.db);
337         setQFout(NULL);
338
339         return successResult;
340 }
341
342
343 /*
344  * Parse command line options
345  */
346
347 static void
348 parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
349 {
350         static struct option long_options[] =
351         {
352                 {"echo-all", no_argument, NULL, 'a'},
353                 {"no-align", no_argument, NULL, 'A'},
354                 {"command", required_argument, NULL, 'c'},
355                 {"dbname", required_argument, NULL, 'd'},
356                 {"echo-queries", no_argument, NULL, 'e'},
357                 {"echo-errors", no_argument, NULL, 'b'},
358                 {"echo-hidden", no_argument, NULL, 'E'},
359                 {"file", required_argument, NULL, 'f'},
360                 {"field-separator", required_argument, NULL, 'F'},
361                 {"field-separator-zero", no_argument, NULL, 'z'},
362                 {"host", required_argument, NULL, 'h'},
363                 {"html", no_argument, NULL, 'H'},
364                 {"list", no_argument, NULL, 'l'},
365                 {"log-file", required_argument, NULL, 'L'},
366                 {"no-readline", no_argument, NULL, 'n'},
367                 {"single-transaction", no_argument, NULL, '1'},
368                 {"output", required_argument, NULL, 'o'},
369                 {"port", required_argument, NULL, 'p'},
370                 {"pset", required_argument, NULL, 'P'},
371                 {"quiet", no_argument, NULL, 'q'},
372                 {"record-separator", required_argument, NULL, 'R'},
373                 {"record-separator-zero", no_argument, NULL, '0'},
374                 {"single-step", no_argument, NULL, 's'},
375                 {"single-line", no_argument, NULL, 'S'},
376                 {"tuples-only", no_argument, NULL, 't'},
377                 {"table-attr", required_argument, NULL, 'T'},
378                 {"username", required_argument, NULL, 'U'},
379                 {"set", required_argument, NULL, 'v'},
380                 {"variable", required_argument, NULL, 'v'},
381                 {"version", no_argument, NULL, 'V'},
382                 {"no-password", no_argument, NULL, 'w'},
383                 {"password", no_argument, NULL, 'W'},
384                 {"expanded", no_argument, NULL, 'x'},
385                 {"no-psqlrc", no_argument, NULL, 'X'},
386                 {"help", no_argument, NULL, '?'},
387                 {NULL, 0, NULL, 0}
388         };
389
390         int                     optindex;
391         int                     c;
392
393         memset(options, 0, sizeof *options);
394
395         while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
396                                                         long_options, &optindex)) != -1)
397         {
398                 switch (c)
399                 {
400                         case 'a':
401                                 SetVariable(pset.vars, "ECHO", "all");
402                                 break;
403                         case 'A':
404                                 pset.popt.topt.format = PRINT_UNALIGNED;
405                                 break;
406                         case 'b':
407                                 SetVariable(pset.vars, "ECHO", "errors");
408                                 break;
409                         case 'c':
410                                 options->action_string = pg_strdup(optarg);
411                                 if (optarg[0] == '\\')
412                                 {
413                                         options->action = ACT_SINGLE_SLASH;
414                                         options->action_string++;
415                                 }
416                                 else
417                                         options->action = ACT_SINGLE_QUERY;
418                                 break;
419                         case 'd':
420                                 options->dbname = pg_strdup(optarg);
421                                 break;
422                         case 'e':
423                                 SetVariable(pset.vars, "ECHO", "queries");
424                                 break;
425                         case 'E':
426                                 SetVariableBool(pset.vars, "ECHO_HIDDEN");
427                                 break;
428                         case 'f':
429                                 options->action = ACT_FILE;
430                                 options->action_string = pg_strdup(optarg);
431                                 break;
432                         case 'F':
433                                 pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
434                                 pset.popt.topt.fieldSep.separator_zero = false;
435                                 break;
436                         case 'h':
437                                 options->host = pg_strdup(optarg);
438                                 break;
439                         case 'H':
440                                 pset.popt.topt.format = PRINT_HTML;
441                                 break;
442                         case 'l':
443                                 options->action = ACT_LIST_DB;
444                                 break;
445                         case 'L':
446                                 options->logfilename = pg_strdup(optarg);
447                                 break;
448                         case 'n':
449                                 options->no_readline = true;
450                                 break;
451                         case 'o':
452                                 setQFout(optarg);
453                                 break;
454                         case 'p':
455                                 options->port = pg_strdup(optarg);
456                                 break;
457                         case 'P':
458                                 {
459                                         char       *value;
460                                         char       *equal_loc;
461                                         bool            result;
462
463                                         value = pg_strdup(optarg);
464                                         equal_loc = strchr(value, '=');
465                                         if (!equal_loc)
466                                                 result = do_pset(value, NULL, &pset.popt, true);
467                                         else
468                                         {
469                                                 *equal_loc = '\0';
470                                                 result = do_pset(value, equal_loc + 1, &pset.popt, true);
471                                         }
472
473                                         if (!result)
474                                         {
475                                                 fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
476                                                 exit(EXIT_FAILURE);
477                                         }
478
479                                         free(value);
480                                         break;
481                                 }
482                         case 'q':
483                                 SetVariableBool(pset.vars, "QUIET");
484                                 break;
485                         case 'R':
486                                 pset.popt.topt.recordSep.separator = pg_strdup(optarg);
487                                 pset.popt.topt.recordSep.separator_zero = false;
488                                 break;
489                         case 's':
490                                 SetVariableBool(pset.vars, "SINGLESTEP");
491                                 break;
492                         case 'S':
493                                 SetVariableBool(pset.vars, "SINGLELINE");
494                                 break;
495                         case 't':
496                                 pset.popt.topt.tuples_only = true;
497                                 break;
498                         case 'T':
499                                 pset.popt.topt.tableAttr = pg_strdup(optarg);
500                                 break;
501                         case 'U':
502                                 options->username = pg_strdup(optarg);
503                                 break;
504                         case 'v':
505                                 {
506                                         char       *value;
507                                         char       *equal_loc;
508
509                                         value = pg_strdup(optarg);
510                                         equal_loc = strchr(value, '=');
511                                         if (!equal_loc)
512                                         {
513                                                 if (!DeleteVariable(pset.vars, value))
514                                                 {
515                                                         fprintf(stderr, _("%s: could not delete variable \"%s\"\n"),
516                                                                         pset.progname, value);
517                                                         exit(EXIT_FAILURE);
518                                                 }
519                                         }
520                                         else
521                                         {
522                                                 *equal_loc = '\0';
523                                                 if (!SetVariable(pset.vars, value, equal_loc + 1))
524                                                 {
525                                                         fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
526                                                                         pset.progname, value);
527                                                         exit(EXIT_FAILURE);
528                                                 }
529                                         }
530
531                                         free(value);
532                                         break;
533                                 }
534                         case 'V':
535                                 showVersion();
536                                 exit(EXIT_SUCCESS);
537                         case 'w':
538                                 pset.getPassword = TRI_NO;
539                                 break;
540                         case 'W':
541                                 pset.getPassword = TRI_YES;
542                                 break;
543                         case 'x':
544                                 pset.popt.topt.expanded = true;
545                                 break;
546                         case 'X':
547                                 options->no_psqlrc = true;
548                                 break;
549                         case 'z':
550                                 pset.popt.topt.fieldSep.separator_zero = true;
551                                 break;
552                         case '0':
553                                 pset.popt.topt.recordSep.separator_zero = true;
554                                 break;
555                         case '1':
556                                 options->single_txn = true;
557                                 break;
558                         case '?':
559                                 /* Actual help option given */
560                                 if (strcmp(argv[optind - 1], "--help") == 0 || strcmp(argv[optind - 1], "-?") == 0)
561                                 {
562                                         usage();
563                                         exit(EXIT_SUCCESS);
564                                 }
565                                 /* unknown option reported by getopt */
566                                 else
567                                 {
568                                         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
569                                                         pset.progname);
570                                         exit(EXIT_FAILURE);
571                                 }
572                                 break;
573                         default:
574                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
575                                                 pset.progname);
576                                 exit(EXIT_FAILURE);
577                                 break;
578                 }
579         }
580
581         /*
582          * if we still have arguments, use it as the database name and username
583          */
584         while (argc - optind >= 1)
585         {
586                 if (!options->dbname)
587                         options->dbname = argv[optind];
588                 else if (!options->username)
589                         options->username = argv[optind];
590                 else if (!pset.quiet)
591                         fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
592                                         pset.progname, argv[optind]);
593
594                 optind++;
595         }
596 }
597
598
599 /*
600  * Load .psqlrc file, if found.
601  */
602 static void
603 process_psqlrc(char *argv0)
604 {
605         char            home[MAXPGPATH];
606         char            rc_file[MAXPGPATH];
607         char            my_exec_path[MAXPGPATH];
608         char            etc_path[MAXPGPATH];
609         char       *envrc = getenv("PSQLRC");
610
611         if (find_my_exec(argv0, my_exec_path) < 0)
612         {
613                 fprintf(stderr, _("%s: could not find own program executable\n"), argv0);
614                 exit(EXIT_FAILURE);
615         }
616
617         get_etc_path(my_exec_path, etc_path);
618
619         snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
620         process_psqlrc_file(rc_file);
621
622         if (envrc != NULL && strlen(envrc) > 0)
623         {
624                 /* might need to free() this */
625                 char       *envrc_alloc = pstrdup(envrc);
626
627                 expand_tilde(&envrc_alloc);
628                 process_psqlrc_file(envrc_alloc);
629         }
630         else if (get_home_path(home))
631         {
632                 snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
633                 process_psqlrc_file(rc_file);
634         }
635 }
636
637
638
639 static void
640 process_psqlrc_file(char *filename)
641 {
642         char       *psqlrc_minor,
643                            *psqlrc_major;
644
645 #if defined(WIN32) && (!defined(__MINGW32__))
646 #define R_OK 4
647 #endif
648
649         psqlrc_minor = psprintf("%s-%s", filename, PG_VERSION);
650         psqlrc_major = psprintf("%s-%s", filename, PG_MAJORVERSION);
651
652         /* check for minor version first, then major, then no version */
653         if (access(psqlrc_minor, R_OK) == 0)
654                 (void) process_file(psqlrc_minor, false, false);
655         else if (access(psqlrc_major, R_OK) == 0)
656                 (void) process_file(psqlrc_major, false, false);
657         else if (access(filename, R_OK) == 0)
658                 (void) process_file(filename, false, false);
659
660         free(psqlrc_minor);
661         free(psqlrc_major);
662 }
663
664
665
666 /* showVersion
667  *
668  * This output format is intended to match GNU standards.
669  */
670 static void
671 showVersion(void)
672 {
673         puts("psql (PostgreSQL) " PG_VERSION);
674 }
675
676
677
678 /*
679  * Assign hooks for psql variables.
680  *
681  * This isn't an amazingly good place for them, but neither is anywhere else.
682  */
683
684 static void
685 autocommit_hook(const char *newval)
686 {
687         pset.autocommit = ParseVariableBool(newval);
688 }
689
690 static void
691 on_error_stop_hook(const char *newval)
692 {
693         pset.on_error_stop = ParseVariableBool(newval);
694 }
695
696 static void
697 quiet_hook(const char *newval)
698 {
699         pset.quiet = ParseVariableBool(newval);
700 }
701
702 static void
703 singleline_hook(const char *newval)
704 {
705         pset.singleline = ParseVariableBool(newval);
706 }
707
708 static void
709 singlestep_hook(const char *newval)
710 {
711         pset.singlestep = ParseVariableBool(newval);
712 }
713
714 static void
715 fetch_count_hook(const char *newval)
716 {
717         pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
718 }
719
720 static void
721 echo_hook(const char *newval)
722 {
723         if (newval == NULL)
724                 pset.echo = PSQL_ECHO_NONE;
725         else if (strcmp(newval, "queries") == 0)
726                 pset.echo = PSQL_ECHO_QUERIES;
727         else if (strcmp(newval, "errors") == 0)
728                 pset.echo = PSQL_ECHO_ERRORS;
729         else if (strcmp(newval, "all") == 0)
730                 pset.echo = PSQL_ECHO_ALL;
731         else
732                 pset.echo = PSQL_ECHO_NONE;
733 }
734
735 static void
736 echo_hidden_hook(const char *newval)
737 {
738         if (newval == NULL)
739                 pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
740         else if (strcmp(newval, "noexec") == 0)
741                 pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
742         else if (pg_strcasecmp(newval, "off") == 0)
743                 pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
744         else
745                 pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
746 }
747
748 static void
749 on_error_rollback_hook(const char *newval)
750 {
751         if (newval == NULL)
752                 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
753         else if (pg_strcasecmp(newval, "interactive") == 0)
754                 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
755         else if (pg_strcasecmp(newval, "off") == 0)
756                 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
757         else
758                 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
759 }
760
761 static void
762 histcontrol_hook(const char *newval)
763 {
764         if (newval == NULL)
765                 pset.histcontrol = hctl_none;
766         else if (strcmp(newval, "ignorespace") == 0)
767                 pset.histcontrol = hctl_ignorespace;
768         else if (strcmp(newval, "ignoredups") == 0)
769                 pset.histcontrol = hctl_ignoredups;
770         else if (strcmp(newval, "ignoreboth") == 0)
771                 pset.histcontrol = hctl_ignoreboth;
772         else
773                 pset.histcontrol = hctl_none;
774 }
775
776 static void
777 prompt1_hook(const char *newval)
778 {
779         pset.prompt1 = newval ? newval : "";
780 }
781
782 static void
783 prompt2_hook(const char *newval)
784 {
785         pset.prompt2 = newval ? newval : "";
786 }
787
788 static void
789 prompt3_hook(const char *newval)
790 {
791         pset.prompt3 = newval ? newval : "";
792 }
793
794 static void
795 verbosity_hook(const char *newval)
796 {
797         if (newval == NULL)
798                 pset.verbosity = PQERRORS_DEFAULT;
799         else if (strcmp(newval, "default") == 0)
800                 pset.verbosity = PQERRORS_DEFAULT;
801         else if (strcmp(newval, "terse") == 0)
802                 pset.verbosity = PQERRORS_TERSE;
803         else if (strcmp(newval, "verbose") == 0)
804                 pset.verbosity = PQERRORS_VERBOSE;
805         else
806                 pset.verbosity = PQERRORS_DEFAULT;
807
808         if (pset.db)
809                 PQsetErrorVerbosity(pset.db, pset.verbosity);
810 }
811
812
813 static void
814 EstablishVariableSpace(void)
815 {
816         pset.vars = CreateVariableSpace();
817
818         SetVariableAssignHook(pset.vars, "AUTOCOMMIT", autocommit_hook);
819         SetVariableAssignHook(pset.vars, "ON_ERROR_STOP", on_error_stop_hook);
820         SetVariableAssignHook(pset.vars, "QUIET", quiet_hook);
821         SetVariableAssignHook(pset.vars, "SINGLELINE", singleline_hook);
822         SetVariableAssignHook(pset.vars, "SINGLESTEP", singlestep_hook);
823         SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
824         SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
825         SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
826         SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
827         SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
828         SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
829         SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);
830         SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook);
831         SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook);
832 }