Support PGXS.
This commit is contained in:
		
							
								
								
									
										467
									
								
								bin/pgut/pgut.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										467
									
								
								bin/pgut/pgut.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,467 @@ | ||||
| /* | ||||
|  * pgut.c | ||||
|  * | ||||
|  * Copyright (c) 2009, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | ||||
|  */ | ||||
| #include "pgut.h" | ||||
|  | ||||
| #include "postgres_fe.h" | ||||
| #include "libpq/pqsignal.h" | ||||
|  | ||||
| #include <unistd.h> | ||||
|  | ||||
| const char *progname = NULL; | ||||
| const char *dbname = NULL; | ||||
| char	   *host = NULL; | ||||
| char	   *port = NULL; | ||||
| char	   *username = NULL; | ||||
| pqbool		password = false; | ||||
|  | ||||
| /* Interrupted by SIGINT (Ctrl+C) ? */ | ||||
| pqbool		interrupted = false; | ||||
|  | ||||
| /* Database connections */ | ||||
| PGconn	   *current_conn = NULL; | ||||
| static PGcancel *volatile cancel_conn = NULL; | ||||
|  | ||||
| /* Connection routines */ | ||||
| static void init_cancel_handler(void); | ||||
| static void on_before_exec(PGconn *conn); | ||||
| static void on_after_exec(void); | ||||
| static void on_interrupt(void); | ||||
| static void on_exit(void); | ||||
| static void exit_or_abort(int exitcode); | ||||
| const char *get_user_name(const char *progname); | ||||
|  | ||||
| const char default_optstring[] = "d:h:p:U:W"; | ||||
|  | ||||
| const struct option default_longopts[] = | ||||
| { | ||||
| 	{"dbname", required_argument, NULL, 'd'}, | ||||
| 	{"host", required_argument, NULL, 'h'}, | ||||
| 	{"port", required_argument, NULL, 'p'}, | ||||
| 	{"username", required_argument, NULL, 'U'}, | ||||
| 	{"password", no_argument, NULL, 'W'}, | ||||
| 	{NULL, 0, NULL, 0} | ||||
| }; | ||||
|  | ||||
| static const char * | ||||
| merge_optstring(const char *opts) | ||||
| { | ||||
| 	size_t	len; | ||||
| 	char   *result; | ||||
|  | ||||
| 	if (opts == NULL) | ||||
| 		return default_optstring; | ||||
|  | ||||
| 	len = strlen(opts); | ||||
| 	if (len == 0) | ||||
| 		return default_optstring; | ||||
|  | ||||
| 	result = malloc(len + lengthof(default_optstring)); | ||||
| 	memcpy(&result[0], opts, len); | ||||
| 	memcpy(&result[len], default_optstring, lengthof(default_optstring)); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| static const struct option * | ||||
| merge_longopts(const struct option *opts) | ||||
| { | ||||
| 	size_t	len; | ||||
| 	struct option *result; | ||||
|  | ||||
| 	if (opts == NULL) | ||||
| 		return default_longopts; | ||||
|  | ||||
| 	for (len = 0; opts[len].name; len++) { } | ||||
| 	if (len == 0) | ||||
| 		return default_longopts; | ||||
|  | ||||
| 	result = (struct option *) malloc((len + lengthof(default_longopts)) * sizeof(struct option)); | ||||
| 	memcpy(&result[0], opts, len * sizeof(struct option)); | ||||
| 	memcpy(&result[len], default_longopts, lengthof(default_longopts) * sizeof(struct option)); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| int | ||||
| pgut_getopt(int argc, char **argv) | ||||
| { | ||||
| 	const char			   *optstring; | ||||
| 	const struct option	   *longopts; | ||||
|  | ||||
| 	int		c; | ||||
| 	int		optindex = 0; | ||||
|  | ||||
| 	progname = get_progname(argv[0]); | ||||
| 	set_pglocale_pgservice(argv[0], "pgscripts"); | ||||
|  | ||||
| 	/* | ||||
| 	 * Help message and version are handled at first. | ||||
| 	 */ | ||||
| 	if (argc > 1) | ||||
| 	{ | ||||
| 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) | ||||
| 			return pgut_help(); | ||||
| 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) | ||||
| 			return pgut_version(); | ||||
| 	} | ||||
|  | ||||
| 	optstring = merge_optstring(pgut_optstring); | ||||
| 	longopts = merge_longopts(pgut_longopts); | ||||
|  | ||||
| 	while ((c = getopt_long(argc, argv, optstring, longopts, &optindex)) != -1) | ||||
| 	{ | ||||
| 		switch (c) | ||||
| 		{ | ||||
| 		case 'h': | ||||
| 			host = optarg; | ||||
| 			break; | ||||
| 		case 'p': | ||||
| 			port = optarg; | ||||
| 			break; | ||||
| 		case 'U': | ||||
| 			username = optarg; | ||||
| 			break; | ||||
| 		case 'W': | ||||
| 			password = true; | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 			dbname = optarg; | ||||
| 			break; | ||||
| 		default: | ||||
| 			if (!pgut_argument(c, optarg)) | ||||
| 			{ | ||||
| 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); | ||||
| 				exit_or_abort(EXITCODE_ERROR); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for (; optind < argc; optind++) | ||||
| 	{ | ||||
| 		if (!pgut_argument(0, argv[optind])) | ||||
| 		{ | ||||
| 			fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), | ||||
| 					progname, argv[optind]); | ||||
| 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); | ||||
| 			exit_or_abort(EXITCODE_ERROR); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	init_cancel_handler(); | ||||
| 	atexit(on_exit); | ||||
|  | ||||
| 	(void) (dbname || | ||||
| 	(dbname = getenv("PGDATABASE")) || | ||||
| 	(dbname = getenv("PGUSER")) || | ||||
| 	(dbname = get_user_name(progname))); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| reconnect(void) | ||||
| { | ||||
| 	PGconn	   *conn; | ||||
| 	char	   *pwd = NULL; | ||||
| 	bool		new_pass; | ||||
|  | ||||
| 	disconnect(); | ||||
|  | ||||
| 	if (password) | ||||
| 		pwd = simple_prompt("Password: ", 100, false); | ||||
|  | ||||
| 	/* | ||||
| 	 * Start the connection.  Loop until we have a password if requested by | ||||
| 	 * backend. | ||||
| 	 */ | ||||
| 	do | ||||
| 	{ | ||||
| 		new_pass = false; | ||||
| 		conn = PQsetdbLogin(host, port, NULL, NULL, dbname, username, pwd); | ||||
|  | ||||
| 		if (!conn) | ||||
| 		{ | ||||
| 			fprintf(stderr, _("%s: could not connect to database %s\n"), | ||||
| 					progname, dbname); | ||||
| 			exit_or_abort(EXITCODE_ERROR); | ||||
| 		} | ||||
|  | ||||
| 		if (PQstatus(conn) == CONNECTION_BAD && | ||||
| 			PQconnectionNeedsPassword(conn) && | ||||
| 			pwd == NULL) | ||||
| 		{ | ||||
| 			PQfinish(conn); | ||||
| 			pwd = simple_prompt("Password: ", 100, false); | ||||
| 			new_pass = true; | ||||
| 		} | ||||
| 	} while (new_pass); | ||||
|  | ||||
| 	free(pwd); | ||||
|  | ||||
| 	/* check to see that the backend connection was successfully made */ | ||||
| 	if (PQstatus(conn) == CONNECTION_BAD) | ||||
| 	{ | ||||
| 		fprintf(stderr, _("%s: could not connect to database %s: %s"), | ||||
| 				progname, dbname, PQerrorMessage(conn)); | ||||
| 		exit_or_abort(EXITCODE_ERROR); | ||||
| 	} | ||||
|  | ||||
| 	current_conn = conn; | ||||
| } | ||||
|  | ||||
| void | ||||
| disconnect(void) | ||||
| { | ||||
| 	if (current_conn) | ||||
| 	{ | ||||
| 		PQfinish(current_conn); | ||||
| 		current_conn = NULL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| PGresult * | ||||
| execute_nothrow(const char *query, int nParams, const char **params) | ||||
| { | ||||
| 	PGresult   *res; | ||||
|  | ||||
| 	on_before_exec(current_conn); | ||||
| 	if (nParams == 0) | ||||
| 		res = PQexec(current_conn, query); | ||||
| 	else | ||||
| 		res = PQexecParams(current_conn, query, nParams, NULL, params, NULL, NULL, 0); | ||||
| 	on_after_exec(); | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * execute - Execute a SQL and return the result, or exit_or_abort() if failed. | ||||
|  */ | ||||
| PGresult * | ||||
| execute(const char *query, int nParams, const char **params) | ||||
| { | ||||
| 	if (interrupted) | ||||
| 	{ | ||||
| 		interrupted = false; | ||||
| 		fprintf(stderr, _("%s: interrupted\n"), progname); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		PGresult   *res = execute_nothrow(query, nParams, params); | ||||
|  | ||||
| 		if (PQresultStatus(res) == PGRES_TUPLES_OK || | ||||
| 			PQresultStatus(res) == PGRES_COMMAND_OK) | ||||
| 			return res; | ||||
|  | ||||
| 		fprintf(stderr, _("%s: query failed: %s"), | ||||
| 				progname, PQerrorMessage(current_conn)); | ||||
| 		fprintf(stderr, _("%s: query was: %s\n"), | ||||
| 				progname, query); | ||||
| 		PQclear(res); | ||||
| 	} | ||||
|  | ||||
| 	exit_or_abort(EXITCODE_ERROR); | ||||
| 	return NULL;	/* keep compiler quiet */ | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * command - Execute a SQL and discard the result, or exit_or_abort() if failed. | ||||
|  */ | ||||
| void | ||||
| command(const char *query, int nParams, const char **params) | ||||
| { | ||||
| 	PGresult *res = execute(query, nParams, params); | ||||
| 	PQclear(res); | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifdef WIN32 | ||||
| static CRITICAL_SECTION cancelConnLock; | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * on_before_exec | ||||
|  * | ||||
|  * Set cancel_conn to point to the current database connection. | ||||
|  */ | ||||
| static void | ||||
| on_before_exec(PGconn *conn) | ||||
| { | ||||
| 	PGcancel   *old; | ||||
|  | ||||
| #ifdef WIN32 | ||||
| 	EnterCriticalSection(&cancelConnLock); | ||||
| #endif | ||||
|  | ||||
| 	/* Free the old one if we have one */ | ||||
| 	old = cancel_conn; | ||||
|  | ||||
| 	/* be sure handle_sigint doesn't use pointer while freeing */ | ||||
| 	cancel_conn = NULL; | ||||
|  | ||||
| 	if (old != NULL) | ||||
| 		PQfreeCancel(old); | ||||
|  | ||||
| 	cancel_conn = PQgetCancel(conn); | ||||
|  | ||||
| #ifdef WIN32 | ||||
| 	LeaveCriticalSection(&cancelConnLock); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * on_after_exec | ||||
|  * | ||||
|  * Free the current cancel connection, if any, and set to NULL. | ||||
|  */ | ||||
| static void | ||||
| on_after_exec(void) | ||||
| { | ||||
| 	PGcancel   *old; | ||||
|  | ||||
| #ifdef WIN32 | ||||
| 	EnterCriticalSection(&cancelConnLock); | ||||
| #endif | ||||
|  | ||||
| 	old = cancel_conn; | ||||
|  | ||||
| 	/* be sure handle_sigint doesn't use pointer while freeing */ | ||||
| 	cancel_conn = NULL; | ||||
|  | ||||
| 	if (old != NULL) | ||||
| 		PQfreeCancel(old); | ||||
|  | ||||
| #ifdef WIN32 | ||||
| 	LeaveCriticalSection(&cancelConnLock); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Handle interrupt signals by cancelling the current command. | ||||
|  */ | ||||
| static void | ||||
| on_interrupt(void) | ||||
| { | ||||
| 	int			save_errno = errno; | ||||
| 	char		errbuf[256]; | ||||
|  | ||||
| 	/* Set interruped flag */ | ||||
| 	interrupted = true; | ||||
|  | ||||
| 	/* Send QueryCancel if we are processing a database query */ | ||||
| 	if (cancel_conn != NULL && PQcancel(cancel_conn, errbuf, sizeof(errbuf))) | ||||
| 		fprintf(stderr, _("Cancel request sent\n")); | ||||
|  | ||||
| 	errno = save_errno;			/* just in case the write changed it */ | ||||
| } | ||||
|  | ||||
| static pqbool	in_cleanup = false; | ||||
|  | ||||
| static void | ||||
| on_exit(void) | ||||
| { | ||||
| 	in_cleanup = true; | ||||
| 	pgut_cleanup(false); | ||||
| 	disconnect(); | ||||
| } | ||||
|  | ||||
| static void | ||||
| exit_or_abort(int exitcode) | ||||
| { | ||||
| 	if (in_cleanup) | ||||
| 	{ | ||||
| 		/* oops, error in cleanup*/ | ||||
| 		pgut_cleanup(true); | ||||
| 		abort(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* normal exit */ | ||||
| 		exit(exitcode); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the current user name. | ||||
|  */ | ||||
| const char * | ||||
| get_user_name(const char *progname) | ||||
| { | ||||
| #ifndef WIN32 | ||||
| 	struct passwd *pw; | ||||
|  | ||||
| 	pw = getpwuid(geteuid()); | ||||
| 	if (!pw) | ||||
| 	{ | ||||
| 		fprintf(stderr, _("%s: could not obtain information about current user: %s\n"), | ||||
| 				progname, strerror(errno)); | ||||
| 		exit_or_abort(EXITCODE_ERROR); | ||||
| 	} | ||||
| 	return pw->pw_name; | ||||
| #else | ||||
| 	static char username[128];	/* remains after function exit */ | ||||
| 	DWORD		len = sizeof(username) - 1; | ||||
|  | ||||
| 	if (!GetUserName(username, &len)) | ||||
| 	{ | ||||
| 		fprintf(stderr, _("%s: could not get current user name: %s\n"), | ||||
| 				progname, strerror(errno)); | ||||
| 		exit_or_abort(EXITCODE_ERROR); | ||||
| 	} | ||||
| 	return username; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifndef WIN32 | ||||
| static void | ||||
| handle_sigint(SIGNAL_ARGS) | ||||
| { | ||||
| 	on_interrupt(); | ||||
| } | ||||
|  | ||||
| static void | ||||
| init_cancel_handler(void) | ||||
| { | ||||
| 	pqsignal(SIGINT, handle_sigint); | ||||
| } | ||||
| #else							/* WIN32 */ | ||||
|  | ||||
| /* | ||||
|  * Console control handler for Win32. Note that the control handler will | ||||
|  * execute on a *different thread* than the main one, so we need to do | ||||
|  * proper locking around those structures. | ||||
|  */ | ||||
| static BOOL WINAPI | ||||
| consoleHandler(DWORD dwCtrlType) | ||||
| { | ||||
| 	if (dwCtrlType == CTRL_C_EVENT || | ||||
| 		dwCtrlType == CTRL_BREAK_EVENT) | ||||
| 	{ | ||||
| 		EnterCriticalSection(&cancelConnLock); | ||||
| 		on_interrupt(); | ||||
| 		LeaveCriticalSection(&cancelConnLock); | ||||
| 		return TRUE; | ||||
| 	} | ||||
| 	else | ||||
| 		/* Return FALSE for any signals not being handled */ | ||||
| 		return FALSE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| init_cancel_handler(void) | ||||
| { | ||||
| 	InitializeCriticalSection(&cancelConnLock); | ||||
|  | ||||
| 	SetConsoleCtrlHandler(consoleHandler, TRUE); | ||||
| } | ||||
|  | ||||
| unsigned int | ||||
| sleep(unsigned int seconds) | ||||
| { | ||||
| 	Sleep(seconds * 1000); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif   /* WIN32 */ | ||||
							
								
								
									
										65
									
								
								bin/pgut/pgut.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										65
									
								
								bin/pgut/pgut.h
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,65 @@ | ||||
| /* | ||||
|  * pgut.h | ||||
|  * | ||||
|  * Copyright (c) 2009, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | ||||
|  */ | ||||
|  | ||||
| #ifndef PGUT_H | ||||
| #define PGUT_H | ||||
|  | ||||
| #include "libpq-fe.h" | ||||
| #include <getopt.h> | ||||
|  | ||||
| /* | ||||
|  * pgut client variables and functions | ||||
|  */ | ||||
| extern const char		   *pgut_optstring; | ||||
| extern const struct option	pgut_longopts[]; | ||||
|  | ||||
| extern pqbool	pgut_argument(int c, const char *arg); | ||||
| extern int		pgut_help(void); | ||||
| extern int		pgut_version(void); | ||||
| extern void		pgut_cleanup(pqbool fatal); | ||||
|  | ||||
| /* | ||||
|  * exit codes | ||||
|  */ | ||||
|  | ||||
| #define EXITCODE_OK		0	/**< normal exit */ | ||||
| #define EXITCODE_ERROR	1	/**< normal error */ | ||||
| #define EXITCODE_HELP	2	/**< help and version mode */ | ||||
| #define EXITCODE_FATAL	3	/**< fatal error */ | ||||
|  | ||||
| /* | ||||
|  * pgut framework variables and functions | ||||
|  */ | ||||
|  | ||||
| #ifndef true | ||||
| #define true	1 | ||||
| #endif | ||||
| #ifndef false | ||||
| #define false	0 | ||||
| #endif | ||||
|  | ||||
| extern const char  *progname; | ||||
| extern const char  *dbname; | ||||
| extern char		   *host; | ||||
| extern char		   *port; | ||||
| extern char		   *username; | ||||
| extern pqbool		password; | ||||
| extern pqbool		interrupted; | ||||
| extern PGconn	   *current_conn; | ||||
|  | ||||
| extern int	pgut_getopt(int argc, char **argv); | ||||
|  | ||||
| extern void reconnect(void); | ||||
| extern void disconnect(void); | ||||
| extern PGresult *execute_nothrow(const char *query, int nParams, const char **params); | ||||
| extern PGresult *execute(const char *query, int nParams, const char **params); | ||||
| extern void command(const char *query, int nParams, const char **params); | ||||
|  | ||||
| #ifdef WIN32 | ||||
| extern unsigned int sleep(unsigned int seconds); | ||||
| #endif | ||||
|  | ||||
| #endif   /* PGUT_H */ | ||||
		Reference in New Issue
	
	Block a user