Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit25c933c

Browse files
committed
Get rid of bogus dependency on typcategory in to_json() and friends.
These functions were relying on typcategory to identify arrays andcomposites, which is not reliable and not the normal way to do it.Using typcategory to identify boolean, numeric types, and json itself isalso pretty questionable, though the code in those cases didn't seem to beat risk of anything worse than wrong output. Instead, use the standardlsyscache functions to identify arrays and composites, and rely on a directcheck of the type OID for the other cases.In HEAD, also be sure to look through domains so that a domain is treatedthe same as its base type for conversions to JSON. However, this is asmall behavioral change; given the lack of field complaints, we won'tback-patch it.In passing, refactor so that there's only one copy of the code that decideswhich conversion strategy to apply, not multiple copies that could (andhave) gotten out of sync.
1 parent9012022 commit25c933c

File tree

1 file changed

+108
-66
lines changed

1 file changed

+108
-66
lines changed

‎src/backend/utils/adt/json.c

Lines changed: 108 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ typedef enum/* required operations on state stack */
7070
JSON_STACKOP_POP/* pop, or expect end of input if no stack */
7171
}JsonStackOp;
7272

73+
typedefenum/* 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+
7384
staticvoidjson_validate_cstring(char*input);
7485
staticvoidjson_lex(JsonLexContext*lex);
7586
staticvoidjson_lex_string(JsonLexContext*lex);
@@ -82,13 +93,16 @@ static void composite_to_json(Datum composite, StringInfo result,
8293
booluse_line_feeds);
8394
staticvoidarray_dim_to_json(StringInforesult,intdim,intndims,int*dims,
8495
Datum*vals,bool*nulls,int*valcount,
85-
TYPCATEGORYtcategory,Oidtypoutputfunc,
96+
JsonTypeCategorytcategory,Oidoutfuncoid,
8697
booluse_line_feeds);
8798
staticvoidarray_to_json_internal(Datumarray,StringInforesult,
88-
booluse_line_feeds);
99+
booluse_line_feeds);
100+
staticvoidjson_categorize_type(Oidtypoid,
101+
JsonTypeCategory*tcategory,
102+
Oid*outfuncoid);
103+
staticvoiddatum_to_json(Datumval,boolis_null,StringInforesult,
104+
JsonTypeCategorytcategory,Oidoutfuncoid);
89105

90-
/* fake type category for JSON so we can distinguish it in datum_to_json */
91-
#defineTYPCATEGORY_JSON 'j'
92106
/* chars to consider as part of an alphanumeric token */
93107
#defineJSON_ALPHANUMERIC_CHAR(c) \
94108
(((c) >= 'a' && (c) <= 'z') || \
@@ -816,14 +830,67 @@ extract_mb_char(char *s)
816830
}
817831

818832
/*
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+
staticvoid
840+
json_categorize_type(Oidtypoid,
841+
JsonTypeCategory*tcategory,
842+
Oid*outfuncoid)
843+
{
844+
booltypisvarlena;
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+
caseBOOLOID:
857+
*tcategory=JSONTYPE_BOOL;
858+
break;
859+
860+
caseINT2OID:
861+
caseINT4OID:
862+
caseINT8OID:
863+
caseFLOAT4OID:
864+
caseFLOAT8OID:
865+
caseNUMERICOID:
866+
*tcategory=JSONTYPE_NUMERIC;
867+
break;
868+
869+
caseJSONOID:
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+
elseif (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".
820887
*
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.
823890
*/
824891
staticvoid
825892
datum_to_json(Datumval,boolis_null,StringInforesult,
826-
TYPCATEGORYtcategory,Oidtypoutputfunc)
893+
JsonTypeCategorytcategory,Oidoutfuncoid)
827894
{
828895
char*outputstr;
829896
boolnumeric_error;
@@ -837,20 +904,20 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
837904

838905
switch (tcategory)
839906
{
840-
caseTYPCATEGORY_ARRAY:
907+
caseJSONTYPE_ARRAY:
841908
array_to_json_internal(val,result, false);
842909
break;
843-
caseTYPCATEGORY_COMPOSITE:
910+
caseJSONTYPE_COMPOSITE:
844911
composite_to_json(val,result, false);
845912
break;
846-
caseTYPCATEGORY_BOOLEAN:
913+
caseJSONTYPE_BOOL:
847914
if (DatumGetBool(val))
848915
appendStringInfoString(result,"true");
849916
else
850917
appendStringInfoString(result,"false");
851918
break;
852-
caseTYPCATEGORY_NUMERIC:
853-
outputstr=OidOutputFunctionCall(typoutputfunc,val);
919+
caseJSONTYPE_NUMERIC:
920+
outputstr=OidOutputFunctionCall(outfuncoid,val);
854921

855922
/*
856923
* 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,
863930
escape_json(result,outputstr);
864931
pfree(outputstr);
865932
break;
866-
caseTYPCATEGORY_JSON:
933+
caseJSONTYPE_JSON:
867934
/* JSON will already be escaped */
868-
outputstr=OidOutputFunctionCall(typoutputfunc,val);
935+
outputstr=OidOutputFunctionCall(outfuncoid,val);
869936
appendStringInfoString(result,outputstr);
870937
pfree(outputstr);
871938
break;
872939
default:
873-
outputstr=OidOutputFunctionCall(typoutputfunc,val);
940+
outputstr=OidOutputFunctionCall(outfuncoid,val);
874941
escape_json(result,outputstr);
875942
pfree(outputstr);
876943
break;
@@ -884,8 +951,8 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
884951
*/
885952
staticvoid
886953
array_dim_to_json(StringInforesult,intdim,intndims,int*dims,Datum*vals,
887-
bool*nulls,int*valcount,TYPCATEGORYtcategory,
888-
Oidtypoutputfunc,booluse_line_feeds)
954+
bool*nulls,int*valcount,JsonTypeCategorytcategory,
955+
Oidoutfuncoid,booluse_line_feeds)
889956
{
890957
inti;
891958
constchar*sep;
@@ -904,7 +971,7 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
904971
if (dim+1==ndims)
905972
{
906973
datum_to_json(vals[*valcount],nulls[*valcount],result,tcategory,
907-
typoutputfunc);
974+
outfuncoid);
908975
(*valcount)++;
909976
}
910977
else
@@ -914,7 +981,7 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
914981
* we'll say no.
915982
*/
916983
array_dim_to_json(result,dim+1,ndims,dims,vals,nulls,
917-
valcount,tcategory,typoutputfunc, false);
984+
valcount,tcategory,outfuncoid, false);
918985
}
919986
}
920987

@@ -937,11 +1004,9 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
9371004
bool*nulls;
9381005
int16typlen;
9391006
booltypbyval;
940-
chartypalign,
941-
typdelim;
942-
Oidtypioparam;
943-
Oidtypoutputfunc;
944-
TYPCATEGORYtcategory;
1007+
chartypalign;
1008+
JsonTypeCategorytcategory;
1009+
Oidoutfuncoid;
9451010

9461011
ndim=ARR_NDIM(v);
9471012
dim=ARR_DIMS(v);
@@ -953,23 +1018,18 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
9531018
return;
9541019
}
9551020

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);
9591026

9601027
deconstruct_array(v,element_type,typlen,typbyval,
9611028
typalign,&elements,&nulls,
9621029
&nitems);
9631030

964-
if (element_type==RECORDOID)
965-
tcategory=TYPCATEGORY_COMPOSITE;
966-
elseif (element_type==JSONOID)
967-
tcategory=TYPCATEGORY_JSON;
968-
else
969-
tcategory=TypeCategory(element_type);
970-
9711031
array_dim_to_json(result,0,ndim,dim,elements,nulls,&count,tcategory,
972-
typoutputfunc,use_line_feeds);
1032+
outfuncoid,use_line_feeds);
9731033

9741034
pfree(elements);
9751035
pfree(nulls);
@@ -1009,13 +1069,11 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
10091069

10101070
for (i=0;i<tupdesc->natts;i++)
10111071
{
1012-
Datumval,
1013-
origval;
1072+
Datumval;
10141073
boolisnull;
10151074
char*attname;
1016-
TYPCATEGORYtcategory;
1017-
Oidtypoutput;
1018-
booltypisvarlena;
1075+
JsonTypeCategorytcategory;
1076+
Oidoutfuncoid;
10191077

10201078
if (tupdesc->attrs[i]->attisdropped)
10211079
continue;
@@ -1028,34 +1086,18 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
10281086
escape_json(result,attname);
10291087
appendStringInfoChar(result,':');
10301088

1031-
origval=heap_getattr(tuple,i+1,tupdesc,&isnull);
1032-
1033-
if (tupdesc->attrs[i]->atttypid==RECORDARRAYOID)
1034-
tcategory=TYPCATEGORY_ARRAY;
1035-
elseif (tupdesc->attrs[i]->atttypid==RECORDOID)
1036-
tcategory=TYPCATEGORY_COMPOSITE;
1037-
elseif (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);
10411090

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+
}
10511096
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);
10551099

1056-
/* Clean up detoasted copy, if any */
1057-
if (val!=origval)
1058-
pfree(DatumGetPointer(val));
1100+
datum_to_json(val,isnull,result,tcategory,outfuncoid);
10591101
}
10601102

10611103
appendStringInfoChar(result,'}');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp