startup.c 19.7 KB
Newer Older
P
Peter Eisentraut 已提交
1 2 3
/*
 * psql - the PostgreSQL interactive terminal
 *
4
 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
P
Peter Eisentraut 已提交
5
 *
6
 * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.146 2008/01/01 19:45:56 momjian 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
	/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
144 145
	pset.popt.topt.format = PRINT_ALIGNED;
	pset.popt.topt.border = 1;
146
	pset.popt.topt.pager = 1;
147 148
	pset.popt.topt.start_table = true;
	pset.popt.topt.stop_table = true;
149
	pset.popt.default_footer = true;
150

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		psql_scan_destroy(scan_state);
275 276
	}

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

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

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

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

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

306 307 308 309 310 311 312 313 314 315 316 317 318 319
				/* 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);
320 321 322
			}
			else
				printf(_("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"),
323
					   pset.progname, PG_VERSION);
324 325

			printf(_("Type:  \\copyright for distribution terms\n"
B
Bruce Momjian 已提交
326 327 328 329
					 "       \\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"));
330 331 332 333 334

			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 已提交
335 336 337
					   pset.sversion / 10000, (pset.sversion / 100) % 100,
					   pset.progname,
					   client_ver / 10000, (client_ver / 100) % 100);
338

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

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

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

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

	return successResult;
362 363 364
}


365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
/*
 * 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;
}

387 388 389 390 391 392

/*
 * Parse command line options
 */

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

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

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

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

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

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

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

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

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

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

		optind++;
	}
625 626 627 628
}


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

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

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

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



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

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

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

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



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

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



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

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

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


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

	wincp = GetACP();
	concp = GetConsoleCP();
B
Bruce Momjian 已提交
728 729
	if (wincp != concp)
	{
B
Bruce Momjian 已提交
730
		printf(_("Warning: Console code page (%u) differs from Windows code page (%u)\n"
731
				 "         8-bit characters might not work correctly. See psql reference\n"
B
Bruce Momjian 已提交
732
			   "         page \"Notes for Windows users\" for details.\n\n"),
B
Bruce Momjian 已提交
733
			   concp, wincp);
B
> >  
Bruce Momjian 已提交
734 735 736
	}
}
#endif
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 774


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

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

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 881
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);
882
	SetVariableAssignHook(pset.vars, "FETCH_COUNT", fetch_count_hook);
883 884 885 886 887 888 889 890 891
	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);
}