Skip to content

Commit 63efa8e

Browse files
author
Nikita Glukhov
committed
Try to preserve formatting for text jsons
1 parent 0c2b409 commit 63efa8e

File tree

6 files changed

+57
-30
lines changed

6 files changed

+57
-30
lines changed

src/backend/utils/adt/json_generic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ jsonvContainerOps =
556556
jsonvFindValueInArray,
557557
jsonvGetArrayElement,
558558
jsonvGetArraySize,
559-
JsonbToCString,
559+
JsonbToCStringRaw,
560560
};
561561

562562
JsonValue *

src/backend/utils/adt/jsonb.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,12 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
442442
break;
443443
}
444444

445-
_state->res = pushScalarJsonbValue(&_state->parseState, &v, false);
445+
_state->res = pushScalarJsonbValue(&_state->parseState, &v, false, true);
446446
}
447447

448448
#ifndef JSON_C
449449
/*
450-
* JsonbToCString
450+
* JsonbToCStringRaw
451451
* Converts jsonb value to a C-string.
452452
*
453453
* If 'out' argument is non-null, the resulting C-string is stored inside the
@@ -458,7 +458,7 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
458458
* if they are converting it to a text* object.
459459
*/
460460
char *
461-
JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
461+
JsonbToCStringRaw(StringInfo out, JsonbContainer *in, int estimated_len)
462462
{
463463
return JsonbToCStringWorker(out, in, estimated_len, JsonFormatNormal);
464464
}
@@ -495,6 +495,7 @@ JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len,
495495
/* If we are indenting, don't add a space after a comma */
496496
int ispaces = format == JsonFormatNormal ? 2 : 1;
497497
bool indent = format == JsonFormatIndented;
498+
bool skipNested = format == JsonFormatNormal;
498499

499500
/*
500501
* Don't indent the very first item. This gets set to the indent flag at
@@ -512,7 +513,7 @@ JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len,
512513
it = JsonbIteratorInit(in);
513514

514515
while (redo_switch ||
515-
((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE))
516+
((type = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE))
516517
{
517518
redo_switch = false;
518519
switch (type)
@@ -553,11 +554,14 @@ JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len,
553554
jsonb_put_escaped_value(out, &v);
554555
appendBinaryStringInfo(out, ": ", 2);
555556

556-
type = JsonbIteratorNext(&it, &v, false);
557+
type = JsonbIteratorNext(&it, &v, skipNested);
557558
if (type == WJB_VALUE)
558559
{
559560
first = false;
560-
jsonb_put_escaped_value(out, &v);
561+
if (v.type == jbvBinary)
562+
JsonbToCString(out, v.val.binary.data, v.val.binary.len);
563+
else
564+
jsonb_put_escaped_value(out, &v);
561565
}
562566
else
563567
{
@@ -578,7 +582,11 @@ JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len,
578582

579583
if (!raw_scalar)
580584
add_indent(out, use_indent, level);
581-
jsonb_put_escaped_value(out, &v);
585+
586+
if (v.type == jbvBinary)
587+
JsonbToCString(out, v.val.binary.data, v.val.binary.len);
588+
else
589+
jsonb_put_escaped_value(out, &v);
582590
break;
583591
case WJB_END_ARRAY:
584592
level--;
@@ -903,6 +911,15 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
903911
{
904912
JsonbIteratorToken type;
905913

914+
JsonToJsonValue(jsonb, &jb);
915+
916+
if (result->parseState)
917+
{
918+
pushScalarJsonbValue(&result->parseState, &jb,
919+
false, false);
920+
return;
921+
}
922+
906923
while ((type = JsonbIteratorNext(&it, &jb, false))
907924
!= WJB_DONE)
908925
{
@@ -934,7 +951,8 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
934951
return;
935952
}
936953

937-
result->res = pushScalarJsonbValue(&result->parseState, &jb, key_scalar);
954+
result->res = pushScalarJsonbValue(&result->parseState, &jb, key_scalar,
955+
true);
938956
}
939957

940958
/*

src/backend/utils/adt/jsonb_util.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ static void appendElement(JsonbParseState *pstate, const JsonbValue *scalarVal);
101101
static int lengthCompareJsonbPair(const void *a, const void *b, void *arg);
102102
static void uniqueifyJsonbObject(JsonbValue *object);
103103
static JsonbValue *pushSingleScalarJsonbValue(JsonbParseState **pstate,
104-
const JsonbValue *jbval);
104+
const JsonbValue *jbval,
105+
bool unpackBinary);
105106
static void jsonbInitContainer(JsonContainerData *jc, JsonbContainer *jbc, int len);
106107

107108
JsonValue *
@@ -163,7 +164,7 @@ JsonValueFlatten(const JsonValue *val, JsonValueEncoder encoder,
163164
if (IsAJsonbScalar(val))
164165
{
165166
JsonbParseState *pstate = NULL;
166-
val = pushSingleScalarJsonbValue(&pstate, val);
167+
val = pushSingleScalarJsonbValue(&pstate, val, true);
167168
}
168169
else
169170
{
@@ -695,16 +696,16 @@ JsonbParseStateClone(JsonbParseState *state)
695696
* are unpacked before being added to the result.
696697
*/
697698
JsonbValue *
698-
pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq,
699-
const JsonbValue *jbval)
699+
pushJsonbValueExt(JsonbParseState **pstate, JsonbIteratorToken seq,
700+
const JsonbValue *jbval, bool unpackBinary)
700701
{
701702
JsonIterator *it;
702703
JsonbValue *res = NULL;
703704
JsonbValue v;
704705
JsonbIteratorToken tok;
705706

706707
if (!jbval || (seq != WJB_ELEM && seq != WJB_VALUE) ||
707-
jbval->type != jbvBinary)
708+
jbval->type != jbvBinary || !unpackBinary)
708709
{
709710
/* drop through */
710711
return pushJsonbValueScalar(pstate, seq, jbval);
@@ -772,7 +773,7 @@ pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq,
772773
appendValue(*pstate, scalarVal);
773774
break;
774775
case WJB_ELEM:
775-
Assert(IsAJsonbScalar(scalarVal));
776+
/* Assert(IsAJsonbScalar(scalarVal)); */
776777
appendElement(*pstate, scalarVal);
777778
break;
778779
case WJB_END_OBJECT:
@@ -811,7 +812,8 @@ pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq,
811812
}
812813

813814
static JsonbValue *
814-
pushSingleScalarJsonbValue(JsonbParseState **pstate, const JsonbValue *jbval)
815+
pushSingleScalarJsonbValue(JsonbParseState **pstate, const JsonbValue *jbval,
816+
bool unpackBinary)
815817
{
816818
/* single root scalar */
817819
JsonbValue va;
@@ -821,20 +823,21 @@ pushSingleScalarJsonbValue(JsonbParseState **pstate, const JsonbValue *jbval)
821823
va.val.array.nElems = 1;
822824

823825
pushJsonbValue(pstate, WJB_BEGIN_ARRAY, &va);
824-
pushJsonbValue(pstate, WJB_ELEM, jbval);
826+
pushJsonbValueExt(pstate, WJB_ELEM, jbval, unpackBinary);
825827
return pushJsonbValue(pstate, WJB_END_ARRAY, NULL);
826828
}
827829

828830
static JsonbValue *
829831
pushNestedScalarJsonbValue(JsonbParseState **pstate, const JsonbValue *jbval,
830-
bool isKey)
832+
bool isKey, bool unpackBinary)
831833
{
832834
switch ((*pstate)->contVal.type)
833835
{
834836
case jbvArray:
835-
return pushJsonbValue(pstate, WJB_ELEM, jbval);
837+
return pushJsonbValueExt(pstate, WJB_ELEM, jbval, unpackBinary);
836838
case jbvObject:
837-
return pushJsonbValue(pstate, isKey ? WJB_KEY : WJB_VALUE, jbval);
839+
return pushJsonbValueExt(pstate, isKey ? WJB_KEY : WJB_VALUE, jbval,
840+
unpackBinary);
838841
default:
839842
elog(ERROR, "unexpected parent of nested structure");
840843
return NULL;
@@ -843,11 +846,11 @@ pushNestedScalarJsonbValue(JsonbParseState **pstate, const JsonbValue *jbval,
843846

844847
JsonbValue *
845848
pushScalarJsonbValue(JsonbParseState **pstate, const JsonbValue *jbval,
846-
bool isKey)
849+
bool isKey, bool unpackBinary)
847850
{
848851
return *pstate == NULL
849-
? pushSingleScalarJsonbValue(pstate, jbval)
850-
: pushNestedScalarJsonbValue(pstate, jbval, isKey);
852+
? pushSingleScalarJsonbValue(pstate, jbval, unpackBinary)
853+
: pushNestedScalarJsonbValue(pstate, jbval, isKey, unpackBinary);
851854

852855
}
853856

@@ -2155,5 +2158,5 @@ jsonbContainerOps =
21552158
jsonbFindValueInArray,
21562159
jsonbGetArrayElement,
21572160
NULL,
2158-
JsonbToCString,
2161+
JsonbToCStringRaw,
21592162
};

src/backend/utils/adt/jsonfuncs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4278,7 +4278,7 @@ addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb)
42784278
Assert(v.type == jbvArray);
42794279
(void) JsonbIteratorNext(&it, &v, false); /* fetch scalar value */
42804280

4281-
(void) pushScalarJsonbValue(jbps, &v, false);
4281+
(void) pushScalarJsonbValue(jbps, &v, false, true);
42824282
}
42834283
else
42844284
{

src/include/utils/json_generic.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ extern JsonValue *JsonContainerExtractKeys(JsonContainer *jsc);
298298
extern JsonValue *JsonValueFromCString(char *json, int len);
299299

300300

301-
extern char *JsonbToCString(StringInfo out, JsonContainer *in,
301+
extern char *JsonbToCStringRaw(StringInfo out, JsonContainer *in,
302302
int estimated_len);
303303
extern char *JsonbToCStringIndent(StringInfo out, JsonContainer *in,
304304
int estimated_len);
@@ -310,6 +310,9 @@ extern char *JsonbToCStringCanonical(StringInfo out, JsonContainer *in,
310310
#define JsonToCStringExt(out, in, estimated_len) \
311311
((*(in)->ops->toString)(out, in, estimated_len))
312312

313+
#define JsonbToCString(out, in, estimated_len) \
314+
JsonToCStringExt(out, in, estimated_len)
315+
313316
extern JsonValue *jsonFindKeyInObject(JsonContainer *obj, const char *key, int len);
314317
extern JsonValue *jsonFindLastKeyInObject(JsonContainer *obj, const char *key, int len);
315318
extern JsonValue *jsonFindValueInArray(JsonContainer *array, const JsonValue *elem);

src/include/utils/jsonb.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,17 @@ extern JsonbValue *findJsonbValueFromContainer(const JsonbContainer *sheader,
354354
extern JsonbValue *getKeyJsonValueFromContainer(const struct JsonContainerData *container,
355355
const char *keyVal, int keyLen,
356356
JsonbValue *res);
357-
extern JsonbValue *pushJsonbValue(JsonbParseState **pstate,
358-
JsonbIteratorToken seq,
359-
const JsonbValue *jbval);
357+
extern JsonbValue *pushJsonbValueExt(JsonbParseState **pstate,
358+
JsonbIteratorToken seq,
359+
const JsonbValue *jbVal,
360+
bool unpackBinary);
361+
#define pushJsonbValue(pstate, seq, jv) pushJsonbValueExt(pstate, seq, jv, true)
360362
extern JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate,
361363
JsonbIteratorToken seq,
362364
const JsonbValue *scalarVal);
363365
extern JsonbValue *pushScalarJsonbValue(JsonbParseState **pstate,
364-
const JsonbValue *jbval, bool isKey);
366+
const JsonbValue *jbval, bool isKey,
367+
bool unpackBinary);
365368
extern JsonbParseState *JsonbParseStateClone(JsonbParseState *state);
366369
typedef struct JsonIteratorData JsonIterator;
367370
extern JsonbIteratorToken JsonbIteratorNext(JsonIterator **it, JsonbValue *val,

0 commit comments

Comments
 (0)