| From: | Jan Nidzwetzki <jan(at)planetscale(dot)com> |
|---|---|
| To: | Tomas Vondra <tomas(at)vondra(dot)me> |
| Cc: | pgsql-hackers(at)lists(dot)postgresql(dot)org |
| Subject: | Re: pg_class.reltuples can become non-finite and never recovers |
| Date: | 2026-07-28 14:08:27 |
| Message-ID: | 4F1151D9-B4DD-49BA-B7F1-9D175EA2CDFB@planetscale.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hello Tomas,
> On 27. Jul 2026, at 14:06, Jan Nidzwetzki <jan(at)planetscale(dot)com> wrote:
>
>> On 24. Jul 2026, at 15:55, Tomas Vondra <tomas(at)vondra(dot)me> 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 | Content-Type | Size |
|---|---|---|
| 0001-Reject-non-finite-reltuples-in-the-statistics-import.patch | application/octet-stream | 6.7 KB |
| unknown_filename | text/plain | 54 bytes |
| From | Date | Subject | |
|---|---|---|---|
| Previous Message | Robert Haas | 2026-07-28 14:00:03 | Re: log_postmaster_stats |