Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 83fcaff

Browse files
committed
Fix a couple of cases of JSON output.
First, as noted by Itagaki Takahiro, a datum of type JSON doesn't need to be escaped. Second, ensure that numeric output not in the form of a legal JSON number is quoted and escaped.
1 parent 5223f96 commit 83fcaff

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

src/backend/utils/adt/json.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims,int * dims,
8484
Oid typoutputfunc, bool use_line_feeds);
8585
static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds);
8686

87+
/* fake type category for JSON so we can distinguish it in datum_to_json */
88+
#define TYPCATEGORY_JSON 'j'
89+
/* letters appearing in numeric output that aren't valid in a JSON number */
90+
#define NON_NUMERIC_LETTER "NnAnIiFfTtYy"
8791
/*
8892
* Input.
8993
*/
@@ -707,10 +711,20 @@ datum_to_json(Datum val, StringInfo result, TYPCATEGORY tcategory,
707711
case TYPCATEGORY_NUMERIC:
708712
outputstr = OidOutputFunctionCall(typoutputfunc, val);
709713
/*
710-
* Don't call escape_json here. Numeric output should
711-
* be a valid JSON number and JSON numbers shouldn't
712-
* be quoted.
714+
* Don't call escape_json here if it's a valid JSON
715+
* number. Numeric output should usually be a valid
716+
* JSON number and JSON numbers shouldn't be quoted.
717+
* Quote cases like "Nan" and "Infinity", however.
713718
*/
719+
if (strpbrk(outputstr,NON_NUMERIC_LETTER) == NULL)
720+
appendStringInfoString(result, outputstr);
721+
else
722+
escape_json(result, outputstr);
723+
pfree(outputstr);
724+
break;
725+
case TYPCATEGORY_JSON:
726+
/* JSON will already be escaped */
727+
outputstr = OidOutputFunctionCall(typoutputfunc, val);
714728
appendStringInfoString(result, outputstr);
715729
pfree(outputstr);
716730
break;
@@ -806,9 +820,10 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
806820
typalign, &elements, &nulls,
807821
&nitems);
808822

809-
/* can't have an array of arrays, so this is the only special case here */
810823
if (element_type == RECORDOID)
811824
tcategory = TYPCATEGORY_COMPOSITE;
825+
else if (element_type == JSONOID)
826+
tcategory = TYPCATEGORY_JSON;
812827
else
813828
tcategory = TypeCategory(element_type);
814829

@@ -876,6 +891,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
876891
tcategory = TYPCATEGORY_ARRAY;
877892
else if (tupdesc->attrs[i]->atttypid == RECORDOID)
878893
tcategory = TYPCATEGORY_COMPOSITE;
894+
else if (tupdesc->attrs[i]->atttypid == JSONOID)
895+
tcategory = TYPCATEGORY_JSON;
879896
else
880897
tcategory = TypeCategory(tupdesc->attrs[i]->atttypid);
881898

src/test/regress/expected/json.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,33 @@ SELECT row_to_json(row((select array_agg(x) as d from generate_series(5,10) x)),
367367
{"f1":[5,6,7,8,9,10]}
368368
(1 row)
369369

370+
-- non-numeric output
371+
SELECT row_to_json(q)
372+
FROM (SELECT 'NaN'::float8 AS "float8field") q;
373+
row_to_json
374+
-----------------------
375+
{"float8field":"NaN"}
376+
(1 row)
377+
378+
SELECT row_to_json(q)
379+
FROM (SELECT 'Infinity'::float8 AS "float8field") q;
380+
row_to_json
381+
----------------------------
382+
{"float8field":"Infinity"}
383+
(1 row)
384+
385+
SELECT row_to_json(q)
386+
FROM (SELECT '-Infinity'::float8 AS "float8field") q;
387+
row_to_json
388+
-----------------------------
389+
{"float8field":"-Infinity"}
390+
(1 row)
391+
392+
-- json input
393+
SELECT row_to_json(q)
394+
FROM (SELECT '{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}'::json AS "jsonfield") q;
395+
row_to_json
396+
------------------------------------------------------------------
397+
{"jsonfield":{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}}
398+
(1 row)
399+

src/test/regress/sql/json.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,18 @@ SELECT row_to_json(q,true)
9797
FROM rows q;
9898

9999
SELECT row_to_json(row((select array_agg(x) as d from generate_series(5,10) x)),false);
100+
101+
-- non-numeric output
102+
SELECT row_to_json(q)
103+
FROM (SELECT 'NaN'::float8 AS "float8field") q;
104+
105+
SELECT row_to_json(q)
106+
FROM (SELECT 'Infinity'::float8 AS "float8field") q;
107+
108+
SELECT row_to_json(q)
109+
FROM (SELECT '-Infinity'::float8 AS "float8field") q;
110+
111+
-- json input
112+
SELECT row_to_json(q)
113+
FROM (SELECT '{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}'::json AS "jsonfield") q;
114+

0 commit comments

Comments
 (0)