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

Commit 75f6ba8

Browse files
author
Nikita Glukhov
committed
Fix unary arithmetic jsonpath expressions
1 parent 12557e9 commit 75f6ba8

File tree

5 files changed

+108
-33
lines changed

5 files changed

+108
-33
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
9292
case jpiFilter:
9393
case jpiIsUnknown:
9494
case jpiNot:
95+
case jpiPlus:
9596
case jpiMinus:
9697
case jpiExists:
9798
{
@@ -475,6 +476,7 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
475476
case jpiNot:
476477
case jpiExists:
477478
case jpiIsUnknown:
479+
case jpiPlus:
478480
case jpiMinus:
479481
case jpiFilter:
480482
read_int32(v->arg, base, pos);
@@ -500,6 +502,7 @@ jspGetArg(JsonPathItem *v, JsonPathItem *a)
500502
v->type == jpiNot ||
501503
v->type == jpiIsUnknown ||
502504
v->type == jpiExists ||
505+
v->type == jpiPlus ||
503506
v->type == jpiMinus
504507
);
505508

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ executeExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
383383
}
384384

385385
static JsonPathExecResult
386-
executeArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
387-
List **found)
386+
executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
387+
JsonbValue *jb, List **found)
388388
{
389389
JsonPathExecResult jper;
390390
JsonPathItem elem;
@@ -398,29 +398,18 @@ executeArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
398398
Datum rdatum;
399399
Datum res;
400400

401-
if (jsp->type == jpiMinus)
402-
jspGetArg(jsp, &elem);
403-
else
404-
jspGetLeftArg(jsp, &elem);
401+
jspGetLeftArg(jsp, &elem);
405402

406403
jper = recursiveExecute(cxt, &elem, jb, &lseq);
407404

408-
if (jper == jperOk && jsp->type != jpiMinus)
405+
if (jper == jperOk)
409406
{
410407
jspGetRightArg(jsp, &elem);
411408
jper = recursiveExecute(cxt, &elem, jb, &rseq);
412409
}
413410

414-
if (jsp->type == jpiMinus)
415-
{
416-
if (jper != jperOk || list_length(lseq) != 1)
417-
return jperError; /* ERRCODE_SINGLETON_JSON_ITEM_REQUIRED; */
418-
}
419-
else
420-
{
421-
if (jper != jperOk || list_length(lseq) != 1 || list_length(rseq) != 1)
422-
return jperError; /* ERRCODE_SINGLETON_JSON_ITEM_REQUIRED; */
423-
}
411+
if (jper != jperOk || list_length(lseq) != 1 || list_length(rseq) != 1)
412+
return jperError; /* ERRCODE_SINGLETON_JSON_ITEM_REQUIRED; */
424413

425414
lval = linitial(lseq);
426415

@@ -430,29 +419,22 @@ executeArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
430419
if (lval->type != jbvNumeric)
431420
return jperError; /* ERRCODE_SINGLETON_JSON_ITEM_REQUIRED; */
432421

433-
if (jsp->type != jpiMinus)
434-
{
435-
rval = linitial(rseq);
422+
rval = linitial(rseq);
436423

437-
if (JsonbType(rval) == jbvScalar)
438-
rval = JsonbExtractScalar(rval->val.binary.data, &rvalbuf);
424+
if (JsonbType(rval) == jbvScalar)
425+
rval = JsonbExtractScalar(rval->val.binary.data, &rvalbuf);
439426

440-
if (rval->type != jbvNumeric)
441-
return jperError; /* ERRCODE_SINGLETON_JSON_ITEM_REQUIRED; */
442-
}
427+
if (rval->type != jbvNumeric)
428+
return jperError; /* ERRCODE_SINGLETON_JSON_ITEM_REQUIRED; */
443429

444430
if (!found)
445431
return jperOk;
446432

447433
ldatum = NumericGetDatum(lval->val.numeric);
448-
if (jsp->type != jpiMinus)
449-
rdatum = NumericGetDatum(rval->val.numeric);
434+
rdatum = NumericGetDatum(rval->val.numeric);
450435

451436
switch (jsp->type)
452437
{
453-
case jpiMinus:
454-
res = DirectFunctionCall1(numeric_uminus, ldatum);
455-
break;
456438
case jpiAdd:
457439
res = DirectFunctionCall2(numeric_add, ldatum, rdatum);
458440
break;
@@ -481,7 +463,7 @@ executeArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
481463
return jperOk;
482464
}
483465

484-
static JsonbValue*
466+
static JsonbValue *
485467
copyJsonbValue(JsonbValue *src)
486468
{
487469
JsonbValue *dst = palloc(sizeof(*dst));
@@ -491,6 +473,65 @@ copyJsonbValue(JsonbValue *src)
491473
return dst;
492474
}
493475

476+
static JsonPathExecResult
477+
executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
478+
JsonbValue *jb, List **found)
479+
{
480+
JsonPathExecResult jper;
481+
JsonPathItem elem;
482+
List *seq = NIL;
483+
ListCell *lc;
484+
485+
jspGetArg(jsp, &elem);
486+
jper = recursiveExecute(cxt, &elem, jb, &seq);
487+
488+
if (jper == jperError)
489+
return jperError; /* ERRCODE_JSON_NUMBER_NOT_FOUND; */
490+
491+
jper = jperNotFound;
492+
493+
foreach(lc, seq)
494+
{
495+
JsonbValue *val = lfirst(lc);
496+
JsonbValue valbuf;
497+
498+
if (JsonbType(val) == jbvScalar)
499+
val = JsonbExtractScalar(val->val.binary.data, &valbuf);
500+
501+
if (val->type == jbvNumeric)
502+
{
503+
jper = jperOk;
504+
505+
if (!found)
506+
return jper;
507+
}
508+
else if (!found)
509+
continue; /* skip non-numerics processing */
510+
511+
if (val->type != jbvNumeric)
512+
return jperError; /* ERRCODE_JSON_NUMBER_NOT_FOUND; */
513+
514+
val = copyJsonbValue(val);
515+
516+
switch (jsp->type)
517+
{
518+
case jpiPlus:
519+
break;
520+
case jpiMinus:
521+
val->val.numeric =
522+
DatumGetNumeric(DirectFunctionCall1(
523+
numeric_uminus, NumericGetDatum(val->val.numeric)));
524+
break;
525+
default:
526+
elog(ERROR, "unknown jsonpath arithmetic operation %d", jsp->type);
527+
}
528+
529+
*found = lappend(*found, val);
530+
}
531+
532+
return jper;
533+
}
534+
494535
static JsonPathExecResult
495536
recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
496537
List **found, uint32 level, uint32 first, uint32 last)
@@ -792,8 +833,11 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
792833
case jpiMul:
793834
case jpiDiv:
794835
case jpiMod:
836+
res = executeBinaryArithmExpr(cxt, jsp, jb, found);
837+
break;
838+
case jpiPlus:
795839
case jpiMinus:
796-
res = executeArithmExpr(cxt, jsp, jb, found);
840+
res = executeUnaryArithmExpr(cxt, jsp, jb, found);
797841
break;
798842
case jpiRoot:
799843
if (jspGetNext(jsp, &elem))

src/backend/utils/adt/jsonpath_gram.y

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ pexpr:
300300

301301
expr:
302302
accessor_expr { $$ = makeItemList($1); }
303-
| '+' pexpr %prec UMINUS { $$ = $2; }
303+
| '+' pexpr %prec UMINUS { $$ = makeItemUnary(jpiPlus, $2); }
304304
| '-' pexpr %prec UMINUS { $$ = makeItemUnary(jpiMinus, $2); }
305305
| pexpr '+' pexpr { $$ = makeItemBinary(jpiAdd, $1, $3); }
306306
| pexpr '-' pexpr { $$ = makeItemBinary(jpiSub, $1, $3); }

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,27 @@ select _jsonpath_exists(jsonb '{"c": {"a": 0, "b":1}}', '$.** ? (.a == 1 - +.b)'
618618
t
619619
(1 row)
620620

621+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (+@[*] > +2)');
622+
_jsonpath_exists
623+
------------------
624+
t
625+
(1 row)
626+
627+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (+@[*] > +3)');
628+
_jsonpath_exists
629+
------------------
630+
f
631+
(1 row)
632+
633+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -2)');
634+
_jsonpath_exists
635+
------------------
636+
t
637+
(1 row)
638+
639+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -3)');
640+
_jsonpath_exists
641+
------------------
642+
f
643+
(1 row)
644+

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,7 @@ select _jsonpath_exists(jsonb '{"c": {"a": -1, "b":1}}', '$.** ? (.a == - .b)');
128128
select _jsonpath_exists(jsonb '{"c": {"a": 0, "b":1}}', '$.** ? (.a == 1 - .b)');
129129
select _jsonpath_exists(jsonb '{"c": {"a": 2, "b":1}}', '$.** ? (.a == 1 - - .b)');
130130
select _jsonpath_exists(jsonb '{"c": {"a": 0, "b":1}}', '$.** ? (.a == 1 - +.b)');
131+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (+@[*] > +2)');
132+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (+@[*] > +3)');
133+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -2)');
134+
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -3)');

0 commit comments

Comments
 (0)