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);