Skip to content

Commit 0abe1a1

Browse files
author
Nikita Glukhov
committed
Add raw jbvArray and jbvObject support to jsonpath
1 parent 55e4b88 commit 0abe1a1

File tree

1 file changed

+85
-11
lines changed

1 file changed

+85
-11
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ static JsonbValue *JsonbInitBinary(JsonbValue *jbv, Jsonb *jb);
254254
static int JsonbType(JsonbValue *jb);
255255
static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
256256
static JsonbValue *wrapItemsInArray(const JsonValueList *items);
257+
static JsonbValue *wrapJsonObjectOrArray(JsonbValue *jbv, JsonbValue *buf);
257258
static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
258259
bool useTz, bool *have_error);
259260

@@ -646,7 +647,14 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
646647
}
647648

648649
case jpiKey:
649-
if (JsonbType(jb) == jbvObject)
650+
if (jb->type == jbvObject)
651+
{
652+
JsonbValue obj;
653+
654+
jb = wrapJsonObjectOrArray(jb, &obj);
655+
return executeItemOptUnwrapTarget(cxt, jsp, jb, found, unwrap);
656+
}
657+
else if (jb->type == jbvBinary && JsonbType(jb) == jbvObject)
650658
{
651659
JsonbValue *v;
652660
JsonbValue key;
@@ -725,6 +733,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
725733
int innermostArraySize = cxt->innermostArraySize;
726734
int i;
727735
int size = JsonbArraySize(jb);
736+
bool binary = jb->type == jbvBinary;
728737
bool singleton = size < 0;
729738
bool hasNext = jspGetNext(jsp, &elem);
730739

@@ -784,7 +793,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
784793
v = jb;
785794
copy = true;
786795
}
787-
else
796+
else if (binary)
788797
{
789798
v = getIthJsonbValueFromContainer(jb->val.binary.data,
790799
(uint32) index);
@@ -794,6 +803,11 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
794803

795804
copy = false;
796805
}
806+
else
807+
{
808+
v = &jb->val.array.elems[index];
809+
copy = true;
810+
}
797811

798812
if (!hasNext && !found)
799813
return jperOk;
@@ -858,10 +872,10 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
858872
case jpiAnyKey:
859873
if (JsonbType(jb) == jbvObject)
860874
{
875+
JsonbValue bin;
861876
bool hasNext = jspGetNext(jsp, &elem);
862877

863-
if (jb->type != jbvBinary)
864-
elog(ERROR, "invalid jsonb object type: %d", jb->type);
878+
jb = wrapJsonObjectOrArray(jb, &bin);
865879

866880
return executeAnyItem
867881
(cxt, hasNext ? &elem : NULL,
@@ -926,8 +940,11 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
926940

927941
case jpiAny:
928942
{
943+
JsonbValue bin;
929944
bool hasNext = jspGetNext(jsp, &elem);
930945

946+
jb = wrapJsonObjectOrArray(jb, &bin);
947+
931948
/* first try without any intermediate steps */
932949
if (jsp->content.anybounds.first == 0)
933950
{
@@ -1127,10 +1144,34 @@ executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
11271144
JsonbValue *jb, JsonValueList *found,
11281145
bool unwrapElements)
11291146
{
1130-
if (jb->type != jbvBinary)
1147+
if (jb->type == jbvArray)
11311148
{
1132-
Assert(jb->type != jbvArray);
1133-
elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1149+
JsonPathExecResult res = jperNotFound;
1150+
JsonbValue *elem = jb->val.array.elems;
1151+
JsonbValue *last = elem + jb->val.array.nElems;
1152+
1153+
for (; elem < last; elem++)
1154+
{
1155+
if (jsp)
1156+
{
1157+
res = executeItemOptUnwrapTarget(cxt, jsp, elem, found,
1158+
unwrapElements);
1159+
1160+
if (jperIsError(res))
1161+
break;
1162+
if (res == jperOk && !found)
1163+
break;
1164+
}
1165+
else
1166+
{
1167+
if (found)
1168+
JsonValueListAppend(found, copyJsonbValue(elem));
1169+
else
1170+
return jperOk;
1171+
}
1172+
}
1173+
1174+
return res;
11341175
}
11351176

11361177
return executeAnyItem
@@ -1191,8 +1232,6 @@ executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
11911232
JsonValueListInitIterator(&seq, &it);
11921233
while ((item = JsonValueListNext(&seq, &it)))
11931234
{
1194-
Assert(item->type != jbvArray);
1195-
11961235
if (JsonbType(item) == jbvArray)
11971236
executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
11981237
else
@@ -1940,6 +1979,7 @@ executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
19401979
JsonPathExecResult res = jperNotFound;
19411980
JsonPathItem next;
19421981
JsonbContainer *jbc;
1982+
JsonbValue bin;
19431983
JsonbValue key;
19441984
JsonbValue val;
19451985
JsonbValue idval;
@@ -1951,12 +1991,13 @@ executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
19511991
int64 id;
19521992
bool hasNext;
19531993

1954-
if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
1994+
if (JsonbType(jb) != jbvObject)
19551995
RETURN_ERROR(ereport(ERROR,
19561996
(errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
19571997
errmsg("jsonpath item method .%s() can only be applied to an object",
19581998
jspOperationName(jsp->type)))));
19591999

2000+
jb = wrapJsonObjectOrArray(jb, &bin);
19602001
jbc = jb->val.binary.data;
19612002

19622003
if (!JsonContainerSize(jbc))
@@ -2153,7 +2194,8 @@ getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
21532194
static int
21542195
JsonbArraySize(JsonbValue *jb)
21552196
{
2156-
Assert(jb->type != jbvArray);
2197+
if (jb->type == jbvArray)
2198+
return jb->val.array.nElems;
21572199

21582200
if (jb->type == jbvBinary)
21592201
{
@@ -2529,6 +2571,33 @@ JsonbInitBinary(JsonbValue *jbv, Jsonb *jb)
25292571
return jbv;
25302572
}
25312573

2574+
/*
2575+
* Transform a JsonbValue into a binary JsonbValue by encoding it to a
2576+
* binary jsonb container.
2577+
*/
2578+
static JsonbValue *
2579+
JsonbWrapInBinary(JsonbValue *jbv, JsonbValue *out)
2580+
{
2581+
Jsonb *jb;
2582+
2583+
if (!out)
2584+
out = palloc(sizeof(*out));
2585+
2586+
jb = JsonbValueToJsonb(jbv);
2587+
JsonbInitBinary(out, jb);
2588+
2589+
return out;
2590+
}
2591+
2592+
static JsonbValue *
2593+
wrapJsonObjectOrArray(JsonbValue *jbv, JsonbValue *buf)
2594+
{
2595+
if (jbv->type != jbvObject && jbv->type != jbvArray)
2596+
return jbv;
2597+
2598+
return JsonbWrapInBinary(jbv, buf);
2599+
}
2600+
25322601
/*
25332602
* Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
25342603
*/
@@ -2578,7 +2647,12 @@ wrapItemsInArray(const JsonValueList *items)
25782647

25792648
JsonValueListInitIterator(items, &it);
25802649
while ((jbv = JsonValueListNext(items, &it)))
2650+
{
2651+
JsonbValue bin;
2652+
2653+
jbv = wrapJsonObjectOrArray(jbv, &bin);
25812654
pushJsonbValue(&ps, WJB_ELEM, jbv);
2655+
}
25822656

25832657
return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
25842658
}

0 commit comments

Comments
 (0)