| From: | Rui Zhao <zhaorui126(at)gmail(dot)com> |
|---|---|
| To: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> |
| Cc: | Chinmay Kanchi <cgkanchi(at)gmail(dot)com>, pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Subject: | Re: GIN (JSONPath) checks equality only on the first node of each operand |
| Date: | 2026-10-20 06:59:13 |
| Message-ID: | CAHWVJhEUf0z339+bntyPkBX=ysN2iqXqofRQ7jHjEy98_KeoHw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
Hi Tom,
Thanks for the fixes. I think v1 covers both reported problems.
While reading v1, I saw that extract_jsp_query() sends @@ expressions
to extract_jsp_bool_expr(). That function switches on node types such
as jpiAnd and jpiEqual. I wondered how it handles a predicate followed
by a method, so I tried ($.age == 25).size() in GDB. jsp->type was still
jpiEqual, with $.age on the left, 25 on the right, and size() as its
next item.
In an SQL expression tree, a function call would have a FuncExpr node
around its argument. Here, jsonpath_gram.y builds a list of the
predicate and accessor:
accessor_expr:
path_primary { $$ = list_make1($1); }
| '(' expr ')' accessor_op { $$ = list_make2($2, $4); }
| '(' predicate ')' accessor_op { $$ = list_make2($2, $4); }
| accessor_expr accessor_op { $$ = lappend($1, $2); }
;
expr:
accessor_expr { $$ = makeItemList($1); }
makeItemList() links ($.age == 25) and size() through next. The head
remains jpiEqual, but extract_jsp_bool_expr() ignores its next item.
V1 checks for following items on the literal operand, but not on the
predicate itself.
Using the existing testjsonb data from jsonb.sql:
SELECT count(*) FROM testjsonb
WHERE j @@ '($.age == 25).size().boolean()';
v1 v1 + 0001
Sequential scan 1012 1012
GIN jsonb_ops 2 1012
GIN jsonb_path_ops 2 1012
The equality takes this branch:
else if (jspIsScalar(right_item.type) &&
!jspHasNext(&right_item))
{
scalar_item = &right_item;
path_item = &left_item;
}
left_item is $.age, and right_item is the constant 25 with no next item.
The function therefore extracts $.age == 25 as the index condition,
ignoring the methods attached to the equality itself.
In this case, .size() returns 1 for both true and false, and .boolean()
turns that into true. All 1012 rows should match, but GIN returns only
the two rows with age = 25.
To be honest, this is a corner case, and I haven't found a more common
way to trigger it. It seems unlikely to occur in normal queries.
0001 adds this check at the start of extract_jsp_bool_expr():
if (jspHasNext(jsp))
return NULL;
It is on top of v1 and adds regression tests.
All 239 core regression tests passed.
Regards,
Rui
| Attachment | Content-Type | Size |
|---|---|---|
| nocfbot-0001-Fix-GIN-quals-for-jsonpath-predicates-followed-by-me.patch | application/octet-stream | 4.2 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Michael Paquier | 2026-10-20 07:12:59 | Re: BUG #19763: ManualBug2 NULL pointer dereference in make_build_data via examine_expression bypass of lookup_var_a |
| Previous Message | Fujii Masao | 2026-10-20 06:16:52 | Re: BUG #19644: byteaout, float8out and float4out are marked IMMUTABLE but depend on GUCs |