startup.c 20.2 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.136 2006/08/29 15:19:51 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
	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

B
Bruce Momjian 已提交
177 178
	if (options.username)
	{
179
		/*
B
Bruce Momjian 已提交
180 181 182
		 * 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.
183
		 */
184
		if (strcmp(options.username, "\001") == 0)
185
			username = simple_prompt("User name: ", 100, true);
B
Bruce Momjian 已提交
186
		else
187
			username = pg_strdup(options.username);
188 189
	}

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

199
	if (pset.getPassword)
200
		password = simple_prompt(password_prompt, 100, false);
201

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		psql_scan_destroy(scan_state);
288 289
	}

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

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

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

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

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

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

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

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

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

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

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

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

	return successResult;
375 376 377
}


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

400 401 402 403 404 405

/*
 * Parse command line options
 */

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

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

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

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

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

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

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

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

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

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

		optind++;
	}
646

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

650 651 652 653
}


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

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

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

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



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

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

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

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



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

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



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

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

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


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

	wincp = GetACP();
	concp = GetConsoleCP();
B
Bruce Momjian 已提交
753 754
	if (wincp != concp)
	{
B
Bruce Momjian 已提交
755 756 757
		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 已提交
758
			   concp, wincp);
B
> >  
Bruce Momjian 已提交
759 760
	}
}
B
Bruce Momjian 已提交
761

B
> >  
Bruce Momjian 已提交
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 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 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 910


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

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