startup.c 20.4 KB
Newer Older
P
Peter Eisentraut 已提交
1 2 3
/*
 * psql - the PostgreSQL interactive terminal
 *
4
 * Copyright (c) 2000-2006, PostgreSQL Global Development Group
P
Peter Eisentraut 已提交
5
 *
6
 * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.137 2006/08/29 22:25:08 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
	struct adhoc_opts options;
	int			successResult;
107

B
Bruce Momjian 已提交
108 109
	char	   *username = NULL;
	char	   *password = NULL;
B
Bruce Momjian 已提交
110
	char	   *password_prompt = NULL;
B
Bruce Momjian 已提交
111
	bool		need_pass;
112

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

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

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

	setup_cancel_handler();

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

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

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

152
	pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
153

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

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

172
	parse_psql_options(argc, argv, &options);
173

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

B
Bruce Momjian 已提交
179 180
	if (options.username)
	{
181
		/*
B
Bruce Momjian 已提交
182 183 184
		 * The \001 is a hack to support the deprecated -u option which issues
		 * a username prompt. The recommended option is -U followed by the
		 * name on the command line.
185
		 */
186
		if (strcmp(options.username, "\001") == 0)
187
			username = simple_prompt("User name: ", 100, true);
B
Bruce Momjian 已提交
188
		else
189
			username = pg_strdup(options.username);
190 191
	}

192
	if (options.username == NULL)
193
		password_prompt = pg_strdup(_("Password: "));
194 195
	else
	{
196
		password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
197
								 strlen(options.username) + 1);
198
		sprintf(password_prompt, _("Password for user %s: "), options.username);
199
	}
200

201
	if (pset.getPassword)
202
		password = simple_prompt(password_prompt, 100, false);
203

B
Bruce Momjian 已提交
204 205 206 207
	/* loop until we have a password if requested by backend */
	do
	{
		need_pass = false;
208
		pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
209
					options.action == ACT_LIST_DB && options.dbname == NULL ?
A
 
Andrew Dunstan 已提交
210
							   "postgres" : options.dbname,
211
							   username, password);
B
Bruce Momjian 已提交
212

213
		if (PQstatus(pset.db) == CONNECTION_BAD &&
214
			strcmp(PQerrorMessage(pset.db), PQnoPasswordSupplied) == 0 &&
215
			!feof(stdin))
B
Bruce Momjian 已提交
216
		{
217
			PQfinish(pset.db);
B
Bruce Momjian 已提交
218 219 220
			need_pass = true;
			free(password);
			password = NULL;
221
			password = simple_prompt(password_prompt, 100, false);
B
Bruce Momjian 已提交
222 223
		}
	} while (need_pass);
224

B
Bruce Momjian 已提交
225 226
	free(username);
	free(password);
227
	free(password_prompt);
B
Bruce Momjian 已提交
228

229
	if (PQstatus(pset.db) == CONNECTION_BAD)
B
Bruce Momjian 已提交
230
	{
231
		fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
232
		PQfinish(pset.db);
B
Bruce Momjian 已提交
233 234 235
		exit(EXIT_BADCONN);
	}

236 237
	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);

238
	SyncVariables();
P
Peter Eisentraut 已提交
239

B
Bruce Momjian 已提交
240 241
	if (options.action == ACT_LIST_DB)
	{
242
		int			success = listAllDbs(false);
B
Bruce Momjian 已提交
243

244
		PQfinish(pset.db);
245
		exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
B
Bruce Momjian 已提交
246 247
	}

248 249 250 251
	if (options.logfilename)
	{
		pset.logfile = fopen(options.logfilename, "a");
		if (!pset.logfile)
252 253
			fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
					pset.progname, options.logfilename, strerror(errno));
254 255
	}

256
	/*
257 258
	 * Now find something to do
	 */
B
Bruce Momjian 已提交
259

260
	/*
261 262
	 * process file given by -f
	 */
263
	if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
264 265
	{
		if (!options.no_psqlrc)
266
			process_psqlrc(argv[0]);
267

B
Bruce Momjian 已提交
268
		successResult = process_file(options.action_string, options.single_txn);
269 270
	}

271
	/*
272 273
	 * process slash command if one was given to -c
	 */
B
Bruce Momjian 已提交
274
	else if (options.action == ACT_SINGLE_SLASH)
275
	{
276 277
		PsqlScanState scan_state;

278
		if (pset.echo == PSQL_ECHO_ALL)
279
			puts(options.action_string);
280

281 282 283 284 285
		scan_state = psql_scan_create();
		psql_scan_setup(scan_state,
						options.action_string,
						strlen(options.action_string));

286
		successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
287
			? EXIT_SUCCESS : EXIT_FAILURE;
288 289

		psql_scan_destroy(scan_state);
290 291
	}

292
	/*
293 294
	 * If the query given to -c was a normal one, send it
	 */
B
Bruce Momjian 已提交
295
	else if (options.action == ACT_SINGLE_QUERY)
296
	{
297
		if (pset.echo == PSQL_ECHO_ALL)
298
			puts(options.action_string);
299

300
		successResult = SendQuery(options.action_string)
301 302 303
			? EXIT_SUCCESS : EXIT_FAILURE;
	}

304
	/*
305 306
	 * or otherwise enter interactive main loop
	 */
B
Bruce Momjian 已提交
307
	else
308
	{
309 310 311
		if (!options.no_psqlrc)
			process_psqlrc(argv[0]);

312
		if (!pset.quiet && !pset.notty)
313
		{
B
Bruce Momjian 已提交
314
			int			client_ver = parse_version(PG_VERSION);
315

316
			if (pset.sversion != client_ver)
317
			{
318
				const char *server_version;
B
Bruce Momjian 已提交
319
				char		server_ver_str[16];
320

321 322 323 324 325 326 327 328 329 330 331 332 333 334
				/* 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);
335 336 337
			}
			else
				printf(_("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"),
338
					   pset.progname, PG_VERSION);
339 340

			printf(_("Type:  \\copyright for distribution terms\n"
B
Bruce Momjian 已提交
341 342 343 344
					 "       \\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"));
345 346 347 348 349

			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 已提交
350 351 352
					   pset.sversion / 10000, (pset.sversion / 100) % 100,
					   pset.progname,
					   client_ver / 10000, (client_ver / 100) % 100);
353

B
Bruce Momjian 已提交
354
#ifdef USE_SSL
355
			printSSLInfo();
B
> >  
Bruce Momjian 已提交
356 357 358
#endif
#ifdef WIN32
			checkWin32Codepage();
B
Bruce Momjian 已提交
359
#endif
360 361
		}

362 363
		if (!pset.notty)
			initializeInput(options.no_readline ? 0 : 1);
364
		if (options.action_string)		/* -f - was used */
365
			pset.inputfile = "<stdin>";
366

P
Peter Eisentraut 已提交
367
		successResult = MainLoop(stdin);
368
	}
B
Bruce Momjian 已提交
369 370

	/* clean up */
371 372
	if (pset.logfile)
		fclose(pset.logfile);
373 374
	PQfinish(pset.db);
	setQFout(NULL);
B
Bruce Momjian 已提交
375 376

	return successResult;
377 378 379
}


380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
/*
 * 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;
}

402 403 404 405 406 407

/*
 * Parse command line options
 */

static void
408
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
409
{
410
	static struct option long_options[] =
411 412
	{
		{"echo-all", no_argument, NULL, 'a'},
B
Bruce Momjian 已提交
413 414 415
		{"no-align", no_argument, NULL, 'A'},
		{"command", required_argument, NULL, 'c'},
		{"dbname", required_argument, NULL, 'd'},
416
		{"echo-queries", no_argument, NULL, 'e'},
417
		{"echo-hidden", no_argument, NULL, 'E'},
B
Bruce Momjian 已提交
418
		{"file", required_argument, NULL, 'f'},
419
		{"field-separator", required_argument, NULL, 'F'},
B
Bruce Momjian 已提交
420 421 422
		{"host", required_argument, NULL, 'h'},
		{"html", no_argument, NULL, 'H'},
		{"list", no_argument, NULL, 'l'},
423
		{"log-file", required_argument, NULL, 'L'},
424
		{"no-readline", no_argument, NULL, 'n'},
B
Bruce Momjian 已提交
425
		{"single-transaction", no_argument, NULL, '1'},
426
		{"output", required_argument, NULL, 'o'},
B
Bruce Momjian 已提交
427 428 429
		{"port", required_argument, NULL, 'p'},
		{"pset", required_argument, NULL, 'P'},
		{"quiet", no_argument, NULL, 'q'},
430
		{"record-separator", required_argument, NULL, 'R'},
B
Bruce Momjian 已提交
431 432 433 434 435 436 437 438 439
		{"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'},
440
		{"expanded", no_argument, NULL, 'x'},
441
		{"no-psqlrc", no_argument, NULL, 'X'},
B
Bruce Momjian 已提交
442
		{"help", no_argument, NULL, '?'},
T
Tatsuo Ishii 已提交
443
		{NULL, 0, NULL, 0}
B
Bruce Momjian 已提交
444 445 446 447 448 449
	};

	int			optindex;
	extern char *optarg;
	extern int	optind;
	int			c;
450
	bool		used_old_u_option = false;
451

452
	memset(options, 0, sizeof *options);
453

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

518
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
519 520
					equal_loc = strchr(value, '=');
					if (!equal_loc)
521
						result = do_pset(value, NULL, &pset.popt, true);
B
Bruce Momjian 已提交
522 523 524
					else
					{
						*equal_loc = '\0';
525
						result = do_pset(value, equal_loc + 1, &pset.popt, true);
B
Bruce Momjian 已提交
526 527 528 529
					}

					if (!result)
					{
530
						fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
B
Bruce Momjian 已提交
531 532 533 534 535 536 537
						exit(EXIT_FAILURE);
					}

					free(value);
					break;
				}
			case 'q':
538
				SetVariableBool(pset.vars, "QUIET");
B
Bruce Momjian 已提交
539
				break;
540
			case 'R':
541
				pset.popt.topt.recordSep = pg_strdup(optarg);
542
				break;
B
Bruce Momjian 已提交
543
			case 's':
544
				SetVariableBool(pset.vars, "SINGLESTEP");
B
Bruce Momjian 已提交
545 546
				break;
			case 'S':
547
				SetVariableBool(pset.vars, "SINGLELINE");
B
Bruce Momjian 已提交
548 549
				break;
			case 't':
550
				pset.popt.topt.tuples_only = true;
B
Bruce Momjian 已提交
551 552
				break;
			case 'T':
553
				pset.popt.topt.tableAttr = pg_strdup(optarg);
B
Bruce Momjian 已提交
554 555
				break;
			case 'u':
556
				pset.getPassword = true;
B
Bruce Momjian 已提交
557 558
				options->username = "\001";		/* hopefully nobody has that
												 * username */
559 560
				/* this option is out */
				used_old_u_option = true;
B
Bruce Momjian 已提交
561 562 563 564 565 566 567 568 569
				break;
			case 'U':
				options->username = optarg;
				break;
			case 'v':
				{
					char	   *value;
					char	   *equal_loc;

570
					value = pg_strdup(optarg);
B
Bruce Momjian 已提交
571 572 573
					equal_loc = strchr(value, '=');
					if (!equal_loc)
					{
574
						if (!DeleteVariable(pset.vars, value))
B
Bruce Momjian 已提交
575
						{
576
							fprintf(stderr, _("%s: could not delete variable \"%s\"\n"),
577
									pset.progname, value);
B
Bruce Momjian 已提交
578 579 580 581 582 583
							exit(EXIT_FAILURE);
						}
					}
					else
					{
						*equal_loc = '\0';
584
						if (!SetVariable(pset.vars, value, equal_loc + 1))
B
Bruce Momjian 已提交
585
						{
586
							fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
587
									pset.progname, value);
B
Bruce Momjian 已提交
588 589 590 591 592 593 594 595
							exit(EXIT_FAILURE);
						}
					}

					free(value);
					break;
				}
			case 'V':
596 597
				showVersion();
				exit(EXIT_SUCCESS);
B
Bruce Momjian 已提交
598
			case 'W':
599
				pset.getPassword = true;
B
Bruce Momjian 已提交
600
				break;
601 602 603
			case 'x':
				pset.popt.topt.expanded = true;
				break;
604 605 606
			case 'X':
				options->no_psqlrc = true;
				break;
B
Bruce Momjian 已提交
607 608 609
			case '1':
				options->single_txn = true;
				break;
B
Bruce Momjian 已提交
610
			case '?':
611 612 613 614 615 616 617 618 619
				/* 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
				{
620
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
621
							pset.progname);
622
					exit(EXIT_FAILURE);
623
				}
B
Bruce Momjian 已提交
624 625
				break;
			default:
626
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
627
						pset.progname);
628
				exit(EXIT_FAILURE);
B
Bruce Momjian 已提交
629 630
				break;
		}
631 632
	}

B
Bruce Momjian 已提交
633
	/*
B
Bruce Momjian 已提交
634
	 * if we still have arguments, use it as the database name and username
B
Bruce Momjian 已提交
635 636 637 638 639 640 641
	 */
	while (argc - optind >= 1)
	{
		if (!options->dbname)
			options->dbname = argv[optind];
		else if (!options->username)
			options->username = argv[optind];
642
		else if (!pset.quiet)
643
			fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
644
					pset.progname, argv[optind]);
B
Bruce Momjian 已提交
645 646 647

		optind++;
	}
648

649
	if (used_old_u_option && !pset.quiet)
650
		fprintf(stderr, _("%s: Warning: The -u option is deprecated. Use -U.\n"), pset.progname);
651

652 653 654 655
}


/*
P
Peter Eisentraut 已提交
656
 * Load .psqlrc file, if found.
657 658
 */
static void
659
process_psqlrc(char *argv0)
660
{
B
Bruce Momjian 已提交
661
	char		home[MAXPGPATH];
662
	char		rc_file[MAXPGPATH];
B
Bruce Momjian 已提交
663 664
	char		my_exec_path[MAXPGPATH];
	char		etc_path[MAXPGPATH];
665 666 667

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

669 670
	snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
	process_psqlrc_file(rc_file);
671

672
	if (get_home_path(home))
673
	{
674 675
		snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
		process_psqlrc_file(rc_file);
676 677 678 679 680 681 682 683 684
	}
}



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

686 687
#if defined(WIN32) && (!defined(__MINGW32__))
#define R_OK 4
688 689
#endif

690 691
	psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
	sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
692

693
	if (access(psqlrc, R_OK) == 0)
B
Bruce Momjian 已提交
694
		(void) process_file(psqlrc, false);
695
	else if (access(filename, R_OK) == 0)
B
Bruce Momjian 已提交
696
		(void) process_file(filename, false);
697
	free(psqlrc);
698 699 700 701 702 703
}



/* showVersion
 *
704
 * This output format is intended to match GNU standards.
705 706
 */
static void
707
showVersion(void)
708
{
709
	puts("psql (PostgreSQL) " PG_VERSION);
710

711
#if defined(USE_READLINE)
712
	puts(_("contains support for command-line editing"));
713
#endif
714
}
B
Bruce Momjian 已提交
715 716 717 718 719 720 721 722 723



/*
 * printSSLInfo
 *
 * Prints information about the current SSL connection, if SSL is in use
 */
#ifdef USE_SSL
B
Bruce Momjian 已提交
724
static void
B
Bruce Momjian 已提交
725 726
printSSLInfo(void)
{
B
Bruce Momjian 已提交
727 728
	int			sslbits = -1;
	SSL		   *ssl;
B
Bruce Momjian 已提交
729 730 731

	ssl = PQgetssl(pset.db);
	if (!ssl)
B
Bruce Momjian 已提交
732
		return;					/* no SSL */
B
Bruce Momjian 已提交
733 734

	SSL_get_cipher_bits(ssl, &sslbits);
735
	printf(_("SSL connection (cipher: %s, bits: %i)\n\n"),
B
Bruce Momjian 已提交
736
		   SSL_get_cipher(ssl), sslbits);
B
Bruce Momjian 已提交
737 738
}
#endif
B
> >  
Bruce Momjian 已提交
739 740 741 742 743 744 745 746 747 748 749


/*
 * checkWin32Codepage
 *
 * Prints a warning when win32 console codepage differs from Windows codepage
 */
#ifdef WIN32
static void
checkWin32Codepage(void)
{
B
Bruce Momjian 已提交
750 751
	unsigned int wincp,
				concp;
B
> >  
Bruce Momjian 已提交
752 753 754

	wincp = GetACP();
	concp = GetConsoleCP();
B
Bruce Momjian 已提交
755 756
	if (wincp != concp)
	{
B
Bruce Momjian 已提交
757 758 759
		printf(_("Warning: Console code page (%u) differs from Windows code page (%u)\n"
				 "         8-bit characters may not work correctly. See psql reference\n"
			   "         page \"Notes for Windows users\" for details.\n\n"),
B
Bruce Momjian 已提交
760
			   concp, wincp);
B
> >  
Bruce Momjian 已提交
761 762
	}
}
B
Bruce Momjian 已提交
763

B
> >  
Bruce Momjian 已提交
764
#endif
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802


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

803 804 805 806 807 808
static void
fetch_count_hook(const char *newval)
{
	pset.fetch_count = ParseVariableNum(newval, -1, -1, false);
}

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 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
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);
910
	SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
911 912 913 914 915 916 917 918 919
	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);
}