]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Reject oversized MCV lists in pg_restore_extended_stats()
authorMichael Paquier <michael@paquier.xyz>
Tue, 16 Jun 2026 05:47:20 +0000 (14:47 +0900)
committerMichael Paquier <michael@paquier.xyz>
Tue, 16 Jun 2026 06:14:58 +0000 (15:14 +0900)
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 <kdbase.hack@gmail.com>
Discussion: https://postgr.es/m/CAON2xHORd2ESXm1KcVeeZ0Kd_aJk4dL4M2WLtzVDM4puaZ-20w@mail.gmail.com

src/backend/statistics/extended_stats_funcs.c
src/test/regress/expected/stats_import.out
src/test/regress/sql/stats_import.sql

index 4a65a46df41a8ab1c79ddec6640c42b7fb4b6c28..2cb3942056f9ae7b94818e4d5c0fe896cb78a369 100644 (file)
@@ -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))
        {
index 4520f0b664eb39f079e0e602cc8a7f94fbf5d410..dabf9ba1cd82734d21fa92ffc907cb170cb7aa8f 100644 (file)
@@ -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',
index 6064b7722da898c9c1d65fd20865778f62e605ad..58140315efbcbbbf7859e140d25e4c0c645bccd9 100644 (file)
@@ -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',