]> granicus.if.org Git - postgresql/commitdiff
Prevent infinity and NaN in jsonb/plperl transform
authorPeter Eisentraut <peter_e@gmx.net>
Mon, 30 Apr 2018 16:28:45 +0000 (12:28 -0400)
committerPeter Eisentraut <peter_e@gmx.net>
Mon, 30 Apr 2018 17:22:57 +0000 (13:22 -0400)
jsonb uses numeric internally, and numeric can store NaN, but that is
not allowed by jsonb on input, so we shouldn't store it.  Also prevent
infinity to get a consistent error message.  (numeric input would reject
infinity anyway.)

Reported-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
contrib/jsonb_plperl/expected/jsonb_plperl.out
contrib/jsonb_plperl/expected/jsonb_plperlu.out
contrib/jsonb_plperl/jsonb_plperl.c
contrib/jsonb_plperl/sql/jsonb_plperl.sql
contrib/jsonb_plperl/sql/jsonb_plperlu.sql

index 99a2e8e135d42c99cac505b2029ecc11aafd921d..d6c3becf6313cd1e3cba77d0a8371e7b5749e584 100644 (file)
@@ -39,6 +39,26 @@ SELECT testSVToJsonb();
  1
 (1 row)
 
+CREATE FUNCTION testInf() RETURNS jsonb
+LANGUAGE plperl
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'Inf';
+return $val;
+$$;
+SELECT testInf();
+ERROR:  cannot convert infinity to jsonb
+CONTEXT:  PL/Perl function "testinf"
+CREATE FUNCTION testNaN() RETURNS jsonb
+LANGUAGE plperl
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'NaN';
+return $val;
+$$;
+SELECT testNaN();
+ERROR:  cannot convert NaN to jsonb
+CONTEXT:  PL/Perl function "testnan"
 -- this revealed a bug in the original implementation
 CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
 LANGUAGE plperl
@@ -71,7 +91,7 @@ SELECT roundtrip('1');
 (1 row)
 
 SELECT roundtrip('1E+131071');
-ERROR:  cannot convert infinite value to jsonb
+ERROR:  cannot convert infinity to jsonb
 CONTEXT:  PL/Perl function "roundtrip"
 SELECT roundtrip('-1');
  roundtrip 
@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}');
 
 \set VERBOSITY terse \\ -- suppress cascade details
 DROP EXTENSION plperl CASCADE;
-NOTICE:  drop cascades to 6 other objects
+NOTICE:  drop cascades to 8 other objects
index 8053cf6aa8044a387cdaf4c3b756925023ace7a3..65ed21f3b2d9c8121fa3ed4043e800e75c4e99e4 100644 (file)
@@ -39,6 +39,26 @@ SELECT testSVToJsonb();
  1
 (1 row)
 
+CREATE FUNCTION testInf() RETURNS jsonb
+LANGUAGE plperlu
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'Inf';
+return $val;
+$$;
+SELECT testInf();
+ERROR:  cannot convert infinity to jsonb
+CONTEXT:  PL/Perl function "testinf"
+CREATE FUNCTION testNaN() RETURNS jsonb
+LANGUAGE plperlu
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'NaN';
+return $val;
+$$;
+SELECT testNaN();
+ERROR:  cannot convert NaN to jsonb
+CONTEXT:  PL/Perl function "testnan"
 -- this revealed a bug in the original implementation
 CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
 LANGUAGE plperlu
@@ -71,7 +91,7 @@ SELECT roundtrip('1');
 (1 row)
 
 SELECT roundtrip('1E+131071');
-ERROR:  cannot convert infinite value to jsonb
+ERROR:  cannot convert infinity to jsonb
 CONTEXT:  PL/Perl function "roundtrip"
 SELECT roundtrip('-1');
  roundtrip 
@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}');
 
 \set VERBOSITY terse \\ -- suppress cascade details
 DROP EXTENSION plperlu CASCADE;
-NOTICE:  drop cascades to 6 other objects
+NOTICE:  drop cascades to 8 other objects
index cde38b295c5a42377f786b4f092330d93fc8713b..bde93a71fc04c4f26c35e549bda65b6b741ab812 100644 (file)
@@ -211,10 +211,22 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
                        {
                                double          nval = SvNV(in);
 
+                               /*
+                                * jsonb doesn't allow infinity or NaN (per JSON
+                                * specification), but the numeric type that is used for the
+                                * storage accepts NaN, so we have to prevent it here
+                                * explicitly.  We don't really have to check for isinf()
+                                * here, as numeric doesn't allow it and it would be caught
+                                * later, but it makes for a nicer error message.
+                                */
                                if (isinf(nval))
                                        ereport(ERROR,
-                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                        (errmsg("cannot convert infinite value to jsonb"))));
+                                                       (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                                        (errmsg("cannot convert infinity to jsonb"))));
+                               if (isnan(nval))
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                                        (errmsg("cannot convert NaN to jsonb"))));
 
                                out.type = jbvNumeric;
                                out.val.numeric =
index 8b0a8764afa91d4f587e639407f3647410f5c871..5f94a4c51aed02ca4d5ed70fa404755214b58af8 100644 (file)
@@ -34,6 +34,28 @@ $$;
 SELECT testSVToJsonb();
 
 
+CREATE FUNCTION testInf() RETURNS jsonb
+LANGUAGE plperl
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'Inf';
+return $val;
+$$;
+
+SELECT testInf();
+
+
+CREATE FUNCTION testNaN() RETURNS jsonb
+LANGUAGE plperl
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'NaN';
+return $val;
+$$;
+
+SELECT testNaN();
+
+
 -- this revealed a bug in the original implementation
 CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
 LANGUAGE plperl
index 9287f7672f76ff95ef3527d55c54a25d3cd6a7d2..9c0c083c99c0c6df0929d44f5468750d3b652c69 100644 (file)
@@ -34,6 +34,28 @@ $$;
 SELECT testSVToJsonb();
 
 
+CREATE FUNCTION testInf() RETURNS jsonb
+LANGUAGE plperlu
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'Inf';
+return $val;
+$$;
+
+SELECT testInf();
+
+
+CREATE FUNCTION testNaN() RETURNS jsonb
+LANGUAGE plperlu
+TRANSFORM FOR TYPE jsonb
+AS $$
+$val = 0 + 'NaN';
+return $val;
+$$;
+
+SELECT testNaN();
+
+
 -- this revealed a bug in the original implementation
 CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
 LANGUAGE plperlu