Commit e348e7ae authored by Peter Eisentraut's avatar Peter Eisentraut

Prevent infinity and NaN in jsonb/plperl transform

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: default avatarDagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Reviewed-by: default avatarTom Lane <tgl@sss.pgh.pa.us>
parent f7df8043
...@@ -39,6 +39,26 @@ SELECT testSVToJsonb(); ...@@ -39,6 +39,26 @@ SELECT testSVToJsonb();
1 1
(1 row) (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 -- this revealed a bug in the original implementation
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
LANGUAGE plperl LANGUAGE plperl
...@@ -71,7 +91,7 @@ SELECT roundtrip('1'); ...@@ -71,7 +91,7 @@ SELECT roundtrip('1');
(1 row) (1 row)
SELECT roundtrip('1E+131071'); SELECT roundtrip('1E+131071');
ERROR: cannot convert infinite value to jsonb ERROR: cannot convert infinity to jsonb
CONTEXT: PL/Perl function "roundtrip" CONTEXT: PL/Perl function "roundtrip"
SELECT roundtrip('-1'); SELECT roundtrip('-1');
roundtrip roundtrip
...@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}'); ...@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}');
\set VERBOSITY terse \\ -- suppress cascade details \set VERBOSITY terse \\ -- suppress cascade details
DROP EXTENSION plperl CASCADE; DROP EXTENSION plperl CASCADE;
NOTICE: drop cascades to 6 other objects NOTICE: drop cascades to 8 other objects
...@@ -39,6 +39,26 @@ SELECT testSVToJsonb(); ...@@ -39,6 +39,26 @@ SELECT testSVToJsonb();
1 1
(1 row) (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 -- this revealed a bug in the original implementation
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
LANGUAGE plperlu LANGUAGE plperlu
...@@ -71,7 +91,7 @@ SELECT roundtrip('1'); ...@@ -71,7 +91,7 @@ SELECT roundtrip('1');
(1 row) (1 row)
SELECT roundtrip('1E+131071'); SELECT roundtrip('1E+131071');
ERROR: cannot convert infinite value to jsonb ERROR: cannot convert infinity to jsonb
CONTEXT: PL/Perl function "roundtrip" CONTEXT: PL/Perl function "roundtrip"
SELECT roundtrip('-1'); SELECT roundtrip('-1');
roundtrip roundtrip
...@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}'); ...@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}');
\set VERBOSITY terse \\ -- suppress cascade details \set VERBOSITY terse \\ -- suppress cascade details
DROP EXTENSION plperlu CASCADE; DROP EXTENSION plperlu CASCADE;
NOTICE: drop cascades to 6 other objects NOTICE: drop cascades to 8 other objects
...@@ -211,10 +211,22 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem) ...@@ -211,10 +211,22 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
{ {
double nval = SvNV(in); 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)) if (isinf(nval))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
(errmsg("cannot convert infinite value to jsonb")))); (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.type = jbvNumeric;
out.val.numeric = out.val.numeric =
......
...@@ -34,6 +34,28 @@ $$; ...@@ -34,6 +34,28 @@ $$;
SELECT testSVToJsonb(); 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 -- this revealed a bug in the original implementation
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
LANGUAGE plperl LANGUAGE plperl
......
...@@ -34,6 +34,28 @@ $$; ...@@ -34,6 +34,28 @@ $$;
SELECT testSVToJsonb(); 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 -- this revealed a bug in the original implementation
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
LANGUAGE plperlu LANGUAGE plperlu
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment