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.156 2009/04/05 04:19:58 tgl 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

P
Peter Eisentraut 已提交
21 22
#include <locale.h>

23 24
#include "command.h"
#include "common.h"
25 26
#include "describe.h"
#include "help.h"
27
#include "input.h"
28 29
#include "mainloop.h"
#include "settings.h"
30

31

32

33 34 35
/*
 * Global psql options
 */
36
PsqlSettings pset;
37

38
#ifndef WIN32
39
#define SYSPSQLRC	"psqlrc"
B
Bruce Momjian 已提交
40
#define PSQLRC		".psqlrc"
41 42
#else
#define SYSPSQLRC	"psqlrc"
43
#define PSQLRC		"psqlrc.conf"
44
#endif
45

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

B
Bruce Momjian 已提交
59 60 61 62 63 64
struct adhoc_opts
{
	char	   *dbname;
	char	   *host;
	char	   *port;
	char	   *username;
65
	char	   *logfilename;
B
Bruce Momjian 已提交
66 67 68
	enum _actions action;
	char	   *action_string;
	bool		no_readline;
69
	bool		no_psqlrc;
B
Bruce Momjian 已提交
70
	bool		single_txn;
71 72
};

73
static void parse_psql_options(int argc, char *argv[],
B
Bruce Momjian 已提交
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
{
B
Bruce Momjian 已提交
88 89 90
	struct adhoc_opts options;
	int			successResult;
	char	   *password = NULL;
B
Bruce Momjian 已提交
91
	char	   *password_prompt = NULL;
92
	bool		new_pass;
93

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

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

110
#ifdef WIN32
B
Bruce Momjian 已提交
111
	setvbuf(stderr, NULL, _IONBF, 0);
112
#endif
113 114 115 116 117

	setup_cancel_handler();

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

118
	pset.db = NULL;
119
	setDecimalLocale();
120 121 122
	pset.encoding = PQenv2encoding();
	pset.queryFout = stdout;
	pset.queryFoutPipe = false;
123 124
	pset.cur_cmd_source = stdin;
	pset.cur_cmd_interactive = false;
125

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

136
	pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
137

138
	pset.getPassword = TRI_DEFAULT;
139

140 141 142 143 144 145 146 147 148 149 150
	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);

151
	parse_psql_options(argc, argv, &options);
152

153
	if (!pset.popt.topt.fieldSep)
154
		pset.popt.topt.fieldSep = pg_strdup(DEFAULT_FIELD_SEP);
155
	if (!pset.popt.topt.recordSep)
156
		pset.popt.topt.recordSep = pg_strdup(DEFAULT_RECORD_SEP);
157

158
	if (options.username == NULL)
159
		password_prompt = pg_strdup(_("Password: "));
160 161
	else
	{
162
		password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
163 164 165
								 strlen(options.username) + 1);
		sprintf(password_prompt, _("Password for user %s: "),
				options.username);
166
	}
167

168
	if (pset.getPassword == TRI_YES)
169
		password = simple_prompt(password_prompt, 100, false);
170

B
Bruce Momjian 已提交
171 172 173
	/* loop until we have a password if requested by backend */
	do
	{
174
		new_pass = false;
175
		pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
176
					options.action == ACT_LIST_DB && options.dbname == NULL ?
A
 
Andrew Dunstan 已提交
177
							   "postgres" : options.dbname,
178
							   options.username, password);
B
Bruce Momjian 已提交
179

180
		if (PQstatus(pset.db) == CONNECTION_BAD &&
181
			PQconnectionNeedsPassword(pset.db) &&
182 183
			password == NULL &&
			pset.getPassword != TRI_NO)
B
Bruce Momjian 已提交
184
		{
185
			PQfinish(pset.db);
186
			password = simple_prompt(password_prompt, 100, false);
187
			new_pass = true;
B
Bruce Momjian 已提交
188
		}
189
	} while (new_pass);
190

B
Bruce Momjian 已提交
191
	free(password);
192
	free(password_prompt);
B
Bruce Momjian 已提交
193

194
	if (PQstatus(pset.db) == CONNECTION_BAD)
B
Bruce Momjian 已提交
195
	{
196
		fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
197
		PQfinish(pset.db);
B
Bruce Momjian 已提交
198 199 200
		exit(EXIT_BADCONN);
	}

201 202
	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);

203
	SyncVariables();
P
Peter Eisentraut 已提交
204

B
Bruce Momjian 已提交
205 206
	if (options.action == ACT_LIST_DB)
	{
207
		int			success = listAllDbs(false);
B
Bruce Momjian 已提交
208

209
		PQfinish(pset.db);
210
		exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
B
Bruce Momjian 已提交
211 212
	}

213 214 215 216
	if (options.logfilename)
	{
		pset.logfile = fopen(options.logfilename, "a");
		if (!pset.logfile)
217 218
			fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
					pset.progname, options.logfilename, strerror(errno));
219 220
	}

221
	/*
222 223
	 * Now find something to do
	 */
B
Bruce Momjian 已提交
224

225
	/*
226 227
	 * process file given by -f
	 */
228
	if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
229 230
	{
		if (!options.no_psqlrc)
231
			process_psqlrc(argv[0]);
232

B
Bruce Momjian 已提交
233
		successResult = process_file(options.action_string, options.single_txn);
234 235
	}

236
	/*
237 238
	 * process slash command if one was given to -c
	 */
B
Bruce Momjian 已提交
239
	else if (options.action == ACT_SINGLE_SLASH)
240
	{
241 242
		PsqlScanState scan_state;

243
		if (pset.echo == PSQL_ECHO_ALL)
244
			puts(options.action_string);
245

246 247 248 249 250
		scan_state = psql_scan_create();
		psql_scan_setup(scan_state,
						options.action_string,
						strlen(options.action_string));

251
		successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
252
			? EXIT_SUCCESS : EXIT_FAILURE;
253 254

		psql_scan_destroy(scan_state);
255 256
	}

257
	/*
258 259
	 * If the query given to -c was a normal one, send it
	 */
B
Bruce Momjian 已提交
260
	else if (options.action == ACT_SINGLE_QUERY)
261
	{
262
		if (pset.echo == PSQL_ECHO_ALL)
263
			puts(options.action_string);
264

265
		successResult = SendQuery(options.action_string)
266 267 268
			? EXIT_SUCCESS : EXIT_FAILURE;
	}

269
	/*
270 271
	 * or otherwise enter interactive main loop
	 */
B
Bruce Momjian 已提交
272
	else
273
	{
274 275
		if (!options.no_psqlrc)
			process_psqlrc(argv[0]);
276 277

		connection_warnings();
278
		if (!pset.quiet && !pset.notty)
279
			printf(_("Type \"help\" for help.\n\n"));
280 281
		if (!pset.notty)
			initializeInput(options.no_readline ? 0 : 1);
282
		if (options.action_string)		/* -f - was used */
283
			pset.inputfile = "<stdin>";
284

P
Peter Eisentraut 已提交
285
		successResult = MainLoop(stdin);
286
	}
B
Bruce Momjian 已提交
287 288

	/* clean up */
289 290
	if (pset.logfile)
		fclose(pset.logfile);
291 292
	PQfinish(pset.db);
	setQFout(NULL);
B
Bruce Momjian 已提交
293 294

	return successResult;
295 296 297 298 299 300 301 302
}


/*
 * Parse command line options
 */

static void
303
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
304
{
305
	static struct option long_options[] =
306 307
	{
		{"echo-all", no_argument, NULL, 'a'},
B
Bruce Momjian 已提交
308 309 310
		{"no-align", no_argument, NULL, 'A'},
		{"command", required_argument, NULL, 'c'},
		{"dbname", required_argument, NULL, 'd'},
311
		{"echo-queries", no_argument, NULL, 'e'},
312
		{"echo-hidden", no_argument, NULL, 'E'},
B
Bruce Momjian 已提交
313
		{"file", required_argument, NULL, 'f'},
314
		{"field-separator", required_argument, NULL, 'F'},
B
Bruce Momjian 已提交
315 316 317
		{"host", required_argument, NULL, 'h'},
		{"html", no_argument, NULL, 'H'},
		{"list", no_argument, NULL, 'l'},
318
		{"log-file", required_argument, NULL, 'L'},
319
		{"no-readline", no_argument, NULL, 'n'},
B
Bruce Momjian 已提交
320
		{"single-transaction", no_argument, NULL, '1'},
321
		{"output", required_argument, NULL, 'o'},
B
Bruce Momjian 已提交
322 323 324
		{"port", required_argument, NULL, 'p'},
		{"pset", required_argument, NULL, 'P'},
		{"quiet", no_argument, NULL, 'q'},
325
		{"record-separator", required_argument, NULL, 'R'},
B
Bruce Momjian 已提交
326 327 328 329 330 331 332 333
		{"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'},
334
		{"no-password", no_argument, NULL, 'w'},
B
Bruce Momjian 已提交
335
		{"password", no_argument, NULL, 'W'},
336
		{"expanded", no_argument, NULL, 'x'},
337
		{"no-psqlrc", no_argument, NULL, 'X'},
B
Bruce Momjian 已提交
338
		{"help", no_argument, NULL, '?'},
T
Tatsuo Ishii 已提交
339
		{NULL, 0, NULL, 0}
B
Bruce Momjian 已提交
340 341 342 343 344 345
	};

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

347
	memset(options, 0, sizeof *options);
348

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

413
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
414 415
					equal_loc = strchr(value, '=');
					if (!equal_loc)
416
						result = do_pset(value, NULL, &pset.popt, true);
B
Bruce Momjian 已提交
417 418 419
					else
					{
						*equal_loc = '\0';
420
						result = do_pset(value, equal_loc + 1, &pset.popt, true);
B
Bruce Momjian 已提交
421 422 423 424
					}

					if (!result)
					{
425
						fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
B
Bruce Momjian 已提交
426 427 428 429 430 431 432
						exit(EXIT_FAILURE);
					}

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

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

					free(value);
					break;
				}
			case 'V':
484 485
				showVersion();
				exit(EXIT_SUCCESS);
486 487 488
			case 'w':
				pset.getPassword = TRI_NO;
				break;
B
Bruce Momjian 已提交
489
			case 'W':
490
				pset.getPassword = TRI_YES;
B
Bruce Momjian 已提交
491
				break;
492 493 494
			case 'x':
				pset.popt.topt.expanded = true;
				break;
495 496 497
			case 'X':
				options->no_psqlrc = true;
				break;
B
Bruce Momjian 已提交
498 499 500
			case '1':
				options->single_txn = true;
				break;
B
Bruce Momjian 已提交
501
			case '?':
502 503 504 505 506 507 508 509 510
				/* 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
				{
511
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
512
							pset.progname);
513
					exit(EXIT_FAILURE);
514
				}
B
Bruce Momjian 已提交
515 516
				break;
			default:
517
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
518
						pset.progname);
519
				exit(EXIT_FAILURE);
B
Bruce Momjian 已提交
520 521
				break;
		}
522 523
	}

B
Bruce Momjian 已提交
524
	/*
B
Bruce Momjian 已提交
525
	 * if we still have arguments, use it as the database name and username
B
Bruce Momjian 已提交
526 527 528 529 530 531 532
	 */
	while (argc - optind >= 1)
	{
		if (!options->dbname)
			options->dbname = argv[optind];
		else if (!options->username)
			options->username = argv[optind];
533
		else if (!pset.quiet)
534
			fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
535
					pset.progname, argv[optind]);
B
Bruce Momjian 已提交
536 537 538

		optind++;
	}
539 540 541 542
}


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

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

556 557
	snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
	process_psqlrc_file(rc_file);
558

559
	if (get_home_path(home))
560
	{
561 562
		snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
		process_psqlrc_file(rc_file);
563 564 565 566 567 568 569 570 571
	}
}



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

573 574
#if defined(WIN32) && (!defined(__MINGW32__))
#define R_OK 4
575 576
#endif

577 578
	psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
	sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
579

580
	if (access(psqlrc, R_OK) == 0)
B
Bruce Momjian 已提交
581
		(void) process_file(psqlrc, false);
582
	else if (access(filename, R_OK) == 0)
B
Bruce Momjian 已提交
583
		(void) process_file(filename, false);
584
	free(psqlrc);
585 586 587 588 589 590
}



/* showVersion
 *
591
 * This output format is intended to match GNU standards.
592 593
 */
static void
594
showVersion(void)
595
{
596
	puts("psql (PostgreSQL) " PG_VERSION);
597

598
#if defined(USE_READLINE)
599
	puts(_("contains support for command-line editing"));
600
#endif
601
}
B
Bruce Momjian 已提交
602 603 604



605 606 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
/*
 * 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);
}

641 642 643 644 645 646
static void
fetch_count_hook(const char *newval)
{
	pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
}

647 648 649 650 651 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
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);
748
	SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
749 750 751 752 753 754 755 756 757
	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);
}