@@ -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
165168TupleDesc ret_tdesc ;
166169MemoryContext tmp_cxt ;
167170char * 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- * SQLfunction json_array_elements
1078+ * SQLfunctions 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{
10811099text * json = PG_GETARG_TEXT_P (0 );
10821100
1083- /* elementsdoesn't need any escaped strings, so use false here */
1084- JsonLexContext * lex = makeJsonLexContext (json ,false );
1101+ /* elementsonly needs escaped strings when as_text */
1102+ JsonLexContext * lex = makeJsonLexContext (json ,as_text );
10851103JsonSemAction * sem ;
10861104ReturnSetInfo * rsi ;
10871105MemoryContext old_cxt ;
@@ -1124,6 +1142,9 @@ json_array_elements(PG_FUNCTION_ARGS)
11241142sem -> array_element_start = elements_array_element_start ;
11251143sem -> array_element_end = elements_array_element_end ;
11261144
1145+ state -> normalize_results = as_text ;
1146+ state -> next_scalar = false;
1147+
11271148state -> lex = lex ;
11281149state -> 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 */
11481169if (_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)
11581189text * val ;
11591190HeapTuple tuple ;
11601191Datum values [1 ];
1161- static bool nulls [1 ]= {false};
1192+ bool nulls [1 ]= {false};
11621193
11631194/* skip over nested objects */
11641195if (_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 */
11681199old_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
11751219tuple = 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 ),
12051249errmsg ("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/*