diff options
-rw-r--r-- | src/backend/utils/adt/jsonpath.c | 250 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonpath_exec.c | 332 | ||||
-rw-r--r-- | src/include/utils/jsonpath.h | 7 |
3 files changed, 298 insertions, 291 deletions
diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c index c5ba3b7f1d0..0a16f93f39b 100644 --- a/src/backend/utils/adt/jsonpath.c +++ b/src/backend/utils/adt/jsonpath.c @@ -519,18 +519,9 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, case jpiNull: appendStringInfoString(buf, "null"); break; - case jpiKey: - if (inKey) - appendStringInfoChar(buf, '.'); - escape_json(buf, jspGetString(v, NULL)); - break; case jpiString: escape_json(buf, jspGetString(v, NULL)); break; - case jpiVariable: - appendStringInfoChar(buf, '$'); - escape_json(buf, jspGetString(v, NULL)); - break; case jpiNumeric: if (jspHasNext(v)) appendStringInfoChar(buf, '('); @@ -576,58 +567,6 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, if (printBracketes) appendStringInfoChar(buf, ')'); break; - case jpiLikeRegex: - if (printBracketes) - appendStringInfoChar(buf, '('); - - jspInitByBuffer(&elem, v->base, v->content.like_regex.expr); - printJsonPathItem(buf, &elem, false, - operationPriority(elem.type) <= - operationPriority(v->type)); - - appendStringInfoString(buf, " like_regex "); - - escape_json(buf, v->content.like_regex.pattern); - - if (v->content.like_regex.flags) - { - appendStringInfoString(buf, " flag \""); - - if (v->content.like_regex.flags & JSP_REGEX_ICASE) - appendStringInfoChar(buf, 'i'); - if (v->content.like_regex.flags & JSP_REGEX_DOTALL) - appendStringInfoChar(buf, 's'); - if (v->content.like_regex.flags & JSP_REGEX_MLINE) - appendStringInfoChar(buf, 'm'); - if (v->content.like_regex.flags & JSP_REGEX_WSPACE) - appendStringInfoChar(buf, 'x'); - if (v->content.like_regex.flags & JSP_REGEX_QUOTE) - appendStringInfoChar(buf, 'q'); - - appendStringInfoChar(buf, '"'); - } - - 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); - printJsonPathItem(buf, &elem, false, false); - appendStringInfoChar(buf, ')'); - break; case jpiNot: appendStringInfoString(buf, "!("); jspGetArg(v, &elem); @@ -640,22 +579,17 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, printJsonPathItem(buf, &elem, false, false); appendStringInfoString(buf, ") is unknown"); break; - case jpiExists: - appendStringInfoString(buf, "exists ("); + case jpiPlus: + case jpiMinus: + if (printBracketes) + appendStringInfoChar(buf, '('); + appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-'); jspGetArg(v, &elem); - printJsonPathItem(buf, &elem, false, false); - appendStringInfoChar(buf, ')'); - break; - case jpiCurrent: - Assert(!inKey); - appendStringInfoChar(buf, '@'); - break; - case jpiRoot: - Assert(!inKey); - appendStringInfoChar(buf, '$'); - break; - case jpiLast: - appendStringInfoString(buf, "last"); + printJsonPathItem(buf, &elem, false, + operationPriority(elem.type) <= + operationPriority(v->type)); + if (printBracketes) + appendStringInfoChar(buf, ')'); break; case jpiAnyArray: appendStringInfoString(buf, "[*]"); @@ -712,6 +646,35 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, v->content.anybounds.first, v->content.anybounds.last); break; + case jpiKey: + if (inKey) + appendStringInfoChar(buf, '.'); + escape_json(buf, jspGetString(v, NULL)); + break; + case jpiCurrent: + Assert(!inKey); + appendStringInfoChar(buf, '@'); + break; + case jpiRoot: + Assert(!inKey); + appendStringInfoChar(buf, '$'); + break; + case jpiVariable: + appendStringInfoChar(buf, '$'); + escape_json(buf, jspGetString(v, NULL)); + break; + case jpiFilter: + appendStringInfoString(buf, "?("); + jspGetArg(v, &elem); + printJsonPathItem(buf, &elem, false, false); + appendStringInfoChar(buf, ')'); + break; + case jpiExists: + appendStringInfoString(buf, "exists ("); + jspGetArg(v, &elem); + printJsonPathItem(buf, &elem, false, false); + appendStringInfoChar(buf, ')'); + break; case jpiType: appendStringInfoString(buf, ".type()"); break; @@ -742,6 +705,43 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, case jpiKeyValue: appendStringInfoString(buf, ".keyvalue()"); break; + case jpiLast: + appendStringInfoString(buf, "last"); + break; + case jpiLikeRegex: + if (printBracketes) + appendStringInfoChar(buf, '('); + + jspInitByBuffer(&elem, v->base, v->content.like_regex.expr); + printJsonPathItem(buf, &elem, false, + operationPriority(elem.type) <= + operationPriority(v->type)); + + appendStringInfoString(buf, " like_regex "); + + escape_json(buf, v->content.like_regex.pattern); + + if (v->content.like_regex.flags) + { + appendStringInfoString(buf, " flag \""); + + if (v->content.like_regex.flags & JSP_REGEX_ICASE) + appendStringInfoChar(buf, 'i'); + if (v->content.like_regex.flags & JSP_REGEX_DOTALL) + appendStringInfoChar(buf, 's'); + if (v->content.like_regex.flags & JSP_REGEX_MLINE) + appendStringInfoChar(buf, 'm'); + if (v->content.like_regex.flags & JSP_REGEX_WSPACE) + appendStringInfoChar(buf, 'x'); + if (v->content.like_regex.flags & JSP_REGEX_QUOTE) + appendStringInfoChar(buf, 'q'); + + appendStringInfoChar(buf, '"'); + } + + if (printBracketes) + appendStringInfoChar(buf, ')'); + break; default: elog(ERROR, "unrecognized jsonpath item type: %d", v->type); } @@ -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 jpiDouble: + return "double"; 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; @@ -900,8 +900,8 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos) case jpiKeyValue: case jpiLast: break; - case jpiKey: case jpiString: + case jpiKey: case jpiVariable: read_int32(v->content.value.datalen, base, pos); /* FALLTHROUGH */ @@ -911,30 +911,24 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos) break; case jpiAnd: case jpiOr: - case jpiAdd: - case jpiSub: - case jpiMul: - case jpiDiv: - case jpiMod: case jpiEqual: case jpiNotEqual: case jpiLess: case jpiGreater: case jpiLessOrEqual: case jpiGreaterOrEqual: + case jpiAdd: + case jpiSub: + case jpiMul: + case jpiDiv: + case jpiMod: case jpiStartsWith: read_int32(v->content.args.left, base, pos); read_int32(v->content.args.right, base, pos); break; - case jpiLikeRegex: - read_int32(v->content.like_regex.flags, base, pos); - read_int32(v->content.like_regex.expr, base, pos); - read_int32(v->content.like_regex.patternlen, base, pos); - v->content.like_regex.pattern = base + pos; - break; case jpiNot: - case jpiExists: case jpiIsUnknown: + case jpiExists: case jpiPlus: case jpiMinus: case jpiFilter: @@ -950,6 +944,12 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos) read_int32(v->content.anybounds.first, base, pos); read_int32(v->content.anybounds.last, base, pos); break; + case jpiLikeRegex: + read_int32(v->content.like_regex.flags, base, pos); + read_int32(v->content.like_regex.expr, base, pos); + read_int32(v->content.like_regex.patternlen, base, pos); + v->content.like_regex.pattern = base + pos; + break; default: elog(ERROR, "unrecognized jsonpath item type: %d", v->type); } @@ -958,12 +958,12 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos) void jspGetArg(JsonPathItem *v, JsonPathItem *a) { - Assert(v->type == jpiFilter || - v->type == jpiNot || + Assert(v->type == jpiNot || v->type == jpiIsUnknown || - v->type == jpiExists || v->type == jpiPlus || v->type == jpiMinus || + v->type == jpiFilter || + v->type == jpiExists || v->type == jpiDatetime); jspInitByBuffer(a, v->base, v->content.arg); @@ -974,21 +974,20 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a) { if (jspHasNext(v)) { - Assert(v->type == jpiString || + Assert(v->type == jpiNull || + v->type == jpiString || v->type == jpiNumeric || v->type == jpiBool || - v->type == jpiNull || - v->type == jpiKey || - v->type == jpiAny || - v->type == jpiAnyArray || - v->type == jpiAnyKey || - v->type == jpiIndexArray || - v->type == jpiFilter || - v->type == jpiCurrent || - v->type == jpiExists || - v->type == jpiRoot || - v->type == jpiVariable || - v->type == jpiLast || + v->type == jpiAnd || + v->type == jpiOr || + v->type == jpiNot || + v->type == jpiIsUnknown || + v->type == jpiEqual || + v->type == jpiNotEqual || + v->type == jpiLess || + v->type == jpiGreater || + v->type == jpiLessOrEqual || + v->type == jpiGreaterOrEqual || v->type == jpiAdd || v->type == jpiSub || v->type == jpiMul || @@ -996,16 +995,16 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a) v->type == jpiMod || v->type == jpiPlus || v->type == jpiMinus || - v->type == jpiEqual || - v->type == jpiNotEqual || - v->type == jpiGreater || - v->type == jpiGreaterOrEqual || - v->type == jpiLess || - v->type == jpiLessOrEqual || - v->type == jpiAnd || - v->type == jpiOr || - v->type == jpiNot || - v->type == jpiIsUnknown || + v->type == jpiAnyArray || + v->type == jpiAnyKey || + v->type == jpiIndexArray || + v->type == jpiAny || + v->type == jpiKey || + v->type == jpiCurrent || + v->type == jpiRoot || + v->type == jpiVariable || + v->type == jpiFilter || + v->type == jpiExists || v->type == jpiType || v->type == jpiSize || v->type == jpiAbs || @@ -1014,6 +1013,7 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a) v->type == jpiDouble || v->type == jpiDatetime || v->type == jpiKeyValue || + v->type == jpiLast || v->type == jpiStartsWith || v->type == jpiLikeRegex); diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 9a09604f642..163b75eb815 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -621,6 +621,37 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, switch (jsp->type) { + case jpiNull: + case jpiBool: + case jpiNumeric: + case jpiString: + case jpiVariable: + { + JsonbValue vbuf; + JsonbValue *v; + bool hasNext = jspGetNext(jsp, &elem); + + if (!hasNext && !found && jsp->type != jpiVariable) + { + /* + * Skip evaluation, but not for variables. We must + * trigger an error for the missing variable. + */ + res = jperOk; + break; + } + + v = hasNext ? &vbuf : palloc(sizeof(*v)); + + baseObject = cxt->baseObject; + getJsonPathItem(cxt, jsp, v); + + res = executeNextItem(cxt, jsp, &elem, + v, found, hasNext); + cxt->baseObject = baseObject; + } + break; + /* all boolean item types: */ case jpiAnd: case jpiOr: @@ -642,63 +673,32 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, break; } - case jpiKey: - if (JsonbType(jb) == jbvObject) - { - JsonbValue *v; - JsonbValue key; - - key.type = jbvString; - key.val.string.val = jspGetString(jsp, &key.val.string.len); - - v = findJsonbValueFromContainer(jb->val.binary.data, - JB_FOBJECT, &key); + case jpiAdd: + return executeBinaryArithmExpr(cxt, jsp, jb, + numeric_add_opt_error, found); - if (v != NULL) - { - res = executeNextItem(cxt, jsp, NULL, - v, found, false); + case jpiSub: + return executeBinaryArithmExpr(cxt, jsp, jb, + numeric_sub_opt_error, found); - /* free value if it was not added to found list */ - if (jspHasNext(jsp) || !found) - pfree(v); - } - else if (!jspIgnoreStructuralErrors(cxt)) - { - Assert(found); + case jpiMul: + return executeBinaryArithmExpr(cxt, jsp, jb, + numeric_mul_opt_error, found); - if (!jspThrowErrors(cxt)) - return jperError; + case jpiDiv: + return executeBinaryArithmExpr(cxt, jsp, jb, + numeric_div_opt_error, found); - ereport(ERROR, - (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \ - errmsg("JSON object does not contain key \"%s\"", - pnstrdup(key.val.string.val, - key.val.string.len)))); - } - } - else if (unwrap && JsonbType(jb) == jbvArray) - return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false); - else if (!jspIgnoreStructuralErrors(cxt)) - { - Assert(found); - RETURN_ERROR(ereport(ERROR, - (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), - errmsg("jsonpath member accessor can only be applied to an object")))); - } - break; + case jpiMod: + return executeBinaryArithmExpr(cxt, jsp, jb, + numeric_mod_opt_error, found); - case jpiRoot: - jb = cxt->root; - baseObject = setBaseObject(cxt, jb, 0); - res = executeNextItem(cxt, jsp, NULL, jb, found, true); - cxt->baseObject = baseObject; - break; + case jpiPlus: + return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found); - case jpiCurrent: - res = executeNextItem(cxt, jsp, NULL, cxt->current, - found, true); - break; + case jpiMinus: + return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus, + found); case jpiAnyArray: if (JsonbType(jb) == jbvArray) @@ -716,6 +716,30 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, errmsg("jsonpath wildcard array accessor can only be applied to an array")))); break; + case jpiAnyKey: + if (JsonbType(jb) == jbvObject) + { + bool hasNext = jspGetNext(jsp, &elem); + + if (jb->type != jbvBinary) + elog(ERROR, "invalid jsonb object type: %d", jb->type); + + return executeAnyItem + (cxt, hasNext ? &elem : NULL, + jb->val.binary.data, found, 1, 1, 1, + false, jspAutoUnwrap(cxt)); + } + else if (unwrap && JsonbType(jb) == jbvArray) + return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false); + else if (!jspIgnoreStructuralErrors(cxt)) + { + Assert(found); + RETURN_ERROR(ereport(ERROR, + (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND), + errmsg("jsonpath wildcard member accessor can only be applied to an object")))); + } + break; + case jpiIndexArray: if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt)) { @@ -822,46 +846,70 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, } break; - case jpiLast: + case jpiAny: { - JsonbValue tmpjbv; - JsonbValue *lastjbv; - int last; bool hasNext = jspGetNext(jsp, &elem); - if (cxt->innermostArraySize < 0) - elog(ERROR, "evaluating jsonpath LAST outside of array subscript"); - - if (!hasNext && !found) + /* first try without any intermediate steps */ + if (jsp->content.anybounds.first == 0) { - res = jperOk; - break; - } - - last = cxt->innermostArraySize - 1; + bool savedIgnoreStructuralErrors; - lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv)); + savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors; + cxt->ignoreStructuralErrors = true; + res = executeNextItem(cxt, jsp, &elem, + jb, found, true); + cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors; - lastjbv->type = jbvNumeric; - lastjbv->val.numeric = int64_to_numeric(last); + if (res == jperOk && !found) + break; + } - res = executeNextItem(cxt, jsp, &elem, - lastjbv, found, hasNext); + if (jb->type == jbvBinary) + res = executeAnyItem + (cxt, hasNext ? &elem : NULL, + jb->val.binary.data, found, + 1, + jsp->content.anybounds.first, + jsp->content.anybounds.last, + true, jspAutoUnwrap(cxt)); + break; } - break; - case jpiAnyKey: + case jpiKey: if (JsonbType(jb) == jbvObject) { - bool hasNext = jspGetNext(jsp, &elem); + JsonbValue *v; + JsonbValue key; - if (jb->type != jbvBinary) - elog(ERROR, "invalid jsonb object type: %d", jb->type); + key.type = jbvString; + key.val.string.val = jspGetString(jsp, &key.val.string.len); - return executeAnyItem - (cxt, hasNext ? &elem : NULL, - jb->val.binary.data, found, 1, 1, 1, - false, jspAutoUnwrap(cxt)); + v = findJsonbValueFromContainer(jb->val.binary.data, + JB_FOBJECT, &key); + + if (v != NULL) + { + res = executeNextItem(cxt, jsp, NULL, + v, found, false); + + /* free value if it was not added to found list */ + if (jspHasNext(jsp) || !found) + pfree(v); + } + else if (!jspIgnoreStructuralErrors(cxt)) + { + Assert(found); + + if (!jspThrowErrors(cxt)) + return jperError; + + ereport(ERROR, + (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \ + errmsg("JSON object does not contain key \"%s\"", + pnstrdup(key.val.string.val, + key.val.string.len)))); + } } else if (unwrap && JsonbType(jb) == jbvArray) return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false); @@ -869,37 +917,22 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, { Assert(found); RETURN_ERROR(ereport(ERROR, - (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND), - errmsg("jsonpath wildcard member accessor can only be applied to an object")))); + (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), + errmsg("jsonpath member accessor can only be applied to an object")))); } 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 jpiCurrent: + res = executeNextItem(cxt, jsp, NULL, cxt->current, + found, true); + break; - case jpiMinus: - return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus, - found); + case jpiRoot: + jb = cxt->root; + baseObject = setBaseObject(cxt, jb, 0); + res = executeNextItem(cxt, jsp, NULL, jb, found, true); + cxt->baseObject = baseObject; + break; case jpiFilter: { @@ -919,67 +952,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, break; } - case jpiAny: - { - bool hasNext = jspGetNext(jsp, &elem); - - /* first try without any intermediate steps */ - if (jsp->content.anybounds.first == 0) - { - bool savedIgnoreStructuralErrors; - - savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors; - cxt->ignoreStructuralErrors = true; - res = executeNextItem(cxt, jsp, &elem, - jb, found, true); - cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors; - - if (res == jperOk && !found) - break; - } - - if (jb->type == jbvBinary) - res = executeAnyItem - (cxt, hasNext ? &elem : NULL, - jb->val.binary.data, found, - 1, - jsp->content.anybounds.first, - jsp->content.anybounds.last, - true, jspAutoUnwrap(cxt)); - break; - } - - case jpiNull: - case jpiBool: - case jpiNumeric: - case jpiString: - case jpiVariable: - { - JsonbValue vbuf; - JsonbValue *v; - bool hasNext = jspGetNext(jsp, &elem); - - if (!hasNext && !found && jsp->type != jpiVariable) - { - /* - * Skip evaluation, but not for variables. We must - * trigger an error for the missing variable. - */ - res = jperOk; - break; - } - - v = hasNext ? &vbuf : palloc(sizeof(*v)); - - baseObject = cxt->baseObject; - getJsonPathItem(cxt, jsp, v); - - res = executeNextItem(cxt, jsp, &elem, - v, found, hasNext); - cxt->baseObject = baseObject; - } - break; - case jpiType: { JsonbValue *jbv = palloc(sizeof(*jbv)); @@ -1110,6 +1082,34 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, return executeKeyValueMethod(cxt, jsp, jb, found); + case jpiLast: + { + JsonbValue tmpjbv; + JsonbValue *lastjbv; + int last; + bool hasNext = jspGetNext(jsp, &elem); + + if (cxt->innermostArraySize < 0) + elog(ERROR, "evaluating jsonpath LAST outside of array subscript"); + + if (!hasNext && !found) + { + res = jperOk; + break; + } + + last = cxt->innermostArraySize - 1; + + lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv)); + + lastjbv->type = jbvNumeric; + lastjbv->val.numeric = int64_to_numeric(last); + + res = executeNextItem(cxt, jsp, &elem, + lastjbv, found, hasNext); + } + break; + default: elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type); } diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h index f0181e045f7..0a3a6330170 100644 --- a/src/include/utils/jsonpath.h +++ b/src/include/utils/jsonpath.h @@ -49,6 +49,13 @@ DatumGetJsonPathPCopy(Datum d) /* * All node's type of jsonpath expression + * + * These become part of the on-disk representation of the jsonpath type. + * Therefore, to preserve pg_upgradability, the order must not be changed, and + * new values must be added at the end. + * + * It is recommended that switch cases etc. in other parts of the code also + * use this order, to maintain some consistency. */ typedef enum JsonPathItemType { |