mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
string to decimal, decimal to string, check decimal bounds
This commit is contained in:
parent
f793fb553a
commit
582f76c83b
@ -42,12 +42,22 @@ bool DataTypeDecimal<T>::equals(const IDataType & rhs) const
|
||||
template <typename T>
|
||||
void DataTypeDecimal<T>::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const
|
||||
{
|
||||
const T & value = static_cast<const ColumnType &>(column).getData()[row_num];
|
||||
T value = static_cast<const ColumnType &>(column).getData()[row_num];
|
||||
if (value < 0)
|
||||
{
|
||||
value *= -1;
|
||||
writeChar('-', ostr); /// avoid crop leading minus when whole part is zero
|
||||
}
|
||||
|
||||
writeIntText(wholePart(value), ostr);
|
||||
writeChar('.', ostr);
|
||||
if (scale)
|
||||
writeIntText(fractionalPart(value), ostr);
|
||||
{
|
||||
writeChar('.', ostr);
|
||||
String str_fractional(scale, '0');
|
||||
for (Int32 pos = scale - 1; pos >= 0; --pos, value /= 10)
|
||||
str_fractional[pos] += value % 10;
|
||||
ostr.write(str_fractional.data(), scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,6 +72,18 @@ void DataTypeDecimal<T>::deserializeText(IColumn & column, ReadBuffer & istr, co
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
T DataTypeDecimal<T>::parseFromString(const String & str) const
|
||||
{
|
||||
ReadBufferFromMemory buf(str.data(), str.size());
|
||||
T x;
|
||||
UInt32 unread_scale = scale;
|
||||
readDecimalText(buf, x, precision, unread_scale, true);
|
||||
x *= getScaleMultiplier(unread_scale);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void DataTypeDecimal<T>::serializeBinary(const Field & field, WriteBuffer & ostr) const
|
||||
{
|
||||
@ -166,6 +188,7 @@ static DataTypePtr create(const ASTPtr & arguments)
|
||||
void registerDataTypeDecimal(DataTypeFactory & factory)
|
||||
{
|
||||
factory.registerDataType("Decimal", create, DataTypeFactory::CaseInsensitive);
|
||||
factory.registerAlias("DEC", "Decimal", DataTypeFactory::CaseInsensitive);
|
||||
}
|
||||
|
||||
|
||||
|
@ -198,6 +198,8 @@ public:
|
||||
return DataTypeDecimal<R>::getScaleMultiplier(scale_delta);
|
||||
}
|
||||
|
||||
T parseFromString(const String & str) const;
|
||||
|
||||
private:
|
||||
const UInt32 precision;
|
||||
const UInt32 scale; /// TODO: should we support scales out of [0, precision]?
|
||||
|
@ -188,7 +188,7 @@ namespace detail
|
||||
#if 1
|
||||
inline void writeSIntText(__int128 x, WriteBuffer & buf)
|
||||
{
|
||||
if (unlikely((x - 1) == 0))
|
||||
if (unlikely((x - 1) > x))
|
||||
{
|
||||
buf.write("-170141183460469231731687303715884105728", 40);
|
||||
return;
|
||||
|
@ -96,6 +96,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int CANNOT_PARSE_NUMBER;
|
||||
extern const int ARGUMENT_OUT_OF_BOUND;
|
||||
}
|
||||
|
||||
|
||||
@ -553,7 +554,7 @@ ReturnType readFloatTextSimpleImpl(T & x, ReadBuffer & buf)
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, unsigned int & scale)
|
||||
inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, unsigned int & scale, bool digits_only = false)
|
||||
{
|
||||
x = 0;
|
||||
int sign = 1;
|
||||
@ -598,28 +599,30 @@ inline void readDecimalText(ReadBuffer & buf, T & x, unsigned int precision, uns
|
||||
case '9':
|
||||
leading_zeores = false;
|
||||
if (trailing_zeores || precision == 0)
|
||||
throw Exception("Cannot read decimal value", ErrorCodes::CANNOT_PARSE_NUMBER);
|
||||
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)
|
||||
throw Exception("Cannot read decimal value", ErrorCodes::CANNOT_PARSE_NUMBER);
|
||||
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)
|
||||
if (after_point && scale)
|
||||
{
|
||||
--scale;
|
||||
if (scale == 0)
|
||||
if (!scale)
|
||||
trailing_zeores = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (digits_only)
|
||||
throw Exception("Unexpected symbol while reading decimal", ErrorCodes::CANNOT_PARSE_NUMBER);
|
||||
x *= sign;
|
||||
return;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ static Field convertNumericType(const Field & from, const IDataType & type)
|
||||
|
||||
|
||||
template <typename From, typename To>
|
||||
static Field convertIntToDecimalTypeImpl(const Field & from, const To & type)
|
||||
static Field convertIntToDecimalType(const Field & from, const To & type)
|
||||
{
|
||||
using FieldType = typename To::FieldType;
|
||||
|
||||
@ -86,13 +86,27 @@ static Field convertIntToDecimalTypeImpl(const Field & from, const To & type)
|
||||
return Field(FieldType(scaled_value));
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static Field convertStringToDecimalType(const Field & from, const DataTypeDecimal<T> & type)
|
||||
{
|
||||
using FieldType = typename DataTypeDecimal<T>::FieldType;
|
||||
|
||||
const String & str_value = from.get<String>();
|
||||
T value = type.parseFromString(str_value);
|
||||
return Field(FieldType(value));
|
||||
}
|
||||
|
||||
|
||||
template <typename To>
|
||||
static Field convertIntToDecimalType(const Field & from, const To & type)
|
||||
static Field convertDecimalType(const Field & from, const To & type)
|
||||
{
|
||||
if (from.getType() == Field::Types::UInt64)
|
||||
return convertIntToDecimalTypeImpl<UInt64>(from, type);
|
||||
return convertIntToDecimalType<UInt64>(from, type);
|
||||
if (from.getType() == Field::Types::Int64)
|
||||
return convertIntToDecimalTypeImpl<Int64>(from, type);
|
||||
return convertIntToDecimalType<Int64>(from, type);
|
||||
if (from.getType() == Field::Types::String)
|
||||
return convertStringToDecimalType(from, type);
|
||||
|
||||
throw Exception("Type mismatch in IN or VALUES section. Expected: " + type.getName() + ". Got: "
|
||||
+ Field::Types::toString(from.getType()), ErrorCodes::TYPE_MISMATCH);
|
||||
@ -150,9 +164,9 @@ Field convertFieldToTypeImpl(const Field & src, const IDataType & type)
|
||||
if (typeid_cast<const DataTypeInt64 *>(&type)) return convertNumericType<Int64>(src, type);
|
||||
if (typeid_cast<const DataTypeFloat32 *>(&type)) return convertNumericType<Float32>(src, type);
|
||||
if (typeid_cast<const DataTypeFloat64 *>(&type)) return convertNumericType<Float64>(src, type);
|
||||
if (auto * ptype = typeid_cast<const DataTypeDecimal<Int32> *>(&type)) return convertIntToDecimalType(src, *ptype);
|
||||
if (auto * ptype = typeid_cast<const DataTypeDecimal<Int64> *>(&type)) return convertIntToDecimalType(src, *ptype);
|
||||
if (auto * ptype = typeid_cast<const DataTypeDecimal<Int128> *>(&type)) return convertIntToDecimalType(src, *ptype);
|
||||
if (auto * ptype = typeid_cast<const DataTypeDecimal<Int32> *>(&type)) return convertDecimalType(src, *ptype);
|
||||
if (auto * ptype = typeid_cast<const DataTypeDecimal<Int64> *>(&type)) return convertDecimalType(src, *ptype);
|
||||
if (auto * ptype = typeid_cast<const DataTypeDecimal<Int128> *>(&type)) return convertDecimalType(src, *ptype);
|
||||
|
||||
const bool is_date = typeid_cast<const DataTypeDate *>(&type);
|
||||
bool is_datetime = false;
|
||||
|
@ -0,0 +1,21 @@
|
||||
999999999 999999999999999999 0 0.999999999 0.000000000000000000 0.00000000000000000000000000000000000000 9999.99999 0.000000000 0.000000000000000000 0
|
||||
1 1 1 0.000000001 0.000000000000000000 0.00000000000000000000000000000000000000 0.00001 0.000000001 0.000000000000000000 1
|
||||
-999999999 -999999999999999999 0 -0.999999999 0.000000000000000000 0.00000000000000000000000000000000000000 -9999.99999 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.000000000000000001 0.00000000000000000000000000000000000001 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 -99999999999999999999999999999999999999 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 -0.000000000000000001 -0.00000000000000000000000000000000000001 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.99999999999999999999999999999999999999 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000001 0
|
||||
0 0 0 0.000000000 0.000000000000000000 -0.99999999999999999999999999999999999999 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 -0.000000000000000001 0
|
||||
0 0 0 0.000000000 0.999999999999999999 0.00000000000000000000000000000000000000 0.00000 999999999.999999999 0.000000000000000000 0
|
||||
0 0 0 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
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 99999999999999999999.999999999999999999 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000000 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 -99999999999999999999.999999999999999999 0
|
||||
0 0 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.00000 0.000000000 0.000000000000000000 0
|
||||
42 42 0 0.000000000 0.000000000000000000 0.00000000000000000000000000000000000000 0.99999 0.000000000 0.000000000000000000 0
|
93
dbms/tests/queries/0_stateless/00700_decimal_bounds.sql
Normal file
93
dbms/tests/queries/0_stateless/00700_decimal_bounds.sql
Normal file
@ -0,0 +1,93 @@
|
||||
CREATE DATABASE IF NOT EXISTS test;
|
||||
DROP TABLE IF EXISTS test.decimal;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS test.decimal (x DECIMAL(10, -2)) ENGINE = Memory; -- { serverError 69 }
|
||||
CREATE TABLE IF NOT EXISTS test.decimal (x DECIMAL(10, 15)) ENGINE = Memory; -- { serverError 69 }
|
||||
CREATE TABLE IF NOT EXISTS test.decimal (x DECIMAL(0, 0)) ENGINE = Memory; -- { serverError 69 }
|
||||
|
||||
CREATE TABLE IF NOT EXISTS test.decimal
|
||||
(
|
||||
a DECIMAL(9,0),
|
||||
b DECIMAL(18,0),
|
||||
c DECIMAL(38,0),
|
||||
d DECIMAL(9, 9),
|
||||
e DECIMAL(18, 18),
|
||||
f DECIMAL(38, 38),
|
||||
g Decimal(9, 5),
|
||||
h decimal(18, 9),
|
||||
i deciMAL(38, 18),
|
||||
j DECIMAL(1,0)
|
||||
) ENGINE = Memory;
|
||||
|
||||
INSERT INTO test.decimal (a) VALUES (1000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (a) VALUES (-1000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (b) VALUES (1000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (b) VALUES (-1000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (c) VALUES (100000000000000000000000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (c) VALUES (-100000000000000000000000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (d) VALUES (1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (d) VALUES (-1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (e) VALUES (1000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (e) VALUES (-1000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (f) VALUES (1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (f) VALUES (-1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (g) VALUES (10000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (g) VALUES (-10000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (h) VALUES (1000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (h) VALUES (-1000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (i) VALUES (100000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (i) VALUES (-100000000000000000000); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (j) VALUES (10); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (j) VALUES (-10); -- { clientError 69 }
|
||||
|
||||
INSERT INTO test.decimal (a) VALUES (0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (a) VALUES (-0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (b) VALUES (0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (b) VALUES (-0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (c) VALUES (0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (c) VALUES (-0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (d) VALUES (0.0000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (d) VALUES (-0.0000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (e) VALUES (0.0000000000000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (e) VALUES (-0.0000000000000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (f) VALUES (0.000000000000000000000000000000000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (f) VALUES (-0.000000000000000000000000000000000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (g) VALUES (0.000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (g) VALUES (-0.000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (h) VALUES (0.0000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (h) VALUES (-0.0000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (i) VALUES (0.0000000000000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (i) VALUES (-0.0000000000000000001); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (j) VALUES (0.1); -- { clientError 69 }
|
||||
INSERT INTO test.decimal (j) VALUES (-0.1); -- { clientError 69 }
|
||||
|
||||
INSERT INTO test.decimal (a, b, d, g) VALUES (999999999, 999999999999999999, 0.999999999, 9999.99999);
|
||||
INSERT INTO test.decimal (a, b, d, g) VALUES (-999999999, -999999999999999999, -0.999999999, -9999.99999);
|
||||
INSERT INTO test.decimal (c) VALUES (99999999999999999999999999999999999999);
|
||||
INSERT INTO test.decimal (c) VALUES (-99999999999999999999999999999999999999);
|
||||
INSERT INTO test.decimal (f) VALUES (0.99999999999999999999999999999999999999);
|
||||
INSERT INTO test.decimal (f) VALUES (-0.99999999999999999999999999999999999999);
|
||||
INSERT INTO test.decimal (e, h) VALUES (0.999999999999999999, 999999999.999999999);
|
||||
INSERT INTO test.decimal (e, h) VALUES (-0.999999999999999999, -999999999.999999999);
|
||||
INSERT INTO test.decimal (i) VALUES (99999999999999999999.999999999999999999);
|
||||
INSERT INTO test.decimal (i) VALUES (-99999999999999999999.999999999999999999);
|
||||
|
||||
INSERT INTO test.decimal (a, b, c, d, g, j, h) VALUES (1, 1, 1, 0.000000001, 0.00001, 1, 0.000000001);
|
||||
INSERT INTO test.decimal (a, b, c, d, g, j, h) VALUES (-1, -1, -1, -0.000000001, -0.00001, -1, -0.000000001);
|
||||
INSERT INTO test.decimal (e, f) VALUES (0.000000000000000001, 0.00000000000000000000000000000000000001);
|
||||
INSERT INTO test.decimal (e, f) VALUES (-0.000000000000000001, -0.00000000000000000000000000000000000001);
|
||||
INSERT INTO test.decimal (i) VALUES (0.000000000000000001);
|
||||
INSERT INTO test.decimal (i) VALUES (-0.000000000000000001);
|
||||
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f, g, h, i, j) VALUES (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f, g, h, i, j) VALUES (-0, -0, -0, -0, -0, -0, -0, -0, -0, -0);
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f, g, h, i, j) VALUES (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
INSERT INTO test.decimal (a, b, c, d, e, f, g, h, i, j) VALUES (-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -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 }
|
||||
|
||||
SELECT * FROM test.decimal;
|
||||
--DROP TABLE IF EXISTS test.defaults;
|
Loading…
Reference in New Issue
Block a user