startup.c 19.6 KB
Newer Older
P
Peter Eisentraut 已提交
1 2 3
/*
 * psql - the PostgreSQL interactive terminal
 *
4
 * Copyright (c) 2000-2007, PostgreSQL Global Development Group
P
Peter Eisentraut 已提交
5
 *
6
 * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.144 2007/12/11 19:01:06 tgl Exp $
P
Peter Eisentraut 已提交
7
 */
8
#include "postgres_fe.h"
9 10

#include <sys/types.h>
11 12 13
#ifdef USE_SSL
#include <openssl/ssl.h>
#endif
14

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

22
#include "getopt_long.h"
23

24
#ifndef HAVE_INT_OPTRESET
B
Bruce Momjian 已提交
25
int			optreset;
26 27
#endif

P
Peter Eisentraut 已提交
28 29
#include <locale.h>

30 31 32

#include "command.h"
#include "common.h"
33 34
#include "describe.h"
#include "help.h"
35
#include "input.h"
36 37
#include "mainloop.h"
#include "settings.h"
38

39

40

41 42 43
/*
 * Global psql options
 */
44
PsqlSettings pset;
45

46
#ifndef WIN32
47
#define SYSPSQLRC	"psqlrc"
B
Bruce Momjian 已提交
48
#define PSQLRC		".psqlrc"
49 50
#else
#define SYSPSQLRC	"psqlrc"
51
#define PSQLRC		"psqlrc.conf"
52
#endif
53

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

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

81
static int	parse_version(const char *versionString);
82
static void parse_psql_options(int argc, char *argv[],
B
Bruce Momjian 已提交
83
				   struct adhoc_opts * options);
84
static void process_psqlrc(char *argv0);
85
static void process_psqlrc_file(char *filename);
86
static void showVersion(void);
87
static void EstablishVariableSpace(void);
88

B
Bruce Momjian 已提交
89
#ifdef USE_SSL
90
static void printSSLInfo(void);
B
Bruce Momjian 已提交
91
#endif
92

B
> >  
Bruce Momjian 已提交
93
#ifdef WIN32
94
static void checkWin32Codepage(void);
B
> >  
Bruce Momjian 已提交
95
#endif
96 97 98

/*
 *
99
 * main
100 101 102
 *
 */
int
103
main(int argc, char *argv[])
104
{
B
Bruce Momjian 已提交
105 106 107
	struct adhoc_opts options;
	int			successResult;
	char	   *password = NULL;
B
Bruce Momjian 已提交
108
	char	   *password_prompt = NULL;
109
	bool		new_pass;
110

111
	set_pglocale_pgservice(argv[0], "psql");
P
Peter Eisentraut 已提交
112

113 114
	if (argc > 1)
	{
B
Bruce Momjian 已提交
115
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
116 117 118 119
		{
			usage();
			exit(EXIT_SUCCESS);
		}
B
Bruce Momjian 已提交
120
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
121 122 123 124
		{
			showVersion();
			exit(EXIT_SUCCESS);
		}
B
Bruce Momjian 已提交
125
	}
126

127
#ifdef WIN32
B
Bruce Momjian 已提交
128
	setvbuf(stderr, NULL, _IONBF, 0);
129
#endif
130 131 132 133 134

	setup_cancel_handler();

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

135
	pset.db = NULL;
136
	setDecimalLocale();
137 138 139
	pset.encoding = PQenv2encoding();
	pset.queryFout = stdout;
	pset.queryFoutPipe = false;
140 141
	pset.cur_cmd_source = stdin;
	pset.cur_cmd_interactive = false;
142

143 144
	pset.popt.topt.format = PRINT_ALIGNED;
	pset.popt.topt.border = 1;
145
	pset.popt.topt.pager = 1;
146 147
	pset.popt.topt.start_table = true;
	pset.popt.topt.stop_table = true;
148
	pset.popt.default_footer = true;
149

150
	pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
151

152
	/* This is obsolete and should be removed sometime. */
153
#ifdef PSQL_ALWAYS_GET_PASSWORDS
154
	pset.getPassword = true;
155
#else
156
	pset.getPassword = false;
157 158
#endif

159 160 161 162 163 164 165 166 167 168 169
	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);

170
	parse_psql_options(argc, argv, &options);
171

172
	if (!pset.popt.topt.fieldSep)
173
		pset.popt.topt.fieldSep = pg_strdup(DEFAULT_FIELD_SEP);
174
	if (!pset.popt.topt.recordSep)
175
		pset.popt.topt.recordSep = pg_strdup(DEFAULT_RECORD_SEP);
176

177
	if (options.username == NULL)
178
		password_prompt = pg_strdup(_("Password: "));
179 180
	else
	{
181
		password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
182 183 184
								 strlen(options.username) + 1);
		sprintf(password_prompt, _("Password for user %s: "),
				options.username);
185
	}
186

187
	if (pset.getPassword)
188
		password = simple_prompt(password_prompt, 100, false);
189

B
Bruce Momjian 已提交
190 191 192
	/* loop until we have a password if requested by backend */
	do
	{
193
		new_pass = false;
194
		pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
195
					options.action == ACT_LIST_DB && options.dbname == NULL ?
A
 
Andrew Dunstan 已提交
196
							   "postgres" : options.dbname,
197
							   options.username, password);
B
Bruce Momjian 已提交
198

199
		if (PQstatus(pset.db) == CONNECTION_BAD &&
200
			PQconnectionNeedsPassword(pset.db) &&
201
			password == NULL &&
202
			!feof(stdin))
B
Bruce Momjian 已提交
203
		{
204
			PQfinish(pset.db);
205
			password = simple_prompt(password_prompt, 100, false);
206
			new_pass = true;
B
Bruce Momjian 已提交
207
		}
208
	} while (new_pass);
209

B
Bruce Momjian 已提交
210
	free(password);
211
	free(password_prompt);
B
Bruce Momjian 已提交
212

213
	if (PQstatus(pset.db) == CONNECTION_BAD)
B
Bruce Momjian 已提交
214
	{
215
		fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
216
		PQfinish(pset.db);
B
Bruce Momjian 已提交
217 218 219
		exit(EXIT_BADCONN);
	}

220 221
	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);

222
	SyncVariables();
P
Peter Eisentraut 已提交
223

B
Bruce Momjian 已提交
224 225
	if (options.action == ACT_LIST_DB)
	{
226
		int			success = listAllDbs(false);
B
Bruce Momjian 已提交
227

228
		PQfinish(pset.db);
229
		exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
B
Bruce Momjian 已提交
230 231
	}

232 233 234 235
	if (options.logfilename)
	{
		pset.logfile = fopen(options.logfilename, "a");
		if (!pset.logfile)
236 237
			fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
					pset.progname, options.logfilename, strerror(errno));
238 239
	}

240
	/*
241 242
	 * Now find something to do
	 */
B
Bruce Momjian 已提交
243

244
	/*
245 246
	 * process file given by -f
	 */
247
	if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
248 249
	{
		if (!options.no_psqlrc)
250
			process_psqlrc(argv[0]);
251

B
Bruce Momjian 已提交
252
		successResult = process_file(options.action_string, options.single_txn);
253 254
	}

255
	/*
256 257
	 * process slash command if one was given to -c
	 */
B
Bruce Momjian 已提交
258
	else if (options.action == ACT_SINGLE_SLASH)
259
	{
260 261
		PsqlScanState scan_state;

262
		if (pset.echo == PSQL_ECHO_ALL)
263
			puts(options.action_string);
264

265 266 267 268 269
		scan_state = psql_scan_create();
		psql_scan_setup(scan_state,
						options.action_string,
						strlen(options.action_string));

270
		successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
271
			? EXIT_SUCCESS : EXIT_FAILURE;
272 273

		psql_scan_destroy(scan_state);
274 275
	}

276
	/*
277 278
	 * If the query given to -c was a normal one, send it
	 */
B
Bruce Momjian 已提交
279
	else if (options.action == ACT_SINGLE_QUERY)
280
	{
281
		if (pset.echo == PSQL_ECHO_ALL)
282
			puts(options.action_string);
283

284
		successResult = SendQuery(options.action_string)
285 286 287
			? EXIT_SUCCESS : EXIT_FAILURE;
	}

288
	/*
289 290
	 * or otherwise enter interactive main loop
	 */
B
Bruce Momjian 已提交
291
	else
292
	{
293 294 295
		if (!options.no_psqlrc)
			process_psqlrc(argv[0]);

296
		if (!pset.quiet && !pset.notty)
297
		{
B
Bruce Momjian 已提交
298
			int			client_ver = parse_version(PG_VERSION);
299

300
			if (pset.sversion != client_ver)
301
			{
302
				const char *server_version;
B
Bruce Momjian 已提交
303
				char		server_ver_str[16];
304

305 306 307 308 309 310 311 312 313 314 315 316 317 318
				/* Try to get full text form, might include "devel" etc */
				server_version = PQparameterStatus(pset.db, "server_version");
				if (!server_version)
				{
					snprintf(server_ver_str, sizeof(server_ver_str),
							 "%d.%d.%d",
							 pset.sversion / 10000,
							 (pset.sversion / 100) % 100,
							 pset.sversion % 100);
					server_version = server_ver_str;
				}

				printf(_("Welcome to %s %s (server %s), the PostgreSQL interactive terminal.\n\n"),
					   pset.progname, PG_VERSION, server_version);
319 320 321
			}
			else
				printf(_("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"),
322
					   pset.progname, PG_VERSION);
323 324

			printf(_("Type:  \\copyright for distribution terms\n"
B
Bruce Momjian 已提交
325 326 327 328
					 "       \\h for help with SQL commands\n"
					 "       \\? for help with psql commands\n"
				  "       \\g or terminate with semicolon to execute query\n"
					 "       \\q to quit\n\n"));
329 330 331 332 333

			if (pset.sversion / 100 != client_ver / 100)
				printf(_("WARNING:  You are connected to a server with major version %d.%d,\n"
						 "but your %s client is major version %d.%d.  Some backslash commands,\n"
						 "such as \\d, might not work properly.\n\n"),
B
Bruce Momjian 已提交
334 335 336
					   pset.sversion / 10000, (pset.sversion / 100) % 100,
					   pset.progname,
					   client_ver / 10000, (client_ver / 100) % 100);
337

B
Bruce Momjian 已提交
338
#ifdef USE_SSL
339
			printSSLInfo();
B
> >  
Bruce Momjian 已提交
340 341 342
#endif
#ifdef WIN32
			checkWin32Codepage();
B
Bruce Momjian 已提交
343
#endif
344 345
		}

346 347
		if (!pset.notty)
			initializeInput(options.no_readline ? 0 : 1);
348
		if (options.action_string)		/* -f - was used */
349
			pset.inputfile = "<stdin>";
350

P
Peter Eisentraut 已提交
351
		successResult = MainLoop(stdin);
352
	}
B
Bruce Momjian 已提交
353 354

	/* clean up */
355 356
	if (pset.logfile)
		fclose(pset.logfile);
357 358
	PQfinish(pset.db);
	setQFout(NULL);
B
Bruce Momjian 已提交
359 360

	return successResult;
361 362 363
}


364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
/*
 * Convert a version string into a number.
 */
static int
parse_version(const char *versionString)
{
	int			cnt;
	int			vmaj,
				vmin,
				vrev;

	cnt = sscanf(versionString, "%d.%d.%d", &vmaj, &vmin, &vrev);

	if (cnt < 2)
		return -1;

	if (cnt == 2)
		vrev = 0;

	return (100 * vmaj + vmin) * 100 + vrev;
}

386 387 388 389 390 391

/*
 * Parse command line options
 */

static void
392
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
393
{
394
	static struct option long_options[] =
395 396
	{
		{"echo-all", no_argument, NULL, 'a'},
B
Bruce Momjian 已提交
397 398 399
		{"no-align", no_argument, NULL, 'A'},
		{"command", required_argument, NULL, 'c'},
		{"dbname", required_argument, NULL, 'd'},
400
		{"echo-queries", no_argument, NULL, 'e'},
401
		{"echo-hidden", no_argument, NULL, 'E'},
B
Bruce Momjian 已提交
402
		{"file", required_argument, NULL, 'f'},
403
		{"field-separator", required_argument, NULL, 'F'},
B
Bruce Momjian 已提交
404 405 406
		{"host", required_argument, NULL, 'h'},
		{"html", no_argument, NULL, 'H'},
		{"list", no_argument, NULL, 'l'},
407
		{"log-file", required_argument, NULL, 'L'},
408
		{"no-readline", no_argument, NULL, 'n'},
B
Bruce Momjian 已提交
409
		{"single-transaction", no_argument, NULL, '1'},
410
		{"output", required_argument, NULL, 'o'},
B
Bruce Momjian 已提交
411 412 413
		{"port", required_argument, NULL, 'p'},
		{"pset", required_argument, NULL, 'P'},
		{"quiet", no_argument, NULL, 'q'},
414
		{"record-separator", required_argument, NULL, 'R'},
B
Bruce Momjian 已提交
415 416 417 418 419 420 421 422 423
		{"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'},
424
		{"expanded", no_argument, NULL, 'x'},
425
		{"no-psqlrc", no_argument, NULL, 'X'},
B
Bruce Momjian 已提交
426
		{"help", no_argument, NULL, '?'},
T
Tatsuo Ishii 已提交
427
		{NULL, 0, NULL, 0}
B
Bruce Momjian 已提交
428 429 430 431 432 433
	};

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

435
	memset(options, 0, sizeof *options);
436

437
	while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VWxX?1",
438
							long_options, &optindex)) != -1)
439
	{
B
Bruce Momjian 已提交
440 441
		switch (c)
		{
442 443 444
			case 'a':
				SetVariable(pset.vars, "ECHO", "all");
				break;
B
Bruce Momjian 已提交
445
			case 'A':
446
				pset.popt.topt.format = PRINT_UNALIGNED;
B
Bruce Momjian 已提交
447 448 449 450
				break;
			case 'c':
				options->action_string = optarg;
				if (optarg[0] == '\\')
P
Peter Eisentraut 已提交
451
				{
B
Bruce Momjian 已提交
452
					options->action = ACT_SINGLE_SLASH;
P
Peter Eisentraut 已提交
453 454
					options->action_string++;
				}
B
Bruce Momjian 已提交
455 456 457 458 459 460 461
				else
					options->action = ACT_SINGLE_QUERY;
				break;
			case 'd':
				options->dbname = optarg;
				break;
			case 'e':
462
				SetVariable(pset.vars, "ECHO", "queries");
B
Bruce Momjian 已提交
463 464
				break;
			case 'E':
465
				SetVariableBool(pset.vars, "ECHO_HIDDEN");
B
Bruce Momjian 已提交
466 467 468 469 470 471
				break;
			case 'f':
				options->action = ACT_FILE;
				options->action_string = optarg;
				break;
			case 'F':
472
				pset.popt.topt.fieldSep = pg_strdup(optarg);
B
Bruce Momjian 已提交
473 474 475 476 477
				break;
			case 'h':
				options->host = optarg;
				break;
			case 'H':
478
				pset.popt.topt.format = PRINT_HTML;
B
Bruce Momjian 已提交
479 480 481 482
				break;
			case 'l':
				options->action = ACT_LIST_DB;
				break;
483 484 485
			case 'L':
				options->logfilename = optarg;
				break;
B
Bruce Momjian 已提交
486 487 488 489
			case 'n':
				options->no_readline = true;
				break;
			case 'o':
490
				setQFout(optarg);
B
Bruce Momjian 已提交
491 492 493 494 495 496 497 498 499 500
				break;
			case 'p':
				options->port = optarg;
				break;
			case 'P':
				{
					char	   *value;
					char	   *equal_loc;
					bool		result;

501
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
502 503
					equal_loc = strchr(value, '=');
					if (!equal_loc)
504
						result = do_pset(value, NULL, &pset.popt, true);
B
Bruce Momjian 已提交
505 506 507
					else
					{
						*equal_loc = '\0';
508
						result = do_pset(value, equal_loc + 1, &pset.popt, true);
B
Bruce Momjian 已提交
509 510 511 512
					}

					if (!result)
					{
513
						fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
B
Bruce Momjian 已提交
514 515 516 517 518 519 520
						exit(EXIT_FAILURE);
					}

					free(value);
					break;
				}
			case 'q':
521
				SetVariableBool(pset.vars, "QUIET");
B
Bruce Momjian 已提交
522
				break;
523
			case 'R':
524
				pset.popt.topt.recordSep = pg_strdup(optarg);
525
				break;
B
Bruce Momjian 已提交
526
			case 's':
527
				SetVariableBool(pset.vars, "SINGLESTEP");
B
Bruce Momjian 已提交
528 529
				break;
			case 'S':
530
				SetVariableBool(pset.vars, "SINGLELINE");
B
Bruce Momjian 已提交
531 532
				break;
			case 't':
533
				pset.popt.topt.tuples_only = true;
B
Bruce Momjian 已提交
534 535
				break;
			case 'T':
536
				pset.popt.topt.tableAttr = pg_strdup(optarg);
B
Bruce Momjian 已提交
537 538 539 540 541 542 543 544 545
				break;
			case 'U':
				options->username = optarg;
				break;
			case 'v':
				{
					char	   *value;
					char	   *equal_loc;

546
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
547 548 549
					equal_loc = strchr(value, '=');
					if (!equal_loc)
					{
550
						if (!DeleteVariable(pset.vars, value))
B
Bruce Momjian 已提交
551
						{
552
							fprintf(stderr, _("%s: could not delete variable \"%s\"\n"),
553
									pset.progname, value);
B
Bruce Momjian 已提交
554 555 556 557 558 559
							exit(EXIT_FAILURE);
						}
					}
					else
					{
						*equal_loc = '\0';
560
						if (!SetVariable(pset.vars, value, equal_loc + 1))
B
Bruce Momjian 已提交
561
						{
562
							fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
563
									pset.progname, value);
B
Bruce Momjian 已提交
564 565 566 567 568 569 570 571
							exit(EXIT_FAILURE);
						}
					}

					free(value);
					break;
				}
			case 'V':
572 573
				showVersion();
				exit(EXIT_SUCCESS);
B
Bruce Momjian 已提交
574
			case 'W':
575
				pset.getPassword = true;
B
Bruce Momjian 已提交
576
				break;
577 578 579
			case 'x':
				pset.popt.topt.expanded = true;
				break;
580 581 582
			case 'X':
				options->no_psqlrc = true;
				break;
B
Bruce Momjian 已提交
583 584 585
			case '1':
				options->single_txn = true;
				break;
B
Bruce Momjian 已提交
586
			case '?':
587 588 589 590 591 592 593 594 595
				/* 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
				{
596
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
597
							pset.progname);
598
					exit(EXIT_FAILURE);
599
				}
B
Bruce Momjian 已提交
600 601
				break;
			default:
602
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
603
						pset.progname);
604
				exit(EXIT_FAILURE);
B
Bruce Momjian 已提交
605 606
				break;
		}
607 608
	}

B
Bruce Momjian 已提交
609
	/*
B
Bruce Momjian 已提交
610
	 * if we still have arguments, use it as the database name and username
B
Bruce Momjian 已提交
611 612 613 614 615 616 617
	 */
	while (argc - optind >= 1)
	{
		if (!options->dbname)
			options->dbname = argv[optind];
		else if (!options->username)
			options->username = argv[optind];
618
		else if (!pset.quiet)
619
			fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
620
					pset.progname, argv[optind]);
B
Bruce Momjian 已提交
621 622 623

		optind++;
	}
624 625 626 627
}


/*
P
Peter Eisentraut 已提交
628
 * Load .psqlrc file, if found.
629 630
 */
static void
631
process_psqlrc(char *argv0)
632
{
B
Bruce Momjian 已提交
633
	char		home[MAXPGPATH];
634
	char		rc_file[MAXPGPATH];
B
Bruce Momjian 已提交
635 636
	char		my_exec_path[MAXPGPATH];
	char		etc_path[MAXPGPATH];
637 638 639

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

641 642
	snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
	process_psqlrc_file(rc_file);
643

644
	if (get_home_path(home))
645
	{
646 647
		snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
		process_psqlrc_file(rc_file);
648 649 650 651 652 653 654 655 656
	}
}



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

658 659
#if defined(WIN32) && (!defined(__MINGW32__))
#define R_OK 4
660 661
#endif

662 663
	psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
	sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
664

665
	if (access(psqlrc, R_OK) == 0)
B
Bruce Momjian 已提交
666
		(void) process_file(psqlrc, false);
667
	else if (access(filename, R_OK) == 0)
B
Bruce Momjian 已提交
668
		(void) process_file(filename, false);
669
	free(psqlrc);
670 671 672 673 674 675
}



/* showVersion
 *
676
 * This output format is intended to match GNU standards.
677 678
 */
static void
679
showVersion(void)
680
{
681
	puts("psql (PostgreSQL) " PG_VERSION);
682

683
#if defined(USE_READLINE)
684
	puts(_("contains support for command-line editing"));
685
#endif
686
}
B
Bruce Momjian 已提交
687 688 689 690 691 692 693 694 695



/*
 * printSSLInfo
 *
 * Prints information about the current SSL connection, if SSL is in use
 */
#ifdef USE_SSL
B
Bruce Momjian 已提交
696
static void
B
Bruce Momjian 已提交
697 698
printSSLInfo(void)
{
B
Bruce Momjian 已提交
699 700
	int			sslbits = -1;
	SSL		   *ssl;
B
Bruce Momjian 已提交
701 702 703

	ssl = PQgetssl(pset.db);
	if (!ssl)
B
Bruce Momjian 已提交
704
		return;					/* no SSL */
B
Bruce Momjian 已提交
705 706

	SSL_get_cipher_bits(ssl, &sslbits);
707
	printf(_("SSL connection (cipher: %s, bits: %i)\n\n"),
B
Bruce Momjian 已提交
708
		   SSL_get_cipher(ssl), sslbits);
B
Bruce Momjian 已提交
709 710
}
#endif
B
> >  
Bruce Momjian 已提交
711 712 713 714 715 716 717 718 719 720 721


/*
 * checkWin32Codepage
 *
 * Prints a warning when win32 console codepage differs from Windows codepage
 */
#ifdef WIN32
static void
checkWin32Codepage(void)
{
B
Bruce Momjian 已提交
722 723
	unsigned int wincp,
				concp;
B
> >  
Bruce Momjian 已提交
724 725 726

	wincp = GetACP();
	concp = GetConsoleCP();
B
Bruce Momjian 已提交
727 728
	if (wincp != concp)
	{
B
Bruce Momjian 已提交
729
		printf(_("Warning: Console code page (%u) differs from Windows code page (%u)\n"
730
				 "         8-bit characters might not work correctly. See psql reference\n"
B
Bruce Momjian 已提交
731
			   "         page \"Notes for Windows users\" for details.\n\n"),
B
Bruce Momjian 已提交
732
			   concp, wincp);
B
> >  
Bruce Momjian 已提交
733 734 735
	}
}
#endif
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773


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

774 775 776 777 778 779
static void
fetch_count_hook(const char *newval)
{
	pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
}

780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
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);
881
	SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
882 883 884 885 886 887 888 889 890
	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);
}