pg_restore_attribute_stats accepts and persists null_frac=NaN

From: ♂π≌26218 <1991230470(at)qq(dot)com>
To: pgsql-bugs <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: pg_restore_attribute_stats accepts and persists null_frac=NaN
Date: 2026-09-08 09:53:01
Message-ID: tencent_16A3D0E291B9D54FC48D30FC166410A02806@qq.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hi, I found a potential bug in PostgreSQL's planner statistics restoration function where `pg_restore_attribute_stats()` accepts and persists `null_frac=NaN`, even though `null_frac` represents a fraction of rows and should be a finite value between zero and one inclusive. Description: `pg_restore_attribute_stats()` is used to restore planner statistics for a given attribute. When called with `null_frac` set to `'NaN'::real`, the function returns `true` and writes the value into `pg_statistic.stanullfrac`. Subsequently, `pg_stats.null_frac` contains `NaN`. This violates the expected domain of `null_frac`, which should always be a finite fraction. The reviewed source location is `src/backend/statistics/attribute_stats.c:363-377`, where the input datum appears to be written without any finite/range validation. PostgreSQL version: - PostgreSQL 19beta3 (Docker-based runtime) - Reviewed source snapshot: `f836b688f8dc627ce97760dec5569aa7c064ffe9` - Build relationship: the tested image was not built from that exact source snapshot Environment: - Docker-based PostgreSQL 19beta3 runtime - No special server configuration required beyond the privileges needed to restore planner statistics Steps to Reproduce: ```sql \set VERBOSITY verbose CREATE TABLE attr_nan_test(a int); INSERT INTO attr_nan_test VALUES (1), (2), (3), (NULL); ANALYZE attr_nan_test; SELECT pg_catalog.pg_restore_attribute_stats( &nbsp;'schemaname', 'public', &nbsp;'relname', 'attr_nan_test', &nbsp;'attname', 'a', &nbsp;'inherited', false, &nbsp;'null_frac', 'NaN'::real, &nbsp;'n_distinct', 2::real ); SELECT null_frac FROM pg_stats WHERE tablename = 'attr_nan_test' AND attname = 'a';

For the control, replace 'NaN'::real&nbsp;with 0.25::real.

Actual Result:

The function returns true, and the query returns:
text

null_frac --------- NaN

Expected Result:

The restoration function should reject NaN, Infinity, negative values, and values greater than one for null_frac. It should return false&nbsp;or raise a controlled error without replacing the previous statistic.

Reproduction Frequency:

Positive reproduction: 2/2 on PostgreSQL 19beta3

Negative control: null_frac=0.25&nbsp;was accepted and stored normally

Additional Observations:

The issue likely stems from the absence of validation on the null_frac&nbsp;input in attribute_stats.c:363-377. While the practical impact is limited because pg_restore_attribute_stats()&nbsp;is intended for privileged statistics restoration, accepting NaN&nbsp;could lead to unexpected planner behavior or confusion when viewing pg_stats.

I searched the public PostgreSQL bug archives and did not find any report specifically addressing null_frac=NaN&nbsp;acceptance in pg_restore_attribute_stats(). Please confirm whether this is considered a bug or an intentional behavior.

♂π≌26218
1991230470(at)qq(dot)com

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message ♂π≌26218 2026-09-08 09:56:41 pg_restore_attribute_stats accepts an unsorted range-length histogram
Previous Message ♂π≌26218 2026-09-08 09:50:09 Hunspell AF alias count silently wraps to a smaller value