diff --git a/src/common/backend/utils/adt/jsonb.cpp b/src/common/backend/utils/adt/jsonb.cpp index b4e0d239c959960ccab5613cf792c6b829813d54..ee419f6ff0aafe389f80ca7bfffde05537024c41 100644 --- a/src/common/backend/utils/adt/jsonb.cpp +++ b/src/common/backend/utils/adt/jsonb.cpp @@ -19,6 +19,7 @@ #include "utils/jsonapi.h" #include "utils/jsonb.h" #include "knl/knl_thread.h" +#include "miscadmin.h" typedef struct JsonbInState { JsonbParseState *parseState; @@ -374,78 +375,97 @@ char *JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len) JsonbValue v; int level = 0; bool redo_switch = false; + + /* + * Number in jsonb is stored by numeric, we should set display_leading_zero to on, + * otherwise, "0.1" will be displayed as ".1", it is not supposed for a JSON data. + */ + unsigned int original_behavior = u_sess->utils_cxt.behavior_compat_flags; + u_sess->utils_cxt.behavior_compat_flags = original_behavior | OPT_DISPLAY_LEADING_ZERO; - if (out == NULL) - out = makeStringInfo(); - - enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64); - it = JsonbIteratorInit(in); - - while (redo_switch || ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)) { - redo_switch = false; - switch (type) { - case WJB_BEGIN_ARRAY: - if (!first) - appendBinaryStringInfo(out, ", ", 2); - first = true; - - if (!v.array.rawScalar) - appendStringInfoChar(out, '['); - level++; - break; - case WJB_BEGIN_OBJECT: - if (!first) - appendBinaryStringInfo(out, ", ", 2); - first = true; - appendStringInfoCharMacro(out, '{'); - - level++; - break; - case WJB_KEY: - if (!first) - appendBinaryStringInfo(out, ", ", 2); - first = true; - - /* json rules guarantee this is a string */ - jsonb_put_escaped_value(out, &v); - appendBinaryStringInfo(out, ": ", 2); - - type = JsonbIteratorNext(&it, &v, false); - if (type == WJB_VALUE) { - first = false; + PG_TRY(); + { + if (out == NULL) + out = makeStringInfo(); + + enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64); + it = JsonbIteratorInit(in); + + while (redo_switch || ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)) { + redo_switch = false; + switch (type) { + case WJB_BEGIN_ARRAY: + if (!first) + appendBinaryStringInfo(out, ", ", 2); + first = true; + + if (!v.array.rawScalar) + appendStringInfoChar(out, '['); + level++; + break; + case WJB_BEGIN_OBJECT: + if (!first) + appendBinaryStringInfo(out, ", ", 2); + first = true; + appendStringInfoCharMacro(out, '{'); + + level++; + break; + case WJB_KEY: + if (!first) + appendBinaryStringInfo(out, ", ", 2); + first = true; + + /* json rules guarantee this is a string */ jsonb_put_escaped_value(out, &v); - } else { - Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY); - /* - * We need to rerun the current switch() since we need to - * output the object which we just got from the iterator - * before calling the iterator again. - */ - redo_switch = true; - } - break; - case WJB_ELEM: - if (!first) - appendBinaryStringInfo(out, ", ", 2); - else + appendBinaryStringInfo(out, ": ", 2); + + type = JsonbIteratorNext(&it, &v, false); + if (type == WJB_VALUE) { + first = false; + jsonb_put_escaped_value(out, &v); + } else { + Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY); + /* + * We need to rerun the current switch() since we need to + * output the object which we just got from the iterator + * before calling the iterator again. + */ + redo_switch = true; + } + break; + case WJB_ELEM: + if (!first) + appendBinaryStringInfo(out, ", ", 2); + else + first = false; + jsonb_put_escaped_value(out, &v); + break; + case WJB_END_ARRAY: + level--; + if (!v.array.rawScalar) + appendStringInfoChar(out, ']'); first = false; - jsonb_put_escaped_value(out, &v); - break; - case WJB_END_ARRAY: - level--; - if (!v.array.rawScalar) - appendStringInfoChar(out, ']'); - first = false; - break; - case WJB_END_OBJECT: - level--; - appendStringInfoCharMacro(out, '}'); - first = false; - break; - default: - elog(ERROR, "unknown flag of jsonb iterator"); + break; + case WJB_END_OBJECT: + level--; + appendStringInfoCharMacro(out, '}'); + first = false; + break; + default: + elog(ERROR, "unknown flag of jsonb iterator"); + } } + + u_sess->utils_cxt.behavior_compat_flags = original_behavior; + Assert(level == 0); } - Assert(level == 0); + PG_CATCH(); + { + u_sess->utils_cxt.behavior_compat_flags = original_behavior; + PG_RE_THROW(); + } + PG_END_TRY(); + return out->data; } diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index b2f29631dc1181bb95fc944d4991ad4c4d561a9b..364f33b83e77e21df335bc818bda93d42e5fc703 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -110,7 +110,7 @@ referenced column: jsonb SELECT '0.1'::jsonb; -- OK jsonb ------- - .1 + 0.1 (1 row) SELECT '9223372036854775808'::jsonb; -- OK, even though it's too large for int8 diff --git a/src/test/regress/expected/jsonb2.out b/src/test/regress/expected/jsonb2.out index d3c1093ac1b1593a175d660c336857e45e43c1e0..3a2a24d4a8f231ab30beb382e2865855889b160a 100644 --- a/src/test/regress/expected/jsonb2.out +++ b/src/test/regress/expected/jsonb2.out @@ -54,9 +54,9 @@ DETAIL: Token "." is invalid. CONTEXT: JSON data, line 1: -1.5e5.... referenced column: jsonb select '-1.5e-5'::jsonb; - jsonb ----------- - -.000015 + jsonb +----------- + -0.000015 (1 row) select '-1.5e+5'::jsonb; @@ -229,7 +229,7 @@ from cmpjsonb order by 1,2,3,4,5,6,7,8,9; "" | [] | -1 | f | t | t | t | f | f "a" | "b" | -1 | f | t | t | t | f | f "a" | "cc" | -1 | f | t | t | t | f | f - "a" | -.586 | -1 | f | t | t | t | f | f + "a" | -0.586 | -1 | f | t | t | t | f | f "aa" | "aa" | 0 | t | f | f | t | f | t "s" | ["s"] | -1 | f | t | t | t | f | f "true" | true | -1 | f | t | t | t | f | f @@ -291,7 +291,7 @@ from cmpjsonb order by 1,2,3,4,5,6,7,8; "" | [] | f | t | t | t | f | f "a" | "b" | f | t | t | t | f | f "a" | "cc" | f | t | t | t | f | f - "a" | -.586 | f | t | t | t | f | f + "a" | -0.586 | f | t | t | t | f | f "aa" | "aa" | t | f | f | t | f | t "s" | ["s"] | f | t | t | t | f | f "true" | true | f | t | t | t | f | f