Introduce default parameters to DECIMAL family types

In standard SQL, the syntax DECIMAL(M) is equivalent to DECIMAL(M,0).
Similarly, the syntax DECIMAL is equivalent to DECIMAL(M,0), where the
implementation is permitted to decide the value of M.

https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html

Since MySQL uses 10 as the default value for precision,
suggesting to also support this in ClickHouse
This commit is contained in:
Song Liyong 2023-08-11 13:40:40 +02:00 committed by Val Doroshchuk
parent 525cc46b0b
commit 15310117b0
4 changed files with 48 additions and 14 deletions

View File

@ -4,15 +4,17 @@ sidebar_position: 42
sidebar_label: Decimal
---
# Decimal(P, S), Decimal32(S), Decimal64(S), Decimal128(S), Decimal256(S)
# Decimal, Decimal(P), Decimal(P, S), Decimal32(S), Decimal64(S), Decimal128(S), Decimal256(S)
Signed fixed-point numbers that keep precision during add, subtract and multiply operations. For division least significant digits are discarded (not rounded).
## Parameters
- P - precision. Valid range: \[ 1 : 76 \]. Determines how many decimal digits number can have (including fraction).
- P - precision. Valid range: \[ 1 : 76 \]. Determines how many decimal digits number can have (including fraction). By default the precision is 10.
- S - scale. Valid range: \[ 0 : P \]. Determines how many decimal digits fraction can have.
Decimal(P) is equivalent to Decimal(P, 0). Similarly, the syntax Decimal is equivalent to Decimal(10, 0).
Depending on P parameter value Decimal(P, S) is a synonym for:
- P from \[ 1 : 9 \] - for Decimal32(S)
- P from \[ 10 : 18 \] - for Decimal64(S)

View File

@ -74,21 +74,30 @@ SerializationPtr DataTypeDecimal<T>::doGetDefaultSerialization() const
static DataTypePtr create(const ASTPtr & arguments)
{
if (!arguments || arguments->children.size() != 2)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
"Decimal data type family must have exactly two arguments: precision and scale");
UInt64 precision = 10;
UInt64 scale = 0;
if (arguments)
{
if (arguments->children.empty() || arguments->children.size() > 2)
throw Exception(
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
"Decimal data type family must have precision and optional scale arguments");
const auto * precision = arguments->children[0]->as<ASTLiteral>();
const auto * scale = arguments->children[1]->as<ASTLiteral>();
const auto * precision_arg = arguments->children[0]->as<ASTLiteral>();
if (!precision_arg || precision_arg->value.getType() != Field::Types::UInt64)
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Decimal argument precision is invalid");
precision = precision_arg->value.get<UInt64>();
if (!precision || precision->value.getType() != Field::Types::UInt64 ||
!scale || !(scale->value.getType() == Field::Types::Int64 || scale->value.getType() == Field::Types::UInt64))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Decimal data type family must have two numbers as its arguments");
if (arguments->children.size() == 2)
{
const auto * scale_arg = arguments->children[1]->as<ASTLiteral>();
if (!scale_arg || !isInt64OrUInt64FieldType(scale_arg->value.getType()))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Decimal argument scale is invalid");
scale = scale_arg->value.get<UInt64>();
}
}
UInt64 precision_value = precision->value.get<UInt64>();
UInt64 scale_value = scale->value.get<UInt64>();
return createDecimal<DataTypeDecimal>(precision_value, scale_value);
return createDecimal<DataTypeDecimal>(precision, scale);
}
template <typename T>

View File

@ -0,0 +1,4 @@
Decimal(9, 8)
Decimal(18, 0)
Decimal(10, 0)
Decimal(18, 0) Decimal(10, 0)

View File

@ -0,0 +1,19 @@
DROP TABLE IF EXISTS decimal;
CREATE TABLE IF NOT EXISTS decimal
(
d1 DECIMAL(9, 8),
d2 DECIMAL(18),
d3 DECIMAL
)
ENGINE = MergeTree
PARTITION BY toInt32(d1)
ORDER BY (d2, d3);
INSERT INTO decimal (d1, d2, d3) VALUES (4.2, 4.2, 4.2);
SELECT type FROM system.columns WHERE table = 'decimal' AND database = currentDatabase();
SELECT toTypeName(d2), toTypeName(d3) FROM decimal LIMIT 1;
DROP TABLE decimal;