From f6e4ec0a705b180f29e4910dd5297b815a260eec Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 16 Jun 2026 14:47:20 +0900 Subject: [PATCH] Reject oversized MCV lists in pg_restore_extended_stats() import_mcv(), called by pg_restore_extended_stats(), allowed a list of MCV items to be larger than the maximum supported when the stats are loaded back in statext_mcv_deserialize() (STATS_MCVLIST_MAX_ITEMS or 10k items). A follow-up attempt at loading them would cause a failure, statext_mcv_deserialize() blocking any attempts. Attempts at restoring MCV lists too long are now rejected, generating a WARNING like other inconsistent inputs. Author: Ewan Young Discussion: https://postgr.es/m/CAON2xHORd2ESXm1KcVeeZ0Kd_aJk4dL4M2WLtzVDM4puaZ-20w@mail.gmail.com --- src/backend/statistics/extended_stats_funcs.c | 15 +++++++++++++++ src/test/regress/expected/stats_import.out | 19 +++++++++++++++++++ src/test/regress/sql/stats_import.sql | 14 ++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/backend/statistics/extended_stats_funcs.c b/src/backend/statistics/extended_stats_funcs.c index 4a65a46df41..2cb3942056f 100644 --- a/src/backend/statistics/extended_stats_funcs.c +++ b/src/backend/statistics/extended_stats_funcs.c @@ -851,6 +851,21 @@ import_mcv(const ArrayType *mcv_arr, const ArrayType *freqs_arr, * the reference array for determining their length. */ nitems = ARR_DIMS(mcv_arr)[0]; + + /* + * Reject a MCV list larger than what statext_mcv_deserialize() is able to + * accept. + */ + if (nitems > STATS_MCVLIST_MAX_ITEMS) + { + ereport(WARNING, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not parse array \"%s\": number of items (%d) exceeds maximum (%d)", + extarginfo[MOST_COMMON_VALS_ARG].argname, + nitems, STATS_MCVLIST_MAX_ITEMS)); + goto mcv_error; + } + if (!check_mcvlist_array(freqs_arr, MOST_COMMON_FREQS_ARG, 1, nitems) || !check_mcvlist_array(base_freqs_arr, MOST_COMMON_BASE_FREQS_ARG, 1, nitems)) { diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out index 4520f0b664e..dabf9ba1cd8 100644 --- a/src/test/regress/expected/stats_import.out +++ b/src/test/regress/expected/stats_import.out @@ -2231,6 +2231,25 @@ WARNING: could not parse array "most_common_vals": found 4 attributes but expec f (1 row) +-- warn: more MCV items than can be handled. +SELECT pg_catalog.pg_restore_extended_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'statistics_schemaname', 'stats_import', + 'statistics_name', 'test_stat_mcv', + 'inherited', false, + 'most_common_vals', (SELECT array_agg(ARRAY[g::text, g::text]) + FROM generate_series(1, 10001) g), + 'most_common_freqs', (SELECT array_agg((1.0 / 10001)::double precision) + FROM generate_series(1, 10001) g), + 'most_common_base_freqs', (SELECT array_agg((1.0 / 10001)::double precision) + FROM generate_series(1, 10001) g)); +WARNING: could not parse array "most_common_vals": number of items (10001) exceeds maximum (10000) + pg_restore_extended_stats +--------------------------- + f +(1 row) + -- ok: mcv SELECT pg_catalog.pg_restore_extended_stats( 'schemaname', 'stats_import', diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql index 6064b7722da..58140315efb 100644 --- a/src/test/regress/sql/stats_import.sql +++ b/src/test/regress/sql/stats_import.sql @@ -1612,6 +1612,20 @@ SELECT pg_catalog.pg_restore_extended_stats( 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[], 'most_common_base_freqs', '{0.00390625,0.015625,0.00390625,0.015625}'::double precision[]); +-- warn: more MCV items than can be handled. +SELECT pg_catalog.pg_restore_extended_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'statistics_schemaname', 'stats_import', + 'statistics_name', 'test_stat_mcv', + 'inherited', false, + 'most_common_vals', (SELECT array_agg(ARRAY[g::text, g::text]) + FROM generate_series(1, 10001) g), + 'most_common_freqs', (SELECT array_agg((1.0 / 10001)::double precision) + FROM generate_series(1, 10001) g), + 'most_common_base_freqs', (SELECT array_agg((1.0 / 10001)::double precision) + FROM generate_series(1, 10001) g)); + -- ok: mcv SELECT pg_catalog.pg_restore_extended_stats( 'schemaname', 'stats_import', -- 2.47.3