GIN jsonb_ops misses root strings in strict jsonpath queries

From: Rui Zhao <zhaorui126(at)gmail(dot)com>
To: PostgreSQL mailing lists <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Subject: GIN jsonb_ops misses root strings in strict jsonpath queries
Date: 2026-10-20 15:43:41
Message-ID: CAHWVJhHH0k3PxWmS==V1p_PONOMUaSm6LjUV487fwnOqd0jTQw@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hi,

A GIN jsonb_ops scan can miss a root string when a jsonpath comparison
uses strict mode. I reproduced this on master at e75fcc9867f.

Using the existing test_jsonb data in jsonb.sql, which includes the
root string "a scalar":

SELECT test_json FROM test_jsonb
WHERE test_json @@ 'strict $ == "a scalar"';
-- "a scalar"

SELECT test_json FROM test_jsonb
WHERE test_json @? 'strict $ ? (@ == "a scalar")';
-- "a scalar"

CREATE INDEX test_jsonb_idx ON test_jsonb USING gin (test_json);
SET enable_seqscan = off;

SELECT test_json FROM test_jsonb
WHERE test_json @@ 'strict $ == "a scalar"';
-- 0 rows

SELECT test_json FROM test_jsonb
WHERE test_json @? 'strict $ ? (@ == "a scalar")';
-- 0 rows

The index stores root strings with JGINFLAG_KEY. Internally, a root
scalar is wrapped in an array. JsonbValueToJsonb() does this inside
its IsAJsonbScalar(val) branch:

scalarArray.type = jbvArray;
scalarArray.val.array.rawScalar = true;
scalarArray.val.array.nElems = 1;

pushJsonbValue(&pstate, WJB_BEGIN_ARRAY, &scalarArray); /* [ */
pushJsonbValue(&pstate, WJB_ELEM, val); /* original value */
pushJsonbValue(&pstate, WJB_END_ARRAY, NULL); /* ] */

gin_extract_jsonb() therefore sees WJB_ELEM and stores the root string
in the GIN index with the JGINFLAG_KEY marker.
But when processing the SQL query, jsonb_ops__extract_nodes() sets
key_entry to GIN_FALSE for the root in strict mode. That searches for
JGINFLAG_STR instead, so it cannot find the matching root string.

The attached patch changes that root case to GIN_TRUE. Both queries
then return "a scalar" using the existing index; no REINDEX is needed.
This bug affects only strict-mode queries using jsonb_ops.

The patch adds the queries above to jsonb.sql. make check passed all
239 tests. Without the code fix, only the two new indexed queries fail.

Regards,
Rui

Attachment Content-Type Size
v1-0001-Fix-GIN-lookups-for-root-strings-in-strict-jsonpa.patch application/octet-stream 3.8 KB

Browse pgsql-bugs by date

  From Date Subject
Next Message Fujii Masao 2026-10-20 16:05:23 Re: BUG #19644: byteaout, float8out and float4out are marked IMMUTABLE but depend on GUCs
Previous Message Michael Ries 2026-10-20 15:36:44 Re: Bug in statement trigger for MERGE operations that move rows between partitions