diff --git a/doc/src/sgml/ref/create_statistics.sgml b/doc/src/sgml/ref/create_statistics.sgml index dbe28d6685..edbcf5840b 100644 --- a/doc/src/sgml/ref/create_statistics.sgml +++ b/doc/src/sgml/ref/create_statistics.sgml @@ -34,7 +34,7 @@ CREATE STATISTICS [ IF NOT EXISTS ] statistics_na CREATE STATISTICS will create a new extended statistics - object on the specified table. + object on the specified table, foreign table or materialized view. The statistics will be created in the current database and will be owned by the user issuing the command. diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 46abadcc81..2dd32d9318 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -102,14 +102,16 @@ CreateStatistics(CreateStatsStmt *stmt) * take only ShareUpdateExclusiveLock on relation, conflicting with * ANALYZE and other DDL that sets statistical information. */ - rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock); + rel = relation_openrv(stmt->relation, ShareUpdateExclusiveLock); relid = RelationGetRelid(rel); if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_MATVIEW) + rel->rd_rel->relkind != RELKIND_MATVIEW && + rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("relation \"%s\" is not a table or materialized view", + errmsg("relation \"%s\" is not a table, foreign table, or materialized view", RelationGetRelationName(rel)))); /* @@ -248,7 +250,7 @@ CreateStatistics(CreateStatsStmt *stmt) CatalogTupleInsert(statrel, htup); statoid = HeapTupleGetOid(htup); heap_freetuple(htup); - heap_close(statrel, RowExclusiveLock); + relation_close(statrel, RowExclusiveLock); /* * Invalidate relcache so that others see the new statistics. diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 22b5f784dc..8824018786 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6676,9 +6676,14 @@ getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables) { TableInfo *tbinfo = &tblinfo[i]; - /* Only plain tables and materialized views can have extended statistics. */ + /* + * Only plain tables, materialized views, foreign tables and + * partitioned tables can have extended statistics. + */ if (tbinfo->relkind != RELKIND_RELATION && - tbinfo->relkind != RELKIND_MATVIEW) + tbinfo->relkind != RELKIND_MATVIEW && + tbinfo->relkind != RELKIND_FOREIGN_TABLE && + tbinfo->relkind != RELKIND_PARTITIONED_TABLE) continue; /* diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 6a3345548a..658d285769 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -47,6 +47,46 @@ ANALYZE ab1 (a); WARNING: extended statistics "public.ab1_a_b_stats" could not be collected for relation public.ab1 ANALYZE ab1; DROP TABLE ab1; +-- Verify supported object types for extended statistics +CREATE schema tststats; +CREATE TABLE tststats.t (a int, b int, c text); +CREATE INDEX ti ON tststats.t (a, b); +CREATE SEQUENCE tststats.s; +CREATE VIEW tststats.v AS SELECT * FROM tststats.t; +CREATE MATERIALIZED VIEW tststats.mv AS SELECT * FROM tststats.t; +CREATE TYPE tststats.ty AS (a int, b int, c text); +CREATE FOREIGN DATA WRAPPER extstats_dummy_fdw; +CREATE SERVER extstats_dummy_srv FOREIGN DATA WRAPPER extstats_dummy_fdw; +CREATE FOREIGN TABLE tststats.f (a int, b int, c text) SERVER extstats_dummy_srv; +CREATE TABLE tststats.pt (a int, b int, c text) PARTITION BY RANGE (a, b); +CREATE TABLE tststats.pt1 PARTITION OF tststats.pt FOR VALUES FROM (-10, -10) TO (10, 10); +CREATE STATISTICS tststats.s1 ON (a, b) FROM tststats.t; +CREATE STATISTICS tststats.s2 ON (a, b) FROM tststats.ti; +ERROR: relation "ti" is not a table, foreign table, or materialized view +CREATE STATISTICS tststats.s3 ON (a, b) FROM tststats.s; +ERROR: relation "s" is not a table, foreign table, or materialized view +CREATE STATISTICS tststats.s4 ON (a, b) FROM tststats.v; +ERROR: relation "v" is not a table, foreign table, or materialized view +CREATE STATISTICS tststats.s5 ON (a, b) FROM tststats.mv; +CREATE STATISTICS tststats.s6 ON (a, b) FROM tststats.ty; +ERROR: relation "ty" is not a table, foreign table, or materialized view +CREATE STATISTICS tststats.s7 ON (a, b) FROM tststats.f; +CREATE STATISTICS tststats.s8 ON (a, b) FROM tststats.pt; +CREATE STATISTICS tststats.s9 ON (a, b) FROM tststats.pt1; +DO $$ +DECLARE + relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass; +BEGIN + EXECUTE 'CREATE STATISTICS tststats.s10 ON (a, b) FROM ' || relname; +EXCEPTION WHEN wrong_object_type THEN + RAISE NOTICE 'stats on toast table not created'; +END; +$$; +NOTICE: stats on toast table not created +SET client_min_messages TO warning; +DROP SCHEMA tststats CASCADE; +DROP FOREIGN DATA WRAPPER extstats_dummy_fdw CASCADE; +RESET client_min_messages; -- n-distinct tests CREATE TABLE ndistinct ( filler1 TEXT, diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index ebb6a78383..3c7e0684d3 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -40,6 +40,44 @@ ANALYZE ab1 (a); ANALYZE ab1; DROP TABLE ab1; +-- Verify supported object types for extended statistics +CREATE schema tststats; + +CREATE TABLE tststats.t (a int, b int, c text); +CREATE INDEX ti ON tststats.t (a, b); +CREATE SEQUENCE tststats.s; +CREATE VIEW tststats.v AS SELECT * FROM tststats.t; +CREATE MATERIALIZED VIEW tststats.mv AS SELECT * FROM tststats.t; +CREATE TYPE tststats.ty AS (a int, b int, c text); +CREATE FOREIGN DATA WRAPPER extstats_dummy_fdw; +CREATE SERVER extstats_dummy_srv FOREIGN DATA WRAPPER extstats_dummy_fdw; +CREATE FOREIGN TABLE tststats.f (a int, b int, c text) SERVER extstats_dummy_srv; +CREATE TABLE tststats.pt (a int, b int, c text) PARTITION BY RANGE (a, b); +CREATE TABLE tststats.pt1 PARTITION OF tststats.pt FOR VALUES FROM (-10, -10) TO (10, 10); + +CREATE STATISTICS tststats.s1 ON (a, b) FROM tststats.t; +CREATE STATISTICS tststats.s2 ON (a, b) FROM tststats.ti; +CREATE STATISTICS tststats.s3 ON (a, b) FROM tststats.s; +CREATE STATISTICS tststats.s4 ON (a, b) FROM tststats.v; +CREATE STATISTICS tststats.s5 ON (a, b) FROM tststats.mv; +CREATE STATISTICS tststats.s6 ON (a, b) FROM tststats.ty; +CREATE STATISTICS tststats.s7 ON (a, b) FROM tststats.f; +CREATE STATISTICS tststats.s8 ON (a, b) FROM tststats.pt; +CREATE STATISTICS tststats.s9 ON (a, b) FROM tststats.pt1; +DO $$ +DECLARE + relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass; +BEGIN + EXECUTE 'CREATE STATISTICS tststats.s10 ON (a, b) FROM ' || relname; +EXCEPTION WHEN wrong_object_type THEN + RAISE NOTICE 'stats on toast table not created'; +END; +$$; + +SET client_min_messages TO warning; +DROP SCHEMA tststats CASCADE; +DROP FOREIGN DATA WRAPPER extstats_dummy_fdw CASCADE; +RESET client_min_messages; -- n-distinct tests CREATE TABLE ndistinct (