@@ -52,6 +52,25 @@ typedef struct OkeysState
5252 int sent_count ;
5353} OkeysState ;
5454
55+ /* state for iterate_json_string_values function */
56+ typedef struct IterateJsonStringValuesState
57+ {
58+ JsonLexContext * lex ;
59+ JsonIterateStringValuesAction action ; /* an action that will be applied
60+ to each json value */
61+ void * action_state ; /* any necessary context for iteration */
62+ } IterateJsonStringValuesState ;
63+
64+ /* state for transform_json_string_values function */
65+ typedef struct TransformJsonStringValuesState
66+ {
67+ JsonLexContext * lex ;
68+ StringInfo strval ; /* resulting json */
69+ JsonTransformStringValuesAction action ; /* an action that will be applied
70+ to each json value */
71+ void * action_state ; /* any necessary context for transformation */
72+ } TransformJsonStringValuesState ;
73+
5574/* state for json_get* functions */
5675typedef struct GetState
5776{
@@ -271,6 +290,18 @@ static void setPathArray(JsonbIterator **it, Datum *path_elems,
271290 int level , Jsonb * newval , uint32 nelems , int op_type );
272291static void addJsonbToParseState (JsonbParseState * * jbps , Jsonb * jb );
273292
293+ /* function supporting iterate_json_string_values */
294+ static void iterate_string_values_scalar (void * state , char * token , JsonTokenType tokentype );
295+
296+ /* functions supporting transform_json_string_values */
297+ static void transform_string_values_object_start (void * state );
298+ static void transform_string_values_object_end (void * state );
299+ static void transform_string_values_array_start (void * state );
300+ static void transform_string_values_array_end (void * state );
301+ static void transform_string_values_object_field_start (void * state , char * fname , bool isnull );
302+ static void transform_string_values_array_element_start (void * state , bool isnull );
303+ static void transform_string_values_scalar (void * state , char * token , JsonTokenType tokentype );
304+
274305
275306/*
276307 * SQL function json_object_keys
@@ -4130,3 +4161,208 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
41304161 }
41314162 }
41324163}
4164+
4165+ /*
4166+ * Iterate over jsonb string values or elements, and pass them together with an
4167+ * iteration state to a specified JsonIterateStringValuesAction.
4168+ */
4169+ void
4170+ iterate_jsonb_string_values (Jsonb * jb , void * state , JsonIterateStringValuesAction action )
4171+ {
4172+ JsonbIterator * it ;
4173+ JsonbValue v ;
4174+ JsonbIteratorToken type ;
4175+
4176+ it = JsonbIteratorInit (& jb -> root );
4177+
4178+ while ((type = JsonbIteratorNext (& it , & v , false)) != WJB_DONE )
4179+ {
4180+ if ((type == WJB_VALUE || type == WJB_ELEM ) && v .type == jbvString )
4181+ {
4182+ action (state , v .val .string .val , v .val .string .len );
4183+ }
4184+ }
4185+ }
4186+
4187+ /*
4188+ * Iterate over json string values or elements, and pass them together with an
4189+ * iteration state to a specified JsonIterateStringValuesAction.
4190+ */
4191+ void
4192+ iterate_json_string_values (text * json , void * action_state , JsonIterateStringValuesAction action )
4193+ {
4194+ JsonLexContext * lex = makeJsonLexContext (json , true);
4195+ JsonSemAction * sem = palloc0 (sizeof (JsonSemAction ));
4196+ IterateJsonStringValuesState * state = palloc0 (sizeof (IterateJsonStringValuesState ));
4197+
4198+ state -> lex = lex ;
4199+ state -> action = action ;
4200+ state -> action_state = action_state ;
4201+
4202+ sem -> semstate = (void * ) state ;
4203+ sem -> scalar = iterate_string_values_scalar ;
4204+
4205+ pg_parse_json (lex , sem );
4206+ }
4207+
4208+ /*
4209+ * An auxiliary function for iterate_json_string_values to invoke a specified
4210+ * JsonIterateStringValuesAction.
4211+ */
4212+ static void
4213+ iterate_string_values_scalar (void * state , char * token , JsonTokenType tokentype )
4214+ {
4215+ IterateJsonStringValuesState * _state = (IterateJsonStringValuesState * ) state ;
4216+ if (tokentype == JSON_TOKEN_STRING )
4217+ (* _state -> action ) (_state -> action_state , token , strlen (token ));
4218+ }
4219+
4220+ /*
4221+ * Iterate over a jsonb, and apply a specified JsonTransformStringValuesAction
4222+ * to every string value or element. Any necessary context for a
4223+ * JsonTransformStringValuesAction can be passed in the action_state variable.
4224+ * Function returns a copy of an original jsonb object with transformed values.
4225+ */
4226+ Jsonb *
4227+ transform_jsonb_string_values (Jsonb * jsonb , void * action_state ,
4228+ JsonTransformStringValuesAction transform_action )
4229+ {
4230+ JsonbIterator * it ;
4231+ JsonbValue v , * res = NULL ;
4232+ JsonbIteratorToken type ;
4233+ JsonbParseState * st = NULL ;
4234+ text * out ;
4235+ bool is_scalar = false;
4236+
4237+ it = JsonbIteratorInit (& jsonb -> root );
4238+ is_scalar = it -> isScalar ;
4239+
4240+ while ((type = JsonbIteratorNext (& it , & v , false)) != WJB_DONE )
4241+ {
4242+ if ((type == WJB_VALUE || type == WJB_ELEM ) && v .type == jbvString )
4243+ {
4244+ out = transform_action (action_state , v .val .string .val , v .val .string .len );
4245+ v .val .string .val = VARDATA_ANY (out );
4246+ v .val .string .len = VARSIZE_ANY_EXHDR (out );
4247+ res = pushJsonbValue (& st , type , type < WJB_BEGIN_ARRAY ? & v : NULL );
4248+ }
4249+ else
4250+ {
4251+ res = pushJsonbValue (& st , type , (type == WJB_KEY ||
4252+ type == WJB_VALUE ||
4253+ type == WJB_ELEM ) ? & v : NULL );
4254+ }
4255+ }
4256+
4257+ if (res -> type == jbvArray )
4258+ res -> val .array .rawScalar = is_scalar ;
4259+
4260+ return JsonbValueToJsonb (res );
4261+ }
4262+
4263+ /*
4264+ * Iterate over a json, and apply a specified JsonTransformStringValuesAction
4265+ * to every string value or element. Any necessary context for a
4266+ * JsonTransformStringValuesAction can be passed in the action_state variable.
4267+ * Function returns a StringInfo, which is a copy of an original json with
4268+ * transformed values.
4269+ */
4270+ text *
4271+ transform_json_string_values (text * json , void * action_state ,
4272+ JsonTransformStringValuesAction transform_action )
4273+ {
4274+ JsonLexContext * lex = makeJsonLexContext (json , true);
4275+ JsonSemAction * sem = palloc0 (sizeof (JsonSemAction ));
4276+ TransformJsonStringValuesState * state = palloc0 (sizeof (TransformJsonStringValuesState ));
4277+
4278+ state -> lex = lex ;
4279+ state -> strval = makeStringInfo ();
4280+ state -> action = transform_action ;
4281+ state -> action_state = action_state ;
4282+
4283+ sem -> semstate = (void * ) state ;
4284+ sem -> scalar = transform_string_values_scalar ;
4285+ sem -> object_start = transform_string_values_object_start ;
4286+ sem -> object_end = transform_string_values_object_end ;
4287+ sem -> array_start = transform_string_values_array_start ;
4288+ sem -> array_end = transform_string_values_array_end ;
4289+ sem -> scalar = transform_string_values_scalar ;
4290+ sem -> array_element_start = transform_string_values_array_element_start ;
4291+ sem -> object_field_start = transform_string_values_object_field_start ;
4292+
4293+ pg_parse_json (lex , sem );
4294+
4295+ return cstring_to_text_with_len (state -> strval -> data , state -> strval -> len );
4296+ }
4297+
4298+ /*
4299+ * Set of auxiliary functions for transform_json_string_values to invoke a
4300+ * specified JsonTransformStringValuesAction for all values and left everything
4301+ * else untouched.
4302+ */
4303+ static void
4304+ transform_string_values_object_start (void * state )
4305+ {
4306+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4307+ appendStringInfoCharMacro (_state -> strval , '{' );
4308+ }
4309+
4310+ static void
4311+ transform_string_values_object_end (void * state )
4312+ {
4313+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4314+ appendStringInfoCharMacro (_state -> strval , '}' );
4315+ }
4316+
4317+ static void
4318+ transform_string_values_array_start (void * state )
4319+ {
4320+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4321+ appendStringInfoCharMacro (_state -> strval , '[' );
4322+ }
4323+
4324+ static void
4325+ transform_string_values_array_end (void * state )
4326+ {
4327+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4328+ appendStringInfoCharMacro (_state -> strval , ']' );
4329+ }
4330+
4331+ static void
4332+ transform_string_values_object_field_start (void * state , char * fname , bool isnull )
4333+ {
4334+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4335+
4336+ if (_state -> strval -> data [_state -> strval -> len - 1 ] != '{' )
4337+ appendStringInfoCharMacro (_state -> strval , ',' );
4338+
4339+ /*
4340+ * Unfortunately we don't have the quoted and escaped string any more, so
4341+ * we have to re-escape it.
4342+ */
4343+ escape_json (_state -> strval , fname );
4344+ appendStringInfoCharMacro (_state -> strval , ':' );
4345+ }
4346+
4347+ static void
4348+ transform_string_values_array_element_start (void * state , bool isnull )
4349+ {
4350+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4351+
4352+ if (_state -> strval -> data [_state -> strval -> len - 1 ] != '[' )
4353+ appendStringInfoCharMacro (_state -> strval , ',' );
4354+ }
4355+
4356+ static void
4357+ transform_string_values_scalar (void * state , char * token , JsonTokenType tokentype )
4358+ {
4359+ TransformJsonStringValuesState * _state = (TransformJsonStringValuesState * ) state ;
4360+
4361+ if (tokentype == JSON_TOKEN_STRING )
4362+ {
4363+ text * out = (* _state -> action ) (_state -> action_state , token , strlen (token ));
4364+ escape_json (_state -> strval , text_to_cstring (out ));
4365+ }
4366+ else
4367+ appendStringInfoString (_state -> strval , token );
4368+ }
0 commit comments