This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new c331aeb983 [vortex] Fix predicate pushdown literals for DATE and
second-precision TIMESTAMP (#9558)
c331aeb983 is described below
commit c331aeb98396409955a3e100133352550d03fdd1
Author: Eunbin Son <[email protected]>
AuthorDate: Thu Sep 3 17:24:03 2026 +0900
[vortex] Fix predicate pushdown literals for DATE and second-precision
TIMESTAMP (#9558)
---
.../format/vortex/VortexPredicateConverter.java | 8 ++-
.../vortex/VortexPredicateConverterTest.java | 63 ++++++++++++++++++++++
2 files changed, 69 insertions(+), 2 deletions(-)
diff --git
a/paimon-vortex/paimon-vortex-format/src/main/java/org/apache/paimon/format/vortex/VortexPredicateConverter.java
b/paimon-vortex/paimon-vortex-format/src/main/java/org/apache/paimon/format/vortex/VortexPredicateConverter.java
index e66f6cbece..d957daddfb 100644
---
a/paimon-vortex/paimon-vortex-format/src/main/java/org/apache/paimon/format/vortex/VortexPredicateConverter.java
+++
b/paimon-vortex/paimon-vortex-format/src/main/java/org/apache/paimon/format/vortex/VortexPredicateConverter.java
@@ -147,8 +147,9 @@ public class VortexPredicateConverter implements
PredicateVisitor<Expression> {
case SMALLINT:
return Expression.literal((Short) value);
case INTEGER:
- case DATE:
return Expression.literal((Integer) value);
+ case DATE:
+ return Expression.literalDate((Integer) value,
Expression.TimeUnit.DAYS);
case BIGINT:
return Expression.literal((Long) value);
case FLOAT:
@@ -179,7 +180,10 @@ public class VortexPredicateConverter implements
PredicateVisitor<Expression> {
private static Expression toTimestampLiteral(
Timestamp ts, int precision, @Nullable String timeZone) {
- if (precision <= 3) {
+ if (precision == 0) {
+ return Expression.literalTimestamp(
+ ts.getMillisecond() / 1000, Expression.TimeUnit.SECONDS,
timeZone);
+ } else if (precision <= 3) {
return Expression.literalTimestamp(
ts.getMillisecond(), Expression.TimeUnit.MILLISECONDS,
timeZone);
} else if (precision <= 6) {
diff --git
a/paimon-vortex/paimon-vortex-format/src/test/java/org/apache/paimon/format/vortex/VortexPredicateConverterTest.java
b/paimon-vortex/paimon-vortex-format/src/test/java/org/apache/paimon/format/vortex/VortexPredicateConverterTest.java
index 59a46a0a51..b36860ae7d 100644
---
a/paimon-vortex/paimon-vortex-format/src/test/java/org/apache/paimon/format/vortex/VortexPredicateConverterTest.java
+++
b/paimon-vortex/paimon-vortex-format/src/test/java/org/apache/paimon/format/vortex/VortexPredicateConverterTest.java
@@ -361,6 +361,69 @@ public class VortexPredicateConverterTest {
assertEquals(BinaryString.fromString("hello"),
rows.get(0).getString(2));
}
+ @Test
+ public void testDateSemantic(@TempDir java.nio.file.Path tempDir) throws
Exception {
+ // f_date >= 20 (epoch day) should return rows with f_date=20,30
+ RowType dateRowType = RowType.builder().field("f_date",
DataTypes.DATE()).build();
+ PredicateBuilder dateBuilder = new PredicateBuilder(dateRowType);
+ List<InternalRow> rows =
+ roundTrip(
+ tempDir,
+ dateRowType,
+ new GenericRow[] {GenericRow.of(10),
GenericRow.of(20), GenericRow.of(30)},
+
Collections.singletonList(dateBuilder.greaterOrEqual(0, 20)));
+ assertEquals(2, rows.size());
+ assertEquals(20, rows.get(0).getInt(0));
+ assertEquals(30, rows.get(1).getInt(0));
+ }
+
+ @Test
+ public void testTimestampSecondsPrecisionSemantic(@TempDir
java.nio.file.Path tempDir)
+ throws Exception {
+ // f_ts >= 2000s should return rows with f_ts=2000s,3000s
+ RowType tsRowType = RowType.builder().field("f_ts",
DataTypes.TIMESTAMP(0)).build();
+ PredicateBuilder tsBuilder = new PredicateBuilder(tsRowType);
+ List<InternalRow> rows =
+ roundTrip(
+ tempDir,
+ tsRowType,
+ new GenericRow[] {
+
GenericRow.of(Timestamp.fromEpochMillis(1_000_000L)),
+
GenericRow.of(Timestamp.fromEpochMillis(2_000_000L)),
+
GenericRow.of(Timestamp.fromEpochMillis(3_000_000L))
+ },
+ Collections.singletonList(
+ tsBuilder.greaterOrEqual(
+ 0,
Timestamp.fromEpochMillis(2_000_000L))));
+ assertEquals(2, rows.size());
+ assertEquals(2_000_000L, rows.get(0).getTimestamp(0,
0).getMillisecond());
+ assertEquals(3_000_000L, rows.get(1).getTimestamp(0,
0).getMillisecond());
+ }
+
+ @Test
+ public void testTimestampLtzSecondsPrecisionSemantic(@TempDir
java.nio.file.Path tempDir)
+ throws Exception {
+ // f_ts_ltz == 2000s should return only the row with f_ts_ltz=2000s
+ RowType tsRowType =
+ RowType.builder()
+ .field("f_ts_ltz",
DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(0))
+ .build();
+ PredicateBuilder tsBuilder = new PredicateBuilder(tsRowType);
+ List<InternalRow> rows =
+ roundTrip(
+ tempDir,
+ tsRowType,
+ new GenericRow[] {
+
GenericRow.of(Timestamp.fromEpochMillis(1_000_000L)),
+
GenericRow.of(Timestamp.fromEpochMillis(2_000_000L)),
+
GenericRow.of(Timestamp.fromEpochMillis(3_000_000L))
+ },
+ Collections.singletonList(
+ tsBuilder.equal(0,
Timestamp.fromEpochMillis(2_000_000L))));
+ assertEquals(1, rows.size());
+ assertEquals(2_000_000L, rows.get(0).getTimestamp(0,
0).getMillisecond());
+ }
+
private List<InternalRow> roundTrip(
java.nio.file.Path tempDir,
RowType rowType,