Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9d1d611

Browse files
author
Nikita Glukhov
committed
Add jsonpath array constructors
1 parent 9dbe6d1 commit 9d1d611

File tree

8 files changed

+128
-2
lines changed

8 files changed

+128
-2
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,9 +338,13 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
338338
case jpiPlus:
339339
case jpiMinus:
340340
case jpiExists:
341+
case jpiArray:
341342
{
342343
int32 arg = reserveSpaceForItemPointer(buf);
343344

345+
if (!item->value.arg)
346+
break;
347+
344348
chld = flattenJsonPathParseItem(buf, item->value.arg,
345349
nestingLevel + argNestingLevel,
346350
insideArraySubscript);
@@ -754,6 +758,15 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
754758
if (printBracketes || jspHasNext(v))
755759
appendStringInfoChar(buf, ')');
756760
break;
761+
case jpiArray:
762+
appendStringInfoChar(buf, '[');
763+
if (v->content.arg)
764+
{
765+
jspGetArg(v, &elem);
766+
printJsonPathItem(buf, &elem, false, false);
767+
}
768+
appendStringInfoChar(buf, ']');
769+
break;
757770
default:
758771
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
759772
}
@@ -953,6 +966,7 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
953966
case jpiPlus:
954967
case jpiMinus:
955968
case jpiFilter:
969+
case jpiArray:
956970
read_int32(v->content.arg, base, pos);
957971
break;
958972
case jpiIndexArray:
@@ -982,7 +996,8 @@ jspGetArg(JsonPathItem *v, JsonPathItem *a)
982996
v->type == jpiIsUnknown ||
983997
v->type == jpiExists ||
984998
v->type == jpiPlus ||
985-
v->type == jpiMinus);
999+
v->type == jpiMinus ||
1000+
v->type == jpiArray);
9861001

9871002
jspInitByBuffer(a, v->base, v->content.arg);
9881003
}
@@ -1033,7 +1048,8 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
10331048
v->type == jpiDatetime ||
10341049
v->type == jpiKeyValue ||
10351050
v->type == jpiStartsWith ||
1036-
v->type == jpiSequence);
1051+
v->type == jpiSequence ||
1052+
v->type == jpiArray);
10371053

10381054
if (a)
10391055
jspInitByBuffer(a, v->base, v->nextPos);

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,29 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
16371637
break;
16381638
}
16391639

1640+
case jpiArray:
1641+
{
1642+
JsonValueList list = {0};
1643+
JsonbValue *arr;
1644+
JsonItem jsi;
1645+
1646+
if (jsp->content.arg)
1647+
{
1648+
jspGetArg(jsp, &elem);
1649+
res = executeItem(cxt, &elem, jb, &list);
1650+
1651+
if (jperIsError(res))
1652+
break;
1653+
}
1654+
1655+
arr = wrapItemsInArray(&list, cxt->isJsonb);
1656+
1657+
res = executeNextItem(cxt, jsp, NULL,
1658+
JsonbValueToJsonItem(arr, &jsi),
1659+
found, true);
1660+
break;
1661+
}
1662+
16401663
default:
16411664
elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
16421665
}

src/backend/utils/adt/jsonpath_gram.y

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ path_primary:
211211
| '@' { $$ = makeItemType(jpiCurrent); }
212212
| LAST_P { $$ = makeItemType(jpiLast); }
213213
| '(' expr_seq ')' { $$ = $2; }
214+
| '[' ']' { $$ = makeItemUnary(jpiArray, NULL); }
215+
| '[' expr_or_seq ']' { $$ = makeItemUnary(jpiArray, $2); }
214216
;
215217

216218
accessor_expr:

src/include/utils/jsonpath.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ typedef enum JsonPathItemType
9090
jpiStartsWith, /* STARTS WITH predicate */
9191
jpiLikeRegex, /* LIKE_REGEX predicate */
9292
jpiSequence, /* sequence constructor: 'expr, ...' */
93+
jpiArray, /* array constructor: '[expr, ...]' */
9394
} JsonPathItemType;
9495

9596
/* XQuery regex mode flags for LIKE_REGEX predicate */

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,12 @@ SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)');
22132213
------------------
22142214
(0 rows)
22152215

2216+
SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '[$[*].a]');
2217+
jsonb_path_query
2218+
------------------
2219+
[1, 2]
2220+
(1 row)
2221+
22162222
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
22172223
ERROR: JSON object does not contain key "a"
22182224
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a');
@@ -2245,6 +2251,12 @@ SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].
22452251
[]
22462252
(1 row)
22472253

2254+
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '[$[*].a]');
2255+
jsonb_path_query_array
2256+
------------------------
2257+
[[1, 2]]
2258+
(1 row)
2259+
22482260
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
22492261
ERROR: JSON object does not contain key "a"
22502262
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a', silent => true);
@@ -2431,3 +2443,49 @@ select jsonb_path_query('[1,2,3,4,5]', '$[(0, $[*], 5) ? (@ == 3)]');
24312443
select jsonb_path_query('[1,2,3,4,5]', '$[(0, $[*], 3) ? (@ == 3)]');
24322444
ERROR: invalid SQL/JSON subscript
24332445
DETAIL: jsonpath array subscript is not a singleton numeric value
2446+
-- extension: array constructors
2447+
select jsonb_path_query('[1, 2, 3]', '[]');
2448+
jsonb_path_query
2449+
------------------
2450+
[]
2451+
(1 row)
2452+
2453+
select jsonb_path_query('[1, 2, 3]', '[1, 2, $[*], 4, 5]');
2454+
jsonb_path_query
2455+
-----------------------
2456+
[1, 2, 1, 2, 3, 4, 5]
2457+
(1 row)
2458+
2459+
select jsonb_path_query('[1, 2, 3]', '[1, 2, $[*], 4, 5][*]');
2460+
jsonb_path_query
2461+
------------------
2462+
1
2463+
2
2464+
1
2465+
2
2466+
3
2467+
4
2468+
5
2469+
(7 rows)
2470+
2471+
select jsonb_path_query('[1, 2, 3]', '[(1, (2, $[*])), (4, 5)]');
2472+
jsonb_path_query
2473+
-----------------------
2474+
[1, 2, 1, 2, 3, 4, 5]
2475+
(1 row)
2476+
2477+
select jsonb_path_query('[1, 2, 3]', '[[1, 2], [$[*], 4], 5, [(1,2)?(@ > 5)]]');
2478+
jsonb_path_query
2479+
-------------------------------
2480+
[[1, 2], [1, 2, 3, 4], 5, []]
2481+
(1 row)
2482+
2483+
select jsonb_path_query('[1, 2, 3]', 'strict [1, 2, $[*].a, 4, 5]');
2484+
ERROR: SQL/JSON member not found
2485+
DETAIL: jsonpath member accessor can only be applied to an object
2486+
select jsonb_path_query('[[1, 2], [3, 4, 5], [], [6, 7]]', '[$[*][*] ? (@ > 3)]');
2487+
jsonb_path_query
2488+
------------------
2489+
[4, 5, 6, 7]
2490+
(1 row)
2491+

src/test/regress/expected/jsonpath.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,18 @@ select '$[(1, (2, $.a)), 3, (4, 5)]'::jsonpath;
604604
$[(1, (2, $."a")),3,(4, 5)]
605605
(1 row)
606606

607+
select '[]'::jsonpath;
608+
jsonpath
609+
----------
610+
[]
611+
(1 row)
612+
613+
select '[[1, 2], ([(3, 4, 5), 6], []), $.a[*]]'::jsonpath;
614+
jsonpath
615+
------------------------------------------
616+
[[1, 2], ([(3, 4, 5), 6], []), $."a"[*]]
617+
(1 row)
618+
607619
select '$ ? (@.a < 1)'::jsonpath;
608620
jsonpath
609621
---------------

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,13 +502,15 @@ set time zone default;
502502

503503
SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]');
504504
SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)');
505+
SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '[$[*].a]');
505506

506507
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
507508
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a');
508509
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ == 1)');
509510
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 10)');
510511
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 1, "max": 4}');
511512
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 3, "max": 4}');
513+
SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '[$[*].a]');
512514

513515
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
514516
SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a', silent => true);
@@ -548,3 +550,12 @@ select jsonb_path_query('[1,2,3,4,5]', '-(10, 20, $[1 to 3], 30)');
548550
select jsonb_path_query('[1,2,3,4,5]', 'lax (10, 20.5, $[1 to 3], "30").double()');
549551
select jsonb_path_query('[1,2,3,4,5]', '$[(0, $[*], 5) ? (@ == 3)]');
550552
select jsonb_path_query('[1,2,3,4,5]', '$[(0, $[*], 3) ? (@ == 3)]');
553+
554+
-- extension: array constructors
555+
select jsonb_path_query('[1, 2, 3]', '[]');
556+
select jsonb_path_query('[1, 2, 3]', '[1, 2, $[*], 4, 5]');
557+
select jsonb_path_query('[1, 2, 3]', '[1, 2, $[*], 4, 5][*]');
558+
select jsonb_path_query('[1, 2, 3]', '[(1, (2, $[*])), (4, 5)]');
559+
select jsonb_path_query('[1, 2, 3]', '[[1, 2], [$[*], 4], 5, [(1,2)?(@ > 5)]]');
560+
select jsonb_path_query('[1, 2, 3]', 'strict [1, 2, $[*].a, 4, 5]');
561+
select jsonb_path_query('[[1, 2], [3, 4, 5], [], [6, 7]]', '[$[*][*] ? (@ > 3)]');

src/test/regress/sql/jsonpath.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ select '(1, 2, $.a) == 5'::jsonpath;
113113
select '$[(1, 2, $.a) to (3, 4)]'::jsonpath;
114114
select '$[(1, (2, $.a)), 3, (4, 5)]'::jsonpath;
115115
116+
select '[]'::jsonpath;
117+
select '[[1, 2], ([(3, 4, 5), 6], []), $.a[*]]'::jsonpath;
118+
116119
select '$ ? (@.a < 1)'::jsonpath;
117120
select '$ ? (@.a < -1)'::jsonpath;
118121
select '$ ? (@.a < +1)'::jsonpath;

0 commit comments

Comments
 (0)