From 32e27bd320821df49dd212912b9e90d3d98e24f1 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 15 Jan 2026 09:36:05 +0900 Subject: [PATCH] Introduce routines to validate and free MVNDistinct and MVDependencies These routines are useful to perform some basic validation checks on each object structure, working currently on attribute numbers for non-expression and expression attnums. These checks could be extended in the future. Note that this code is not used yet in the tree, and that these functions will become handy for an upcoming patch for the import of extended statistics data. However, they are worth their own independent change as they are actually useful by themselves, with at least the extension code argument in mind (or perhaps I am just feeling more pedantic today). Extracted from a larger patch by the same author, with many adjustments and fixes by me. Author: Corey Huinker Reviewed-by: Chao Li Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/CADkLM=dpz3KFnqP-dgJ-zvRvtjsa8UZv8wDAQdqho=qN3kX0Zg@mail.gmail.com --- src/backend/statistics/dependencies.c | 76 +++++++++++++++++++ src/backend/statistics/mvdistinct.c | 76 +++++++++++++++++++ .../statistics/extended_stats_internal.h | 8 ++ 3 files changed, 160 insertions(+) diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c index f634f20dd66..e3a2f5817e0 100644 --- a/src/backend/statistics/dependencies.c +++ b/src/backend/statistics/dependencies.c @@ -579,6 +579,82 @@ statext_dependencies_deserialize(bytea *data) return dependencies; } +/* + * Free allocations of a MVDependencies. + */ +void +statext_dependencies_free(MVDependencies *dependencies) +{ + for (int i = 0; i < dependencies->ndeps; i++) + pfree(dependencies->deps[i]); + pfree(dependencies); +} + +/* + * Validate a set of MVDependencies against the extended statistics object + * definition. + * + * Every MVDependencies must be checked to ensure that the attnums in the + * attributes list correspond to attnums/expressions defined by the + * extended statistics object. + * + * Positive attnums are attributes which must be found in the stxkeys, while + * negative attnums correspond to an expression number, no attribute number + * can be below (0 - numexprs). + */ +bool +statext_dependencies_validate(const MVDependencies *dependencies, + const int2vector *stxkeys, + int numexprs, int elevel) +{ + int attnum_expr_lowbound = 0 - numexprs; + + /* Scan through each dependency entry */ + for (int i = 0; i < dependencies->ndeps; i++) + { + const MVDependency *dep = dependencies->deps[i]; + + /* + * Cross-check each attribute in a dependency entry with the extended + * stats object definition. + */ + for (int j = 0; j < dep->nattributes; j++) + { + AttrNumber attnum = dep->attributes[j]; + bool ok = false; + + if (attnum > 0) + { + /* attribute number in stxkeys */ + for (int k = 0; k < stxkeys->dim1; k++) + { + if (attnum == stxkeys->values[k]) + { + ok = true; + break; + } + } + } + else if ((attnum < 0) && (attnum >= attnum_expr_lowbound)) + { + /* attribute number for an expression */ + ok = true; + } + + if (!ok) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("could not validate \"%s\" object: invalid attribute number %d found", + "pg_dependencies", attnum))); + return false; + } + } + } + + return true; +} + /* * dependency_is_fully_matched * checks that a functional dependency is fully matched given clauses on diff --git a/src/backend/statistics/mvdistinct.c b/src/backend/statistics/mvdistinct.c index c87e2ecbfa0..4f8f578a22f 100644 --- a/src/backend/statistics/mvdistinct.c +++ b/src/backend/statistics/mvdistinct.c @@ -325,6 +325,82 @@ statext_ndistinct_deserialize(bytea *data) return ndistinct; } +/* + * Free allocations of a MVNDistinct. + */ +void +statext_ndistinct_free(MVNDistinct *ndistinct) +{ + for (int i = 0; i < ndistinct->nitems; i++) + pfree(ndistinct->items[i].attributes); + pfree(ndistinct); +} + +/* + * Validate a set of MVNDistincts against the extended statistics object + * definition. + * + * Every MVNDistinctItem must be checked to ensure that the attnums in the + * attributes list correspond to attnums/expressions defined by the extended + * statistics object. + * + * Positive attnums are attributes which must be found in the stxkeys, + * while negative attnums correspond to an expression number, no attribute + * number can be below (0 - numexprs). + */ +bool +statext_ndistinct_validate(const MVNDistinct *ndistinct, + const int2vector *stxkeys, + int numexprs, int elevel) +{ + int attnum_expr_lowbound = 0 - numexprs; + + /* Scan through each MVNDistinct entry */ + for (int i = 0; i < ndistinct->nitems; i++) + { + MVNDistinctItem item = ndistinct->items[i]; + + /* + * Cross-check each attribute in a MVNDistinct entry with the extended + * stats object definition. + */ + for (int j = 0; j < item.nattributes; j++) + { + AttrNumber attnum = item.attributes[j]; + bool ok = false; + + if (attnum > 0) + { + /* attribute number in stxkeys */ + for (int k = 0; k < stxkeys->dim1; k++) + { + if (attnum == stxkeys->values[k]) + { + ok = true; + break; + } + } + } + else if ((attnum < 0) && (attnum >= attnum_expr_lowbound)) + { + /* attribute number for an expression */ + ok = true; + } + + if (!ok) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("could not validate \"%s\" object: invalid attribute number %d found", + "pg_ndistinct", attnum))); + return false; + } + } + } + + return true; +} + /* * ndistinct_for_combination * Estimates number of distinct values in a combination of columns. diff --git a/src/include/statistics/extended_stats_internal.h b/src/include/statistics/extended_stats_internal.h index 229f1a755a6..b5003ec242c 100644 --- a/src/include/statistics/extended_stats_internal.h +++ b/src/include/statistics/extended_stats_internal.h @@ -72,10 +72,18 @@ typedef struct StatsBuildData extern MVNDistinct *statext_ndistinct_build(double totalrows, StatsBuildData *data); extern bytea *statext_ndistinct_serialize(MVNDistinct *ndistinct); extern MVNDistinct *statext_ndistinct_deserialize(bytea *data); +extern bool statext_ndistinct_validate(const MVNDistinct *ndistinct, + const int2vector *stxkeys, + int numexprs, int elevel); +extern void statext_ndistinct_free(MVNDistinct *ndistinct); extern MVDependencies *statext_dependencies_build(StatsBuildData *data); extern bytea *statext_dependencies_serialize(MVDependencies *dependencies); extern MVDependencies *statext_dependencies_deserialize(bytea *data); +extern bool statext_dependencies_validate(const MVDependencies *dependencies, + const int2vector *stxkeys, + int numexprs, int elevel); +extern void statext_dependencies_free(MVDependencies *dependencies); extern MCVList *statext_mcv_build(StatsBuildData *data, double totalrows, int stattarget);