| From: | John Naylor <johncnaylorls(at)gmail(dot)com> |
|---|---|
| To: | pgsql-bugs <pgsql-bugs(at)lists(dot)postgresql(dot)org> |
| Subject: | spg_quad_inner_consistent() doesn't check all four box corners |
| Date: | 2026-10-29 08:37:37 |
| Message-ID: | CANWCAZZZpkwrX0kC4Jo6KM27J6dyBdCDir-PbjEYAS06r=4-ag@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
In the thread for Bug #19597, I wrote:
> I may have found 3 other possible bugs involving SP-Gist in the course
> of investigating this, so I will share those in separate threads when
> I return to this topic.
Here's the first of these. All three were found with fuzzing. This
wrong-result repro piggybacks on the regression test from the above
bug fix:
create table spgist_quad_fp_tbl(p point);
insert into spgist_quad_fp_tbl select point(i, 5) from
generate_series(1, 300) i;
create index spgist_quad_fp_idx on spgist_quad_fp_tbl using spgist(p);
insert into spgist_quad_fp_tbl values (point(3, 5 + 1e-6));
insert into spgist_quad_fp_tbl values (point(114 - 5e-7, 5 + 1e-6));
insert into spgist_quad_fp_tbl values (point(200, 5 - 5e-6));
set enable_seqscan = off;
select count(*) from spgist_quad_fp_tbl
where p <@ box(point(0, 4.99999), point(400, 4.9999995));
count
-------
0
(1 row)
reset enable_seqscan;
set enable_indexscan = off;
select count(*) from spgist_quad_fp_tbl
where p <@ box(point(0, 4.99999), point(400, 4.9999995));
count
-------
1
(1 row)
reset all;
--
spg_quad_inner_consistent() prunes quadrants that don't contain a
corner of the box. If the box lies well below the centroid and
straddles the y axis, it finds we need to visit quadrants 2 and 3. So
far so good. In the above case, the top edge of the box is within
EPSILON of the centroid. The top right corner goes to quadrant 1, and
the left corners go to quadrant 3. The bottom right corner belongs in
quadrant 2, but the code doesn't actually test that, it tests the
upper left corner again, so it visits quadrants 1 and 3 and skips the
quadrant we need which is 2. The fix is simple:
p = boxQuery->low;
r |= 1 << getQuadrant(centroid, &p);
p.y = boxQuery->high.y;
r |= 1 << getQuadrant(centroid, &p);
p = boxQuery->high;
r |= 1 << getQuadrant(centroid, &p);
- p.x = boxQuery->low.x;
+ p.y = boxQuery->low.y;
r |= 1 << getQuadrant(centroid, &p);
The attached does this and adds a regression test. I'll commit this soon.
--
John Naylor
Amazon Web Services
| Attachment | Content-Type | Size |
|---|---|---|
| v1-0001-Check-all-four-box-corners-in-SP-GiST-quad-tree-s.patch | text/x-patch | 3.3 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Fujii Masao | 2026-10-29 11:47:43 | Re: START_REPLICATION silently truncates an overlong LSN component |
| Previous Message | Narayanan Venkateswaran | 2026-10-29 06:41:05 | Re: BUG #19800: Wrong results: self-join elimination drops an ORDER BY sort key with GROUPING SETS / CUBE / ROLLUP |