Skip to content

perf(calcite): answer temporal MIN/MAX from zone maps; scan them without java.time - #559

Merged
dfa1 merged 1 commit into
mainfrom
feat/temporal-minmax-pushdown
Oct 18, 2026
Merged

dfa1 merged 1 commit into
mainfrom
feat/temporal-minmax-pushdown

Conversation

@dfa1

@dfa1 dfa1 commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Stacked on #558 (rebased onto main once it merges).

  • Push-down: MIN/MAX of a date/time/timestamp column always scanned: the zone statistic is the raw storage integer and the literal builder had no temporal branch. Temporal resolves a column's kind and unit once and converts a raw integer to Calcite's internal form (epoch days, millis of day, epoch millis) with the decoders' rounding; the rule converts the statistic before building the literal.
  • Scan: temporal columns are read through the same conversion, no metadata parse or java.time object per row.
  • Precision: TIME/TIMESTAMP were declared at Calcite's default precision 0 while the scan delivered milliseconds, so a literal for the column lost them (min(order_placedOn) came back .0 instead of .335). They are now TIME(3)/TIMESTAMP(3); JDBC getString shows the milliseconds.

Raincloud appian-order (4.28M rows): min(placedOn), max(shipBy), max(inspectionTime) 337 → 28 ms.

Tests

  • TemporalPushDownTest: date/time/timestamp MIN/MAX (pre-epoch µs, two chunks) pushed and equal to the scan (+ interval '0'); Temporal rounding and out-of-day rejection.
  • vortex-jni cross-check: the same over Rust-written date/time/timestamp columns.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WtuVGQ5h5Lk6Zn4JnkxF1K

…out java.time

MIN/MAX of a date, time or timestamp column always scanned: the zone
statistic is the raw storage integer, and the literal builder had no
DATE/TIME/TIMESTAMP branch, so the rule abandoned. The scan path was slow
on those columns too: it parsed the extension metadata and built a
LocalDate/LocalTime/Instant for every row.

Temporal resolves a column's kind and unit once and converts a raw
storage integer straight to Calcite's internal form (epoch days, millis
of day, epoch millis), with the decoders' rounding: a millisecond date
and a timestamp floor, a time must lie within the day. The scan reads
temporal columns through it, and the aggregate rule converts a zone
statistic the same way before building the literal.

The adapter declared TIME and TIMESTAMP at Calcite's default precision
0 while the scan delivered milliseconds, so a literal built for the
column lost them: min(order_placedOn) came back .0 instead of .335. They
are now TIME(3) and TIMESTAMP(3), the precision the values carry, and
JDBC getString shows the milliseconds.

Raincloud appian-order (4.28M rows), best of 3:
  min(placedOn), max(shipBy), max(inspectionTime)   337 -> 28 ms

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WtuVGQ5h5Lk6Zn4JnkxF1K
@dfa1
dfa1 force-pushed the feat/temporal-minmax-pushdown branch from 941b156 to 3cbdfc2 Compare October 18, 2026 10:28
@dfa1
dfa1 merged commit f901f87 into main Oct 18, 2026
9 checks passed
@dfa1
dfa1 deleted the feat/temporal-minmax-pushdown branch October 18, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant