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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy