Ian Bertolacci created CALCITE-5212:
---------------------------------------

             Summary: 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


(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.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to