mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Second attempt at organizing jsonpath operators and methods
Second attempt at 283a95da92
. Since we can't reorder the enum values
of JsonPathItemType, instead reorder the switch cases where they are
used to generally follow the order of the enum values, for better
maintainability.
This commit is contained in:
@ -519,18 +519,9 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
|
|||||||
case jpiNull:
|
case jpiNull:
|
||||||
appendStringInfoString(buf, "null");
|
appendStringInfoString(buf, "null");
|
||||||
break;
|
break;
|
||||||
case jpiKey:
|
|
||||||
if (inKey)
|
|
||||||
appendStringInfoChar(buf, '.');
|
|
||||||
escape_json(buf, jspGetString(v, NULL));
|
|
||||||
break;
|
|
||||||
case jpiString:
|
case jpiString:
|
||||||
escape_json(buf, jspGetString(v, NULL));
|
escape_json(buf, jspGetString(v, NULL));
|
||||||
break;
|
break;
|
||||||
case jpiVariable:
|
|
||||||
appendStringInfoChar(buf, '$');
|
|
||||||
escape_json(buf, jspGetString(v, NULL));
|
|
||||||
break;
|
|
||||||
case jpiNumeric:
|
case jpiNumeric:
|
||||||
if (jspHasNext(v))
|
if (jspHasNext(v))
|
||||||
appendStringInfoChar(buf, '(');
|
appendStringInfoChar(buf, '(');
|
||||||
@ -576,58 +567,6 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
|
|||||||
if (printBracketes)
|
if (printBracketes)
|
||||||
appendStringInfoChar(buf, ')');
|
appendStringInfoChar(buf, ')');
|
||||||
break;
|
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:
|
case jpiNot:
|
||||||
appendStringInfoString(buf, "!(");
|
appendStringInfoString(buf, "!(");
|
||||||
jspGetArg(v, &elem);
|
jspGetArg(v, &elem);
|
||||||
@ -640,22 +579,17 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
|
|||||||
printJsonPathItem(buf, &elem, false, false);
|
printJsonPathItem(buf, &elem, false, false);
|
||||||
appendStringInfoString(buf, ") is unknown");
|
appendStringInfoString(buf, ") is unknown");
|
||||||
break;
|
break;
|
||||||
case jpiExists:
|
case jpiPlus:
|
||||||
appendStringInfoString(buf, "exists (");
|
case jpiMinus:
|
||||||
|
if (printBracketes)
|
||||||
|
appendStringInfoChar(buf, '(');
|
||||||
|
appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
|
||||||
jspGetArg(v, &elem);
|
jspGetArg(v, &elem);
|
||||||
printJsonPathItem(buf, &elem, false, false);
|
printJsonPathItem(buf, &elem, false,
|
||||||
appendStringInfoChar(buf, ')');
|
operationPriority(elem.type) <=
|
||||||
break;
|
operationPriority(v->type));
|
||||||
case jpiCurrent:
|
if (printBracketes)
|
||||||
Assert(!inKey);
|
appendStringInfoChar(buf, ')');
|
||||||
appendStringInfoChar(buf, '@');
|
|
||||||
break;
|
|
||||||
case jpiRoot:
|
|
||||||
Assert(!inKey);
|
|
||||||
appendStringInfoChar(buf, '$');
|
|
||||||
break;
|
|
||||||
case jpiLast:
|
|
||||||
appendStringInfoString(buf, "last");
|
|
||||||
break;
|
break;
|
||||||
case jpiAnyArray:
|
case jpiAnyArray:
|
||||||
appendStringInfoString(buf, "[*]");
|
appendStringInfoString(buf, "[*]");
|
||||||
@ -712,6 +646,35 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
|
|||||||
v->content.anybounds.first,
|
v->content.anybounds.first,
|
||||||
v->content.anybounds.last);
|
v->content.anybounds.last);
|
||||||
break;
|
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:
|
case jpiType:
|
||||||
appendStringInfoString(buf, ".type()");
|
appendStringInfoString(buf, ".type()");
|
||||||
break;
|
break;
|
||||||
@ -742,6 +705,43 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
|
|||||||
case jpiKeyValue:
|
case jpiKeyValue:
|
||||||
appendStringInfoString(buf, ".keyvalue()");
|
appendStringInfoString(buf, ".keyvalue()");
|
||||||
break;
|
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:
|
default:
|
||||||
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
|
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
|
||||||
}
|
}
|
||||||
@ -771,11 +771,11 @@ jspOperationName(JsonPathItemType type)
|
|||||||
return "<=";
|
return "<=";
|
||||||
case jpiGreaterOrEqual:
|
case jpiGreaterOrEqual:
|
||||||
return ">=";
|
return ">=";
|
||||||
case jpiPlus:
|
|
||||||
case jpiAdd:
|
case jpiAdd:
|
||||||
|
case jpiPlus:
|
||||||
return "+";
|
return "+";
|
||||||
case jpiMinus:
|
|
||||||
case jpiSub:
|
case jpiSub:
|
||||||
|
case jpiMinus:
|
||||||
return "-";
|
return "-";
|
||||||
case jpiMul:
|
case jpiMul:
|
||||||
return "*";
|
return "*";
|
||||||
@ -783,26 +783,26 @@ jspOperationName(JsonPathItemType type)
|
|||||||
return "/";
|
return "/";
|
||||||
case jpiMod:
|
case jpiMod:
|
||||||
return "%";
|
return "%";
|
||||||
case jpiStartsWith:
|
|
||||||
return "starts with";
|
|
||||||
case jpiLikeRegex:
|
|
||||||
return "like_regex";
|
|
||||||
case jpiType:
|
case jpiType:
|
||||||
return "type";
|
return "type";
|
||||||
case jpiSize:
|
case jpiSize:
|
||||||
return "size";
|
return "size";
|
||||||
case jpiKeyValue:
|
|
||||||
return "keyvalue";
|
|
||||||
case jpiDouble:
|
|
||||||
return "double";
|
|
||||||
case jpiAbs:
|
case jpiAbs:
|
||||||
return "abs";
|
return "abs";
|
||||||
case jpiFloor:
|
case jpiFloor:
|
||||||
return "floor";
|
return "floor";
|
||||||
case jpiCeiling:
|
case jpiCeiling:
|
||||||
return "ceiling";
|
return "ceiling";
|
||||||
|
case jpiDouble:
|
||||||
|
return "double";
|
||||||
case jpiDatetime:
|
case jpiDatetime:
|
||||||
return "datetime";
|
return "datetime";
|
||||||
|
case jpiKeyValue:
|
||||||
|
return "keyvalue";
|
||||||
|
case jpiStartsWith:
|
||||||
|
return "starts with";
|
||||||
|
case jpiLikeRegex:
|
||||||
|
return "like_regex";
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unrecognized jsonpath item type: %d", type);
|
elog(ERROR, "unrecognized jsonpath item type: %d", type);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -900,8 +900,8 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
|
|||||||
case jpiKeyValue:
|
case jpiKeyValue:
|
||||||
case jpiLast:
|
case jpiLast:
|
||||||
break;
|
break;
|
||||||
case jpiKey:
|
|
||||||
case jpiString:
|
case jpiString:
|
||||||
|
case jpiKey:
|
||||||
case jpiVariable:
|
case jpiVariable:
|
||||||
read_int32(v->content.value.datalen, base, pos);
|
read_int32(v->content.value.datalen, base, pos);
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
@ -911,30 +911,24 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
|
|||||||
break;
|
break;
|
||||||
case jpiAnd:
|
case jpiAnd:
|
||||||
case jpiOr:
|
case jpiOr:
|
||||||
case jpiAdd:
|
|
||||||
case jpiSub:
|
|
||||||
case jpiMul:
|
|
||||||
case jpiDiv:
|
|
||||||
case jpiMod:
|
|
||||||
case jpiEqual:
|
case jpiEqual:
|
||||||
case jpiNotEqual:
|
case jpiNotEqual:
|
||||||
case jpiLess:
|
case jpiLess:
|
||||||
case jpiGreater:
|
case jpiGreater:
|
||||||
case jpiLessOrEqual:
|
case jpiLessOrEqual:
|
||||||
case jpiGreaterOrEqual:
|
case jpiGreaterOrEqual:
|
||||||
|
case jpiAdd:
|
||||||
|
case jpiSub:
|
||||||
|
case jpiMul:
|
||||||
|
case jpiDiv:
|
||||||
|
case jpiMod:
|
||||||
case jpiStartsWith:
|
case jpiStartsWith:
|
||||||
read_int32(v->content.args.left, base, pos);
|
read_int32(v->content.args.left, base, pos);
|
||||||
read_int32(v->content.args.right, base, pos);
|
read_int32(v->content.args.right, base, pos);
|
||||||
break;
|
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 jpiNot:
|
||||||
case jpiExists:
|
|
||||||
case jpiIsUnknown:
|
case jpiIsUnknown:
|
||||||
|
case jpiExists:
|
||||||
case jpiPlus:
|
case jpiPlus:
|
||||||
case jpiMinus:
|
case jpiMinus:
|
||||||
case jpiFilter:
|
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.first, base, pos);
|
||||||
read_int32(v->content.anybounds.last, base, pos);
|
read_int32(v->content.anybounds.last, base, pos);
|
||||||
break;
|
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:
|
default:
|
||||||
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
|
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
|
||||||
}
|
}
|
||||||
@ -958,12 +958,12 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
|
|||||||
void
|
void
|
||||||
jspGetArg(JsonPathItem *v, JsonPathItem *a)
|
jspGetArg(JsonPathItem *v, JsonPathItem *a)
|
||||||
{
|
{
|
||||||
Assert(v->type == jpiFilter ||
|
Assert(v->type == jpiNot ||
|
||||||
v->type == jpiNot ||
|
|
||||||
v->type == jpiIsUnknown ||
|
v->type == jpiIsUnknown ||
|
||||||
v->type == jpiExists ||
|
|
||||||
v->type == jpiPlus ||
|
v->type == jpiPlus ||
|
||||||
v->type == jpiMinus ||
|
v->type == jpiMinus ||
|
||||||
|
v->type == jpiFilter ||
|
||||||
|
v->type == jpiExists ||
|
||||||
v->type == jpiDatetime);
|
v->type == jpiDatetime);
|
||||||
|
|
||||||
jspInitByBuffer(a, v->base, v->content.arg);
|
jspInitByBuffer(a, v->base, v->content.arg);
|
||||||
@ -974,21 +974,20 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
|
|||||||
{
|
{
|
||||||
if (jspHasNext(v))
|
if (jspHasNext(v))
|
||||||
{
|
{
|
||||||
Assert(v->type == jpiString ||
|
Assert(v->type == jpiNull ||
|
||||||
|
v->type == jpiString ||
|
||||||
v->type == jpiNumeric ||
|
v->type == jpiNumeric ||
|
||||||
v->type == jpiBool ||
|
v->type == jpiBool ||
|
||||||
v->type == jpiNull ||
|
v->type == jpiAnd ||
|
||||||
v->type == jpiKey ||
|
v->type == jpiOr ||
|
||||||
v->type == jpiAny ||
|
v->type == jpiNot ||
|
||||||
v->type == jpiAnyArray ||
|
v->type == jpiIsUnknown ||
|
||||||
v->type == jpiAnyKey ||
|
v->type == jpiEqual ||
|
||||||
v->type == jpiIndexArray ||
|
v->type == jpiNotEqual ||
|
||||||
v->type == jpiFilter ||
|
v->type == jpiLess ||
|
||||||
v->type == jpiCurrent ||
|
v->type == jpiGreater ||
|
||||||
v->type == jpiExists ||
|
v->type == jpiLessOrEqual ||
|
||||||
v->type == jpiRoot ||
|
v->type == jpiGreaterOrEqual ||
|
||||||
v->type == jpiVariable ||
|
|
||||||
v->type == jpiLast ||
|
|
||||||
v->type == jpiAdd ||
|
v->type == jpiAdd ||
|
||||||
v->type == jpiSub ||
|
v->type == jpiSub ||
|
||||||
v->type == jpiMul ||
|
v->type == jpiMul ||
|
||||||
@ -996,16 +995,16 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
|
|||||||
v->type == jpiMod ||
|
v->type == jpiMod ||
|
||||||
v->type == jpiPlus ||
|
v->type == jpiPlus ||
|
||||||
v->type == jpiMinus ||
|
v->type == jpiMinus ||
|
||||||
v->type == jpiEqual ||
|
v->type == jpiAnyArray ||
|
||||||
v->type == jpiNotEqual ||
|
v->type == jpiAnyKey ||
|
||||||
v->type == jpiGreater ||
|
v->type == jpiIndexArray ||
|
||||||
v->type == jpiGreaterOrEqual ||
|
v->type == jpiAny ||
|
||||||
v->type == jpiLess ||
|
v->type == jpiKey ||
|
||||||
v->type == jpiLessOrEqual ||
|
v->type == jpiCurrent ||
|
||||||
v->type == jpiAnd ||
|
v->type == jpiRoot ||
|
||||||
v->type == jpiOr ||
|
v->type == jpiVariable ||
|
||||||
v->type == jpiNot ||
|
v->type == jpiFilter ||
|
||||||
v->type == jpiIsUnknown ||
|
v->type == jpiExists ||
|
||||||
v->type == jpiType ||
|
v->type == jpiType ||
|
||||||
v->type == jpiSize ||
|
v->type == jpiSize ||
|
||||||
v->type == jpiAbs ||
|
v->type == jpiAbs ||
|
||||||
@ -1014,6 +1013,7 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
|
|||||||
v->type == jpiDouble ||
|
v->type == jpiDouble ||
|
||||||
v->type == jpiDatetime ||
|
v->type == jpiDatetime ||
|
||||||
v->type == jpiKeyValue ||
|
v->type == jpiKeyValue ||
|
||||||
|
v->type == jpiLast ||
|
||||||
v->type == jpiStartsWith ||
|
v->type == jpiStartsWith ||
|
||||||
v->type == jpiLikeRegex);
|
v->type == jpiLikeRegex);
|
||||||
|
|
||||||
|
@ -621,6 +621,37 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
|
|
||||||
switch (jsp->type)
|
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: */
|
/* all boolean item types: */
|
||||||
case jpiAnd:
|
case jpiAnd:
|
||||||
case jpiOr:
|
case jpiOr:
|
||||||
@ -642,63 +673,32 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case jpiKey:
|
case jpiAdd:
|
||||||
if (JsonbType(jb) == jbvObject)
|
return executeBinaryArithmExpr(cxt, jsp, jb,
|
||||||
{
|
numeric_add_opt_error, found);
|
||||||
JsonbValue *v;
|
|
||||||
JsonbValue key;
|
|
||||||
|
|
||||||
key.type = jbvString;
|
case jpiSub:
|
||||||
key.val.string.val = jspGetString(jsp, &key.val.string.len);
|
return executeBinaryArithmExpr(cxt, jsp, jb,
|
||||||
|
numeric_sub_opt_error, found);
|
||||||
|
|
||||||
v = findJsonbValueFromContainer(jb->val.binary.data,
|
case jpiMul:
|
||||||
JB_FOBJECT, &key);
|
return executeBinaryArithmExpr(cxt, jsp, jb,
|
||||||
|
numeric_mul_opt_error, found);
|
||||||
|
|
||||||
if (v != NULL)
|
case jpiDiv:
|
||||||
{
|
return executeBinaryArithmExpr(cxt, jsp, jb,
|
||||||
res = executeNextItem(cxt, jsp, NULL,
|
numeric_div_opt_error, found);
|
||||||
v, found, false);
|
|
||||||
|
|
||||||
/* free value if it was not added to found list */
|
case jpiMod:
|
||||||
if (jspHasNext(jsp) || !found)
|
return executeBinaryArithmExpr(cxt, jsp, jb,
|
||||||
pfree(v);
|
numeric_mod_opt_error, found);
|
||||||
}
|
|
||||||
else if (!jspIgnoreStructuralErrors(cxt))
|
|
||||||
{
|
|
||||||
Assert(found);
|
|
||||||
|
|
||||||
if (!jspThrowErrors(cxt))
|
case jpiPlus:
|
||||||
return jperError;
|
return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
|
||||||
|
|
||||||
ereport(ERROR,
|
case jpiMinus:
|
||||||
(errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \
|
return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
|
||||||
errmsg("JSON object does not contain key \"%s\"",
|
found);
|
||||||
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 jpiRoot:
|
|
||||||
jb = cxt->root;
|
|
||||||
baseObject = setBaseObject(cxt, jb, 0);
|
|
||||||
res = executeNextItem(cxt, jsp, NULL, jb, found, true);
|
|
||||||
cxt->baseObject = baseObject;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case jpiCurrent:
|
|
||||||
res = executeNextItem(cxt, jsp, NULL, cxt->current,
|
|
||||||
found, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case jpiAnyArray:
|
case jpiAnyArray:
|
||||||
if (JsonbType(jb) == jbvArray)
|
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"))));
|
errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
|
||||||
break;
|
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:
|
case jpiIndexArray:
|
||||||
if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
|
if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
|
||||||
{
|
{
|
||||||
@ -822,103 +846,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
if (unwrap && JsonbType(jb) == jbvArray)
|
|
||||||
return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
|
|
||||||
false);
|
|
||||||
|
|
||||||
jspGetArg(jsp, &elem);
|
|
||||||
st = executeNestedBoolItem(cxt, &elem, jb);
|
|
||||||
if (st != jpbTrue)
|
|
||||||
res = jperNotFound;
|
|
||||||
else
|
|
||||||
res = executeNextItem(cxt, jsp, NULL,
|
|
||||||
jb, found, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case jpiAny:
|
case jpiAny:
|
||||||
{
|
{
|
||||||
bool hasNext = jspGetNext(jsp, &elem);
|
bool hasNext = jspGetNext(jsp, &elem);
|
||||||
@ -949,37 +876,82 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case jpiNull:
|
case jpiKey:
|
||||||
case jpiBool:
|
if (JsonbType(jb) == jbvObject)
|
||||||
case jpiNumeric:
|
|
||||||
case jpiString:
|
|
||||||
case jpiVariable:
|
|
||||||
{
|
{
|
||||||
JsonbValue vbuf;
|
|
||||||
JsonbValue *v;
|
JsonbValue *v;
|
||||||
bool hasNext = jspGetNext(jsp, &elem);
|
JsonbValue key;
|
||||||
|
|
||||||
if (!hasNext && !found && jsp->type != jpiVariable)
|
key.type = jbvString;
|
||||||
|
key.val.string.val = jspGetString(jsp, &key.val.string.len);
|
||||||
|
|
||||||
|
v = findJsonbValueFromContainer(jb->val.binary.data,
|
||||||
|
JB_FOBJECT, &key);
|
||||||
|
|
||||||
|
if (v != NULL)
|
||||||
{
|
{
|
||||||
/*
|
res = executeNextItem(cxt, jsp, NULL,
|
||||||
* Skip evaluation, but not for variables. We must
|
v, found, false);
|
||||||
* trigger an error for the missing variable.
|
|
||||||
*/
|
/* free value if it was not added to found list */
|
||||||
res = jperOk;
|
if (jspHasNext(jsp) || !found)
|
||||||
break;
|
pfree(v);
|
||||||
}
|
}
|
||||||
|
else if (!jspIgnoreStructuralErrors(cxt))
|
||||||
|
{
|
||||||
|
Assert(found);
|
||||||
|
|
||||||
v = hasNext ? &vbuf : palloc(sizeof(*v));
|
if (!jspThrowErrors(cxt))
|
||||||
|
return jperError;
|
||||||
|
|
||||||
baseObject = cxt->baseObject;
|
ereport(ERROR,
|
||||||
getJsonPathItem(cxt, jsp, v);
|
(errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \
|
||||||
|
errmsg("JSON object does not contain key \"%s\"",
|
||||||
res = executeNextItem(cxt, jsp, &elem,
|
pnstrdup(key.val.string.val,
|
||||||
v, found, hasNext);
|
key.val.string.len))));
|
||||||
cxt->baseObject = baseObject;
|
}
|
||||||
|
}
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
|
case jpiCurrent:
|
||||||
|
res = executeNextItem(cxt, jsp, NULL, cxt->current,
|
||||||
|
found, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case jpiRoot:
|
||||||
|
jb = cxt->root;
|
||||||
|
baseObject = setBaseObject(cxt, jb, 0);
|
||||||
|
res = executeNextItem(cxt, jsp, NULL, jb, found, true);
|
||||||
|
cxt->baseObject = baseObject;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case jpiFilter:
|
||||||
|
{
|
||||||
|
JsonPathBool st;
|
||||||
|
|
||||||
|
if (unwrap && JsonbType(jb) == jbvArray)
|
||||||
|
return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
|
||||||
|
false);
|
||||||
|
|
||||||
|
jspGetArg(jsp, &elem);
|
||||||
|
st = executeNestedBoolItem(cxt, &elem, jb);
|
||||||
|
if (st != jpbTrue)
|
||||||
|
res = jperNotFound;
|
||||||
|
else
|
||||||
|
res = executeNextItem(cxt, jsp, NULL,
|
||||||
|
jb, found, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case jpiType:
|
case jpiType:
|
||||||
{
|
{
|
||||||
JsonbValue *jbv = palloc(sizeof(*jbv));
|
JsonbValue *jbv = palloc(sizeof(*jbv));
|
||||||
@ -1110,6 +1082,34 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
|
|||||||
|
|
||||||
return executeKeyValueMethod(cxt, jsp, jb, found);
|
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:
|
default:
|
||||||
elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
|
elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,13 @@ DatumGetJsonPathPCopy(Datum d)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* All node's type of jsonpath expression
|
* 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
|
typedef enum JsonPathItemType
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user