Re: BUG #19031: pg_trgm infinite loop on certain cases
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: washwithcare@gmail.com
Cc: pgsql-bugs@lists.postgresql.org, Nikita Glukhov <glukhov.n.a@gmail.com>,
Alexander Korotkov <aekorotkov@gmail.com>
Date: 2025-08-26T00:54:23Z
Lists: pgsql-bugs
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Put "excludeOnly" GIN scan keys at the end of the scankey array.
- d532069c391a 16.11 landed
- 4a593043eee9 14.20 landed
- 456c6a05d990 17.7 landed
- 3e0f5f00b34b 13.23 landed
- 3a7a3eaaf9fe 18.0 landed
- 34249b3b5847 15.15 landed
- 327b7324d071 19 (unreleased) landed
-
Do CHECK_FOR_INTERRUPTS inside, not before, scanGetItem.
- d17abaea8eda 17.7 landed
- b55068236c5e 19 (unreleased) landed
- b2d71c455f05 13.23 landed
- a9c1b9c1c606 15.15 landed
- a7da746c1177 14.20 landed
- 44c2e5b76c98 18.0 landed
- 25eadfd0fe7b 16.11 landed
Attachments
- 0001-move-CFI-inside-scanGetItem.patch (text/x-diff) patch 0001
- 0002-put-excludeOnly-keys-last.patch (text/x-diff) patch 0002
PG Bug reporting form <noreply@postgresql.org> writes:
> When querying against a column with a gin_trgm_ops index, using <% with a
> string without any trigrams followed by a string with trigrams causes what
> appears to be an infinite loop, and the query cannot be canceled, and the
> process must be restarted in order to kill the long running query.
Thanks for the test case! AFAICT this is a bug in 4b754d6c1
which introduced "excludeOnly" GIN scan keys. There is a comment
in scanGetItem that says
/*
* ginNewScanKey() should never mark the first key as
* excludeOnly.
*/
However, if you look at ginNewScanKey, it's totally not concerned
about avoiding that. In this test case, the first scan key is marked
excludeOnly, and that sends scanGetItem into what seems an infinite
loop.
After reading the comments in that commit, I think what we actually
want is to require excludeOnly scan keys to appear last. The 0002
patch attached modifies ginNewScanKey to re-order the scan keys to
guarantee that, and it fixes this test case.
However, I don't totally understand *why* it fixes the test case.
Especially not after I noted that there's already a test case in
pg_trgm that exercises exactly this situation:
select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
If you put an Assert into ginNewScanKey that the first scan key
isn't excludeOnly (instead of the re-sort), it fails on that query.
So why do we not see an infinite loop for that test case? I don't
really understand the GIN code well enough to figure out what is
the difference.
In the meantime, the 0001 patch attached moves the
CHECK_FOR_INTERRUPTS() call in gingetbitmap to be inside the loop in
scanGetItem, so that it's able to respond to a query cancel request in
this situation. I think we'd better do that even after fixing the
present bug.
regards, tom lane