@@ -94,6 +94,7 @@ static void datum_to_json(Datum val, bool is_null, StringInfo result,
9494bool key_scalar );
9595static void add_json (Datum val ,bool is_null ,StringInfo result ,
9696Oid val_type ,bool key_scalar );
97+ static text * catenate_stringinfo_string (StringInfo buffer ,const char * addon );
9798
9899/* the null action object used for pure validation */
99100static JsonSemAction nullSemAction =
@@ -175,7 +176,7 @@ lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
175176
176177/* utility function to check if a string is a valid JSON number */
177178extern bool
178- IsValidJsonNumber (const char * str ,int len )
179+ IsValidJsonNumber (const char * str ,int len )
179180{
180181bool numeric_error ;
181182JsonLexContext dummy_lex ;
@@ -200,7 +201,7 @@ IsValidJsonNumber(const char * str, int len)
200201
201202json_lex_number (& dummy_lex ,dummy_lex .input ,& numeric_error );
202203
203- return !numeric_error ;
204+ return !numeric_error ;
204205}
205206
206207/*
@@ -1370,7 +1371,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
13701371text * jsontext ;
13711372
13721373/* callers are expected to ensure that null keys are not passed in */
1373- Assert ( ! (key_scalar && is_null ));
1374+ Assert (! (key_scalar && is_null ));
13741375
13751376if (is_null )
13761377{
@@ -1404,6 +1405,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14041405break ;
14051406case JSONTYPE_NUMERIC :
14061407outputstr = OidOutputFunctionCall (outfuncoid ,val );
1408+
14071409/*
14081410 * Don't call escape_json for a non-key if it's a valid JSON
14091411 * number.
@@ -1798,6 +1800,8 @@ to_json(PG_FUNCTION_ARGS)
17981800
17991801/*
18001802 * json_agg transition function
1803+ *
1804+ * aggregate input column as a json array value.
18011805 */
18021806Datum
18031807json_agg_transfn (PG_FUNCTION_ARGS )
@@ -1884,18 +1888,18 @@ json_agg_finalfn(PG_FUNCTION_ARGS)
18841888
18851889state = PG_ARGISNULL (0 ) ?NULL : (StringInfo )PG_GETARG_POINTER (0 );
18861890
1891+ /* NULL result for no rows in, as is standard with aggregates */
18871892if (state == NULL )
18881893PG_RETURN_NULL ();
18891894
1890- appendStringInfoChar (state ,']' );
1891-
1892- PG_RETURN_TEXT_P (cstring_to_text_with_len (state -> data ,state -> len ));
1895+ /* Else return state with appropriate array terminator added */
1896+ PG_RETURN_TEXT_P (catenate_stringinfo_string (state ,"]" ));
18931897}
18941898
18951899/*
18961900 * json_object_agg transition function.
18971901 *
1898- * aggregate two input columns as a single json value.
1902+ * aggregate two input columns as a single jsonobject value.
18991903 */
19001904Datum
19011905json_object_agg_transfn (PG_FUNCTION_ARGS )
@@ -1909,7 +1913,7 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
19091913if (!AggCheckCallContext (fcinfo ,& aggcontext ))
19101914{
19111915/* cannot be called directly because of internal-type argument */
1912- elog (ERROR ,"json_agg_transfn called in non-aggregate context" );
1916+ elog (ERROR ,"json_object_agg_transfn called in non-aggregate context" );
19131917}
19141918
19151919if (PG_ARGISNULL (0 ))
@@ -1976,7 +1980,6 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
19761980
19771981/*
19781982 * json_object_agg final function.
1979- *
19801983 */
19811984Datum
19821985json_object_agg_finalfn (PG_FUNCTION_ARGS )
@@ -1988,12 +1991,32 @@ json_object_agg_finalfn(PG_FUNCTION_ARGS)
19881991
19891992state = PG_ARGISNULL (0 ) ?NULL : (StringInfo )PG_GETARG_POINTER (0 );
19901993
1994+ /* NULL result for no rows in, as is standard with aggregates */
19911995if (state == NULL )
19921996PG_RETURN_NULL ();
19931997
1994- appendStringInfoString (state ," }" );
1998+ /* Else return state with appropriate object terminator added */
1999+ PG_RETURN_TEXT_P (catenate_stringinfo_string (state ," }" ));
2000+ }
2001+
2002+ /*
2003+ * Helper function for aggregates: return given StringInfo's contents plus
2004+ * specified trailing string, as a text datum. We need this because aggregate
2005+ * final functions are not allowed to modify the aggregate state.
2006+ */
2007+ static text *
2008+ catenate_stringinfo_string (StringInfo buffer ,const char * addon )
2009+ {
2010+ /* custom version of cstring_to_text_with_len */
2011+ int buflen = buffer -> len ;
2012+ int addlen = strlen (addon );
2013+ text * result = (text * )palloc (buflen + addlen + VARHDRSZ );
2014+
2015+ SET_VARSIZE (result ,buflen + addlen + VARHDRSZ );
2016+ memcpy (VARDATA (result ),buffer -> data ,buflen );
2017+ memcpy (VARDATA (result )+ buflen ,addon ,addlen );
19952018
1996- PG_RETURN_TEXT_P ( cstring_to_text_with_len ( state -> data , state -> len )) ;
2019+ return result ;
19972020}
19982021
19992022/*