zzwqqq created CALCITE-7529:
-------------------------------

             Summary: RexExecutor constant reduction loses sub-millisecond 
precision for TIME/TIMESTAMP literals
                 Key: CALCITE-7529
                 URL: https://issues.apache.org/jira/browse/CALCITE-7529
             Project: Calcite
          Issue Type: Bug
          Components: core
            Reporter: zzwqqq


When a custom RelDataTypeSystem allows datetime precision greater than 
Calcite's default maximum precision, RexExecutor constant reduction can lose 
sub-millisecond precision for TIME and TIMESTAMP values.

Calcite's default RelDataTypeSystem limits TIME/TIMESTAMP precision to 3, but 
users can override RelDataTypeSystem#getMaxPrecision. With such a type system, 
RexBuilder can be configured to create TIME(6) and TIMESTAMP(6) literals backed 
by TimeString/TimestampString.

However, RexExecutorImpl reduces constant expressions through generated Java 
code, where TIME and TIMESTAMP values are represented using millisecond-based 
runtime values. When RexExecutable.reduce rebuilds a RexLiteral from those 
values, digits beyond milliseconds are lost.

Minimal reproduction:

{code:java}
@Test void testReduceCastToTimeKeepsPrecision() {
  final RelDataTypeFactory typeFactory =
      new JavaTypeFactoryImpl(
          new RelDataTypeSystemImpl() {
            @Override public int getMaxPrecision(SqlTypeName typeName) {
              switch (typeName) {
              case TIME:
              case TIMESTAMP:
                return 6;
              default:
                return super.getMaxPrecision(typeName);
              }
            }
          });
  final RexBuilder rexBuilder = new RexBuilder(typeFactory);
  final RexExecutorImpl executor =
      new RexExecutorImpl(
          DataContexts.of(
              ImmutableMap.of(
                  DataContext.Variable.TIME_ZONE.camelName, 
TimeZone.getTimeZone("GMT"),
                  DataContext.Variable.LOCALE.camelName, Locale.US)));

  final RexNode cast =
      rexBuilder.makeCast(
          typeFactory.createSqlType(SqlTypeName.TIME, 6),
          rexBuilder.makeLiteral("12:34:56.123456"));

  final List<RexNode> reducedValues = new ArrayList<>();
  executor.reduce(rexBuilder, ImmutableList.of(cast), reducedValues);

  assertThat(
      ((RexLiteral) 
reducedValues.get(0)).getValueAs(TimeString.class).toString(6),
      equalTo("12:34:56.123456"));
}
{code}

Expected:

{code}
12:34:56.123456
{code}

Actual before the fix:

{code}
12:34:56.123000
{code}

The same issue can occur for TIMESTAMP(6). It can also affect already-created 
high precision TimeString/TimestampString RexLiterals if they are passed 
through RexExecutorImpl.reduce.

A possible fix is to preserve high-precision temporal literal casts as Rex 
literals when they can be represented directly by TimeString/TimestampString, 
and to let RexExecutorImpl return existing RexLiteral values without compiling 
and executing them again.





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

Reply via email to