startup.c 20.4 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.141 2007/07/08 19:07:38 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;
111
	bool		new_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
	/* loop until we have a password if requested by backend */
	do
	{
207
		new_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 215
			PQconnectionUsedPassword(pset.db) &&
			password == NULL &&
216
			!feof(stdin))
B
Bruce Momjian 已提交
217
		{
218
			PQfinish(pset.db);
219
			password = simple_prompt(password_prompt, 100, false);
220
			new_pass = true;
B
Bruce Momjian 已提交
221
		}
222
	} while (new_pass);
223

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		psql_scan_destroy(scan_state);
289 290
	}

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

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

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

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

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

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

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

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

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

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

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

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

	return successResult;
376 377 378
}


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

401 402 403 404 405 406

/*
 * Parse command line options
 */

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

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

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

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

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

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

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

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

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

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

		optind++;
	}
647

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

651 652 653 654
}


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

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

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

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



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

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

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

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



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

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



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

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

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


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

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


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

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

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 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
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);
908
	SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
909 910 911 912 913 914 915 916 917
	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);
}