diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml
index 8b4abef8c68..e5fe423fc61 100644
--- a/doc/src/sgml/system-views.sgml
+++ b/doc/src/sgml/system-views.sgml
@@ -5045,6 +5045,45 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
non-null elements. (Null for scalar types.)
+
+
+
+ range_length_histogram anyarray
+
+
+ A histogram of the lengths of non-empty and non-null range values of an
+ expression. (Null for non-range types.)
+
+
+ This histogram is calculated using the subtype_diff
+ range function regardless of whether range bounds are inclusive.
+
+
+
+
+
+ range_empty_frac float4
+
+
+ Fraction of expression entries whose values are empty ranges.
+ (Null for non-range types.)
+
+
+
+
+
+ range_bounds_histogram anyarray
+
+
+ A histogram of lower and upper bounds of non-empty and non-null range
+ values. (Null for non-range types.)
+
+
+ These two histograms are represented as a single array of ranges, whose
+ lower bounds represent the histogram of lower bounds, and upper bounds
+ represent the histogram of upper bounds.
+
+
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 7553f31fef0..1ea8f1faa9e 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -363,7 +363,28 @@ CREATE VIEW pg_stats_ext_exprs WITH (security_barrier) AS
WHEN (stat.a).stakind3 = 5 THEN (stat.a).stanumbers3
WHEN (stat.a).stakind4 = 5 THEN (stat.a).stanumbers4
WHEN (stat.a).stakind5 = 5 THEN (stat.a).stanumbers5
- END) AS elem_count_histogram
+ END) AS elem_count_histogram,
+ (CASE
+ WHEN (stat.a).stakind1 = 6 THEN (stat.a).stavalues1
+ WHEN (stat.a).stakind2 = 6 THEN (stat.a).stavalues2
+ WHEN (stat.a).stakind3 = 6 THEN (stat.a).stavalues3
+ WHEN (stat.a).stakind4 = 6 THEN (stat.a).stavalues4
+ WHEN (stat.a).stakind5 = 6 THEN (stat.a).stavalues5
+ END) AS range_length_histogram,
+ (CASE
+ WHEN (stat.a).stakind1 = 6 THEN (stat.a).stanumbers1[1]
+ WHEN (stat.a).stakind2 = 6 THEN (stat.a).stanumbers2[1]
+ WHEN (stat.a).stakind3 = 6 THEN (stat.a).stanumbers3[1]
+ WHEN (stat.a).stakind4 = 6 THEN (stat.a).stanumbers4[1]
+ WHEN (stat.a).stakind5 = 6 THEN (stat.a).stanumbers5[1]
+ END) AS range_empty_frac,
+ (CASE
+ WHEN (stat.a).stakind1 = 7 THEN (stat.a).stavalues1
+ WHEN (stat.a).stakind2 = 7 THEN (stat.a).stavalues2
+ WHEN (stat.a).stakind3 = 7 THEN (stat.a).stavalues3
+ WHEN (stat.a).stakind4 = 7 THEN (stat.a).stavalues4
+ WHEN (stat.a).stakind5 = 7 THEN (stat.a).stavalues5
+ END) AS range_bounds_histogram
FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid)
LEFT JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid)
LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace)
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index a09d8a6c645..a910b3d04e6 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202602051
+#define CATALOG_VERSION_NO 202602101
#endif
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f4ee2bd7459..f9bc213e5a1 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2696,7 +2696,31 @@ pg_stats_ext_exprs| SELECT cn.nspname AS schemaname,
WHEN ((stat.a).stakind4 = 5) THEN (stat.a).stanumbers4
WHEN ((stat.a).stakind5 = 5) THEN (stat.a).stanumbers5
ELSE NULL::real[]
- END AS elem_count_histogram
+ END AS elem_count_histogram,
+ CASE
+ WHEN ((stat.a).stakind1 = 6) THEN (stat.a).stavalues1
+ WHEN ((stat.a).stakind2 = 6) THEN (stat.a).stavalues2
+ WHEN ((stat.a).stakind3 = 6) THEN (stat.a).stavalues3
+ WHEN ((stat.a).stakind4 = 6) THEN (stat.a).stavalues4
+ WHEN ((stat.a).stakind5 = 6) THEN (stat.a).stavalues5
+ ELSE NULL::anyarray
+ END AS range_length_histogram,
+ CASE
+ WHEN ((stat.a).stakind1 = 6) THEN (stat.a).stanumbers1[1]
+ WHEN ((stat.a).stakind2 = 6) THEN (stat.a).stanumbers2[1]
+ WHEN ((stat.a).stakind3 = 6) THEN (stat.a).stanumbers3[1]
+ WHEN ((stat.a).stakind4 = 6) THEN (stat.a).stanumbers4[1]
+ WHEN ((stat.a).stakind5 = 6) THEN (stat.a).stanumbers5[1]
+ ELSE NULL::real
+ END AS range_empty_frac,
+ CASE
+ WHEN ((stat.a).stakind1 = 7) THEN (stat.a).stavalues1
+ WHEN ((stat.a).stakind2 = 7) THEN (stat.a).stavalues2
+ WHEN ((stat.a).stakind3 = 7) THEN (stat.a).stavalues3
+ WHEN ((stat.a).stakind4 = 7) THEN (stat.a).stavalues4
+ WHEN ((stat.a).stakind5 = 7) THEN (stat.a).stavalues5
+ ELSE NULL::anyarray
+ END AS range_bounds_histogram
FROM (((((pg_statistic_ext s
JOIN pg_class c ON ((c.oid = s.stxrelid)))
LEFT JOIN pg_statistic_ext_data sd ON ((s.oid = sd.stxoid)))
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index b2a06579135..cb8856ac50f 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -3628,3 +3628,30 @@ SELECT * FROM check_estimated_rows('SELECT * FROM sb_2 WHERE numeric_lt(y, 1.0)'
-- Tidy up
DROP TABLE sb_1, sb_2 CASCADE;
+-- Check statistics generated for range type and expressions.
+CREATE TABLE stats_ext_tbl_range(name text, irange int4range);
+INSERT INTO stats_ext_tbl_range VALUES
+ ('red', '[1,7)'::int4range),
+ ('blue', '[2,8]'::int4range),
+ ('green', '[3,9)'::int4range);
+CREATE STATISTICS stats_ext_range (mcv)
+ ON irange, (irange + '[4,10)'::int4range)
+ FROM stats_ext_tbl_range;
+ANALYZE stats_ext_tbl_range;
+SELECT attnames, most_common_vals
+ FROM pg_stats_ext
+ WHERE statistics_name = 'stats_ext_range';
+ attnames | most_common_vals
+----------+------------------------------------------------------------
+ {irange} | {{"[1,7)","[1,10)"},{"[2,9)","[2,10)"},{"[3,9)","[3,10)"}}
+(1 row)
+
+SELECT range_length_histogram, range_empty_frac, range_bounds_histogram
+ FROM pg_stats_ext_exprs
+ WHERE statistics_name = 'stats_ext_range';
+ range_length_histogram | range_empty_frac | range_bounds_histogram
+------------------------+------------------+------------------------------
+ {7,8,9} | 0 | {"[1,10)","[2,10)","[3,10)"}
+(1 row)
+
+DROP TABLE stats_ext_tbl_range;
diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql
index 76ee9d29c08..9dcce3440c8 100644
--- a/src/test/regress/sql/stats_ext.sql
+++ b/src/test/regress/sql/stats_ext.sql
@@ -1866,3 +1866,21 @@ SELECT * FROM check_estimated_rows('SELECT * FROM sb_2 WHERE numeric_lt(y, 1.0)'
-- Tidy up
DROP TABLE sb_1, sb_2 CASCADE;
+
+-- Check statistics generated for range type and expressions.
+CREATE TABLE stats_ext_tbl_range(name text, irange int4range);
+INSERT INTO stats_ext_tbl_range VALUES
+ ('red', '[1,7)'::int4range),
+ ('blue', '[2,8]'::int4range),
+ ('green', '[3,9)'::int4range);
+CREATE STATISTICS stats_ext_range (mcv)
+ ON irange, (irange + '[4,10)'::int4range)
+ FROM stats_ext_tbl_range;
+ANALYZE stats_ext_tbl_range;
+SELECT attnames, most_common_vals
+ FROM pg_stats_ext
+ WHERE statistics_name = 'stats_ext_range';
+SELECT range_length_histogram, range_empty_frac, range_bounds_histogram
+ FROM pg_stats_ext_exprs
+ WHERE statistics_name = 'stats_ext_range';
+DROP TABLE stats_ext_tbl_range;