From 5fe3f037be8866fcfbddc2c287cb4e6e8fcf7a3f Mon Sep 17 00:00:00 2001
From: Takahiro Itagaki
Date: Mon, 25 May 2009 07:06:38 +0000
Subject: [PATCH] version 1.0.5. - Disable autovacuum for working tables and
update logs. - Do ANALYZE automatically after reorg unless -Z, --no-analyze
option is specified.
---
bin/pg_reorg.c | 88 ++++++++++++++++++++-------------
bin/pgut/pgut.c | 114 ++++++++++++++++++++++++++-----------------
bin/pgut/pgut.h | 32 +++++++++---
doc/pg_reorg-ja.html | 10 ++--
doc/pg_reorg.html | 9 ++--
doc/style.css | 10 ++--
lib/pg_reorg.sql.in | 15 ++++++
lib/pgut/pgut-be.h | 3 ++
lib/reorg.c | 52 +++++++++++++++++++-
9 files changed, 232 insertions(+), 101 deletions(-)
diff --git a/bin/pg_reorg.c b/bin/pg_reorg.c
index 36b23fd..3f1c31a 100755
--- a/bin/pg_reorg.c
+++ b/bin/pg_reorg.c
@@ -8,7 +8,7 @@
* @brief Client Modules
*/
-const char *PROGRAM_VERSION = "1.0.4";
+const char *PROGRAM_VERSION = "1.0.5";
const char *PROGRAM_URL = "http://reorg.projects.postgresql.org/";
const char *PROGRAM_EMAIL = "reorg-general@lists.pgfoundry.org";
@@ -92,9 +92,9 @@ static bool sqlstate_equals(PGresult *res, const char *state)
return strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), state) == 0;
}
-static bool echo = false;
static bool verbose = false;
static bool quiet = false;
+static bool analyze = true;
/*
* The table begin re-organized. If not null, we need to cleanup temp
@@ -110,16 +110,14 @@ utoa(unsigned int value, char *buffer)
return buffer;
}
-const char *pgut_optstring = "eqvat:no:";
-
-const struct option pgut_longopts[] = {
- {"echo", no_argument, NULL, 'e'},
+const struct option pgut_options[] = {
{"quiet", no_argument, NULL, 'q'},
{"verbose", no_argument, NULL, 'v'},
{"all", no_argument, NULL, 'a'},
{"table", required_argument, NULL, 't'},
{"no-order", no_argument, NULL, 'n'},
{"order-by", required_argument, NULL, 'o'},
+ {"no-analyze", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -132,9 +130,6 @@ pgut_argument(int c, const char *arg)
{
switch (c)
{
- case 'e':
- echo = true;
- break;
case 'q':
quiet = true;
break;
@@ -153,6 +148,9 @@ pgut_argument(int c, const char *arg)
case 'o':
assign_option(&orderby, c, arg);
break;
+ case 'Z':
+ analyze = false;
+ break;
default:
return false;
}
@@ -249,9 +247,9 @@ reorg_one_database(const char *orderby, const char *table)
PGresult *res;
int i;
int num;
- PQExpBufferData sql;
+ StringInfoData sql;
- initPQExpBuffer(&sql);
+ initStringInfo(&sql);
reconnect();
@@ -262,18 +260,18 @@ reorg_one_database(const char *orderby, const char *table)
command("SET client_min_messages = warning", 0, NULL);
/* acquire target tables */
- appendPQExpBufferStr(&sql, "SELECT * FROM reorg.tables WHERE ");
+ appendStringInfoString(&sql, "SELECT * FROM reorg.tables WHERE ");
if (table)
{
- appendPQExpBufferStr(&sql, "relid = $1::regclass");
- res = execute_nothrow(sql.data, 1, &table);
+ appendStringInfoString(&sql, "relid = $1::regclass");
+ res = execute_elevel(sql.data, 1, &table, LOG);
}
else
{
- appendPQExpBufferStr(&sql, "pkid IS NOT NULL");
+ appendStringInfoString(&sql, "pkid IS NOT NULL");
if (!orderby)
- appendPQExpBufferStr(&sql, " AND ckid IS NOT NULL");
- res = execute_nothrow(sql.data, 0, NULL);
+ appendStringInfoString(&sql, " AND ckid IS NOT NULL");
+ res = execute_elevel(sql.data, 0, NULL, LOG);
}
if (PQresultStatus(res) != PGRES_TUPLES_OK)
@@ -321,13 +319,13 @@ reorg_one_database(const char *orderby, const char *table)
table.lock_table = getstr(res, i, c++);
ckey = getstr(res, i, c++);
- resetPQExpBuffer(&sql);
+ resetStringInfo(&sql);
if (!orderby)
{
/* CLUSTER mode */
if (ckey == NULL)
elog(ERROR, "relation \"%s\" has no cluster key", table.target_name);
- appendPQExpBuffer(&sql, "%s ORDER BY %s", create_table, ckey);
+ appendStringInfo(&sql, "%s ORDER BY %s", create_table, ckey);
table.create_table = sql.data;
}
else if (!orderby[0])
@@ -338,7 +336,7 @@ reorg_one_database(const char *orderby, const char *table)
else
{
/* User specified ORDER BY */
- appendPQExpBuffer(&sql, "%s ORDER BY %s", create_table, orderby);
+ appendStringInfo(&sql, "%s ORDER BY %s", create_table, orderby);
table.create_table = sql.data;
}
@@ -354,7 +352,7 @@ reorg_one_database(const char *orderby, const char *table)
cleanup:
PQclear(res);
disconnect();
- termPQExpBuffer(&sql);
+ termStringInfo(&sql);
return ret;
}
@@ -387,12 +385,15 @@ apply_log(const reorg_table *table, int count)
static void
reorg_one_table(const reorg_table *table, const char *orderby)
{
- PGresult *res;
- const char *params[1];
- int num;
- int i;
- char *vxid;
- char buffer[12];
+ PGresult *res;
+ const char *params[1];
+ int num;
+ int i;
+ char *vxid;
+ char buffer[12];
+ StringInfoData sql;
+
+ initStringInfo(&sql);
if (verbose)
{
@@ -430,16 +431,16 @@ reorg_one_table(const reorg_table *table, const char *orderby)
*/
params[0] = utoa(table->target_oid, buffer);
- res = execute(
- "SELECT 1 FROM pg_trigger"
- " WHERE tgrelid = $1 AND tgname >= 'z_reorg_trigger' LIMIT 1",
- 1, params);
+ res = execute("SELECT reorg.conflicted_triggers($1)", 1, params);
if (PQntuples(res) > 0)
- elog(ERROR, "trigger conflicted for %s", table->target_name);
+ elog(ERROR, "trigger %s conflicted for %s",
+ PQgetvalue(res, 0, 0), table->target_name);
command(table->create_pktype, 0, NULL);
command(table->create_log, 0, NULL);
command(table->create_trigger, 0, NULL);
+ printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.log_%u')", table->target_oid);
+ command(sql.data, 0, NULL);
command("COMMIT", 0, NULL);
/*
@@ -465,6 +466,8 @@ reorg_one_table(const reorg_table *table, const char *orderby)
PQclear(res);
command(table->delete_log, 0, NULL);
command(table->create_table, 0, NULL);
+ printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.table_%u')", table->target_oid);
+ command(sql.data, 0, NULL);
command("COMMIT", 0, NULL);
/*
@@ -537,7 +540,7 @@ reorg_one_table(const reorg_table *table, const char *orderby)
for (;;)
{
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
- res = execute_nothrow(table->lock_table, 0, NULL);
+ res = execute_elevel(table->lock_table, 0, NULL, NOTICE);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -577,8 +580,23 @@ reorg_one_table(const reorg_table *table, const char *orderby)
command("COMMIT", 0, NULL);
current_table = NULL;
-
free(vxid);
+
+ /*
+ * 7. Analyze.
+ * Note that current_table is already set to NULL here because analyze
+ * is an unimportant operation; No clean up even if failed.
+ */
+ if (verbose)
+ fprintf(stderr, "---- analyze ----\n");
+
+ command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
+ printfStringInfo(&sql, "ANALYZE %s%s",
+ (verbose ? "VERBOSE " : ""), table->target_name);
+ command(sql.data, 0, NULL);
+ command("COMMIT", 0, NULL);
+
+ termStringInfo(&sql);
}
void
@@ -624,7 +642,7 @@ pgut_help(void)
" -t, --table=TABLE reorg specific table only\n"
" -n, --no-order do vacuum full instead of cluster\n"
" -o, --order-by=columns order by columns instead of cluster keys\n"
- " -e, --echo show the commands being sent to the server\n"
+ " -Z, --no-analyze don't analyze at end\n"
" -q, --quiet don't write any messages\n"
" -v, --verbose display detailed information during processing\n",
PROGRAM_NAME, PROGRAM_NAME);
diff --git a/bin/pgut/pgut.c b/bin/pgut/pgut.c
index 7011680..ce9636d 100755
--- a/bin/pgut/pgut.c
+++ b/bin/pgut/pgut.c
@@ -21,13 +21,14 @@ const char *host = NULL;
const char *port = NULL;
const char *username = NULL;
bool password = false;
+bool debug = false;
/* Database connections */
PGconn *connection = NULL;
static PGcancel *volatile cancel_conn = NULL;
/* Interrupted by SIGINT (Ctrl+C) ? */
-static bool interrupted = false;
+bool interrupted = false;
/* Connection routines */
static void init_cancel_handler(void);
@@ -39,40 +40,19 @@ static void exit_or_abort(int exitcode);
static void help(void);
static const char *get_user_name(const char *PROGRAM_NAME);
-const char default_optstring[] = "d:h:p:U:W";
-
-const struct option default_longopts[] =
+const struct option default_options[] =
{
{"dbname", required_argument, NULL, 'd'},
{"host", required_argument, NULL, 'h'},
{"port", required_argument, NULL, 'p'},
{"username", required_argument, NULL, 'U'},
{"password", no_argument, NULL, 'W'},
+ {"debug", no_argument, NULL, '!'},
{NULL, 0, NULL, 0}
};
-static const char *optstring = NULL;
static const struct option *longopts = NULL;;
-static const char *
-merge_optstring(const char *opts)
-{
- size_t len;
- char *result;
-
- if (opts == NULL)
- return default_optstring;
-
- len = strlen(opts);
- if (len == 0)
- return default_optstring;
-
- result = malloc(len + lengthof(default_optstring));
- memcpy(&result[0], opts, len);
- memcpy(&result[len], default_optstring, lengthof(default_optstring));
- return result;
-}
-
static const struct option *
merge_longopts(const struct option *opts)
{
@@ -80,23 +60,46 @@ merge_longopts(const struct option *opts)
struct option *result;
if (opts == NULL)
- return default_longopts;
+ return default_options;
for (len = 0; opts[len].name; len++) { }
if (len == 0)
- return default_longopts;
+ return default_options;
- result = (struct option *) malloc((len + lengthof(default_longopts)) * sizeof(struct option));
+ result = (struct option *) malloc((len + lengthof(default_options)) * sizeof(struct option));
memcpy(&result[0], opts, len * sizeof(struct option));
- memcpy(&result[len], default_longopts, lengthof(default_longopts) * sizeof(struct option));
+ memcpy(&result[len], default_options, lengthof(default_options) * sizeof(struct option));
+ return result;
+}
+
+static const char *
+longopts_to_optstring(const struct option *opts)
+{
+ size_t len;
+ char *result;
+ char *s;
+
+ for (len = 0; opts[len].name; len++) { }
+ result = malloc(len * 2 + 1);
+
+ s = result;
+ for (len = 0; opts[len].name; len++)
+ {
+ *s++ = opts[len].val;
+ if (opts[len].has_arg == required_argument)
+ *s++ = ':';
+ }
+ *s = '\0';
+
return result;
}
void
parse_options(int argc, char **argv)
{
- int c;
- int optindex = 0;
+ int c;
+ int optindex = 0;
+ const char *optstring;
PROGRAM_NAME = get_progname(argv[0]);
set_pglocale_pgservice(argv[0], "pgscripts");
@@ -117,8 +120,8 @@ parse_options(int argc, char **argv)
}
/* Merge default and user options. */
- optstring = merge_optstring(pgut_optstring);
- longopts = merge_longopts(pgut_longopts);
+ longopts = merge_longopts(pgut_options);
+ optstring = longopts_to_optstring(longopts);
while ((c = getopt_long(argc, argv, optstring, longopts, &optindex)) != -1)
{
@@ -139,6 +142,9 @@ parse_options(int argc, char **argv)
case 'W':
password = true;
break;
+ case '!':
+ debug = true;
+ break;
default:
if (!pgut_argument(c, optarg))
{
@@ -250,7 +256,7 @@ disconnect(void)
}
PGresult *
-execute_nothrow(const char *query, int nParams, const char **params)
+execute_elevel(const char *query, int nParams, const char **params, int elevel)
{
PGresult *res;
@@ -260,6 +266,19 @@ execute_nothrow(const char *query, int nParams, const char **params)
elog(ERROR, "%s: interrupted", PROGRAM_NAME);
}
+ /* write query to elog if debug */
+ if (debug)
+ {
+ int i;
+
+ if (strchr(query, '\n'))
+ elog(LOG, "(query)\n%s", query);
+ else
+ elog(LOG, "(query) %s", query);
+ for (i = 0; i < nParams; i++)
+ elog(LOG, "\t(param:%d) = %s", i, params[i] ? params[i] : "(null)");
+ }
+
on_before_exec(connection);
if (nParams == 0)
res = PQexec(connection, query);
@@ -267,6 +286,17 @@ execute_nothrow(const char *query, int nParams, const char **params)
res = PQexecParams(connection, query, nParams, NULL, params, NULL, NULL, 0);
on_after_exec();
+ switch (PQresultStatus(res))
+ {
+ case PGRES_TUPLES_OK:
+ case PGRES_COMMAND_OK:
+ break;
+ default:
+ elog(elevel, "query failed: %squery was: %s",
+ PQerrorMessage(connection), query);
+ break;
+ }
+
return res;
}
@@ -276,17 +306,7 @@ execute_nothrow(const char *query, int nParams, const char **params)
PGresult *
execute(const char *query, int nParams, const char **params)
{
- PGresult *res = execute_nothrow(query, nParams, params);
-
- if (PQresultStatus(res) == PGRES_TUPLES_OK ||
- PQresultStatus(res) == PGRES_COMMAND_OK)
- return res;
-
- fprintf(stderr, "%s: query failed: %s", PROGRAM_NAME, PQerrorMessage(connection));
- fprintf(stderr, "%s: query was: %s\n", PROGRAM_NAME, query);
- PQclear(res);
- exit_or_abort(ERROR);
- return NULL; /* keep compiler quiet */
+ return execute_elevel(query, nParams, params, ERROR);
}
/*
@@ -307,6 +327,9 @@ elog(int elevel, const char *fmt, ...)
{
va_list args;
+ if (!debug && elevel <= LOG)
+ return;
+
switch (elevel)
{
case LOG:
@@ -457,7 +480,8 @@ static void help(void)
fprintf(stderr, " -p, --port=PORT database server port\n");
fprintf(stderr, " -U, --username=USERNAME user name to connect as\n");
fprintf(stderr, " -W, --password force password prompt\n");
- fprintf(stderr, "\nGeneric Options:\n");
+ fprintf(stderr, "\nGeneric options:\n");
+ fprintf(stderr, " --debug debug mode\n");
fprintf(stderr, " --help show this help, then exit\n");
fprintf(stderr, " --version output version information, then exit\n\n");
if (PROGRAM_URL)
diff --git a/bin/pgut/pgut.h b/bin/pgut/pgut.h
index 454d3ea..44333a8 100755
--- a/bin/pgut/pgut.h
+++ b/bin/pgut/pgut.h
@@ -30,8 +30,7 @@ typedef char bool;
/*
* pgut client variables and functions
*/
-extern const char *pgut_optstring;
-extern const struct option pgut_longopts[];
+extern const struct option pgut_options[];
extern bool pgut_argument(int c, const char *arg);
extern void pgut_help(void);
@@ -51,15 +50,17 @@ extern const char *host;
extern const char *port;
extern const char *username;
extern bool password;
+extern bool debug;
extern PGconn *connection;
+extern bool interrupted;
extern void parse_options(int argc, char **argv);
extern bool assign_option(const char **value, int c, const char *arg);
extern void reconnect(void);
extern void disconnect(void);
-extern PGresult *execute_nothrow(const char *query, int nParams, const char **params);
+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);
@@ -87,6 +88,8 @@ __attribute__((format(printf, 2, 3)));
/*
* StringInfo
*/
+#define STRINGINFO_H
+
#define StringInfoData PQExpBufferData
#define StringInfo PQExpBuffer
#define makeStringInfo createPQExpBuffer
@@ -95,12 +98,29 @@ __attribute__((format(printf, 2, 3)));
#define termStringInfo termPQExpBuffer
#define resetStringInfo resetPQExpBuffer
#define enlargeStringInfo enlargePQExpBuffer
-/*
-#define printfPQExpBuffer = resetStringInfo + appendStringInfo
-*/
+#define printfStringInfo printfPQExpBuffer /* reset + append */
#define appendStringInfo appendPQExpBuffer
#define appendStringInfoString appendPQExpBufferStr
#define appendStringInfoChar appendPQExpBufferChar
#define appendBinaryStringInfo appendBinaryPQExpBuffer
+/*
+ * import from postgres.h and catalog/genbki.h in 8.4
+ */
+#if PG_VERSION_NUM < 80400
+
+typedef unsigned long Datum;
+typedef struct MemoryContextData *MemoryContext;
+
+#define CATALOG(name,oid) typedef struct CppConcat(FormData_,name)
+#define BKI_BOOTSTRAP
+#define BKI_SHARED_RELATION
+#define BKI_WITHOUT_OIDS
+#define DATA(x) extern int no_such_variable
+#define DESCR(x) extern int no_such_variable
+#define SHDESCR(x) extern int no_such_variable
+typedef int aclitem;
+
+#endif
+
#endif /* PGUT_H */
diff --git a/doc/pg_reorg-ja.html b/doc/pg_reorg-ja.html
index 32b73fe..90bda39 100755
--- a/doc/pg_reorg-ja.html
+++ b/doc/pg_reorg-ja.html
@@ -30,7 +30,6 @@ pg_reorg -- PostgreSQLデータベース内のテーブルに対して、参照/
-U [--username] username
-W [--password]
message-options : 出力メッセージ
- -e [--echo]
-q [--quiet]
-v [--verbose]
order-options : 並び替えの基準
@@ -40,6 +39,7 @@ pg_reorg -- PostgreSQLデータベース内のテーブルに対して、参照/
-a [--all]
-d [--dbname] dbname
-t [--table] table
+ -Z [--no-analyze]
@@ -57,7 +57,6 @@ pg_reorg -- PostgreSQLデータベース内のテーブルに対して、参照/
- このユーティリティは、スーパーユーザのみが実行することができます。
- 対象のテーブルはPRIMARY KEYを持っている必要があります。
-- pg_reorg 実行後のデータの状態は、統計情報に反映されていません。統計情報を最新化するため、pg_reorg 実行後にANALYZEを実行してください。
@@ -108,8 +107,6 @@ pg_reorg を実行した際に任意のメッセージを出力するための
-- -e
--echo
-- pg_reorg が生成し、サーバに送るコマンドをエコー表示します。
- -q
--quiet
- 進行メッセージを表示しません。
- -v
--verbose
@@ -157,6 +154,11 @@ pg_reorg を実行する対象を指定するパラメータです。
- オンライン CLUSTER 、または、オンライン VACUUM FULL を行うテーブルを指定します。
このオプションが指定されていない場合は、対象となったデータベースに存在する全ての対象テーブルに対して処理を行います。
+
+- -Z
--no-analyze
+- 再編成後に ANALYZE を行いません。
+このオプションが指定されていない場合は、再編成後に ANALYZE します。
+
diff --git a/doc/pg_reorg.html b/doc/pg_reorg.html
index 09f16b3..10756e9 100755
--- a/doc/pg_reorg.html
+++ b/doc/pg_reorg.html
@@ -29,7 +29,6 @@ See also options for details.
-U [--username] username
-W [--password]
message-options
- -e [--echo]
-q [--quiet]
-v [--verbose]
order-options
@@ -39,6 +38,7 @@ See also options for details.
-a [--all]
-d [--dbname] dbname
-t [--table] table
+ -Z [--no-analyze]
@@ -57,7 +57,6 @@ You can choose one of the following methods to reorganize.
- Only superusers can use the utility.
- Target table must have PRIMARY KEY.
-- You'd better to do ANALYZE after pg_reorg is completed.
@@ -103,8 +102,6 @@ You can choose one of the following methods to reorganize.
--quiet is ignored if some of the other options are specified.
-- -e
--echo
-- Echo the commands that pg_reorg generates and sends to the server.
- -q
--quiet
- Do not display progress messages.
- -v
--verbose
@@ -148,6 +145,10 @@ You cannot use --all and --dbname or --table together
--table table
- Reorganize table only. If you don't specify this option, all tables in specified databases are reorganized.
+
+- -Z
--no-analyze
+- Do ANALYZE after reorganization. If you don't specify this option, ANALYZE is performed automatically after reorg.
+
diff --git a/doc/style.css b/doc/style.css
index c3107b4..aca10f8 100755
--- a/doc/style.css
+++ b/doc/style.css
@@ -16,11 +16,11 @@ HR { margin: 5px 0px 5px 0px }
h2, h3, h4, h5, h6 {
- color: Black;
- background: none;
- padding-top: 0.5em;
- padding-bottom: 0.17em;
- border-bottom: 1px solid #aaaaaa;
+ color: Black;
+ background: none;
+ padding-top: 0.5em;
+ padding-bottom: 0.17em;
+ border-bottom: 1px solid #aaaaaa;
}
H1 { font-size: x-large; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; }
H2 { font-size: large; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; }
diff --git a/lib/pg_reorg.sql.in b/lib/pg_reorg.sql.in
index 59cb0c5..58c22c8 100755
--- a/lib/pg_reorg.sql.in
+++ b/lib/pg_reorg.sql.in
@@ -11,6 +11,10 @@ BEGIN;
CREATE SCHEMA reorg;
+CREATE FUNCTION reorg.version() RETURNS text AS
+'MODULE_PATHNAME', 'reorg_version'
+LANGUAGE 'C' IMMUTABLE STRICT;
+
CREATE AGGREGATE reorg.array_accum (
sfunc = array_append,
basetype = anyelement,
@@ -142,6 +146,17 @@ CREATE FUNCTION reorg.reorg_trigger() RETURNS trigger AS
'MODULE_PATHNAME', 'reorg_trigger'
LANGUAGE 'C' VOLATILE STRICT SECURITY DEFINER;
+CREATE FUNCTION reorg.conflicted_triggers(oid) RETURNS SETOF name AS
+$$
+SELECT tgname FROM pg_trigger
+ WHERE tgrelid = $1 AND tgname >= 'z_reorg_trigger'
+$$
+LANGUAGE sql STABLE STRICT;
+
+CREATE FUNCTION reorg.disable_autovacuum(regclass) RETURNS void AS
+'MODULE_PATHNAME', 'reorg_disable_autovacuum'
+LANGUAGE 'C' VOLATILE STRICT;
+
CREATE FUNCTION reorg.reorg_apply(
sql_peek cstring,
sql_insert cstring,
diff --git a/lib/pgut/pgut-be.h b/lib/pgut/pgut-be.h
index af76c27..2059402 100755
--- a/lib/pgut/pgut-be.h
+++ b/lib/pgut/pgut-be.h
@@ -67,6 +67,9 @@ extern text *cstring_to_text(const char *s);
extern int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes,
Datum *values, const char *nulls, bool read_only, long tcount);
+#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))
+#define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d))
+
#endif
#endif /* PGUT_BE_H */
diff --git a/lib/reorg.c b/lib/reorg.c
index 2e9ace5..99e9a2c 100755
--- a/lib/reorg.c
+++ b/lib/reorg.c
@@ -31,19 +31,23 @@
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);
+PG_FUNCTION_INFO_V1(reorg_version);
PG_FUNCTION_INFO_V1(reorg_trigger);
PG_FUNCTION_INFO_V1(reorg_apply);
PG_FUNCTION_INFO_V1(reorg_get_index_keys);
PG_FUNCTION_INFO_V1(reorg_indexdef);
PG_FUNCTION_INFO_V1(reorg_swap);
PG_FUNCTION_INFO_V1(reorg_drop);
+PG_FUNCTION_INFO_V1(reorg_disable_autovacuum);
static void reorg_init(void);
static SPIPlanPtr reorg_prepare(const char *src, int nargs, Oid *argtypes);
@@ -70,6 +74,12 @@ must_be_superuser(const char *func)
static void RenameRelationInternal(Oid myrelid, const char *newrelname, Oid namespaceId);
#endif
+Datum
+reorg_version(PG_FUNCTION_ARGS)
+{
+ return CStringGetTextDatum("pg_reorg 1.0.5");
+}
+
/**
* @fn Datum reorg_trigger(PG_FUNCTION_ARGS)
* @brief Insert a operation log into log-table.
@@ -274,7 +284,7 @@ typedef struct IndexDef
} IndexDef;
static char *
-generate_relation_name(Oid relid)
+get_relation_name(Oid relid)
{
Oid nsp = get_rel_namespace(relid);
char *nspname;
@@ -380,7 +390,7 @@ parse_indexdef(IndexDef *stmt, Oid index, Oid table)
{
char *sql = pg_get_indexdef_string(index);
const char *idxname = get_quoted_relname(index);
- const char *tblname = generate_relation_name(table);
+ const char *tblname = get_relation_name(table);
/* CREATE [UNIQUE] INDEX */
stmt->create = sql;
@@ -646,6 +656,19 @@ reorg_drop(PG_FUNCTION_ARGS)
"DROP TRIGGER IF EXISTS z_reorg_trigger ON %s.%s CASCADE",
nspname, relname);
+#if PG_VERSION_NUM < 80400
+ /* delete autovacuum settings */
+ reorg_execf(
+ SPI_OK_DELETE,
+ "DELETE FROM pg_catalog.pg_autovacuum v"
+ " USING pg_class c, pg_namespace n"
+ " WHERE relname IN ('log_%u', 'table_%u')"
+ " AND n.nspname = 'reorg'"
+ " AND c.relnamespace = n.oid"
+ " AND v.vacrelid = c.oid",
+ oid, oid);
+#endif
+
/* drop log table */
reorg_execf(
SPI_OK_UTILITY,
@@ -669,6 +692,31 @@ reorg_drop(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+Datum
+reorg_disable_autovacuum(PG_FUNCTION_ARGS)
+{
+ Oid oid = PG_GETARG_OID(0);
+
+ /* connect to SPI manager */
+ reorg_init();
+
+#if PG_VERSION_NUM >= 80400
+ reorg_execf(
+ SPI_OK_UTILITY,
+ "ALTER TABLE %s SET (autovacuum_enabled = off)",
+ get_relation_name(oid));
+#else
+ reorg_execf(
+ SPI_OK_INSERT,
+ "INSERT INTO pg_catalog.pg_autovacuum VALUES (%u, false, -1, -1, -1, -1, -1, -1, -1, -1)",
+ oid);
+#endif
+
+ SPI_finish();
+
+ PG_RETURN_VOID();
+}
+
/* init SPI */
static void
reorg_init(void)