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データベース内のテーブルに対して、参照/ @@ -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.

@@ -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)