From 25c668725ad0619351d32920ae882e9f9aec1e56 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Fri, 28 Jun 2019 14:21:17 +0200 Subject: [PATCH 4/4] Add a --glibc-dependent option. When this flag is passed, all indexes that depend on a glibc collation will be reindexed. This is especially important given the upcoming glibc 2.28 version which break the ordering of most collations, including en_US. This option is compatible with the --job, --dbname and the --all options (among others) but not the --schema, --table and --index options. --- src/bin/scripts/reindexdb.c | 387 ++++++++++++++++++----- src/bin/scripts/t/092_reindexdb_glibc.pl | 106 +++++++ 2 files changed, 412 insertions(+), 81 deletions(-) create mode 100644 src/bin/scripts/t/092_reindexdb_glibc.pl diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index f8a78a1b4a..3742cebef0 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -10,6 +10,9 @@ */ #include "postgres_fe.h" + +#include "catalog/pg_class_d.h" + #include "common.h" #include "common/logging.h" #include "fe_utils/connect.h" @@ -30,25 +33,29 @@ typedef enum ReindexType static ReindexType get_parallel_object_list(PGconn *conn, ReindexType type, SimpleStringList *user_list, SimplePtrList * process_list, - const char *progname, bool echo); + const char *progname, bool echo, + bool glibc_dependent); static void reindex_one_database(const char *dbname, ReindexType type, SimpleStringList *user_list, const char *host, const char *port, const char *username, enum trivalue prompt_password, const char *progname, bool echo, bool verbose, bool concurrently, - int concurrentCons); + int concurrentCons, bool glibc_dependent); static void reindex_all_databases(const char *maintenance_db, const char *host, const char *port, const char *username, enum trivalue prompt_password, const char *progname, bool echo, bool quiet, bool verbose, bool concurrently, - int concurrentCons); + int concurrentCons, bool glibc_dependent); static void run_reindex_command(PGconn *conn, ReindexType type, const char *name, const char *progname, bool echo, bool verbose, bool concurrently, bool async); static void slot_process_item(ParallelSlot *slot, int *pending_conn, ReindexType process_type, const char *progname, bool echo, bool verbose, bool concurrently, bool parallel); +static char *get_glibc_query(PGconn *conn); +static void append_indexes_per_table(PGresult *res, + SimplePtrList *process_list); static void help(const char *progname); @@ -73,6 +80,7 @@ main(int argc, char *argv[]) {"verbose", no_argument, NULL, 'v'}, {"concurrently", no_argument, NULL, 1}, {"maintenance-db", required_argument, NULL, 2}, + {"glibc-dependent", no_argument, NULL, 3}, {NULL, 0, NULL, 0} }; @@ -92,6 +100,7 @@ main(int argc, char *argv[]) bool quiet = false; bool verbose = false; bool concurrently = false; + bool glibc_dependent = false; SimpleStringList indexes = {NULL, NULL}; SimpleStringList tables = {NULL, NULL}; SimpleStringList schemas = {NULL, NULL}; @@ -174,6 +183,9 @@ main(int argc, char *argv[]) case 2: maintenance_db = pg_strdup(optarg); break; + case 3: + glibc_dependent = true; + break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -230,7 +242,7 @@ main(int argc, char *argv[]) reindex_all_databases(maintenance_db, host, port, username, prompt_password, progname, echo, quiet, verbose, - concurrently, 1); + concurrently, 1, glibc_dependent); } else if (syscatalog) { @@ -256,6 +268,12 @@ main(int argc, char *argv[]) exit(1); } + if (glibc_dependent) + { + pg_log_error("cannot reindex glibc dependent objects and system catalogs at the same time"); + exit(1); + } + if (dbname == NULL) { if (getenv("PGDATABASE")) @@ -268,10 +286,17 @@ main(int argc, char *argv[]) reindex_one_database(dbname, REINDEX_SYSTEM, NULL, host, port, username, prompt_password, progname, - echo, verbose, concurrently, 1); + echo, verbose, concurrently, 1, false); } else { + if (glibc_dependent && (schemas.head != NULL || indexes.head != NULL + || tables.head != NULL)) + { + pg_log_error("cannot reindex glibc dependent objects and a subset of objects"); + exit(1); + } + if (dbname == NULL) { if (getenv("PGDATABASE")) @@ -286,7 +311,7 @@ main(int argc, char *argv[]) reindex_one_database(dbname, REINDEX_SCHEMA, &schemas, host, port, username, prompt_password, progname, echo, verbose, concurrently, - Min(concurrentCons, nsp_count)); + Min(concurrentCons, nsp_count), false); if (indexes.head != NULL) @@ -297,13 +322,13 @@ main(int argc, char *argv[]) reindex_one_database(dbname, REINDEX_INDEX, &indexes, host, port, username, prompt_password, progname, echo, verbose, concurrently, - concurrentCons); + concurrentCons, false); if (tables.head != NULL) reindex_one_database(dbname, REINDEX_TABLE, &tables, host, port, username, prompt_password, progname, echo, verbose, concurrently, - Min(concurrentCons, tbl_count)); + Min(concurrentCons, tbl_count), false); /* * reindex database only if neither index nor table nor schema is @@ -312,7 +337,8 @@ main(int argc, char *argv[]) if (indexes.head == NULL && tables.head == NULL && schemas.head == NULL) reindex_one_database(dbname, REINDEX_DATABASE, NULL, host, port, username, prompt_password, progname, - echo, verbose, concurrently, concurrentCons); + echo, verbose, concurrently, concurrentCons, + glibc_dependent); } exit(0); @@ -323,7 +349,8 @@ reindex_one_database(const char *dbname, ReindexType type, SimpleStringList *user_list, const char *host, const char *port, const char *username, enum trivalue prompt_password, const char *progname, bool echo, - bool verbose, bool concurrently, int concurrentCons) + bool verbose, bool concurrently, int concurrentCons, + bool glibc_dependent) { PGconn *conn; bool parallel = concurrentCons > 1; @@ -350,12 +377,58 @@ reindex_one_database(const char *dbname, ReindexType type, { if (user_list) { + Assert(!glibc_dependent); + /* * In non parallel mode, if the user provided a list, just use it * as-is */ simple_ptr_list_append(&process_list, user_list); } + else if (glibc_dependent) + { + SimpleStringList *dummy = palloc0(sizeof(SimpleStringList)); + PGresult *res; + PQExpBufferData buf; + int ntups; + int i; + + process_type = REINDEX_INDEX; + + run_reindex_command(conn, REINDEX_SYSTEM, NULL, progname, echo, + verbose, concurrently, glibc_dependent); + + res = executeQuery(conn, get_glibc_query(conn), progname, echo); + + /* + * If no rows are returned, there are no matching tables, so we + * are done. + */ + ntups = PQntuples(res); + if (ntups == 0) + { + PQclear(res); + PQfinish(conn); + return; + } + + /* Build qualified identifiers for each table */ + initPQExpBuffer(&buf); + for (i = 0; i < ntups; i++) + { + appendPQExpBufferStr(&buf, + fmtQualifiedId(PQgetvalue(res, i, 1), + PQgetvalue(res, i, 0))); + + simple_string_list_append(dummy, buf.data); + + resetPQExpBuffer(&buf); + } + simple_ptr_list_append(&process_list, dummy); + + termPQExpBuffer(&buf); + PQclear(res); + } else { /* @@ -383,7 +456,8 @@ reindex_one_database(const char *dbname, ReindexType type, /* Get the list of objects to process */ process_type = get_parallel_object_list(conn, type, user_list, - &process_list, progname, echo); + &process_list, progname, echo, + glibc_dependent); } /* Lower down the number of required connections if needed. */ @@ -622,7 +696,7 @@ static ReindexType get_parallel_object_list(PGconn *conn, ReindexType type, SimpleStringList *user_list, SimplePtrList * process_list, const char *progname, - bool echo) + bool echo, bool glibc_dependent) { ReindexType process_type = type; PQExpBufferData buf; @@ -639,66 +713,88 @@ get_parallel_object_list(PGconn *conn, ReindexType type, Assert(user_list == NULL); - process_type = REINDEX_TABLE; + if (glibc_dependent) + { + process_type = REINDEX_INDEX; - initPQExpBuffer(&catalog_query); + res = executeQuery(conn, get_glibc_query(conn), progname, echo); - /* - * This query is run using a safe search_path, so there's no need to - * fully qualify everything. - */ - appendPQExpBuffer(&catalog_query, - "SELECT c.relname, ns.nspname\n" - " FROM pg_catalog.pg_class c\n" - " JOIN pg_catalog.pg_namespace ns" - " ON c.relnamespace = ns.oid\n" - " WHERE ns.nspname != 'pg_catalog'\n" - " AND c.relkind IN (" - CppAsString2(RELKIND_RELATION) ", " - CppAsString2(RELKIND_MATVIEW) ")\n" - " ORDER BY c.relpages DESC;"); - - res = executeQuery(conn, catalog_query.data, progname, echo); - termPQExpBuffer(&catalog_query); + /* + * If no rows are returned, there are no matching tables, so we + * are done. + */ + ntups = PQntuples(res); + if (ntups == 0) + { + PQclear(res); + PQfinish(conn); + return process_type; + } - /* - * If no rows are returned, there are no matching tables, so we are - * done. - */ - ntups = PQntuples(res); - if (ntups == 0) - { - PQclear(res); - PQfinish(conn); - return process_type; + append_indexes_per_table(res, process_list); } - - /* Build qualified identifiers for each table */ - initPQExpBuffer(&buf); - for (i = 0; i < ntups; i++) + else { - tables = pg_malloc0(sizeof(SimpleStringList)); + process_type = REINDEX_TABLE; + + initPQExpBuffer(&catalog_query); + + /* + * This query is run using a safe search_path, so there's no need + * to fully qualify everything. + */ + appendPQExpBuffer(&catalog_query, + "SELECT c.relname, ns.nspname\n" + " FROM pg_catalog.pg_class c\n" + " JOIN pg_catalog.pg_namespace ns" + " ON c.relnamespace = ns.oid\n" + " WHERE ns.nspname != 'pg_catalog'\n" + " AND c.relkind IN (" + CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_MATVIEW) ")\n" + " ORDER BY c.relpages DESC;"); + + res = executeQuery(conn, catalog_query.data, progname, echo); + termPQExpBuffer(&catalog_query); + + /* + * If no rows are returned, there are no matching tables, so we are + * done. + */ + ntups = PQntuples(res); + if (ntups == 0) + { + PQclear(res); + PQfinish(conn); + return process_type; + } + + /* Build qualified identifiers for each table */ + initPQExpBuffer(&buf); + for (i = 0; i < ntups; i++) + { + tables = pg_malloc0(sizeof(SimpleStringList)); - appendPQExpBufferStr(&buf, - fmtQualifiedId(PQgetvalue(res, i, 1), - PQgetvalue(res, i, 0))); + appendPQExpBufferStr(&buf, + fmtQualifiedId(PQgetvalue(res, i, 1), + PQgetvalue(res, i, 0))); - simple_string_list_append(tables, buf.data); - simple_ptr_list_append(process_list, tables); - resetPQExpBuffer(&buf); + simple_string_list_append(tables, buf.data); + simple_ptr_list_append(process_list, tables); + resetPQExpBuffer(&buf); + } + termPQExpBuffer(&buf); + PQclear(res); } - termPQExpBuffer(&buf); - PQclear(res); } else if (type == REINDEX_INDEX) { - SimpleStringList *indexes = NULL; SimpleStringListCell *cell; PGresult *res; int ntups; - char *prev_rel = NULL; Assert(user_list != NULL); + Assert(!glibc_dependent); initPQExpBuffer(&catalog_query); @@ -710,7 +806,8 @@ get_parallel_object_list(PGconn *conn, ReindexType type, * locking issues that would be implied. */ appendPQExpBuffer(&catalog_query, - "SELECT ic.relname, ns.nspname, tc.oid\n" + "SELECT ic.relname AS index_relname," + " ns.nspname AS index_nspname, tc.oid AS table_oid\n" " FROM pg_catalog.pg_index i\n" " JOIN pg_catalog.pg_class ic" " ON i.indexrelid OPERATOR(pg_catalog.=) ic.oid\n" @@ -759,28 +856,7 @@ get_parallel_object_list(PGconn *conn, ReindexType type, return process_type; } - indexes = pg_malloc0(sizeof(SimpleStringList)); - - /* Build a list of qualified index name, aggregated per table */ - for (i = 0; i < ntups; i++) - { - if (!prev_rel) - prev_rel = pg_strdup(PQgetvalue(res, i, 2)); - - if (strcmp(PQgetvalue(res, i, 2), prev_rel) != 0) - { - simple_ptr_list_append(process_list, indexes); - - indexes = pg_malloc0(sizeof(SimpleStringList)); - pg_free(prev_rel); - prev_rel = pg_strdup(PQgetvalue(res, i, 2)); - } - - simple_string_list_append(indexes, - fmtQualifiedId(PQgetvalue(res, i, 1), - PQgetvalue(res, i, 0))); - } - simple_ptr_list_append(process_list, indexes); + append_indexes_per_table(res, process_list); PQclear(res); } @@ -796,6 +872,7 @@ get_parallel_object_list(PGconn *conn, ReindexType type, SimpleStringListCell *cell; Assert(user_list != NULL); + Assert(!glibc_dependent); for (cell = user_list->head; cell; cell = cell->next) { @@ -809,6 +886,152 @@ get_parallel_object_list(PGconn *conn, ReindexType type, return process_type; } +/* + * This function returns a query to retrieve all indexes that depends on a + * glibc stable sort ordering, and thus could get corrupted if that order + * changed. The returned query will be executed using a safe search_path, so + * there's no need to fully qualify everything. + * + * Indexes on the system catalogs are excluded, as those would get reindexed + * explicitly if a reindex on glibc-dependent indexes is asked. + * + * The list of impacted indexes is retrieved using the indclass field in + * pg_index and not the indkey field, as indexes must be retrieved too. The + * underlying type is then joined, and only indexes containing at least one + * column of type category String are kept. We however ignore special opclass + * varchar_pattern_ops and text_pattern_ops, as those do not depend on the + * underlying collation order. + * + * Note that there's no knowledge about specific glibc version or collation + * name. + */ +static char * +get_glibc_query(PGconn *conn) +{ + /* pg 10 added pg_collation */ + if (PQserverVersion(conn) >= 100000) + return "SELECT DISTINCT ic.relname AS index_relname," + " n.nspname AS index_nspname, tc.oid AS table_oid," + " pg_catalog.pg_indexes_size(tc.oid)" + " FROM pg_catalog.pg_class AS tc\n" + " JOIN pg_catalog.pg_index AS ix ON ix.indrelid = tc.oid\n" + " JOIN pg_catalog.pg_namespace AS n ON n.oid = tc.relnamespace\n" + " JOIN pg_catalog.pg_class AS ic ON ic.oid = ix.indexrelid\n" + " JOIN pg_catalog.pg_opclass AS opc ON opc.oid = ANY(ix.indclass)\n" + " JOIN pg_catalog.pg_type AS t ON t.oid = opc.opcintype\n" + " JOIN pg_catalog.pg_collation AS coll ON coll.oid = t.typcollation\n" + " WHERE t.typcategory = 'S'\n" + " AND n.nspname != 'pg_catalog'\n" + " AND tc.relkind IN ('m', 'r')\n" + " AND opc.opcname NOT IN ('text_pattern_ops', 'varchar_pattern_ops')\n" + " AND coll.collprovider IN ('d', 'c')\n" + " ORDER BY pg_catalog.pg_indexes_size(tc.oid) DESC;"; + /* pg 9.3 added materialized views */ + else if (PQserverVersion(conn) >= 90300) + return "SELECT DISTINCT ic.relname AS index_relname," + " n.nspname AS index_nspname, tc.oid AS table_oid," + " pg_catalog.pg_indexes_size(tc.oid)" + " FROM pg_catalog.pg_class AS tc\n" + " JOIN pg_catalog.pg_index AS ix ON ix.indrelid = tc.oid\n" + " JOIN pg_catalog.pg_namespace AS n ON n.oid = tc.relnamespace\n" + " JOIN pg_catalog.pg_class AS ic ON ic.oid = ix.indexrelid\n" + " JOIN pg_catalog.pg_opclass AS opc ON opc.oid = ANY(ix.indclass)\n" + " JOIN pg_catalog.pg_type AS t ON t.oid = opc.opcintype\n" + " WHERE t.typcategory = 'S'\n" + " AND n.nspname != 'pg_catalog'\n" + " AND tc.relkind IN ('m', 'r')\n" + " AND opc.opcname NOT IN ('text_pattern_ops', 'varchar_pattern_ops')\n" + " ORDER BY pg_catalog.pg_indexes_size(tc.oid) DESC;"; + /* pg 9.0 added pg_indexes_size() */ + else if (PQserverVersion(conn) >= 90000) + return "SELECT DISTINCT ic.relname AS index_relname," + " n.nspname AS index_nspname, tc.oid AS table_oid," + " pg_catalog.pg_indexes_size(tc.oid)" + " FROM pg_catalog.pg_class AS tc\n" + " JOIN pg_catalog.pg_index AS ix ON ix.indrelid = tc.oid\n" + " JOIN pg_catalog.pg_namespace AS n ON n.oid = tc.relnamespace\n" + " JOIN pg_catalog.pg_class AS ic ON ic.oid = ix.indexrelid\n" + " JOIN pg_catalog.pg_opclass AS opc ON opc.oid = ANY(ix.indclass)\n" + " JOIN pg_catalog.pg_type AS t ON t.oid = opc.opcintype\n" + " WHERE t.typcategory = 'S'\n" + " AND n.nspname != 'pg_catalog'\n" + " AND tc.relkind = 'r'\n" + " AND opc.opcname NOT IN ('text_pattern_ops', 'varchar_pattern_ops')\n" + " ORDER BY pg_catalog.pg_indexes_size(tc.oid) DESC;"; + /* pg 8.1 added pg_relation_size() */ + else if (PQserverVersion(conn) >= 80100) + return "SELECT DISTINCT ic.relname AS index_relname," + " n.nspname AS index_nspname, tc.oid AS table_oid," + " pg_catalog.pg_relation_size(tc.oid)" + " FROM pg_catalog.pg_class AS tc\n" + " JOIN pg_catalog.pg_index AS ix ON ix.indrelid = tc.oid\n" + " JOIN pg_catalog.pg_namespace AS n ON n.oid = tc.relnamespace\n" + " JOIN pg_catalog.pg_class AS ic ON ic.oid = ix.indexrelid\n" + " JOIN pg_catalog.pg_opclass AS opc ON opc.oid = ANY(ix.indclass)\n" + " JOIN pg_catalog.pg_type AS t ON t.oid = opc.opcintype\n" + " WHERE t.typcategory = 'S'\n" + " AND n.nspname != 'pg_catalog'\n" + " AND tc.relkind = 'r'\n" + " AND opc.opcname NOT IN ('text_pattern_ops', 'varchar_pattern_ops')\n" + " ORDER BY pg_catalog.pg_relation_size(tc.oid) DESC;"; + else + return "SELECT DISTINCT ic.relname AS index_relname," + " n.nspname AS index_nspname, tc.oid AS table_oid," + " FROM pg_catalog.pg_class AS tc\n" + " JOIN pg_catalog.pg_index AS ix ON ix.indrelid = tc.oid\n" + " JOIN pg_catalog.pg_namespace AS n ON n.oid = tc.relnamespace\n" + " JOIN pg_catalog.pg_class AS ic ON ic.oid = ix.indexrelid\n" + " JOIN pg_catalog.pg_opclass AS opc ON opc.oid = ANY(ix.indclass)\n" + " JOIN pg_catalog.pg_type AS t ON t.oid = opc.opcintype\n" + " WHERE t.typcategory = 'S'\n" + " AND n.nspname != 'pg_catalog'\n" + " AND tc.relkind = 'r'\n" + " AND opc.opcname NOT IN ('text_pattern_ops', 'varchar_pattern_ops');"; +} + +/* + * Build a list of qualified index name, per table. + * + * The result set must be: + * (index_relname, index_nspname, table_oid) + */ +static void +append_indexes_per_table(PGresult *res, SimplePtrList *process_list) +{ + SimpleStringList *indexes = NULL; + char *prev_rel = NULL; + int ntups = PQntuples(res); + int i; + + indexes = pg_malloc0(sizeof(SimpleStringList)); + + Assert(strcmp(PQfname(res, 0), "index_relname") == 0); + Assert(strcmp(PQfname(res, 1), "index_nspname") == 0); + Assert(strcmp(PQfname(res, 2), "table_oid") == 0); + + /* Build a list of qualified index name, per table */ + for (i = 0; i < ntups; i++) + { + if (!prev_rel) + prev_rel = pg_strdup(PQgetvalue(res, i, 2)); + + if (strcmp(PQgetvalue(res, i, 2), prev_rel) != 0) + { + simple_ptr_list_append(process_list, indexes); + + indexes = pg_malloc0(sizeof(SimpleStringList)); + pg_free(prev_rel); + prev_rel = pg_strdup(PQgetvalue(res, i, 2)); + } + + simple_string_list_append(indexes, + fmtQualifiedId(PQgetvalue(res, i, 1), + PQgetvalue(res, i, 0))); + } + + simple_ptr_list_append(process_list, indexes); +} + static void slot_process_item(ParallelSlot *slot, int *pending_conn, ReindexType process_type, const char *progname, bool echo, @@ -840,7 +1063,8 @@ reindex_all_databases(const char *maintenance_db, const char *host, const char *port, const char *username, enum trivalue prompt_password, const char *progname, bool echo, bool quiet, bool verbose, - bool concurrently, int concurrentCons) + bool concurrently, int concurrentCons, + bool glibc_dependent) { PGconn *conn; PGresult *result; @@ -870,7 +1094,7 @@ reindex_all_databases(const char *maintenance_db, reindex_one_database(connstr.data, REINDEX_DATABASE, NULL, host, port, username, prompt_password, progname, echo, verbose, concurrently, - concurrentCons); + concurrentCons, glibc_dependent); } termPQExpBuffer(&connstr); @@ -888,6 +1112,7 @@ help(const char *progname) printf(_(" --concurrently reindex concurrently\n")); printf(_(" -d, --dbname=DBNAME database to reindex\n")); printf(_(" -e, --echo show the commands being sent to the server\n")); + printf(_(" --glibc-dependent only reindex indexes depending on GLIBC\n")); printf(_(" -i, --index=INDEX recreate specific index(es) only\n")); printf(_(" -j, --jobs=NUM use this many concurrent connections to reindex\n")); printf(_(" -q, --quiet don't write any messages\n")); diff --git a/src/bin/scripts/t/092_reindexdb_glibc.pl b/src/bin/scripts/t/092_reindexdb_glibc.pl new file mode 100644 index 0000000000..22b07d2acb --- /dev/null +++ b/src/bin/scripts/t/092_reindexdb_glibc.pl @@ -0,0 +1,106 @@ +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 60; + +if (exists $ENV{MY_PG_REGRESS}) +{ + $ENV{PG_REGRESS} = $ENV{MY_PG_REGRESS}; +} + +my $node = get_new_node('main'); +$node->init; +$node->start; + +$ENV{PGOPTIONS} = '--client-min-messages=WARNING'; + +# glibc-dependent processing +my %idxs; +my %newidxs; + +$node->psql('postgres', 'CREATE TABLE "TEST"(id integer, val text)'); +$node->psql('postgres', 'CREATE INDEX idx1 ON "TEST"(id)'); +$node->psql('postgres', 'CREATE INDEX "IDX2" ON "TEST"(val)'); +$node->psql('postgres', 'CREATE INDEX idx3 ON "TEST"(val text_pattern_ops)'); +$node->psql('postgres', 'CREATE INDEX idx4 ON "TEST"(val text_pattern_ops, val)'); +$node->psql('postgres', 'CREATE INDEX idx5 ON "TEST"((lower(val)))'); +$node->psql('postgres', 'CREATE INDEX idx6 ON "TEST"((lower(val)) text_pattern_ops)'); +$node->psql('postgres', 'CREATE INDEX idx7 ON "TEST"((lower(val)), (lower(val)) text_pattern_ops)'); + +# get original indexes' relfilenode +foreach my $idx ('idx1', 'IDX2', 'idx3', 'idx4', 'idx5', 'idx6', 'idx7') +{ + my ($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT relfilenode" + . " FROM pg_catalog.pg_class c" + . " WHERE c.relname = '$idx'"); + + isnt($stdout, '', 'A relfinode should be returned'); + isnt($stdout, 0, 'Relfinode should not be 0'); + $idxs{$idx} = $stdout; +} + +$node->issues_sql_like( + [ 'vreindexdb', '--glibc-dependent', 'postgres' ], + qr/statement: REINDEX SYSTEM postgres;/, + 'reindex system tables'); + +# get possibly new indexes' relfilenode +foreach my $idx ('idx1', 'IDX2', 'idx3', 'idx4', 'idx5', 'idx6', 'idx7') +{ + my ($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT relfilenode" + . " FROM pg_catalog.pg_class c" + . " WHERE c.relname = '$idx'"); + + isnt($stdout, '', 'A relfinode should be returned'); + isnt($stdout, 0, "Relfinode shouldn't be 0"); + $newidxs{$idx} = $stdout; +} + +is($idxs{'idx1'}, $newidxs{'idx1'}, + 'Non string index should not have been reindexed'); +isnt($idxs{'IDX2'}, $newidxs{'IDX2'}, + 'String index with non specific opclass should have been reindexed'); +is($idxs{'idx3'}, $newidxs{'idx3'}, + 'String index with specific opclass should not have been reindexed'); +isnt($idxs{'idx4'}, $newidxs{'idx4'}, + 'String index with mix of opclass should have been reindexed'); +isnt($idxs{'idx5'}, $newidxs{'idx5'}, + 'String functional index with non specific opclass should have been reindexed'); +is($idxs{'idx6'}, $newidxs{'idx6'}, + 'String functional index with specific opclass should not have been reindexed'); +isnt($idxs{'idx7'}, $newidxs{'idx7'}, + 'String functional index with mix of opclass should have been reindexed'); + +$node->issues_sql_like( + [ 'vreindexdb', '--glibc-dependent', '-j2', 'postgres' ], + qr/statement: REINDEX SYSTEM postgres;/, + 'reindex system tables'); + +# get possibly new indexes' relfilenode +foreach my $idx ('idx1', 'IDX2', 'idx3', 'idx4', 'idx5', 'idx6', 'idx7') +{ + my ($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT relfilenode" + . " FROM pg_catalog.pg_class c" + . " WHERE c.relname = '$idx'"); + + isnt($stdout, '', 'A relfinode should be returned'); + isnt($stdout, 0, "Relfinode shouldn't be 0"); + $idxs{$idx} = $stdout; +} + +is($idxs{'idx1'}, $newidxs{'idx1'}, + 'Non string index should not have been reindexed'); +isnt($idxs{'IDX2'}, $newidxs{'IDX2'}, + 'String index with non specific opclass should have been reindexed'); +is($idxs{'idx3'}, $newidxs{'idx3'}, + 'String index with specific opclass should not have been reindexed'); +isnt($idxs{'idx4'}, $newidxs{'idx4'}, + 'String index with mix of opclass should have been reindexed'); +isnt($idxs{'idx5'}, $newidxs{'idx5'}, + 'String functional index with non specific opclass should have been reindexed'); +is($idxs{'idx6'}, $newidxs{'idx6'}, + 'String functional index with specific opclass should not have been reindexed'); +isnt($idxs{'idx7'}, $newidxs{'idx7'}, + 'String functional index with mix of opclass should have been reindexed'); -- 2.20.1