diff --git a/bin/pg_repack.c b/bin/pg_repack.c index 940a0d81..bed8427d 100644 --- a/bin/pg_repack.c +++ b/bin/pg_repack.c @@ -211,6 +211,7 @@ typedef struct repack_table static bool is_superuser(void); static void check_tablespace(void); +static bool check_systemtables(void); static bool preliminary_checks(char *errbuf, size_t errsize); static bool is_requested_relation_exists(char *errbuf, size_t errsize); static void repack_all_databases(const char *order_by); @@ -421,6 +422,47 @@ is_superuser(void) return false; } +bool +check_systemtables() + +{ + PGresult *query_result = NULL; + int num; + SimpleStringListCell *cell; + StringInfoData sql; + int iparam = 0; + + num = simple_string_list_size(table_list); + + initStringInfo(&sql); + + appendStringInfoString(&sql, "select 1 from pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace where n.nspname IN ('pg_catalog','information_schema') AND c.oid IN ("); + + for (cell = table_list.head; cell; cell = cell->next) + { + appendStringInfo(&sql, "'%s'::regclass::oid", cell->val); + iparam++; + if (iparam < num) + appendStringInfoChar(&sql, ','); + } + + appendStringInfoString(&sql,")"); + + query_result = execute_elevel(sql.data,0,NULL, DEBUG2); + + if (PQresultStatus(query_result) == PGRES_TUPLES_OK) + { + if (PQntuples(query_result) >= 1) + { + return true; + } + } + + CLEARPGRES(query_result); + + return false; +} + /* * Check if the tablespace requested exists. * @@ -487,6 +529,12 @@ preliminary_checks(char *errbuf, size_t errsize){ goto cleanup; } + if (check_systemtables()) { + if (errbuf) + snprintf(errbuf, errsize, "For System Tables Use VACUUM FULL."); + goto cleanup; + } + /* Query the extension version. Exit if no match */ res = execute_elevel("select repack.version(), repack.version_sql()", 0, NULL, DEBUG2); @@ -1276,7 +1324,7 @@ repack_one_table(repack_table *table, const char *orderby) return; /* push repack_cleanup_callback() on stack to clean temporary objects */ - pgut_atexit_push(repack_cleanup_callback, &table->target_oid); + pgut_atexit_push(repack_cleanup_callback, table); /* * 1. Setup advisory lock and trigger on main table. @@ -1966,7 +2014,8 @@ lock_exclusive(PGconn *conn, const char *relid, const char *lock_query, bool sta void repack_cleanup_callback(bool fatal, void *userdata) { - Oid target_table = *(Oid *) userdata; + repack_table *table = (repack_table *) userdata; + Oid target_table = table->target_oid; const char *params[2]; char buffer[12]; char num_buff[12]; @@ -1981,7 +2030,16 @@ repack_cleanup_callback(bool fatal, void *userdata) * so just use an unconditional reconnect(). */ reconnect(ERROR); + + command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); + if (!(lock_exclusive(connection, params[0], table->lock_table, false))) + { + elog(ERROR, "lock_exclusive() failed in connection for %s during cleanup callback", + table->target_name); + } + command("SELECT repack.repack_drop($1, $2)", 2, params); + command("COMMIT", 0, NULL); temp_obj_num = 0; /* reset temporary object counter after cleanup */ } } @@ -2011,7 +2069,16 @@ repack_cleanup(bool fatal, const repack_table *table) /* do cleanup */ params[0] = utoa(table->target_oid, buffer); params[1] = utoa(temp_obj_num, num_buff); + + command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); + if (!(lock_exclusive(connection, params[0], table->lock_table, false))) + { + elog(ERROR, "lock_exclusive() failed in connection for %s during cleanup", + table->target_name); + } + command("SELECT repack.repack_drop($1, $2)", 2, params); + command("COMMIT", 0, NULL); temp_obj_num = 0; /* reset temporary object counter after cleanup */ } } diff --git a/bin/pgut/pgut.h b/bin/pgut/pgut.h index e347bea7..9253855b 100644 --- a/bin/pgut/pgut.h +++ b/bin/pgut/pgut.h @@ -51,7 +51,7 @@ extern const char *PROGRAM_ISSUES; extern bool interrupted; extern int pgut_log_level; extern int pgut_abort_level; -extern bool pgut_echo; +extern bool pgut_echo; extern void pgut_init(int argc, char **argv); extern void pgut_atexit_push(pgut_atexit_callback callback, void *userdata);