[
https://issues.apache.org/jira/browse/CALCITE-5212?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Ian Bertolacci updated CALCITE-5212:
------------------------------------
Description:
(Frankly, I'm not sure if there is really any need to change this behavior, as
scale without precision is a very odd case that doesn't really make a lot of
sense in the larger picture (the system we're building on top of uses precision
to mean digits _before_ the decimal-point and not the total number of digits,
and we're still playing around with if and how that should be expressed in
Calcite's type-system), but I'm still writing this out anyways just in-case it
is of interest to anyone or if someone else encounters this behavior and want's
an explanation.)
{{`RelDataTypeFactoryImpl.createSqlType(SqlTypeName.DECIMAL,
RelDataType.PRECISION_NOT_SPECIFIED, 5)`}} could be expected to create a
Decimal with scale 5.
However it instead creates a Decimal with scale 0.†
This happens because:
# RelDataType does not include scale in its digest if precision is not
specified.
Thus: Two Decimal types with different scales but no precision have *the same*
digest.
# RelDataType uses the digest to compute a hash code.
Thus: Two Decimal types with different scales but no precision have *the same*
hash code.
# {{`RelDataTypeFactoryImpl.canonize(RelDataType)`}} is used to look up a type
in {{`DATATYPE_CACHE`}} which uses the hash code as the key.
Thus: Two Decimal types with different scales but no precision *will collide*
in the cache.
# There is no check in RelDataTypeFactoryImpl or SqlTypeFactoryImpl's
canonize method to assert that the type returned from the cache actually
matches the type given as a parameter.
Thus: If the parameter type matches a type in the cache, the cache'd type will
*always* be returned, even if it the two types are different.
# RelDataTypeFactoryImpl and its child classes (such as SqlTypeFactoryImpl)
all use the result canonize *at the end* of the type creation functions (such
as createSqlType) as the result of the function.
Thus: If the function creates an intermediate Decimal type with scale but no
precision, the result of the function will be whatever that intermediate type
matches with in the cache, which could have any scale.
† I think it might actually be possible for a scale other than zero to be
returned if a Decimal with non-zero scale and unspecified precision has been
created before the Decimal with zero scale and unspecified precision has been
created.
was:
(Frankly, I'm not sure if there is really any need to resolve this problem, as
scale without precision is a very odd case that doesn't really make a lot of
sense in the larger picture (the system we're building on top of uses precision
to mean digits before the decimal and not the total number of digits), but I'm
still writing this out anyways just in-case it is of interest to anyone or if
someone else encounters this behavior and want's an explanation.)
{{`RelDataTypeFactoryImpl.createSqlType(SqlTypeName.DECIMAL,
RelDataType.PRECISION_NOT_SPECIFIED, 5)`}} could be expected to create a
Decimal with scale 5.
However it instead creates a Decimal with scale 0.†
This happens because:
# RelDataType does not include scale in its digest if precision is not
specified.
Thus: Two Decimal types with different scales but no precision have *the same*
digest.
# RelDataType uses the digest to compute a hash code.
Thus: Two Decimal types with different scales but no precision have *the same*
hash code.
# {{`RelDataTypeFactoryImpl.canonize(RelDataType)`}} is used to look up a type
in {{`DATATYPE_CACHE`}} which uses the hash code as the key.
Thus: Two Decimal types with different scales but no precision *will collide*
in the cache.
# There is no check in RelDataTypeFactoryImpl or SqlTypeFactoryImpl's
canonize method to assert that the type returned from the cache actually
matches the type given as a parameter.
Thus: If the parameter type matches a type in the cache, the cache'd type will
*always* be returned, even if it the two types are different.
# RelDataTypeFactoryImpl and its child classes (such as SqlTypeFactoryImpl)
all use the result canonize *at the end* of the type creation functions (such
as createSqlType) as the result of the function.
Thus: If the function creates an intermediate Decimal type with scale but no
precision, the result of the function will be whatever that intermediate type
matches with in the cache, which could have any scale.
† I think it might actually be possible for a scale other than zero to be
returned if a Decimal with non-zero scale and unspecified precision has been
created before the Decimal with zero scale and unspecified precision has been
created.
> Attempting to create a Decimal with scale specified but precision not
> specified results in Decimal with scale 0
> ---------------------------------------------------------------------------------------------------------------
>
> Key: CALCITE-5212
> URL: https://issues.apache.org/jira/browse/CALCITE-5212
> Project: Calcite
> Issue Type: Bug
> Affects Versions: 1.30.0
> Reporter: Ian Bertolacci
> Priority: Minor
>
> (Frankly, I'm not sure if there is really any need to change this behavior,
> as scale without precision is a very odd case that doesn't really make a lot
> of sense in the larger picture (the system we're building on top of uses
> precision to mean digits _before_ the decimal-point and not the total number
> of digits, and we're still playing around with if and how that should be
> expressed in Calcite's type-system), but I'm still writing this out anyways
> just in-case it is of interest to anyone or if someone else encounters this
> behavior and want's an explanation.)
>
> {{`RelDataTypeFactoryImpl.createSqlType(SqlTypeName.DECIMAL,
> RelDataType.PRECISION_NOT_SPECIFIED, 5)`}} could be expected to create a
> Decimal with scale 5.
> However it instead creates a Decimal with scale 0.†
> This happens because:
> # RelDataType does not include scale in its digest if precision is not
> specified.
> Thus: Two Decimal types with different scales but no precision have *the
> same* digest.
> # RelDataType uses the digest to compute a hash code.
> Thus: Two Decimal types with different scales but no precision have *the
> same* hash code.
> # {{`RelDataTypeFactoryImpl.canonize(RelDataType)`}} is used to look up a
> type in {{`DATATYPE_CACHE`}} which uses the hash code as the key.
> Thus: Two Decimal types with different scales but no precision *will collide*
> in the cache.
> # There is no check in RelDataTypeFactoryImpl or SqlTypeFactoryImpl's
> canonize method to assert that the type returned from the cache actually
> matches the type given as a parameter.
> Thus: If the parameter type matches a type in the cache, the cache'd type
> will *always* be returned, even if it the two types are different.
> # RelDataTypeFactoryImpl and its child classes (such as SqlTypeFactoryImpl)
> all use the result canonize *at the end* of the type creation functions (such
> as createSqlType) as the result of the function.
> Thus: If the function creates an intermediate Decimal type with scale but no
> precision, the result of the function will be whatever that intermediate type
> matches with in the cache, which could have any scale.
> † I think it might actually be possible for a scale other than zero to be
> returned if a Decimal with non-zero scale and unspecified precision has been
> created before the Decimal with zero scale and unspecified precision has been
> created.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)