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

Commit 6ee595c

Browse files
author
Nikita Glukhov
committed
Allow jsonpath parenthized expressions to be a base part of a path
1 parent f9e4061 commit 6ee595c

File tree

7 files changed

+106
-16
lines changed

7 files changed

+106
-16
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,13 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
745745
v->type == jpiRoot ||
746746
v->type == jpiVariable ||
747747
v->type == jpiLast ||
748+
v->type == jpiAdd ||
749+
v->type == jpiSub ||
750+
v->type == jpiMul ||
751+
v->type == jpiDiv ||
752+
v->type == jpiMod ||
753+
v->type == jpiPlus ||
754+
v->type == jpiMinus ||
748755
v->type == jpiType ||
749756
v->type == jpiSize ||
750757
v->type == jpiAbs ||

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
712712
Datum ldatum;
713713
Datum rdatum;
714714
Datum res;
715+
bool hasNext;
715716

716717
jspGetLeftArg(jsp, &elem);
717718

@@ -743,7 +744,9 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
743744
if (rval->type != jbvNumeric)
744745
return jperMakeError(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED);
745746

746-
if (!found)
747+
hasNext = jspGetNext(jsp, &elem);
748+
749+
if (!found && !hasNext)
747750
return jperOk;
748751

749752
ldatum = NumericGetDatum(lval->val.numeric);
@@ -774,6 +777,9 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
774777
lval->type = jbvNumeric;
775778
lval->val.numeric = DatumGetNumeric(res);
776779

780+
if (hasNext)
781+
return recursiveExecute(cxt, &elem, lval, found);
782+
777783
*found = lappend(*found, lval);
778784

779785
return jperOk;
@@ -787,6 +793,7 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
787793
JsonPathItem elem;
788794
List *seq = NIL;
789795
ListCell *lc;
796+
bool hasNext;
790797

791798
jspGetArg(jsp, &elem);
792799
jper = recursiveExecuteAndUnwrap(cxt, &elem, jb, &seq);
@@ -796,6 +803,8 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
796803

797804
jper = jperNotFound;
798805

806+
hasNext = jspGetNext(jsp, &elem);
807+
799808
foreach(lc, seq)
800809
{
801810
JsonbValue *val = lfirst(lc);
@@ -806,12 +815,10 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
806815

807816
if (val->type == jbvNumeric)
808817
{
809-
jper = jperOk;
810-
811-
if (!found)
812-
return jper;
818+
if (!found && !hasNext)
819+
return jperOk;
813820
}
814-
else if (!found)
821+
else if (!found && !hasNext)
815822
continue; /* skip non-numerics processing */
816823

817824
if (val->type != jbvNumeric)
@@ -832,7 +839,26 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
832839
elog(ERROR, "unknown jsonpath arithmetic operation %d", jsp->type);
833840
}
834841

835-
*found = lappend(*found, val);
842+
if (hasNext)
843+
{
844+
JsonPathExecResult jper2 = recursiveExecute(cxt, &elem, val, found);
845+
846+
if (jperIsError(jper2))
847+
return jper2;
848+
849+
if (jper2 == jperOk)
850+
{
851+
if (!found)
852+
return jperOk;
853+
jper = jperOk;
854+
}
855+
}
856+
else
857+
{
858+
Assert(found);
859+
*found = lappend(*found, val);
860+
jper = jperOk;
861+
}
836862
}
837863

838864
return jper;

src/backend/utils/adt/jsonpath_gram.y

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,23 @@ makeItemUnary(int type, JsonPathParseItem* a)
147147
}
148148

149149
static JsonPathParseItem*
150-
makeItemList(List *list) {
151-
JsonPathParseItem *head, *end;
152-
ListCell *cell;
150+
makeItemList(List *list)
151+
{
152+
JsonPathParseItem *head, *end;
153+
ListCell *cell = list_head(list);
153154

154-
head = end = (JsonPathParseItem*)linitial(list);
155+
head = end = (JsonPathParseItem *) lfirst(cell);
155156

156-
foreach(cell, list)
157-
{
158-
JsonPathParseItem *c = (JsonPathParseItem*)lfirst(cell);
157+
if (!lnext(cell))
158+
return head;
159159

160-
if (c == head)
161-
continue;
160+
/* append items to the end of already existing list */
161+
while (end->next)
162+
end = end->next;
163+
164+
for_each_cell(cell, lnext(cell))
165+
{
166+
JsonPathParseItem *c = (JsonPathParseItem *) lfirst(cell);
162167

163168
end->next = c;
164169
end = c;
@@ -373,6 +378,7 @@ path_primary:
373378
accessor_expr:
374379
path_primary { $$ = list_make1($1); }
375380
| '.' key { $$ = list_make2(makeItemType(jpiCurrent), $2); }
381+
| '(' expr ')' accessor_op { $$ = list_make2($2, $4); }
376382
| accessor_expr accessor_op { $$ = lappend($1, $2); }
377383
;
378384

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,18 @@ select _jsonpath_query(jsonb 'null', 'aaa.type()');
842842
"string"
843843
(1 row)
844844

845+
select _jsonpath_query(jsonb '{"a": 2}', '($.a - 5).abs() + 10');
846+
_jsonpath_query
847+
-----------------
848+
13
849+
(1 row)
850+
851+
select _jsonpath_query(jsonb '{"a": 2.5}', '-($.a * $.a).floor() + 10');
852+
_jsonpath_query
853+
-----------------
854+
4
855+
(1 row)
856+
845857
select _jsonpath_query(jsonb '[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'strict $[*].size()');
846858
ERROR: SQL/JSON array not found
847859
select _jsonpath_query(jsonb '[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'lax $[*].size()');

src/test/regress/expected/jsonpath.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,36 @@ ERROR: bad jsonpath representation
446446
LINE 1: select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
447447
^
448448
DETAIL: unrecognized flag of LIKE_REGEX predicate at or near """
449+
select '($).a.b'::jsonpath;
450+
jsonpath
451+
-----------
452+
$."a"."b"
453+
(1 row)
454+
455+
select '($.a.b).c.d'::jsonpath;
456+
jsonpath
457+
-------------------
458+
$."a"."b"."c"."d"
459+
(1 row)
460+
461+
select '($.a.b + -$.x.y).c.d'::jsonpath;
462+
jsonpath
463+
----------------------------------
464+
($."a"."b" + -$."x"."y")."c"."d"
465+
(1 row)
466+
467+
select '(-+$.a.b).c.d'::jsonpath;
468+
jsonpath
469+
-------------------------
470+
(-(+$."a"."b"))."c"."d"
471+
(1 row)
472+
473+
select '1 + ($.a.b + 2).c.d'::jsonpath;
474+
jsonpath
475+
-------------------------------
476+
(1 + ($."a"."b" + 2)."c"."d")
477+
(1 row)
478+
449479
select '$ ? (a < 1)'::jsonpath;
450480
jsonpath
451481
-------------

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ select _jsonpath_query(jsonb 'null', '123.type()');
170170
select _jsonpath_query(jsonb 'null', '"123".type()');
171171
select _jsonpath_query(jsonb 'null', 'aaa.type()');
172172

173+
select _jsonpath_query(jsonb '{"a": 2}', '($.a - 5).abs() + 10');
174+
select _jsonpath_query(jsonb '{"a": 2.5}', '-($.a * $.a).floor() + 10');
175+
173176
select _jsonpath_query(jsonb '[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'strict $[*].size()');
174177
select _jsonpath_query(jsonb '[1,null,true,"11",[],[1],[1,2,3],{},{"a":1,"b":2}]', 'lax $[*].size()');
175178

src/test/regress/sql/jsonpath.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ select '$ ? (@ like_regex "pattern" flag "isim")'::jsonpath;
8282
select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
8383
select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
8484

85+
select '($).a.b'::jsonpath;
86+
select '($.a.b).c.d'::jsonpath;
87+
select '($.a.b + -$.x.y).c.d'::jsonpath;
88+
select '(-+$.a.b).c.d'::jsonpath;
89+
select '1 + ($.a.b + 2).c.d'::jsonpath;
90+
8591
select '$ ? (a < 1)'::jsonpath;
8692
select '$ ? (a < -1)'::jsonpath;
8793
select '$ ? (a < +1)'::jsonpath;

0 commit comments

Comments
 (0)