aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2012-02-20 15:01:03 -0500
committerAndrew Dunstan <andrew@dunslane.net>2012-02-20 15:01:03 -0500
commit83fcaffea2b55152e45fdcaf3fdaf4c0c89f65ce (patch)
tree03fb078fb180794ea513b895963d537a3d4b21f3 /src
parent5223f96d92fd6fb6fcf260da9f9cb111831f0b37 (diff)
downloadpostgresql-83fcaffea2b55152e45fdcaf3fdaf4c0c89f65ce.tar.gz
postgresql-83fcaffea2b55152e45fdcaf3fdaf4c0c89f65ce.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/json.c25
-rw-r--r--src/test/regress/expected/json.out30
-rw-r--r--src/test/regress/sql/json.sql15
3 files changed, 66 insertions, 4 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 60addf2871f..feda0e00357 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -84,6 +84,10 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims,int * dims,
Oid typoutputfunc, bool use_line_feeds);
static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds);
+/* fake type category for JSON so we can distinguish it in datum_to_json */
+#define TYPCATEGORY_JSON 'j'
+/* letters appearing in numeric output that aren't valid in a JSON number */
+#define NON_NUMERIC_LETTER "NnAnIiFfTtYy"
/*
* Input.
*/
@@ -707,10 +711,20 @@ datum_to_json(Datum val, StringInfo result, TYPCATEGORY tcategory,
case TYPCATEGORY_NUMERIC:
outputstr = OidOutputFunctionCall(typoutputfunc, val);
/*
- * Don't call escape_json here. Numeric output should
- * be a valid JSON number and JSON numbers shouldn't
- * be quoted.
+ * Don't call escape_json here if it's a valid JSON
+ * number. Numeric output should usually be a valid
+ * JSON number and JSON numbers shouldn't be quoted.
+ * Quote cases like "Nan" and "Infinity", however.
*/
+ if (strpbrk(outputstr,NON_NUMERIC_LETTER) == NULL)
+ appendStringInfoString(result, outputstr);
+ else
+ escape_json(result, outputstr);
+ pfree(outputstr);
+ break;
+ case TYPCATEGORY_JSON:
+ /* JSON will already be escaped */
+ outputstr = OidOutputFunctionCall(typoutputfunc, val);
appendStringInfoString(result, outputstr);
pfree(outputstr);
break;
@@ -806,9 +820,10 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
typalign, &elements, &nulls,
&nitems);
- /* can't have an array of arrays, so this is the only special case here */
if (element_type == RECORDOID)
tcategory = TYPCATEGORY_COMPOSITE;
+ else if (element_type == JSONOID)
+ tcategory = TYPCATEGORY_JSON;
else
tcategory = TypeCategory(element_type);
@@ -876,6 +891,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
tcategory = TYPCATEGORY_ARRAY;
else if (tupdesc->attrs[i]->atttypid == RECORDOID)
tcategory = TYPCATEGORY_COMPOSITE;
+ else if (tupdesc->attrs[i]->atttypid == JSONOID)
+ tcategory = TYPCATEGORY_JSON;
else
tcategory = TypeCategory(tupdesc->attrs[i]->atttypid);
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 2b573511139..fa8415cdb77 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -367,3 +367,33 @@ SELECT row_to_json(row((select array_agg(x) as d from generate_series(5,10) x)),
{"f1":[5,6,7,8,9,10]}
(1 row)
+-- non-numeric output
+SELECT row_to_json(q)
+FROM (SELECT 'NaN'::float8 AS "float8field") q;
+ row_to_json
+-----------------------
+ {"float8field":"NaN"}
+(1 row)
+
+SELECT row_to_json(q)
+FROM (SELECT 'Infinity'::float8 AS "float8field") q;
+ row_to_json
+----------------------------
+ {"float8field":"Infinity"}
+(1 row)
+
+SELECT row_to_json(q)
+FROM (SELECT '-Infinity'::float8 AS "float8field") q;
+ row_to_json
+-----------------------------
+ {"float8field":"-Infinity"}
+(1 row)
+
+-- json input
+SELECT row_to_json(q)
+FROM (SELECT '{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}'::json AS "jsonfield") q;
+ row_to_json
+------------------------------------------------------------------
+ {"jsonfield":{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}}
+(1 row)
+
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 61273555aae..ab1c41c1c4c 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -97,3 +97,18 @@ SELECT row_to_json(q,true)
FROM rows q;
SELECT row_to_json(row((select array_agg(x) as d from generate_series(5,10) x)),false);
+
+-- non-numeric output
+SELECT row_to_json(q)
+FROM (SELECT 'NaN'::float8 AS "float8field") q;
+
+SELECT row_to_json(q)
+FROM (SELECT 'Infinity'::float8 AS "float8field") q;
+
+SELECT row_to_json(q)
+FROM (SELECT '-Infinity'::float8 AS "float8field") q;
+
+-- json input
+SELECT row_to_json(q)
+FROM (SELECT '{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}'::json AS "jsonfield") q;
+