diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8f2a2315d8..cec21e42c0 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17689,20 +17689,6 @@ strict $.**.HR
-
-
- number . abs()
- number
-
-
- Absolute value of the given number
-
-
- jsonb_path_query('{"z": -0.3}', '$.z.abs()')
- 0.3
-
-
-
number . ceiling()
@@ -17731,6 +17717,20 @@ strict $.**.HR
+
+
+ number . abs()
+ number
+
+
+ Absolute value of the given number
+
+
+ jsonb_path_query('{"z": -0.3}', '$.z.abs()')
+ 0.3
+
+
+
string . datetime()
diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c
index 8ff9b5646f..c5ba3b7f1d 100644
--- a/src/backend/utils/adt/jsonpath.c
+++ b/src/backend/utils/adt/jsonpath.c
@@ -439,10 +439,10 @@ flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
break;
case jpiType:
case jpiSize:
- case jpiDouble:
case jpiAbs:
- case jpiCeiling:
case jpiFloor:
+ case jpiCeiling:
+ case jpiDouble:
case jpiKeyValue:
break;
default:
@@ -610,6 +610,18 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
if (printBracketes)
appendStringInfoChar(buf, ')');
break;
+ case jpiPlus:
+ case jpiMinus:
+ if (printBracketes)
+ appendStringInfoChar(buf, '(');
+ appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
+ jspGetArg(v, &elem);
+ printJsonPathItem(buf, &elem, false,
+ operationPriority(elem.type) <=
+ operationPriority(v->type));
+ if (printBracketes)
+ appendStringInfoChar(buf, ')');
+ break;
case jpiFilter:
appendStringInfoString(buf, "?(");
jspGetArg(v, &elem);
@@ -700,35 +712,23 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
v->content.anybounds.first,
v->content.anybounds.last);
break;
- case jpiPlus:
- case jpiMinus:
- if (printBracketes)
- appendStringInfoChar(buf, '(');
- appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
- jspGetArg(v, &elem);
- printJsonPathItem(buf, &elem, false,
- operationPriority(elem.type) <=
- operationPriority(v->type));
- if (printBracketes)
- appendStringInfoChar(buf, ')');
- break;
case jpiType:
appendStringInfoString(buf, ".type()");
break;
case jpiSize:
appendStringInfoString(buf, ".size()");
break;
- case jpiDouble:
- appendStringInfoString(buf, ".double()");
- break;
case jpiAbs:
appendStringInfoString(buf, ".abs()");
break;
+ case jpiFloor:
+ appendStringInfoString(buf, ".floor()");
+ break;
case jpiCeiling:
appendStringInfoString(buf, ".ceiling()");
break;
- case jpiFloor:
- appendStringInfoString(buf, ".floor()");
+ case jpiDouble:
+ appendStringInfoString(buf, ".double()");
break;
case jpiDatetime:
appendStringInfoString(buf, ".datetime(");
@@ -771,11 +771,11 @@ jspOperationName(JsonPathItemType type)
return "<=";
case jpiGreaterOrEqual:
return ">=";
- case jpiAdd:
case jpiPlus:
+ case jpiAdd:
return "+";
- case jpiSub:
case jpiMinus:
+ case jpiSub:
return "-";
case jpiMul:
return "*";
@@ -783,26 +783,26 @@ jspOperationName(JsonPathItemType type)
return "/";
case jpiMod:
return "%";
- case jpiType:
- return "type";
- case jpiSize:
- return "size";
- case jpiDouble:
- return "double";
- case jpiAbs:
- return "abs";
- case jpiCeiling:
- return "ceiling";
- case jpiFloor:
- return "floor";
- case jpiDatetime:
- return "datetime";
- case jpiKeyValue:
- return "keyvalue";
case jpiStartsWith:
return "starts with";
case jpiLikeRegex:
return "like_regex";
+ case jpiType:
+ return "type";
+ case jpiSize:
+ return "size";
+ case jpiKeyValue:
+ return "keyvalue";
+ case jpiDouble:
+ return "double";
+ case jpiAbs:
+ return "abs";
+ case jpiFloor:
+ return "floor";
+ case jpiCeiling:
+ return "ceiling";
+ case jpiDatetime:
+ return "datetime";
default:
elog(ERROR, "unrecognized jsonpath item type: %d", type);
return NULL;
@@ -893,10 +893,10 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
case jpiAnyKey:
case jpiType:
case jpiSize:
- case jpiDouble:
case jpiAbs:
- case jpiCeiling:
case jpiFloor:
+ case jpiCeiling:
+ case jpiDouble:
case jpiKeyValue:
case jpiLast:
break;
@@ -935,9 +935,9 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
case jpiNot:
case jpiExists:
case jpiIsUnknown:
- case jpiFilter:
case jpiPlus:
case jpiMinus:
+ case jpiFilter:
case jpiDatetime:
read_int32(v->content.arg, base, pos);
break;
@@ -989,6 +989,13 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
v->type == jpiRoot ||
v->type == jpiVariable ||
v->type == jpiLast ||
+ v->type == jpiAdd ||
+ v->type == jpiSub ||
+ v->type == jpiMul ||
+ v->type == jpiDiv ||
+ v->type == jpiMod ||
+ v->type == jpiPlus ||
+ v->type == jpiMinus ||
v->type == jpiEqual ||
v->type == jpiNotEqual ||
v->type == jpiGreater ||
@@ -999,19 +1006,12 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
v->type == jpiOr ||
v->type == jpiNot ||
v->type == jpiIsUnknown ||
- v->type == jpiAdd ||
- v->type == jpiPlus ||
- v->type == jpiSub ||
- v->type == jpiMinus ||
- v->type == jpiMul ||
- v->type == jpiDiv ||
- v->type == jpiMod ||
v->type == jpiType ||
v->type == jpiSize ||
- v->type == jpiDouble ||
v->type == jpiAbs ||
- v->type == jpiCeiling ||
v->type == jpiFloor ||
+ v->type == jpiCeiling ||
+ v->type == jpiDouble ||
v->type == jpiDatetime ||
v->type == jpiKeyValue ||
v->type == jpiStartsWith ||
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 86b5b76d4e..9a09604f64 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -874,6 +874,33 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break;
+ case jpiAdd:
+ return executeBinaryArithmExpr(cxt, jsp, jb,
+ numeric_add_opt_error, found);
+
+ case jpiSub:
+ return executeBinaryArithmExpr(cxt, jsp, jb,
+ numeric_sub_opt_error, found);
+
+ case jpiMul:
+ return executeBinaryArithmExpr(cxt, jsp, jb,
+ numeric_mul_opt_error, found);
+
+ case jpiDiv:
+ return executeBinaryArithmExpr(cxt, jsp, jb,
+ numeric_div_opt_error, found);
+
+ case jpiMod:
+ return executeBinaryArithmExpr(cxt, jsp, jb,
+ numeric_mod_opt_error, found);
+
+ case jpiPlus:
+ return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
+
+ case jpiMinus:
+ return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
+ found);
+
case jpiFilter:
{
JsonPathBool st;
@@ -953,33 +980,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break;
- case jpiAdd:
- return executeBinaryArithmExpr(cxt, jsp, jb,
- numeric_add_opt_error, found);
-
- case jpiPlus:
- return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
-
- case jpiSub:
- return executeBinaryArithmExpr(cxt, jsp, jb,
- numeric_sub_opt_error, found);
-
- case jpiMinus:
- return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
- found);
-
- case jpiMul:
- return executeBinaryArithmExpr(cxt, jsp, jb,
- numeric_mul_opt_error, found);
-
- case jpiDiv:
- return executeBinaryArithmExpr(cxt, jsp, jb,
- numeric_div_opt_error, found);
-
- case jpiMod:
- return executeBinaryArithmExpr(cxt, jsp, jb,
- numeric_mod_opt_error, found);
-
case jpiType:
{
JsonbValue *jbv = palloc(sizeof(*jbv));
@@ -1021,6 +1021,18 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break;
+ case jpiAbs:
+ return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
+ found);
+
+ case jpiFloor:
+ return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
+ found);
+
+ case jpiCeiling:
+ return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
+ found);
+
case jpiDouble:
{
JsonbValue jbv;
@@ -1086,18 +1098,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break;
- case jpiAbs:
- return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
- found);
-
- case jpiCeiling:
- return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
- found);
-
- case jpiFloor:
- return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
- found);
-
case jpiDatetime:
if (unwrap && JsonbType(jb) == jbvArray)
return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y
index 4233eedc1b..adc259d5bf 100644
--- a/src/backend/utils/adt/jsonpath_gram.y
+++ b/src/backend/utils/adt/jsonpath_gram.y
@@ -80,7 +80,7 @@ static bool makeItemLikeRegex(JsonPathParseItem *expr,
%token OR_P AND_P NOT_P
%token LESS_P LESSEQUAL_P EQUAL_P NOTEQUAL_P GREATEREQUAL_P GREATER_P
%token ANY_P STRICT_P LAX_P LAST_P STARTS_P WITH_P LIKE_REGEX_P FLAG_P
-%token TYPE_P SIZE_P DOUBLE_P ABS_P CEILING_P FLOOR_P KEYVALUE_P
+%token ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P KEYVALUE_P
%token DATETIME_P
%type result
@@ -206,10 +206,10 @@ accessor_expr:
expr:
accessor_expr { $$ = makeItemList($1); }
| '(' expr ')' { $$ = $2; }
- | expr '+' expr { $$ = makeItemBinary(jpiAdd, $1, $3); }
| '+' expr %prec UMINUS { $$ = makeItemUnary(jpiPlus, $2); }
- | expr '-' expr { $$ = makeItemBinary(jpiSub, $1, $3); }
| '-' expr %prec UMINUS { $$ = makeItemUnary(jpiMinus, $2); }
+ | expr '+' expr { $$ = makeItemBinary(jpiAdd, $1, $3); }
+ | expr '-' expr { $$ = makeItemBinary(jpiSub, $1, $3); }
| expr '*' expr { $$ = makeItemBinary(jpiMul, $1, $3); }
| expr '/' expr { $$ = makeItemBinary(jpiDiv, $1, $3); }
| expr '%' expr { $$ = makeItemBinary(jpiMod, $1, $3); }
@@ -278,28 +278,28 @@ key_name:
| EXISTS_P
| STRICT_P
| LAX_P
- | LAST_P
- | FLAG_P
- | TYPE_P
- | SIZE_P
- | DOUBLE_P
| ABS_P
- | CEILING_P
+ | SIZE_P
+ | TYPE_P
| FLOOR_P
+ | DOUBLE_P
+ | CEILING_P
| DATETIME_P
| KEYVALUE_P
+ | LAST_P
| STARTS_P
| WITH_P
| LIKE_REGEX_P
+ | FLAG_P
;
method:
- TYPE_P { $$ = jpiType; }
+ ABS_P { $$ = jpiAbs; }
| SIZE_P { $$ = jpiSize; }
- | DOUBLE_P { $$ = jpiDouble; }
- | ABS_P { $$ = jpiAbs; }
- | CEILING_P { $$ = jpiCeiling; }
+ | TYPE_P { $$ = jpiType; }
| FLOOR_P { $$ = jpiFloor; }
+ | DOUBLE_P { $$ = jpiDouble; }
+ | CEILING_P { $$ = jpiCeiling; }
| KEYVALUE_P { $$ = jpiKeyValue; }
;
%%
diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h
index 59dc233a08..f0181e045f 100644
--- a/src/include/utils/jsonpath.h
+++ b/src/include/utils/jsonpath.h
@@ -66,6 +66,13 @@ typedef enum JsonPathItemType
jpiGreater, /* expr > expr */
jpiLessOrEqual, /* expr <= expr */
jpiGreaterOrEqual, /* expr >= expr */
+ jpiAdd, /* expr + expr */
+ jpiSub, /* expr - expr */
+ jpiMul, /* expr * expr */
+ jpiDiv, /* expr / expr */
+ jpiMod, /* expr % expr */
+ jpiPlus, /* + expr */
+ jpiMinus, /* - expr */
jpiAnyArray, /* [*] */
jpiAnyKey, /* .* */
jpiIndexArray, /* [subscript, ...] */
@@ -76,28 +83,14 @@ typedef enum JsonPathItemType
jpiVariable, /* $variable */
jpiFilter, /* ? (predicate) */
jpiExists, /* EXISTS (expr) predicate */
-
- /*
- * For better maintainability or readability, keep the order of the below
- * jsonpath Operators and Methods at the other places, like in the
- * documentation, switch() cases, keywords list, etc., too.
- */
- jpiAdd, /* expr + expr */
- jpiPlus, /* + expr */
- jpiSub, /* expr - expr */
- jpiMinus, /* - expr */
- jpiMul, /* expr * expr */
- jpiDiv, /* expr / expr */
- jpiMod, /* expr % expr */
jpiType, /* .type() item method */
jpiSize, /* .size() item method */
- jpiDouble, /* .double() item method */
jpiAbs, /* .abs() item method */
- jpiCeiling, /* .ceiling() item method */
jpiFloor, /* .floor() item method */
+ jpiCeiling, /* .ceiling() item method */
+ jpiDouble, /* .double() item method */
jpiDatetime, /* .datetime() item method */
jpiKeyValue, /* .keyvalue() item method */
-
jpiSubscript, /* array subscript: 'expr' or 'expr TO expr' */
jpiLast, /* LAST array subscript */
jpiStartsWith, /* STARTS WITH predicate */