Skip to content

Commit 8c5cdb7

Browse files
committed
Tighten up relation kind checks for extended statistics
We were accepting creation of extended statistics only for regular tables, but they can usefully be created for foreign tables, partitioned tables, and materialized views, too. Allow those cases. While at it, make sure all the rejected cases throw a consistent error message, and add regression tests for the whole thing. Author: David Rowley, Álvaro Herrera Discussion: https://postgr.es/m/CAKJS1f-BmGo410bh5RSPZUvOO0LhmHL2NYmdrC_Jm8pk_FfyCA@mail.gmail.com
1 parent 76799fc commit 8c5cdb7

File tree

5 files changed

+92
-7
lines changed

5 files changed

+92
-7
lines changed

doc/src/sgml/ref/create_statistics.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ CREATE STATISTICS [ IF NOT EXISTS ] <replaceable class="PARAMETER">statistics_na
3434

3535
<para>
3636
<command>CREATE STATISTICS</command> will create a new extended statistics
37-
object on the specified table.
37+
object on the specified table, foreign table or materialized view.
3838
The statistics will be created in the current database and
3939
will be owned by the user issuing the command.
4040
</para>

src/backend/commands/statscmds.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,16 @@ CreateStatistics(CreateStatsStmt *stmt)
102102
* take only ShareUpdateExclusiveLock on relation, conflicting with
103103
* ANALYZE and other DDL that sets statistical information.
104104
*/
105-
rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock);
105+
rel = relation_openrv(stmt->relation, ShareUpdateExclusiveLock);
106106
relid = RelationGetRelid(rel);
107107

108108
if (rel->rd_rel->relkind != RELKIND_RELATION &&
109-
rel->rd_rel->relkind != RELKIND_MATVIEW)
109+
rel->rd_rel->relkind != RELKIND_MATVIEW &&
110+
rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
111+
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
110112
ereport(ERROR,
111113
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
112-
errmsg("relation \"%s\" is not a table or materialized view",
114+
errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
113115
RelationGetRelationName(rel))));
114116

115117
/*
@@ -248,7 +250,7 @@ CreateStatistics(CreateStatsStmt *stmt)
248250
CatalogTupleInsert(statrel, htup);
249251
statoid = HeapTupleGetOid(htup);
250252
heap_freetuple(htup);
251-
heap_close(statrel, RowExclusiveLock);
253+
relation_close(statrel, RowExclusiveLock);
252254

253255
/*
254256
* Invalidate relcache so that others see the new statistics.

src/bin/pg_dump/pg_dump.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6676,9 +6676,14 @@ getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables)
66766676
{
66776677
TableInfo *tbinfo = &tblinfo[i];
66786678

6679-
/* Only plain tables and materialized views can have extended statistics. */
6679+
/*
6680+
* Only plain tables, materialized views, foreign tables and
6681+
* partitioned tables can have extended statistics.
6682+
*/
66806683
if (tbinfo->relkind != RELKIND_RELATION &&
6681-
tbinfo->relkind != RELKIND_MATVIEW)
6684+
tbinfo->relkind != RELKIND_MATVIEW &&
6685+
tbinfo->relkind != RELKIND_FOREIGN_TABLE &&
6686+
tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
66826687
continue;
66836688

66846689
/*

src/test/regress/expected/stats_ext.out

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,46 @@ ANALYZE ab1 (a);
4747
WARNING: extended statistics "public.ab1_a_b_stats" could not be collected for relation public.ab1
4848
ANALYZE ab1;
4949
DROP TABLE ab1;
50+
-- Verify supported object types for extended statistics
51+
CREATE schema tststats;
52+
CREATE TABLE tststats.t (a int, b int, c text);
53+
CREATE INDEX ti ON tststats.t (a, b);
54+
CREATE SEQUENCE tststats.s;
55+
CREATE VIEW tststats.v AS SELECT * FROM tststats.t;
56+
CREATE MATERIALIZED VIEW tststats.mv AS SELECT * FROM tststats.t;
57+
CREATE TYPE tststats.ty AS (a int, b int, c text);
58+
CREATE FOREIGN DATA WRAPPER extstats_dummy_fdw;
59+
CREATE SERVER extstats_dummy_srv FOREIGN DATA WRAPPER extstats_dummy_fdw;
60+
CREATE FOREIGN TABLE tststats.f (a int, b int, c text) SERVER extstats_dummy_srv;
61+
CREATE TABLE tststats.pt (a int, b int, c text) PARTITION BY RANGE (a, b);
62+
CREATE TABLE tststats.pt1 PARTITION OF tststats.pt FOR VALUES FROM (-10, -10) TO (10, 10);
63+
CREATE STATISTICS tststats.s1 ON (a, b) FROM tststats.t;
64+
CREATE STATISTICS tststats.s2 ON (a, b) FROM tststats.ti;
65+
ERROR: relation "ti" is not a table, foreign table, or materialized view
66+
CREATE STATISTICS tststats.s3 ON (a, b) FROM tststats.s;
67+
ERROR: relation "s" is not a table, foreign table, or materialized view
68+
CREATE STATISTICS tststats.s4 ON (a, b) FROM tststats.v;
69+
ERROR: relation "v" is not a table, foreign table, or materialized view
70+
CREATE STATISTICS tststats.s5 ON (a, b) FROM tststats.mv;
71+
CREATE STATISTICS tststats.s6 ON (a, b) FROM tststats.ty;
72+
ERROR: relation "ty" is not a table, foreign table, or materialized view
73+
CREATE STATISTICS tststats.s7 ON (a, b) FROM tststats.f;
74+
CREATE STATISTICS tststats.s8 ON (a, b) FROM tststats.pt;
75+
CREATE STATISTICS tststats.s9 ON (a, b) FROM tststats.pt1;
76+
DO $$
77+
DECLARE
78+
relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass;
79+
BEGIN
80+
EXECUTE 'CREATE STATISTICS tststats.s10 ON (a, b) FROM ' || relname;
81+
EXCEPTION WHEN wrong_object_type THEN
82+
RAISE NOTICE 'stats on toast table not created';
83+
END;
84+
$$;
85+
NOTICE: stats on toast table not created
86+
SET client_min_messages TO warning;
87+
DROP SCHEMA tststats CASCADE;
88+
DROP FOREIGN DATA WRAPPER extstats_dummy_fdw CASCADE;
89+
RESET client_min_messages;
5090
-- n-distinct tests
5191
CREATE TABLE ndistinct (
5292
filler1 TEXT,

src/test/regress/sql/stats_ext.sql

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,44 @@ ANALYZE ab1 (a);
4040
ANALYZE ab1;
4141
DROP TABLE ab1;
4242

43+
-- Verify supported object types for extended statistics
44+
CREATE schema tststats;
45+
46+
CREATE TABLE tststats.t (a int, b int, c text);
47+
CREATE INDEX ti ON tststats.t (a, b);
48+
CREATE SEQUENCE tststats.s;
49+
CREATE VIEW tststats.v AS SELECT * FROM tststats.t;
50+
CREATE MATERIALIZED VIEW tststats.mv AS SELECT * FROM tststats.t;
51+
CREATE TYPE tststats.ty AS (a int, b int, c text);
52+
CREATE FOREIGN DATA WRAPPER extstats_dummy_fdw;
53+
CREATE SERVER extstats_dummy_srv FOREIGN DATA WRAPPER extstats_dummy_fdw;
54+
CREATE FOREIGN TABLE tststats.f (a int, b int, c text) SERVER extstats_dummy_srv;
55+
CREATE TABLE tststats.pt (a int, b int, c text) PARTITION BY RANGE (a, b);
56+
CREATE TABLE tststats.pt1 PARTITION OF tststats.pt FOR VALUES FROM (-10, -10) TO (10, 10);
57+
58+
CREATE STATISTICS tststats.s1 ON (a, b) FROM tststats.t;
59+
CREATE STATISTICS tststats.s2 ON (a, b) FROM tststats.ti;
60+
CREATE STATISTICS tststats.s3 ON (a, b) FROM tststats.s;
61+
CREATE STATISTICS tststats.s4 ON (a, b) FROM tststats.v;
62+
CREATE STATISTICS tststats.s5 ON (a, b) FROM tststats.mv;
63+
CREATE STATISTICS tststats.s6 ON (a, b) FROM tststats.ty;
64+
CREATE STATISTICS tststats.s7 ON (a, b) FROM tststats.f;
65+
CREATE STATISTICS tststats.s8 ON (a, b) FROM tststats.pt;
66+
CREATE STATISTICS tststats.s9 ON (a, b) FROM tststats.pt1;
67+
DO $$
68+
DECLARE
69+
relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass;
70+
BEGIN
71+
EXECUTE 'CREATE STATISTICS tststats.s10 ON (a, b) FROM ' || relname;
72+
EXCEPTION WHEN wrong_object_type THEN
73+
RAISE NOTICE 'stats on toast table not created';
74+
END;
75+
$$;
76+
77+
SET client_min_messages TO warning;
78+
DROP SCHEMA tststats CASCADE;
79+
DROP FOREIGN DATA WRAPPER extstats_dummy_fdw CASCADE;
80+
RESET client_min_messages;
4381

4482
-- n-distinct tests
4583
CREATE TABLE ndistinct (

0 commit comments

Comments
 (0)