@@ -88,17 +88,20 @@ static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
8888static void jsonb_categorize_type (Oid typoid ,
8989 JsonbTypeCategory * tcategory ,
9090 Oid * outfuncoid );
91- static void composite_to_jsonb (Datum composite , JsonbInState * result );
91+ static void composite_to_jsonb (Datum composite , JsonbInState * result ,
92+ bool unpackJson );
9293static void array_dim_to_jsonb (JsonbInState * result , int dim , int ndims , int * dims ,
9394 Datum * vals , bool * nulls , int * valcount ,
94- JsonbTypeCategory tcategory , Oid outfuncoid );
95- static void array_to_jsonb_internal (Datum array , JsonbInState * result );
95+ JsonbTypeCategory tcategory , Oid outfuncoid ,
96+ bool unpackJson );
97+ static void array_to_jsonb_internal (Datum array , JsonbInState * result ,
98+ bool unpackJson );
9699static void jsonb_categorize_type (Oid typoid ,
97100 JsonbTypeCategory * tcategory ,
98101 Oid * outfuncoid );
99102static void datum_to_jsonb (Datum val , bool is_null , JsonbInState * result ,
100103 JsonbTypeCategory tcategory , Oid outfuncoid ,
101- bool key_scalar );
104+ bool key_scalar , bool unpackJson );
102105static void add_jsonb (Datum val , bool is_null , JsonbInState * result ,
103106 Oid val_type , bool key_scalar );
104107#ifndef JSON_C
@@ -796,7 +799,7 @@ jsonb_categorize_type(Oid typoid,
796799static void
797800datum_to_jsonb (Datum val , bool is_null , JsonbInState * result ,
798801 JsonbTypeCategory tcategory , Oid outfuncoid ,
799- bool key_scalar )
802+ bool key_scalar , bool unpackJson )
800803{
801804 char * outputstr ;
802805 bool numeric_error ;
@@ -829,10 +832,10 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
829832 switch (tcategory )
830833 {
831834 case JSONBTYPE_ARRAY :
832- array_to_jsonb_internal (val , result );
835+ array_to_jsonb_internal (val , result , unpackJson );
833836 return ;
834837 case JSONBTYPE_COMPOSITE :
835- composite_to_jsonb (val , result );
838+ composite_to_jsonb (val , result , unpackJson );
836839 return ;
837840 case JSONBTYPE_BOOL :
838841 if (key_scalar )
@@ -954,6 +957,8 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
954957 pushScalarJsonbValue (& result -> parseState ,
955958 JsonToJsonValue (jsonb , & jb ),
956959 false, false);
960+ else if (!unpackJson )
961+ result -> res = JsonToJsonValue (jsonb , NULL );
957962 else
958963 {
959964 JsonbIteratorToken type ;
@@ -996,7 +1001,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
9961001static void
9971002array_dim_to_jsonb (JsonbInState * result , int dim , int ndims , int * dims , Datum * vals ,
9981003 bool * nulls , int * valcount , JsonbTypeCategory tcategory ,
999- Oid outfuncoid )
1004+ Oid outfuncoid , bool unpackJson )
10001005{
10011006 int i ;
10021007
@@ -1015,13 +1020,13 @@ array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *v
10151020 if (dim + 1 == ndims )
10161021 {
10171022 datum_to_jsonb (vals [* valcount ], nulls [* valcount ], result , tcategory ,
1018- outfuncoid , false);
1023+ outfuncoid , false, unpackJson );
10191024 (* valcount )++ ;
10201025 }
10211026 else
10221027 {
10231028 array_dim_to_jsonb (result , dim + 1 , ndims , dims , vals , nulls ,
1024- valcount , tcategory , outfuncoid );
1029+ valcount , tcategory , outfuncoid , unpackJson );
10251030 }
10261031 }
10271032
@@ -1032,7 +1037,7 @@ array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *v
10321037 * Turn an array into JSON.
10331038 */
10341039static void
1035- array_to_jsonb_internal (Datum array , JsonbInState * result )
1040+ array_to_jsonb_internal (Datum array , JsonbInState * result , bool unpackJson )
10361041{
10371042 ArrayType * v = DatumGetArrayTypeP (array );
10381043 Oid element_type = ARR_ELEMTYPE (v );
@@ -1070,7 +1075,7 @@ array_to_jsonb_internal(Datum array, JsonbInState *result)
10701075 & nitems );
10711076
10721077 array_dim_to_jsonb (result , 0 , ndim , dim , elements , nulls , & count , tcategory ,
1073- outfuncoid );
1078+ outfuncoid , unpackJson );
10741079
10751080 pfree (elements );
10761081 pfree (nulls );
@@ -1080,7 +1085,7 @@ array_to_jsonb_internal(Datum array, JsonbInState *result)
10801085 * Turn a composite / record into JSON.
10811086 */
10821087static void
1083- composite_to_jsonb (Datum composite , JsonbInState * result )
1088+ composite_to_jsonb (Datum composite , JsonbInState * result , bool unpackJson )
10841089{
10851090 HeapTupleHeader td ;
10861091 Oid tupType ;
@@ -1143,7 +1148,8 @@ composite_to_jsonb(Datum composite, JsonbInState *result)
11431148 else
11441149 jsonb_categorize_type (att -> atttypid , & tcategory , & outfuncoid );
11451150
1146- datum_to_jsonb (val , isnull , result , tcategory , outfuncoid , false);
1151+ datum_to_jsonb (val , isnull , result , tcategory , outfuncoid , false,
1152+ unpackJson );
11471153 }
11481154
11491155 result -> res = pushJsonbValue (& result -> parseState , WJB_END_OBJECT , NULL );
@@ -1179,7 +1185,8 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result,
11791185 jsonb_categorize_type (val_type ,
11801186 & tcategory , & outfuncoid );
11811187
1182- datum_to_jsonb (val , is_null , result , tcategory , outfuncoid , key_scalar );
1188+ datum_to_jsonb (val , is_null , result , tcategory , outfuncoid , key_scalar ,
1189+ true);
11831190}
11841191
11851192/*
@@ -1204,7 +1211,7 @@ to_jsonb(PG_FUNCTION_ARGS)
12041211
12051212 memset (& result , 0 , sizeof (JsonbInState ));
12061213
1207- datum_to_jsonb (val , false, & result , tcategory , outfuncoid , false);
1214+ datum_to_jsonb (val , false, & result , tcategory , outfuncoid , false, true );
12081215
12091216 PG_RETURN_JSONB_P (JsonbValueToJsonb (result .res ));
12101217}
@@ -1567,11 +1574,7 @@ jsonb_agg_transfn(PG_FUNCTION_ARGS)
15671574 JsonbInState elem ;
15681575 Datum val ;
15691576 JsonbInState * result ;
1570- bool single_scalar = false;
1571- JsonbIterator * it ;
1572- Jsonb * jbelem ;
15731577 JsonbValue v ;
1574- JsonbIteratorToken type ;
15751578
15761579 if (!AggCheckCallContext (fcinfo , & aggcontext ))
15771580 {
@@ -1631,62 +1634,14 @@ jsonb_agg_transfn(PG_FUNCTION_ARGS)
16311634 memset (& elem , 0 , sizeof (JsonbInState ));
16321635
16331636 datum_to_jsonb (val , PG_ARGISNULL (1 ), & elem , state -> val_category ,
1634- state -> val_output_func , false);
1635-
1636- jbelem = JsonbValueToJsonb (elem .res );
1637+ state -> val_output_func , false, false);
16371638
16381639 /* switch to the aggregate context for accumulation operations */
16391640
16401641 oldcontext = MemoryContextSwitchTo (aggcontext );
16411642
1642- it = JsonbIteratorInit (& jbelem -> root );
1643-
1644- while ((type = JsonbIteratorNext (& it , & v , false)) != WJB_DONE )
1645- {
1646- switch (type )
1647- {
1648- case WJB_BEGIN_ARRAY :
1649- if (v .val .array .rawScalar )
1650- single_scalar = true;
1651- else
1652- result -> res = pushJsonbValue (& result -> parseState ,
1653- type , NULL );
1654- break ;
1655- case WJB_END_ARRAY :
1656- if (!single_scalar )
1657- result -> res = pushJsonbValue (& result -> parseState ,
1658- type , NULL );
1659- break ;
1660- case WJB_BEGIN_OBJECT :
1661- case WJB_END_OBJECT :
1662- result -> res = pushJsonbValue (& result -> parseState ,
1663- type , NULL );
1664- break ;
1665- case WJB_ELEM :
1666- case WJB_KEY :
1667- case WJB_VALUE :
1668- if (v .type == jbvString )
1669- {
1670- /* copy string values in the aggregate context */
1671- char * buf = palloc (v .val .string .len + 1 );
1672-
1673- snprintf (buf , v .val .string .len + 1 , "%s" , v .val .string .val );
1674- v .val .string .val = buf ;
1675- }
1676- else if (v .type == jbvNumeric )
1677- {
1678- /* same for numeric */
1679- v .val .numeric =
1680- DatumGetNumeric (DirectFunctionCall1 (numeric_uplus ,
1681- NumericGetDatum (v .val .numeric )));
1682- }
1683- result -> res = pushJsonbValue (& result -> parseState ,
1684- type , & v );
1685- break ;
1686- default :
1687- elog (ERROR , "unknown jsonb iterator token type" );
1688- }
1689- }
1643+ result -> res = pushJsonbValueExt (& result -> parseState , WJB_ELEM ,
1644+ JsonValueCopy (& v , elem .res ), false);
16901645
16911646 MemoryContextSwitchTo (oldcontext );
16921647
@@ -1737,12 +1692,10 @@ jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
17371692 JsonbAggState * state ;
17381693 Datum val ;
17391694 JsonbInState * result ;
1740- bool single_scalar ;
1741- JsonbIterator * it ;
1742- Jsonb * jbkey ,
1743- * jbval ;
1744- JsonbValue v ;
1745- JsonbIteratorToken type ;
1695+ const JsonbValue * jbkey ,
1696+ * jbval ;
1697+ JsonbValue jbkeybuf ,
1698+ v ;
17461699
17471700 if (!AggCheckCallContext (fcinfo , & aggcontext ))
17481701 {
@@ -1810,122 +1763,46 @@ jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
18101763 memset (& elem , 0 , sizeof (JsonbInState ));
18111764
18121765 datum_to_jsonb (val , false, & elem , state -> key_category ,
1813- state -> key_output_func , true);
1766+ state -> key_output_func , true, false );
18141767
1815- jbkey = JsonbValueToJsonb ( elem .res ) ;
1768+ jbkey = elem .res ;
18161769
18171770 val = PG_ARGISNULL (2 ) ? (Datum ) 0 : PG_GETARG_DATUM (2 );
18181771
18191772 memset (& elem , 0 , sizeof (JsonbInState ));
18201773
18211774 datum_to_jsonb (val , PG_ARGISNULL (2 ), & elem , state -> val_category ,
1822- state -> val_output_func , false);
1823-
1824- jbval = JsonbValueToJsonb (elem .res );
1825-
1826- it = JsonbIteratorInit (& jbkey -> root );
1775+ state -> val_output_func , false, false);
18271776
1828- /* switch to the aggregate context for accumulation operations */
1829-
1830- oldcontext = MemoryContextSwitchTo (aggcontext );
1777+ jbval = elem .res ;
18311778
18321779 /*
18331780 * keys should be scalar, and we should have already checked for that
18341781 * above when calling datum_to_jsonb, so we only need to look for these
18351782 * things.
18361783 */
18371784
1838- while ((type = JsonbIteratorNext (& it , & v , false)) != WJB_DONE )
1839- {
1840- switch (type )
1841- {
1842- case WJB_BEGIN_ARRAY :
1843- if (!v .val .array .rawScalar )
1844- elog (ERROR , "unexpected structure for key" );
1845- break ;
1846- case WJB_ELEM :
1847- if (v .type == jbvString )
1848- {
1849- /* copy string values in the aggregate context */
1850- char * buf = palloc (v .val .string .len + 1 );
1785+ jbkey = JsonValueUnwrap (jbkey , & jbkeybuf );
18511786
1852- snprintf (buf , v .val .string .len + 1 , "%s" , v .val .string .val );
1853- v .val .string .val = buf ;
1854- }
1855- else
1856- {
1857- ereport (ERROR ,
1858- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1859- errmsg ("object keys must be strings" )));
1860- }
1861- result -> res = pushJsonbValue (& result -> parseState ,
1862- WJB_KEY , & v );
1863- break ;
1864- case WJB_END_ARRAY :
1865- break ;
1866- default :
1867- elog (ERROR , "unexpected structure for key" );
1868- break ;
1869- }
1870- }
1787+ if (jbkey -> type != jbvString )
1788+ ereport (ERROR ,
1789+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1790+ errmsg ("object keys must be strings" )));
18711791
1872- it = JsonbIteratorInit ( & jbval -> root );
1792+ /* switch to the aggregate context for accumulation operations */
18731793
1874- single_scalar = false ;
1794+ oldcontext = MemoryContextSwitchTo ( aggcontext ) ;
18751795
1796+ result -> res = pushJsonbValue (& result -> parseState , WJB_KEY ,
1797+ JsonValueCopy (& v , jbkey ));
18761798 /*
18771799 * values can be anything, including structured and null, so we treat them
18781800 * as in json_agg_transfn, except that single scalars are always pushed as
18791801 * WJB_VALUE items.
18801802 */
18811803
1882- while ((type = JsonbIteratorNext (& it , & v , false)) != WJB_DONE )
1883- {
1884- switch (type )
1885- {
1886- case WJB_BEGIN_ARRAY :
1887- if (v .val .array .rawScalar )
1888- single_scalar = true;
1889- else
1890- result -> res = pushJsonbValue (& result -> parseState ,
1891- type , NULL );
1892- break ;
1893- case WJB_END_ARRAY :
1894- if (!single_scalar )
1895- result -> res = pushJsonbValue (& result -> parseState ,
1896- type , NULL );
1897- break ;
1898- case WJB_BEGIN_OBJECT :
1899- case WJB_END_OBJECT :
1900- result -> res = pushJsonbValue (& result -> parseState ,
1901- type , NULL );
1902- break ;
1903- case WJB_ELEM :
1904- case WJB_KEY :
1905- case WJB_VALUE :
1906- if (v .type == jbvString )
1907- {
1908- /* copy string values in the aggregate context */
1909- char * buf = palloc (v .val .string .len + 1 );
1910-
1911- snprintf (buf , v .val .string .len + 1 , "%s" , v .val .string .val );
1912- v .val .string .val = buf ;
1913- }
1914- else if (v .type == jbvNumeric )
1915- {
1916- /* same for numeric */
1917- v .val .numeric =
1918- DatumGetNumeric (DirectFunctionCall1 (numeric_uplus ,
1919- NumericGetDatum (v .val .numeric )));
1920- }
1921- result -> res = pushJsonbValue (& result -> parseState ,
1922- single_scalar ? WJB_VALUE : type ,
1923- & v );
1924- break ;
1925- default :
1926- elog (ERROR , "unknown jsonb iterator token type" );
1927- }
1928- }
1804+ result -> res = pushJsonbValueExt (& result -> parseState , WJB_VALUE ,
1805+ JsonValueCopy (& v , jbval ), false);
19291806
19301807 MemoryContextSwitchTo (oldcontext );
19311808
0 commit comments