diff options
author | Andrew Dunstan <andrew@dunslane.net> | 2025-03-05 09:50:34 -0500 |
---|---|---|
committer | Andrew Dunstan <andrew@dunslane.net> | 2025-03-05 10:04:02 -0500 |
commit | 4603903d294bbdd644afecf9b5970827db6d1ff5 (patch) | |
tree | 29212352a8e09f5076b03c752976b416eeba8014 /src/backend/utils/adt/jsonfuncs.c | |
parent | 5ead85fbc81162ab1594f656b036a22e814f96b3 (diff) | |
download | postgresql-4603903d294bbdd644afecf9b5970827db6d1ff5.tar.gz postgresql-4603903d294bbdd644afecf9b5970827db6d1ff5.zip |
Allow json{b}_strip_nulls to remove null array elements
An additional paramater ("strip_in_arrays") is added to these functions.
It defaults to false. If true, then null array elements are removed as
well as null valued object fields. JSON that just consists of a single
null is not affected.
Author: Florents Tselai <florents.tselai@gmail.com>
Discussion: https://postgr.es/m/4BCECCD5-4F40-4313-9E98-9E16BEB0B01D@gmail.com
Diffstat (limited to 'src/backend/utils/adt/jsonfuncs.c')
-rw-r--r-- | src/backend/utils/adt/jsonfuncs.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index c2e90f1a3bf..9f43b58dba5 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -286,6 +286,7 @@ typedef struct StripnullState JsonLexContext *lex; StringInfo strval; bool skip_next_null; + bool strip_in_arrays; } StripnullState; /* structure for generalized json/jsonb value passing */ @@ -4460,8 +4461,19 @@ sn_array_element_start(void *state, bool isnull) { StripnullState *_state = (StripnullState *) state; - if (_state->strval->data[_state->strval->len - 1] != '[') + /* If strip_in_arrays is enabled and this is a null, mark it for skipping */ + if (isnull && _state->strip_in_arrays) + { + _state->skip_next_null = true; + return JSON_SUCCESS; + } + + /* Only add a comma if this is not the first valid element */ + if (_state->strval->len > 0 && + _state->strval->data[_state->strval->len - 1] != '[') + { appendStringInfoCharMacro(_state->strval, ','); + } return JSON_SUCCESS; } @@ -4493,6 +4505,7 @@ Datum json_strip_nulls(PG_FUNCTION_ARGS) { text *json = PG_GETARG_TEXT_PP(0); + bool strip_in_arrays = PG_NARGS() == 2 ? PG_GETARG_BOOL(1) : false; StripnullState *state; JsonLexContext lex; JsonSemAction *sem; @@ -4503,6 +4516,7 @@ json_strip_nulls(PG_FUNCTION_ARGS) state->lex = makeJsonLexContext(&lex, json, true); state->strval = makeStringInfo(); state->skip_next_null = false; + state->strip_in_arrays = strip_in_arrays; sem->semstate = state; sem->object_start = sn_object_start; @@ -4520,12 +4534,13 @@ json_strip_nulls(PG_FUNCTION_ARGS) } /* - * SQL function jsonb_strip_nulls(jsonb) -> jsonb + * SQL function jsonb_strip_nulls(jsonb, bool) -> jsonb */ Datum jsonb_strip_nulls(PG_FUNCTION_ARGS) { Jsonb *jb = PG_GETARG_JSONB_P(0); + bool strip_in_arrays = false; JsonbIterator *it; JsonbParseState *parseState = NULL; JsonbValue *res = NULL; @@ -4534,6 +4549,9 @@ jsonb_strip_nulls(PG_FUNCTION_ARGS) JsonbIteratorToken type; bool last_was_key = false; + if (PG_NARGS() == 2) + strip_in_arrays = PG_GETARG_BOOL(1); + if (JB_ROOT_IS_SCALAR(jb)) PG_RETURN_POINTER(jb); @@ -4564,6 +4582,11 @@ jsonb_strip_nulls(PG_FUNCTION_ARGS) (void) pushJsonbValue(&parseState, WJB_KEY, &k); } + /* if strip_in_arrays is set, also skip null array elements */ + if (strip_in_arrays) + if (type == WJB_ELEM && v.type == jbvNull) + continue; + if (type == WJB_VALUE || type == WJB_ELEM) res = pushJsonbValue(&parseState, type, &v); else |