v9-0005-Add-range-statistics-to-pg_restore_extended_stats.patch
text/x-patch
Filename: v9-0005-Add-range-statistics-to-pg_restore_extended_stats.patch
Type: text/x-patch
Part: 4
Patch
Format: format-patch
Series: patch v9-0005
Subject: Add range statistics to pg_restore_extended_stats expressions.
| File | + | − |
|---|---|---|
| src/backend/statistics/extended_stats_funcs.c | 89 | 7 |
| src/bin/pg_dump/pg_dump.c | 4 | 1 |
| src/test/regress/expected/stats_import.out | 188 | 12 |
| src/test/regress/sql/stats_import.sql | 165 | 7 |
From 9e4b64f8d7ea2089fe001b81c852aa7e11928f15 Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Mon, 9 Feb 2026 14:26:30 -0500
Subject: [PATCH v9 5/5] Add range statistics to pg_restore_extended_stats
expressions.
Add support for the statistics range_length_histogram, range_empty_frac,
and range_bounds_histogram to statistics for expressions. These were
previously not supported because they were not exposed via
pg_stats_ext_exprs.
---
src/backend/statistics/extended_stats_funcs.c | 96 ++++++++-
src/bin/pg_dump/pg_dump.c | 5 +-
src/test/regress/expected/stats_import.out | 200 ++++++++++++++++--
src/test/regress/sql/stats_import.sql | 172 ++++++++++++++-
4 files changed, 446 insertions(+), 27 deletions(-)
diff --git a/src/backend/statistics/extended_stats_funcs.c b/src/backend/statistics/extended_stats_funcs.c
index 229092e852d..e94f297f1a4 100644
--- a/src/backend/statistics/extended_stats_funcs.c
+++ b/src/backend/statistics/extended_stats_funcs.c
@@ -21,6 +21,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_collation_d.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_operator.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_statistic_ext_data.h"
#include "miscadmin.h"
@@ -97,6 +98,9 @@ enum extended_stats_exprs_element
MOST_COMMON_ELEMS_ELEM,
MOST_COMMON_ELEM_FREQS_ELEM,
ELEM_COUNT_HISTOGRAM_ELEM,
+ RANGE_LENGTH_HISTOGRAM_ELEM,
+ RANGE_EMPTY_FRAC_ELEM,
+ RANGE_BOUNDS_HISTOGRAM_ELEM,
NUM_ATTRIBUTE_STATS_ELEMS
};
@@ -115,6 +119,9 @@ static const char *extexprargname[NUM_ATTRIBUTE_STATS_ELEMS] =
"most_common_elems",
"most_common_elem_freqs",
"elem_count_histogram",
+ "range_length_histogram",
+ "range_empty_frac",
+ "range_bounds_histogram"
};
static bool extended_statistics_update(FunctionCallInfo fcinfo);
@@ -1163,10 +1170,10 @@ import_pg_statistic(Relation pgsd, JsonbContainer *cont,
goto pg_statistic_error;
/*
- * There are two arg pairs, MCV+MCF and MCEV+MCEF. Both values must either
- * be found or not be found. Any disagreement is a warning. Once we have
- * ruled out disagreeing pairs, we can use either found flag as a proxy
- * for the other.
+ * There are three arg pairs, MCV+MCF, MCEV+MCEF, and RLE+REF. Both values
+ * must either be found or not found. Any disagreement is a warning. Once
+ * we have ruled out diagreeing pairs, we can use either found flag as a
+ * proxy for the other.
*/
if (found[MOST_COMMON_VALS_ELEM] != found[MOST_COMMON_FREQS_ELEM])
{
@@ -1190,6 +1197,17 @@ import_pg_statistic(Relation pgsd, JsonbContainer *cont,
extexprargname[MOST_COMMON_ELEM_FREQS_ELEM]));
goto pg_statistic_error;
}
+ if (found[RANGE_LENGTH_HISTOGRAM_ELEM] != found[RANGE_EMPTY_FRAC_ELEM])
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse \"%s\": invalid element in expression %d",
+ argname, exprnum),
+ errhint("\"%s\" and \"%s\" must be both either strings or nulls.",
+ extexprargname[RANGE_BOUNDS_HISTOGRAM_ELEM],
+ extexprargname[RANGE_EMPTY_FRAC_ELEM]));
+ goto pg_statistic_error;
+ }
/* This finds the right operators even if atttypid is a domain */
typcache = lookup_type_cache(typid, TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR);
@@ -1400,10 +1418,74 @@ import_pg_statistic(Relation pgsd, JsonbContainer *cont,
}
/*
- * Currently there is no extended stats export of the statistic kinds
- * BOUNDS_HISTOGRAM or RANGE_LENGTH_HISTOGRAM so these cannot be imported.
- * These may be added in the future.
+ * STATISTIC_KIND_BOUNDS_HISTOGRAM
+ *
+ * This stakind appears before STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM even
+ * though it is numerically greater, and all other stakinds appear in
+ * numerical order. We duplicate this quirk for consistency.
*/
+ if (found[RANGE_BOUNDS_HISTOGRAM_ELEM])
+ {
+ Datum stavalues;
+ bool val_ok = false;
+ char *s;
+ Oid rtypid = typid;
+
+ /*
+ * If it's a multirange, step down to the range type, as is done by
+ * multirange_typanalyze().
+ */
+ if (type_is_multirange(typid))
+ rtypid = get_multirange_range(typid);
+
+ s = jbv_string_get_cstr(&val[RANGE_BOUNDS_HISTOGRAM_ELEM]);
+
+ stavalues = array_in_safe(array_in_fn, s, rtypid, typmod, exprnum,
+ extexprargname[RANGE_BOUNDS_HISTOGRAM_ELEM],
+ &val_ok);
+
+ if (val_ok)
+ statatt_set_slot(values, nulls, replaces,
+ STATISTIC_KIND_BOUNDS_HISTOGRAM,
+ InvalidOid, InvalidOid,
+ 0, true, stavalues, false);
+ else
+ goto pg_statistic_error;
+ }
+
+ /* STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM */
+ if (found[RANGE_LENGTH_HISTOGRAM_ELEM])
+ {
+ Datum empty_frac[] = {(Datum) 0};
+ Datum stavalues;
+ Datum stanumbers;
+ bool val_ok = false;
+ char *s;
+
+ if (jbv_to_infunc_datum(&val[RANGE_EMPTY_FRAC_ELEM], float4in, exprnum,
+ extexprargname[RANGE_EMPTY_FRAC_ELEM], &empty_frac[0]))
+ {
+ ArrayType *arry = construct_array_builtin(empty_frac, 1, FLOAT4OID);
+
+ stanumbers = PointerGetDatum(arry);
+ }
+ else
+ goto pg_statistic_error;
+
+ s = jbv_string_get_cstr(&val[RANGE_LENGTH_HISTOGRAM_ELEM]);
+ stavalues = array_in_safe(array_in_fn, s, FLOAT8OID, -1, exprnum,
+ extexprargname[RANGE_LENGTH_HISTOGRAM_ELEM],
+ &val_ok);
+
+ if (val_ok)
+ statatt_set_slot(values, nulls, replaces,
+ STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM,
+ Float8LessOperator, InvalidOid,
+ stanumbers, false, stavalues, false);
+ else
+ goto pg_statistic_error;
+ }
+
pgstup = heap_form_tuple(RelationGetDescr(pgsd), values, nulls);
pgstdat = heap_copy_tuple_as_datum(pgstup, RelationGetDescr(pgsd));
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 293aee02866..229e20859fd 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -18682,7 +18682,10 @@ dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
" 'correlation', ee.correlation::text, "
" 'most_common_elems', ee.most_common_elems::text, "
" 'most_common_elem_freqs', ee.most_common_elem_freqs::text, "
- " 'elem_count_histogram', ee.elem_count_histogram::text "
+ " 'elem_count_histogram', ee.elem_count_histogram::text, "
+ " 'range_length_histogram', ee.range_length_histogram::text, "
+ " 'range_empty_frac', ee.range_empty_frac::text, "
+ " 'range_bounds_histogram', ee.range_bounds_histogram::text "
" )) AS j(obj)"
"WHERE ee.statistics_schemaname = $1 "
"AND ee.statistics_name = $2 ");
diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out
index 3d2fe6b881f..739ae36747a 100644
--- a/src/test/regress/expected/stats_import.out
+++ b/src/test/regress/expected/stats_import.out
@@ -2133,6 +2133,11 @@ most_common_base_freqs | {0.0625,0.0625,0.0625,0.0625}
CREATE STATISTICS stats_import.test_mr_stat
ON name, mrange, ( mrange + '{[10000,10200)}'::int4multirange)
FROM stats_import.test_mr;
+CREATE TABLE stats_import.test_mr_clone ( LIKE stats_import.test_mr )
+ WITH (autovacuum_enabled = false);
+CREATE STATISTICS stats_import.test_mr_stat_clone
+ ON name, mrange, ( mrange + '{[10000,10200)}'::int4multirange)
+ FROM stats_import.test_mr_clone;
-- ok: multirange stats
SELECT pg_catalog.pg_restore_extended_stats(
'schemaname', 'stats_import',
@@ -2156,7 +2161,11 @@ SELECT pg_catalog.pg_restore_extended_stats(
{red,"{[21,23),[25,29),[120,130)}","{[21,23),[25,29),[120,130),[10000,10200)}"}}'::text[],
'most_common_freqs', '{0.3333333333333333,0.3333333333333333,0.3333333333333333}'::double precision[],
'most_common_base_freqs', '{0.1111111111111111,0.1111111111111111,0.1111111111111111}'::double precision[],
- 'exprs', '[{ "avg_width": "60", "null_frac": "0", "n_distinct": "-1" }]'::jsonb);
+ 'exprs', '[{ "avg_width": "60", "null_frac": "0", "n_distinct": "-1",
+ "range_length_histogram": "{10179,10189,10199}",
+ "range_empty_frac": "0",
+ "range_bounds_histogram": "{\"[1,10200)\",\"[11,10200)\",\"[21,10200)\"}"
+ }]'::jsonb);
pg_restore_extended_stats
---------------------------
t
@@ -2193,7 +2202,8 @@ most_common_base_freqs | {0.1111111111111111,0.1111111111111111,0.11111111111111
SELECT e.expr, e.null_frac, e.avg_width, e.n_distinct, e.most_common_vals,
e.most_common_freqs, e.histogram_bounds, e.correlation,
- e.most_common_elems, e.most_common_elem_freqs, e.elem_count_histogram
+ e.most_common_elems, e.most_common_elem_freqs, e.elem_count_histogram,
+ e.range_length_histogram, e.range_empty_frac, e.range_bounds_histogram
FROM pg_stats_ext_exprs AS e
WHERE e.statistics_schemaname = 'stats_import' AND
e.statistics_name = 'test_mr_stat' AND
@@ -2211,6 +2221,9 @@ correlation |
most_common_elems |
most_common_elem_freqs |
elem_count_histogram |
+range_length_histogram | {10179,10189,10199}
+range_empty_frac | 0
+range_bounds_histogram | {"[1,10200)","[11,10200)","[21,10200)"}
-- Incorrect extended stats kind, exprs not supported
SELECT pg_catalog.pg_restore_extended_stats(
@@ -3008,7 +3021,10 @@ CROSS JOIN LATERAL (
'correlation', ee.correlation::text,
'most_common_elems', ee.most_common_elems::text,
'most_common_elem_freqs', ee.most_common_elem_freqs::text,
- 'elem_count_histogram', ee.elem_count_histogram::text)))
+ 'elem_count_histogram', ee.elem_count_histogram::text,
+ 'range_length_histogram', ee.range_length_histogram::text,
+ 'range_empty_frac', ee.range_empty_frac::text,
+ 'range_bounds_histogram', ee.range_bounds_histogram::text)))
FROM pg_stats_ext_exprs AS ee
WHERE ee.statistics_schemaname = e.statistics_schemaname AND
ee.statistics_name = e.statistics_name AND
@@ -3065,7 +3081,10 @@ SELECT o.inherited,
o.histogram_bounds::text AS histogram_bounds,
o.correlation,
o.most_common_elems::text AS most_common_elems,
- o.most_common_elem_freqs, o.elem_count_histogram
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS o
WHERE o.statistics_schemaname = 'stats_import' AND
o.statistics_name = 'test_stat'
@@ -3077,12 +3096,15 @@ SELECT n.inherited,
n.histogram_bounds::text AS histogram_bounds,
n.correlation,
n.most_common_elems::text AS most_common_elems,
- n.most_common_elem_freqs, n.elem_count_histogram
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS n
WHERE n.statistics_schemaname = 'stats_import' AND
n.statistics_name = 'test_stat_clone';
- inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram
------------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------
+ inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram
+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------
(0 rows)
-- Set difference for exprs: new MINUS old.
@@ -3093,7 +3115,10 @@ SELECT n.inherited,
n.histogram_bounds::text AS histogram_bounds,
n.correlation,
n.most_common_elems::text AS most_common_elems,
- n.most_common_elem_freqs, n.elem_count_histogram
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS n
WHERE n.statistics_schemaname = 'stats_import' AND
n.statistics_name = 'test_stat_clone'
@@ -3105,16 +3130,166 @@ SELECT o.inherited,
o.histogram_bounds::text AS histogram_bounds,
o.correlation,
o.most_common_elems::text AS most_common_elems,
- o.most_common_elem_freqs, o.elem_count_histogram
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS o
WHERE o.statistics_schemaname = 'stats_import' AND
o.statistics_name = 'test_stat';
- inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram
------------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------
+ inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram
+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------
+(0 rows)
+
+ANALYZE stats_import.test_mr;
+-- Copy stats from test_mr_stat to test_mr_stat_clone
+SELECT e.statistics_name,
+ pg_catalog.pg_restore_extended_stats(
+ 'schemaname', e.statistics_schemaname::text,
+ 'relname', 'test_mr_clone',
+ 'statistics_schemaname', e.statistics_schemaname::text,
+ 'statistics_name', 'test_mr_stat_clone',
+ 'inherited', e.inherited,
+ 'n_distinct', e.n_distinct,
+ 'dependencies', e.dependencies,
+ 'most_common_vals', e.most_common_vals,
+ 'most_common_freqs', e.most_common_freqs,
+ 'most_common_base_freqs', e.most_common_base_freqs,
+ 'exprs', x.exprs)
+FROM pg_stats_ext AS e
+CROSS JOIN LATERAL (
+ SELECT jsonb_agg(jsonb_strip_nulls(jsonb_build_object(
+ 'null_frac', ee.null_frac::text,
+ 'avg_width', ee.avg_width::text,
+ 'n_distinct', ee.n_distinct::text,
+ 'most_common_vals', ee.most_common_vals::text,
+ 'most_common_freqs', ee.most_common_freqs::text,
+ 'histogram_bounds', ee.histogram_bounds::text,
+ 'correlation', ee.correlation::text,
+ 'most_common_elems', ee.most_common_elems::text,
+ 'most_common_elem_freqs', ee.most_common_elem_freqs::text,
+ 'elem_count_histogram', ee.elem_count_histogram::text,
+ 'range_length_histogram', ee.range_length_histogram::text,
+ 'range_empty_frac', ee.range_empty_frac::text,
+ 'range_bounds_histogram', ee.range_bounds_histogram::text)))
+ FROM pg_stats_ext_exprs AS ee
+ WHERE ee.statistics_schemaname = e.statistics_schemaname AND
+ ee.statistics_name = e.statistics_name AND
+ ee.inherited = e.inherited
+ ) AS x(exprs)
+WHERE e.statistics_schemaname = 'stats_import'
+AND e.statistics_name = 'test_mr_stat';
+ statistics_name | pg_restore_extended_stats
+-----------------+---------------------------
+ test_mr_stat | t
+(1 row)
+
+-- Set difference old MINUS new.
+SELECT o.inherited,
+ o.n_distinct, o.dependencies, o.most_common_vals,
+ o.most_common_freqs, o.most_common_base_freqs
+ FROM pg_stats_ext AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat'
+EXCEPT
+SELECT n.inherited,
+ n.n_distinct, n.dependencies, n.most_common_vals,
+ n.most_common_freqs, n.most_common_base_freqs
+ FROM pg_stats_ext AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone';
+ inherited | n_distinct | dependencies | most_common_vals | most_common_freqs | most_common_base_freqs
+-----------+------------+--------------+------------------+-------------------+------------------------
+(0 rows)
+
+-- Set difference new MINUS old.
+SELECT n.inherited,
+ n.n_distinct, n.dependencies, n.most_common_vals,
+ n.most_common_freqs, n.most_common_base_freqs
+ FROM pg_stats_ext AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone'
+EXCEPT
+SELECT o.inherited,
+ o.n_distinct, o.dependencies, o.most_common_vals,
+ o.most_common_freqs, o.most_common_base_freqs
+ FROM pg_stats_ext AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat';
+ inherited | n_distinct | dependencies | most_common_vals | most_common_freqs | most_common_base_freqs
+-----------+------------+--------------+------------------+-------------------+------------------------
+(0 rows)
+
+-- Set difference for exprs: old MINUS new.
+SELECT o.inherited,
+ o.null_frac, o.avg_width, o.n_distinct,
+ o.most_common_vals::text AS most_common_vals,
+ o.most_common_freqs,
+ o.histogram_bounds::text AS histogram_bounds,
+ o.correlation,
+ o.most_common_elems::text AS most_common_elems,
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat'
+EXCEPT
+SELECT n.inherited,
+ n.null_frac, n.avg_width, n.n_distinct,
+ n.most_common_vals::text AS most_common_vals,
+ n.most_common_freqs,
+ n.histogram_bounds::text AS histogram_bounds,
+ n.correlation,
+ n.most_common_elems::text AS most_common_elems,
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone';
+ inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram
+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------
+(0 rows)
+
+-- Set difference for exprs: new MINUS old.
+SELECT n.inherited,
+ n.null_frac, n.avg_width, n.n_distinct,
+ n.most_common_vals::text AS most_common_vals,
+ n.most_common_freqs,
+ n.histogram_bounds::text AS histogram_bounds,
+ n.correlation,
+ n.most_common_elems::text AS most_common_elems,
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone'
+EXCEPT
+SELECT o.inherited,
+ o.null_frac, o.avg_width, o.n_distinct,
+ o.most_common_vals::text AS most_common_vals,
+ o.most_common_freqs,
+ o.histogram_bounds::text AS histogram_bounds,
+ o.correlation,
+ o.most_common_elems::text AS most_common_elems,
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat';
+ inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram
+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------
(0 rows)
DROP SCHEMA stats_import CASCADE;
-NOTICE: drop cascades to 7 other objects
+NOTICE: drop cascades to 8 other objects
DETAIL: drop cascades to type stats_import.complex_type
drop cascades to table stats_import.test
drop cascades to table stats_import.test_mr
@@ -3122,3 +3297,4 @@ drop cascades to table stats_import.part_parent
drop cascades to sequence stats_import.testseq
drop cascades to view stats_import.testview
drop cascades to table stats_import.test_clone
+drop cascades to table stats_import.test_mr_clone
diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql
index 4ec8565c622..a2d7247e485 100644
--- a/src/test/regress/sql/stats_import.sql
+++ b/src/test/regress/sql/stats_import.sql
@@ -1521,6 +1521,12 @@ CREATE STATISTICS stats_import.test_mr_stat
ON name, mrange, ( mrange + '{[10000,10200)}'::int4multirange)
FROM stats_import.test_mr;
+CREATE TABLE stats_import.test_mr_clone ( LIKE stats_import.test_mr )
+ WITH (autovacuum_enabled = false);
+CREATE STATISTICS stats_import.test_mr_stat_clone
+ ON name, mrange, ( mrange + '{[10000,10200)}'::int4multirange)
+ FROM stats_import.test_mr_clone;
+
-- ok: multirange stats
SELECT pg_catalog.pg_restore_extended_stats(
'schemaname', 'stats_import',
@@ -1544,7 +1550,11 @@ SELECT pg_catalog.pg_restore_extended_stats(
{red,"{[21,23),[25,29),[120,130)}","{[21,23),[25,29),[120,130),[10000,10200)}"}}'::text[],
'most_common_freqs', '{0.3333333333333333,0.3333333333333333,0.3333333333333333}'::double precision[],
'most_common_base_freqs', '{0.1111111111111111,0.1111111111111111,0.1111111111111111}'::double precision[],
- 'exprs', '[{ "avg_width": "60", "null_frac": "0", "n_distinct": "-1" }]'::jsonb);
+ 'exprs', '[{ "avg_width": "60", "null_frac": "0", "n_distinct": "-1",
+ "range_length_histogram": "{10179,10189,10199}",
+ "range_empty_frac": "0",
+ "range_bounds_histogram": "{\"[1,10200)\",\"[11,10200)\",\"[21,10200)\"}"
+ }]'::jsonb);
SELECT replace(e.n_distinct, '}, ', E'},\n') AS n_distinct,
replace(e.dependencies, '}, ', E'},\n') AS dependencies,
@@ -1559,7 +1569,8 @@ WHERE e.statistics_schemaname = 'stats_import' AND
SELECT e.expr, e.null_frac, e.avg_width, e.n_distinct, e.most_common_vals,
e.most_common_freqs, e.histogram_bounds, e.correlation,
- e.most_common_elems, e.most_common_elem_freqs, e.elem_count_histogram
+ e.most_common_elems, e.most_common_elem_freqs, e.elem_count_histogram,
+ e.range_length_histogram, e.range_empty_frac, e.range_bounds_histogram
FROM pg_stats_ext_exprs AS e
WHERE e.statistics_schemaname = 'stats_import' AND
e.statistics_name = 'test_mr_stat' AND
@@ -2068,7 +2079,10 @@ CROSS JOIN LATERAL (
'correlation', ee.correlation::text,
'most_common_elems', ee.most_common_elems::text,
'most_common_elem_freqs', ee.most_common_elem_freqs::text,
- 'elem_count_histogram', ee.elem_count_histogram::text)))
+ 'elem_count_histogram', ee.elem_count_histogram::text,
+ 'range_length_histogram', ee.range_length_histogram::text,
+ 'range_empty_frac', ee.range_empty_frac::text,
+ 'range_bounds_histogram', ee.range_bounds_histogram::text)))
FROM pg_stats_ext_exprs AS ee
WHERE ee.statistics_schemaname = e.statistics_schemaname AND
ee.statistics_name = e.statistics_name AND
@@ -2114,7 +2128,10 @@ SELECT o.inherited,
o.histogram_bounds::text AS histogram_bounds,
o.correlation,
o.most_common_elems::text AS most_common_elems,
- o.most_common_elem_freqs, o.elem_count_histogram
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS o
WHERE o.statistics_schemaname = 'stats_import' AND
o.statistics_name = 'test_stat'
@@ -2126,7 +2143,10 @@ SELECT n.inherited,
n.histogram_bounds::text AS histogram_bounds,
n.correlation,
n.most_common_elems::text AS most_common_elems,
- n.most_common_elem_freqs, n.elem_count_histogram
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS n
WHERE n.statistics_schemaname = 'stats_import' AND
n.statistics_name = 'test_stat_clone';
@@ -2139,7 +2159,10 @@ SELECT n.inherited,
n.histogram_bounds::text AS histogram_bounds,
n.correlation,
n.most_common_elems::text AS most_common_elems,
- n.most_common_elem_freqs, n.elem_count_histogram
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS n
WHERE n.statistics_schemaname = 'stats_import' AND
n.statistics_name = 'test_stat_clone'
@@ -2151,9 +2174,144 @@ SELECT o.inherited,
o.histogram_bounds::text AS histogram_bounds,
o.correlation,
o.most_common_elems::text AS most_common_elems,
- o.most_common_elem_freqs, o.elem_count_histogram
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
FROM pg_stats_ext_exprs AS o
WHERE o.statistics_schemaname = 'stats_import' AND
o.statistics_name = 'test_stat';
+ANALYZE stats_import.test_mr;
+
+-- Copy stats from test_mr_stat to test_mr_stat_clone
+SELECT e.statistics_name,
+ pg_catalog.pg_restore_extended_stats(
+ 'schemaname', e.statistics_schemaname::text,
+ 'relname', 'test_mr_clone',
+ 'statistics_schemaname', e.statistics_schemaname::text,
+ 'statistics_name', 'test_mr_stat_clone',
+ 'inherited', e.inherited,
+ 'n_distinct', e.n_distinct,
+ 'dependencies', e.dependencies,
+ 'most_common_vals', e.most_common_vals,
+ 'most_common_freqs', e.most_common_freqs,
+ 'most_common_base_freqs', e.most_common_base_freqs,
+ 'exprs', x.exprs)
+FROM pg_stats_ext AS e
+CROSS JOIN LATERAL (
+ SELECT jsonb_agg(jsonb_strip_nulls(jsonb_build_object(
+ 'null_frac', ee.null_frac::text,
+ 'avg_width', ee.avg_width::text,
+ 'n_distinct', ee.n_distinct::text,
+ 'most_common_vals', ee.most_common_vals::text,
+ 'most_common_freqs', ee.most_common_freqs::text,
+ 'histogram_bounds', ee.histogram_bounds::text,
+ 'correlation', ee.correlation::text,
+ 'most_common_elems', ee.most_common_elems::text,
+ 'most_common_elem_freqs', ee.most_common_elem_freqs::text,
+ 'elem_count_histogram', ee.elem_count_histogram::text,
+ 'range_length_histogram', ee.range_length_histogram::text,
+ 'range_empty_frac', ee.range_empty_frac::text,
+ 'range_bounds_histogram', ee.range_bounds_histogram::text)))
+ FROM pg_stats_ext_exprs AS ee
+ WHERE ee.statistics_schemaname = e.statistics_schemaname AND
+ ee.statistics_name = e.statistics_name AND
+ ee.inherited = e.inherited
+ ) AS x(exprs)
+WHERE e.statistics_schemaname = 'stats_import'
+AND e.statistics_name = 'test_mr_stat';
+
+-- Set difference old MINUS new.
+SELECT o.inherited,
+ o.n_distinct, o.dependencies, o.most_common_vals,
+ o.most_common_freqs, o.most_common_base_freqs
+ FROM pg_stats_ext AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat'
+EXCEPT
+SELECT n.inherited,
+ n.n_distinct, n.dependencies, n.most_common_vals,
+ n.most_common_freqs, n.most_common_base_freqs
+ FROM pg_stats_ext AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone';
+-- Set difference new MINUS old.
+SELECT n.inherited,
+ n.n_distinct, n.dependencies, n.most_common_vals,
+ n.most_common_freqs, n.most_common_base_freqs
+ FROM pg_stats_ext AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone'
+EXCEPT
+SELECT o.inherited,
+ o.n_distinct, o.dependencies, o.most_common_vals,
+ o.most_common_freqs, o.most_common_base_freqs
+ FROM pg_stats_ext AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat';
+
+-- Set difference for exprs: old MINUS new.
+SELECT o.inherited,
+ o.null_frac, o.avg_width, o.n_distinct,
+ o.most_common_vals::text AS most_common_vals,
+ o.most_common_freqs,
+ o.histogram_bounds::text AS histogram_bounds,
+ o.correlation,
+ o.most_common_elems::text AS most_common_elems,
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat'
+EXCEPT
+SELECT n.inherited,
+ n.null_frac, n.avg_width, n.n_distinct,
+ n.most_common_vals::text AS most_common_vals,
+ n.most_common_freqs,
+ n.histogram_bounds::text AS histogram_bounds,
+ n.correlation,
+ n.most_common_elems::text AS most_common_elems,
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone';
+
+-- Set difference for exprs: new MINUS old.
+SELECT n.inherited,
+ n.null_frac, n.avg_width, n.n_distinct,
+ n.most_common_vals::text AS most_common_vals,
+ n.most_common_freqs,
+ n.histogram_bounds::text AS histogram_bounds,
+ n.correlation,
+ n.most_common_elems::text AS most_common_elems,
+ n.most_common_elem_freqs, n.elem_count_histogram,
+ n.range_length_histogram::text AS range_length_histogram,
+ n.range_empty_frac,
+ n.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS n
+ WHERE n.statistics_schemaname = 'stats_import' AND
+ n.statistics_name = 'test_mr_stat_clone'
+EXCEPT
+SELECT o.inherited,
+ o.null_frac, o.avg_width, o.n_distinct,
+ o.most_common_vals::text AS most_common_vals,
+ o.most_common_freqs,
+ o.histogram_bounds::text AS histogram_bounds,
+ o.correlation,
+ o.most_common_elems::text AS most_common_elems,
+ o.most_common_elem_freqs, o.elem_count_histogram,
+ o.range_length_histogram::text AS range_length_histogram,
+ o.range_empty_frac,
+ o.range_bounds_histogram::text AS range_bounds_histogram
+ FROM pg_stats_ext_exprs AS o
+ WHERE o.statistics_schemaname = 'stats_import' AND
+ o.statistics_name = 'test_mr_stat';
+
+
DROP SCHEMA stats_import CASCADE;
--
2.53.0