This is an automated email from the ASF dual-hosted git repository.

xuzifu666 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new c60d0883cc [CALCITE-7304] Floor/Ceil can not simplify with WEEK 
TimeUnit
c60d0883cc is described below

commit c60d0883ccdad88154f556551b138befea91e064
Author: Yu Xu <[email protected]>
AuthorDate: Sun May 24 20:58:09 2026 +0800

    [CALCITE-7304] Floor/Ceil can not simplify with WEEK TimeUnit
---
 .../java/org/apache/calcite/rex/RexSimplify.java   | 14 ++++
 .../calcite/test/RexImplicationCheckerTest.java    | 79 ++++++++++++++++++++++
 .../apache/calcite/test/SqlToRelConverterTest.java | 20 ++++++
 3 files changed, 113 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java 
b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
index 1c38d2d721..4d7702295b 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -2687,6 +2687,20 @@ private static boolean canRollUp(TimeUnit outer, 
TimeUnit inner) {
         break;
       }
       break;
+    case WEEK:
+      switch (inner) {
+      case WEEK:
+      case DAY:
+      case HOUR:
+      case MINUTE:
+      case SECOND:
+      case MILLISECOND:
+      case MICROSECOND:
+        return true;
+      default:
+        break;
+      }
+      break;
     case QUARTER:
       switch (inner) {
       case QUARTER:
diff --git 
a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java 
b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
index 042dcae1f0..60fbc4e6b8 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -24,6 +24,7 @@
 import org.apache.calcite.rex.RexSimplify;
 import org.apache.calcite.rex.RexUnknownAs;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.DateString;
@@ -556,4 +557,82 @@ public class RexImplicationCheckerTest {
     }
   }
 
+  /** Test case of
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7304";>[CALCITE-7304]
+   * Floor/Ceil can not simplify with WEEK TimeUnit</a>. */
+  @Test void testSimplifyCeilFloorWeek() {
+    final Fixture f = new Fixture();
+    // RexInterpreter does not support WEEK and DAY, so we disable paranoid
+    // verification for this test.
+    final RexSimplify nonParanoidSimplify = f.simplify.withParanoid(false);
+    final RexNode literalTs =
+        f.timestampLiteral(new TimestampString("2010-10-10 00:00:00"));
+
+    // Positive tests: floor(floor(x, inner), WEEK) -> floor(x, WEEK)
+    // when inner is DAY or finer.
+    for (TimeUnitRange innerRange : ImmutableList.of(
+        TimeUnitRange.WEEK, TimeUnitRange.DAY)) {
+      final RexNode innerFloorCall =
+          f.rexBuilder.makeCall(SqlStdOperatorTable.FLOOR, literalTs,
+              f.rexBuilder.makeFlag(innerRange));
+      final RexNode innerCeilCall =
+          f.rexBuilder.makeCall(SqlStdOperatorTable.CEIL, literalTs,
+              f.rexBuilder.makeFlag(innerRange));
+      final RexNode outerFloorCall =
+          f.rexBuilder.makeCall(SqlStdOperatorTable.FLOOR, innerFloorCall,
+              f.rexBuilder.makeFlag(TimeUnitRange.WEEK));
+      final RexNode outerCeilCall =
+          f.rexBuilder.makeCall(SqlStdOperatorTable.CEIL, innerCeilCall,
+              f.rexBuilder.makeFlag(TimeUnitRange.WEEK));
+      final RexCall floorSimplifiedExpr =
+          (RexCall) nonParanoidSimplify.simplifyPreservingType(outerFloorCall,
+              RexUnknownAs.UNKNOWN, true);
+      assertThat(floorSimplifiedExpr.getKind(), is(SqlKind.FLOOR));
+      assertThat(((RexLiteral) floorSimplifiedExpr.getOperands().get(1))
+              .getValue(),
+          hasToString(TimeUnitRange.WEEK.toString()));
+      assertThat(floorSimplifiedExpr.getOperands().get(0),
+          hasToString(literalTs.toString()));
+      final RexCall ceilSimplifiedExpr =
+          (RexCall) nonParanoidSimplify.simplifyPreservingType(outerCeilCall,
+              RexUnknownAs.UNKNOWN, true);
+      assertThat(ceilSimplifiedExpr.getKind(), is(SqlKind.CEIL));
+      assertThat(((RexLiteral) ceilSimplifiedExpr.getOperands().get(1))
+              .getValue(),
+          hasToString(TimeUnitRange.WEEK.toString()));
+      assertThat(ceilSimplifiedExpr.getOperands().get(0),
+          hasToString(literalTs.toString()));
+    }
+
+    // Negative tests: WEEK cannot rollup to MONTH or DAY,
+    // and MONTH cannot rollup to WEEK.
+    for (TimeUnitRange outerRange : ImmutableList.of(
+        TimeUnitRange.MONTH, TimeUnitRange.DAY)) {
+      assertNotSimplified(f, nonParanoidSimplify, SqlStdOperatorTable.FLOOR, 
literalTs,
+          TimeUnitRange.WEEK, outerRange);
+      assertNotSimplified(f, nonParanoidSimplify, SqlStdOperatorTable.CEIL, 
literalTs,
+          TimeUnitRange.WEEK, outerRange);
+    }
+    for (TimeUnitRange innerRange : ImmutableList.of(
+        TimeUnitRange.MONTH, TimeUnitRange.YEAR)) {
+      assertNotSimplified(f, nonParanoidSimplify, SqlStdOperatorTable.FLOOR, 
literalTs,
+          innerRange, TimeUnitRange.WEEK);
+      assertNotSimplified(f, nonParanoidSimplify, SqlStdOperatorTable.CEIL, 
literalTs,
+          innerRange, TimeUnitRange.WEEK);
+    }
+  }
+
+  private void assertNotSimplified(Fixture f, RexSimplify simplify, 
SqlOperator operator,
+      RexNode timestamp, TimeUnitRange innerRange, TimeUnitRange outerRange) {
+    final RexNode innerCall =
+        f.rexBuilder.makeCall(operator, timestamp,
+            f.rexBuilder.makeFlag(innerRange));
+    final RexNode outerCall =
+        f.rexBuilder.makeCall(operator, innerCall,
+            f.rexBuilder.makeFlag(outerRange));
+    final RexNode simplifiedExpr =
+        simplify.simplifyPreservingType(outerCall, RexUnknownAs.UNKNOWN, true);
+    assertThat(simplifiedExpr, hasToString(outerCall.toString()));
+  }
+
 }
diff --git 
a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index ebad0e9450..9217e74895 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -76,9 +76,11 @@
 
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasSize;
 
 /**
@@ -6133,4 +6135,22 @@ void checkUserDefinedOrderByOver(NullCollation 
nullCollation) {
         + "FROM emp JOIN dept using (deptno)";
     sql(sql).withConformance(SqlConformanceEnum.PRESTO).ok();
   }
+
+  /** Test case of
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7304";>[CALCITE-7304]
+   * Floor/Ceil can not simplify with WEEK TimeUnit</a>. */
+  @Test void testSimplifyNestedFloorWeekFromSql() {
+    final String sql = "select floor(floor(hiredate TO DAY) TO WEEK) from emp";
+    final RelNode rel = sql(sql).toRel();
+    final HepProgramBuilder programBuilder = HepProgram.builder();
+    programBuilder.addRuleInstance(CoreRules.PROJECT_REDUCE_EXPRESSIONS);
+    final HepPlanner planner = new HepPlanner(programBuilder.build());
+    planner.setRoot(rel);
+    final RelNode optimized = planner.findBestExp();
+    final String plan = RelOptUtil.toString(optimized);
+    // After PROJECT_REDUCE_EXPRESSIONS, nested floor(floor(x TO DAY) TO WEEK)
+    // should be simplified to floor(x TO WEEK).
+    assertThat(plan, not(containsString("FLOOR(FLOOR")));
+    assertThat(plan, containsString("FLOOR($4, FLAG(WEEK))"));
+  }
 }

Reply via email to