Skip to content

Commit dc26ba0

Browse files
craig[bot]normanchenn
andcommitted
Merge #144385
144385: jsonpath: add support for non-integer array indices r=normanchenn a=normanchenn #### jsonpath: enable disabled parser and logic tests This commit uncomments previously disabled parser and logic tests that were left behind in their respective commits that added the functionality to perform the parsing or evaluation. Release note: None #### jsonpath: add support for non-integer array indices This commit adds support for non-integer array indices, which adds Postgres compatibility in the JSONPath feature set. Non-integer array indices are rounded towards zero before being used as array indices (floor for positive numbers, ceil for negative numbers). Epic: None Release note (sql change): Add support for non-integer array indices in JSONPath queries (ex. `SELECT jsonb_path_query('[1, 2, 3]', '$[2.5]');`). Indices are rounded towards 0. Co-authored-by: Norman Chen <[email protected]>
2 parents 4689b7d + 730ab15 commit dc26ba0

File tree

4 files changed

+125
-44
lines changed

4 files changed

+125
-44
lines changed

pkg/sql/logictest/testdata/logic_test/jsonb_path_query

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,22 +264,25 @@ SELECT jsonb_path_query('[1, 2, 3, 4, 5]', '$[1]');
264264
----
265265
2
266266

267-
# TODO(normanchenn): this will be changed after floats are supported.
268-
statement error pq: jsonpath array subscript is not a single numeric value
269-
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[0.99]')
267+
query T
268+
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[0.99]');
269+
----
270+
10
270271

271-
# TODO(normanchenn): this will be changed after floats are supported.
272-
statement error pq: jsonpath array subscript is not a single numeric value
273-
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[1.01]')
272+
query T
273+
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[1.01]');
274+
----
275+
9
274276

275277
query T
276278
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[$varInt]', '{"varInt": 1, "varFloat": 2.3, "varString": "a", "varBool": true, "varNull": null}')
277279
----
278280
9
279281

280-
# TODO(normanchenn): this will be changed after floats are supported.
281-
statement error pgcode 22033 jsonpath array subscript is not a single numeric value
282-
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[$varFloat]', '{"varInt": 1, "varFloat": 2.3, "varString": "a", "varBool": true, "varNull": null}')
282+
query T
283+
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[$varFloat]', '{"varInt": 1, "varFloat": 2.3, "varString": "a", "varBool": true, "varNull": null}');
284+
----
285+
8
283286

284287
statement error pgcode 22033 jsonpath array subscript is not a single numeric value
285288
SELECT jsonb_path_query('{"a": [10, 9, 8, 7]}', '$.a[$varString]', '{"varInt": 1, "varFloat": 2.3, "varString": "a", "varBool": true, "varNull": null}')
@@ -1552,3 +1555,48 @@ query T
15521555
SELECT jsonb_path_query('[1,2,3]', '$[last ? (@.type() == "number")]');
15531556
----
15541557
3
1558+
1559+
query T
1560+
SELECT jsonb_path_query('[1, 2, 3]', '$[1.1]');
1561+
----
1562+
2
1563+
1564+
query T
1565+
SELECT jsonb_path_query('[1, 2, 3]', '$[1.5]');
1566+
----
1567+
2
1568+
1569+
query T
1570+
SELECT jsonb_path_query('[1, 2, 3]', '$[1.99999999]');
1571+
----
1572+
2
1573+
1574+
query T
1575+
SELECT jsonb_path_query('[1, 2, 3]', '$[2.1]');
1576+
----
1577+
3
1578+
1579+
query T
1580+
SELECT jsonb_path_query('[1, 2, 3]', '$[2.5]');
1581+
----
1582+
3
1583+
1584+
query T
1585+
SELECT jsonb_path_query('[1, 2, 3]', '$[2.99999999]');
1586+
----
1587+
3
1588+
1589+
query T
1590+
SELECT jsonb_path_query('[1, 2, 3]', '$[-0.1]');
1591+
----
1592+
1
1593+
1594+
query T
1595+
SELECT jsonb_path_query('[1, 2, 3]', '$[-0.5]');
1596+
----
1597+
1
1598+
1599+
query T
1600+
SELECT jsonb_path_query('[1, 2, 3]', '$[-0.99999999]');
1601+
----
1602+
1

pkg/sql/logictest/testdata/logic_test/jsonpath

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ SELECT '$.number()'::JSONPATH;
195195
statement error unimplemented
196196
SELECT '$.string()'::JSONPATH;
197197

198+
query T
199+
SELECT '$.*'::JSONPATH
200+
----
201+
$.*
202+
198203
## When we allow table creation
199204

200205
# statement ok
@@ -222,11 +227,6 @@ SELECT '$.string()'::JSONPATH;
222227

223228
## Unsupported Jsonpath
224229

225-
# query T
226-
# SELECT '$.*'::JSONPATH
227-
# ----
228-
# $.*
229-
230230
# query T
231231
# SELECT '$.a.type()'::JSONPATH
232232
# ----

pkg/util/jsonpath/eval/array.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ package eval
88
import (
99
"math"
1010

11+
"github.com/cockroachdb/apd/v3"
1112
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
1213
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
14+
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
1315
"github.com/cockroachdb/cockroach/pkg/util/json"
1416
"github.com/cockroachdb/cockroach/pkg/util/jsonpath"
1517
"github.com/cockroachdb/errors"
@@ -125,11 +127,33 @@ func asInt(j json.JSON) (int, error) {
125127
if !ok {
126128
return 0, errIndexNotSingleNumValue
127129
}
128-
i64, err := d.Int64()
130+
131+
// First, try direct conversion to int64.
132+
if i64, err := d.Int64(); err == nil {
133+
return validateInt32Range(i64)
134+
}
135+
136+
// If direct conversion fails, truncate the non-integer towards zero.
137+
var err error
138+
dec := &apd.Decimal{}
139+
if d.Sign() == 1 {
140+
_, err = tree.ExactCtx.Floor(dec, d)
141+
} else {
142+
_, err = tree.ExactCtx.Ceil(dec, d)
143+
}
144+
if err != nil {
145+
return 0, errIndexNotSingleNumValue
146+
}
147+
148+
i64, err := dec.Int64()
129149
if err != nil {
130150
return 0, errIndexNotSingleNumValue
131151
}
132-
// Postgres returns an error if the index is outside int32 range.
152+
return validateInt32Range(i64)
153+
}
154+
155+
// validateInt32Range checks if the int64 value is within int32 range.
156+
func validateInt32Range(i64 int64) (int, error) {
133157
if i64 < math.MinInt32 || i64 > math.MaxInt32 {
134158
return 0, errInvalidSubscript
135159
}

pkg/util/jsonpath/parser/testdata/jsonpath

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -599,41 +599,50 @@ $.a.type()
599599
----
600600
$."a".type() -- normalized!
601601

602-
# postgres allows floats as array indexes
603-
# parse
604-
# $.abc[1.0]
605-
# ----
602+
# Postgres outputs $."abc"[1.0]. This might be a limitation of the apd library.
603+
parse
604+
$.abc[1.0]
605+
----
606+
$."abc"[1] -- normalized!
606607

607-
# parse
608-
# $.abc[1.1]
609-
# ----
608+
parse
609+
$.abc[1.1]
610+
----
611+
$."abc"[1.1] -- normalized!
610612

611-
# in postgres this becomes $."a"[1000000000]
612-
# parse
613-
# $.abc[1e9]
614-
# ----
613+
# Postgres outputs $."abc"[1000000000].
614+
parse
615+
$.abc[1e9]
616+
----
617+
$."abc"[1E+9] -- normalized!
615618

616-
# parse
617-
# $.abc[0.0]
618-
# ----
619+
# Postgres outputs $."abc"[0.0].
620+
parse
621+
$.abc[0.0]
622+
----
623+
$."abc"[0] -- normalized!
619624

620-
# postgres allows negatives as array indexes
621-
# parse
622-
# $.abc[-0]
623-
# ----
625+
# TODO(normanchenn): Related to the TODOs in pkg/util/jsonpath/operation.go.
626+
parse
627+
$.abc[-0]
628+
----
629+
$."abc"[(-0)] -- normalized!
624630

625-
# parse
626-
# $.abc[-1.99]
627-
# ----
631+
parse
632+
$.abc[-1.99]
633+
----
634+
$."abc"[(-1.99)] -- normalized!
628635

629-
# parse
630-
# $[1.999999999999999]
631-
# ----
636+
parse
637+
$[1.999999999999999]
638+
----
639+
$[1.999999999999999]
632640

633-
# parse
634-
# $.1a
635-
# ----
641+
parse
642+
$[null]
643+
----
644+
$[null]
636645

637646
# parse
638-
# $[null]
647+
# $.1a
639648
# ----

0 commit comments

Comments
 (0)