From 68dc5925458b414ae6242cf71a11152507f13f09 Mon Sep 17 00:00:00 2001 From: Dmitry Ivanov Date: Mon, 20 Mar 2017 23:04:41 +0300 Subject: [PATCH] introduce option --parent-table (-I, stands for 'inheritance'), fix function repack_one_database(), introduce function repack.get_table_and_inheritors() --- bin/pg_repack.c | 69 +++++++++++++++++++++++++++++++++----------- lib/exports.txt | 40 +++++++++++++------------ lib/pg_repack.sql.in | 5 ++++ lib/repack.c | 41 ++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 38 deletions(-) diff --git a/bin/pg_repack.c b/bin/pg_repack.c index 36ceed8..db7aa01 100644 --- a/bin/pg_repack.c +++ b/bin/pg_repack.c @@ -109,7 +109,7 @@ const char *PROGRAM_VERSION = "unknown"; */ #define SQL_XID_SNAPSHOT_80300 \ "SELECT repack.array_accum(l.virtualtransaction) " \ - " FROM pg_locks AS l" \ + " FROM pg_locks AS l" \ " LEFT JOIN pg_stat_activity AS a " \ " ON l.pid = a.procpid " \ " LEFT JOIN pg_database AS d " \ @@ -174,7 +174,7 @@ typedef struct repack_index { Oid target_oid; /* target: OID */ const char *create_index; /* CREATE INDEX */ - index_status_t status; /* Track parallel build statuses. */ + index_status_t status; /* Track parallel build statuses. */ int worker_idx; /* which worker conn is handling */ } repack_index; @@ -238,6 +238,7 @@ static bool sqlstate_equals(PGresult *res, const char *state) static bool analyze = true; static bool alldb = false; static bool noorder = false; +static SimpleStringList parent_table_list = {NULL, NULL}; static SimpleStringList table_list = {NULL, NULL}; static SimpleStringList schema_list = {NULL, NULL}; static char *orderby = NULL; @@ -265,6 +266,7 @@ static pgut_option options[] = { { 'b', 'a', "all", &alldb }, { 'l', 't', "table", &table_list }, + { 'l', 'I', "parent-table", &parent_table_list }, { 'l', 'c', "schema", &schema_list }, { 'b', 'n', "no-order", &noorder }, { 'b', 'N', "dry-run", &dryrun }, @@ -306,12 +308,16 @@ main(int argc, char *argv[]) if (r_index.head && table_list.head) ereport(ERROR, (errcode(EINVAL), errmsg("cannot specify --index (-i) and --table (-t)"))); + if (r_index.head && parent_table_list.head) + ereport(ERROR, (errcode(EINVAL), + errmsg("cannot specify --index (-i) and --parent-table (-P)"))); else if (r_index.head && only_indexes) ereport(ERROR, (errcode(EINVAL), errmsg("cannot specify --index (-i) and --only-indexes (-x)"))); - else if (only_indexes && !table_list.head) + else if (only_indexes && !(table_list.head || parent_table_list.head)) ereport(ERROR, (errcode(EINVAL), - errmsg("cannot repack all indexes of database, specify the table(s) via --table (-t)"))); + errmsg("cannot repack all indexes of database, specify the table(s)" + "via --table (-t) or --parent-table (-P)"))); else if (alldb) ereport(ERROR, (errcode(EINVAL), errmsg("cannot repack specific index(es) in all databases"))); @@ -336,7 +342,7 @@ main(int argc, char *argv[]) } else { - if (schema_list.head && table_list.head) + if (schema_list.head && (table_list.head || parent_table_list.head)) ereport(ERROR, (errcode(EINVAL), errmsg("cannot repack specific table(s) in schema, use schema.table notation instead"))); @@ -346,7 +352,7 @@ main(int argc, char *argv[]) if (alldb) { - if (table_list.head) + if (table_list.head || parent_table_list.head) ereport(ERROR, (errcode(EINVAL), errmsg("cannot repack specific table(s) in all databases"))); @@ -602,15 +608,17 @@ repack_one_database(const char *orderby, char *errbuf, size_t errsize) SimpleStringListCell *cell; const char **params = NULL; int iparam = 0; + size_t num_parent_tables; size_t num_tables; size_t num_schemas; size_t num_params; + num_parent_tables = simple_string_list_size(parent_table_list); num_tables = simple_string_list_size(table_list); num_schemas = simple_string_list_size(schema_list); /* 1st param is the user-specified tablespace */ - num_params = num_tables + num_schemas + 1; + num_params = num_parent_tables + num_tables + num_schemas + 1; params = pgut_malloc(num_params * sizeof(char *)); initStringInfo(&sql); @@ -633,18 +641,42 @@ repack_one_database(const char *orderby, char *errbuf, size_t errsize) " WHERE "); params[iparam++] = tablespace; - if (num_tables) + if (num_tables || num_parent_tables) { - appendStringInfoString(&sql, "("); - for (cell = table_list.head; cell; cell = cell->next) + /* standalone tables */ + if (num_tables) { - /* Construct table name placeholders to be used by PQexecParams */ - appendStringInfo(&sql, "relid = $%d::regclass", iparam + 1); - params[iparam++] = cell->val; - if (cell->next) - appendStringInfoString(&sql, " OR "); + appendStringInfoString(&sql, "("); + for (cell = table_list.head; cell; cell = cell->next) + { + /* Construct table name placeholders to be used by PQexecParams */ + appendStringInfo(&sql, "relid = $%d::regclass", iparam + 1); + params[iparam++] = cell->val; + if (cell->next) + appendStringInfoString(&sql, " OR "); + } + appendStringInfoString(&sql, ")"); + } + + if (num_tables && num_parent_tables) + appendStringInfoString(&sql, " OR "); + + /* parent tables + inherited children */ + if (num_parent_tables) + { + appendStringInfoString(&sql, "("); + for (cell = parent_table_list.head; cell; cell = cell->next) + { + /* Construct table name placeholders to be used by PQexecParams */ + appendStringInfo(&sql, + "relid = ANY(repack.get_table_and_inheritors($%d::regclass))", + iparam + 1); + params[iparam++] = cell->val; + if (cell->next) + appendStringInfoString(&sql, " OR "); + } + appendStringInfoString(&sql, ")"); } - appendStringInfoString(&sql, ")"); } else if (num_schemas) { @@ -2008,7 +2040,7 @@ repack_all_indexes(char *errbuf, size_t errsize) initStringInfo(&sql); reconnect(ERROR); - assert(r_index.head || table_list.head); + assert(r_index.head || table_list.head || parent_table_list.head); if (!preliminary_checks(errbuf, errsize)) goto cleanup; @@ -2023,6 +2055,8 @@ repack_all_indexes(char *errbuf, size_t errsize) cell = r_index.head; } + + /* TODO: fix this also for parent_table_list */ else if (table_list.head) { appendStringInfoString(&sql, @@ -2087,6 +2121,7 @@ pgut_help(bool details) printf("Options:\n"); printf(" -a, --all repack all databases\n"); printf(" -t, --table=TABLE repack specific table only\n"); + printf(" -I, --parent-table=TABLE repack specific parent table and its inheritors\n"); printf(" -c, --schema=SCHEMA repack tables in specific schema only\n"); printf(" -s, --tablespace=TBLSPC move repacked tables to a new tablespace\n"); printf(" -S, --moveidx move repacked indexes to TBLSPC too\n"); diff --git a/lib/exports.txt b/lib/exports.txt index ebc1092..b3bd953 100644 --- a/lib/exports.txt +++ b/lib/exports.txt @@ -1,19 +1,21 @@ -Pg_magic_func 1 -pg_finfo_repack_apply 2 -pg_finfo_repack_disable_autovacuum 3 -pg_finfo_repack_drop 4 -pg_finfo_repack_get_order_by 5 -pg_finfo_repack_indexdef 6 -pg_finfo_repack_swap 7 -pg_finfo_repack_trigger 8 -pg_finfo_repack_version 9 -pg_finfo_repack_index_swap 10 -repack_apply 11 -repack_disable_autovacuum 12 -repack_drop 13 -repack_get_order_by 14 -repack_indexdef 15 -repack_swap 16 -repack_trigger 17 -repack_version 18 -repack_index_swap 19 +Pg_magic_func 1 +pg_finfo_repack_apply 2 +pg_finfo_repack_disable_autovacuum 3 +pg_finfo_repack_drop 4 +pg_finfo_repack_get_order_by 5 +pg_finfo_repack_indexdef 6 +pg_finfo_repack_swap 7 +pg_finfo_repack_trigger 8 +pg_finfo_repack_version 9 +pg_finfo_repack_index_swap 10 +pg_finfo_repack_get_table_and_inheritors 11 +repack_apply 12 +repack_disable_autovacuum 13 +repack_drop 14 +repack_get_order_by 15 +repack_indexdef 16 +repack_swap 17 +repack_trigger 18 +repack_version 19 +repack_index_swap 20 +repack_get_table_and_inheritors 21 diff --git a/lib/pg_repack.sql.in b/lib/pg_repack.sql.in index d294548..13c95f5 100644 --- a/lib/pg_repack.sql.in +++ b/lib/pg_repack.sql.in @@ -254,3 +254,8 @@ LANGUAGE C VOLATILE STRICT; CREATE FUNCTION repack.repack_index_swap(oid) RETURNS void AS 'MODULE_PATHNAME', 'repack_index_swap' LANGUAGE C STABLE STRICT; + +CREATE FUNCTION repack.get_table_and_inheritors(regclass) RETURNS regclass[] AS +'MODULE_PATHNAME', 'repack_get_table_and_inheritors' +LANGUAGE C STABLE STRICT; + diff --git a/lib/repack.c b/lib/repack.c index 4e6711b..2355fe4 100644 --- a/lib/repack.c +++ b/lib/repack.c @@ -25,12 +25,14 @@ #include "catalog/pg_am.h" #endif +#include "catalog/pg_inherits_fn.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" #include "catalog/pg_type.h" #include "commands/tablecmds.h" #include "commands/trigger.h" #include "miscadmin.h" +#include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/rel.h" @@ -61,6 +63,7 @@ extern Datum PGUT_EXPORT repack_swap(PG_FUNCTION_ARGS); extern Datum PGUT_EXPORT repack_drop(PG_FUNCTION_ARGS); extern Datum PGUT_EXPORT repack_disable_autovacuum(PG_FUNCTION_ARGS); extern Datum PGUT_EXPORT repack_index_swap(PG_FUNCTION_ARGS); +extern Datum PGUT_EXPORT repack_get_table_and_inheritors(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(repack_version); PG_FUNCTION_INFO_V1(repack_trigger); @@ -71,6 +74,7 @@ PG_FUNCTION_INFO_V1(repack_swap); PG_FUNCTION_INFO_V1(repack_drop); PG_FUNCTION_INFO_V1(repack_disable_autovacuum); PG_FUNCTION_INFO_V1(repack_index_swap); +PG_FUNCTION_INFO_V1(repack_get_table_and_inheritors); static void repack_init(void); static SPIPlanPtr repack_prepare(const char *src, int nargs, Oid *argtypes); @@ -312,9 +316,9 @@ repack_apply(PG_FUNCTION_ARGS) * can delete all the rows we have processed at-once. */ if (i == 0) - appendStringInfoString(&sql_pop, pkid); + appendStringInfoString(&sql_pop, pkid); else - appendStringInfo(&sql_pop, ",%s", pkid); + appendStringInfo(&sql_pop, ",%s", pkid); pfree(pkid); } /* i must be > 0 (and hence we must have some rows to delete) @@ -1342,3 +1346,36 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, Oid namespaceId) PG_END_TRY(); } #endif + +Datum +repack_get_table_and_inheritors(PG_FUNCTION_ARGS) +{ + Oid parent = PG_GETARG_OID(0); + List *relations; + Datum *relations_array; + int relations_array_size; + ArrayType *result; + ListCell *lc; + int i; + + relations = find_all_inheritors(parent, NoLock, NULL); + + relations_array_size = list_length(relations); + if (relations_array_size == 0) + PG_RETURN_ARRAYTYPE_P(construct_empty_array(OIDOID)); + + relations_array = palloc(relations_array_size * sizeof(Datum)); + + i = 0; + foreach (lc, relations) + relations_array[i++] = ObjectIdGetDatum(lfirst_oid(lc)); + + result = construct_array(relations_array, + relations_array_size, + OIDOID, sizeof(Oid), + true, 'i'); + + pfree(relations_array); + + PG_RETURN_ARRAYTYPE_P(result); +}