Hello Tomas,

> On 27. Jul 2026, at 14:06, Jan Nidzwetzki <[email protected]> wrote:
> 
>> On 24. Jul 2026, at 15:55, Tomas Vondra <[email protected]> wrote:

[...]

>>>> 4. Statistics import accepts Infinity and NaN
>>>> ---------------------------------------------
>>>> 
>>>> Finally, the reltuples argument of pg_restore_relation_stats() (and the
>>>> shared relation_statistics_update_internal() path) is only validated
>>>> with:
>>>> 
>>>>   if (reltuples < -1.0)                    /* relation_stats.c:126 */
>>>>   {
>>>>       ereport(WARNING, ...);
>>>>       result = false;                      /* update skipped */
>>>>   }
> 
> [...]
> 
>>>> We have not addressed this one in the attached patches, because
>>>> rejecting non-finite values here is a slightly larger policy question
>>>> (error vs. clamp-to -1). If there is agreement on the desired
>>>> behavior, we are glad to propose a patch for this as well.
>>>> 
>>> 
>>> OTOH this seems like something we might want to do, to validate and
>>> reject clearly bogus values.
>>> 
>> 
>> No opinion on this. But I was checking how we validate the values when
>> importing stats, and I noticed relation_statistics_update_internal does
>> this:
>> 
>>   if (reltuples < -1.0)
>>   {
>>       ereport(WARNING,
>>               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
>>                errmsg("argument \"%s\" must not be less than -1.0",
>> "reltuples")));
>>       result = false;
>>   }
>> 
>> Isn't that a bit strange it's not (reltuplees < 0.0)?
> 
> This caught my attention as well. From my understanding, -1.0 should be
> allowed, since in 3d351d916b2 the value -1 was introduced as a sentinel
> meaning "unknown / never analyzed". But we also allow values between
> -1.0 and 0 here. I think the looseness below zero is harmless because
> every reader treats negative as "unknown".

As discussed upthread, here's the follow-up patch to validate and
reject clearly bogus reltuples at import.

Currently, the function relation_statistics_update_internal() validates
the incoming reltuples only with

   if (reltuples < -1.0) { ereport(WARNING, ...); result = false; }

This means that both Infinity and NaN values pass this test since
neither is less than -1.0. As a result, non-finite values are accepted
and stored in pg_class.reltuples.

The patch rejects non-finite reltuples the same non-fatal way the
existing out-of-range check does: ereport(WARNING), set result = false,
and skip that field, so an otherwise-valid stats import (or pg_upgrade)
still proceeds and only the bad value is dropped.

It also adds a regression test to stats_import covering the rejected
values (Infinity, -Infinity, NaN) and confirming that a legitimate -1
is still accepted.

The statistics import functions are new in v18, so this applies to v18+.

Best regards
Jan

Attachment: 0001-Reject-non-finite-reltuples-in-the-statistics-import.patch
Description: Binary data

---
Jan Nidzwetzki
PlanetScale Postgres Core Team



Reply via email to