From c5f23fdbe03f419080a25c791b905c3aa464f0e8 Mon Sep 17 00:00:00 2001 From: zhangwenchao <656540940@qq.com> Date: Mon, 2 Mar 2026 16:44:30 +0800 Subject: [PATCH] Fix assertion failure in getNdvBySegHeapTuple for empty partitions. When merging leaf partition statistics for a partitioned table, getNdvBySegHeapTuple could hit Assert(valuetype == FLOAT8OID) if a partition had relTuples == 0 and its pg_statistic entry lacked a valid STATISTIC_KIND_NDV_BY_SEGMENTS slot (or the slot had an unexpected element type). The original guard condition only handled two cases: 1. Non-empty partition with NDV value == 0 2. Non-empty partition without NDV_BY_SEGMENTS It missed the case where an empty partition (relTuples == 0) has a pg_statistic entry but no valid FLOAT8OID NDV_BY_SEGMENTS slot, causing the code to fall through to the assertion. Fix by checking valuetype != FLOAT8OID upfront: skip empty partitions gracefully, and mark non-empty partitions as invalid. --- src/backend/commands/analyzeutils.c | 30 +++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/backend/commands/analyzeutils.c b/src/backend/commands/analyzeutils.c index c4f9fa5dedb..641ea015ea3 100644 --- a/src/backend/commands/analyzeutils.c +++ b/src/backend/commands/analyzeutils.c @@ -759,17 +759,31 @@ getNdvBySegHeapTuple(AttStatsSlot * *ndvbsSlots, HeapTuple *heaptupleStats, floa (void) get_attstatsslot(ndvbsSlots[i], heaptupleStats[i], STATISTIC_KIND_NDV_BY_SEGMENTS, InvalidOid, ATTSTATSSLOT_VALUES); - if ((InvalidOid != ndvbsSlots[i]->valuetype && // result is not empty - // not empty partition with invalid ndvbs - (relTuples[i] > 0 && DatumGetFloat8(ndvbsSlots[i]->values[0]) == 0)) || - // not empty partition without ndvbs - (InvalidOid == ndvbsSlots[i]->valuetype && relTuples[i] > 0)) { - valid = false; - break; + if (ndvbsSlots[i]->valuetype != FLOAT8OID) + { + /* + * NDV_BY_SEGMENTS slot not found or has unexpected type. + * Non-empty partitions must have valid NDV_BY_SEGMENTS; + * empty partitions (relTuples == 0) can be skipped. + */ + if (relTuples[i] > 0) + { + valid = false; + break; + } + pfree(ndvbsSlots[i]); + ndvbsSlots[i] = NULL; + continue; } - Assert(ndvbsSlots[i]->valuetype == FLOAT8OID); Assert(ndvbsSlots[i]->nvalues == 1); + + /* Non-empty partition with zero NDV is suspicious */ + if (relTuples[i] > 0 && DatumGetFloat8(ndvbsSlots[i]->values[0]) == 0) + { + valid = false; + break; + } } return valid; }