Re:BUG #19501: btree_gist: use float4/float8 comparison functions to handle NaN correctly

From: ylwangtju <ylwangtju(at)qq(dot)com>
To: zengman <zengman(at)halodbtech(dot)com>, pgsql-bugs <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Cc: zengman <zengman(at)halodbtech(dot)com>
Subject: Re:BUG #19501: btree_gist: use float4/float8 comparison functions to handle NaN correctly
Date: 2026-06-18 16:43:34
Message-ID: tencent_3720A390761FE22DBD346D11B781D5AC6706@qq.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

In addition to the index scan inconsistency you described, I found two further security-relevant effects from the same root cause.

Effect 1: EXCLUDE constraint bypass (float4)

CREATE TABLE reservations (

room float4,

during tsrange,

EXCLUDE USING gist (room WITH =, during WITH &amp;&amp;)

);

INSERT INTO reservations VALUES ('NaN'::float4, '[2025-01-01,2025-01-02)');

INSERT INTO reservations VALUES ('NaN'::float4, '[2025-01-01,2025-01-02)');

SELECT COUNT(*) FROM reservations;

Expected: 1 (second insert blocked). Actual: 2. The EXCLUDE constraint is silently bypassed for NaN values, allowing duplicate conflicting rows to be inserted.

Effect 2: RLS bypass (float8)

CREATE TABLE measurements (id int, val float8);

CREATE INDEX ON measurements USING gist (val);

INSERT INTO measurements VALUES (1, 'NaN'), (2, 1.5);

ALTER TABLE measurements ENABLE ROW LEVEL SECURITY;

ALTER TABLE measurements FORCE ROW LEVEL SECURITY;

CREATE POLICY hide_nan ON measurements FOR SELECT USING (val != 'NaN'::float8);

CREATE ROLE lowpriv LOGIN;

GRANT SELECT ON measurements TO lowpriv;

SET ROLE lowpriv;

SET enable_seqscan = off;

SET enable_bitmapscan = off;

SELECT * FROM measurements ORDER BY id;

Expected: only (2, 1.5). Actual: both rows including (1, NaN). The RLS policy is bypassed when the GiST index is used because gbt_float8_consistent() sets *recheck = false unconditionally, so the heap-level RLS filter is never applied.
The fix is right, and I just followed up some other impacts.

Original


From:PG Bug reporting form <noreply(at)postgresql(dot)org&gt;
Sent Time:May 29, 2026 23:35
To:pgsql-bugs <pgsql-bugs(at)lists(dot)postgresql(dot)org&gt;
Cc:zengman <zengman(at)halodbtech(dot)com&gt;
Subject:BUG #19501: btree_gist: use float4/float8 comparison functions to handle NaN correctly

The&nbsp;following&nbsp;bug&nbsp;has&nbsp;been&nbsp;logged&nbsp;on&nbsp;the&nbsp;website:

Bug&nbsp;reference:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;19501
Logged&nbsp;by:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Man&nbsp;Zeng
Email&nbsp;address:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zengman(at)halodbtech(dot)com
PostgreSQL&nbsp;version:&nbsp;18.4
Operating&nbsp;system:&nbsp;&nbsp;&nbsp;24.04.1-Ubuntu
Description:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

Hi&nbsp;all,

Here's&nbsp;an&nbsp;interesting&nbsp;case&nbsp;where&nbsp;btree_gist&nbsp;returns&nbsp;inconsistent&nbsp;results
between&nbsp;index&nbsp;scans&nbsp;and&nbsp;sequential&nbsp;scans&nbsp;when&nbsp;NaN&nbsp;values&nbsp;are&nbsp;involved.

```
postgres(at)zxm-VMware-Virtual-Platform:~/code/zengine$&nbsp;psql
psql&nbsp;(19devel)
Type&nbsp;"help"&nbsp;for&nbsp;help.

test=#&nbsp;CREATE&nbsp;EXTENSION&nbsp;btree_gist;
CREATE&nbsp;EXTENSION
test=#&nbsp;CREATE&nbsp;TABLE&nbsp;test_nan_bug&nbsp;(v&nbsp;float8);
CREATE&nbsp;TABLE
test=#&nbsp;INSERT&nbsp;INTO&nbsp;test_nan_bug&nbsp;VALUES&nbsp;(1.0),&nbsp;(2.0),&nbsp;('NaN'::float8),&nbsp;(3.0);
INSERT&nbsp;0&nbsp;4
test=#&nbsp;CREATE&nbsp;INDEX&nbsp;idx_nan_bug&nbsp;ON&nbsp;test_nan_bug&nbsp;USING&nbsp;gist(v);
CREATE&nbsp;INDEX
test=#&nbsp;SET&nbsp;enable_indexscan=off;
SET
test=#&nbsp;SELECT&nbsp;count(*)&nbsp;FROM&nbsp;test_nan_bug&nbsp;WHERE&nbsp;v&nbsp;=&nbsp;'NaN'::float8;
&nbsp;count
-------
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1
(1&nbsp;row)

test=#&nbsp;EXPLAIN&nbsp;VERBOSE&nbsp;SELECT&nbsp;count(*)&nbsp;FROM&nbsp;test_nan_bug&nbsp;WHERE&nbsp;v&nbsp;=
'NaN'::float8;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QUERY&nbsp;PLAN
-------------------------------------------------------------------------
&nbsp;Aggregate&nbsp;&nbsp;(cost=1.05..1.06&nbsp;rows=1&nbsp;width=8)
&nbsp;&nbsp;&nbsp;Output:&nbsp;count(*)
&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp;Seq&nbsp;Scan&nbsp;on&nbsp;public.test_nan_bug&nbsp;&nbsp;(cost=0.00..1.05&nbsp;rows=1&nbsp;width=0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Output:&nbsp;v
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Filter:&nbsp;(test_nan_bug.v&nbsp;=&nbsp;'NaN'::double&nbsp;precision)
(5&nbsp;rows)

test=#&nbsp;SET&nbsp;enable_indexscan=on;&nbsp;SET&nbsp;enable_seqscan=off;
SET
SET
test=#&nbsp;SELECT&nbsp;count(*)&nbsp;FROM&nbsp;test_nan_bug&nbsp;WHERE&nbsp;v&nbsp;=&nbsp;'NaN'::float8;
&nbsp;count
-------
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0
(1&nbsp;row)

test=#&nbsp;EXPLAIN&nbsp;VERBOSE&nbsp;SELECT&nbsp;count(*)&nbsp;FROM&nbsp;test_nan_bug&nbsp;WHERE&nbsp;v&nbsp;=
'NaN'::float8;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QUERY&nbsp;PLAN
--------------------------------------------------------------------------------------------------
&nbsp;Aggregate&nbsp;&nbsp;(cost=8.15..8.16&nbsp;rows=1&nbsp;width=8)
&nbsp;&nbsp;&nbsp;Output:&nbsp;count(*)
&nbsp;&nbsp;&nbsp;-&gt;&nbsp;&nbsp;Index&nbsp;Only&nbsp;Scan&nbsp;using&nbsp;idx_nan_bug&nbsp;on&nbsp;public.test_nan_bug
(cost=0.13..8.15&nbsp;rows=1&nbsp;width=0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Output:&nbsp;v
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Index&nbsp;Cond:&nbsp;(test_nan_bug.v&nbsp;=&nbsp;'NaN'::double&nbsp;precision)
(5&nbsp;rows)

```

Steps&nbsp;to&nbsp;reproduce:
```sql
CREATE&nbsp;EXTENSION&nbsp;btree_gist;
CREATE&nbsp;TABLE&nbsp;test_nan_bug&nbsp;(v&nbsp;float8);
INSERT&nbsp;INTO&nbsp;test_nan_bug&nbsp;VALUES&nbsp;(1.0),&nbsp;(2.0),&nbsp;('NaN'::float8),&nbsp;(3.0);
CREATE&nbsp;INDEX&nbsp;idx_nan_bug&nbsp;ON&nbsp;test_nan_bug&nbsp;USING&nbsp;gist(v);

SET&nbsp;enable_indexscan=off;
SELECT&nbsp;count(*)&nbsp;FROM&nbsp;test_nan_bug&nbsp;WHERE&nbsp;v&nbsp;=&nbsp;'NaN'::float8;

SET&nbsp;enable_indexscan=on;&nbsp;SET&nbsp;enable_seqscan=off;
SELECT&nbsp;count(*)&nbsp;FROM&nbsp;test_nan_bug&nbsp;WHERE&nbsp;v&nbsp;=&nbsp;'NaN'::float8;
```

My&nbsp;fix&nbsp;replaces&nbsp;the&nbsp;C&nbsp;comparison&nbsp;operators&nbsp;with&nbsp;PostgreSQL's&nbsp;float
comparison&nbsp;functions&nbsp;(float8_gt,&nbsp;float8_ge,&nbsp;float8_eq,&nbsp;etc.)&nbsp;and
float8_cmp_internal,&nbsp;which&nbsp;handle&nbsp;NaN&nbsp;consistently.

```
diff&nbsp;--git&nbsp;a/contrib/btree_gist/btree_float4.c
b/contrib/btree_gist/btree_float4.c
index&nbsp;c076918fd48..eaecdac0980&nbsp;100644
---&nbsp;a/contrib/btree_gist/btree_float4.c
+++&nbsp;b/contrib/btree_gist/btree_float4.c
@@&nbsp;-29,27&nbsp;+29,27&nbsp;@@&nbsp;PG_FUNCTION_INFO_V1(gbt_float4_sortsupport);
&nbsp;static&nbsp;bool
&nbsp;gbt_float4gt(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float4&nbsp;*)&nbsp;a)&nbsp;&gt;&nbsp;*((const&nbsp;float4&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4_gt(*(const&nbsp;float4&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float4&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float4ge(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float4&nbsp;*)&nbsp;a)&nbsp;&gt;=&nbsp;*((const&nbsp;float4&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4_ge(*(const&nbsp;float4&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float4&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float4eq(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float4&nbsp;*)&nbsp;a)&nbsp;==&nbsp;*((const&nbsp;float4&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4_eq(*(const&nbsp;float4&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float4&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float4le(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float4&nbsp;*)&nbsp;a)&nbsp;<=&nbsp;*((const&nbsp;float4&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4_le(*(const&nbsp;float4&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float4&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float4lt(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float4&nbsp;*)&nbsp;a)&nbsp;<&nbsp;*((const&nbsp;float4&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4_lt(*(const&nbsp;float4&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float4&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;
&nbsp;static&nbsp;int
@@&nbsp;-57,16&nbsp;+57,12&nbsp;@@&nbsp;gbt_float4key_cmp(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo
*flinfo)
&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float4KEY&nbsp;&nbsp;*ia&nbsp;=&nbsp;(float4KEY&nbsp;*)&nbsp;(((const&nbsp;Nsrt&nbsp;*)&nbsp;a)-&gt;t);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float4KEY&nbsp;&nbsp;*ib&nbsp;=&nbsp;(float4KEY&nbsp;*)&nbsp;(((const&nbsp;Nsrt&nbsp;*)&nbsp;b)-&gt;t);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp;
&nbsp;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ia-&gt;lower&nbsp;==&nbsp;ib-&gt;lower)
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ia-&gt;upper&nbsp;==&nbsp;ib-&gt;upper)
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;
-
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(ia-&gt;upper&nbsp;&gt;&nbsp;ib-&gt;upper)&nbsp;?&nbsp;1&nbsp;:&nbsp;-1;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
-
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(ia-&gt;lower&nbsp;&gt;&nbsp;ib-&gt;lower)&nbsp;?&nbsp;1&nbsp;:&nbsp;-1;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;=&nbsp;float4_cmp_internal(ia-&gt;lower,&nbsp;ib-&gt;lower);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(cmp&nbsp;!=&nbsp;0)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cmp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float4_cmp_internal(ia-&gt;upper,&nbsp;ib-&gt;upper);
&nbsp;}
&nbsp;
&nbsp;static&nbsp;float8
diff&nbsp;--git&nbsp;a/contrib/btree_gist/btree_float8.c
b/contrib/btree_gist/btree_float8.c
index&nbsp;d7386e885a2..132065a648c&nbsp;100644
---&nbsp;a/contrib/btree_gist/btree_float8.c
+++&nbsp;b/contrib/btree_gist/btree_float8.c
@@&nbsp;-30,27&nbsp;+30,27&nbsp;@@&nbsp;PG_FUNCTION_INFO_V1(gbt_float8_sortsupport);
&nbsp;static&nbsp;bool
&nbsp;gbt_float8gt(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float8&nbsp;*)&nbsp;a)&nbsp;&gt;&nbsp;*((const&nbsp;float8&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float8_gt(*(const&nbsp;float8&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float8&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float8ge(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float8&nbsp;*)&nbsp;a)&nbsp;&gt;=&nbsp;*((const&nbsp;float8&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float8_ge(*(const&nbsp;float8&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float8&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float8eq(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float8&nbsp;*)&nbsp;a)&nbsp;==&nbsp;*((const&nbsp;float8&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float8_eq(*(const&nbsp;float8&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float8&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float8le(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float8&nbsp;*)&nbsp;a)&nbsp;<=&nbsp;*((const&nbsp;float8&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float8_le(*(const&nbsp;float8&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float8&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;static&nbsp;bool
&nbsp;gbt_float8lt(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo&nbsp;*flinfo)
&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(*((const&nbsp;float8&nbsp;*)&nbsp;a)&nbsp;<&nbsp;*((const&nbsp;float8&nbsp;*)&nbsp;b));
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float8_lt(*(const&nbsp;float8&nbsp;*)&nbsp;a,&nbsp;*(const&nbsp;float8&nbsp;*)&nbsp;b);
&nbsp;}
&nbsp;
&nbsp;static&nbsp;int
@@&nbsp;-58,16&nbsp;+58,12&nbsp;@@&nbsp;gbt_float8key_cmp(const&nbsp;void&nbsp;*a,&nbsp;const&nbsp;void&nbsp;*b,&nbsp;FmgrInfo
*flinfo)
&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float8KEY&nbsp;&nbsp;*ia&nbsp;=&nbsp;(float8KEY&nbsp;*)&nbsp;(((const&nbsp;Nsrt&nbsp;*)&nbsp;a)-&gt;t);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float8KEY&nbsp;&nbsp;*ib&nbsp;=&nbsp;(float8KEY&nbsp;*)&nbsp;(((const&nbsp;Nsrt&nbsp;*)&nbsp;b)-&gt;t);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp;
&nbsp;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ia-&gt;lower&nbsp;==&nbsp;ib-&gt;lower)
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(ia-&gt;upper&nbsp;==&nbsp;ib-&gt;upper)
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;
-
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(ia-&gt;upper&nbsp;&gt;&nbsp;ib-&gt;upper)&nbsp;?&nbsp;1&nbsp;:&nbsp;-1;
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
-
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(ia-&gt;lower&nbsp;&gt;&nbsp;ib-&gt;lower)&nbsp;?&nbsp;1&nbsp;:&nbsp;-1;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;=&nbsp;float8_cmp_internal(ia-&gt;lower,&nbsp;ib-&gt;lower);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(cmp&nbsp;!=&nbsp;0)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cmp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;float8_cmp_internal(ia-&gt;upper,&nbsp;ib-&gt;upper);
&nbsp;}
&nbsp;
&nbsp;static&nbsp;float8
diff&nbsp;--git&nbsp;a/contrib/btree_gist/expected/float4.out
b/contrib/btree_gist/expected/float4.out
index&nbsp;dfe732049e6..99ed6ae4668&nbsp;100644
---&nbsp;a/contrib/btree_gist/expected/float4.out
+++&nbsp;b/contrib/btree_gist/expected/float4.out
@@&nbsp;-89,3&nbsp;+89,12&nbsp;@@&nbsp;SELECT&nbsp;a,&nbsp;a&nbsp;<-&gt;&nbsp;'-179.0'&nbsp;FROM&nbsp;float4tmp&nbsp;ORDER&nbsp;BY&nbsp;a&nbsp;<-&gt;
'-179.0'&nbsp;LIMIT&nbsp;3;
&nbsp;&nbsp;-158.17741&nbsp;|&nbsp;20.822586
&nbsp;(3&nbsp;rows)
&nbsp;
+INSERT&nbsp;INTO&nbsp;float4tmp&nbsp;VALUES&nbsp;('NaN'),&nbsp;('NaN');
+SET&nbsp;enable_seqscan=off;
+SELECT&nbsp;count(*)&nbsp;FROM&nbsp;float4tmp&nbsp;WHERE&nbsp;a&nbsp;=&nbsp;'NaN';
+&nbsp;count
+-------
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2
+(1&nbsp;row)
+
+RESET&nbsp;enable_seqscan;
diff&nbsp;--git&nbsp;a/contrib/btree_gist/expected/float8.out
b/contrib/btree_gist/expected/float8.out
index&nbsp;ebd0ef3d689..e463b8869d6&nbsp;100644
---&nbsp;a/contrib/btree_gist/expected/float8.out
+++&nbsp;b/contrib/btree_gist/expected/float8.out
@@&nbsp;-89,3&nbsp;+89,12&nbsp;@@&nbsp;SELECT&nbsp;a,&nbsp;a&nbsp;<-&gt;&nbsp;'-1890.0'&nbsp;FROM&nbsp;float8tmp&nbsp;ORDER&nbsp;BY&nbsp;a&nbsp;<-&gt;
'-1890.0'&nbsp;LIMIT&nbsp;3;
&nbsp;&nbsp;&nbsp;-1769.73634&nbsp;|&nbsp;120.26366000000007
&nbsp;(3&nbsp;rows)
&nbsp;
+INSERT&nbsp;INTO&nbsp;float8tmp&nbsp;VALUES&nbsp;('NaN'),&nbsp;('NaN');
+SET&nbsp;enable_seqscan=off;
+SELECT&nbsp;count(*)&nbsp;FROM&nbsp;float8tmp&nbsp;WHERE&nbsp;a&nbsp;=&nbsp;'NaN';
+&nbsp;count
+-------
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2
+(1&nbsp;row)
+
+RESET&nbsp;enable_seqscan;
diff&nbsp;--git&nbsp;a/contrib/btree_gist/sql/float4.sql
b/contrib/btree_gist/sql/float4.sql
index&nbsp;3da1ce953c8..0cacee08276&nbsp;100644
---&nbsp;a/contrib/btree_gist/sql/float4.sql
+++&nbsp;b/contrib/btree_gist/sql/float4.sql
@@&nbsp;-35,3&nbsp;+35,11&nbsp;@@&nbsp;SELECT&nbsp;count(*)&nbsp;FROM&nbsp;float4tmp&nbsp;WHERE&nbsp;a&nbsp;&gt;&nbsp;&nbsp;-179.0::float4;
&nbsp;EXPLAIN&nbsp;(COSTS&nbsp;OFF)
&nbsp;SELECT&nbsp;a,&nbsp;a&nbsp;<-&gt;&nbsp;'-179.0'&nbsp;FROM&nbsp;float4tmp&nbsp;ORDER&nbsp;BY&nbsp;a&nbsp;<-&gt;&nbsp;'-179.0'&nbsp;LIMIT&nbsp;3;
&nbsp;SELECT&nbsp;a,&nbsp;a&nbsp;<-&gt;&nbsp;'-179.0'&nbsp;FROM&nbsp;float4tmp&nbsp;ORDER&nbsp;BY&nbsp;a&nbsp;<-&gt;&nbsp;'-179.0'&nbsp;LIMIT&nbsp;3;
+
+INSERT&nbsp;INTO&nbsp;float4tmp&nbsp;VALUES&nbsp;('NaN'),&nbsp;('NaN');
+
+SET&nbsp;enable_seqscan=off;
+
+SELECT&nbsp;count(*)&nbsp;FROM&nbsp;float4tmp&nbsp;WHERE&nbsp;a&nbsp;=&nbsp;'NaN';
+
+RESET&nbsp;enable_seqscan;
diff&nbsp;--git&nbsp;a/contrib/btree_gist/sql/float8.sql
b/contrib/btree_gist/sql/float8.sql
index&nbsp;e1e819b37f9..2d6ef9d95e7&nbsp;100644
---&nbsp;a/contrib/btree_gist/sql/float8.sql
+++&nbsp;b/contrib/btree_gist/sql/float8.sql
@@&nbsp;-35,3&nbsp;+35,11&nbsp;@@&nbsp;SELECT&nbsp;count(*)&nbsp;FROM&nbsp;float8tmp&nbsp;WHERE&nbsp;a&nbsp;&gt;
-1890.0::float8;
&nbsp;EXPLAIN&nbsp;(COSTS&nbsp;OFF)
&nbsp;SELECT&nbsp;a,&nbsp;a&nbsp;<-&gt;&nbsp;'-1890.0'&nbsp;FROM&nbsp;float8tmp&nbsp;ORDER&nbsp;BY&nbsp;a&nbsp;<-&gt;&nbsp;'-1890.0'&nbsp;LIMIT&nbsp;3;
&nbsp;SELECT&nbsp;a,&nbsp;a&nbsp;<-&gt;&nbsp;'-1890.0'&nbsp;FROM&nbsp;float8tmp&nbsp;ORDER&nbsp;BY&nbsp;a&nbsp;<-&gt;&nbsp;'-1890.0'&nbsp;LIMIT&nbsp;3;
+
+INSERT&nbsp;INTO&nbsp;float8tmp&nbsp;VALUES&nbsp;('NaN'),&nbsp;('NaN');
+
+SET&nbsp;enable_seqscan=off;
+
+SELECT&nbsp;count(*)&nbsp;FROM&nbsp;float8tmp&nbsp;WHERE&nbsp;a&nbsp;=&nbsp;'NaN';
+
+RESET&nbsp;enable_seqscan;
```
Any&nbsp;thoughts?

Regards,
Man&nbsp;Zeng

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2026-06-18 18:17:12 BUG #19527: Double-Abort Crash in `ResOwnerReleaseOSSLCipher` via `encrypt_iv` with Oversized Input
Previous Message Ayush Tiwari 2026-06-18 14:41:32 Re: BUG #19525: In `contrib/dict_int`, handling a token whose first byte is a null byte causes `pnstrdup()` .