@@ -70,6 +70,17 @@ typedef enum /* required operations on state stack */
70
70
JSON_STACKOP_POP /* pop, or expect end of input if no stack */
71
71
} JsonStackOp ;
72
72
73
+ typedef enum /* type categories for datum_to_json */
74
+ {
75
+ JSONTYPE_NULL , /* null, so we didn't bother to identify */
76
+ JSONTYPE_BOOL , /* boolean (built-in types only) */
77
+ JSONTYPE_NUMERIC , /* numeric (ditto) */
78
+ JSONTYPE_JSON , /* JSON itself */
79
+ JSONTYPE_ARRAY , /* array */
80
+ JSONTYPE_COMPOSITE , /* composite */
81
+ JSONTYPE_OTHER /* all else */
82
+ } JsonTypeCategory ;
83
+
73
84
static void json_validate_cstring (char * input );
74
85
static void json_lex (JsonLexContext * lex );
75
86
static void json_lex_string (JsonLexContext * lex );
@@ -82,13 +93,16 @@ static void composite_to_json(Datum composite, StringInfo result,
82
93
bool use_line_feeds );
83
94
static void array_dim_to_json (StringInfo result , int dim , int ndims , int * dims ,
84
95
Datum * vals , bool * nulls , int * valcount ,
85
- TYPCATEGORY tcategory , Oid typoutputfunc ,
96
+ JsonTypeCategory tcategory , Oid outfuncoid ,
86
97
bool use_line_feeds );
87
98
static void array_to_json_internal (Datum array , StringInfo result ,
88
- bool use_line_feeds );
99
+ bool use_line_feeds );
100
+ static void json_categorize_type (Oid typoid ,
101
+ JsonTypeCategory * tcategory ,
102
+ Oid * outfuncoid );
103
+ static void datum_to_json (Datum val , bool is_null , StringInfo result ,
104
+ JsonTypeCategory tcategory , Oid outfuncoid );
89
105
90
- /* fake type category for JSON so we can distinguish it in datum_to_json */
91
- #define TYPCATEGORY_JSON 'j'
92
106
/* chars to consider as part of an alphanumeric token */
93
107
#define JSON_ALPHANUMERIC_CHAR (c ) \
94
108
(((c) >= 'a' && (c) <= 'z') || \
@@ -816,14 +830,67 @@ extract_mb_char(char *s)
816
830
}
817
831
818
832
/*
819
- * Turn a scalar Datum into JSON, appending the string to "result".
833
+ * Determine how we want to print values of a given type in datum_to_json.
834
+ *
835
+ * Given the datatype OID, return its JsonTypeCategory, as well as the type's
836
+ * output function OID. If the returned category is JSONTYPE_CAST, we
837
+ * return the OID of the type->JSON cast function instead.
838
+ */
839
+ static void
840
+ json_categorize_type (Oid typoid ,
841
+ JsonTypeCategory * tcategory ,
842
+ Oid * outfuncoid )
843
+ {
844
+ bool typisvarlena ;
845
+
846
+ /*
847
+ * We should look through domains here, but we'll wait till 9.4.
848
+ */
849
+
850
+ /* We'll usually need to return the type output function */
851
+ getTypeOutputInfo (typoid , outfuncoid , & typisvarlena );
852
+
853
+ /* Check for known types */
854
+ switch (typoid )
855
+ {
856
+ case BOOLOID :
857
+ * tcategory = JSONTYPE_BOOL ;
858
+ break ;
859
+
860
+ case INT2OID :
861
+ case INT4OID :
862
+ case INT8OID :
863
+ case FLOAT4OID :
864
+ case FLOAT8OID :
865
+ case NUMERICOID :
866
+ * tcategory = JSONTYPE_NUMERIC ;
867
+ break ;
868
+
869
+ case JSONOID :
870
+ * tcategory = JSONTYPE_JSON ;
871
+ break ;
872
+
873
+ default :
874
+ /* Check for arrays and composites */
875
+ if (OidIsValid (get_element_type (typoid )))
876
+ * tcategory = JSONTYPE_ARRAY ;
877
+ else if (type_is_rowtype (typoid ))
878
+ * tcategory = JSONTYPE_COMPOSITE ;
879
+ else
880
+ * tcategory = JSONTYPE_OTHER ;
881
+ break ;
882
+ }
883
+ }
884
+
885
+ /*
886
+ * Turn a Datum into JSON text, appending the string to "result".
820
887
*
821
- * Hand off a non-scalar datum to composite_to_json or array_to_json_internal
822
- * as appropriate .
888
+ * tcategory and outfuncoid are from a previous call to json_categorize_type,
889
+ * except that if is_null is true then they can be invalid .
823
890
*/
824
891
static void
825
892
datum_to_json (Datum val , bool is_null , StringInfo result ,
826
- TYPCATEGORY tcategory , Oid typoutputfunc )
893
+ JsonTypeCategory tcategory , Oid outfuncoid )
827
894
{
828
895
char * outputstr ;
829
896
bool numeric_error ;
@@ -837,20 +904,20 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
837
904
838
905
switch (tcategory )
839
906
{
840
- case TYPCATEGORY_ARRAY :
907
+ case JSONTYPE_ARRAY :
841
908
array_to_json_internal (val , result , false);
842
909
break ;
843
- case TYPCATEGORY_COMPOSITE :
910
+ case JSONTYPE_COMPOSITE :
844
911
composite_to_json (val , result , false);
845
912
break ;
846
- case TYPCATEGORY_BOOLEAN :
913
+ case JSONTYPE_BOOL :
847
914
if (DatumGetBool (val ))
848
915
appendStringInfoString (result , "true" );
849
916
else
850
917
appendStringInfoString (result , "false" );
851
918
break ;
852
- case TYPCATEGORY_NUMERIC :
853
- outputstr = OidOutputFunctionCall (typoutputfunc , val );
919
+ case JSONTYPE_NUMERIC :
920
+ outputstr = OidOutputFunctionCall (outfuncoid , val );
854
921
855
922
/*
856
923
* Don't call escape_json here if it's a valid JSON number.
@@ -863,14 +930,14 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
863
930
escape_json (result , outputstr );
864
931
pfree (outputstr );
865
932
break ;
866
- case TYPCATEGORY_JSON :
933
+ case JSONTYPE_JSON :
867
934
/* JSON will already be escaped */
868
- outputstr = OidOutputFunctionCall (typoutputfunc , val );
935
+ outputstr = OidOutputFunctionCall (outfuncoid , val );
869
936
appendStringInfoString (result , outputstr );
870
937
pfree (outputstr );
871
938
break ;
872
939
default :
873
- outputstr = OidOutputFunctionCall (typoutputfunc , val );
940
+ outputstr = OidOutputFunctionCall (outfuncoid , val );
874
941
escape_json (result , outputstr );
875
942
pfree (outputstr );
876
943
break ;
@@ -884,8 +951,8 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
884
951
*/
885
952
static void
886
953
array_dim_to_json (StringInfo result , int dim , int ndims , int * dims , Datum * vals ,
887
- bool * nulls , int * valcount , TYPCATEGORY tcategory ,
888
- Oid typoutputfunc , bool use_line_feeds )
954
+ bool * nulls , int * valcount , JsonTypeCategory tcategory ,
955
+ Oid outfuncoid , bool use_line_feeds )
889
956
{
890
957
int i ;
891
958
const char * sep ;
@@ -904,7 +971,7 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
904
971
if (dim + 1 == ndims )
905
972
{
906
973
datum_to_json (vals [* valcount ], nulls [* valcount ], result , tcategory ,
907
- typoutputfunc );
974
+ outfuncoid );
908
975
(* valcount )++ ;
909
976
}
910
977
else
@@ -914,7 +981,7 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
914
981
* we'll say no.
915
982
*/
916
983
array_dim_to_json (result , dim + 1 , ndims , dims , vals , nulls ,
917
- valcount , tcategory , typoutputfunc , false);
984
+ valcount , tcategory , outfuncoid , false);
918
985
}
919
986
}
920
987
@@ -937,11 +1004,9 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
937
1004
bool * nulls ;
938
1005
int16 typlen ;
939
1006
bool typbyval ;
940
- char typalign ,
941
- typdelim ;
942
- Oid typioparam ;
943
- Oid typoutputfunc ;
944
- TYPCATEGORY tcategory ;
1007
+ char typalign ;
1008
+ JsonTypeCategory tcategory ;
1009
+ Oid outfuncoid ;
945
1010
946
1011
ndim = ARR_NDIM (v );
947
1012
dim = ARR_DIMS (v );
@@ -953,23 +1018,18 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
953
1018
return ;
954
1019
}
955
1020
956
- get_type_io_data (element_type , IOFunc_output ,
957
- & typlen , & typbyval , & typalign ,
958
- & typdelim , & typioparam , & typoutputfunc );
1021
+ get_typlenbyvalalign (element_type ,
1022
+ & typlen , & typbyval , & typalign );
1023
+
1024
+ json_categorize_type (element_type ,
1025
+ & tcategory , & outfuncoid );
959
1026
960
1027
deconstruct_array (v , element_type , typlen , typbyval ,
961
1028
typalign , & elements , & nulls ,
962
1029
& nitems );
963
1030
964
- if (element_type == RECORDOID )
965
- tcategory = TYPCATEGORY_COMPOSITE ;
966
- else if (element_type == JSONOID )
967
- tcategory = TYPCATEGORY_JSON ;
968
- else
969
- tcategory = TypeCategory (element_type );
970
-
971
1031
array_dim_to_json (result , 0 , ndim , dim , elements , nulls , & count , tcategory ,
972
- typoutputfunc , use_line_feeds );
1032
+ outfuncoid , use_line_feeds );
973
1033
974
1034
pfree (elements );
975
1035
pfree (nulls );
@@ -1009,13 +1069,11 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
1009
1069
1010
1070
for (i = 0 ; i < tupdesc -> natts ; i ++ )
1011
1071
{
1012
- Datum val ,
1013
- origval ;
1072
+ Datum val ;
1014
1073
bool isnull ;
1015
1074
char * attname ;
1016
- TYPCATEGORY tcategory ;
1017
- Oid typoutput ;
1018
- bool typisvarlena ;
1075
+ JsonTypeCategory tcategory ;
1076
+ Oid outfuncoid ;
1019
1077
1020
1078
if (tupdesc -> attrs [i ]-> attisdropped )
1021
1079
continue ;
@@ -1028,34 +1086,18 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
1028
1086
escape_json (result , attname );
1029
1087
appendStringInfoChar (result , ':' );
1030
1088
1031
- origval = heap_getattr (tuple , i + 1 , tupdesc , & isnull );
1032
-
1033
- if (tupdesc -> attrs [i ]-> atttypid == RECORDARRAYOID )
1034
- tcategory = TYPCATEGORY_ARRAY ;
1035
- else if (tupdesc -> attrs [i ]-> atttypid == RECORDOID )
1036
- tcategory = TYPCATEGORY_COMPOSITE ;
1037
- else if (tupdesc -> attrs [i ]-> atttypid == JSONOID )
1038
- tcategory = TYPCATEGORY_JSON ;
1039
- else
1040
- tcategory = TypeCategory (tupdesc -> attrs [i ]-> atttypid );
1089
+ val = heap_getattr (tuple , i + 1 , tupdesc , & isnull );
1041
1090
1042
- getTypeOutputInfo (tupdesc -> attrs [i ]-> atttypid ,
1043
- & typoutput , & typisvarlena );
1044
-
1045
- /*
1046
- * If we have a toasted datum, forcibly detoast it here to avoid
1047
- * memory leakage inside the type's output routine.
1048
- */
1049
- if (typisvarlena && !isnull )
1050
- val = PointerGetDatum (PG_DETOAST_DATUM (origval ));
1091
+ if (isnull )
1092
+ {
1093
+ tcategory = JSONTYPE_NULL ;
1094
+ outfuncoid = InvalidOid ;
1095
+ }
1051
1096
else
1052
- val = origval ;
1053
-
1054
- datum_to_json (val , isnull , result , tcategory , typoutput );
1097
+ json_categorize_type (tupdesc -> attrs [i ]-> atttypid ,
1098
+ & tcategory , & outfuncoid );
1055
1099
1056
- /* Clean up detoasted copy, if any */
1057
- if (val != origval )
1058
- pfree (DatumGetPointer (val ));
1100
+ datum_to_json (val , isnull , result , tcategory , outfuncoid );
1059
1101
}
1060
1102
1061
1103
appendStringInfoChar (result , '}' );
0 commit comments