From 283a95da923605c1cc148155db2d865d0801b419 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 3 Jan 2024 11:25:33 +0100 Subject: [PATCH] Reorganise jsonpath operators and methods Various jsonpath operators and methods add various keywords, switch cases, and documentation entries in some order. However, they are not consistent; reorder them for better maintainability or readability. Author: Jeevan Chalke Discussion: https://www.postgresql.org/message-id/flat/CAM2+6=XjTyqrrqHAOj80r0wVQxJSxc0iyib9bPC55uFO9VKatg@mail.gmail.com --- doc/src/sgml/func.sgml | 28 ++++----- src/backend/utils/adt/jsonpath.c | 88 +++++++++++++-------------- src/backend/utils/adt/jsonpath_exec.c | 78 ++++++++++++------------ src/backend/utils/adt/jsonpath_gram.y | 22 +++---- src/include/utils/jsonpath.h | 27 +++++--- 5 files changed, 125 insertions(+), 118 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index cec21e42c0..8f2a2315d8 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17689,6 +17689,20 @@ strict $.**.HR + + + number . abs() + number + + + Absolute value of the given number + + + jsonb_path_query('{"z": -0.3}', '$.z.abs()') + 0.3 + + + number . ceiling() @@ -17717,20 +17731,6 @@ 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 c5ba3b7f1d..8ff9b5646f 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 jpiAbs: - case jpiFloor: - case jpiCeiling: case jpiDouble: + case jpiAbs: + case jpiCeiling: + case jpiFloor: case jpiKeyValue: break; default: @@ -610,18 +610,6 @@ 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); @@ -712,23 +700,35 @@ 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 jpiDouble: - appendStringInfoString(buf, ".double()"); + case jpiFloor: + appendStringInfoString(buf, ".floor()"); break; case jpiDatetime: appendStringInfoString(buf, ".datetime("); @@ -771,11 +771,11 @@ jspOperationName(JsonPathItemType type) return "<="; case jpiGreaterOrEqual: return ">="; - case jpiPlus: case jpiAdd: + case jpiPlus: return "+"; - case jpiMinus: case jpiSub: + case jpiMinus: return "-"; case jpiMul: return "*"; @@ -783,26 +783,26 @@ jspOperationName(JsonPathItemType type) return "/"; case jpiMod: return "%"; - 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 jpiFloor: + return "floor"; case jpiDatetime: return "datetime"; + case jpiKeyValue: + return "keyvalue"; + case jpiStartsWith: + return "starts with"; + case jpiLikeRegex: + return "like_regex"; 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 jpiAbs: - case jpiFloor: - case jpiCeiling: case jpiDouble: + case jpiAbs: + case jpiCeiling: + case jpiFloor: 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,13 +989,6 @@ 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 || @@ -1006,12 +999,19 @@ 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 == jpiAbs || - v->type == jpiFloor || - v->type == jpiCeiling || v->type == jpiDouble || + v->type == jpiAbs || + v->type == jpiCeiling || + v->type == jpiFloor || 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 9a09604f64..86b5b76d4e 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -874,33 +874,6 @@ 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; @@ -980,6 +953,33 @@ 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,18 +1021,6 @@ 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; @@ -1098,6 +1086,18 @@ 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 adc259d5bf..4233eedc1b 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 ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P KEYVALUE_P +%token TYPE_P SIZE_P DOUBLE_P ABS_P CEILING_P FLOOR_P KEYVALUE_P %token DATETIME_P %type result @@ -206,10 +206,10 @@ accessor_expr: expr: accessor_expr { $$ = makeItemList($1); } | '(' expr ')' { $$ = $2; } - | '+' expr %prec UMINUS { $$ = makeItemUnary(jpiPlus, $2); } - | '-' expr %prec UMINUS { $$ = makeItemUnary(jpiMinus, $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(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 - | ABS_P - | SIZE_P + | LAST_P + | FLAG_P | TYPE_P - | FLOOR_P + | SIZE_P | DOUBLE_P + | ABS_P | CEILING_P + | FLOOR_P | DATETIME_P | KEYVALUE_P - | LAST_P | STARTS_P | WITH_P | LIKE_REGEX_P - | FLAG_P ; method: - ABS_P { $$ = jpiAbs; } + TYPE_P { $$ = jpiType; } | SIZE_P { $$ = jpiSize; } - | TYPE_P { $$ = jpiType; } - | FLOOR_P { $$ = jpiFloor; } | DOUBLE_P { $$ = jpiDouble; } + | ABS_P { $$ = jpiAbs; } | CEILING_P { $$ = jpiCeiling; } + | FLOOR_P { $$ = jpiFloor; } | KEYVALUE_P { $$ = jpiKeyValue; } ; %% diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h index f0181e045f..59dc233a08 100644 --- a/src/include/utils/jsonpath.h +++ b/src/include/utils/jsonpath.h @@ -66,13 +66,6 @@ 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, ...] */ @@ -83,14 +76,28 @@ 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 */ - jpiAbs, /* .abs() item method */ - jpiFloor, /* .floor() item method */ - jpiCeiling, /* .ceiling() item method */ jpiDouble, /* .double() item method */ + jpiAbs, /* .abs() item method */ + jpiCeiling, /* .ceiling() item method */ + jpiFloor, /* .floor() 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 */