From 8796b2122a9b04ea4e7c36fcba67403c4a764877 Mon Sep 17 00:00:00 2001 From: ZhouXing19 Date: Mon, 3 Nov 2025 23:12:39 +0000 Subject: [PATCH] sql/jsonpath: unwrap array with root key for index acceleration Fixes: #156741 Previously, we didn't consider the case where the queried JSON is an array and the root key can unwrap one layer of the array. For example: ``` INSERT INTO json_tab VALUES (1,'[{"b": {"x": "y"}, "a": "x"}, null]'); CREATE INVERTED INDEX foo_inv ON json_tab(b); SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.b'); ``` This previously returned an empty result but should return 1. This commit fixes the issue by adding array-unwrapping for the root key (`$`). Release note (bug fix): Fix JSON path index acceleration with JSON array objects. Only 25.4.0 releases are affected. --- .../jsonb_path_exists_index_acceleration | 25 ++++ .../execbuilder/testdata/jsonb_path_query | 44 +++--- pkg/sql/opt/xform/testdata/rules/select | 128 +++++++++++++++++- pkg/util/jsonpath/path.go | 69 ++++------ 4 files changed, 195 insertions(+), 71 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/jsonb_path_exists_index_acceleration b/pkg/sql/logictest/testdata/logic_test/jsonb_path_exists_index_acceleration index 5d74a8c45649..3094d01e2247 100644 --- a/pkg/sql/logictest/testdata/logic_test/jsonb_path_exists_index_acceleration +++ b/pkg/sql/logictest/testdata/logic_test/jsonb_path_exists_index_acceleration @@ -557,6 +557,31 @@ SELECT a FROM json_tab@primary WHERE jsonb_path_exists(b, '$.a ? (@.b == $x)', ' statement error index "foo_inv" is inverted and cannot be used for this query SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a ? (@.b == $x)', '{"x": "c"}') ORDER BY a; +statement ok +INSERT INTO json_tab VALUES +(20,'[{"b": {"x": "y"}, "a": "x"}, null]'), +(21,'[[{"b": {"x": "y"}, "a": "x"}], null]'); + +query I +SELECT a FROM json_tab@primary WHERE jsonb_path_exists(b, '$."b"[*]'); +---- +20 + +query I +SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.b'); +---- +20 + +query I +SELECT a FROM json_tab@primary WHERE jsonb_path_exists(b, '$."b"[*]'); +---- +20 + +query I +SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$."b"[*]'); +---- +20 + subtest anykey statement ok diff --git a/pkg/sql/opt/exec/execbuilder/testdata/jsonb_path_query b/pkg/sql/opt/exec/execbuilder/testdata/jsonb_path_query index f72521a2bd82..c689d9160166 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/jsonb_path_query +++ b/pkg/sql/opt/exec/execbuilder/testdata/jsonb_path_query @@ -65,12 +65,12 @@ vectorized: true │ └── • inverted filter │ inverted column: b_inverted_key - │ num spans: 2 + │ num spans: 4 │ └── • scan missing stats table: json_tab@foo_inv - spans: 2 spans + spans: 4 spans query T EXPLAIN SELECT jsonb_path_query(b, '$.a.b.c') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b.c') ORDER BY a; @@ -88,12 +88,12 @@ vectorized: true │ └── • inverted filter │ inverted column: b_inverted_key - │ num spans: 4 + │ num spans: 8 │ └── • scan missing stats table: json_tab@foo_inv - spans: 4 spans + spans: 8 spans query T EXPLAIN SELECT a, jsonb_path_query(b, '$.a[*].b') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a[*].b') ORDER BY a; @@ -111,12 +111,12 @@ vectorized: true │ └── • inverted filter │ inverted column: b_inverted_key - │ num spans: 3 + │ num spans: 6 │ └── • scan missing stats table: json_tab@foo_inv - spans: 3 spans + spans: 6 spans query T EXPLAIN SELECT a, jsonb_path_query(b, '$.a') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a') ORDER BY a; @@ -134,12 +134,12 @@ vectorized: true │ └── • inverted filter │ inverted column: b_inverted_key - │ num spans: 1 + │ num spans: 2 │ └── • scan missing stats table: json_tab@foo_inv - spans: 1 span + spans: 2 spans # If inverted index is not hinted, we would scan the whole table. query T kvtrace @@ -152,55 +152,55 @@ Scan /Table/106/{1-2} query T kvtrace SELECT jsonb_path_query(b, '$.a.b') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} Scan /Table/106/1/3/0, /Table/106/1/4/0, /Table/106/1/6/0, /Table/106/1/7/0, /Table/106/1/8/0, /Table/106/1/9/0, /Table/106/1/11/0, /Table/106/1/12/0, /Table/106/1/13/0, /Table/106/1/14/0, /Table/106/1/15/0, /Table/106/1/16/0 query T kvtrace SELECT jsonb_path_query(b, '$.a[*].b') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a[*].b') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} Scan /Table/106/1/3/0, /Table/106/1/4/0, /Table/106/1/6/0, /Table/106/1/7/0, /Table/106/1/8/0, /Table/106/1/9/0, /Table/106/1/11/0, /Table/106/1/12/0, /Table/106/1/13/0, /Table/106/1/14/0, /Table/106/1/15/0, /Table/106/1/16/0 query T kvtrace SELECT jsonb_path_query(b, '$.a[*][*].b') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a[*][*].b') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/Arr/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} Scan /Table/106/1/3/0, /Table/106/1/4/0, /Table/106/1/6/0, /Table/106/1/7/0, /Table/106/1/8/0, /Table/106/1/9/0, /Table/106/1/11/0, /Table/106/1/12/0, /Table/106/1/13/0, /Table/106/1/14/0, /Table/106/1/15/0, /Table/106/1/16/0 query T kvtrace SELECT jsonb_path_query(b, '$.a.b[*].c') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b[*].c') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/"b"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/"b"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/"b"/Arr/}, /Table/106/2/{???-"a"/"b"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/"b"/Arr/Arr/}, /Table/106/2/{???-"a"/"b"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/"b"/Arr/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/"b"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/"b"/Arr/}, /Table/106/2/{???-Arr/"a"/"b"/Arr/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/"b"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/"b"/Arr/}, /Table/106/2/{???-"a"/Arr/"b"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/"b"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/"b"/Arr/}, /Table/106/2/{???-"a"/"b"/Arr/Arr/Arr/}, /Table/106/2/{???-"a"/"b"/Arr/Arr/}, /Table/106/2/{???-"a"/"b"/Arr/} Scan /Table/106/1/6/0 query T kvtrace SELECT jsonb_path_query(b, '$.a.b ? (@.x.y.z == "y")') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.z == "y")') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} Scan /Table/106/1/11/0 query T kvtrace SELECT jsonb_path_query(b, '$.a.b ? (@.x.y.ztrue == true)') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.ztrue == true)') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"ztrue"/Arr/{True-False} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/Arr/{True-False} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/"ztrue"/{True-False} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/Arr/{True-False} Scan /Table/106/1/12/0 query T kvtrace SELECT jsonb_path_query(b, '$.a.b ? (@.x.y.zfalse == false)') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.zfalse == false)') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"zfalse"/{False-"\f"}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"zfalse"/Arr/{False-"\f"} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/"b"/"x"/"y"/"zfalse"/{False-"\f"}, /Table/106/2/"a"/"b"/"x"/"y"/"zfalse"/Arr/{False-"\f"} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zfalse"/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/"zfalse"/{False-"\f"} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"zfalse"/Arr/{False-"\f"}, /Table/106/2/"a"/"b"/"x"/"y"/"zfalse"/{False-"\f"}, /Table/106/2/"a"/"b"/"x"/"y"/"zfalse"/Arr/{False-"\f"} Scan /Table/106/1/13/0 query T kvtrace SELECT jsonb_path_query(b, '$.a.b ? (@.x.y.zint == 10)') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.zint == 10)') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"zint"/1E+1{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"zint"/Arr/1E+1{-/PrefixEnd} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"zint"/Arr/1E+1{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"zint"/1E+1{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"zint"/Arr/1E+1{-/PrefixEnd} Scan /Table/106/1/14/0 query T kvtrace SELECT jsonb_path_query(b, '$.a.b ? (@.x.y.znull == null)') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.znull == null)') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"znull"/{NULL-!NULL}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"znull"/Arr/{NULL-!NULL} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/"b"/"x"/"y"/"znull"/{NULL-!NULL}, /Table/106/2/"a"/"b"/"x"/"y"/"znull"/Arr/{NULL-!NULL} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"znull"/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/"znull"/{NULL-!NULL} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"znull"/Arr/{NULL-!NULL}, /Table/106/2/"a"/"b"/"x"/"y"/"znull"/{NULL-!NULL}, /Table/106/2/"a"/"b"/"x"/"y"/"znull"/Arr/{NULL-!NULL} Scan /Table/106/1/15/0, /Table/106/1/16/0 # Multiple jsonb_path_exists in the filter. For all select clause to be @@ -214,30 +214,30 @@ Scan /Table/106/{1-2} query T kvtrace SELECT a, jsonb_path_query(b, '$.a.b ? (@.x.y.z == "y")'), jsonb_path_query(b, '$.a.b ? (@.x.y.ztrue == true)') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.z == "y")') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} Scan /Table/106/1/11/0 query T kvtrace SELECT a, jsonb_path_query(b, '$.a.b ? (@.x.y.z == "y")'), jsonb_path_query(b, '$.a.b ? (@.x.y.ztrue == true)') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b ? (@.x.y.z == "y")') OR jsonb_path_exists(b, '$.a.b ? (@.x.y.ztrue == true)') ORDER BY a; ---- -Scan /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"ztrue"/{True-False} ... /Table/106/2/"a"/"b"/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/Arr/{True-False} +Scan /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/Arr/"y"/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/Arr/"ztrue"/Arr/{True-False}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/"y"{-/PrefixEnd}, /Table/106/2/Arr/"a"/Arr/"b"/Arr/Arr/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd} ... /Table/106/2/"a"/"b"/"x"/"y"/"z"/Arr/"y"{-/PrefixEnd}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/{True-False}, /Table/106/2/"a"/"b"/"x"/"y"/"ztrue"/Arr/{True-False} Scan /Table/106/1/11/0, /Table/106/1/12/0 # Test with concatenation of different json path expressions with AND in the filter. query T kvtrace SELECT a, jsonb_path_query(b, '$.a.d') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.d') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} Scan /Table/106/1/3/0, /Table/106/1/6/0, /Table/106/1/10/0 query T kvtrace SELECT a, jsonb_path_query(b, '$.a.b') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/} Scan /Table/106/1/3/0, /Table/106/1/4/0, /Table/106/1/6/0, /Table/106/1/7/0, /Table/106/1/8/0, /Table/106/1/9/0, /Table/106/1/11/0, /Table/106/1/12/0, /Table/106/1/13/0, /Table/106/1/14/0, /Table/106/1/15/0, /Table/106/1/16/0 query T kvtrace SELECT a, jsonb_path_query(b, '$.a.b'), jsonb_path_query(b, '$.a.d') FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b') AND jsonb_path_exists(b, '$.a.d') ORDER BY a; ---- -Scan /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/}, /Table/106/2/{???-"a"/Arr/} +Scan /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-Arr/"a"/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/Arr/}, /Table/106/2/{???-"a"/Arr/}, /Table/106/2/{???-"a"/Arr/} Scan /Table/106/1/3/0, /Table/106/1/6/0 diff --git a/pkg/sql/opt/xform/testdata/rules/select b/pkg/sql/opt/xform/testdata/rules/select index 5bb5e55e380a..a5d25d85a683 100644 --- a/pkg/sql/opt/xform/testdata/rules/select +++ b/pkg/sql/opt/xform/testdata/rules/select @@ -13590,6 +13590,8 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [???, Arr/"a"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/) │ ├── [???, "a"/Arr/Arr/) │ └── [???, "a"/Arr/) ├── key: (1) @@ -13597,6 +13599,8 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [???, Arr/"a"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/) ├── [???, "a"/Arr/Arr/) └── [???, "a"/Arr/) @@ -13608,7 +13612,7 @@ memo (optimized, ~11KB, required=[presentation: k:1]) ├── G1: (project G2 G3 k) (project G4 G3 k) │ └── [presentation: k:1] │ ├── best: (project G4 G3 k) - │ └── cost: 113329.84 + │ └── cost: 113337.84 ├── G2: (select G5 G6) (index-join G4 b,cols=(1,4)) │ └── [] │ ├── best: (select G5 G6) @@ -13617,7 +13621,7 @@ memo (optimized, ~11KB, required=[presentation: k:1]) ├── G4: (inverted-filter G7 j_inverted_key) │ └── [] │ ├── best: (inverted-filter G7 j_inverted_key) - │ └── cost: 111663.19 + │ └── cost: 111671.19 ├── G5: (scan b,cols=(1,4)) │ └── [] │ ├── best: (scan b,cols=(1,4)) @@ -13626,7 +13630,7 @@ memo (optimized, ~11KB, required=[presentation: k:1]) ├── G7: (scan b@j_inv_idx,inverted,cols=(1,9),constrained inverted) │ └── [] │ ├── best: (scan b@j_inv_idx,inverted,cols=(1,9),constrained inverted) - │ └── cost: 110696.58 + │ └── cost: 110704.58 ├── G8: (function G9 jsonb_path_exists) ├── G9: (scalar-list G10 G11) ├── G10: (variable j) @@ -13643,12 +13647,16 @@ project ├── columns: k:1!null ├── inverted expression: /9 │ ├── tight: true, unique: false - │ └── union spans: [???, Arr/) + │ └── union spans + │ ├── [???, Arr/Arr/) + │ └── [???, Arr/) ├── key: (1) └── scan b@j_inv_idx,inverted ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 - └── spans: [???, Arr/) + └── spans + ├── [???, Arr/Arr/) + └── [???, Arr/) opt expect=GenerateInvertedIndexScans SELECT k FROM b WHERE jsonb_path_exists(j, '$.a[*]') @@ -13661,12 +13669,16 @@ project ├── columns: k:1!null ├── inverted expression: /9 │ ├── tight: true, unique: false - │ └── union spans: [???, Arr/) + │ └── union spans + │ ├── [???, Arr/Arr/) + │ └── [???, Arr/) ├── key: (1) └── scan b@j_inv_idx,inverted ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 - └── spans: [???, Arr/) + └── spans + ├── [???, Arr/Arr/) + └── [???, Arr/) opt expect=GenerateInvertedIndexScans SELECT k FROM b WHERE jsonb_path_exists(j, '$.a[*].b') @@ -13680,6 +13692,9 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [???, Arr/"a"/Arr/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/) │ ├── [???, "a"/Arr/Arr/Arr/) │ ├── [???, "a"/Arr/Arr/) │ └── [???, "a"/Arr/) @@ -13688,6 +13703,9 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [???, Arr/"a"/Arr/Arr/Arr/) + ├── [???, Arr/"a"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/) ├── [???, "a"/Arr/Arr/Arr/) ├── [???, "a"/Arr/Arr/) └── [???, "a"/Arr/) @@ -13704,6 +13722,12 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/) + │ ├── [???, Arr/"a"/Arr/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/"b"/Arr/) + │ ├── [???, Arr/"a"/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/"b"/Arr/) │ ├── [???, "a"/Arr/Arr/"b"/Arr/Arr/) │ ├── [???, "a"/Arr/Arr/"b"/Arr/) │ ├── [???, "a"/Arr/"b"/Arr/Arr/) @@ -13715,6 +13739,12 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/) + ├── [???, Arr/"a"/Arr/"b"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/"b"/Arr/) + ├── [???, Arr/"a"/"b"/Arr/Arr/) + ├── [???, Arr/"a"/"b"/Arr/) ├── [???, "a"/Arr/Arr/"b"/Arr/Arr/) ├── [???, "a"/Arr/Arr/"b"/Arr/) ├── [???, "a"/Arr/"b"/Arr/Arr/) @@ -13734,6 +13764,18 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [???, Arr/"a"/Arr/Arr/Arr/"b"/Arr/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/Arr/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/Arr/"b"/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/) + │ ├── [???, Arr/"a"/Arr/"b"/Arr/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/Arr/"b"/Arr/) + │ ├── [???, Arr/"a"/"b"/Arr/Arr/Arr/) + │ ├── [???, Arr/"a"/"b"/Arr/Arr/) + │ ├── [???, Arr/"a"/"b"/Arr/) │ ├── [???, "a"/Arr/Arr/Arr/"b"/Arr/Arr/Arr/) │ ├── [???, "a"/Arr/Arr/Arr/"b"/Arr/Arr/) │ ├── [???, "a"/Arr/Arr/Arr/"b"/Arr/) @@ -13751,6 +13793,18 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [???, Arr/"a"/Arr/Arr/Arr/"b"/Arr/Arr/Arr/) + ├── [???, Arr/"a"/Arr/Arr/Arr/"b"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/Arr/Arr/"b"/Arr/) + ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/Arr/Arr/) + ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/Arr/"b"/Arr/) + ├── [???, Arr/"a"/Arr/"b"/Arr/Arr/Arr/) + ├── [???, Arr/"a"/Arr/"b"/Arr/Arr/) + ├── [???, Arr/"a"/Arr/"b"/Arr/) + ├── [???, Arr/"a"/"b"/Arr/Arr/Arr/) + ├── [???, Arr/"a"/"b"/Arr/Arr/) + ├── [???, Arr/"a"/"b"/Arr/) ├── [???, "a"/Arr/Arr/Arr/"b"/Arr/Arr/Arr/) ├── [???, "a"/Arr/Arr/Arr/"b"/Arr/Arr/) ├── [???, "a"/Arr/Arr/Arr/"b"/Arr/) @@ -13776,6 +13830,12 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [Arr/"a"/Arr/Arr/"x"/"y", Arr/"a"/Arr/Arr/"x"/"y"] + │ ├── [Arr/"a"/Arr/Arr/"x"/Arr/"y", Arr/"a"/Arr/Arr/"x"/Arr/"y"] + │ ├── [Arr/"a"/Arr/"x"/"y", Arr/"a"/Arr/"x"/"y"] + │ ├── [Arr/"a"/Arr/"x"/Arr/"y", Arr/"a"/Arr/"x"/Arr/"y"] + │ ├── [Arr/"a"/"x"/"y", Arr/"a"/"x"/"y"] + │ ├── [Arr/"a"/"x"/Arr/"y", Arr/"a"/"x"/Arr/"y"] │ ├── ["a"/Arr/Arr/"x"/"y", "a"/Arr/Arr/"x"/"y"] │ ├── ["a"/Arr/Arr/"x"/Arr/"y", "a"/Arr/Arr/"x"/Arr/"y"] │ ├── ["a"/Arr/"x"/"y", "a"/Arr/"x"/"y"] @@ -13787,6 +13847,12 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [Arr/"a"/Arr/Arr/"x"/"y", Arr/"a"/Arr/Arr/"x"/"y"] + ├── [Arr/"a"/Arr/Arr/"x"/Arr/"y", Arr/"a"/Arr/Arr/"x"/Arr/"y"] + ├── [Arr/"a"/Arr/"x"/"y", Arr/"a"/Arr/"x"/"y"] + ├── [Arr/"a"/Arr/"x"/Arr/"y", Arr/"a"/Arr/"x"/Arr/"y"] + ├── [Arr/"a"/"x"/"y", Arr/"a"/"x"/"y"] + ├── [Arr/"a"/"x"/Arr/"y", Arr/"a"/"x"/Arr/"y"] ├── ["a"/Arr/Arr/"x"/"y", "a"/Arr/Arr/"x"/"y"] ├── ["a"/Arr/Arr/"x"/Arr/"y", "a"/Arr/Arr/"x"/Arr/"y"] ├── ["a"/Arr/"x"/"y", "a"/Arr/"x"/"y"] @@ -13806,6 +13872,12 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [Arr/"a"/Arr/Arr/"x"/123, Arr/"a"/Arr/Arr/"x"/123] + │ ├── [Arr/"a"/Arr/Arr/"x"/Arr/123, Arr/"a"/Arr/Arr/"x"/Arr/123] + │ ├── [Arr/"a"/Arr/"x"/123, Arr/"a"/Arr/"x"/123] + │ ├── [Arr/"a"/Arr/"x"/Arr/123, Arr/"a"/Arr/"x"/Arr/123] + │ ├── [Arr/"a"/"x"/123, Arr/"a"/"x"/123] + │ ├── [Arr/"a"/"x"/Arr/123, Arr/"a"/"x"/Arr/123] │ ├── ["a"/Arr/Arr/"x"/123, "a"/Arr/Arr/"x"/123] │ ├── ["a"/Arr/Arr/"x"/Arr/123, "a"/Arr/Arr/"x"/Arr/123] │ ├── ["a"/Arr/"x"/123, "a"/Arr/"x"/123] @@ -13817,6 +13889,12 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [Arr/"a"/Arr/Arr/"x"/123, Arr/"a"/Arr/Arr/"x"/123] + ├── [Arr/"a"/Arr/Arr/"x"/Arr/123, Arr/"a"/Arr/Arr/"x"/Arr/123] + ├── [Arr/"a"/Arr/"x"/123, Arr/"a"/Arr/"x"/123] + ├── [Arr/"a"/Arr/"x"/Arr/123, Arr/"a"/Arr/"x"/Arr/123] + ├── [Arr/"a"/"x"/123, Arr/"a"/"x"/123] + ├── [Arr/"a"/"x"/Arr/123, Arr/"a"/"x"/Arr/123] ├── ["a"/Arr/Arr/"x"/123, "a"/Arr/Arr/"x"/123] ├── ["a"/Arr/Arr/"x"/Arr/123, "a"/Arr/Arr/"x"/Arr/123] ├── ["a"/Arr/"x"/123, "a"/Arr/"x"/123] @@ -13836,6 +13914,12 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [Arr/"a"/Arr/Arr/"x"/True, Arr/"a"/Arr/Arr/"x"/True] + │ ├── [Arr/"a"/Arr/Arr/"x"/Arr/True, Arr/"a"/Arr/Arr/"x"/Arr/True] + │ ├── [Arr/"a"/Arr/"x"/True, Arr/"a"/Arr/"x"/True] + │ ├── [Arr/"a"/Arr/"x"/Arr/True, Arr/"a"/Arr/"x"/Arr/True] + │ ├── [Arr/"a"/"x"/True, Arr/"a"/"x"/True] + │ ├── [Arr/"a"/"x"/Arr/True, Arr/"a"/"x"/Arr/True] │ ├── ["a"/Arr/Arr/"x"/True, "a"/Arr/Arr/"x"/True] │ ├── ["a"/Arr/Arr/"x"/Arr/True, "a"/Arr/Arr/"x"/Arr/True] │ ├── ["a"/Arr/"x"/True, "a"/Arr/"x"/True] @@ -13847,6 +13931,12 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [Arr/"a"/Arr/Arr/"x"/True, Arr/"a"/Arr/Arr/"x"/True] + ├── [Arr/"a"/Arr/Arr/"x"/Arr/True, Arr/"a"/Arr/Arr/"x"/Arr/True] + ├── [Arr/"a"/Arr/"x"/True, Arr/"a"/Arr/"x"/True] + ├── [Arr/"a"/Arr/"x"/Arr/True, Arr/"a"/Arr/"x"/Arr/True] + ├── [Arr/"a"/"x"/True, Arr/"a"/"x"/True] + ├── [Arr/"a"/"x"/Arr/True, Arr/"a"/"x"/Arr/True] ├── ["a"/Arr/Arr/"x"/True, "a"/Arr/Arr/"x"/True] ├── ["a"/Arr/Arr/"x"/Arr/True, "a"/Arr/Arr/"x"/Arr/True] ├── ["a"/Arr/"x"/True, "a"/Arr/"x"/True] @@ -13866,6 +13956,12 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [Arr/"a"/Arr/Arr/"x"/False, Arr/"a"/Arr/Arr/"x"/False] + │ ├── [Arr/"a"/Arr/Arr/"x"/Arr/False, Arr/"a"/Arr/Arr/"x"/Arr/False] + │ ├── [Arr/"a"/Arr/"x"/False, Arr/"a"/Arr/"x"/False] + │ ├── [Arr/"a"/Arr/"x"/Arr/False, Arr/"a"/Arr/"x"/Arr/False] + │ ├── [Arr/"a"/"x"/False, Arr/"a"/"x"/False] + │ ├── [Arr/"a"/"x"/Arr/False, Arr/"a"/"x"/Arr/False] │ ├── ["a"/Arr/Arr/"x"/False, "a"/Arr/Arr/"x"/False] │ ├── ["a"/Arr/Arr/"x"/Arr/False, "a"/Arr/Arr/"x"/Arr/False] │ ├── ["a"/Arr/"x"/False, "a"/Arr/"x"/False] @@ -13877,6 +13973,12 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [Arr/"a"/Arr/Arr/"x"/False, Arr/"a"/Arr/Arr/"x"/False] + ├── [Arr/"a"/Arr/Arr/"x"/Arr/False, Arr/"a"/Arr/Arr/"x"/Arr/False] + ├── [Arr/"a"/Arr/"x"/False, Arr/"a"/Arr/"x"/False] + ├── [Arr/"a"/Arr/"x"/Arr/False, Arr/"a"/Arr/"x"/Arr/False] + ├── [Arr/"a"/"x"/False, Arr/"a"/"x"/False] + ├── [Arr/"a"/"x"/Arr/False, Arr/"a"/"x"/Arr/False] ├── ["a"/Arr/Arr/"x"/False, "a"/Arr/Arr/"x"/False] ├── ["a"/Arr/Arr/"x"/Arr/False, "a"/Arr/Arr/"x"/Arr/False] ├── ["a"/Arr/"x"/False, "a"/Arr/"x"/False] @@ -13897,6 +13999,12 @@ project ├── inverted expression: /9 │ ├── tight: true, unique: false │ └── union spans + │ ├── [???, Arr/"a"/Arr/"b") + │ ├── [Arr/"a"/Arr/"b"/PrefixEnd, Arr/"a"/Arr/"b"/Arr) + │ ├── [Arr/"a"/Arr/"b"/Arr/PrefixEnd, Arr/"a"/Arr/Arr/) + │ ├── [???, Arr/"a"/"b") + │ ├── [Arr/"a"/"b"/PrefixEnd, Arr/"a"/"b"/Arr) + │ ├── [Arr/"a"/"b"/Arr/PrefixEnd, Arr/"a"/Arr/) │ ├── [???, "a"/Arr/"b") │ ├── ["a"/Arr/"b"/PrefixEnd, "a"/Arr/"b"/Arr) │ ├── ["a"/Arr/"b"/Arr/PrefixEnd, "a"/Arr/Arr/) @@ -13908,6 +14016,12 @@ project ├── columns: k:1!null j_inverted_key:9!null └── inverted constraint: /9/1 └── spans + ├── [???, Arr/"a"/Arr/"b") + ├── [Arr/"a"/Arr/"b"/PrefixEnd, Arr/"a"/Arr/"b"/Arr) + ├── [Arr/"a"/Arr/"b"/Arr/PrefixEnd, Arr/"a"/Arr/Arr/) + ├── [???, Arr/"a"/"b") + ├── [Arr/"a"/"b"/PrefixEnd, Arr/"a"/"b"/Arr) + ├── [Arr/"a"/"b"/Arr/PrefixEnd, Arr/"a"/Arr/) ├── [???, "a"/Arr/"b") ├── ["a"/Arr/"b"/PrefixEnd, "a"/Arr/"b"/Arr) ├── ["a"/Arr/"b"/Arr/PrefixEnd, "a"/Arr/Arr/) diff --git a/pkg/util/jsonpath/path.go b/pkg/util/jsonpath/path.go index f27d4e3eb4bf..7439ffcc85f9 100644 --- a/pkg/util/jsonpath/path.go +++ b/pkg/util/jsonpath/path.go @@ -452,38 +452,38 @@ const spanThreshold = 10_000 // currentIndex: 0, finalKeyIndex: 3 (last Key is "[?(@.driver == "Piastri")]") // // Iteration 0 (Root component ($)): +// - Consider both the situations of object and array at root level. +// > encoded_json_prefix -> encoded_obj_json_prefix +// > encoded_json_prefix + array_marker -> encoded_arr_json_prefix // - Skip Root, advance to currentIndex=1 // - Recurse with same prefixBytes // // Iteration 1 (Key "f1"): -// - Build object prefix: encoded_json_prefix + "f1" -> f1_obj_prefix -// - Build array prefix: encoded_json_prefix + "f1" + array_marker -> f1_arr_prefix -// - Recurse with prefixBytes: [f1_obj_prefix, f1_arr_prefix], currentIndex=2 +// - Build object prefix: +// > encoded_obj_json_prefix + "f1" -> obj_f1_obj_prefix +// > encoded_arr_json_prefix + "f1" -> arr_f1_obj_prefix +// - Build array prefix: +// > encoded_obj_json_prefix + "f1" + array_marker -> obj_f1_arr_prefix +// > encoded_arr_json_prefix + "f1" + array_marker -> arr_f1_arr_prefix +// - Recurse with prefixBytes: [obj_f1_obj_prefix, arr_f1_obj_prefix, obj_f1_arr_prefix, arr_f1_arr_prefix], currentIndex=2 // // Iteration 2 (Key "mclaren"): -// - f1_obj_prefix + "mclaren" -> f1_obj_mclaren_obj_prefix -// - f1_arr_prefix + "mclaren" -> f1_arr_mclaren_obj_prefix -// - f1_obj_prefix + "mclaren" + array_marker -> f1_obj_mclaren_arr_prefix -// - f1_arr_prefix + "mclaren" + array_marker -> f1_arr_mclaren_arr_prefix -// - Recurse with prefixBytes: -// > f1_obj_mclaren_obj_prefix -// > f1_arr_mclaren_obj_prefix -// > f1_obj_mclaren_arr_prefix -// > f1_arr_mclaren_arr_prefix +// - obj_f1_obj_prefix + "mclaren" -> obj_f1_obj_mclaren_obj_prefix +// - arr_f1_obj_prefix + "mclaren" -> arr_f1_obj_mclaren_obj_prefix +// - obj_f1_arr_prefix + "mclaren" -> obj_f1_arr_mclaren_obj_prefix +// - arr_f1_arr_prefix + "mclaren" -> arr_f1_arr_mclaren_obj_prefix +// - obj_f1_obj_prefix + "mclaren" + array_marker -> obj_f1_obj_mclaren_arr_prefix +// - arr_f1_obj_prefix + "mclaren" + array_marker -> arr_f1_obj_mclaren_arr_prefix +// - obj_f1_arr_prefix + "mclaren" + array_marker -> obj_f1_arr_mclaren_arr_prefix +// - arr_f1_arr_prefix + "mclaren" + array_marker -> arr_f1_arr_mclaren_arr_prefix +// - Recurse with 8 prefixBytes above. // - currentIndex=3 // // Iteration 3 (Filter - terminal case): // - We need to add an optional array prefix, since the Filter enables // unwrapping one extra layer of array. -// - Thus we have 8 prefixes now: -// > f1_obj_mclaren_obj_prefix -// > f1_arr_mclaren_obj_prefix -// > f1_obj_mclaren_arr_prefix -// > f1_arr_mclaren_arr_prefix -// > f1_obj_mclaren_obj_prefix_arr -// > f1_arr_mclaren_obj_prefix_arr -// > f1_obj_mclaren_arr_prefix_arr -// > f1_arr_mclaren_arr_prefix_arr +// - Thus we have 16 prefixes now: +// {obj|arr}_f1_{obj|arr}_mclaren_{obj|arr}_{arr} // - Extract left path (@.driver) and right value ("Piastri") // - We now construct the new start and new last key index with the left path // - currentIndex: 0, finalKeyIndex: 2 (last Key is "Piastri") @@ -499,23 +499,8 @@ const spanThreshold = 10_000 // > Iteration 3.2 (Scalar "Piastri" - terminal case): // - We are at terminal, thus generate single value spans with each of // the prefixes built so far + "Piastri". -// - Eventually, we returns the concatenation (OR) of 16 (2^4) spans: -// > f1_obj_mclaren_obj_driver_obj_Piastri -// > f1_arr_mclaren_obj_driver_obj_Piastri -// > f1_obj_mclaren_arr_driver_obj_Piastri -// > f1_arr_mclaren_obj_driver_obj_Piastri -// > f1_obj_mclaren_obj_driver_arr_Piastri -// > f1_arr_mclaren_obj_driver_arr_Piastri -// > f1_obj_mclaren_arr_driver_arr_Piastri -// > f1_arr_mclaren_obj_driver_arr_Piastri -// > f1_obj_mclaren_obj_arr_driver_obj_Piastri -// > f1_arr_mclaren_obj_arr_driver_obj_Piastri -// > f1_obj_mclaren_arr_arr_driver_obj_Piastri -// > f1_arr_mclaren_obj_arr_driver_obj_Piastri -// > f1_obj_mclaren_obj_arr_driver_arr_Piastri -// > f1_arr_mclaren_obj_arr_driver_arr_Piastri -// > f1_obj_mclaren_arr_arr_driver_arr_Piastri -// > f1_arr_mclaren_obj_arr_driver_arr_Piastri +// - Eventually, we returns the concatenation (OR) of 32 (2^5) spans: +// > {obj|arr}_f1_{obj|arr}_mclaren_{obj|arr}_{arr}_driver_{obj|arr}_Piastri func buildInvertedIndexSpans( prefixBytes [][]byte, pathComponents []Path, @@ -639,16 +624,16 @@ func buildInvertedIndexSpans( // Encode as array element: {"key": [...]}. nextPrefixes = append(nextPrefixes, encoding.EncodeArrayAscending(encoding.EncodeJSONKeyStringAscending(prefix[:len(prefix):len(prefix)], keyName, false /* end */))) } - case Wildcard: + case Root, Wildcard: prefixBytesLen := len(prefixBytes) for i := 0; i < prefixBytesLen; i++ { - // Wildcard can unwrap one extra layer of array. + // Wildcard or Root can unwrap one extra layer of array. prefix := prefixBytes[i] prefixBytes = append(prefixBytes, encoding.EncodeArrayAscending(prefix[:len(prefix):len(prefix)])) } nextPrefixes = prefixBytes - case Root, Current: - // For non-Key components, pass through existing prefixes unchanged. + case Current: + // For Current (@), pass through existing prefixes unchanged. nextPrefixes = prefixBytes default: // This is a pattern we don't support for inverted index.