pg.ddx.io  pgsql-bugs@postgresql.org mailing list archive  
help / color / mirror / Atom feed
pg_restore_attribute_stats accepts and persists null_frac=NaN
2+ messages / 2 participants
[nested] [flat]

* pg_restore_attribute_stats accepts and persists null_frac=NaN
@ 2026-09-08 09:53  =?utf-8?B?4pmCz4DiiYwyNjIxOA==?= <1991230470@qq.com>
  0 siblings, 1 reply; 2+ messages in thread

From: ♂π≌26218 @ 2026-09-08 09:53 UTC (permalink / raw)
  To: pgsql-bugs <pgsql-bugs@lists.postgresql.org>

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@qq.com

^ permalink  raw  reply  [nested|flat] 2+ messages in thread

* Re: pg_restore_attribute_stats accepts and persists null_frac=NaN
@ 2026-09-11 08:00  Michael Paquier <michael@paquier.xyz>
  parent: =?utf-8?B?4pmCz4DiiYwyNjIxOA==?= <1991230470@qq.com>
  0 siblings, 0 replies; 2+ messages in thread

From: Michael Paquier @ 2026-09-11 08:00 UTC (permalink / raw)
  To: ♂π≌26218 <1991230470@qq.com>; +Cc: pgsql-bugs <pgsql-bugs@lists.postgresql.org>

On Tue, Sep 08, 2026 at 05:53:01PM +0800, ♂π≌26218 wrote:
> 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.

Being able to inject stats, even buggy ones, is one reason why this
feature can be attractive in some cases.  There are many other ways to
make the planner go crazy on arbitrary data, as far as I know.

Does your example lead to a server crash or an assertion failure?  If
the answer to my last question is yes, that may be worth
strenghtening with more control of the input, but in terms of stats
injection, "incorrect" or "unexpected planner behavior" is not worth
bothering about.
--
Michael

Attachments:

  [application/pgp-signature] signature.asc (832B, ../../aqO1CDpx8K55lJs5@paquier.xyz/2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 2+ messages in thread


end of thread, other threads:[~2026-09-11 08:00 UTC | newest]

Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-09-08 09:53 pg_restore_attribute_stats accepts and persists null_frac=NaN =?utf-8?B?4pmCz4DiiYwyNjIxOA==?= <1991230470@qq.com>
2026-09-11 08:00 ` Michael Paquier <michael@paquier.xyz>

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox