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:
Takahiro Itagaki 2010-03-25 07:13:16 +00:00
parent 8392b9462a
commit f3873ff55b
19 changed files with 2239 additions and 1228 deletions

View File

@ -3,7 +3,7 @@
#
# 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)
PROGRAM = pg_reorg
REGRESS = init reorg

View File

@ -8,15 +8,16 @@
* @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_EMAIL = "reorg-general@lists.pgfoundry.org";
#include "pgut/pgut.h"
#include "pgut/pgut-fe.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#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 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_LOCK_NOT_AVAILABLE "55P03"
#define SQLSTATE_QUERY_CANCELED "57014"
static bool sqlstate_equals(PGresult *res, const char *state)
{
return strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), state) == 0;
}
static bool verbose = false;
static bool analyze = true;
static bool alldb = false;
static bool noorder = false;
static char *table = NULL;
static char *orderby = NULL;
static int wait_timeout = 60; /* in seconds */
/* buffer should have at least 11 bytes */
static char *
@ -110,11 +112,11 @@ utoa(unsigned int value, char *buffer)
static pgut_option options[] =
{
{ 'b', 'v', "verbose", &verbose },
{ 'b', 'a', "all", &alldb },
{ 's', 't', "table", &table },
{ 'b', 'n', "no-order", &noorder },
{ 's', 'o', "order-by", &orderby },
{ 'i', 'T', "wait-timeout", &wait_timeout },
{ 'B', 'Z', "no-analyze", &analyze },
{ 0 },
};
@ -129,7 +131,9 @@ main(int argc, char *argv[])
if (i == argc - 1)
dbname = argv[i];
else if (i < argc)
elog(ERROR_ARGS, "too many arguments");
ereport(ERROR,
(errcode(EINVAL),
errmsg("too many arguments")));
if (noorder)
orderby = "";
@ -137,13 +141,17 @@ main(int argc, char *argv[])
if (alldb)
{
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);
}
else
{
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;
@ -159,7 +167,7 @@ reorg_all_databases(const char *orderby)
int i;
dbname = "postgres";
reconnect();
reconnect(ERROR);
result = execute("SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", 0, NULL);
disconnect();
@ -169,7 +177,7 @@ reorg_all_databases(const char *orderby)
dbname = PQgetvalue(result, i, 0);
if (!quiet)
if (pgut_log_level >= INFO)
{
printf("%s: reorg database \"%s\"", PROGRAM_NAME, dbname);
fflush(stdout);
@ -177,7 +185,7 @@ reorg_all_databases(const char *orderby)
ret = reorg_one_database(orderby, NULL);
if (!quiet)
if (pgut_log_level >= INFO)
{
if (ret)
printf("\n");
@ -223,7 +231,10 @@ reorg_one_database(const char *orderby, const char *table)
initStringInfo(&sql);
reconnect();
reconnect(ERROR);
/* Disable statement timeout. */
command("SET statement_timeout = 0", 0, NULL);
/* Restrict search_path to system catalog. */
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)
{
appendStringInfoString(&sql, "relid = $1::regclass");
res = execute_elevel(sql.data, 1, &table, LOG);
res = execute_elevel(sql.data, 1, &table, DEBUG2);
}
else
{
appendStringInfoString(&sql, "pkid IS NOT NULL");
if (!orderby)
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)
@ -280,7 +291,9 @@ reorg_one_database(const char *orderby, const char *table)
table.ckid = getoid(res, i, c++);
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_log = getstr(res, i, c++);
@ -296,7 +309,9 @@ reorg_one_database(const char *orderby, const char *table)
{
/* CLUSTER mode */
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);
table.create_table = sql.data;
}
@ -367,35 +382,30 @@ reorg_one_table(const reorg_table *table, const char *orderby)
initStringInfo(&sql);
if (verbose)
{
fprintf(stderr, "---- reorg_one_table ----\n");
fprintf(stderr, "target_name : %s\n", table->target_name);
fprintf(stderr, "target_oid : %u\n", table->target_oid);
fprintf(stderr, "target_toast : %u\n", table->target_toast);
fprintf(stderr, "target_tidx : %u\n", table->target_tidx);
fprintf(stderr, "pkid : %u\n", table->pkid);
fprintf(stderr, "ckid : %u\n", table->ckid);
fprintf(stderr, "create_pktype : %s\n", table->create_pktype);
fprintf(stderr, "create_log : %s\n", table->create_log);
fprintf(stderr, "create_trigger : %s\n", table->create_trigger);
fprintf(stderr, "create_table : %s\n", table->create_table);
fprintf(stderr, "delete_log : %s\n", table->delete_log);
fprintf(stderr, "lock_table : %s\n", table->lock_table);
fprintf(stderr, "sql_peek : %s\n", table->sql_peek);
fprintf(stderr, "sql_insert : %s\n", table->sql_insert);
fprintf(stderr, "sql_delete : %s\n", table->sql_delete);
fprintf(stderr, "sql_update : %s\n", table->sql_update);
fprintf(stderr, "sql_pop : %s\n", table->sql_pop);
}
elog(DEBUG2, "---- reorg_one_table ----");
elog(DEBUG2, "target_name : %s", table->target_name);
elog(DEBUG2, "target_oid : %u", table->target_oid);
elog(DEBUG2, "target_toast : %u", table->target_toast);
elog(DEBUG2, "target_tidx : %u", table->target_tidx);
elog(DEBUG2, "pkid : %u", table->pkid);
elog(DEBUG2, "ckid : %u", table->ckid);
elog(DEBUG2, "create_pktype : %s", table->create_pktype);
elog(DEBUG2, "create_log : %s", table->create_log);
elog(DEBUG2, "create_trigger : %s", table->create_trigger);
elog(DEBUG2, "create_table : %s", table->create_table);
elog(DEBUG2, "delete_log : %s", table->delete_log);
elog(DEBUG2, "lock_table : %s", table->lock_table);
elog(DEBUG2, "sql_peek : %s", table->sql_peek);
elog(DEBUG2, "sql_insert : %s", table->sql_insert);
elog(DEBUG2, "sql_delete : %s", table->sql_delete);
elog(DEBUG2, "sql_update : %s", table->sql_update);
elog(DEBUG2, "sql_pop : %s", table->sql_pop);
/*
* 1. Setup workspaces and a trigger.
*/
if (verbose)
fprintf(stderr, "---- setup ----\n");
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
elog(DEBUG2, "---- setup ----");
lock_exclusive(utoa(table->target_oid, buffer), table->lock_table);
/*
* 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);
if (PQntuples(res) > 0)
elog(ERROR, "trigger %s conflicted for %s",
PQgetvalue(res, 0, 0), table->target_name);
ereport(ERROR,
(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_log, 0, NULL);
@ -425,8 +437,7 @@ reorg_one_table(const reorg_table *table, const char *orderby)
/*
* 2. Copy tuples into temp table.
*/
if (verbose)
fprintf(stderr, "---- copy tuples ----\n");
elog(DEBUG2, "---- copy tuples ----");
command("BEGIN ISOLATION LEVEL SERIALIZABLE", 0, NULL);
/* 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.
*/
if (verbose)
fprintf(stderr, "---- create indexes ----\n");
elog(DEBUG2, "---- create indexes ----");
params[0] = utoa(table->target_oid, buffer);
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.create_index = getstr(res, i, c++);
if (verbose)
{
fprintf(stderr, "[%d]\n", i);
fprintf(stderr, "target_oid : %u\n", index.target_oid);
fprintf(stderr, "create_index : %s\n", index.create_index);
}
elog(DEBUG2, "[%d]", i);
elog(DEBUG2, "target_oid : %u", index.target_oid);
elog(DEBUG2, "create_index : %s", index.create_index);
/*
* 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.
*/
if (verbose)
fprintf(stderr, "---- swap ----\n");
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);
}
}
elog(DEBUG2, "---- swap ----");
lock_exclusive(utoa(table->target_oid, buffer), table->lock_table);
apply_log(table, 0);
params[0] = utoa(table->target_oid, buffer);
command("SELECT reorg.reorg_swap($1)", 1, params);
@ -543,8 +523,7 @@ reorg_one_table(const reorg_table *table, const char *orderby)
/*
* 6. Drop.
*/
if (verbose)
fprintf(stderr, "---- drop ----\n");
elog(DEBUG2, "---- drop ----");
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
params[0] = utoa(table->target_oid, buffer);
@ -561,12 +540,10 @@ reorg_one_table(const reorg_table *table, const char *orderby)
*/
if (analyze)
{
if (verbose)
fprintf(stderr, "---- analyze ----\n");
elog(DEBUG2, "---- analyze ----");
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
printfStringInfo(&sql, "ANALYZE %s%s",
(verbose ? "VERBOSE " : ""), table->target_name);
printfStringInfo(&sql, "ANALYZE %s", table->target_name);
command(sql.data, 0, NULL);
command("COMMIT", 0, NULL);
}
@ -574,6 +551,79 @@ reorg_one_table(const reorg_table *table, const char *orderby)
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
* objects before the program exits.
@ -598,7 +648,7 @@ reorg_cleanup(bool fatal, void *userdata)
/* Try reconnection if not available. */
if (PQstatus(connection) != CONNECTION_OK)
reconnect();
reconnect(ERROR);
/* do cleanup */
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(" -n, --no-order do vacuum full instead of cluster\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(" -v, --verbose display detailed information during processing\n");
}

687
bin/pgut/pgut-fe.c Executable file
View 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
View 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 */

File diff suppressed because it is too large Load Diff

View File

@ -11,23 +11,16 @@
#define PGUT_H
#include "c.h"
#include <assert.h>
#ifndef WIN32
#include <sys/time.h>
#include <unistd.h>
#endif
#include "libpq-fe.h"
#include "pqexpbuffer.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
#include "utils/elog.h"
#define INFINITE_STR "INFINITE"
@ -38,40 +31,6 @@ typedef enum YesNo
YES
} 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);
/*
@ -82,52 +41,33 @@ extern const char *PROGRAM_VERSION;
extern const char *PROGRAM_URL;
extern const char *PROGRAM_EMAIL;
extern void pgut_help(bool details);
/*
* 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;
extern bool interrupted;
extern int pgut_log_level;
extern int pgut_abort_level;
extern bool pgut_echo;
#ifndef PGUT_NO_PROMPT
extern YesNo prompt_password;
#endif
extern PGconn *connection;
extern bool interrupted;
extern void help(bool details);
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_init(int argc, char **argv);
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_putenv(const char *key, const char *value);
/*
* Database connections
*/
extern PGconn *pgut_connect(int elevel);
extern PGconn *pgut_connectdb(const char *conninfo, int elevel);
extern PGconn *pgut_connect(const char *info, YesNo prompt, int elevel);
extern void pgut_disconnect(PGconn *conn);
extern PGresult *pgut_execute(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, int elevel);
extern bool pgut_send(PGconn* conn, const char *query, int nParams, const char **params, int elevel);
extern void pgut_disconnect_all(void);
extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, const char **params);
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 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
*/
@ -139,37 +79,38 @@ extern char *strdup_trim(const char *str);
#define pgut_new(type) ((type *) pgut_malloc(sizeof(type)))
#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
*/
extern FILE *pgut_fopen(const char *path, const char *mode, bool missing_ok);
extern void pgut_mkdir(const char *path);
extern FILE *pgut_fopen(const char *path, const char *mode);
extern bool pgut_mkdir(const char *path);
/*
* elog
*/
#define LOG (-4)
#define INFO (-3)
#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 */
#define E_PG_CONNECT (-1) /* PostgreSQL connection error */
#define E_PG_COMMAND (-2) /* PostgreSQL query or command error */
#undef elog
extern void
elog(int elevel, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#undef ereport
#define ereport(elevel, rest) \
(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
extern void CHECK_FOR_INTERRUPTS(void);
@ -209,6 +150,7 @@ extern void CHECK_FOR_INTERRUPTS(void);
#define appendStringInfoChar appendPQExpBufferChar
#define appendBinaryStringInfo appendBinaryPQExpBuffer
extern bool appendStringInfoVA(StringInfo str, const char *fmt, va_list args);
extern int appendStringInfoFile(StringInfo str, FILE *fp);
extern int appendStringInfoFd(StringInfo str, int fd);

View File

@ -17,11 +17,21 @@
<h1>pg_reorg ホームページへようこそ</h1>
<hr />
</center>
<p>このプロジェクトでは <strong>pg_reorg</strong><strong>pg_batch</strong> の2つのツールを頒布しています。</p>
<p>
pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンドです。
<strong>pg_reorg</strong> は PostgreSQL のテーブルを再編成するシェルコマンドです。
共有ロックや排他ロックを取得しないため、再編成中であっても行の参照や更新を行うことができます。
このモジュールは CLUSTER や VACUUM FULL コマンドのより良い代替になります。
</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>
<ul>
<li><a href="http://pgfoundry.org/frs/?group_id=1000411">ダウンロード</a> : ソースコードのほか、Windows 用バイナリもダウンロードできます。</li>
@ -34,9 +44,11 @@ pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンド
<hr />
<h2>ドキュメント</h2>
<p>
<a href="pg_reorg-ja.html">ドキュメントはこちら</a>
</p>
<ul>
<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>
<p>

View File

@ -17,10 +17,22 @@
<h1>Welcome to the pg_reorg Project Home Page</h1>
<hr />
</center>
<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.
</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>
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>
@ -34,9 +46,11 @@ where you can find <a href="http://pgfoundry.org/frs/?group_id=1000411">download
<hr />
<h2>Documentation</h2>
<p>
<a href="pg_reorg.html">Documentations here</a>.
</p>
<ul>
<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>
<p>

View File

@ -8,7 +8,12 @@
</head>
<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> &gt;
<a href="pg_reorg-ja.html">pg_reorg</a>
<div>
<hr />
<div class="index">
<ol>
@ -31,28 +36,34 @@ pg_reorg -- PostgreSQLデータベース内のテーブルに対して、参照/
<h2 id="synopsis">概要</h2>
<p>
pg_reorg [connection-options...] [message-options...] [order-options...] [target-options...]
pg_reorg [OPTIONS]
</p>
<p>指定できるオプションには4つのカテゴリがあります。
<p>オプション OPTIONS には以下を指定できます。
詳細は<a href="#options">オプション</a>を参照してください。</p>
<dl>
<dt>connection-options : 接続パラメータ</dt>
<dd>-h [--host] host</dd>
<dd>-p [--port] port</dd>
<dd>-U [--username] username</dd>
<dd>-W [--password]</dd>
<dt>message-options : 出力メッセージ</dt>
<dd>-q [--quiet]</dd>
<dd>-v [--verbose]</dd>
<dt>order-options : 並び替えの基準</dt>
<dd>-o [--order-by] columns [,...]</dd>
<dd>-n [--no-order]</dd>
<dt>target-options : 処理対象</dt>
<dd>-a [--all]</dd>
<dd>-d [--dbname] dbname</dd>
<dd>-t [--table] table</dd>
<dd>-Z [--no-analyze]</dd>
</dl>
<ul>
<li>固有オプション<ul>
<li>-o [--order-by] columns [,...]</li>
<li>-n [--no-order]</li>
<li>-t [--table] table</li>
<li>-T [--wait-timeout] seconds</li>
<li>-Z [--no-analyze]</li>
</ul></li>
<li>接続オプション<ul>
<li>-a, --all : 全てのデータベースに対して実行します</li>
<li>-d, --dbname=DBNAME : 接続するデータベース</li>
<li>-h, --host=HOSTNAME : データベースサーバホスト、またはソケットディレクトリ</li>
<li>-p, --port=PORT : データベースサーバのポート</li>
<li>-U, --username=USERNAME : このユーザとして接続します</li>
<li>-W, --password : パスワード入力を強制します</li>
</ul></li>
<li>一般オプション<ul>
<li>-e, --echo : サーバに送信するSQLを表示します</li>
<li>-E, --elevel=LEVEL : ログ出力レベルを設定します</li>
<li>--help : ヘルプを表示し、終了します</li>
<li>--version : バージョン情報を出力し、終了します</li>
</ul></li>
</ul>
<h2 id="description">説明</h2>
<p>pg_reorg は、PostgreSQLデータベース内のテーブルを再編成(行の並び替え)するユーティリティです。
@ -77,47 +88,11 @@ pg_reorg [connection-options...] [message-options...] [order-options...] [tar
</p>
<h2 id="options">オプション</h2>
<p>pg_reorg では、下記の4種類のコマンドライン引数を指定できます。</p>
<p>pg_reorg では、下記のコマンドライン引数を指定できます。</p>
<dl>
<h3>connection-options</h3>
<p>PostgreSQLに接続するためのパラメータです。</p>
<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 を実行する際の並び替えの基準を指定するパラメータです。
<h3>固有オプション</h3>
<p>pg_reorg を実行する対象と並び替えの基準を指定するパラメータです。
何も指定されていない場合は、cluster index順にオンライン CLUSTER を行います。
この2つを同時に指定することはできません。
</p>
@ -131,9 +106,34 @@ pg_reorg を実行した際に任意のメッセージを出力するための
<dd>指定したカラムをキーにオンライン CLUSTER を行います。</dd>
</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>
pg_reorg を実行する対象を指定するパラメータです。
PostgreSQLに接続するためのパラメータです。
--allと--dbnameまたは--tableを同時に指定することはできません。
</p>
@ -142,26 +142,46 @@ pg_reorg を実行する対象を指定するパラメータです。
<dd>対象となる全てのデータベースに対してオンライン CLUSTER、または、オンラインVACUUM FULLを行います。</dd>
<dt>
-d dbname<br />
--dbname dbname
-d DBNAME<br />
--dbname=DBNAME
</dt>
<dd>オンライン CLUSTER、または、オンライン VACUUM FULL を行うデータベース名を指定します。
データベース名が指定されておらず、-aまたは--allも指定されていない場合、
データベース名はPGDATABASE環境変数から読み取られます。この変数も設定されていない場合は、接続時に指定したユーザ名が使用されます。
</dd>
データベース名はPGDATABASE環境変数から読み取られます。
この変数も設定されていない場合は、接続時に指定したユーザ名が使用されます。</dd>
<dt>
-t table<br />
--table table
</dt>
<dd>オンライン CLUSTER 、または、オンライン VACUUM FULL を行うテーブルを指定します。
このオプションが指定されていない場合は、対象となったデータベースに存在する全ての対象テーブルに対して処理を行います。
</dd>
<dt>-h HOSTNAME<br />
--host=HOSTNAME</dt>
<dd>サーバが稼働しているマシンのホスト名を指定します。ホスト名がスラッシュから始まる場合、Unixドメインソケット用のディレクトリとして使用されます。</dd>
<dt>-Z<br />--no-analyze</dt>
<dd>再編成後に ANALYZE を行いません。
このオプションが指定されていない場合は、再編成後に ANALYZE します。</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>データベースに接続する前に、強制的にパスワード入力を促します。
サーバがパスワード認証を要求する場合 自動的にパスワード入力を促しますので、これが重要になることはありません。
しかし、サーバにパスワードが必要かどうかを判断するための接続試行を無駄に行います。
こうした余計な接続試行を防ぐために -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>
<h2 id="environment">環境変数</h2>
@ -268,9 +288,12 @@ pg_reorg の実行中には、VACUUM と ANALYZE <STRONG>以外</STRONG> のDDL
<h2 id="requirement">動作環境</h2>
<dl>
<dt>PostgreSQLバージョン</dt><dd>PostgreSQL 8.3</dd>
<dt>OS</dt><dd>RHEL 5.2, Windows XP SP3</dd>
<dt>ディスク容量</dt><dd>処理対象のテーブル、インデックスサイズの2倍以上のディスク空き容量</dd>
<dt>PostgreSQLバージョン</dt>
<dd>PostgreSQL 8.3, 8.4, 9.0</dd>
<dt>OS</dt>
<dd>RHEL 5.2, Windows XP SP3</dd>
<dt>ディスク容量</dt>
<dd>処理対象のテーブル、インデックスサイズの2倍以上のディスク空き容量 (対象が1GBならば、さらに追加で2GB)</dd>
</dl>
<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>
<hr />
<div class="navigation">
<a href="index-ja.html">Top</a> &gt;
<a href="pg_reorg-ja.html">pg_reorg</a>
<div>
<p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
<script type="text/javascript">

View File

@ -8,7 +8,12 @@
</head>
<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> &gt;
<a href="pg_reorg.html">pg_reorg</a>
<div>
<hr />
<div class="index">
<ol>
@ -31,28 +36,34 @@ pg_reorg -- Reorganize tables in PostgreSQL databases without any locks.
<h2 id="synopsis">Synopsis</h2>
<p>
pg_reorg [connection-options...] [message-options...] [order-options...] [target-options...]
pg_reorg [OPTIONS]
</p>
<p>There 4 option categories.
See also <a href="#options">options</a> for details.</p>
<dl>
<dt>connection-options</dt>
<dd>-h [--host] host</dd>
<dd>-p [--port] port</dd>
<dd>-U [--username] username</dd>
<dd>-W [--password]</dd>
<dt>message-options</dt>
<dd>-q [--quiet]</dd>
<dd>-v [--verbose]</dd>
<dt>order-options</dt>
<dd>-o [--order-by] columns [,...]</dd>
<dd>-n [--no-order]</dd>
<dt>target-options</dt>
<dd>-a [--all]</dd>
<dd>-d [--dbname] dbname</dd>
<dd>-t [--table] table</dd>
<dd>-Z [--no-analyze]</dd>
</dl>
<p>The following options can be specified in OPTIONS.
See also "<a href="#options">Options</a>" for details.</p>
<ul>
<li>Reorg Options<ul>
<li>-o [--order-by] columns [,...]</li>
<li>-n [--no-order]</li>
<li>-t [--table] table</li>
<li>-T [--wait-timeout] seconds</li>
<li>-Z [--no-analyze]</li>
</ul></li>
<li>Connection Options<ul>
<li>-a, --all : reorganize all databases</li>
<li>-d, --dbname=DBNAME : database to connect</li>
<li>-h, --host=HOSTNAME : database server host or socket directory</li>
<li>-p, --port=PORT : database server port</li>
<li>-U, --username=USERNAME : user name to connect as</li>
<li>-W, --password : force password prompt</li>
</ul></li>
<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>
<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>
<h2 id="options">Options</h2>
<p>pg_reorg has command line options in 4 categolies.</p>
<div>
<p>pg_reorg has the following command line options:</p>
<dl>
<h3>connection-options</h3>
<p>Parameters to connect PostgreSQL.</p>
<h3>Reorg Options</h3>
<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>
<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 />
--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>
@ -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>
</dl>
<h3>message-options</h3>
<p>Specifies message output by pg_reorg.
--quiet is ignored if some of the other options are specified.</p>
<h3>Generic Options</h3>
<dl>
<dt>-q<br />--quiet</dt>
<dd>Do not display progress messages. </dd>
<dt>-v<br />--verbose</dt>
<dd>Print detailed information during processing.</dd>
</dl>
<h3>order-options</h3>
<p>Options to order rows.
If not specified, pg_reorg do online CLUSTER using cluster indexes.
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>
<dt>-e<br />--echo</dt>
<dd>Echo commands sent to server.</dd>
<dt>-E<br />--elevel</dt>
<dd>Choose the output message level from DEBUG, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC.
The default is INFO.</dd>
<dt>--help</dt>
<dd>Show usage of the program.</dd>
<dt>--version</dt>
<dd>Show the version number of the program.</dd>
</dl>
<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>
<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>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>
<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>
<hr />
<div class="navigation">
<a href="index.html">Top</a> &gt;
<a href="pg_reorg.html">pg_reorg</a>
<div>
<p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
<script type="text/javascript">

View File

@ -79,3 +79,7 @@ p.footer {
text-align: right;
font-size: small;
}
span.param {
color: #0000cd;
}

View File

@ -118,7 +118,7 @@ CREATE VIEW reorg.tables AS
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,
'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,
'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,

View File

@ -8,7 +8,7 @@
*/
#include "postgres.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "pgut-be.h"
#if PG_VERSION_NUM < 80400
@ -42,4 +42,11 @@ cstring_to_text(const char *s)
return result;
}
void
tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
Datum *values, bool *isnull)
{
tuplestore_puttuple(state, heap_form_tuple(tdesc, values, isnull));
}
#endif

View File

@ -10,6 +10,48 @@
#ifndef 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
#define PGDLLIMPORT DLLIMPORT
@ -33,8 +75,6 @@
#define GetCurrentCommandId(used) GetCurrentCommandId()
#define stringToQualifiedNameList(str) \
stringToQualifiedNameList((str), "pg_bulkload")
#define setNewRelfilenode(rel, xid) \
setNewRelfilenode((rel))
#define PageAddItem(page, item, size, offnum, overwrite, is_heap) \
PageAddItem((page), (item), (size), (offnum), LP_USED)
@ -56,32 +96,75 @@
#define GetBulkInsertState() (NULL)
#define FreeBulkInsertState(bistate) ((void)0)
#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_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;
#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 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 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
#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) \
func_signature_string((funcname), (nargs), (argtypes))
#define GetConfigOption(name, restrict_superuser) GetConfigOption((name))
#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 */

View File

@ -30,14 +30,14 @@
PG_MODULE_MAGIC;
Datum reorg_version(PG_FUNCTION_ARGS);
Datum reorg_trigger(PG_FUNCTION_ARGS);
Datum reorg_apply(PG_FUNCTION_ARGS);
Datum reorg_get_index_keys(PG_FUNCTION_ARGS);
Datum reorg_indexdef(PG_FUNCTION_ARGS);
Datum reorg_swap(PG_FUNCTION_ARGS);
Datum reorg_drop(PG_FUNCTION_ARGS);
Datum reorg_disable_autovacuum(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_version(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_trigger(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_apply(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_get_index_keys(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_indexdef(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_swap(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_drop(PG_FUNCTION_ARGS);
extern Datum PGUT_EXPORT reorg_disable_autovacuum(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(reorg_version);
PG_FUNCTION_INFO_V1(reorg_trigger);
@ -75,7 +75,7 @@ static void RenameRelationInternal(Oid myrelid, const char *newrelname, Oid name
Datum
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
View 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
View 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
View 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
View 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