-- Reproducer: tdigest_in() accepts out-of-range numbers, because sscanf() has
-- no way to report a range error.
--
-- This one does not crash either, it silently accepts input it should reject
-- and stores something different from what was written.
--
-- tdigest_in() parses the whole value with sscanf() (tdigest.c around lines
-- 2646 and 2694) and only checks that the parsed values make sense relative to
-- each other. But sscanf() has undefined behaviour when the number does not
-- fit the target type (C99 7.21.6.2p10), and glibc's implementation does not
-- report it:
--
--     %lld saturates:  "99999999999999999999"  -> INT64_MAX
--                      "-99999999999999999999" -> INT64_MIN
--     %d   wraps:      "2147483648"            -> -2147483648
--                      "4294967296"            -> 0
--                      "4294967306"            -> 10
--                      "99999999999"           -> 1215752191
--
-- The count overflow checks added in d030f1f run on the parsed (already
-- mangled) values, so they do not catch any of this.

\set VERBOSITY terse

-- 1) the counts saturate to INT64_MAX. Both the total and the centroid count
-- saturate to the same value, so they still agree with each other and the
-- digest is accepted. Note the output does not match the input.
SELECT 'flags 1 count 99999999999999999999 compression 10 centroids 1 (1, 99999999999999999999)'::tdigest;

-- 2) worse, the compression is parsed with %d and wraps modulo 2^32. 4294967306
-- is 2^32 + 10, so this is accepted and stored as compression 10 - well inside
-- the allowed range, so the range check that follows sees nothing wrong.
SELECT 'flags 1 count 3 compression 4294967306 centroids 1 (1, 3)'::tdigest;

-- and 2^33 + 10 gives the same thing
SELECT 'flags 1 count 3 compression 8589934602 centroids 1 (1, 3)'::tdigest;

-- this means the text output of tdigest_in() is not the text that was fed to
-- it, i.e. the type is not round-trip stable and a dump/restore of such a
-- value produces a different digest
SELECT 'flags 1 count 3 compression 4294967306 centroids 1 (1, 3)'::tdigest::text
         = 'flags 1 count 3 compression 4294967306 centroids 1 (1.000000, 3)' AS round_trips;

-- 3) values that happen to wrap to something outside the allowed range are
-- still rejected, but by the range check and with a misleading message - the
-- parse itself never fails
SELECT 'flags 1 count 3 compression 4294967296 centroids 1 (1, 3)'::tdigest;
SELECT 'flags 1 count 3 compression 2147483648 centroids 1 (1, 3)'::tdigest;

-- 4) negative counts saturate to INT64_MIN, and are then caught by the
-- "count value for the t-digest must be positive" check
SELECT 'flags 1 count -99999999999999999999 compression 10 centroids 1 (1, 3)'::tdigest;

-- subnormal means should be accepted (and treated as 0.0)
SELECT 'flags 1 count 2 compression 10 centroids 2 (1e-320, 1) (2e-320, 1)'::tdigest;
