@@ -66,6 +66,9 @@ static void each_object_field_end(void *state, char *fname, bool isnull);
6666static void each_array_start (void * state );
6767static void each_scalar (void * state , char * token , JsonTokenType tokentype );
6868
69+ /* common worker for json_each* functions */
70+ static inline Datum elements_worker (PG_FUNCTION_ARGS , bool as_text );
71+
6972/* semantic action functions for json_array_elements */
7073static void elements_object_start (void * state );
7174static void elements_array_element_start (void * state , bool isnull );
@@ -165,6 +168,9 @@ typedef struct ElementsState
165168 TupleDesc ret_tdesc ;
166169 MemoryContext tmp_cxt ;
167170 char * result_start ;
171+ bool normalize_results ;
172+ bool next_scalar ;
173+ char * normalized_scalar ;
168174} ElementsState ;
169175
170176/* state for get_json_object_as_hash */
@@ -1069,19 +1075,31 @@ each_scalar(void *state, char *token, JsonTokenType tokentype)
10691075}
10701076
10711077/*
1072- * SQL function json_array_elements
1078+ * SQL functions json_array_elements and json_array_elements_text
10731079 *
10741080 * get the elements from a json array
10751081 *
10761082 * a lot of this processing is similar to the json_each* functions
10771083 */
10781084Datum
10791085json_array_elements (PG_FUNCTION_ARGS )
1086+ {
1087+ return elements_worker (fcinfo , false);
1088+ }
1089+
1090+ Datum
1091+ json_array_elements_text (PG_FUNCTION_ARGS )
1092+ {
1093+ return elements_worker (fcinfo , true);
1094+ }
1095+
1096+ static inline Datum
1097+ elements_worker (PG_FUNCTION_ARGS , bool as_text )
10801098{
10811099 text * json = PG_GETARG_TEXT_P (0 );
10821100
1083- /* elements doesn't need any escaped strings, so use false here */
1084- JsonLexContext * lex = makeJsonLexContext (json , false );
1101+ /* elements only needs escaped strings when as_text */
1102+ JsonLexContext * lex = makeJsonLexContext (json , as_text );
10851103 JsonSemAction * sem ;
10861104 ReturnSetInfo * rsi ;
10871105 MemoryContext old_cxt ;
@@ -1124,6 +1142,9 @@ json_array_elements(PG_FUNCTION_ARGS)
11241142 sem -> array_element_start = elements_array_element_start ;
11251143 sem -> array_element_end = elements_array_element_end ;
11261144
1145+ state -> normalize_results = as_text ;
1146+ state -> next_scalar = false;
1147+
11271148 state -> lex = lex ;
11281149 state -> tmp_cxt = AllocSetContextCreate (CurrentMemoryContext ,
11291150 "json_array_elements temporary cxt" ,
@@ -1146,7 +1167,17 @@ elements_array_element_start(void *state, bool isnull)
11461167
11471168 /* save a pointer to where the value starts */
11481169 if (_state -> lex -> lex_level == 1 )
1149- _state -> result_start = _state -> lex -> token_start ;
1170+ {
1171+ /*
1172+ * next_scalar will be reset in the array_element_end handler, and
1173+ * since we know the value is a scalar there is no danger of it being
1174+ * on while recursing down the tree.
1175+ */
1176+ if (_state -> normalize_results && _state -> lex -> token_type == JSON_TOKEN_STRING )
1177+ _state -> next_scalar = true;
1178+ else
1179+ _state -> result_start = _state -> lex -> token_start ;
1180+ }
11501181}
11511182
11521183static void
@@ -1158,7 +1189,7 @@ elements_array_element_end(void *state, bool isnull)
11581189 text * val ;
11591190 HeapTuple tuple ;
11601191 Datum values [1 ];
1161- static bool nulls [1 ] = {false};
1192+ bool nulls [1 ] = {false};
11621193
11631194 /* skip over nested objects */
11641195 if (_state -> lex -> lex_level != 1 )
@@ -1167,10 +1198,23 @@ elements_array_element_end(void *state, bool isnull)
11671198 /* use the tmp context so we can clean up after each tuple is done */
11681199 old_cxt = MemoryContextSwitchTo (_state -> tmp_cxt );
11691200
1170- len = _state -> lex -> prev_token_terminator - _state -> result_start ;
1171- val = cstring_to_text_with_len (_state -> result_start , len );
1201+ if (isnull && _state -> normalize_results )
1202+ {
1203+ nulls [0 ] = true;
1204+ values [0 ] = (Datum ) NULL ;
1205+ }
1206+ else if (_state -> next_scalar )
1207+ {
1208+ values [0 ] = CStringGetTextDatum (_state -> normalized_scalar );
1209+ _state -> next_scalar = false;
1210+ }
1211+ else
1212+ {
1213+ len = _state -> lex -> prev_token_terminator - _state -> result_start ;
1214+ val = cstring_to_text_with_len (_state -> result_start , len );
1215+ values [0 ] = PointerGetDatum (val );
1216+ }
11721217
1173- values [0 ] = PointerGetDatum (val );
11741218
11751219 tuple = heap_form_tuple (_state -> ret_tdesc , values , nulls );
11761220
@@ -1204,10 +1248,9 @@ elements_scalar(void *state, char *token, JsonTokenType tokentype)
12041248 (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
12051249 errmsg ("cannot call json_array_elements on a scalar" )));
12061250
1207- /*
1208- * json_array_elements always returns json, so there's no need to think
1209- * about de-escaped values here.
1210- */
1251+ /* supply de-escaped value if required */
1252+ if (_state -> next_scalar )
1253+ _state -> normalized_scalar = token ;
12111254}
12121255
12131256/*
0 commit comments