pg_reorg version 1.1.0.
- Add wait-timeout option and use SET statement_timeout instead of NOWAIT. This can avoid infinite NOWAIT loops to reorganize heavily accessed tables. - Support native build with MSVC on Windows.
This commit is contained in:
		| @ -3,7 +3,7 @@ | |||||||
| # | # | ||||||
| #    Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | #    Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | ||||||
| # | # | ||||||
| SRCS = pg_reorg.c pgut/pgut.c | SRCS = pg_reorg.c pgut/pgut.c pgut/pgut-fe.c | ||||||
| OBJS = $(SRCS:.c=.o) | OBJS = $(SRCS:.c=.o) | ||||||
| PROGRAM = pg_reorg | PROGRAM = pg_reorg | ||||||
| REGRESS = init reorg | REGRESS = init reorg | ||||||
|  | |||||||
							
								
								
									
										230
									
								
								bin/pg_reorg.c
									
									
									
									
									
								
							
							
						
						
									
										230
									
								
								bin/pg_reorg.c
									
									
									
									
									
								
							| @ -8,15 +8,16 @@ | |||||||
|  * @brief Client Modules |  * @brief Client Modules | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| const char *PROGRAM_VERSION	= "1.0.8"; | const char *PROGRAM_VERSION	= "1.1.0"; | ||||||
| const char *PROGRAM_URL		= "http://reorg.projects.postgresql.org/"; | const char *PROGRAM_URL		= "http://reorg.projects.postgresql.org/"; | ||||||
| const char *PROGRAM_EMAIL	= "reorg-general@lists.pgfoundry.org"; | const char *PROGRAM_EMAIL	= "reorg-general@lists.pgfoundry.org"; | ||||||
|  |  | ||||||
| #include "pgut/pgut.h" | #include "pgut/pgut-fe.h" | ||||||
|  |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
| #define APPLY_COUNT		1000 | #define APPLY_COUNT		1000 | ||||||
|  |  | ||||||
| @ -84,21 +85,22 @@ static void reorg_cleanup(bool fatal, void *userdata); | |||||||
|  |  | ||||||
| static char *getstr(PGresult *res, int row, int col); | static char *getstr(PGresult *res, int row, int col); | ||||||
| static Oid getoid(PGresult *res, int row, int col); | static Oid getoid(PGresult *res, int row, int col); | ||||||
|  | static void lock_exclusive(const char *relid, const char *lock_query); | ||||||
|  |  | ||||||
| #define SQLSTATE_INVALID_SCHEMA_NAME	"3F000" | #define SQLSTATE_INVALID_SCHEMA_NAME	"3F000" | ||||||
| #define SQLSTATE_LOCK_NOT_AVAILABLE		"55P03" | #define SQLSTATE_QUERY_CANCELED			"57014" | ||||||
|  |  | ||||||
| static bool sqlstate_equals(PGresult *res, const char *state) | static bool sqlstate_equals(PGresult *res, const char *state) | ||||||
| { | { | ||||||
| 	return strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), state) == 0; | 	return strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), state) == 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool		verbose = false; |  | ||||||
| static bool		analyze = true; | static bool		analyze = true; | ||||||
| static bool		alldb = false; | static bool		alldb = false; | ||||||
| static bool		noorder = false; | static bool		noorder = false; | ||||||
| static char	   *table = NULL; | static char	   *table = NULL; | ||||||
| static char	   *orderby = NULL; | static char	   *orderby = NULL; | ||||||
|  | static int		wait_timeout = 60;	/* in seconds */ | ||||||
|  |  | ||||||
| /* buffer should have at least 11 bytes */ | /* buffer should have at least 11 bytes */ | ||||||
| static char * | static char * | ||||||
| @ -110,11 +112,11 @@ utoa(unsigned int value, char *buffer) | |||||||
|  |  | ||||||
| static pgut_option options[] = | static pgut_option options[] = | ||||||
| { | { | ||||||
| 	{ 'b', 'v', "verbose", &verbose }, |  | ||||||
| 	{ 'b', 'a', "all", &alldb }, | 	{ 'b', 'a', "all", &alldb }, | ||||||
| 	{ 's', 't', "table", &table }, | 	{ 's', 't', "table", &table }, | ||||||
| 	{ 'b', 'n', "no-order", &noorder }, | 	{ 'b', 'n', "no-order", &noorder }, | ||||||
| 	{ 's', 'o', "order-by", &orderby }, | 	{ 's', 'o', "order-by", &orderby }, | ||||||
|  | 	{ 'i', 'T', "wait-timeout", &wait_timeout }, | ||||||
| 	{ 'B', 'Z', "no-analyze", &analyze }, | 	{ 'B', 'Z', "no-analyze", &analyze }, | ||||||
| 	{ 0 }, | 	{ 0 }, | ||||||
| }; | }; | ||||||
| @ -129,7 +131,9 @@ main(int argc, char *argv[]) | |||||||
| 	if (i == argc - 1) | 	if (i == argc - 1) | ||||||
| 		dbname = argv[i]; | 		dbname = argv[i]; | ||||||
| 	else if (i < argc) | 	else if (i < argc) | ||||||
| 		elog(ERROR_ARGS, "too many arguments"); | 		ereport(ERROR, | ||||||
|  | 			(errcode(EINVAL), | ||||||
|  | 			 errmsg("too many arguments"))); | ||||||
|  |  | ||||||
| 	if (noorder) | 	if (noorder) | ||||||
| 		orderby = ""; | 		orderby = ""; | ||||||
| @ -137,13 +141,17 @@ main(int argc, char *argv[]) | |||||||
| 	if (alldb) | 	if (alldb) | ||||||
| 	{ | 	{ | ||||||
| 		if (table) | 		if (table) | ||||||
| 			elog(ERROR, "cannot reorg a specific table in all databases"); | 			ereport(ERROR, | ||||||
|  | 				(errcode(EINVAL), | ||||||
|  | 				 errmsg("cannot reorg a specific table in all databases"))); | ||||||
| 		reorg_all_databases(orderby); | 		reorg_all_databases(orderby); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		if (!reorg_one_database(orderby, table)) | 		if (!reorg_one_database(orderby, table)) | ||||||
| 			elog(ERROR, "%s is not installed", PROGRAM_NAME); | 			ereport(ERROR, | ||||||
|  | 				(errcode(ENOENT), | ||||||
|  | 				 errmsg("%s is not installed", PROGRAM_NAME))); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -159,7 +167,7 @@ reorg_all_databases(const char *orderby) | |||||||
| 	int			i; | 	int			i; | ||||||
|  |  | ||||||
| 	dbname = "postgres"; | 	dbname = "postgres"; | ||||||
| 	reconnect(); | 	reconnect(ERROR); | ||||||
| 	result = execute("SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", 0, NULL); | 	result = execute("SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", 0, NULL); | ||||||
| 	disconnect(); | 	disconnect(); | ||||||
|  |  | ||||||
| @ -169,7 +177,7 @@ reorg_all_databases(const char *orderby) | |||||||
|  |  | ||||||
| 		dbname = PQgetvalue(result, i, 0); | 		dbname = PQgetvalue(result, i, 0); | ||||||
|  |  | ||||||
| 		if (!quiet) | 		if (pgut_log_level >= INFO) | ||||||
| 		{ | 		{ | ||||||
| 			printf("%s: reorg database \"%s\"", PROGRAM_NAME, dbname); | 			printf("%s: reorg database \"%s\"", PROGRAM_NAME, dbname); | ||||||
| 			fflush(stdout); | 			fflush(stdout); | ||||||
| @ -177,7 +185,7 @@ reorg_all_databases(const char *orderby) | |||||||
|  |  | ||||||
| 		ret = reorg_one_database(orderby, NULL); | 		ret = reorg_one_database(orderby, NULL); | ||||||
|  |  | ||||||
| 		if (!quiet) | 		if (pgut_log_level >= INFO) | ||||||
| 		{ | 		{ | ||||||
| 			if (ret) | 			if (ret) | ||||||
| 				printf("\n"); | 				printf("\n"); | ||||||
| @ -223,7 +231,10 @@ reorg_one_database(const char *orderby, const char *table) | |||||||
|  |  | ||||||
| 	initStringInfo(&sql); | 	initStringInfo(&sql); | ||||||
|  |  | ||||||
| 	reconnect(); | 	reconnect(ERROR); | ||||||
|  |  | ||||||
|  | 	/* Disable statement timeout. */ | ||||||
|  | 	command("SET statement_timeout = 0", 0, NULL); | ||||||
|  |  | ||||||
| 	/* Restrict search_path to system catalog. */ | 	/* Restrict search_path to system catalog. */ | ||||||
| 	command("SET search_path = pg_catalog, pg_temp, public", 0, NULL); | 	command("SET search_path = pg_catalog, pg_temp, public", 0, NULL); | ||||||
| @ -236,14 +247,14 @@ reorg_one_database(const char *orderby, const char *table) | |||||||
| 	if (table) | 	if (table) | ||||||
| 	{ | 	{ | ||||||
| 		appendStringInfoString(&sql, "relid = $1::regclass"); | 		appendStringInfoString(&sql, "relid = $1::regclass"); | ||||||
| 		res = execute_elevel(sql.data, 1, &table, LOG); | 		res = execute_elevel(sql.data, 1, &table, DEBUG2); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		appendStringInfoString(&sql, "pkid IS NOT NULL"); | 		appendStringInfoString(&sql, "pkid IS NOT NULL"); | ||||||
| 		if (!orderby) | 		if (!orderby) | ||||||
| 			appendStringInfoString(&sql, " AND ckid IS NOT NULL"); | 			appendStringInfoString(&sql, " AND ckid IS NOT NULL"); | ||||||
| 		res = execute_elevel(sql.data, 0, NULL, LOG); | 		res = execute_elevel(sql.data, 0, NULL, DEBUG2); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (PQresultStatus(res) != PGRES_TUPLES_OK) | 	if (PQresultStatus(res) != PGRES_TUPLES_OK) | ||||||
| @ -280,7 +291,9 @@ reorg_one_database(const char *orderby, const char *table) | |||||||
| 		table.ckid = getoid(res, i, c++); | 		table.ckid = getoid(res, i, c++); | ||||||
|  |  | ||||||
| 		if (table.pkid == 0) | 		if (table.pkid == 0) | ||||||
| 			elog(ERROR, "relation \"%s\" has no primary key", table.target_name); | 			ereport(ERROR, | ||||||
|  | 				(errcode(E_PG_COMMAND), | ||||||
|  | 				 errmsg("relation \"%s\" has no primary key", table.target_name))); | ||||||
|  |  | ||||||
| 		table.create_pktype = getstr(res, i, c++); | 		table.create_pktype = getstr(res, i, c++); | ||||||
| 		table.create_log = getstr(res, i, c++); | 		table.create_log = getstr(res, i, c++); | ||||||
| @ -296,7 +309,9 @@ reorg_one_database(const char *orderby, const char *table) | |||||||
| 		{ | 		{ | ||||||
| 			/* CLUSTER mode */ | 			/* CLUSTER mode */ | ||||||
| 			if (ckey == NULL) | 			if (ckey == NULL) | ||||||
| 				elog(ERROR, "relation \"%s\" has no cluster key", table.target_name); | 				ereport(ERROR, | ||||||
|  | 					(errcode(E_PG_COMMAND), | ||||||
|  | 					 errmsg("relation \"%s\" has no cluster key", table.target_name))); | ||||||
| 			appendStringInfo(&sql, "%s ORDER BY %s", create_table, ckey); | 			appendStringInfo(&sql, "%s ORDER BY %s", create_table, ckey); | ||||||
|             table.create_table = sql.data; |             table.create_table = sql.data; | ||||||
| 		} | 		} | ||||||
| @ -367,35 +382,30 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
|  |  | ||||||
| 	initStringInfo(&sql); | 	initStringInfo(&sql); | ||||||
|  |  | ||||||
| 	if (verbose) | 	elog(DEBUG2, "---- reorg_one_table ----"); | ||||||
| 	{ | 	elog(DEBUG2, "target_name    : %s", table->target_name); | ||||||
| 		fprintf(stderr, "---- reorg_one_table ----\n"); | 	elog(DEBUG2, "target_oid     : %u", table->target_oid); | ||||||
| 		fprintf(stderr, "target_name    : %s\n", table->target_name); | 	elog(DEBUG2, "target_toast   : %u", table->target_toast); | ||||||
| 		fprintf(stderr, "target_oid     : %u\n", table->target_oid); | 	elog(DEBUG2, "target_tidx    : %u", table->target_tidx); | ||||||
| 		fprintf(stderr, "target_toast   : %u\n", table->target_toast); | 	elog(DEBUG2, "pkid           : %u", table->pkid); | ||||||
| 		fprintf(stderr, "target_tidx    : %u\n", table->target_tidx); | 	elog(DEBUG2, "ckid           : %u", table->ckid); | ||||||
| 		fprintf(stderr, "pkid           : %u\n", table->pkid); | 	elog(DEBUG2, "create_pktype  : %s", table->create_pktype); | ||||||
| 		fprintf(stderr, "ckid           : %u\n", table->ckid); | 	elog(DEBUG2, "create_log     : %s", table->create_log); | ||||||
| 		fprintf(stderr, "create_pktype  : %s\n", table->create_pktype); | 	elog(DEBUG2, "create_trigger : %s", table->create_trigger); | ||||||
| 		fprintf(stderr, "create_log     : %s\n", table->create_log); | 	elog(DEBUG2, "create_table   : %s", table->create_table); | ||||||
| 		fprintf(stderr, "create_trigger : %s\n", table->create_trigger); | 	elog(DEBUG2, "delete_log     : %s", table->delete_log); | ||||||
| 		fprintf(stderr, "create_table   : %s\n", table->create_table); | 	elog(DEBUG2, "lock_table     : %s", table->lock_table); | ||||||
| 		fprintf(stderr, "delete_log     : %s\n", table->delete_log); | 	elog(DEBUG2, "sql_peek       : %s", table->sql_peek); | ||||||
| 		fprintf(stderr, "lock_table     : %s\n", table->lock_table); | 	elog(DEBUG2, "sql_insert     : %s", table->sql_insert); | ||||||
| 		fprintf(stderr, "sql_peek       : %s\n", table->sql_peek); | 	elog(DEBUG2, "sql_delete     : %s", table->sql_delete); | ||||||
| 		fprintf(stderr, "sql_insert     : %s\n", table->sql_insert); | 	elog(DEBUG2, "sql_update     : %s", table->sql_update); | ||||||
| 		fprintf(stderr, "sql_delete     : %s\n", table->sql_delete); | 	elog(DEBUG2, "sql_pop        : %s", table->sql_pop); | ||||||
| 		fprintf(stderr, "sql_update     : %s\n", table->sql_update); |  | ||||||
| 		fprintf(stderr, "sql_pop        : %s\n", table->sql_pop); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * 1. Setup workspaces and a trigger. | 	 * 1. Setup workspaces and a trigger. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (verbose) | 	elog(DEBUG2, "---- setup ----"); | ||||||
| 		fprintf(stderr, "---- setup ----\n"); | 	lock_exclusive(utoa(table->target_oid, buffer), table->lock_table); | ||||||
|  |  | ||||||
| 	command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); |  | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Check z_reorg_trigger is the trigger executed at last so that | 	 * Check z_reorg_trigger is the trigger executed at last so that | ||||||
| @ -405,8 +415,10 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
|  |  | ||||||
| 	res = execute("SELECT reorg.conflicted_triggers($1)", 1, params); | 	res = execute("SELECT reorg.conflicted_triggers($1)", 1, params); | ||||||
| 	if (PQntuples(res) > 0) | 	if (PQntuples(res) > 0) | ||||||
| 		elog(ERROR, "trigger %s conflicted for %s", | 		ereport(ERROR, | ||||||
| 			PQgetvalue(res, 0, 0), table->target_name); | 			(errcode(E_PG_COMMAND), | ||||||
|  | 			 errmsg("trigger %s conflicted for %s", | ||||||
|  | 					PQgetvalue(res, 0, 0), table->target_name))); | ||||||
|  |  | ||||||
| 	command(table->create_pktype, 0, NULL); | 	command(table->create_pktype, 0, NULL); | ||||||
| 	command(table->create_log, 0, NULL); | 	command(table->create_log, 0, NULL); | ||||||
| @ -425,8 +437,7 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 	/* | 	/* | ||||||
| 	 * 2. Copy tuples into temp table. | 	 * 2. Copy tuples into temp table. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (verbose) | 	elog(DEBUG2, "---- copy tuples ----"); | ||||||
| 		fprintf(stderr, "---- copy tuples ----\n"); |  | ||||||
|  |  | ||||||
| 	command("BEGIN ISOLATION LEVEL SERIALIZABLE", 0, NULL); | 	command("BEGIN ISOLATION LEVEL SERIALIZABLE", 0, NULL); | ||||||
| 	/* SET work_mem = maintenance_work_mem */ | 	/* SET work_mem = maintenance_work_mem */ | ||||||
| @ -445,8 +456,7 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 	/* | 	/* | ||||||
| 	 * 3. Create indexes on temp table. | 	 * 3. Create indexes on temp table. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (verbose) | 	elog(DEBUG2, "---- create indexes ----"); | ||||||
| 		fprintf(stderr, "---- create indexes ----\n"); |  | ||||||
|  |  | ||||||
| 	params[0] = utoa(table->target_oid, buffer); | 	params[0] = utoa(table->target_oid, buffer); | ||||||
| 	res = execute("SELECT indexrelid," | 	res = execute("SELECT indexrelid," | ||||||
| @ -462,12 +472,9 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 		index.target_oid = getoid(res, i, c++); | 		index.target_oid = getoid(res, i, c++); | ||||||
| 		index.create_index = getstr(res, i, c++); | 		index.create_index = getstr(res, i, c++); | ||||||
|  |  | ||||||
| 		if (verbose) | 		elog(DEBUG2, "[%d]", i); | ||||||
| 		{ | 		elog(DEBUG2, "target_oid   : %u", index.target_oid); | ||||||
| 			fprintf(stderr, "[%d]\n", i); | 		elog(DEBUG2, "create_index : %s", index.create_index); | ||||||
| 			fprintf(stderr, "target_oid   : %u\n", index.target_oid); |  | ||||||
| 			fprintf(stderr, "create_index : %s\n", index.create_index); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		/* | 		/* | ||||||
| 		 * NOTE: If we want to create multiple indexes in parallel, | 		 * NOTE: If we want to create multiple indexes in parallel, | ||||||
| @ -506,35 +513,8 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 	/* | 	/* | ||||||
| 	 * 5. Swap. | 	 * 5. Swap. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (verbose) | 	elog(DEBUG2, "---- swap ----"); | ||||||
| 		fprintf(stderr, "---- swap ----\n"); | 	lock_exclusive(utoa(table->target_oid, buffer), table->lock_table); | ||||||
|  |  | ||||||
| 	for (;;) |  | ||||||
| 	{ |  | ||||||
| 		command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); |  | ||||||
| 		res = execute_elevel(table->lock_table, 0, NULL, NOTICE); |  | ||||||
| 		if (PQresultStatus(res) == PGRES_COMMAND_OK) |  | ||||||
| 		{ |  | ||||||
| 			PQclear(res); |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 		else if (sqlstate_equals(res, SQLSTATE_LOCK_NOT_AVAILABLE)) |  | ||||||
| 		{ |  | ||||||
| 			/* retry if lock conflicted */ |  | ||||||
| 			PQclear(res); |  | ||||||
| 			command("ROLLBACK", 0, NULL); |  | ||||||
| 			sleep(1); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			/* exit otherwise */ |  | ||||||
| 			printf("%s", PQerrorMessage(connection)); |  | ||||||
| 			PQclear(res); |  | ||||||
| 			exit(1); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	apply_log(table, 0); | 	apply_log(table, 0); | ||||||
| 	params[0] = utoa(table->target_oid, buffer); | 	params[0] = utoa(table->target_oid, buffer); | ||||||
| 	command("SELECT reorg.reorg_swap($1)", 1, params); | 	command("SELECT reorg.reorg_swap($1)", 1, params); | ||||||
| @ -543,8 +523,7 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 	/* | 	/* | ||||||
| 	 * 6. Drop. | 	 * 6. Drop. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (verbose) | 	elog(DEBUG2, "---- drop ----"); | ||||||
| 		fprintf(stderr, "---- drop ----\n"); |  | ||||||
|  |  | ||||||
| 	command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); | 	command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); | ||||||
| 	params[0] = utoa(table->target_oid, buffer); | 	params[0] = utoa(table->target_oid, buffer); | ||||||
| @ -561,12 +540,10 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 	 */ | 	 */ | ||||||
| 	if (analyze) | 	if (analyze) | ||||||
| 	{ | 	{ | ||||||
| 		if (verbose) | 		elog(DEBUG2, "---- analyze ----"); | ||||||
| 			fprintf(stderr, "---- analyze ----\n"); |  | ||||||
|  |  | ||||||
| 		command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); | 		command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); | ||||||
| 		printfStringInfo(&sql, "ANALYZE %s%s", | 		printfStringInfo(&sql, "ANALYZE %s", table->target_name); | ||||||
| 			(verbose ? "VERBOSE " : ""), table->target_name); |  | ||||||
| 		command(sql.data, 0, NULL); | 		command(sql.data, 0, NULL); | ||||||
| 		command("COMMIT", 0, NULL); | 		command("COMMIT", 0, NULL); | ||||||
| 	} | 	} | ||||||
| @ -574,6 +551,79 @@ reorg_one_table(const reorg_table *table, const char *orderby) | |||||||
| 	termStringInfo(&sql); | 	termStringInfo(&sql); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Try acquire a table lock but avoid long time locks when conflict. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | lock_exclusive(const char *relid, const char *lock_query) | ||||||
|  | { | ||||||
|  | 	time_t		start = time(NULL); | ||||||
|  | 	int			i; | ||||||
|  | 	 | ||||||
|  | 	for (i = 1; ; i++) | ||||||
|  | 	{ | ||||||
|  | 		time_t		duration; | ||||||
|  | 		char		sql[1024]; | ||||||
|  | 		PGresult   *res; | ||||||
|  | 		int			wait_msec; | ||||||
|  |  | ||||||
|  | 		command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); | ||||||
|  |  | ||||||
|  | 		duration = time(NULL) - start; | ||||||
|  | 		if (duration > wait_timeout) | ||||||
|  | 		{ | ||||||
|  | 			const char *cancel_query; | ||||||
|  | 			if (PQserverVersion(connection) >= 80400 && | ||||||
|  | 				duration > wait_timeout * 2) | ||||||
|  | 			{ | ||||||
|  | 				elog(WARNING, "terminating conflicted backends"); | ||||||
|  | 				cancel_query = | ||||||
|  | 					"SELECT pg_terminate_backend(pid) FROM pg_locks" | ||||||
|  | 					" WHERE locktype = 'relation'" | ||||||
|  | 					"   AND relation = $1 AND pid <> pg_backend_pid()"; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				elog(WARNING, "canceling conflicted backends"); | ||||||
|  | 				cancel_query = | ||||||
|  | 					"SELECT pg_cancel_backend(pid) FROM pg_locks" | ||||||
|  | 					" WHERE locktype = 'relation'" | ||||||
|  | 					"   AND relation = $1 AND pid <> pg_backend_pid()"; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			command(cancel_query, 1, &relid); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		/* wait for a while to lock the table. */ | ||||||
|  | 		wait_msec = Min(1000, i * 100); | ||||||
|  | 		snprintf(sql, lengthof(sql), "SET LOCAL statement_timeout = %d", wait_msec); | ||||||
|  | 		command(sql, 0, NULL); | ||||||
|  |  | ||||||
|  | 		res = execute_elevel(lock_query, 0, NULL, DEBUG2); | ||||||
|  | 		if (PQresultStatus(res) == PGRES_COMMAND_OK) | ||||||
|  | 		{ | ||||||
|  | 			PQclear(res); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		else if (sqlstate_equals(res, SQLSTATE_QUERY_CANCELED)) | ||||||
|  | 		{ | ||||||
|  | 			/* retry if lock conflicted */ | ||||||
|  | 			PQclear(res); | ||||||
|  | 			command("ROLLBACK", 0, NULL); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			/* exit otherwise */ | ||||||
|  | 			printf("%s", PQerrorMessage(connection)); | ||||||
|  | 			PQclear(res); | ||||||
|  | 			exit(1); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	command("RESET statement_timeout", 0, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * The userdata pointing a table being re-organized. We need to cleanup temp |  * The userdata pointing a table being re-organized. We need to cleanup temp | ||||||
|  * objects before the program exits. |  * objects before the program exits. | ||||||
| @ -598,7 +648,7 @@ reorg_cleanup(bool fatal, void *userdata) | |||||||
|  |  | ||||||
| 		/* Try reconnection if not available. */ | 		/* Try reconnection if not available. */ | ||||||
| 		if (PQstatus(connection) != CONNECTION_OK) | 		if (PQstatus(connection) != CONNECTION_OK) | ||||||
| 			reconnect(); | 			reconnect(ERROR); | ||||||
|  |  | ||||||
| 		/* do cleanup */ | 		/* do cleanup */ | ||||||
| 		params[0] = utoa(table->target_oid, buffer); | 		params[0] = utoa(table->target_oid, buffer); | ||||||
| @ -621,6 +671,6 @@ pgut_help(bool details) | |||||||
| 	printf("  -t, --table=TABLE         reorg specific table only\n"); | 	printf("  -t, --table=TABLE         reorg specific table only\n"); | ||||||
| 	printf("  -n, --no-order            do vacuum full instead of cluster\n"); | 	printf("  -n, --no-order            do vacuum full instead of cluster\n"); | ||||||
| 	printf("  -o, --order-by=columns    order by columns instead of cluster keys\n"); | 	printf("  -o, --order-by=columns    order by columns instead of cluster keys\n"); | ||||||
|  | 	printf("  -T, --wait-timeout=secs   timeout to cancel other backends on conflict.\n"); | ||||||
| 	printf("  -Z, --no-analyze          don't analyze at end\n"); | 	printf("  -Z, --no-analyze          don't analyze at end\n"); | ||||||
| 	printf("  -v, --verbose             display detailed information during processing\n"); |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										687
									
								
								bin/pgut/pgut-fe.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										687
									
								
								bin/pgut/pgut-fe.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,687 @@ | |||||||
|  | /*------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * pgut-fe.c | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | ||||||
|  |  * | ||||||
|  |  *------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #define FRONTEND | ||||||
|  | #include "pgut-fe.h" | ||||||
|  |  | ||||||
|  | #ifdef HAVE_GETOPT_H | ||||||
|  | #include <getopt.h> | ||||||
|  | #else | ||||||
|  | #include <getopt_long.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | char	   *dbname = NULL; | ||||||
|  | char	   *host = NULL; | ||||||
|  | char	   *port = NULL; | ||||||
|  | char	   *username = NULL; | ||||||
|  | char	   *password = NULL; | ||||||
|  | YesNo		prompt_password = DEFAULT; | ||||||
|  |  | ||||||
|  | PGconn	   *connection = NULL; | ||||||
|  |  | ||||||
|  | static bool parse_pair(const char buffer[], char key[], char value[]); | ||||||
|  | static char *get_username(void); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * the result is also available with the global variable 'connection'. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | reconnect(int elevel) | ||||||
|  | { | ||||||
|  | 	StringInfoData	buf; | ||||||
|  | 	char		   *new_password; | ||||||
|  |  | ||||||
|  | 	disconnect(); | ||||||
|  | 	initStringInfo(&buf); | ||||||
|  | 	if (dbname && dbname[0]) | ||||||
|  | 		appendStringInfo(&buf, "dbname=%s ", dbname); | ||||||
|  | 	if (host && host[0]) | ||||||
|  | 		appendStringInfo(&buf, "host=%s ", host); | ||||||
|  | 	if (port && port[0]) | ||||||
|  | 		appendStringInfo(&buf, "port=%s ", port); | ||||||
|  | 	if (username && username[0]) | ||||||
|  | 		appendStringInfo(&buf, "username=%s ", username); | ||||||
|  | 	if (password && password[0]) | ||||||
|  | 		appendStringInfo(&buf, "password=%s ", password); | ||||||
|  |  | ||||||
|  | 	connection = pgut_connect(buf.data, prompt_password, elevel); | ||||||
|  |  | ||||||
|  | 	/* update password */ | ||||||
|  | 	if (connection) | ||||||
|  | 	{ | ||||||
|  | 		new_password = PQpass(connection); | ||||||
|  | 		if (new_password && (!password || strcmp(new_password, password))) | ||||||
|  | 		{ | ||||||
|  | 			free(password); | ||||||
|  | 			password = new_password; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	termStringInfo(&buf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | disconnect(void) | ||||||
|  | { | ||||||
|  | 	if (connection) | ||||||
|  | 	{ | ||||||
|  | 		pgut_disconnect(connection); | ||||||
|  | 		connection = NULL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | option_from_env(pgut_option options[]) | ||||||
|  | { | ||||||
|  | 	size_t	i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; options && options[i].type; i++) | ||||||
|  | 	{ | ||||||
|  | 		pgut_option	   *opt = &options[i]; | ||||||
|  | 		char			name[256]; | ||||||
|  | 		size_t			j; | ||||||
|  | 		const char	   *s; | ||||||
|  | 		const char	   *value; | ||||||
|  |  | ||||||
|  | 		if (opt->source > SOURCE_ENV || | ||||||
|  | 			opt->allowed == SOURCE_DEFAULT || opt->allowed > SOURCE_ENV) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		for (s = opt->lname, j = 0; *s && j < lengthof(name) - 1; s++, j++) | ||||||
|  | 		{ | ||||||
|  | 			if (strchr("-_ ", *s)) | ||||||
|  | 				name[j] = '_';	/* - to _ */ | ||||||
|  | 			else | ||||||
|  | 				name[j] = toupper(*s); | ||||||
|  | 		} | ||||||
|  | 		name[j] = '\0'; | ||||||
|  |  | ||||||
|  | 		if ((value = getenv(name)) != NULL) | ||||||
|  | 			pgut_setopt(opt, value, SOURCE_ENV); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* compare two strings ignore cases and ignore -_ */ | ||||||
|  | bool | ||||||
|  | pgut_keyeq(const char *lhs, const char *rhs) | ||||||
|  | { | ||||||
|  | 	for (; *lhs && *rhs; lhs++, rhs++) | ||||||
|  | 	{ | ||||||
|  | 		if (strchr("-_ ", *lhs)) | ||||||
|  | 		{ | ||||||
|  | 			if (!strchr("-_ ", *rhs)) | ||||||
|  | 				return false; | ||||||
|  | 		} | ||||||
|  | 		else if (ToLower(*lhs) != ToLower(*rhs)) | ||||||
|  | 			return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return *lhs == '\0' && *rhs == '\0'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | pgut_setopt(pgut_option *opt, const char *optarg, pgut_optsrc src) | ||||||
|  | { | ||||||
|  | 	const char	  *message; | ||||||
|  |  | ||||||
|  | 	if (opt == NULL) | ||||||
|  | 	{ | ||||||
|  | 		fprintf(stderr, "Try \"%s --help\" for more information.\n", PROGRAM_NAME); | ||||||
|  | 		exit(EINVAL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (opt->source > src) | ||||||
|  | 	{ | ||||||
|  | 		/* high prior value has been set already. */ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	else if (src >= SOURCE_CMDLINE && opt->source >= src) | ||||||
|  | 	{ | ||||||
|  | 		/* duplicated option in command line */ | ||||||
|  | 		message = "specified only once"; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		/* can be overwritten if non-command line source */ | ||||||
|  | 		opt->source = src; | ||||||
|  |  | ||||||
|  | 		switch (opt->type) | ||||||
|  | 		{ | ||||||
|  | 			case 'b': | ||||||
|  | 			case 'B': | ||||||
|  | 				if (optarg == NULL) | ||||||
|  | 				{ | ||||||
|  | 					*((bool *) opt->var) = (opt->type == 'b'); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				else if (parse_bool(optarg, (bool *) opt->var)) | ||||||
|  | 				{ | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				message = "a boolean"; | ||||||
|  | 				break; | ||||||
|  | 			case 'f': | ||||||
|  | 				((pgut_optfn) opt->var)(opt, optarg); | ||||||
|  | 				return; | ||||||
|  | 			case 'i': | ||||||
|  | 				if (parse_int32(optarg, opt->var)) | ||||||
|  | 					return; | ||||||
|  | 				message = "a 32bit signed integer"; | ||||||
|  | 				break; | ||||||
|  | 			case 'u': | ||||||
|  | 				if (parse_uint32(optarg, opt->var)) | ||||||
|  | 					return; | ||||||
|  | 				message = "a 32bit unsigned integer"; | ||||||
|  | 				break; | ||||||
|  | 			case 'I': | ||||||
|  | 				if (parse_int64(optarg, opt->var)) | ||||||
|  | 					return; | ||||||
|  | 				message = "a 64bit signed integer"; | ||||||
|  | 				break; | ||||||
|  | 			case 'U': | ||||||
|  | 				if (parse_uint64(optarg, opt->var)) | ||||||
|  | 					return; | ||||||
|  | 				message = "a 64bit unsigned integer"; | ||||||
|  | 				break; | ||||||
|  | 			case 's': | ||||||
|  | 				if (opt->source != SOURCE_DEFAULT) | ||||||
|  | 					free(*(char **) opt->var); | ||||||
|  | 				*(char **) opt->var = pgut_strdup(optarg); | ||||||
|  | 				return; | ||||||
|  | 			case 't': | ||||||
|  | 				if (parse_time(optarg, opt->var)) | ||||||
|  | 					return; | ||||||
|  | 				message = "a time"; | ||||||
|  | 				break; | ||||||
|  | 			case 'y': | ||||||
|  | 			case 'Y': | ||||||
|  | 				if (optarg == NULL) | ||||||
|  | 				{ | ||||||
|  | 					*(YesNo *) opt->var = (opt->type == 'y' ? YES : NO); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					bool	value; | ||||||
|  | 					if (parse_bool(optarg, &value)) | ||||||
|  | 					{ | ||||||
|  | 						*(YesNo *) opt->var = (value ? YES : NO); | ||||||
|  | 						return; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				message = "a boolean"; | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				ereport(ERROR, | ||||||
|  | 					(errcode(EINVAL), | ||||||
|  | 					 errmsg("invalid option type: %c", opt->type))); | ||||||
|  | 				return;	/* keep compiler quiet */ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (isprint(opt->sname)) | ||||||
|  | 		ereport(ERROR, | ||||||
|  | 			(errcode(EINVAL), | ||||||
|  | 			 errmsg("option -%c, --%s should be %s: '%s'", | ||||||
|  | 				opt->sname, opt->lname, message, optarg))); | ||||||
|  | 	else | ||||||
|  | 		ereport(ERROR, | ||||||
|  | 			(errcode(EINVAL), | ||||||
|  | 			 errmsg("option --%s should be %s: '%s'", | ||||||
|  | 				opt->lname, message, optarg))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Get configuration from configuration file. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | pgut_readopt(const char *path, pgut_option options[], int elevel) | ||||||
|  | { | ||||||
|  | 	FILE   *fp; | ||||||
|  | 	char	buf[1024]; | ||||||
|  | 	char	key[1024]; | ||||||
|  | 	char	value[1024]; | ||||||
|  |  | ||||||
|  | 	if (!options) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	if ((fp = pgut_fopen(path, "Rt")) == NULL) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	while (fgets(buf, lengthof(buf), fp)) | ||||||
|  | 	{ | ||||||
|  | 		size_t		i; | ||||||
|  |  | ||||||
|  | 		for (i = strlen(buf); i > 0 && IsSpace(buf[i - 1]); i--) | ||||||
|  | 			buf[i - 1] = '\0'; | ||||||
|  |  | ||||||
|  | 		if (parse_pair(buf, key, value)) | ||||||
|  | 		{ | ||||||
|  | 			for (i = 0; options[i].type; i++) | ||||||
|  | 			{ | ||||||
|  | 				pgut_option *opt = &options[i]; | ||||||
|  |  | ||||||
|  | 				if (pgut_keyeq(key, opt->lname)) | ||||||
|  | 				{ | ||||||
|  | 					if (opt->allowed == SOURCE_DEFAULT || | ||||||
|  | 						opt->allowed > SOURCE_FILE) | ||||||
|  | 						elog(elevel, "option %s cannot specified in file", opt->lname); | ||||||
|  | 					else if (opt->source <= SOURCE_FILE) | ||||||
|  | 						pgut_setopt(opt, value, SOURCE_FILE); | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (!options[i].type) | ||||||
|  | 				elog(elevel, "invalid option \"%s\"", key); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fclose(fp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char * | ||||||
|  | skip_space(const char *str, const char *line) | ||||||
|  | { | ||||||
|  | 	while (IsSpace(*str)) { str++; } | ||||||
|  | 	return str; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char * | ||||||
|  | get_next_token(const char *src, char *dst, const char *line) | ||||||
|  | { | ||||||
|  | 	const char *s; | ||||||
|  | 	size_t		i; | ||||||
|  | 	size_t		j; | ||||||
|  |  | ||||||
|  | 	if ((s = skip_space(src, line)) == NULL) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	/* parse quoted string */ | ||||||
|  | 	if (*s == '\'') | ||||||
|  | 	{ | ||||||
|  | 		s++; | ||||||
|  | 		for (i = 0, j = 0; s[i] != '\0'; i++) | ||||||
|  | 		{ | ||||||
|  | 			if (s[i] == '\\') | ||||||
|  | 			{ | ||||||
|  | 				i++; | ||||||
|  | 				switch (s[i]) | ||||||
|  | 				{ | ||||||
|  | 					case 'b': | ||||||
|  | 						dst[j] = '\b'; | ||||||
|  | 						break; | ||||||
|  | 					case 'f': | ||||||
|  | 						dst[j] = '\f'; | ||||||
|  | 						break; | ||||||
|  | 					case 'n': | ||||||
|  | 						dst[j] = '\n'; | ||||||
|  | 						break; | ||||||
|  | 					case 'r': | ||||||
|  | 						dst[j] = '\r'; | ||||||
|  | 						break; | ||||||
|  | 					case 't': | ||||||
|  | 						dst[j] = '\t'; | ||||||
|  | 						break; | ||||||
|  | 					case '0': | ||||||
|  | 					case '1': | ||||||
|  | 					case '2': | ||||||
|  | 					case '3': | ||||||
|  | 					case '4': | ||||||
|  | 					case '5': | ||||||
|  | 					case '6': | ||||||
|  | 					case '7': | ||||||
|  | 						{ | ||||||
|  | 							int			k; | ||||||
|  | 							long		octVal = 0; | ||||||
|  |  | ||||||
|  | 							for (k = 0; | ||||||
|  | 								 s[i + k] >= '0' && s[i + k] <= '7' && k < 3; | ||||||
|  | 									 k++) | ||||||
|  | 								octVal = (octVal << 3) + (s[i + k] - '0'); | ||||||
|  | 							i += k - 1; | ||||||
|  | 							dst[j] = ((char) octVal); | ||||||
|  | 						} | ||||||
|  | 						break; | ||||||
|  | 					default: | ||||||
|  | 						dst[j] = s[i]; | ||||||
|  | 						break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else if (s[i] == '\'') | ||||||
|  | 			{ | ||||||
|  | 				i++; | ||||||
|  | 				/* doubled quote becomes just one quote */ | ||||||
|  | 				if (s[i] == '\'') | ||||||
|  | 					dst[j] = s[i]; | ||||||
|  | 				else | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 				dst[j] = s[i]; | ||||||
|  | 			j++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		i = j = strcspn(s, "# \n\r\t\v"); | ||||||
|  | 		memcpy(dst, s, j); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	dst[j] = '\0'; | ||||||
|  | 	return s + i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool | ||||||
|  | parse_pair(const char buffer[], char key[], char value[]) | ||||||
|  | { | ||||||
|  | 	const char *start; | ||||||
|  | 	const char *end; | ||||||
|  |  | ||||||
|  | 	key[0] = value[0] = '\0'; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * parse key | ||||||
|  | 	 */ | ||||||
|  | 	start = buffer; | ||||||
|  | 	if ((start = skip_space(start, buffer)) == NULL) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	end = start + strcspn(start, "=# \n\r\t\v"); | ||||||
|  |  | ||||||
|  | 	/* skip blank buffer */ | ||||||
|  | 	if (end - start <= 0) | ||||||
|  | 	{ | ||||||
|  | 		if (*start == '=') | ||||||
|  | 			elog(WARNING, "syntax error in \"%s\"", buffer); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* key found */ | ||||||
|  | 	strncpy(key, start, end - start); | ||||||
|  | 	key[end - start] = '\0'; | ||||||
|  |  | ||||||
|  | 	/* find key and value split char */ | ||||||
|  | 	if ((start = skip_space(end, buffer)) == NULL) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	if (*start != '=') | ||||||
|  | 	{ | ||||||
|  | 		elog(WARNING, "syntax error in \"%s\"", buffer); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	start++; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * parse value | ||||||
|  | 	 */ | ||||||
|  | 	if ((end = get_next_token(start, value, buffer)) == NULL) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	if ((start = skip_space(end, buffer)) == NULL) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	if (*start != '\0' && *start != '#') | ||||||
|  | 	{ | ||||||
|  | 		elog(WARNING, "syntax error in \"%s\"", buffer); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * execute - Execute a SQL and return the result. | ||||||
|  |  */ | ||||||
|  | PGresult * | ||||||
|  | execute(const char *query, int nParams, const char **params) | ||||||
|  | { | ||||||
|  | 	return pgut_execute(connection, query, nParams, params); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PGresult * | ||||||
|  | execute_elevel(const char *query, int nParams, const char **params, int elevel) | ||||||
|  | { | ||||||
|  | 	return pgut_execute_elevel(connection, query, nParams, params, elevel); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * command - Execute a SQL and discard the result. | ||||||
|  |  */ | ||||||
|  | ExecStatusType | ||||||
|  | command(const char *query, int nParams, const char **params) | ||||||
|  | { | ||||||
|  | 	return pgut_command(connection, query, nParams, params); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | set_elevel(pgut_option *opt, const char *arg) | ||||||
|  | { | ||||||
|  | 	pgut_log_level = parse_elevel(arg); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static pgut_option default_options[] = | ||||||
|  | { | ||||||
|  | 	{ 'b', 'e', "echo"			, &pgut_echo }, | ||||||
|  | 	{ 'f', 'E', "elevel"		, set_elevel }, | ||||||
|  | 	{ 's', 'd', "dbname"		, &dbname }, | ||||||
|  | 	{ 's', 'h', "host"			, &host }, | ||||||
|  | 	{ 's', 'p', "port"			, &port }, | ||||||
|  | 	{ 's', 'U', "username"		, &username }, | ||||||
|  | 	{ 'y', 'w', "no-password"	, &prompt_password }, | ||||||
|  | 	{ 'Y', 'W', "password"		, &prompt_password }, | ||||||
|  | 	{ 0 } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static size_t | ||||||
|  | option_length(const pgut_option opts[]) | ||||||
|  | { | ||||||
|  | 	size_t	len; | ||||||
|  | 	for (len = 0; opts && opts[len].type; len++) { } | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static pgut_option * | ||||||
|  | option_find(int c, pgut_option opts1[], pgut_option opts2[]) | ||||||
|  | { | ||||||
|  | 	size_t	i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; opts1 && opts1[i].type; i++) | ||||||
|  | 		if (opts1[i].sname == c) | ||||||
|  | 			return &opts1[i]; | ||||||
|  | 	for (i = 0; opts2 && opts2[i].type; i++) | ||||||
|  | 		if (opts2[i].sname == c) | ||||||
|  | 			return &opts2[i]; | ||||||
|  |  | ||||||
|  | 	return NULL;	/* not found */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Returns the current user name. | ||||||
|  |  */ | ||||||
|  | static char * | ||||||
|  | get_username(void) | ||||||
|  | { | ||||||
|  | 	char *ret; | ||||||
|  |  | ||||||
|  | #ifndef WIN32 | ||||||
|  | 	struct passwd *pw; | ||||||
|  |  | ||||||
|  | 	pw = getpwuid(geteuid()); | ||||||
|  | 	ret = (pw ? pw->pw_name : NULL); | ||||||
|  | #else | ||||||
|  | 	static char username[128];	/* remains after function execute */ | ||||||
|  | 	DWORD		len = sizeof(username) - 1; | ||||||
|  |  | ||||||
|  | 	if (GetUserNameA(username, &len)) | ||||||
|  | 		ret = username; | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		_dosmaperr(GetLastError()); | ||||||
|  | 		ret = NULL; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	if (ret == NULL) | ||||||
|  | 		ereport(ERROR, | ||||||
|  | 			(errcode_errno(), | ||||||
|  | 			 errmsg("could not get current user name: "))); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | option_has_arg(char type) | ||||||
|  | { | ||||||
|  | 	switch (type) | ||||||
|  | 	{ | ||||||
|  | 		case 'b': | ||||||
|  | 		case 'B': | ||||||
|  | 		case 'y': | ||||||
|  | 		case 'Y': | ||||||
|  | 			return no_argument; | ||||||
|  | 		default: | ||||||
|  | 			return required_argument; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | option_copy(struct option dst[], const pgut_option opts[], size_t len) | ||||||
|  | { | ||||||
|  | 	size_t	i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < len; i++) | ||||||
|  | 	{ | ||||||
|  | 		dst[i].name = opts[i].lname; | ||||||
|  | 		dst[i].has_arg = option_has_arg(opts[i].type); | ||||||
|  | 		dst[i].flag = NULL; | ||||||
|  | 		dst[i].val = opts[i].sname; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct option * | ||||||
|  | option_merge(const pgut_option opts1[], const pgut_option opts2[]) | ||||||
|  | { | ||||||
|  | 	struct option *result; | ||||||
|  | 	size_t	len1 = option_length(opts1); | ||||||
|  | 	size_t	len2 = option_length(opts2); | ||||||
|  | 	size_t	n = len1 + len2; | ||||||
|  |  | ||||||
|  | 	result = pgut_newarray(struct option, n + 1); | ||||||
|  | 	option_copy(result, opts1, len1); | ||||||
|  | 	option_copy(result + len1, opts2, len2); | ||||||
|  | 	memset(&result[n], 0, sizeof(pgut_option)); | ||||||
|  |  | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static char * | ||||||
|  | longopts_to_optstring(const struct option opts[]) | ||||||
|  | { | ||||||
|  | 	size_t	len; | ||||||
|  | 	char   *result; | ||||||
|  | 	char   *s; | ||||||
|  |  | ||||||
|  | 	for (len = 0; opts[len].name; len++) { } | ||||||
|  | 	result = pgut_malloc(len * 2 + 1); | ||||||
|  |  | ||||||
|  | 	s = result; | ||||||
|  | 	for (len = 0; opts[len].name; len++) | ||||||
|  | 	{ | ||||||
|  | 		if (!isprint(opts[len].val)) | ||||||
|  | 			continue; | ||||||
|  | 		*s++ = opts[len].val; | ||||||
|  | 		if (opts[len].has_arg != no_argument) | ||||||
|  | 			*s++ = ':'; | ||||||
|  | 	} | ||||||
|  | 	*s = '\0'; | ||||||
|  |  | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | pgut_getopt(int argc, char **argv, pgut_option options[]) | ||||||
|  | { | ||||||
|  | 	int					c; | ||||||
|  | 	int					optindex = 0; | ||||||
|  | 	char			   *optstring; | ||||||
|  | 	struct option	   *longopts; | ||||||
|  | 	pgut_option		   *opt; | ||||||
|  |  | ||||||
|  | 	pgut_init(argc, argv); | ||||||
|  |  | ||||||
|  | 	/* Help message and version are handled at first. */ | ||||||
|  | 	if (argc > 1) | ||||||
|  | 	{ | ||||||
|  | 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) | ||||||
|  | 		{ | ||||||
|  | 			help(true); | ||||||
|  | 			exit(1); | ||||||
|  | 		} | ||||||
|  | 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) | ||||||
|  | 		{ | ||||||
|  | 			fprintf(stderr, "%s %s\n", PROGRAM_NAME, PROGRAM_VERSION); | ||||||
|  | 			exit(1); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Merge default and user options. */ | ||||||
|  | 	longopts = option_merge(default_options, options); | ||||||
|  | 	optstring = longopts_to_optstring(longopts); | ||||||
|  |  | ||||||
|  | 	/* Assign named options */ | ||||||
|  | 	while ((c = getopt_long(argc, argv, optstring, longopts, &optindex)) != -1) | ||||||
|  | 	{ | ||||||
|  | 		opt = option_find(c, default_options, options); | ||||||
|  | 		pgut_setopt(opt, optarg, SOURCE_CMDLINE); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Read environment variables */ | ||||||
|  | 	option_from_env(options); | ||||||
|  | 	(void) (dbname || | ||||||
|  | 	(dbname = getenv("PGDATABASE")) || | ||||||
|  | 	(dbname = getenv("PGUSER")) || | ||||||
|  | 	(dbname = get_username())); | ||||||
|  |  | ||||||
|  | 	return optind; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | help(bool details) | ||||||
|  | { | ||||||
|  | 	pgut_help(details); | ||||||
|  |  | ||||||
|  | 	if (details) | ||||||
|  | 	{ | ||||||
|  | 		printf("\nConnection options:\n"); | ||||||
|  | 		printf("  -d, --dbname=DBNAME       database to connect\n"); | ||||||
|  | 		printf("  -h, --host=HOSTNAME       database server host or socket directory\n"); | ||||||
|  | 		printf("  -p, --port=PORT           database server port\n"); | ||||||
|  | 		printf("  -U, --username=USERNAME   user name to connect as\n"); | ||||||
|  | 		printf("  -w, --no-password         never prompt for password\n"); | ||||||
|  | 		printf("  -W, --password            force password prompt\n"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	printf("\nGeneric options:\n"); | ||||||
|  | 	if (details) | ||||||
|  | 	{ | ||||||
|  | 		printf("  -e, --echo                echo queries\n"); | ||||||
|  | 		printf("  -E, --elevel=LEVEL        set output message level\n"); | ||||||
|  | 	} | ||||||
|  | 	printf("  --help                    show this help, then exit\n"); | ||||||
|  | 	printf("  --version                 output version information, then exit\n"); | ||||||
|  |  | ||||||
|  | 	if (details && (PROGRAM_URL || PROGRAM_EMAIL)) | ||||||
|  | 	{ | ||||||
|  | 		printf("\n"); | ||||||
|  | 		if (PROGRAM_URL) | ||||||
|  | 			printf("Read the website for details. <%s>\n", PROGRAM_URL); | ||||||
|  | 		if (PROGRAM_EMAIL) | ||||||
|  | 			printf("Report bugs to <%s>.\n", PROGRAM_EMAIL); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								bin/pgut/pgut-fe.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										74
									
								
								bin/pgut/pgut-fe.h
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,74 @@ | |||||||
|  | /*------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * pgut-fe.h | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | ||||||
|  |  * | ||||||
|  |  *------------------------------------------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef PGUT_FE_H | ||||||
|  | #define PGUT_FE_H | ||||||
|  |  | ||||||
|  | #include "pgut.h" | ||||||
|  |  | ||||||
|  | typedef enum pgut_optsrc | ||||||
|  | { | ||||||
|  | 	SOURCE_DEFAULT, | ||||||
|  | 	SOURCE_ENV, | ||||||
|  | 	SOURCE_FILE, | ||||||
|  | 	SOURCE_CMDLINE, | ||||||
|  | 	SOURCE_CONST | ||||||
|  | } pgut_optsrc; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * type: | ||||||
|  |  *	b: bool (true) | ||||||
|  |  *	B: bool (false) | ||||||
|  |  *  f: pgut_optfn | ||||||
|  |  *	i: 32bit signed integer | ||||||
|  |  *	u: 32bit unsigned integer | ||||||
|  |  *	I: 64bit signed integer | ||||||
|  |  *	U: 64bit unsigned integer | ||||||
|  |  *	s: string | ||||||
|  |  *  t: time_t | ||||||
|  |  *	y: YesNo (YES) | ||||||
|  |  *	Y: YesNo (NO) | ||||||
|  |  */ | ||||||
|  | typedef struct pgut_option | ||||||
|  | { | ||||||
|  | 	char		type; | ||||||
|  | 	char		sname;		/* short name */ | ||||||
|  | 	const char *lname;		/* long name */ | ||||||
|  | 	void	   *var;		/* pointer to variable */ | ||||||
|  | 	pgut_optsrc	allowed;	/* allowed source */ | ||||||
|  | 	pgut_optsrc	source;		/* actual source */ | ||||||
|  | } pgut_option; | ||||||
|  |  | ||||||
|  | typedef void (*pgut_optfn) (pgut_option *opt, const char *arg); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | extern char	   *dbname; | ||||||
|  | extern char	   *host; | ||||||
|  | extern char	   *port; | ||||||
|  | extern char	   *username; | ||||||
|  | extern char	   *password; | ||||||
|  | extern YesNo	prompt_password; | ||||||
|  |  | ||||||
|  | extern PGconn	   *connection; | ||||||
|  |  | ||||||
|  | extern void	pgut_help(bool details); | ||||||
|  | extern void help(bool details); | ||||||
|  |  | ||||||
|  | extern void disconnect(void); | ||||||
|  | extern void reconnect(int elevel); | ||||||
|  | extern PGresult *execute(const char *query, int nParams, const char **params); | ||||||
|  | extern PGresult *execute_elevel(const char *query, int nParams, const char **params, int elevel); | ||||||
|  | extern ExecStatusType command(const char *query, int nParams, const char **params); | ||||||
|  |  | ||||||
|  | extern int pgut_getopt(int argc, char **argv, pgut_option options[]); | ||||||
|  | extern void pgut_readopt(const char *path, pgut_option options[], int elevel); | ||||||
|  | extern void pgut_setopt(pgut_option *opt, const char *optarg, pgut_optsrc src); | ||||||
|  | extern bool pgut_keyeq(const char *lhs, const char *rhs); | ||||||
|  |  | ||||||
|  | #endif   /* PGUT_FE_H */ | ||||||
							
								
								
									
										1400
									
								
								bin/pgut/pgut.c
									
									
									
									
									
								
							
							
						
						
									
										1400
									
								
								bin/pgut/pgut.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										144
									
								
								bin/pgut/pgut.h
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								bin/pgut/pgut.h
									
									
									
									
									
								
							| @ -11,23 +11,16 @@ | |||||||
| #define PGUT_H | #define PGUT_H | ||||||
|  |  | ||||||
| #include "c.h" | #include "c.h" | ||||||
|  | #include <assert.h> | ||||||
|  |  | ||||||
|  | #ifndef WIN32 | ||||||
|  | #include <sys/time.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include "libpq-fe.h" | #include "libpq-fe.h" | ||||||
| #include "pqexpbuffer.h" | #include "pqexpbuffer.h" | ||||||
|  | #include "utils/elog.h" | ||||||
| #include <assert.h> |  | ||||||
| #include <sys/time.h> |  | ||||||
|  |  | ||||||
| #if !defined(C_H) && !defined(__cplusplus) |  | ||||||
| #ifndef bool |  | ||||||
| typedef char bool; |  | ||||||
| #endif |  | ||||||
| #ifndef true |  | ||||||
| #define true	((bool) 1) |  | ||||||
| #endif |  | ||||||
| #ifndef false |  | ||||||
| #define false	((bool) 0) |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define INFINITE_STR		"INFINITE" | #define INFINITE_STR		"INFINITE" | ||||||
|  |  | ||||||
| @ -38,40 +31,6 @@ typedef enum YesNo | |||||||
| 	YES | 	YES | ||||||
| } YesNo; | } YesNo; | ||||||
|  |  | ||||||
| typedef enum pgut_optsrc |  | ||||||
| { |  | ||||||
| 	SOURCE_DEFAULT, |  | ||||||
| 	SOURCE_ENV, |  | ||||||
| 	SOURCE_FILE, |  | ||||||
| 	SOURCE_CMDLINE, |  | ||||||
| 	SOURCE_CONST |  | ||||||
| } pgut_optsrc; |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * type: |  | ||||||
|  *	b: bool (true) |  | ||||||
|  *	B: bool (false) |  | ||||||
|  *  f: pgut_optfn |  | ||||||
|  *	i: 32bit signed integer |  | ||||||
|  *	u: 32bit unsigned integer |  | ||||||
|  *	I: 64bit signed integer |  | ||||||
|  *	U: 64bit unsigned integer |  | ||||||
|  *	s: string |  | ||||||
|  *  t: time_t |  | ||||||
|  *	y: YesNo (YES) |  | ||||||
|  *	Y: YesNo (NO) |  | ||||||
|  */ |  | ||||||
| typedef struct pgut_option |  | ||||||
| { |  | ||||||
| 	char		type; |  | ||||||
| 	char		sname;		/* short name */ |  | ||||||
| 	const char *lname;		/* long name */ |  | ||||||
| 	void	   *var;		/* pointer to variable */ |  | ||||||
| 	pgut_optsrc	allowed;	/* allowed source */ |  | ||||||
| 	pgut_optsrc	source;		/* actual source */ |  | ||||||
| } pgut_option; |  | ||||||
|  |  | ||||||
| typedef void (*pgut_optfn) (pgut_option *opt, const char *arg); |  | ||||||
| typedef void (*pgut_atexit_callback)(bool fatal, void *userdata); | typedef void (*pgut_atexit_callback)(bool fatal, void *userdata); | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @ -82,52 +41,33 @@ extern const char  *PROGRAM_VERSION; | |||||||
| extern const char  *PROGRAM_URL; | extern const char  *PROGRAM_URL; | ||||||
| extern const char  *PROGRAM_EMAIL; | extern const char  *PROGRAM_EMAIL; | ||||||
|  |  | ||||||
| extern void	pgut_help(bool details); |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * pgut framework variables and functions |  * pgut framework variables and functions | ||||||
|  */ |  */ | ||||||
| extern const char  *dbname; |  | ||||||
| extern const char  *host; |  | ||||||
| extern const char  *port; |  | ||||||
| extern const char  *username; |  | ||||||
| extern char		   *password; |  | ||||||
| extern bool			debug; |  | ||||||
| extern bool			quiet; |  | ||||||
|  |  | ||||||
| #ifndef PGUT_NO_PROMPT |  | ||||||
| extern YesNo	prompt_password; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| extern PGconn	   *connection; |  | ||||||
| extern bool		interrupted; | extern bool		interrupted; | ||||||
|  | extern int		pgut_log_level; | ||||||
|  | extern int		pgut_abort_level; | ||||||
|  | extern bool		pgut_echo;	 | ||||||
|  |  | ||||||
| extern void help(bool details); | extern void pgut_init(int argc, char **argv); | ||||||
| extern int pgut_getopt(int argc, char **argv, pgut_option options[]); |  | ||||||
| extern void pgut_readopt(const char *path, pgut_option options[], int elevel); |  | ||||||
| extern void pgut_setopt(pgut_option *opt, const char *optarg, pgut_optsrc src); |  | ||||||
| extern bool pgut_keyeq(const char *lhs, const char *rhs); |  | ||||||
| extern void pgut_atexit_push(pgut_atexit_callback callback, void *userdata); | extern void pgut_atexit_push(pgut_atexit_callback callback, void *userdata); | ||||||
| extern void pgut_atexit_pop(pgut_atexit_callback callback, void *userdata); | extern void pgut_atexit_pop(pgut_atexit_callback callback, void *userdata); | ||||||
|  | extern void pgut_putenv(const char *key, const char *value); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Database connections |  * Database connections | ||||||
|  */ |  */ | ||||||
| extern PGconn *pgut_connect(int elevel); | extern PGconn *pgut_connect(const char *info, YesNo prompt, int elevel); | ||||||
| extern PGconn *pgut_connectdb(const char *conninfo, int elevel); |  | ||||||
| extern void pgut_disconnect(PGconn *conn); | extern void pgut_disconnect(PGconn *conn); | ||||||
| extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, const char **params, int elevel); | extern void pgut_disconnect_all(void); | ||||||
| extern ExecStatusType pgut_command(PGconn* conn, const char *query, int nParams, const char **params, int elevel); | extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, const char **params); | ||||||
| extern bool pgut_send(PGconn* conn, const char *query, int nParams, const char **params, int elevel); | PGresult *pgut_execute_elevel(PGconn* conn, const char *query, int nParams, const char **params, int elevel); | ||||||
|  | extern ExecStatusType pgut_command(PGconn* conn, const char *query, int nParams, const char **params); | ||||||
|  | extern bool pgut_commit(PGconn *conn); | ||||||
|  | extern void pgut_rollback(PGconn *conn); | ||||||
|  | extern bool pgut_send(PGconn* conn, const char *query, int nParams, const char **params); | ||||||
| extern int pgut_wait(int num, PGconn *connections[], struct timeval *timeout); | extern int pgut_wait(int num, PGconn *connections[], struct timeval *timeout); | ||||||
|  |  | ||||||
| extern PGconn *reconnect_elevel(int elevel); |  | ||||||
| extern void reconnect(void); |  | ||||||
| extern void disconnect(void); |  | ||||||
| extern PGresult *execute_elevel(const char *query, int nParams, const char **params, int elevel); |  | ||||||
| extern PGresult *execute(const char *query, int nParams, const char **params); |  | ||||||
| extern void command(const char *query, int nParams, const char **params); |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * memory allocators |  * memory allocators | ||||||
|  */ |  */ | ||||||
| @ -139,37 +79,38 @@ extern char *strdup_trim(const char *str); | |||||||
|  |  | ||||||
| #define pgut_new(type)			((type *) pgut_malloc(sizeof(type))) | #define pgut_new(type)			((type *) pgut_malloc(sizeof(type))) | ||||||
| #define pgut_newarray(type, n)	((type *) pgut_malloc(sizeof(type) * (n))) | #define pgut_newarray(type, n)	((type *) pgut_malloc(sizeof(type) * (n))) | ||||||
|  | #define pgut_newvar(type, m, n)	((type *) pgut_malloc(offsetof(type, m) + (n))) | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * file operations |  * file operations | ||||||
|  */ |  */ | ||||||
| extern FILE *pgut_fopen(const char *path, const char *mode, bool missing_ok); | extern FILE *pgut_fopen(const char *path, const char *mode); | ||||||
| extern void pgut_mkdir(const char *path); | extern bool pgut_mkdir(const char *path); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * elog |  * elog | ||||||
|  */ |  */ | ||||||
| #define LOG			(-4) | #define E_PG_CONNECT	(-1)	/* PostgreSQL connection error */ | ||||||
| #define INFO		(-3) | #define E_PG_COMMAND	(-2)	/* PostgreSQL query or command error */ | ||||||
| #define NOTICE		(-2) |  | ||||||
| #define WARNING		(-1) |  | ||||||
| #define HELP		1 |  | ||||||
| #define ERROR		2 |  | ||||||
| #define FATAL		3 |  | ||||||
| #define PANIC		4 |  | ||||||
|  |  | ||||||
| #define ERROR_SYSTEM			10	/* I/O or system error */ |  | ||||||
| #define ERROR_NOMEM				11	/* memory exhausted */ |  | ||||||
| #define ERROR_ARGS				12	/* some configurations are invalid */ |  | ||||||
| #define ERROR_INTERRUPTED		13	/* interrupted by signal */ |  | ||||||
| #define ERROR_PG_COMMAND		14	/* PostgreSQL query or command error */ |  | ||||||
| #define ERROR_PG_CONNECT		15	/* PostgreSQL connection error */ |  | ||||||
|  |  | ||||||
| #undef elog | #undef elog | ||||||
| extern void | #undef ereport | ||||||
| elog(int elevel, const char *fmt, ...) | #define ereport(elevel, rest) \ | ||||||
| __attribute__((format(printf, 2, 3))); | 	(pgut_errstart(elevel) ? (pgut_errfinish rest) : (void) 0) | ||||||
|  |  | ||||||
|  | extern void elog(int elevel, const char *fmt, ...) | ||||||
|  | __attribute__((format(printf, 2, 3))); | ||||||
|  | extern const char *format_elevel(int elevel); | ||||||
|  | extern int parse_elevel(const char *value); | ||||||
|  | extern int errcode_errno(void); | ||||||
|  | extern bool log_required(int elevel, int log_min_level); | ||||||
|  | extern bool pgut_errstart(int elevel); | ||||||
|  | extern void pgut_errfinish(int dummy, ...); | ||||||
|  | extern void pgut_error(int elevel, int code, const char *msg, const char *detail); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * CHECK_FOR_INTERRUPTS | ||||||
|  |  */ | ||||||
| #undef CHECK_FOR_INTERRUPTS | #undef CHECK_FOR_INTERRUPTS | ||||||
| extern void CHECK_FOR_INTERRUPTS(void); | extern void CHECK_FOR_INTERRUPTS(void); | ||||||
|  |  | ||||||
| @ -209,6 +150,7 @@ extern void CHECK_FOR_INTERRUPTS(void); | |||||||
| #define appendStringInfoChar	appendPQExpBufferChar | #define appendStringInfoChar	appendPQExpBufferChar | ||||||
| #define appendBinaryStringInfo	appendBinaryPQExpBuffer | #define appendBinaryStringInfo	appendBinaryPQExpBuffer | ||||||
|  |  | ||||||
|  | extern bool appendStringInfoVA(StringInfo str, const char *fmt, va_list args); | ||||||
| extern int appendStringInfoFile(StringInfo str, FILE *fp); | extern int appendStringInfoFile(StringInfo str, FILE *fp); | ||||||
| extern int appendStringInfoFd(StringInfo str, int fd); | extern int appendStringInfoFd(StringInfo str, int fd); | ||||||
|  |  | ||||||
|  | |||||||
| @ -17,11 +17,21 @@ | |||||||
| <h1>pg_reorg ホームページへようこそ</h1> | <h1>pg_reorg ホームページへようこそ</h1> | ||||||
| <hr /> | <hr /> | ||||||
| </center> | </center> | ||||||
|  |  | ||||||
|  | <p>このプロジェクトでは <strong>pg_reorg</strong> と <strong>pg_batch</strong> の2つのツールを頒布しています。</p> | ||||||
|  |  | ||||||
| <p> | <p> | ||||||
| pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンドです。 | <strong>pg_reorg</strong> は PostgreSQL のテーブルを再編成するシェルコマンドです。 | ||||||
| 共有ロックや排他ロックを取得しないため、再編成中であっても行の参照や更新を行うことができます。 | 共有ロックや排他ロックを取得しないため、再編成中であっても行の参照や更新を行うことができます。 | ||||||
| このモジュールは CLUSTER や VACUUM FULL コマンドのより良い代替になります。 | このモジュールは CLUSTER や VACUUM FULL コマンドのより良い代替になります。 | ||||||
| </p> | </p> | ||||||
|  |  | ||||||
|  | <p> | ||||||
|  | <strong>pg_batch</strong> は PostgreSQL のためのSQLジョブ実行プログラムです。 | ||||||
|  | ジョブ一覧生成するスクリプトを SQL として外部から与え、その出力 SQL をジョブとしてシリアルまたはパラレルに実行します。 | ||||||
|  | VACUUM を行うスクリプトが付属しており、"より良い vacuumdb" として利用できます。 | ||||||
|  | </p> | ||||||
|  |  | ||||||
| <p>この pg_reorg プロジェクトは <a href="http://www.postgresql.org">PostgreSQL</a> コミュニティによる <a href="http://pgfoundry.org">pgFoundry</a> の中の<a href="http://pgfoundry.org/projects/reorg">プロジェクト</a>です。</p> | <p>この pg_reorg プロジェクトは <a href="http://www.postgresql.org">PostgreSQL</a> コミュニティによる <a href="http://pgfoundry.org">pgFoundry</a> の中の<a href="http://pgfoundry.org/projects/reorg">プロジェクト</a>です。</p> | ||||||
| <ul> | <ul> | ||||||
| 	<li><a href="http://pgfoundry.org/frs/?group_id=1000411">ダウンロード</a> : ソースコードのほか、Windows 用バイナリもダウンロードできます。</li> | 	<li><a href="http://pgfoundry.org/frs/?group_id=1000411">ダウンロード</a> : ソースコードのほか、Windows 用バイナリもダウンロードできます。</li> | ||||||
| @ -34,9 +44,11 @@ pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンド | |||||||
| <hr /> | <hr /> | ||||||
|  |  | ||||||
| <h2>ドキュメント</h2> | <h2>ドキュメント</h2> | ||||||
| <p> |  | ||||||
| <a href="pg_reorg-ja.html">ドキュメントはこちら</a>。 | <ul> | ||||||
| </p> | <li><a href="pg_reorg-ja.html">pg_reorg 1.1.0 ドキュメント</a></li> | ||||||
|  | <li><a href="pg_batch-ja.html">pg_batch 1.2.0 ドキュメント</a></li> | ||||||
|  | </ul> | ||||||
|  |  | ||||||
| <h2>実行時間</h2> | <h2>実行時間</h2> | ||||||
| <p> | <p> | ||||||
|  | |||||||
| @ -17,10 +17,22 @@ | |||||||
| <h1>Welcome to the pg_reorg Project Home Page</h1> | <h1>Welcome to the pg_reorg Project Home Page</h1> | ||||||
| <hr /> | <hr /> | ||||||
| </center> | </center> | ||||||
|  |  | ||||||
| <p> | <p> | ||||||
| pg_reorg can re-organize tables on a postgres database without any locks so that you can retrieve or update rows in tables being reorganized. | This project provides two tools for PostgreSQL; <strong>pg_reorg</strong> and <strong>pg_batch</strong>. | ||||||
|  | </p> | ||||||
|  |  | ||||||
|  | <p> | ||||||
|  | <strong>pg_reorg</strong> can re-organize tables on a postgres database without any locks so that you can retrieve or update rows in tables being reorganized. | ||||||
| The module is developed to be a better alternative of CLUSTER and VACUUM FULL. | The module is developed to be a better alternative of CLUSTER and VACUUM FULL. | ||||||
| </p> | </p> | ||||||
|  |  | ||||||
|  | <p> | ||||||
|  | <strong>pg_batch</strong> is a SQL job executor program for PostgreSQL. | ||||||
|  | It generates job list from an external SQL script file, and execute the jobs in serial or parallel. | ||||||
|  | It can be used as "a better vacuumdb" with the attached script to run VACUUM. | ||||||
|  | </p> | ||||||
|  |  | ||||||
| <p> | <p> | ||||||
| The pg_reorg project is a <a href="http://www.postgresql.org">PostgreSQL</a> Community project that is a part of the <a href="http://pgfoundry.org">pgFoundry</a>. | The pg_reorg project is a <a href="http://www.postgresql.org">PostgreSQL</a> Community project that is a part of the <a href="http://pgfoundry.org">pgFoundry</a>. | ||||||
| </p> | </p> | ||||||
| @ -34,9 +46,11 @@ where you can find <a href="http://pgfoundry.org/frs/?group_id=1000411">download | |||||||
| <hr /> | <hr /> | ||||||
|  |  | ||||||
| <h2>Documentation</h2> | <h2>Documentation</h2> | ||||||
| <p> |  | ||||||
| <a href="pg_reorg.html">Documentations here</a>. | <ul> | ||||||
| </p> | <li><a href="pg_reorg.html">pg_reorg 1.1.0 documentation</a></li> | ||||||
|  | <li><a href="pg_batch-ja.html">pg_batch 1.2.0 documentation</a> (ja)</li> | ||||||
|  | </ul> | ||||||
|  |  | ||||||
| <h2>Execution time</h2> | <h2>Execution time</h2> | ||||||
| <p> | <p> | ||||||
|  | |||||||
| @ -8,7 +8,12 @@ | |||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
| <h1 id="pg_reorg">pg_reorg</h1> | <h1 id="pg_reorg">pg_reorg 1.1.0</h1> | ||||||
|  | <div class="navigation"> | ||||||
|  |   <a href="index-ja.html">Top</a> > | ||||||
|  |   <a href="pg_reorg-ja.html">pg_reorg</a> | ||||||
|  | <div> | ||||||
|  | <hr /> | ||||||
|  |  | ||||||
| <div class="index"> | <div class="index"> | ||||||
| <ol> | <ol> | ||||||
| @ -31,28 +36,34 @@ pg_reorg -- PostgreSQLデータベース内のテーブルに対して、参照/ | |||||||
|  |  | ||||||
| <h2 id="synopsis">概要</h2> | <h2 id="synopsis">概要</h2> | ||||||
| <p> | <p> | ||||||
| pg_reorg [connection-options...]  [message-options...]  [order-options...]  [target-options...] | pg_reorg [OPTIONS] | ||||||
| </p> | </p> | ||||||
| <p>指定できるオプションには4つのカテゴリがあります。 |  | ||||||
|  | <p>オプション OPTIONS には以下を指定できます。 | ||||||
| 詳細は<a href="#options">オプション</a>を参照してください。</p> | 詳細は<a href="#options">オプション</a>を参照してください。</p> | ||||||
| <dl> | <ul> | ||||||
|  <dt>connection-options : 接続パラメータ</dt> |   <li>固有オプション<ul> | ||||||
|   <dd>-h [--host] host</dd> |     <li>-o [--order-by]  columns [,...]</li> | ||||||
|   <dd>-p [--port] port</dd> |     <li>-n [--no-order]</li> | ||||||
|   <dd>-U [--username] username</dd> |     <li>-t [--table] table</li> | ||||||
|   <dd>-W [--password]</dd> |     <li>-T [--wait-timeout] seconds</li> | ||||||
|  <dt>message-options : 出力メッセージ</dt> |     <li>-Z [--no-analyze]</li> | ||||||
|   <dd>-q [--quiet]</dd> |   </ul></li> | ||||||
|   <dd>-v [--verbose]</dd> |   <li>接続オプション<ul> | ||||||
|  <dt>order-options : 並び替えの基準</dt> |     <li>-a, --all : 全てのデータベースに対して実行します</li> | ||||||
|   <dd>-o [--order-by]  columns [,...]</dd> |     <li>-d, --dbname=DBNAME : 接続するデータベース</li> | ||||||
|   <dd>-n [--no-order]</dd> |     <li>-h, --host=HOSTNAME : データベースサーバホスト、またはソケットディレクトリ</li> | ||||||
|  <dt>target-options : 処理対象</dt> |     <li>-p, --port=PORT : データベースサーバのポート</li> | ||||||
|   <dd>-a [--all]</dd> |     <li>-U, --username=USERNAME : このユーザとして接続します</li> | ||||||
|   <dd>-d [--dbname] dbname</dd> |     <li>-W, --password : パスワード入力を強制します</li> | ||||||
|   <dd>-t [--table] table</dd> |   </ul></li> | ||||||
|   <dd>-Z [--no-analyze]</dd> |   <li>一般オプション<ul> | ||||||
| </dl> |     <li>-e, --echo : サーバに送信するSQLを表示します</li> | ||||||
|  |     <li>-E, --elevel=LEVEL : ログ出力レベルを設定します</li> | ||||||
|  |     <li>--help : ヘルプを表示し、終了します</li> | ||||||
|  |     <li>--version : バージョン情報を出力し、終了します</li> | ||||||
|  |   </ul></li> | ||||||
|  | </ul> | ||||||
|  |  | ||||||
| <h2 id="description">説明</h2> | <h2 id="description">説明</h2> | ||||||
| <p>pg_reorg は、PostgreSQLデータベース内のテーブルを再編成(行の並び替え)するユーティリティです。 | <p>pg_reorg は、PostgreSQLデータベース内のテーブルを再編成(行の並び替え)するユーティリティです。 | ||||||
| @ -77,47 +88,11 @@ pg_reorg [connection-options...]  [message-options...]  [order-options...]  [tar | |||||||
| </p> | </p> | ||||||
|  |  | ||||||
| <h2 id="options">オプション</h2> | <h2 id="options">オプション</h2> | ||||||
| <p>pg_reorg では、下記の4種類のコマンドライン引数を指定できます。</p> | <p>pg_reorg では、下記のコマンドライン引数を指定できます。</p> | ||||||
| <dl> | <dl> | ||||||
|  |  | ||||||
| <h3>connection-options</h3> | <h3>固有オプション</h3> | ||||||
| <p>PostgreSQLに接続するためのパラメータです。</p> | <p>pg_reorg を実行する対象と並び替えの基準を指定するパラメータです。 | ||||||
|  |  | ||||||
| <dl> |  | ||||||
| <dt>-h host<br /> |  | ||||||
| --host host</dt> |  | ||||||
| <dd>サーバが稼働しているマシンのホスト名を指定します。ホスト名がスラッシュから始まる場合、Unixドメインソケット用のディレクトリとして使用されます。</dd> |  | ||||||
|  |  | ||||||
| <dt>-p port<br /> |  | ||||||
| --port port</dt> |  | ||||||
| <dd>サーバが接続を監視するTCPポートもしくはUnixドメインソケットファイルの拡張子を指定します。</dd> |  | ||||||
|  |  | ||||||
| <dt>-U username<br /> |  | ||||||
| --username username</dt> |  | ||||||
| <dd>接続するユーザ名を指定します。</dd> |  | ||||||
|  |  | ||||||
| <dt>-W<br />--password</dt> |  | ||||||
| <dd>データベースに接続する前に、pg_reorg は強制的にパスワード入力を促します。</dd> |  | ||||||
| <dd>サーバがパスワード認証を要求する場合 pg_reorg は自動的にパスワード入力を促しますので、これが重要になることはありません。 |  | ||||||
| しかし、pg_reorg は、サーバにパスワードが必要かどうかを判断するための接続試行を無駄に行います。 |  | ||||||
| こうした余計な接続試行を防ぐために-Wの入力が有意となる場合もあります。</dd> |  | ||||||
| </dl> |  | ||||||
|  |  | ||||||
| <h3>message-options</h3> |  | ||||||
| <p> |  | ||||||
| pg_reorg を実行した際に任意のメッセージを出力するためのパラメータです。 |  | ||||||
| --quietと他の2つのオプションを同時に指定した場合は、--quietのオプションは無視されます。 |  | ||||||
| </p> |  | ||||||
|  |  | ||||||
| <dl> |  | ||||||
| <dt>-q<br />--quiet</dt> |  | ||||||
| <dd>進行メッセージを表示しません。</dd> |  | ||||||
| <dt>-v<br />--verbose</dt> |  | ||||||
| <dd>処理中に詳細な情報を表示します。</dd> |  | ||||||
| </dl> |  | ||||||
|  |  | ||||||
| <h3>order-options</h3> |  | ||||||
| <p>pg_reorg を実行する際の並び替えの基準を指定するパラメータです。 |  | ||||||
| 何も指定されていない場合は、cluster index順にオンライン CLUSTER を行います。 | 何も指定されていない場合は、cluster index順にオンライン CLUSTER を行います。 | ||||||
| この2つを同時に指定することはできません。 | この2つを同時に指定することはできません。 | ||||||
| </p> | </p> | ||||||
| @ -131,9 +106,34 @@ pg_reorg を実行した際に任意のメッセージを出力するための | |||||||
| <dd>指定したカラムをキーにオンライン CLUSTER を行います。</dd> | <dd>指定したカラムをキーにオンライン CLUSTER を行います。</dd> | ||||||
| </dl> | </dl> | ||||||
|  |  | ||||||
| <h3>target-options</h3> | <dt> | ||||||
|  | -t table<br /> | ||||||
|  | --table=table | ||||||
|  | </dt> | ||||||
|  | <dd>オンライン CLUSTER 、または、オンライン VACUUM FULL を行うテーブルを指定します。 | ||||||
|  | このオプションが指定されていない場合は、対象となったデータベースに存在する全ての対象テーブルに対して処理を行います。 | ||||||
|  | </dd> | ||||||
|  |  | ||||||
|  | <dt> | ||||||
|  | -T seconds<br /> | ||||||
|  | --wait-timeout=seconds | ||||||
|  | </dt> | ||||||
|  | <dd> | ||||||
|  | 再編成完了直前に一瞬だけ排他ロックを取得しますが、この排他ロックが取得できるまで待機する秒数を指定します。 | ||||||
|  | この秒数が経過してもロックが取得できない場合には、対象のテーブルにアクセスしている他の全てのクエリを取り消します。 | ||||||
|  | また、サーバのバージョンが 8.4 またはそれ以降の場合には、指定した秒数の2倍経過してもロックを取得できない場合には、強制的に切断します。 | ||||||
|  | デフォルトは60秒です。 | ||||||
|  | </dd> | ||||||
|  |  | ||||||
|  | <dt>-Z<br />--no-analyze</dt> | ||||||
|  | <dd>再編成後に ANALYZE を行いません。 | ||||||
|  | このオプションが指定されていない場合は、再編成後に ANALYZE します。</dd> | ||||||
|  |  | ||||||
|  | </dl> | ||||||
|  |  | ||||||
|  | <h3>接続オプション</h3> | ||||||
| <p> | <p> | ||||||
| pg_reorg を実行する対象を指定するパラメータです。 | PostgreSQLに接続するためのパラメータです。 | ||||||
| --allと--dbnameまたは--tableを同時に指定することはできません。 | --allと--dbnameまたは--tableを同時に指定することはできません。 | ||||||
| </p> | </p> | ||||||
|  |  | ||||||
| @ -142,26 +142,46 @@ pg_reorg を実行する対象を指定するパラメータです。 | |||||||
| <dd>対象となる全てのデータベースに対してオンライン CLUSTER、または、オンラインVACUUM  FULLを行います。</dd> | <dd>対象となる全てのデータベースに対してオンライン CLUSTER、または、オンラインVACUUM  FULLを行います。</dd> | ||||||
|  |  | ||||||
| <dt> | <dt> | ||||||
| -d dbname<br /> | -d DBNAME<br /> | ||||||
| --dbname dbname | --dbname=DBNAME | ||||||
| </dt> | </dt> | ||||||
| <dd>オンライン CLUSTER、または、オンライン VACUUM FULL を行うデータベース名を指定します。 | <dd>オンライン CLUSTER、または、オンライン VACUUM FULL を行うデータベース名を指定します。 | ||||||
| データベース名が指定されておらず、-a(または--all)も指定されていない場合、 | データベース名が指定されておらず、-a(または--all)も指定されていない場合、 | ||||||
| データベース名はPGDATABASE環境変数から読み取られます。この変数も設定されていない場合は、接続時に指定したユーザ名が使用されます。 | データベース名はPGDATABASE環境変数から読み取られます。 | ||||||
| </dd> | この変数も設定されていない場合は、接続時に指定したユーザ名が使用されます。</dd> | ||||||
|  |  | ||||||
| <dt> | <dt>-h HOSTNAME<br /> | ||||||
| -t table<br /> | --host=HOSTNAME</dt> | ||||||
| --table table | <dd>サーバが稼働しているマシンのホスト名を指定します。ホスト名がスラッシュから始まる場合、Unixドメインソケット用のディレクトリとして使用されます。</dd> | ||||||
| </dt> |  | ||||||
| <dd>オンライン CLUSTER 、または、オンライン VACUUM FULL を行うテーブルを指定します。 |  | ||||||
| このオプションが指定されていない場合は、対象となったデータベースに存在する全ての対象テーブルに対して処理を行います。 |  | ||||||
| </dd> |  | ||||||
|  |  | ||||||
| <dt>-Z<br />--no-analyze</dt> | <dt>-p PORT<br /> | ||||||
| <dd>再編成後に ANALYZE を行いません。 | --port=PORT</dt> | ||||||
| このオプションが指定されていない場合は、再編成後に ANALYZE します。</dd> | <dd>サーバが接続を監視するTCPポートもしくはUnixドメインソケットファイルの拡張子を指定します。</dd> | ||||||
|  |  | ||||||
|  | <dt>-U USERNAME<br /> | ||||||
|  | --username=USERNAME</dt> | ||||||
|  | <dd>接続するユーザ名を指定します。</dd> | ||||||
|  |  | ||||||
|  | <dt>-W<br /> | ||||||
|  | --password</dt> | ||||||
|  | <dd>データベースに接続する前に、強制的にパスワード入力を促します。 | ||||||
|  | サーバがパスワード認証を要求する場合 自動的にパスワード入力を促しますので、これが重要になることはありません。 | ||||||
|  | しかし、サーバにパスワードが必要かどうかを判断するための接続試行を無駄に行います。 | ||||||
|  | こうした余計な接続試行を防ぐために -W の入力が有意となる場合もあります。</dd> | ||||||
|  | </dl> | ||||||
|  |  | ||||||
|  | <h3>一般オプション</h3> | ||||||
|  | <dl> | ||||||
|  | <dt>-e<br />--echo</dt> | ||||||
|  | <dd>サーバに送信するSQLを表示します。</dd> | ||||||
|  | <dt>-E<br />--elevel</dt> | ||||||
|  | <dd>ログ出力レベルを設定します。 | ||||||
|  | DEBUG, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, PANIC から選択します。 | ||||||
|  | デフォルトは INFO です。</dd> | ||||||
|  | <dt>--help</dt> | ||||||
|  | <dd>使用方法について表示します。</dd> | ||||||
|  | <dt>--version</dt> | ||||||
|  | <dd>バージョン情報を表示します。</dd> | ||||||
| </dl> | </dl> | ||||||
|  |  | ||||||
| <h2 id="environment">環境変数</h2> | <h2 id="environment">環境変数</h2> | ||||||
| @ -268,9 +288,12 @@ pg_reorg の実行中には、VACUUM と ANALYZE <STRONG>以外</STRONG> のDDL | |||||||
|  |  | ||||||
| <h2 id="requirement">動作環境</h2> | <h2 id="requirement">動作環境</h2> | ||||||
| <dl> | <dl> | ||||||
| <dt>PostgreSQLバージョン</dt><dd>PostgreSQL 8.3</dd> | <dt>PostgreSQLバージョン</dt> | ||||||
| <dt>OS</dt><dd>RHEL 5.2, Windows XP SP3</dd> | <dd>PostgreSQL 8.3, 8.4, 9.0</dd> | ||||||
| <dt>ディスク容量</dt><dd>処理対象のテーブル、インデックスサイズの2倍以上のディスク空き容量</dd> | <dt>OS</dt> | ||||||
|  | <dd>RHEL 5.2, Windows XP SP3</dd> | ||||||
|  | <dt>ディスク容量</dt> | ||||||
|  | <dd>処理対象のテーブル、インデックスサイズの2倍以上のディスク空き容量 (対象が1GBならば、さらに追加で2GB)</dd> | ||||||
| </dl> | </dl> | ||||||
|  |  | ||||||
| <h2 id="seealso">関連項目</h2> | <h2 id="seealso">関連項目</h2> | ||||||
| @ -278,6 +301,10 @@ pg_reorg の実行中には、VACUUM と ANALYZE <STRONG>以外</STRONG> のDDL | |||||||
| <a href="http://www.postgresql.jp/document/current/html/app-vacuumdb.html">vacuumdb</a> | <a href="http://www.postgresql.jp/document/current/html/app-vacuumdb.html">vacuumdb</a> | ||||||
|  |  | ||||||
| <hr /> | <hr /> | ||||||
|  | <div class="navigation"> | ||||||
|  |   <a href="index-ja.html">Top</a> > | ||||||
|  |   <a href="pg_reorg-ja.html">pg_reorg</a> | ||||||
|  | <div> | ||||||
| <p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p> | <p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p> | ||||||
|  |  | ||||||
| <script type="text/javascript"> | <script type="text/javascript"> | ||||||
|  | |||||||
| @ -8,7 +8,12 @@ | |||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
| <h1 id="pg_reorg">pg_reorg</h1> | <h1 id="pg_reorg">pg_reorg 1.1.0</h1> | ||||||
|  | <div class="navigation"> | ||||||
|  |   <a href="index.html">Top</a> > | ||||||
|  |   <a href="pg_reorg.html">pg_reorg</a> | ||||||
|  | <div> | ||||||
|  | <hr /> | ||||||
|  |  | ||||||
| <div class="index"> | <div class="index"> | ||||||
| <ol> | <ol> | ||||||
| @ -31,28 +36,34 @@ pg_reorg -- Reorganize tables in PostgreSQL databases without any locks. | |||||||
|  |  | ||||||
| <h2 id="synopsis">Synopsis</h2> | <h2 id="synopsis">Synopsis</h2> | ||||||
| <p> | <p> | ||||||
| pg_reorg [connection-options...]  [message-options...]  [order-options...]  [target-options...] | pg_reorg [OPTIONS] | ||||||
| </p> | </p> | ||||||
| <p>There 4 option categories. |  | ||||||
| See also <a href="#options">options</a> for details.</p> | <p>The following options can be specified in OPTIONS. | ||||||
| <dl> | See also "<a href="#options">Options</a>" for details.</p> | ||||||
|  <dt>connection-options</dt> | <ul> | ||||||
|   <dd>-h [--host] host</dd> |   <li>Reorg Options<ul> | ||||||
|   <dd>-p [--port] port</dd> |     <li>-o [--order-by]  columns [,...]</li> | ||||||
|   <dd>-U [--username] username</dd> |     <li>-n [--no-order]</li> | ||||||
|   <dd>-W [--password]</dd> |     <li>-t [--table] table</li> | ||||||
|  <dt>message-options</dt> |     <li>-T [--wait-timeout] seconds</li> | ||||||
|   <dd>-q [--quiet]</dd> |     <li>-Z [--no-analyze]</li> | ||||||
|   <dd>-v [--verbose]</dd> |   </ul></li> | ||||||
|  <dt>order-options</dt> |   <li>Connection Options<ul> | ||||||
|   <dd>-o [--order-by]  columns [,...]</dd> |     <li>-a, --all : reorganize all databases</li> | ||||||
|   <dd>-n [--no-order]</dd> |     <li>-d, --dbname=DBNAME : database to connect</li> | ||||||
|  <dt>target-options</dt> |     <li>-h, --host=HOSTNAME : database server host or socket directory</li> | ||||||
|   <dd>-a [--all]</dd> |     <li>-p, --port=PORT : database server port</li> | ||||||
|   <dd>-d [--dbname] dbname</dd> |     <li>-U, --username=USERNAME : user name to connect as</li> | ||||||
|   <dd>-t [--table] table</dd> |     <li>-W, --password : force password prompt</li> | ||||||
|   <dd>-Z [--no-analyze]</dd> |   </ul></li> | ||||||
| </dl> |   <li>Generic Options<ul> | ||||||
|  |     <li>-e, --echo : echo queries</li> | ||||||
|  |     <li>-E, --elevel=LEVEL : set output message level</li> | ||||||
|  |     <li>--help : show the help, then exit</li> | ||||||
|  |     <li>--version : output version information, then exit</li> | ||||||
|  |   </ul></li> | ||||||
|  | </ul> | ||||||
|  |  | ||||||
| <h2 id="description">Description</h2> | <h2 id="description">Description</h2> | ||||||
| <p>pg_reorg is an utility program to reorganize tables in PostgreSQL databases. | <p>pg_reorg is an utility program to reorganize tables in PostgreSQL databases. | ||||||
| @ -77,15 +88,68 @@ You can choose one of the following methods to reorganize.</p> | |||||||
| </p> | </p> | ||||||
|  |  | ||||||
| <h2 id="options">Options</h2> | <h2 id="options">Options</h2> | ||||||
| <p>pg_reorg has command line options in 4 categolies.</p> | <p>pg_reorg has the following command line options:</p> | ||||||
| <div> |  | ||||||
| <dl> | <dl> | ||||||
|  |  | ||||||
| <h3>connection-options</h3> | <h3>Reorg Options</h3> | ||||||
| <p>Parameters to connect PostgreSQL.</p> | <p>Options to order rows. | ||||||
|  | If not specified, pg_reorg do online CLUSTER using cluster indexes. | ||||||
|  | Only one option can be specified. | ||||||
|  |  | ||||||
|  | Options to specify target tables or databases. | ||||||
|  | </p> | ||||||
|  |  | ||||||
| <div> |  | ||||||
| <dl> | <dl> | ||||||
|  | <dt>-n<br />--no-order</dt> | ||||||
|  | <dd>Do online VACUUM FULL.</dd> | ||||||
|  |  | ||||||
|  | <dt>-o columns [,...]<br /> | ||||||
|  | --order-by=columns [,...]</dt> | ||||||
|  | <dd>Do online CLUSTER ordered by specified columns.</dd> | ||||||
|  |  | ||||||
|  | <dt> | ||||||
|  | -t table<br /> | ||||||
|  | --table=table | ||||||
|  | </dt> | ||||||
|  | <dd>Reorganize table only. If you don't specify this option, all tables in specified databases are reorganized.</dd> | ||||||
|  |  | ||||||
|  | <dt>-Z<br />--no-analyze</dt> | ||||||
|  | <dd>Do ANALYZE after reorganization. If you don't specify this option, ANALYZE is performed automatically after reorg.</dd> | ||||||
|  |  | ||||||
|  | <dt> | ||||||
|  | -T seconds<br /> | ||||||
|  | --wait-timeout=seconds | ||||||
|  | </dt> | ||||||
|  | <dd> | ||||||
|  | pg_reorg needs to take an exclusive lock at the end of the reorganization. | ||||||
|  | This setting controls how long it wait for acquiring the lock in seconds. | ||||||
|  | If the lock cannot be taken even after the duration, pg_reorg forces to cancel conflicted queries. | ||||||
|  | Also, if the server version is 8.4 or newer, pg_reorg forces to disconnect conflicted backends after twice time passed. | ||||||
|  | The default is 60 seconds. | ||||||
|  | </dd> | ||||||
|  |  | ||||||
|  | <dt>-Z<br />--no-analyze</dt> | ||||||
|  | <dd>Disable ANALYZE after the reorganization. | ||||||
|  | If not specified, run ANALYZE after the reorganization.</dd> | ||||||
|  |  | ||||||
|  | </dl> | ||||||
|  |  | ||||||
|  | <h3>Connection Options</h3> | ||||||
|  | <p> | ||||||
|  | Options to connect to servers. | ||||||
|  | You cannot use --all and --dbname or --table together. | ||||||
|  | </p> | ||||||
|  |  | ||||||
|  | <dl> | ||||||
|  | <dt>-a<br />--all</dt> | ||||||
|  | <dd>Reorganize all databases.</dd> | ||||||
|  |  | ||||||
|  | <dt> | ||||||
|  | -d dbname<br /> | ||||||
|  | --dbname dbname | ||||||
|  | </dt> | ||||||
|  | <dd>Specifies the name of the database to be reorganized. If this is not specified and -a (or --all) is not used, the database name is read from the environment variable PGDATABASE. If that is not set, the user name specified for the connection is used. </dd> | ||||||
|  |  | ||||||
| <dt>-h host<br /> | <dt>-h host<br /> | ||||||
| --host host</dt> | --host host</dt> | ||||||
| <dd>Specifies the host name of the machine on which the server is running. If the value begins with a slash, it is used as the directory for the Unix domain socket. </dd> | <dd>Specifies the host name of the machine on which the server is running. If the value begins with a slash, it is used as the directory for the Unix domain socket. </dd> | ||||||
| @ -103,58 +167,17 @@ You can choose one of the following methods to reorganize.</p> | |||||||
| <dd>This option is never essential, since pg_reorg will automatically prompt for a password if the server demands password authentication. However, vacuumdb will waste a connection attempt finding out that the server wants a password. In some cases it is worth typing -W to avoid the extra connection attempt. </dd> | <dd>This option is never essential, since pg_reorg will automatically prompt for a password if the server demands password authentication. However, vacuumdb will waste a connection attempt finding out that the server wants a password. In some cases it is worth typing -W to avoid the extra connection attempt. </dd> | ||||||
| </dl> | </dl> | ||||||
|  |  | ||||||
| <h3>message-options</h3> | <h3>Generic Options</h3> | ||||||
| <p>Specifies message output by pg_reorg. |  | ||||||
| --quiet is ignored if some of the other options are specified.</p> |  | ||||||
|  |  | ||||||
| <dl> | <dl> | ||||||
| <dt>-q<br />--quiet</dt> | <dt>-e<br />--echo</dt> | ||||||
| <dd>Do not display progress messages. </dd> | <dd>Echo commands sent to server.</dd> | ||||||
| <dt>-v<br />--verbose</dt> | <dt>-E<br />--elevel</dt> | ||||||
| <dd>Print detailed information during processing.</dd> | <dd>Choose the output message level from DEBUG, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. | ||||||
| </dl> | The default is INFO.</dd> | ||||||
|  | <dt>--help</dt> | ||||||
| <h3>order-options</h3> | <dd>Show usage of the program.</dd> | ||||||
| <p>Options to order rows. | <dt>--version</dt> | ||||||
| If not specified, pg_reorg do online CLUSTER using cluster indexes. | <dd>Show the version number of the program.</dd> | ||||||
| Only one option can be specified. |  | ||||||
| </p> |  | ||||||
|  |  | ||||||
| <dl> |  | ||||||
| <dt>-n<br />--no-order</dt> |  | ||||||
| <dd>Do online VACUUM FULL.</dd> |  | ||||||
|  |  | ||||||
| <dt>-o columns [,...]<br /> |  | ||||||
| --order-by columns [,...]</dt> |  | ||||||
| <dd>Do online CLUSTER ordered by specified columns.</dd> |  | ||||||
| </dl> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <h3>target-options</h3> |  | ||||||
| <p> |  | ||||||
| Options to specify target tables or databases. |  | ||||||
| You cannot use --all and --dbname or --table together. |  | ||||||
| </p> |  | ||||||
|  |  | ||||||
| <dl> |  | ||||||
| <dt>-a<br />--all</dt> |  | ||||||
| <dd>Reorganize all databases.</dd> |  | ||||||
|  |  | ||||||
| <dt> |  | ||||||
| -d dbname<br /> |  | ||||||
| --dbname dbname |  | ||||||
| </dt> |  | ||||||
| <dd>Specifies the name of the database to be reorganized. If this is not specified and -a (or --all) is not used, the database name is read from the environment variable PGDATABASE. If that is not set, the user name specified for the connection is used. </dd> |  | ||||||
|  |  | ||||||
| <dt> |  | ||||||
| -t table<br /> |  | ||||||
| --table table |  | ||||||
| </dt> |  | ||||||
| <dd>Reorganize table only. If you don't specify this option, all tables in specified databases are reorganized.</dd> |  | ||||||
|  |  | ||||||
| <dt>-Z<br />--no-analyze</dt> |  | ||||||
| <dd>Do ANALYZE after reorganization. If you don't specify this option, ANALYZE is performed automatically after reorg.</dd> |  | ||||||
|  |  | ||||||
| </dl> | </dl> | ||||||
|  |  | ||||||
| <h2 id="environment">Environment</h2> | <h2 id="environment">Environment</h2> | ||||||
| @ -253,9 +276,10 @@ Then, it updates system catalog directly to swap the work table and the original | |||||||
|  |  | ||||||
| <h2 id="requirement">Requirements</h2> | <h2 id="requirement">Requirements</h2> | ||||||
| <dl> | <dl> | ||||||
| <dt>PostgreSQL version</dt><dd>PostgreSQL 8.3</dd> | <dt>PostgreSQL version</dt> | ||||||
|  | <dd>PostgreSQL 8.3, 8.4, 9.0</dd> | ||||||
| <dt>OS</dt><dd>RHEL 5.2, Windows XP SP3</dd> | <dt>OS</dt><dd>RHEL 5.2, Windows XP SP3</dd> | ||||||
| <dt>Disks</dt><dd>Requires amount of disks twice larger than target table and indexes.</dd> | <dt>Disks</dt><dd>Requires amount of disks twice larger than target table and indexes. (If the total size of targets are 1GB, additional 2GB of disks are required.)</dd> | ||||||
| </dl> | </dl> | ||||||
|  |  | ||||||
| <h2 id="seealso">See Also</h2> | <h2 id="seealso">See Also</h2> | ||||||
| @ -263,6 +287,10 @@ Then, it updates system catalog directly to swap the work table and the original | |||||||
| <a href="http://developer.postgresql.org/pgdocs/postgres/app-vacuumdb.html">vacuumdb</a> | <a href="http://developer.postgresql.org/pgdocs/postgres/app-vacuumdb.html">vacuumdb</a> | ||||||
|  |  | ||||||
| <hr /> | <hr /> | ||||||
|  | <div class="navigation"> | ||||||
|  |   <a href="index.html">Top</a> > | ||||||
|  |   <a href="pg_reorg.html">pg_reorg</a> | ||||||
|  | <div> | ||||||
| <p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p> | <p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p> | ||||||
|  |  | ||||||
| <script type="text/javascript"> | <script type="text/javascript"> | ||||||
|  | |||||||
| @ -79,3 +79,7 @@ p.footer { | |||||||
| 	text-align: right; | 	text-align: right; | ||||||
| 	font-size: small; | 	font-size: small; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | span.param { | ||||||
|  | 	color: #0000cd; | ||||||
|  | } | ||||||
|  | |||||||
| @ -118,7 +118,7 @@ CREATE VIEW reorg.tables AS | |||||||
|          reorg.get_create_trigger(R.oid, PK.indexrelid) AS create_trigger, |          reorg.get_create_trigger(R.oid, PK.indexrelid) AS create_trigger, | ||||||
|          'CREATE TABLE reorg.table_' || R.oid || ' WITH (' || array_to_string(array_append(R.reloptions, 'oids=' || CASE WHEN R.relhasoids THEN 'true' ELSE 'false' END), ',') || ') TABLESPACE ' || coalesce(quote_ident(S.spcname), 'pg_default') || ' AS SELECT * FROM ONLY ' || reorg.oid2text(R.oid) AS create_table, |          'CREATE TABLE reorg.table_' || R.oid || ' WITH (' || array_to_string(array_append(R.reloptions, 'oids=' || CASE WHEN R.relhasoids THEN 'true' ELSE 'false' END), ',') || ') TABLESPACE ' || coalesce(quote_ident(S.spcname), 'pg_default') || ' AS SELECT * FROM ONLY ' || reorg.oid2text(R.oid) AS create_table, | ||||||
|          'DELETE FROM reorg.log_' || R.oid AS delete_log, |          'DELETE FROM reorg.log_' || R.oid AS delete_log, | ||||||
|          'LOCK TABLE ' || reorg.oid2text(R.oid) || ' IN ACCESS EXCLUSIVE MODE NOWAIT' AS lock_table, |          'LOCK TABLE ' || reorg.oid2text(R.oid) || ' IN ACCESS EXCLUSIVE MODE' AS lock_table, | ||||||
|          reorg.get_index_keys(CK.indexrelid, R.oid) AS ckey, |          reorg.get_index_keys(CK.indexrelid, R.oid) AS ckey, | ||||||
|          'SELECT * FROM reorg.log_' || R.oid || ' ORDER BY id LIMIT $1' AS sql_peek, |          'SELECT * FROM reorg.log_' || R.oid || ' ORDER BY id LIMIT $1' AS sql_peek, | ||||||
|          'INSERT INTO reorg.table_' || R.oid || ' VALUES ($1.*)' AS sql_insert, |          'INSERT INTO reorg.table_' || R.oid || ' VALUES ($1.*)' AS sql_insert, | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "postgres.h" | #include "postgres.h" | ||||||
| #include "fmgr.h" | #include "access/heapam.h" | ||||||
| #include "pgut-be.h" | #include "pgut-be.h" | ||||||
|  |  | ||||||
| #if PG_VERSION_NUM < 80400 | #if PG_VERSION_NUM < 80400 | ||||||
| @ -42,4 +42,11 @@ cstring_to_text(const char *s) | |||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, | ||||||
|  | 					 Datum *values, bool *isnull) | ||||||
|  | { | ||||||
|  | 	tuplestore_puttuple(state, heap_form_tuple(tdesc, values, isnull)); | ||||||
|  | } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -10,6 +10,48 @@ | |||||||
| #ifndef PGUT_BE_H | #ifndef PGUT_BE_H | ||||||
| #define PGUT_BE_H | #define PGUT_BE_H | ||||||
|  |  | ||||||
|  | #include "fmgr.h" | ||||||
|  | #include "utils/tuplestore.h" | ||||||
|  |  | ||||||
|  | #ifndef WIN32 | ||||||
|  |  | ||||||
|  | #define PGUT_EXPORT | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | #define PGUT_EXPORT		__declspec(dllexport) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * PG_MODULE_MAGIC and PG_FUNCTION_INFO_V1 macros seems to be broken. | ||||||
|  |  * It uses PGDLLIMPORT, but those objects are not imported from postgres | ||||||
|  |  * and exported from the user module. So, it should be always dllexported. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #undef PG_MODULE_MAGIC | ||||||
|  | #define PG_MODULE_MAGIC \ | ||||||
|  | extern PGUT_EXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \ | ||||||
|  | const Pg_magic_struct * \ | ||||||
|  | PG_MAGIC_FUNCTION_NAME(void) \ | ||||||
|  | { \ | ||||||
|  | 	static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \ | ||||||
|  | 	return &Pg_magic_data; \ | ||||||
|  | } \ | ||||||
|  | extern int no_such_variable | ||||||
|  |  | ||||||
|  | #undef PG_FUNCTION_INFO_V1 | ||||||
|  | #define PG_FUNCTION_INFO_V1(funcname) \ | ||||||
|  | extern PGUT_EXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \ | ||||||
|  | const Pg_finfo_record * \ | ||||||
|  | CppConcat(pg_finfo_,funcname) (void) \ | ||||||
|  | { \ | ||||||
|  | 	static const Pg_finfo_record my_finfo = { 1 }; \ | ||||||
|  | 	return &my_finfo; \ | ||||||
|  | } \ | ||||||
|  | extern int no_such_variable | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| #if PG_VERSION_NUM < 80300 | #if PG_VERSION_NUM < 80300 | ||||||
|  |  | ||||||
| #define PGDLLIMPORT					DLLIMPORT | #define PGDLLIMPORT					DLLIMPORT | ||||||
| @ -33,8 +75,6 @@ | |||||||
| #define GetCurrentCommandId(used)	GetCurrentCommandId() | #define GetCurrentCommandId(used)	GetCurrentCommandId() | ||||||
| #define stringToQualifiedNameList(str) \ | #define stringToQualifiedNameList(str) \ | ||||||
|     stringToQualifiedNameList((str), "pg_bulkload") |     stringToQualifiedNameList((str), "pg_bulkload") | ||||||
| #define setNewRelfilenode(rel, xid) \ |  | ||||||
| 	setNewRelfilenode((rel)) |  | ||||||
| #define PageAddItem(page, item, size, offnum, overwrite, is_heap) \ | #define PageAddItem(page, item, size, offnum, overwrite, is_heap) \ | ||||||
| 	PageAddItem((page), (item), (size), (offnum), LP_USED) | 	PageAddItem((page), (item), (size), (offnum), LP_USED) | ||||||
|  |  | ||||||
| @ -56,32 +96,75 @@ | |||||||
| #define GetBulkInsertState()			(NULL) | #define GetBulkInsertState()			(NULL) | ||||||
| #define FreeBulkInsertState(bistate)	((void)0) | #define FreeBulkInsertState(bistate)	((void)0) | ||||||
| #define FreeExprContext(econtext, isCommit)		FreeExprContext((econtext)) | #define FreeExprContext(econtext, isCommit)		FreeExprContext((econtext)) | ||||||
| #define FuncnameGetCandidates(names, nargs, argnames, variadic, defaults) \ |  | ||||||
| 	FuncnameGetCandidates((names), (nargs)) |  | ||||||
| #define pgstat_init_function_usage(fcinfo, fcu)		((void)0) | #define pgstat_init_function_usage(fcinfo, fcu)		((void)0) | ||||||
| #define pgstat_end_function_usage(fcu, finalize)	((void)0) | #define pgstat_end_function_usage(fcu, finalize)	((void)0) | ||||||
|  | #define makeRangeVar(schemaname, relname, location) \ | ||||||
|  | 	makeRangeVar((schemaname), (relname)) | ||||||
|  | #define pgstat_track_activity_query_size	PGBE_ACTIVITY_SIZE | ||||||
| typedef void *BulkInsertState; | typedef void *BulkInsertState; | ||||||
|  |  | ||||||
|  | #define DefineCustomBoolVariable(name, short_desc, long_desc, valueAddr, bootValue, context, flags, assign_hook, show_hook) \ | ||||||
|  | 	do { \ | ||||||
|  | 		*(valueAddr) = (bootValue); \ | ||||||
|  | 		DefineCustomBoolVariable((name), (short_desc), (long_desc), (valueAddr), (context), (assign_hook), (show_hook)); \ | ||||||
|  | 	} while(0) | ||||||
|  | #define DefineCustomIntVariable(name, short_desc, long_desc, valueAddr, bootValue, minValue, maxValue, context, flags, assign_hook, show_hook) \ | ||||||
|  | 	do { \ | ||||||
|  | 		*(valueAddr) = (bootValue); \ | ||||||
|  | 		DefineCustomIntVariable((name), (short_desc), (long_desc), (valueAddr), (minValue), (maxValue), (context), (assign_hook), (show_hook)); \ | ||||||
|  | 	} while(0) | ||||||
|  | #define DefineCustomRealVariable(name, short_desc, long_desc, valueAddr, bootValue, minValue, maxValue, context, flags, assign_hook, show_hook) \ | ||||||
|  | 	do { \ | ||||||
|  | 		*(valueAddr) = (bootValue); \ | ||||||
|  | 		DefineCustomRealVariable((name), (short_desc), (long_desc), (valueAddr), (minValue), (maxValue), (context), (assign_hook), (show_hook)); \ | ||||||
|  | 	} while(0) | ||||||
|  | #define DefineCustomStringVariable(name, short_desc, long_desc, valueAddr, bootValue, context, flags, assign_hook, show_hook) \ | ||||||
|  | 	do { \ | ||||||
|  | 		*(valueAddr) = (char *) (bootValue); \ | ||||||
|  | 		DefineCustomStringVariable((name), (short_desc), (long_desc), (valueAddr), (context), (assign_hook), (show_hook)); \ | ||||||
|  | 	} while(0) | ||||||
|  |  | ||||||
|  | struct config_enum_entry | ||||||
|  | { | ||||||
|  | 	const char *name; | ||||||
|  | 	int			val; | ||||||
|  | 	bool		hidden; | ||||||
|  | }; | ||||||
|  |  | ||||||
| extern char *text_to_cstring(const text *t); | extern char *text_to_cstring(const text *t); | ||||||
| extern text *cstring_to_text(const char *s); | extern text *cstring_to_text(const char *s); | ||||||
|  | extern void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, | ||||||
|  | 					 Datum *values, bool *isnull); | ||||||
|  |  | ||||||
| #define CStringGetTextDatum(s)		PointerGetDatum(cstring_to_text(s)) | #define CStringGetTextDatum(s)		PointerGetDatum(cstring_to_text(s)) | ||||||
| #define TextDatumGetCString(d)		text_to_cstring((text *) DatumGetPointer(d)) | #define TextDatumGetCString(d)		text_to_cstring((text *) DatumGetPointer(d)) | ||||||
|  |  | ||||||
| #elif PG_VERSION_NUM < 80500 |  | ||||||
|  |  | ||||||
| #define FuncnameGetCandidates(names, nargs, argnames, variadic, defaults) \ |  | ||||||
| 	FuncnameGetCandidates((names), (nargs), (variadic), (defaults)) |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if PG_VERSION_NUM < 80500 | #if PG_VERSION_NUM < 90000 | ||||||
|  |  | ||||||
|  | #define reindex_index(indexId, skip_constraint_checks) \ | ||||||
|  | 	reindex_index((indexId)) | ||||||
| #define func_signature_string(funcname, nargs, argnames, argtypes) \ | #define func_signature_string(funcname, nargs, argnames, argtypes) \ | ||||||
| 	func_signature_string((funcname), (nargs), (argtypes)) | 	func_signature_string((funcname), (nargs), (argtypes)) | ||||||
| #define GetConfigOption(name, restrict_superuser)	GetConfigOption((name)) | #define GetConfigOption(name, restrict_superuser)	GetConfigOption((name)) | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if PG_VERSION_NUM < 80300 | ||||||
|  | #define RelationSetNewRelfilenode(rel, xid) \ | ||||||
|  | 	setNewRelfilenode((rel)) | ||||||
|  | #elif PG_VERSION_NUM < 90000 | ||||||
|  | #define RelationSetNewRelfilenode(rel, xid) \ | ||||||
|  | 	setNewRelfilenode((rel), (xid)) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if PG_VERSION_NUM < 80400 | ||||||
|  | #define FuncnameGetCandidates(names, nargs, argnames, variadic, defaults) \ | ||||||
|  | 	FuncnameGetCandidates((names), (nargs)) | ||||||
|  | #elif PG_VERSION_NUM < 90000 | ||||||
|  | #define FuncnameGetCandidates(names, nargs, argnames, variadic, defaults) \ | ||||||
|  | 	FuncnameGetCandidates((names), (nargs), (variadic), (defaults)) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif   /* PGUT_BE_H */ | #endif   /* PGUT_BE_H */ | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								lib/reorg.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								lib/reorg.c
									
									
									
									
									
								
							| @ -30,14 +30,14 @@ | |||||||
|  |  | ||||||
| PG_MODULE_MAGIC; | PG_MODULE_MAGIC; | ||||||
|  |  | ||||||
| Datum reorg_version(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_version(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_trigger(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_trigger(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_apply(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_apply(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_get_index_keys(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_get_index_keys(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_indexdef(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_indexdef(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_swap(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_swap(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_drop(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_drop(PG_FUNCTION_ARGS); | ||||||
| Datum reorg_disable_autovacuum(PG_FUNCTION_ARGS); | extern Datum PGUT_EXPORT reorg_disable_autovacuum(PG_FUNCTION_ARGS); | ||||||
|  |  | ||||||
| PG_FUNCTION_INFO_V1(reorg_version); | PG_FUNCTION_INFO_V1(reorg_version); | ||||||
| PG_FUNCTION_INFO_V1(reorg_trigger); | PG_FUNCTION_INFO_V1(reorg_trigger); | ||||||
| @ -75,7 +75,7 @@ static void RenameRelationInternal(Oid myrelid, const char *newrelname, Oid name | |||||||
| Datum | Datum | ||||||
| reorg_version(PG_FUNCTION_ARGS) | reorg_version(PG_FUNCTION_ARGS) | ||||||
| { | { | ||||||
| 	return CStringGetTextDatum("pg_reorg 1.0.8"); | 	return CStringGetTextDatum("pg_reorg 1.1.0"); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
							
								
								
									
										167
									
								
								msvc/bin.vcproj
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										167
									
								
								msvc/bin.vcproj
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,167 @@ | |||||||
|  | <?xml version="1.0" encoding="shift_jis"?> | ||||||
|  | <VisualStudioProject | ||||||
|  | 	ProjectType="Visual C++" | ||||||
|  | 	Version="8.00" | ||||||
|  | 	Name="bin" | ||||||
|  | 	ProjectGUID="{B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}" | ||||||
|  | 	RootNamespace="bin" | ||||||
|  | 	Keyword="Win32Proj" | ||||||
|  | 	> | ||||||
|  | 	<Platforms> | ||||||
|  | 		<Platform | ||||||
|  | 			Name="Win32" | ||||||
|  | 		/> | ||||||
|  | 	</Platforms> | ||||||
|  | 	<ToolFiles> | ||||||
|  | 	</ToolFiles> | ||||||
|  | 	<Configurations> | ||||||
|  | 		<Configuration | ||||||
|  | 			Name="Release|Win32" | ||||||
|  | 			OutputDirectory="$(SolutionDir)/bin" | ||||||
|  | 			IntermediateDirectory="$(SolutionDir)/obj/$(ProjectName)" | ||||||
|  | 			ConfigurationType="1" | ||||||
|  | 			CharacterSet="1" | ||||||
|  | 			WholeProgramOptimization="1" | ||||||
|  | 			> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCPreBuildEventTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCCustomBuildTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCXMLDataGeneratorTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCWebServiceProxyGeneratorTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCMIDLTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCCLCompilerTool" | ||||||
|  | 				AdditionalIncludeDirectories="../include" | ||||||
|  | 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS" | ||||||
|  | 				ExceptionHandling="0" | ||||||
|  | 				RuntimeLibrary="2" | ||||||
|  | 				UsePrecompiledHeader="0" | ||||||
|  | 				WarningLevel="3" | ||||||
|  | 				WarnAsError="true" | ||||||
|  | 				Detect64BitPortabilityProblems="false" | ||||||
|  | 				DebugInformationFormat="0" | ||||||
|  | 				CompileAs="1" | ||||||
|  | 				DisableSpecificWarnings="4996" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCManagedResourceCompilerTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCResourceCompilerTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCPreLinkEventTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCLinkerTool" | ||||||
|  | 				AdditionalDependencies="kernel32.lib advapi32.lib ws2_32.lib $(NoInherit) libpq.lib libpgport.lib libintl-8.lib" | ||||||
|  | 				OutputFile="$(OutDir)\$(SolutionName).exe" | ||||||
|  | 				LinkIncremental="1" | ||||||
|  | 				GenerateDebugInformation="false" | ||||||
|  | 				SubSystem="1" | ||||||
|  | 				OptimizeReferences="2" | ||||||
|  | 				EnableCOMDATFolding="2" | ||||||
|  | 				TargetMachine="1" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCALinkTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCManifestTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCXDCMakeTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCBscMakeTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCFxCopTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCAppVerifierTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCWebDeploymentTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCPostBuildEventTool" | ||||||
|  | 			/> | ||||||
|  | 		</Configuration> | ||||||
|  | 	</Configurations> | ||||||
|  | 	<References> | ||||||
|  | 	</References> | ||||||
|  | 	<Files> | ||||||
|  | 		<Filter | ||||||
|  | 			Name="src" | ||||||
|  | 			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||||||
|  | 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" | ||||||
|  | 			> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\pg_reorg.c" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\pgut\pgut-fe.c" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\pgut\pgut.c" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 		</Filter> | ||||||
|  | 		<Filter | ||||||
|  | 			Name="include" | ||||||
|  | 			Filter="h;hpp;hxx;hm;inl;inc;xsd" | ||||||
|  | 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" | ||||||
|  | 			> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\pgut\pgut-fe.h" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\pgut\pgut.h" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 		</Filter> | ||||||
|  | 		<Filter | ||||||
|  | 			Name="regress" | ||||||
|  | 			> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\expected\init.out" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\sql\init.sql" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\expected\reorg.out" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\bin\sql\reorg.sql" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 		</Filter> | ||||||
|  | 		<File | ||||||
|  | 			RelativePath="..\bin\Makefile" | ||||||
|  | 			> | ||||||
|  | 		</File> | ||||||
|  | 		<File | ||||||
|  | 			RelativePath=".\readme.txt" | ||||||
|  | 			> | ||||||
|  | 		</File> | ||||||
|  | 	</Files> | ||||||
|  | 	<Globals> | ||||||
|  | 	</Globals> | ||||||
|  | </VisualStudioProject> | ||||||
							
								
								
									
										151
									
								
								msvc/lib.vcproj
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										151
									
								
								msvc/lib.vcproj
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,151 @@ | |||||||
|  | <?xml version="1.0" encoding="shift_jis"?> | ||||||
|  | <VisualStudioProject | ||||||
|  | 	ProjectType="Visual C++" | ||||||
|  | 	Version="8.00" | ||||||
|  | 	Name="lib" | ||||||
|  | 	ProjectGUID="{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}" | ||||||
|  | 	RootNamespace="lib" | ||||||
|  | 	Keyword="Win32Proj" | ||||||
|  | 	> | ||||||
|  | 	<Platforms> | ||||||
|  | 		<Platform | ||||||
|  | 			Name="Win32" | ||||||
|  | 		/> | ||||||
|  | 	</Platforms> | ||||||
|  | 	<ToolFiles> | ||||||
|  | 	</ToolFiles> | ||||||
|  | 	<Configurations> | ||||||
|  | 		<Configuration | ||||||
|  | 			Name="Release|Win32" | ||||||
|  | 			OutputDirectory="$(SolutionDir)/bin" | ||||||
|  | 			IntermediateDirectory="$(SolutionDir)/obj/$(ProjectName)" | ||||||
|  | 			ConfigurationType="2" | ||||||
|  | 			CharacterSet="1" | ||||||
|  | 			WholeProgramOptimization="1" | ||||||
|  | 			> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCPreBuildEventTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCCustomBuildTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCXMLDataGeneratorTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCWebServiceProxyGeneratorTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCMIDLTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCCLCompilerTool" | ||||||
|  | 				AdditionalIncludeDirectories="../include" | ||||||
|  | 				PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS" | ||||||
|  | 				ExceptionHandling="0" | ||||||
|  | 				RuntimeLibrary="2" | ||||||
|  | 				UsePrecompiledHeader="0" | ||||||
|  | 				WarningLevel="3" | ||||||
|  | 				WarnAsError="true" | ||||||
|  | 				Detect64BitPortabilityProblems="false" | ||||||
|  | 				DebugInformationFormat="0" | ||||||
|  | 				CompileAs="1" | ||||||
|  | 				DisableSpecificWarnings="4996;4018" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCManagedResourceCompilerTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCResourceCompilerTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCPreLinkEventTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCLinkerTool" | ||||||
|  | 				AdditionalDependencies="kernel32.lib advapi32.lib ws2_32.lib $(NoInherit) postgres.lib libpq.lib" | ||||||
|  | 				OutputFile="$(OutDir)\$(SolutionName).dll" | ||||||
|  | 				LinkIncremental="1" | ||||||
|  | 				GenerateDebugInformation="false" | ||||||
|  | 				SubSystem="1" | ||||||
|  | 				OptimizeReferences="2" | ||||||
|  | 				EnableCOMDATFolding="2" | ||||||
|  | 				TargetMachine="1" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCALinkTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCManifestTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCXDCMakeTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCBscMakeTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCFxCopTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCAppVerifierTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCWebDeploymentTool" | ||||||
|  | 			/> | ||||||
|  | 			<Tool | ||||||
|  | 				Name="VCPostBuildEventTool" | ||||||
|  | 			/> | ||||||
|  | 		</Configuration> | ||||||
|  | 	</Configurations> | ||||||
|  | 	<References> | ||||||
|  | 	</References> | ||||||
|  | 	<Files> | ||||||
|  | 		<Filter | ||||||
|  | 			Name="src" | ||||||
|  | 			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||||||
|  | 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" | ||||||
|  | 			> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\lib\pgut\pgut-be.c" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\lib\pgut\pgut-spi.c" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\lib\reorg.c" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 		</Filter> | ||||||
|  | 		<Filter | ||||||
|  | 			Name="include" | ||||||
|  | 			Filter="h;hpp;hxx;hm;inl;inc;xsd" | ||||||
|  | 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" | ||||||
|  | 			> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\lib\pgut\pgut-be.h" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\lib\pgut\pgut-spi.h" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
|  | 		</Filter> | ||||||
|  | 		<File | ||||||
|  | 			RelativePath="..\lib\Makefile" | ||||||
|  | 			> | ||||||
|  | 		</File> | ||||||
|  | 		<File | ||||||
|  | 			RelativePath="..\lib\pg_reorg.sql.in" | ||||||
|  | 			> | ||||||
|  | 		</File> | ||||||
|  | 		<File | ||||||
|  | 			RelativePath="..\lib\uninstall_pg_reorg.sql" | ||||||
|  | 			> | ||||||
|  | 		</File> | ||||||
|  | 	</Files> | ||||||
|  | 	<Globals> | ||||||
|  | 	</Globals> | ||||||
|  | </VisualStudioProject> | ||||||
							
								
								
									
										21
									
								
								msvc/pg_reorg.sln
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								msvc/pg_reorg.sln
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  |  | ||||||
|  | Microsoft Visual Studio Solution File, Format Version 9.00 | ||||||
|  | # Visual C++ Express 2005 | ||||||
|  | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin", "bin.vcproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}" | ||||||
|  | EndProject | ||||||
|  | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib", "lib.vcproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}" | ||||||
|  | EndProject | ||||||
|  | Global | ||||||
|  | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
|  | 		Release|Win32 = Release|Win32 | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||||
|  | 		{B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.Release|Win32.ActiveCfg = Release|Win32 | ||||||
|  | 		{B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.Release|Win32.Build.0 = Release|Win32 | ||||||
|  | 		{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.Release|Win32.ActiveCfg = Release|Win32 | ||||||
|  | 		{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.Release|Win32.Build.0 = Release|Win32 | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(SolutionProperties) = preSolution | ||||||
|  | 		HideSolutionNode = FALSE | ||||||
|  | 	EndGlobalSection | ||||||
|  | EndGlobal | ||||||
							
								
								
									
										42
									
								
								msvc/readme.txt
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										42
									
								
								msvc/readme.txt
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | How to build with Microsoft Visual C++ Express 2005 | ||||||
|  |  | ||||||
|  | You might need: | ||||||
|  |   1. Register PostgreSQL directory to your environment. | ||||||
|  |   2. Resolve redefinitions of ERROR macro. | ||||||
|  |  | ||||||
|  | ---- | ||||||
|  | 1. Register PostgreSQL directory to your environment. | ||||||
|  |  | ||||||
|  | The directory configuration options are found in: | ||||||
|  |   Tool > Option > Projects and Solutions > VC++ directory | ||||||
|  |  | ||||||
|  | You might need to add the following directories: | ||||||
|  |   into "include files" | ||||||
|  |     - C:\Program Files\PostgreSQL\8.4\include | ||||||
|  |     - C:\Program Files\PostgreSQL\8.4\include\internal | ||||||
|  |     - C:\Program Files\PostgreSQL\8.4\include\server | ||||||
|  |     - C:\Program Files\PostgreSQL\8.4\include\server\port\win32 | ||||||
|  |     - C:\Program Files\PostgreSQL\8.4\include\server\port\win32_msvc | ||||||
|  |   into "library files" | ||||||
|  |     - C:\Program Files\PostgreSQL\8.4\lib | ||||||
|  |  | ||||||
|  | ---- | ||||||
|  | 2. Resolve redefinitions of ERROR macro. | ||||||
|  |  | ||||||
|  | It might be a bad manner, but I'll recommend to modify your wingdi.h. | ||||||
|  |  | ||||||
|  | --- wingdi.h       2008-01-18 22:17:42.000000000 +0900 | ||||||
|  | +++ wingdi.fixed.h 2010-03-03 09:51:43.015625000 +0900 | ||||||
|  | @@ -101,11 +101,10 @@ | ||||||
|  |  #endif // (_WIN32_WINNT >= _WIN32_WINNT_WINXP) | ||||||
|  |  | ||||||
|  |  /* Region Flags */ | ||||||
|  | -#define ERROR               0 | ||||||
|  | +#define RGN_ERROR           0 | ||||||
|  |  #define NULLREGION          1 | ||||||
|  |  #define SIMPLEREGION        2 | ||||||
|  |  #define COMPLEXREGION       3 | ||||||
|  | -#define RGN_ERROR ERROR | ||||||
|  |  | ||||||
|  |  /* CombineRgn() Styles */ | ||||||
|  |  #define RGN_AND             1 | ||||||
		Reference in New Issue
	
	Block a user