startup.c 17.0 KB
Newer Older
P
Peter Eisentraut 已提交
1 2 3
/*
 * psql - the PostgreSQL interactive terminal
 *
B
Bruce Momjian 已提交
4
 * Copyright (c) 2000-2009, PostgreSQL Global Development Group
P
Peter Eisentraut 已提交
5
 *
6
 * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.154 2009/02/25 13:24:40 petere Exp $
P
Peter Eisentraut 已提交
7
 */
8
#include "postgres_fe.h"
9 10 11

#include <sys/types.h>

12 13
#ifndef WIN32
#include <unistd.h>
B
Bruce Momjian 已提交
14
#else							/* WIN32 */
15
#include <io.h>
16
#include <win32.h>
17
#endif   /* WIN32 */
18

19
#include "getopt_long.h"
20

21
#ifndef HAVE_INT_OPTRESET
B
Bruce Momjian 已提交
22
int			optreset;
23 24
#endif

P
Peter Eisentraut 已提交
25 26
#include <locale.h>

27 28 29

#include "command.h"
#include "common.h"
30 31
#include "describe.h"
#include "help.h"
32
#include "input.h"
33 34
#include "mainloop.h"
#include "settings.h"
35

36

37

38 39 40
/*
 * Global psql options
 */
41
PsqlSettings pset;
42

43
#ifndef WIN32
44
#define SYSPSQLRC	"psqlrc"
B
Bruce Momjian 已提交
45
#define PSQLRC		".psqlrc"
46 47
#else
#define SYSPSQLRC	"psqlrc"
48
#define PSQLRC		"psqlrc.conf"
49
#endif
50

51 52
/*
 * Structures to pass information between the option parsing routine
53 54
 * and the main function
 */
B
Bruce Momjian 已提交
55 56
enum _actions
{
57 58 59 60 61
	ACT_NOTHING = 0,
	ACT_SINGLE_SLASH,
	ACT_LIST_DB,
	ACT_SINGLE_QUERY,
	ACT_FILE
62 63
};

B
Bruce Momjian 已提交
64 65 66 67 68 69
struct adhoc_opts
{
	char	   *dbname;
	char	   *host;
	char	   *port;
	char	   *username;
70
	char	   *logfilename;
B
Bruce Momjian 已提交
71 72 73
	enum _actions action;
	char	   *action_string;
	bool		no_readline;
74
	bool		no_psqlrc;
B
Bruce Momjian 已提交
75
	bool		single_txn;
76 77
};

78
static void parse_psql_options(int argc, char *argv[],
B
Bruce Momjian 已提交
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);
84

85 86
/*
 *
87
 * main
88 89 90
 *
 */
int
91
main(int argc, char *argv[])
92
{
B
Bruce Momjian 已提交
93 94 95
	struct adhoc_opts options;
	int			successResult;
	char	   *password = NULL;
B
Bruce Momjian 已提交
96
	char	   *password_prompt = NULL;
97
	bool		new_pass;
98

99
	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
P
Peter Eisentraut 已提交
100

101 102
	if (argc > 1)
	{
B
Bruce Momjian 已提交
103
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
104 105 106 107
		{
			usage();
			exit(EXIT_SUCCESS);
		}
B
Bruce Momjian 已提交
108
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
109 110 111 112
		{
			showVersion();
			exit(EXIT_SUCCESS);
		}
B
Bruce Momjian 已提交
113
	}
114

115
#ifdef WIN32
B
Bruce Momjian 已提交
116
	setvbuf(stderr, NULL, _IONBF, 0);
117
#endif
118 119 120 121 122

	setup_cancel_handler();

	pset.progname = get_progname(argv[0]);

123
	pset.db = NULL;
124
	setDecimalLocale();
125 126 127
	pset.encoding = PQenv2encoding();
	pset.queryFout = stdout;
	pset.queryFoutPipe = false;
128 129
	pset.cur_cmd_source = stdin;
	pset.cur_cmd_interactive = false;
130

131
	/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
132 133
	pset.popt.topt.format = PRINT_ALIGNED;
	pset.popt.topt.border = 1;
134
	pset.popt.topt.pager = 1;
135 136
	pset.popt.topt.start_table = true;
	pset.popt.topt.stop_table = true;
137
	pset.popt.default_footer = true;
138 139
	/* We must get COLUMNS here before readline() sets it */
	pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
140

141
	pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
142

143
	/* This is obsolete and should be removed sometime. */
144
#ifdef PSQL_ALWAYS_GET_PASSWORDS
145
	pset.getPassword = true;
146
#else
147
	pset.getPassword = false;
148 149
#endif

150 151 152 153 154 155 156 157 158 159 160
	EstablishVariableSpace();

	SetVariable(pset.vars, "VERSION", PG_VERSION_STR);

	/* Default values for variables */
	SetVariableBool(pset.vars, "AUTOCOMMIT");
	SetVariable(pset.vars, "VERBOSITY", "default");
	SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
	SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
	SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);

161
	parse_psql_options(argc, argv, &options);
162

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);
167

168
	if (options.username == NULL)
169
		password_prompt = pg_strdup(_("Password: "));
170 171
	else
	{
172
		password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
173 174 175
								 strlen(options.username) + 1);
		sprintf(password_prompt, _("Password for user %s: "),
				options.username);
176
	}
177

178
	if (pset.getPassword)
179
		password = simple_prompt(password_prompt, 100, false);
180

B
Bruce Momjian 已提交
181 182 183
	/* loop until we have a password if requested by backend */
	do
	{
184
		new_pass = false;
185
		pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
186
					options.action == ACT_LIST_DB && options.dbname == NULL ?
A
 
Andrew Dunstan 已提交
187
							   "postgres" : options.dbname,
188
							   options.username, password);
B
Bruce Momjian 已提交
189

190
		if (PQstatus(pset.db) == CONNECTION_BAD &&
191
			PQconnectionNeedsPassword(pset.db) &&
192
			password == NULL)
B
Bruce Momjian 已提交
193
		{
194
			PQfinish(pset.db);
195
			password = simple_prompt(password_prompt, 100, false);
196
			new_pass = true;
B
Bruce Momjian 已提交
197
		}
198
	} while (new_pass);
199

B
Bruce Momjian 已提交
200
	free(password);
201
	free(password_prompt);
B
Bruce Momjian 已提交
202

203
	if (PQstatus(pset.db) == CONNECTION_BAD)
B
Bruce Momjian 已提交
204
	{
205
		fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
206
		PQfinish(pset.db);
B
Bruce Momjian 已提交
207 208 209
		exit(EXIT_BADCONN);
	}

210 211
	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);

212
	SyncVariables();
P
Peter Eisentraut 已提交
213

B
Bruce Momjian 已提交
214 215
	if (options.action == ACT_LIST_DB)
	{
216
		int			success = listAllDbs(false);
B
Bruce Momjian 已提交
217

218
		PQfinish(pset.db);
219
		exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
B
Bruce Momjian 已提交
220 221
	}

222 223 224 225
	if (options.logfilename)
	{
		pset.logfile = fopen(options.logfilename, "a");
		if (!pset.logfile)
226 227
			fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
					pset.progname, options.logfilename, strerror(errno));
228 229
	}

230
	/*
231 232
	 * Now find something to do
	 */
B
Bruce Momjian 已提交
233

234
	/*
235 236
	 * process file given by -f
	 */
237
	if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
238 239
	{
		if (!options.no_psqlrc)
240
			process_psqlrc(argv[0]);
241

B
Bruce Momjian 已提交
242
		successResult = process_file(options.action_string, options.single_txn);
243 244
	}

245
	/*
246 247
	 * process slash command if one was given to -c
	 */
B
Bruce Momjian 已提交
248
	else if (options.action == ACT_SINGLE_SLASH)
249
	{
250 251
		PsqlScanState scan_state;

252
		if (pset.echo == PSQL_ECHO_ALL)
253
			puts(options.action_string);
254

255 256 257 258 259
		scan_state = psql_scan_create();
		psql_scan_setup(scan_state,
						options.action_string,
						strlen(options.action_string));

260
		successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
261
			? EXIT_SUCCESS : EXIT_FAILURE;
262 263

		psql_scan_destroy(scan_state);
264 265
	}

266
	/*
267 268
	 * If the query given to -c was a normal one, send it
	 */
B
Bruce Momjian 已提交
269
	else if (options.action == ACT_SINGLE_QUERY)
270
	{
271
		if (pset.echo == PSQL_ECHO_ALL)
272
			puts(options.action_string);
273

274
		successResult = SendQuery(options.action_string)
275 276 277
			? EXIT_SUCCESS : EXIT_FAILURE;
	}

278
	/*
279 280
	 * or otherwise enter interactive main loop
	 */
B
Bruce Momjian 已提交
281
	else
282
	{
283 284
		if (!options.no_psqlrc)
			process_psqlrc(argv[0]);
285 286

		connection_warnings();
287
		if (!pset.quiet && !pset.notty)
288
			printf(_("Type \"help\" for help.\n\n"));
289 290
		if (!pset.notty)
			initializeInput(options.no_readline ? 0 : 1);
291
		if (options.action_string)		/* -f - was used */
292
			pset.inputfile = "<stdin>";
293

P
Peter Eisentraut 已提交
294
		successResult = MainLoop(stdin);
295
	}
B
Bruce Momjian 已提交
296 297

	/* clean up */
298 299
	if (pset.logfile)
		fclose(pset.logfile);
300 301
	PQfinish(pset.db);
	setQFout(NULL);
B
Bruce Momjian 已提交
302 303

	return successResult;
304 305 306 307 308 309 310 311
}


/*
 * Parse command line options
 */

static void
312
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
313
{
314
	static struct option long_options[] =
315 316
	{
		{"echo-all", no_argument, NULL, 'a'},
B
Bruce Momjian 已提交
317 318 319
		{"no-align", no_argument, NULL, 'A'},
		{"command", required_argument, NULL, 'c'},
		{"dbname", required_argument, NULL, 'd'},
320
		{"echo-queries", no_argument, NULL, 'e'},
321
		{"echo-hidden", no_argument, NULL, 'E'},
B
Bruce Momjian 已提交
322
		{"file", required_argument, NULL, 'f'},
323
		{"field-separator", required_argument, NULL, 'F'},
B
Bruce Momjian 已提交
324 325 326
		{"host", required_argument, NULL, 'h'},
		{"html", no_argument, NULL, 'H'},
		{"list", no_argument, NULL, 'l'},
327
		{"log-file", required_argument, NULL, 'L'},
328
		{"no-readline", no_argument, NULL, 'n'},
B
Bruce Momjian 已提交
329
		{"single-transaction", no_argument, NULL, '1'},
330
		{"output", required_argument, NULL, 'o'},
B
Bruce Momjian 已提交
331 332 333
		{"port", required_argument, NULL, 'p'},
		{"pset", required_argument, NULL, 'P'},
		{"quiet", no_argument, NULL, 'q'},
334
		{"record-separator", required_argument, NULL, 'R'},
B
Bruce Momjian 已提交
335 336 337 338 339 340 341 342 343
		{"single-step", no_argument, NULL, 's'},
		{"single-line", no_argument, NULL, 'S'},
		{"tuples-only", no_argument, NULL, 't'},
		{"table-attr", required_argument, NULL, 'T'},
		{"username", required_argument, NULL, 'U'},
		{"set", required_argument, NULL, 'v'},
		{"variable", required_argument, NULL, 'v'},
		{"version", no_argument, NULL, 'V'},
		{"password", no_argument, NULL, 'W'},
344
		{"expanded", no_argument, NULL, 'x'},
345
		{"no-psqlrc", no_argument, NULL, 'X'},
B
Bruce Momjian 已提交
346
		{"help", no_argument, NULL, '?'},
T
Tatsuo Ishii 已提交
347
		{NULL, 0, NULL, 0}
B
Bruce Momjian 已提交
348 349 350 351 352 353
	};

	int			optindex;
	extern char *optarg;
	extern int	optind;
	int			c;
354

355
	memset(options, 0, sizeof *options);
356

357
	while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VWxX?1",
358
							long_options, &optindex)) != -1)
359
	{
B
Bruce Momjian 已提交
360 361
		switch (c)
		{
362 363 364
			case 'a':
				SetVariable(pset.vars, "ECHO", "all");
				break;
B
Bruce Momjian 已提交
365
			case 'A':
366
				pset.popt.topt.format = PRINT_UNALIGNED;
B
Bruce Momjian 已提交
367 368 369 370
				break;
			case 'c':
				options->action_string = optarg;
				if (optarg[0] == '\\')
P
Peter Eisentraut 已提交
371
				{
B
Bruce Momjian 已提交
372
					options->action = ACT_SINGLE_SLASH;
P
Peter Eisentraut 已提交
373 374
					options->action_string++;
				}
B
Bruce Momjian 已提交
375 376 377 378 379 380 381
				else
					options->action = ACT_SINGLE_QUERY;
				break;
			case 'd':
				options->dbname = optarg;
				break;
			case 'e':
382
				SetVariable(pset.vars, "ECHO", "queries");
B
Bruce Momjian 已提交
383 384
				break;
			case 'E':
385
				SetVariableBool(pset.vars, "ECHO_HIDDEN");
B
Bruce Momjian 已提交
386 387 388 389 390 391
				break;
			case 'f':
				options->action = ACT_FILE;
				options->action_string = optarg;
				break;
			case 'F':
392
				pset.popt.topt.fieldSep = pg_strdup(optarg);
B
Bruce Momjian 已提交
393 394 395 396 397
				break;
			case 'h':
				options->host = optarg;
				break;
			case 'H':
398
				pset.popt.topt.format = PRINT_HTML;
B
Bruce Momjian 已提交
399 400 401 402
				break;
			case 'l':
				options->action = ACT_LIST_DB;
				break;
403 404 405
			case 'L':
				options->logfilename = optarg;
				break;
B
Bruce Momjian 已提交
406 407 408 409
			case 'n':
				options->no_readline = true;
				break;
			case 'o':
410
				setQFout(optarg);
B
Bruce Momjian 已提交
411 412 413 414 415 416 417 418 419 420
				break;
			case 'p':
				options->port = optarg;
				break;
			case 'P':
				{
					char	   *value;
					char	   *equal_loc;
					bool		result;

421
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
422 423
					equal_loc = strchr(value, '=');
					if (!equal_loc)
424
						result = do_pset(value, NULL, &pset.popt, true);
B
Bruce Momjian 已提交
425 426 427
					else
					{
						*equal_loc = '\0';
428
						result = do_pset(value, equal_loc + 1, &pset.popt, true);
B
Bruce Momjian 已提交
429 430 431 432
					}

					if (!result)
					{
433
						fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
B
Bruce Momjian 已提交
434 435 436 437 438 439 440
						exit(EXIT_FAILURE);
					}

					free(value);
					break;
				}
			case 'q':
441
				SetVariableBool(pset.vars, "QUIET");
B
Bruce Momjian 已提交
442
				break;
443
			case 'R':
444
				pset.popt.topt.recordSep = pg_strdup(optarg);
445
				break;
B
Bruce Momjian 已提交
446
			case 's':
447
				SetVariableBool(pset.vars, "SINGLESTEP");
B
Bruce Momjian 已提交
448 449
				break;
			case 'S':
450
				SetVariableBool(pset.vars, "SINGLELINE");
B
Bruce Momjian 已提交
451 452
				break;
			case 't':
453
				pset.popt.topt.tuples_only = true;
B
Bruce Momjian 已提交
454 455
				break;
			case 'T':
456
				pset.popt.topt.tableAttr = pg_strdup(optarg);
B
Bruce Momjian 已提交
457 458 459 460 461 462 463 464 465
				break;
			case 'U':
				options->username = optarg;
				break;
			case 'v':
				{
					char	   *value;
					char	   *equal_loc;

466
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
467 468 469
					equal_loc = strchr(value, '=');
					if (!equal_loc)
					{
470
						if (!DeleteVariable(pset.vars, value))
B
Bruce Momjian 已提交
471
						{
472
							fprintf(stderr, _("%s: could not delete variable \"%s\"\n"),
473
									pset.progname, value);
B
Bruce Momjian 已提交
474 475 476 477 478 479
							exit(EXIT_FAILURE);
						}
					}
					else
					{
						*equal_loc = '\0';
480
						if (!SetVariable(pset.vars, value, equal_loc + 1))
B
Bruce Momjian 已提交
481
						{
482
							fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
483
									pset.progname, value);
B
Bruce Momjian 已提交
484 485 486 487 488 489 490 491
							exit(EXIT_FAILURE);
						}
					}

					free(value);
					break;
				}
			case 'V':
492 493
				showVersion();
				exit(EXIT_SUCCESS);
B
Bruce Momjian 已提交
494
			case 'W':
495
				pset.getPassword = true;
B
Bruce Momjian 已提交
496
				break;
497 498 499
			case 'x':
				pset.popt.topt.expanded = true;
				break;
500 501 502
			case 'X':
				options->no_psqlrc = true;
				break;
B
Bruce Momjian 已提交
503 504 505
			case '1':
				options->single_txn = true;
				break;
B
Bruce Momjian 已提交
506
			case '?':
507 508 509 510 511 512 513 514 515
				/* Actual help option given */
				if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
				{
					usage();
					exit(EXIT_SUCCESS);
				}
				/* unknown option reported by getopt */
				else
				{
516
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
517
							pset.progname);
518
					exit(EXIT_FAILURE);
519
				}
B
Bruce Momjian 已提交
520 521
				break;
			default:
522
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
523
						pset.progname);
524
				exit(EXIT_FAILURE);
B
Bruce Momjian 已提交
525 526
				break;
		}
527 528
	}

B
Bruce Momjian 已提交
529
	/*
B
Bruce Momjian 已提交
530
	 * if we still have arguments, use it as the database name and username
B
Bruce Momjian 已提交
531 532 533 534 535 536 537
	 */
	while (argc - optind >= 1)
	{
		if (!options->dbname)
			options->dbname = argv[optind];
		else if (!options->username)
			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]);
B
Bruce Momjian 已提交
541 542 543

		optind++;
	}
544 545 546 547
}


/*
P
Peter Eisentraut 已提交
548
 * Load .psqlrc file, if found.
549 550
 */
static void
551
process_psqlrc(char *argv0)
552
{
B
Bruce Momjian 已提交
553
	char		home[MAXPGPATH];
554
	char		rc_file[MAXPGPATH];
B
Bruce Momjian 已提交
555 556
	char		my_exec_path[MAXPGPATH];
	char		etc_path[MAXPGPATH];
557 558 559

	find_my_exec(argv0, my_exec_path);
	get_etc_path(my_exec_path, etc_path);
560

561 562
	snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
	process_psqlrc_file(rc_file);
563

564
	if (get_home_path(home))
565
	{
566 567
		snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
		process_psqlrc_file(rc_file);
568 569 570 571 572 573 574 575 576
	}
}



static void
process_psqlrc_file(char *filename)
{
	char	   *psqlrc;
577

578 579
#if defined(WIN32) && (!defined(__MINGW32__))
#define R_OK 4
580 581
#endif

582 583
	psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
	sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
584

585
	if (access(psqlrc, R_OK) == 0)
B
Bruce Momjian 已提交
586
		(void) process_file(psqlrc, false);
587
	else if (access(filename, R_OK) == 0)
B
Bruce Momjian 已提交
588
		(void) process_file(filename, false);
589
	free(psqlrc);
590 591 592 593 594 595
}



/* showVersion
 *
596
 * This output format is intended to match GNU standards.
597 598
 */
static void
599
showVersion(void)
600
{
601
	puts("psql (PostgreSQL) " PG_VERSION);
602

603
#if defined(USE_READLINE)
604
	puts(_("contains support for command-line editing"));
605
#endif
606
}
B
Bruce Momjian 已提交
607 608 609



610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
/*
 * Assign hooks for psql variables.
 *
 * This isn't an amazingly good place for them, but neither is anywhere else.
 */

static void
autocommit_hook(const char *newval)
{
	pset.autocommit = ParseVariableBool(newval);
}

static void
on_error_stop_hook(const char *newval)
{
	pset.on_error_stop = ParseVariableBool(newval);
}

static void
quiet_hook(const char *newval)
{
	pset.quiet = ParseVariableBool(newval);
}

static void
singleline_hook(const char *newval)
{
	pset.singleline = ParseVariableBool(newval);
}

static void
singlestep_hook(const char *newval)
{
	pset.singlestep = ParseVariableBool(newval);
}

646 647 648 649 650 651
static void
fetch_count_hook(const char *newval)
{
	pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
}

652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
static void
echo_hook(const char *newval)
{
	if (newval == NULL)
		pset.echo = PSQL_ECHO_NONE;
	else if (strcmp(newval, "queries") == 0)
		pset.echo = PSQL_ECHO_QUERIES;
	else if (strcmp(newval, "all") == 0)
		pset.echo = PSQL_ECHO_ALL;
	else
		pset.echo = PSQL_ECHO_NONE;
}

static void
echo_hidden_hook(const char *newval)
{
	if (newval == NULL)
		pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
	else if (strcmp(newval, "noexec") == 0)
		pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
	else if (pg_strcasecmp(newval, "off") == 0)
		pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
	else
		pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
}

static void
on_error_rollback_hook(const char *newval)
{
	if (newval == NULL)
		pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
	else if (pg_strcasecmp(newval, "interactive") == 0)
		pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
	else if (pg_strcasecmp(newval, "off") == 0)
		pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
	else
		pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
}

static void
histcontrol_hook(const char *newval)
{
	if (newval == NULL)
		pset.histcontrol = hctl_none;
	else if (strcmp(newval, "ignorespace") == 0)
		pset.histcontrol = hctl_ignorespace;
	else if (strcmp(newval, "ignoredups") == 0)
		pset.histcontrol = hctl_ignoredups;
	else if (strcmp(newval, "ignoreboth") == 0)
		pset.histcontrol = hctl_ignoreboth;
	else
		pset.histcontrol = hctl_none;
}

static void
prompt1_hook(const char *newval)
{
	pset.prompt1 = newval ? newval : "";
}

static void
prompt2_hook(const char *newval)
{
	pset.prompt2 = newval ? newval : "";
}

static void
prompt3_hook(const char *newval)
{
	pset.prompt3 = newval ? newval : "";
}

static void
verbosity_hook(const char *newval)
{
	if (newval == NULL)
		pset.verbosity = PQERRORS_DEFAULT;
	else if (strcmp(newval, "default") == 0)
		pset.verbosity = PQERRORS_DEFAULT;
	else if (strcmp(newval, "terse") == 0)
		pset.verbosity = PQERRORS_TERSE;
	else if (strcmp(newval, "verbose") == 0)
		pset.verbosity = PQERRORS_VERBOSE;
	else
		pset.verbosity = PQERRORS_DEFAULT;

	if (pset.db)
		PQsetErrorVerbosity(pset.db, pset.verbosity);
}


static void
EstablishVariableSpace(void)
{
	pset.vars = CreateVariableSpace();

	SetVariableAssignHook(pset.vars, "AUTOCOMMIT", autocommit_hook);
	SetVariableAssignHook(pset.vars, "ON_ERROR_STOP", on_error_stop_hook);
	SetVariableAssignHook(pset.vars, "QUIET", quiet_hook);
	SetVariableAssignHook(pset.vars, "SINGLELINE", singleline_hook);
	SetVariableAssignHook(pset.vars, "SINGLESTEP", singlestep_hook);
753
	SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
754 755 756 757 758 759 760 761 762
	SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
	SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
	SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
	SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
	SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
	SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);
	SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook);
	SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook);
}