GIN disagrees with seq scan when NOT and AND operators are combined
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
This thread has been committed, so CI has stopped here. Anything below is the last result it produced.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t254129psql -h localhost -U postgresBuilt from patchset v2 (message #2), October 12, 2026 at 08:57 PM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t254129_2 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t254129_2 && git checkout t254129_2Patchset v2 (message #2) is on t254129_2
Hi all,
When working on pg_lion (https://github.com/cgkanchi/pg_lion), I stumbled
upon a bug where GIN returns fewer rows when multiple ! operators are
specified. I was able to repro this on all versions from 16 to trunk.
Repro:
```
postgres=# CREATE TABLE t (j jsonb);
INSERT INTO t VALUES ('{"a": 1, "b": 10}'), ('{"a": 2, "b": 10}'), ('{"a":
2, "b": 20}');
CREATE TABLE
INSERT 0 3
postgres=# SELECT j FROM t WHERE j @@ '!(!($.a == 1) && $.b == 20)';
j
-------------------
{"a": 1, "b": 10}
{"a": 2, "b": 10}
(2 rows)
postgres=# create index on t using gin(j);
CREATE INDEX
postgres=# SELECT j FROM t WHERE j @@ '!(!($.a == 1) && $.b == 20)';
j
-------------------
{"a": 1, "b": 10}
(1 row)
```
Chinmay Kanchi <cgkanchi@gmail.com> writes:
When working on pg_lion (https://github.com/cgkanchi/pg_lion), I stumbled
upon a bug where GIN returns fewer rows when multiple ! operators are
specified. I was able to repro this on all versions from 16 to trunk.
Thanks for the report. (For the archives' sake, note this repro
requires "set enable_seqscan = 0", else you get a seqscan plan
and no bug.)
I'm not too familiar with this code, but it looks like
extract_jsp_bool_expr concludes that !($.b == 20) is not supported
as a GIN scan condition, and then the next recursion level up does
the wrong thing with the negated && condition. The attached quick
hack seems to fix it. I didn't look around for other instances
of the same thinko, but there might be some.
regards, tom lane