diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index 5cd9140896b1a8c79e27504cf0df993365199615..974e38652496001132df550a7edfa682e2710ab3 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -57,6 +57,9 @@ static void appendElement(JsonbParseState *pstate, JsonbValue *scalarVal); static int lengthCompareJsonbStringValue(const void *a, const void *b); static int lengthCompareJsonbPair(const void *a, const void *b, void *arg); static void uniqueifyJsonbObject(JsonbValue *object); +static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate, + JsonbIteratorToken seq, + JsonbValue *scalarVal); /* * Turn an in-memory JsonbValue into a Jsonb for on-disk storage. @@ -503,10 +506,43 @@ fillJsonbValue(JsonbContainer *container, int index, * * Only sequential tokens pertaining to non-container types should pass a * JsonbValue. There is one exception -- WJB_BEGIN_ARRAY callers may pass a - * "raw scalar" pseudo array to append that. + * "raw scalar" pseudo array to append it - the actual scalar should be passed + * next and it will be added as the only member of the array. + * + * Values of type jvbBinary, which are rolled up arrays and objects, + * are unpacked before being added to the result. */ JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, + JsonbValue *jbval) +{ + JsonbIterator *it; + JsonbValue *res = NULL; + JsonbValue v; + JsonbIteratorToken tok; + + if (!jbval || (seq != WJB_ELEM && seq != WJB_VALUE) || + jbval->type != jbvBinary) + { + /* drop through */ + return pushJsonbValueScalar(pstate, seq, jbval); + } + + /* unpack the binary and add each piece to the pstate */ + it = JsonbIteratorInit(jbval->val.binary.data); + while ((tok = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) + res = pushJsonbValueScalar(pstate, tok, + tok < WJB_BEGIN_ARRAY ? &v : NULL); + + return res; +} + +/* + * Do the actual pushing, with only scalar or pseudo-scalar-array values + * accepted. + */ +static JsonbValue * +pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *scalarVal) { JsonbValue *result = NULL; @@ -549,13 +585,11 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, appendKey(*pstate, scalarVal); break; case WJB_VALUE: - Assert(IsAJsonbScalar(scalarVal) || - scalarVal->type == jbvBinary); + Assert(IsAJsonbScalar(scalarVal)); appendValue(*pstate, scalarVal); break; case WJB_ELEM: - Assert(IsAJsonbScalar(scalarVal) || - scalarVal->type == jbvBinary); + Assert(IsAJsonbScalar(scalarVal)); appendElement(*pstate, scalarVal); break; case WJB_END_OBJECT: diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index 7b561759f7f22d01f80de12369250f1fa972fbcf..b02934a1aef55f9f7f862c7e8703da465d91bb0b 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -418,7 +418,7 @@ extern JsonbValue *findJsonbValueFromContainer(JsonbContainer *sheader, extern JsonbValue *getIthJsonbValueFromContainer(JsonbContainer *sheader, uint32 i); extern JsonbValue *pushJsonbValue(JsonbParseState **pstate, - JsonbIteratorToken seq, JsonbValue *scalarVal); + JsonbIteratorToken seq, JsonbValue *jbVal); extern JsonbIterator *JsonbIteratorInit(JsonbContainer *container); extern JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested);