mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
support e-notation for decimal input [issue-3135]
This commit is contained in:
parent
9148adb717
commit
7db097a49a
@ -554,12 +554,15 @@ ReturnType readFloatTextSimpleImpl(T & x, ReadBuffer & buf)
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, unsigned int & scale, bool digits_only = false)
|
||||
inline void readDigits(ReadBuffer & buf, T & x, unsigned int & digits, int & exponent, bool digits_only = false)
|
||||
{
|
||||
x = 0;
|
||||
exponent = 0;
|
||||
unsigned int max_digits = digits;
|
||||
digits = 0;
|
||||
unsigned int places = 0;
|
||||
typename T::NativeType sign = 1;
|
||||
bool leading_zeores = true;
|
||||
bool trailing_zeores = false;
|
||||
bool leading_zeroes = true;
|
||||
bool after_point = false;
|
||||
|
||||
if (buf.eof())
|
||||
@ -578,16 +581,28 @@ inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, uns
|
||||
}
|
||||
}
|
||||
|
||||
while (!buf.eof())
|
||||
bool stop = false;
|
||||
while (!buf.eof() && !stop)
|
||||
{
|
||||
const char & byte = *buf.position();
|
||||
switch (byte)
|
||||
{
|
||||
case '.':
|
||||
after_point = true;
|
||||
if (scale == 0)
|
||||
trailing_zeores = true;
|
||||
leading_zeroes = false;
|
||||
break;
|
||||
case '0':
|
||||
{
|
||||
if (leading_zeroes)
|
||||
break;
|
||||
|
||||
if (after_point)
|
||||
{
|
||||
++places; /// Count trailing zeroes. They would be used only if there's some other digit after them.
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
case '1': [[fallthrough]];
|
||||
case '2': [[fallthrough]];
|
||||
case '3': [[fallthrough]];
|
||||
@ -597,40 +612,61 @@ inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, uns
|
||||
case '7': [[fallthrough]];
|
||||
case '8': [[fallthrough]];
|
||||
case '9':
|
||||
leading_zeores = false;
|
||||
if (trailing_zeores || precision == 0)
|
||||
throw Exception("Cannot read decimal value", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||
[[fallthrough]];
|
||||
case '0':
|
||||
{
|
||||
/// ignore leading and trailing zeroes
|
||||
if (likely(!leading_zeores && !trailing_zeores))
|
||||
{
|
||||
if (precision == 0 || precision < scale || ((precision == scale) && !after_point))
|
||||
throw Exception("Cannot read decimal value", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||
--precision;
|
||||
x = x * 10 + (byte - '0');
|
||||
}
|
||||
if (after_point && scale)
|
||||
{
|
||||
--scale;
|
||||
if (!scale)
|
||||
trailing_zeores = true;
|
||||
}
|
||||
leading_zeroes = false;
|
||||
|
||||
++places; // num zeroes before + current digit
|
||||
if (digits + places > max_digits)
|
||||
throw Exception("Too many digits in decimal value", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||
|
||||
digits += places;
|
||||
if (after_point)
|
||||
exponent -= places;
|
||||
|
||||
// TODO: accurate shift10 for big integers
|
||||
for (; places; --places)
|
||||
x *= 10;
|
||||
x += (byte - '0');
|
||||
break;
|
||||
}
|
||||
case 'e': [[fallthrough]];
|
||||
case 'E':
|
||||
{
|
||||
++buf.position();
|
||||
Int32 addition_exp = 0;
|
||||
readIntText(addition_exp, buf);
|
||||
exponent += addition_exp;
|
||||
stop = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
if (digits_only)
|
||||
throw Exception("Unexpected symbol while reading decimal", ErrorCodes::CANNOT_PARSE_NUMBER);
|
||||
x *= sign;
|
||||
return;
|
||||
stop = true;
|
||||
continue;
|
||||
}
|
||||
++buf.position();
|
||||
}
|
||||
|
||||
x *= sign;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, unsigned int & scale, bool digits_only = false)
|
||||
{
|
||||
unsigned int digits = precision;
|
||||
int exponent;
|
||||
readDigits(buf, x, digits, exponent, digits_only);
|
||||
|
||||
if (static_cast<int>(digits) + exponent > static_cast<int>(precision - scale))
|
||||
throw Exception("Decimal value is too big", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||
if (static_cast<int>(scale) + exponent < 0)
|
||||
throw Exception("Decimal value is too small", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||
|
||||
scale += exponent;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> void readFloatTextPrecise(T & x, ReadBuffer & in) { readFloatTextPreciseImpl<T, void>(x, in); }
|
||||
template <typename T> bool tryReadFloatTextPrecise(T & x, ReadBuffer & in) { return readFloatTextPreciseImpl<T, bool>(x, in); }
|
||||
|
@ -1,4 +1,5 @@
|
||||
-999999999 -999999999999999999 0 -0.999999999 0.000000000000000000 0.00000000000000000000000000000000000000 -9999.99999 0.000000000 0.000000000000000000 0
|
||||
-900000000 -900000000000000000 -90000000000000000000000000000000000000 -0.000000009 -0.000000000000000009 -0.00000000000000000000000000000000000009 0.00000 0.000000000 0.000000000000000000 0
|
||||
-1 -1 -1 -0.000000001 0.000000000000000000 0.00000000000000000000000000000000000000 -0.00001 -0.000000001 0.000000000000000000 -1
|
||||
0 0 -99999999999999999999999999999999999999 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 -0.999999999999999999 0.00000000000000000000000000000000000000 0.00000 -999999999.999999999 0.000000000000000000 0
|
||||
@ -18,4 +19,5 @@
|
||||
0 0 99999999999999999999999999999999999999 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000000 0
|
||||
1 1 1 0.000000001 0.000000000000000000 0.00000000000000000000000000000000000000 0.00001 0.000000001 0.000000000000000000 1
|
||||
42 42 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.99999 0.000000000 0.000000000000000000 0
|
||||
900000000 900000000000000000 90000000000000000000000000000000000000 0.000000009 0.000000000000000009 0.00000000000000000000000000000000000009 0.00000 0.000000000 0.000000000000000000 0
|
||||
999999999 999999999999999999 0 0.999999999 0.000000000000000000 0.00000000000000000000000000000000000000 9999.99999 0.000000000 0.000000000000000000 0
|
||||
|
@ -90,7 +90,12 @@ INSERT INTO test.decimal (a, b, c, d, e, f, g, h, i, j) VALUES (-0.0, -0.0, -0.0
|
||||
INSERT INTO test.decimal (a, b, g) VALUES ('42.00000', 42.0000000000000000000000000000000, '0.999990');
|
||||
INSERT INTO test.decimal (a) VALUES ('-9x'); -- { clientError 72 }
|
||||
INSERT INTO test.decimal (a) VALUES ('0x1'); -- { clientError 72 }
|
||||
INSERT INTO test.decimal (a) VALUES ('1e2'); -- { clientError 72 }
|
||||
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f) VALUES ('0.9e9', '0.9e18', '0.9e38', '9e-9', '9e-18', '9e-38');
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f) VALUES ('-0.9e9', '-0.9e18', '-0.9e38', '-9e-9', '-9e-18', '-9e-38');
|
||||
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f) VALUES ('1e9', '1e18', '1e38', '1e-10', '1e-19', '1e-39'); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f) VALUES ('-1e9', '-1e18', '-1e38', '-1e-10', '-1e-19', '-1e-39'); -- { clientError 69 }
|
||||
|
||||
SELECT * FROM test.decimal ORDER BY a, b, c, d, e, f, g, h, i, j;
|
||||
DROP TABLE IF EXISTS test.decimal;
|
||||
|
@ -5,6 +5,58 @@ SELECT toDecimal32('1.1', 1), toDecimal32('1.1', 2), toDecimal32('1.1', 8);
|
||||
SELECT toDecimal32('1.1', 0); -- { serverError 69 }
|
||||
SELECT toDecimal32(1.1, 0), toDecimal32(1.1, 1), toDecimal32(1.1, 2), toDecimal32(1.1, 8);
|
||||
|
||||
SELECT '1000000000' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '-1000000000' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '1000000000000000000' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '-1000000000000000000' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '100000000000000000000000000000000000000' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '-100000000000000000000000000000000000000' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '1' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '-1' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '1' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '-1' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '1' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
SELECT '-1' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
|
||||
SELECT '0.1' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '-0.1' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '0.1' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '-0.1' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '0.1' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '-0.1' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '0.0000000001' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '-0.0000000001' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '0.0000000000000000001' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '-0.0000000000000000001' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '0.000000000000000000000000000000000000001' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
SELECT '-0.000000000000000000000000000000000000001' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
|
||||
SELECT '1e9' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '-1E9' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '1E18' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '-1e18' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '1e38' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '-1E38' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '1e0' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '-1e-0' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '1e0' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '-1e-0' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '1e-0' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
SELECT '-1e0' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
|
||||
SELECT '1e-1' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '-1e-1' AS x, toDecimal32(x, 0); -- { serverError 69 }
|
||||
SELECT '1e-1' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '-1e-1' AS x, toDecimal64(x, 0); -- { serverError 69 }
|
||||
SELECT '1e-1' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '-1e-1' AS x, toDecimal128(x, 0); -- { serverError 69 }
|
||||
SELECT '1e-10' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '-1e-10' AS x, toDecimal32(x, 9); -- { serverError 69 }
|
||||
SELECT '1e-19' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '-1e-19' AS x, toDecimal64(x, 18); -- { serverError 69 }
|
||||
SELECT '1e-39' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
SELECT '-1e-39' AS x, toDecimal128(x, 38); -- { serverError 69 }
|
||||
|
||||
SELECT toFloat32(9999999) as x, toDecimal32(x, 0), toDecimal32(-x, 0), toDecimal64(x, 0), toDecimal64(-x, 0);
|
||||
SELECT toFloat32(999999.9) as x, toDecimal32(x, 1), toDecimal32(-x, 1), toDecimal64(x, 1), toDecimal64(-x, 1);
|
||||
SELECT toFloat32(99999.99) as x, toDecimal32(x, 2), toDecimal32(-x, 2), toDecimal64(x, 2), toDecimal64(-x, 2);
|
||||
|
@ -1,3 +1,4 @@
|
||||
{"a":0.055,"b":-0.000000005,"c":0.000000000000000005}
|
||||
{"a":0.100,"b":-0.100000000,"c":0.100000000000000000}
|
||||
{"a":0.200,"b":-0.200000000,"c":0.200000000000000000}
|
||||
{"a":0.300,"b":-0.300000000,"c":0.300000000000000000}
|
||||
@ -10,6 +11,8 @@
|
||||
{"a":3.300,"b":-3.300000000,"c":3.300000000000000000}
|
||||
{"a":42.000,"b":-42.000000000,"c":42.000000000000000000}
|
||||
{"a":42.420,"b":-42.420000000,"c":42.420000000000000000}
|
||||
{"a":440000.000,"b":-400000000.000000000,"c":40000000000000000000.000000000000000000}
|
||||
0.055,-0.000000005,0.000000000000000005
|
||||
0.100,-0.100000000,0.100000000000000000
|
||||
0.200,-0.200000000,0.200000000000000000
|
||||
0.300,-0.300000000,0.300000000000000000
|
||||
@ -22,6 +25,8 @@
|
||||
3.300,-3.300000000,3.300000000000000000
|
||||
42.000,-42.000000000,42.000000000000000000
|
||||
42.420,-42.420000000,42.420000000000000000
|
||||
440000.000,-400000000.000000000,40000000000000000000.000000000000000000
|
||||
0.055 -0.000000005 0.000000000000000005
|
||||
0.100 -0.100000000 0.100000000000000000
|
||||
0.200 -0.200000000 0.200000000000000000
|
||||
0.300 -0.300000000 0.300000000000000000
|
||||
@ -34,3 +39,4 @@
|
||||
3.300 -3.300000000 3.300000000000000000
|
||||
42.000 -42.000000000 42.000000000000000000
|
||||
42.420 -42.420000000 42.420000000000000000
|
||||
440000.000 -400000000.000000000 40000000000000000000.000000000000000000
|
||||
|
@ -11,9 +11,9 @@ CREATE TABLE IF NOT EXISTS test.decimal
|
||||
|
||||
INSERT INTO test.decimal (a, b, c) VALUES (42.0, -42.0, 42) (0.42, -0.42, .42) (42.42, -42.42, 42.42);
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT JSONEachRow {"a":1.1, "b":-1.1, "c":1.1} {"a":1.0, "b":-1.0, "c":1} {"a":0.1, "b":-0.1, "c":.1};
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 2.0, -2.0, 2
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 2.0,-2.0,2
|
||||
;
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 0.2, -0.2, .2
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 0.2 ,-0.2 ,.2
|
||||
;
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 2.2 , -2.2 , 2.2
|
||||
;
|
||||
@ -23,6 +23,10 @@ INSERT INTO test.decimal (a, b, c) FORMAT TabSeparated 3.0 -3.0 3
|
||||
;
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT TabSeparated 0.3 -0.3 .3
|
||||
;
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 4.4E+5,-4E+8,.4E+20
|
||||
;
|
||||
INSERT INTO test.decimal (a, b, c) FORMAT CSV 5.5e-2, -5e-9 ,.5e-17
|
||||
;
|
||||
|
||||
SELECT * FROM test.decimal ORDER BY a FORMAT JSONEachRow;
|
||||
SELECT * FROM test.decimal ORDER BY b DESC FORMAT CSV;
|
||||
|
Loading…
Reference in New Issue
Block a user