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 a4ec47aba5a0..baf315e86b86 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 @@ -205,10 +205,20 @@ private static Expression toTimestampLiteral( Expression.TimeUnit.MICROSECONDS, timeZone); } else { - return Expression.literalTimestamp( - ts.getMillisecond() * 1_000_000 + ts.getNanoOfMillisecond(), - Expression.TimeUnit.NANOSECONDS, - timeZone); + // A TIMESTAMP value reaches year 9999, so nanoseconds since the epoch are not + // representable as an int64 outside roughly [1677-09-21, 2262-04-11]. A wrapped bound + // silently excludes matching rows, so refuse to push the literal down for the same + // reason as the grain checks above. + long nanos; + try { + nanos = + Math.addExact( + Math.multiplyExact(ts.getMillisecond(), 1_000_000L), + ts.getNanoOfMillisecond()); + } catch (ArithmeticException e) { + return null; + } + return Expression.literalTimestamp(nanos, Expression.TimeUnit.NANOSECONDS, timeZone); } } } 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 63b2099a5763..222e6bd0ce62 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 @@ -494,6 +494,27 @@ public void testTimestampMillisSubMillisecondLiteralNotPushed( assertEquals(1_500L, rows.get(0).getTimestamp(0, 0).getMillisecond()); } + @Test + public void testTimestampNanosOverflowingLiteralNotPushed(@TempDir java.nio.file.Path tempDir) + throws Exception { + // epoch millis times 1_000_000 overflows int64 nanoseconds beyond 2262-04-11, and the + // wrapped bound landed before the epoch, so "< 9999-12-31" dropped the epoch row + RowType tsRowType = RowType.builder().field("f_ts", DataTypes.TIMESTAMP(9)).build(); + PredicateBuilder tsBuilder = new PredicateBuilder(tsRowType); + List predicates = + Collections.singletonList( + tsBuilder.lessThan(0, Timestamp.fromEpochMillis(253402214400000L))); + assertNull(VortexPredicateConverter.toVortexExpression(predicates)); + List rows = + roundTrip( + tempDir, + tsRowType, + new GenericRow[] {GenericRow.of(Timestamp.fromEpochMillis(0L))}, + predicates); + assertEquals(1, rows.size()); + assertEquals(0L, rows.get(0).getTimestamp(0, 0).getMillisecond()); + } + private List roundTrip( java.nio.file.Path tempDir, RowType rowType,