diff options
author | Andrew Dunstan <andrew@dunslane.net> | 2015-05-12 15:52:45 -0400 |
---|---|---|
committer | Andrew Dunstan <andrew@dunslane.net> | 2015-05-12 15:52:45 -0400 |
commit | c6947010ceb42143d9f047c65c1eac2b38928ab7 (patch) | |
tree | 038277e46347e8b1edf953f99289ac03950248ea /src/backend/utils/adt/jsonb.c | |
parent | afb9249d06f47d7a6d4a89fea0c3625fe43c5a5d (diff) | |
download | postgresql-c6947010ceb42143d9f047c65c1eac2b38928ab7.tar.gz postgresql-c6947010ceb42143d9f047c65c1eac2b38928ab7.zip |
Additional functions and operators for jsonb
jsonb_pretty(jsonb) produces nicely indented json output.
jsonb || jsonb concatenates two jsonb values.
jsonb - text removes a key and its associated value from the json
jsonb - int removes the designated array element
jsonb - text[] removes a key and associated value or array element at
the designated path
jsonb_replace(jsonb,text[],jsonb) replaces the array element designated
by the path or the value associated with the key designated by the path
with the given value.
Original work by Dmitry Dolgov, adapted and reworked for PostgreSQL core
by Andrew Dunstan, reviewed and tidied up by Petr Jelinek.
Diffstat (limited to 'src/backend/utils/adt/jsonb.c')
-rw-r--r-- | src/backend/utils/adt/jsonb.c | 81 |
1 files changed, 70 insertions, 11 deletions
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 7e2c359b219..bccc6696a4f 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -85,6 +85,8 @@ static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, static void add_jsonb(Datum val, bool is_null, JsonbInState *result, Oid val_type, bool key_scalar); static JsonbParseState * clone_parse_state(JsonbParseState * state); +static char *JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent); +static void add_indent(StringInfo out, bool indent, int level); /* * jsonb type input function @@ -422,12 +424,39 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype) char * JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len) { + return JsonbToCStringWorker(out, in, estimated_len, false); +} + +/* + * same thing but with indentation turned on + */ +char * +JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len) +{ + return JsonbToCStringWorker(out, in, estimated_len, true); +} + +/* + * common worker for above two functions + */ +static char * +JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent) +{ bool first = true; JsonbIterator *it; JsonbIteratorToken type = WJB_DONE; JsonbValue v; int level = 0; bool redo_switch = false; + /* If we are indenting, don't add a space after a comma */ + int ispaces = indent ? 1 : 2; + /* + * Don't indent the very first item. This gets set to the indent flag + * at the bottom of the loop. + */ + bool use_indent = false; + bool raw_scalar = false; + bool last_was_key = false; if (out == NULL) out = makeStringInfo(); @@ -444,26 +473,36 @@ JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len) { case WJB_BEGIN_ARRAY: if (!first) - appendBinaryStringInfo(out, ", ", 2); - first = true; + appendBinaryStringInfo(out, ", ", ispaces); if (!v.val.array.rawScalar) - appendStringInfoChar(out, '['); + { + add_indent(out, use_indent && !last_was_key, level); + appendStringInfoCharMacro(out, '['); + } + else + raw_scalar = true; + + first = true; level++; break; case WJB_BEGIN_OBJECT: if (!first) - appendBinaryStringInfo(out, ", ", 2); - first = true; + appendBinaryStringInfo(out, ", ", ispaces); + + add_indent(out, use_indent && !last_was_key, level); appendStringInfoCharMacro(out, '{'); + first = true; level++; break; case WJB_KEY: if (!first) - appendBinaryStringInfo(out, ", ", 2); + appendBinaryStringInfo(out, ", ", ispaces); first = true; + add_indent(out, use_indent, level); + /* json rules guarantee this is a string */ jsonb_put_escaped_value(out, &v); appendBinaryStringInfo(out, ": ", 2); @@ -488,26 +527,33 @@ JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len) break; case WJB_ELEM: if (!first) - appendBinaryStringInfo(out, ", ", 2); - else - first = false; + appendBinaryStringInfo(out, ", ", ispaces); + first = false; + if (! raw_scalar) + add_indent(out, use_indent, level); jsonb_put_escaped_value(out, &v); break; case WJB_END_ARRAY: level--; - if (!v.val.array.rawScalar) - appendStringInfoChar(out, ']'); + if (! raw_scalar) + { + add_indent(out, use_indent, level); + appendStringInfoCharMacro(out, ']'); + } first = false; break; case WJB_END_OBJECT: level--; + add_indent(out, use_indent, level); appendStringInfoCharMacro(out, '}'); first = false; break; default: elog(ERROR, "unknown jsonb iterator token type"); } + use_indent = indent; + last_was_key = redo_switch; } Assert(level == 0); @@ -515,6 +561,19 @@ JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len) return out->data; } +static void +add_indent(StringInfo out, bool indent, int level) +{ + if (indent) + { + int i; + + appendStringInfoCharMacro(out, '\n'); + for (i = 0; i < level; i++) + appendBinaryStringInfo(out, " ", 4); + } +} + /* * Determine how we want to render values of a given type in datum_to_jsonb. |