Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 27c4a39

Browse files
author
Nikita Glukhov
committed
Add raw jbvArray and jbvObject support to jsonpath
1 parent 13410cc commit 27c4a39

File tree

1 file changed

+103
-13
lines changed

1 file changed

+103
-13
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 103 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ static inline JsonbValue *JsonInitBinary(JsonbValue *jbv, Json *js);
409409
static JsonItem *getScalar(JsonItem *scalar, enum jbvType type);
410410
static JsonbValue *wrapItemsInArray(const JsonValueList *items, bool isJsonb);
411411
static text *JsonItemUnquoteText(JsonItem *jsi, bool isJsonb);
412+
static JsonItem *wrapJsonObjectOrArray(JsonItem *js, JsonItem *buf,
413+
bool isJsonb);
412414

413415
static JsonItem *getJsonObjectKey(JsonItem *jb, char *keystr, int keylen,
414416
bool isJsonb, JsonItem *val);
@@ -945,7 +947,15 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
945947
}
946948

947949
case jpiKey:
948-
if (JsonbType(jb) == jbvObject)
950+
if (JsonItemIsObject(jb))
951+
{
952+
JsonItem obj;
953+
954+
jb = wrapJsonObjectOrArray(jb, &obj, cxt->isJsonb);
955+
return executeItemOptUnwrapTarget(cxt, jsp, jb, found, unwrap);
956+
}
957+
else if (JsonItemIsBinary(jb) &&
958+
JsonContainerIsObject(JsonItemBinary(jb).data))
949959
{
950960
JsonItem val;
951961
int keylen;
@@ -1015,6 +1025,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
10151025
int innermostArraySize = cxt->innermostArraySize;
10161026
int i;
10171027
int size = JsonxArraySize(jb, cxt->isJsonb);
1028+
bool binary = JsonItemIsBinary(jb);
10181029
bool singleton = size < 0;
10191030
bool hasNext = jspGetNext(jsp, &elem);
10201031

@@ -1073,14 +1084,19 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
10731084
{
10741085
jsi = jb;
10751086
}
1076-
else
1087+
else if (binary)
10771088
{
10781089
jsi = getJsonArrayElement(jb, (uint32) index,
10791090
cxt->isJsonb, &jsibuf);
10801091

10811092
if (jsi == NULL)
10821093
continue;
10831094
}
1095+
else
1096+
{
1097+
jsi = JsonbValueToJsonItem(&JsonItemArray(jb).elems[index],
1098+
&jsibuf);
1099+
}
10841100

10851101
if (!hasNext && !found)
10861102
return jperOk;
@@ -1143,11 +1159,10 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
11431159
case jpiAnyKey:
11441160
if (JsonbType(jb) == jbvObject)
11451161
{
1162+
JsonItem bin;
11461163
bool hasNext = jspGetNext(jsp, &elem);
11471164

1148-
if (!JsonItemIsBinary(jb))
1149-
elog(ERROR, "invalid jsonb object type: %d",
1150-
JsonItemGetType(jb));
1165+
jb = wrapJsonObjectOrArray(jb, &bin, cxt->isJsonb);
11511166

11521167
return executeAnyItem
11531168
(cxt, hasNext ? &elem : NULL,
@@ -1212,8 +1227,11 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
12121227

12131228
case jpiAny:
12141229
{
1230+
JsonItem bin;
12151231
bool hasNext = jspGetNext(jsp, &elem);
12161232

1233+
jb = wrapJsonObjectOrArray(jb, &bin, cxt->isJsonb);
1234+
12171235
/* first try without any intermediate steps */
12181236
if (jsp->content.anybounds.first == 0)
12191237
{
@@ -1557,10 +1575,41 @@ executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
15571575
JsonItem *jb, JsonValueList *found,
15581576
bool unwrapElements)
15591577
{
1560-
if (!JsonItemIsBinary(jb))
1578+
if (JsonItemIsArray(jb))
15611579
{
1562-
Assert(!JsonItemIsArray(jb));
1563-
elog(ERROR, "invalid jsonb array value type: %d", JsonItemGetType(jb));
1580+
JsonPathExecResult res = jperNotFound;
1581+
JsonbValue *elem = JsonItemArray(jb).elems;
1582+
JsonbValue *last = elem + JsonItemArray(jb).nElems;
1583+
1584+
for (; elem < last; elem++)
1585+
{
1586+
if (jsp)
1587+
{
1588+
JsonItem buf;
1589+
1590+
res = executeItemOptUnwrapTarget(cxt, jsp,
1591+
JsonbValueToJsonItem(elem, &buf),
1592+
found, unwrapElements);
1593+
1594+
if (jperIsError(res))
1595+
break;
1596+
if (res == jperOk && !found)
1597+
break;
1598+
}
1599+
else
1600+
{
1601+
if (found)
1602+
{
1603+
JsonItem *jsi = palloc(sizeof(*jsi));
1604+
1605+
JsonValueListAppend(found, JsonbValueToJsonItem(elem, jsi));
1606+
}
1607+
else
1608+
return jperOk;
1609+
}
1610+
}
1611+
1612+
return res;
15641613
}
15651614

15661615
return executeAnyItem
@@ -1639,8 +1688,6 @@ executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
16391688
JsonValueListInitIterator(&seq, &it);
16401689
while ((item = JsonValueListNext(&seq, &it)))
16411690
{
1642-
Assert(!JsonItemIsArray(item));
1643-
16441691
if (JsonbType(item) == jbvArray)
16451692
executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
16461693
else
@@ -2266,6 +2313,7 @@ executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
22662313
JsonPathExecResult res = jperNotFound;
22672314
JsonPathItem next;
22682315
JsonbContainer *jbc;
2316+
JsonItem bin;
22692317
JsonbValue key;
22702318
JsonbValue val;
22712319
JsonbValue idval;
@@ -2278,12 +2326,13 @@ executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
22782326
int64 id;
22792327
bool hasNext;
22802328

2281-
if (JsonbType(jb) != jbvObject || !JsonItemIsBinary(jb))
2329+
if (JsonbType(jb) != jbvObject)
22822330
RETURN_ERROR(ereport(ERROR,
22832331
(errcode(ERRCODE_JSON_OBJECT_NOT_FOUND),
22842332
errmsg("jsonpath item method .%s() can only be applied to an object",
22852333
jspOperationName(jsp->type)))));
22862334

2335+
jb = wrapJsonObjectOrArray(jb, &bin, cxt->isJsonb);
22872336
jbc = JsonItemBinary(jb).data;
22882337

22892338
if (!JsonContainerSize(jbc))
@@ -2529,7 +2578,8 @@ getJsonPathVariableFromJsonx(void *varsJsonx, bool isJsonb,
25292578
static int
25302579
JsonxArraySize(JsonItem *jb, bool isJsonb)
25312580
{
2532-
Assert(!JsonItemIsArray(jb));
2581+
if (JsonItemIsArray(jb))
2582+
return JsonItemArray(jb).nElems;
25332583

25342584
if (JsonItemIsBinary(jb))
25352585
{
@@ -2897,6 +2947,41 @@ JsonInitBinary(JsonbValue *jbv, Json *js)
28972947
return jbv;
28982948
}
28992949

2950+
/*
2951+
* Transform a JsonbValue into a binary JsonbValue by encoding it to a
2952+
* binary jsonb container.
2953+
*/
2954+
static JsonItem *
2955+
JsonxWrapInBinary(JsonItem *jsi, JsonItem *out, bool isJsonb)
2956+
{
2957+
if (!out)
2958+
out = palloc(sizeof(*out));
2959+
2960+
if (isJsonb)
2961+
{
2962+
Jsonb *jb = JsonItemToJsonb(jsi);
2963+
2964+
JsonbInitBinary(JsonItemJbv(out), jb);
2965+
}
2966+
else
2967+
{
2968+
Json *js = JsonItemToJson(jsi);
2969+
2970+
JsonInitBinary(JsonItemJbv(out), js);
2971+
}
2972+
2973+
return out;
2974+
}
2975+
2976+
static JsonItem *
2977+
wrapJsonObjectOrArray(JsonItem *js, JsonItem *buf, bool isJsonb)
2978+
{
2979+
if (!JsonItemIsObject(js) && !JsonItemIsArray(js))
2980+
return js;
2981+
2982+
return JsonxWrapInBinary(js, buf, isJsonb);
2983+
}
2984+
29002985
/*
29012986
* Returns jbv* type of of JsonbValue. Note, it never returns jbvBinary as is.
29022987
*/
@@ -3096,15 +3181,20 @@ wrapItemsInArray(const JsonValueList *items, bool isJsonb)
30963181
JsonbParseState *ps = NULL;
30973182
JsonValueListIterator it;
30983183
JsonItem *jsi;
3099-
JsonbValue jbv;
31003184
JsonBuilderFunc push = isJsonb ? pushJsonbValue : pushJsonValue;
31013185

31023186
push(&ps, WJB_BEGIN_ARRAY, NULL);
31033187

31043188
JsonValueListInitIterator(items, &it);
31053189

31063190
while ((jsi = JsonValueListNext(items, &it)))
3191+
{
3192+
JsonItem bin;
3193+
JsonbValue jbv;
3194+
3195+
jsi = wrapJsonObjectOrArray(jsi, &bin, isJsonb);
31073196
push(&ps, WJB_ELEM, JsonItemToJsonbValue(jsi, &jbv));
3197+
}
31083198

31093199
return push(&ps, WJB_END_ARRAY, NULL);
31103200
}

0 commit comments

Comments
 (0)