aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/jsonfuncs.c
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2025-03-05 09:50:34 -0500
committerAndrew Dunstan <andrew@dunslane.net>2025-03-05 10:04:02 -0500
commit4603903d294bbdd644afecf9b5970827db6d1ff5 (patch)
tree29212352a8e09f5076b03c752976b416eeba8014 /src/backend/utils/adt/jsonfuncs.c
parent5ead85fbc81162ab1594f656b036a22e814f96b3 (diff)
downloadpostgresql-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.c27
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