From cd2830bfc7159bdbf52541c9a2faef15a48886ec Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 17 Apr 2020 12:39:39 +0200 Subject: [PATCH] pgstattuple: Have pgstattuple_approx accept TOAST tables TOAST tables have a visibility map and a free space map, so they can be supported by pgstattuple_approx just fine. Add test cases to show how various pgstattuple functions accept TOAST tables. Also add similar tests to pg_visibility, which already accepted TOAST tables correctly but had no test coverage for them. --- .../pg_visibility/expected/pg_visibility.out | 17 +++++++++++-- contrib/pg_visibility/sql/pg_visibility.sql | 7 ++++-- contrib/pgstattuple/expected/pgstattuple.out | 25 ++++++++++++++++--- contrib/pgstattuple/pgstatapprox.c | 10 ++++---- contrib/pgstattuple/sql/pgstattuple.sql | 5 ++++ 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/contrib/pg_visibility/expected/pg_visibility.out b/contrib/pg_visibility/expected/pg_visibility.out index 2abc1b5107..ca4b6e186b 100644 --- a/contrib/pg_visibility/expected/pg_visibility.out +++ b/contrib/pg_visibility/expected/pg_visibility.out @@ -102,8 +102,9 @@ ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table select pg_truncate_visibility_map('test_foreign_table'); ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table -- check some of the allowed relkinds -create table regular_table (a int); -insert into regular_table values (1), (2); +create table regular_table (a int, b text); +alter table regular_table alter column b set storage external; +insert into regular_table values (1, repeat('one', 1000)), (2, repeat('two', 1000)); vacuum regular_table; select count(*) > 0 from pg_visibility('regular_table'); ?column? @@ -111,6 +112,12 @@ select count(*) > 0 from pg_visibility('regular_table'); t (1 row) +select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); + ?column? +---------- + t +(1 row) + truncate regular_table; select count(*) > 0 from pg_visibility('regular_table'); ?column? @@ -118,6 +125,12 @@ select count(*) > 0 from pg_visibility('regular_table'); f (1 row) +select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); + ?column? +---------- + f +(1 row) + create materialized view matview_visibility_test as select * from regular_table; vacuum matview_visibility_test; select count(*) > 0 from pg_visibility('matview_visibility_test'); diff --git a/contrib/pg_visibility/sql/pg_visibility.sql b/contrib/pg_visibility/sql/pg_visibility.sql index c78b90521b..f79b54480b 100644 --- a/contrib/pg_visibility/sql/pg_visibility.sql +++ b/contrib/pg_visibility/sql/pg_visibility.sql @@ -68,12 +68,15 @@ CREATE TABLE droppedtest (c int); select pg_truncate_visibility_map('test_foreign_table'); -- check some of the allowed relkinds -create table regular_table (a int); -insert into regular_table values (1), (2); +create table regular_table (a int, b text); +alter table regular_table alter column b set storage external; +insert into regular_table values (1, repeat('one', 1000)), (2, repeat('two', 1000)); vacuum regular_table; select count(*) > 0 from pg_visibility('regular_table'); +select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); truncate regular_table; select count(*) > 0 from pg_visibility('regular_table'); +select count(*) > 0 from pg_visibility((select reltoastrelid from pg_class where relname = 'regular_table')); create materialized view matview_visibility_test as select * from regular_table; vacuum matview_visibility_test; diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out index 9920dbfd40..40f7825ddb 100644 --- a/contrib/pgstattuple/expected/pgstattuple.out +++ b/contrib/pgstattuple/expected/pgstattuple.out @@ -159,7 +159,7 @@ ERROR: "test_partitioned" (partitioned table) is not supported select pgstattuple('test_partitioned_index'); ERROR: "test_partitioned_index" (partitioned index) is not supported select pgstattuple_approx('test_partitioned'); -ERROR: "test_partitioned" is not a table or materialized view +ERROR: "test_partitioned" is not a table, materialized view, or TOAST table select pg_relpages('test_partitioned'); ERROR: "test_partitioned" is not a table, index, materialized view, sequence, or TOAST table select pgstatindex('test_partitioned'); @@ -173,7 +173,7 @@ create view test_view as select 1; select pgstattuple('test_view'); ERROR: "test_view" (view) is not supported select pgstattuple_approx('test_view'); -ERROR: "test_view" is not a table or materialized view +ERROR: "test_view" is not a table, materialized view, or TOAST table select pg_relpages('test_view'); ERROR: "test_view" is not a table, index, materialized view, sequence, or TOAST table select pgstatindex('test_view'); @@ -189,7 +189,7 @@ create foreign table test_foreign_table () server dummy_server; select pgstattuple('test_foreign_table'); ERROR: "test_foreign_table" (foreign table) is not supported select pgstattuple_approx('test_foreign_table'); -ERROR: "test_foreign_table" is not a table or materialized view +ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table select pg_relpages('test_foreign_table'); ERROR: "test_foreign_table" is not a table, index, materialized view, sequence, or TOAST table select pgstatindex('test_foreign_table'); @@ -218,6 +218,25 @@ select pg_relpages('test_partition'); 0 (1 row) +-- toast tables should work +select pgstattuple((select reltoastrelid from pg_class where relname = 'test')); + pgstattuple +--------------------- + (0,0,0,0,0,0,0,0,0) +(1 row) + +select pgstattuple_approx((select reltoastrelid from pg_class where relname = 'test')); + pgstattuple_approx +----------------------- + (0,0,0,0,0,0,0,0,0,0) +(1 row) + +select pg_relpages((select reltoastrelid from pg_class where relname = 'test')); + pg_relpages +------------- + 0 +(1 row) + -- not for the index calls though, of course select pgstatindex('test_partition'); ERROR: relation "test_partition" is not a btree index diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index 96d837485f..dbc0fa11f6 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -278,15 +278,15 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) errmsg("cannot access temporary tables of other sessions"))); /* - * We support only ordinary relations and materialised views, because we - * depend on the visibility map and free space map for our estimates about - * unscanned pages. + * We support only relation kinds with a visibility map and a free space + * map. */ if (!(rel->rd_rel->relkind == RELKIND_RELATION || - rel->rd_rel->relkind == RELKIND_MATVIEW)) + rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_TOASTVALUE)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("\"%s\" is not a table or materialized view", + errmsg("\"%s\" is not a table, materialized view, or TOAST table", RelationGetRelationName(rel)))); if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) diff --git a/contrib/pgstattuple/sql/pgstattuple.sql b/contrib/pgstattuple/sql/pgstattuple.sql index cfa540302d..5111be0e62 100644 --- a/contrib/pgstattuple/sql/pgstattuple.sql +++ b/contrib/pgstattuple/sql/pgstattuple.sql @@ -100,6 +100,11 @@ CREATE EXTENSION pgstattuple; select pgstattuple_approx('test_partition'); select pg_relpages('test_partition'); +-- toast tables should work +select pgstattuple((select reltoastrelid from pg_class where relname = 'test')); +select pgstattuple_approx((select reltoastrelid from pg_class where relname = 'test')); +select pg_relpages((select reltoastrelid from pg_class where relname = 'test')); + -- not for the index calls though, of course select pgstatindex('test_partition'); select pgstatginindex('test_partition'); -- 2.26.1