@@ -94,6 +94,7 @@ static void datum_to_json(Datum val, bool is_null, StringInfo result,
94
94
bool key_scalar );
95
95
static void add_json (Datum val , bool is_null , StringInfo result ,
96
96
Oid val_type , bool key_scalar );
97
+ static text * catenate_stringinfo_string (StringInfo buffer , const char * addon );
97
98
98
99
/* the null action object used for pure validation */
99
100
static JsonSemAction nullSemAction =
@@ -175,7 +176,7 @@ lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
175
176
176
177
/* utility function to check if a string is a valid JSON number */
177
178
extern bool
178
- IsValidJsonNumber (const char * str , int len )
179
+ IsValidJsonNumber (const char * str , int len )
179
180
{
180
181
bool numeric_error ;
181
182
JsonLexContext dummy_lex ;
@@ -200,7 +201,7 @@ IsValidJsonNumber(const char * str, int len)
200
201
201
202
json_lex_number (& dummy_lex , dummy_lex .input , & numeric_error );
202
203
203
- return ! numeric_error ;
204
+ return !numeric_error ;
204
205
}
205
206
206
207
/*
@@ -1370,7 +1371,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
1370
1371
text * jsontext ;
1371
1372
1372
1373
/* callers are expected to ensure that null keys are not passed in */
1373
- Assert ( ! (key_scalar && is_null ));
1374
+ Assert (! (key_scalar && is_null ));
1374
1375
1375
1376
if (is_null )
1376
1377
{
@@ -1404,6 +1405,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
1404
1405
break ;
1405
1406
case JSONTYPE_NUMERIC :
1406
1407
outputstr = OidOutputFunctionCall (outfuncoid , val );
1408
+
1407
1409
/*
1408
1410
* Don't call escape_json for a non-key if it's a valid JSON
1409
1411
* number.
@@ -1798,6 +1800,8 @@ to_json(PG_FUNCTION_ARGS)
1798
1800
1799
1801
/*
1800
1802
* json_agg transition function
1803
+ *
1804
+ * aggregate input column as a json array value.
1801
1805
*/
1802
1806
Datum
1803
1807
json_agg_transfn (PG_FUNCTION_ARGS )
@@ -1884,18 +1888,18 @@ json_agg_finalfn(PG_FUNCTION_ARGS)
1884
1888
1885
1889
state = PG_ARGISNULL (0 ) ? NULL : (StringInfo ) PG_GETARG_POINTER (0 );
1886
1890
1891
+ /* NULL result for no rows in, as is standard with aggregates */
1887
1892
if (state == NULL )
1888
1893
PG_RETURN_NULL ();
1889
1894
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 , "]" ));
1893
1897
}
1894
1898
1895
1899
/*
1896
1900
* json_object_agg transition function.
1897
1901
*
1898
- * aggregate two input columns as a single json value.
1902
+ * aggregate two input columns as a single json object value.
1899
1903
*/
1900
1904
Datum
1901
1905
json_object_agg_transfn (PG_FUNCTION_ARGS )
@@ -1909,7 +1913,7 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
1909
1913
if (!AggCheckCallContext (fcinfo , & aggcontext ))
1910
1914
{
1911
1915
/* 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" );
1913
1917
}
1914
1918
1915
1919
if (PG_ARGISNULL (0 ))
@@ -1976,7 +1980,6 @@ json_object_agg_transfn(PG_FUNCTION_ARGS)
1976
1980
1977
1981
/*
1978
1982
* json_object_agg final function.
1979
- *
1980
1983
*/
1981
1984
Datum
1982
1985
json_object_agg_finalfn (PG_FUNCTION_ARGS )
@@ -1988,12 +1991,32 @@ json_object_agg_finalfn(PG_FUNCTION_ARGS)
1988
1991
1989
1992
state = PG_ARGISNULL (0 ) ? NULL : (StringInfo ) PG_GETARG_POINTER (0 );
1990
1993
1994
+ /* NULL result for no rows in, as is standard with aggregates */
1991
1995
if (state == NULL )
1992
1996
PG_RETURN_NULL ();
1993
1997
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 );
1995
2018
1996
- PG_RETURN_TEXT_P ( cstring_to_text_with_len ( state -> data , state -> len )) ;
2019
+ return result ;
1997
2020
}
1998
2021
1999
2022
/*
0 commit comments