diff --git a/contrib/test_decoding/expected/stats.out b/contrib/test_decoding/expected/stats.out index 78d36429c8..fa18fba7ba 100644 --- a/contrib/test_decoding/expected/stats.out +++ b/contrib/test_decoding/expected/stats.out @@ -139,6 +139,19 @@ SELECT slot_name FROM pg_stat_replication_slots; COMMIT; DROP TABLE stats_test; +-- Count the number of slots +select count(1) as nb_slots from pg_stat_replication_slots \gset +-- We want pg_stat_have_stats() to return true at least one time for the slots id range +select count(1) > 0 from generate_series(0, :nb_slots - 1) as n where pg_stat_have_stats('replslot', 0, n); + ?column? +---------- + t +(1 row) + +-- Record the replication_slots id(s) for which pg_stat_have_stats() returns true +select array(select n from generate_series(0, :nb_slots - 1) as n where pg_stat_have_stats('replslot', 0, n) order by n asc) as true_ids \gset +\set true_ids '''' :true_ids '''' +-- Drop the 3 slots SELECT pg_drop_replication_slot('regression_slot_stats1'), pg_drop_replication_slot('regression_slot_stats2'), pg_drop_replication_slot('regression_slot_stats3'); @@ -147,3 +160,12 @@ SELECT pg_drop_replication_slot('regression_slot_stats1'), | | (1 row) +-- We want the ones that were true to be false after dropping the slots +select array(select n from generate_series(0, :nb_slots - 1) as n where not pg_stat_have_stats('replslot', 0, n) order by n asc) as false_ids \gset +\set false_ids '''' :false_ids '''' +select :true_ids = :false_ids; + ?column? +---------- + t +(1 row) + diff --git a/contrib/test_decoding/sql/stats.sql b/contrib/test_decoding/sql/stats.sql index 630371f147..ffb021f76d 100644 --- a/contrib/test_decoding/sql/stats.sql +++ b/contrib/test_decoding/sql/stats.sql @@ -51,6 +51,23 @@ SELECT slot_name FROM pg_stat_replication_slots; COMMIT; DROP TABLE stats_test; + +-- Count the number of slots +select count(1) as nb_slots from pg_stat_replication_slots \gset + +-- We want pg_stat_have_stats() to return true at least one time for the slots id range +select count(1) > 0 from generate_series(0, :nb_slots - 1) as n where pg_stat_have_stats('replslot', 0, n); + +-- Record the replication_slots id(s) for which pg_stat_have_stats() returns true +select array(select n from generate_series(0, :nb_slots - 1) as n where pg_stat_have_stats('replslot', 0, n) order by n asc) as true_ids \gset +\set true_ids '''' :true_ids '''' + +-- Drop the 3 slots SELECT pg_drop_replication_slot('regression_slot_stats1'), pg_drop_replication_slot('regression_slot_stats2'), pg_drop_replication_slot('regression_slot_stats3'); + +-- We want the ones that were true to be false after dropping the slots +select array(select n from generate_series(0, :nb_slots - 1) as n where not pg_stat_have_stats('replslot', 0, n) order by n asc) as false_ids \gset +\set false_ids '''' :false_ids '''' +select :true_ids = :false_ids; \ No newline at end of file diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 9b03579e6e..9a80ccdccd 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -403,6 +403,9 @@ heap_create(const char *relname, recordDependencyOnTablespace(RelationRelationId, relid, reltablespace); + /* ensure that stats are dropped if transaction aborts */ + pgstat_create_relation(rel); + return rel; } @@ -1477,9 +1480,6 @@ heap_create_with_catalog(const char *relname, if (oncommit != ONCOMMIT_NOOP) register_on_commit_action(relid, oncommit); - /* ensure that stats are dropped if transaction aborts */ - pgstat_create_relation(new_rel_desc); - /* * ok, the relation has been cataloged, so close our relations and return * the OID of the newly created relation. diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index d7192f35e3..61f1d3926a 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2325,6 +2325,9 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode) if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind)) RelationDropStorage(userIndexRelation); + /* ensure that stats are dropped if transaction commits */ + pgstat_drop_relation(userIndexRelation); + /* * Close and flush the index's relcache entry, to ensure relcache doesn't * try to rebuild it while we're deleting catalog entries. We keep the diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index 6b233ff4c0..fa0a2c6f7a 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -18,6 +18,8 @@ SET enable_indexscan TO on; SET enable_indexonlyscan TO off; -- not enabled by default, but we want to test it... SET track_functions TO 'all'; +-- record dboid for later use +SELECT oid AS dboid from pg_database where datname = current_database() \gset -- save counters BEGIN; SET LOCAL stats_fetch_consistency = snapshot; @@ -771,18 +773,121 @@ SELECT pg_stat_have_stats('bgwriter', 0, 0); SELECT pg_stat_have_stats('zaphod', 0, 0); ERROR: invalid statistics kind: "zaphod" -- db stats have objoid 0 -SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 1); +SELECT pg_stat_have_stats('database', :dboid, 1); pg_stat_have_stats -------------------- f (1 row) -SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 0); +SELECT pg_stat_have_stats('database', :dboid, 0); pg_stat_have_stats -------------------- t (1 row) +-- pg_stat_have_stats returns true for committed index creation +CREATE table stats_test_tab1 as select generate_series(1,10) a; +CREATE index stats_test_idx1 on stats_test_tab1(a); +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +SET enable_seqscan TO off; +select a from stats_test_tab1 where a = 3; + a +--- + 3 +(1 row) + +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +-- pg_stat_have_stats returns false for dropped index with stats +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +DROP index stats_test_idx1; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + f +(1 row) + +-- pg_stat_have_stats returns false for rolled back index creation +BEGIN; +CREATE index stats_test_idx1 on stats_test_tab1(a); +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +select a from stats_test_tab1 where a = 3; + a +--- + 3 +(1 row) + +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +ROLLBACK; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + f +(1 row) + +-- pg_stat_have_stats returns true for reindex CONCURRENTLY +CREATE index stats_test_idx1 on stats_test_tab1(a); +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +select a from stats_test_tab1 where a = 3; + a +--- + 3 +(1 row) + +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +REINDEX index CONCURRENTLY stats_test_idx1; +-- false for previous oid +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + f +(1 row) + +-- true for new oid +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +-- pg_stat_have_stats returns true for a rolled back drop index with stats +BEGIN; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +DROP index stats_test_idx1; +ROLLBACK; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + pg_stat_have_stats +-------------------- + t +(1 row) + +-- put enable_seqscan back to on +SET enable_seqscan TO on; -- ensure that stats accessors handle NULL input correctly SELECT pg_stat_get_replication_slot(NULL); pg_stat_get_replication_slot diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index 096f00ce8b..a63bde9e67 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -16,6 +16,9 @@ SET enable_indexonlyscan TO off; -- not enabled by default, but we want to test it... SET track_functions TO 'all'; +-- record dboid for later use +SELECT oid AS dboid from pg_database where datname = current_database() \gset + -- save counters BEGIN; SET LOCAL stats_fetch_consistency = snapshot; @@ -387,9 +390,52 @@ SELECT pg_stat_have_stats('bgwriter', 0, 0); -- unknown stats kinds error out SELECT pg_stat_have_stats('zaphod', 0, 0); -- db stats have objoid 0 -SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 1); -SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 0); +SELECT pg_stat_have_stats('database', :dboid, 1); +SELECT pg_stat_have_stats('database', :dboid, 0); + +-- pg_stat_have_stats returns true for committed index creation +CREATE table stats_test_tab1 as select generate_series(1,10) a; +CREATE index stats_test_idx1 on stats_test_tab1(a); +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +SET enable_seqscan TO off; +select a from stats_test_tab1 where a = 3; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + +-- pg_stat_have_stats returns false for dropped index with stats +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +DROP index stats_test_idx1; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + +-- pg_stat_have_stats returns false for rolled back index creation +BEGIN; +CREATE index stats_test_idx1 on stats_test_tab1(a); +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +select a from stats_test_tab1 where a = 3; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +ROLLBACK; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + +-- pg_stat_have_stats returns true for reindex CONCURRENTLY +CREATE index stats_test_idx1 on stats_test_tab1(a); +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +select a from stats_test_tab1 where a = 3; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +REINDEX index CONCURRENTLY stats_test_idx1; +-- false for previous oid +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +-- true for new oid +SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); + +-- pg_stat_have_stats returns true for a rolled back drop index with stats +BEGIN; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +DROP index stats_test_idx1; +ROLLBACK; +SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +-- put enable_seqscan back to on +SET enable_seqscan TO on; -- ensure that stats accessors handle NULL input correctly SELECT pg_stat_get_replication_slot(NULL);