Skip to content

fix(isthmus)!: convert precision_time and precision_timestamp up to nanoseconds - #1318

Open
alexandrefimov wants to merge 2 commits into
substrait-io:mainfrom
alexandrefimov:issue-995-precision-ceiling
Open

alexandrefimov wants to merge 2 commits into
substrait-io:mainfrom
alexandrefimov:issue-995-precision-ceiling

Conversation

@alexandrefimov

@alexandrefimov alexandrefimov commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

SubstraitTypeSystem capped TIME, TIMESTAMP and TIMESTAMP_WITH_LOCAL_TIME_ZONE at microseconds, so a nanosecond precision_timestamp was refused although Calcite 1.42.0 builds such a type the moment the ceiling allows it. Raise it to nanoseconds; 10 to 12, which Calcite clamps rather than reports, stay refused and name the bound.

Converting back, a Substrait temporal value is a 64-bit count of its own unit, so nanoseconds reach only 2262 where a TimestampString reaches 9999. A timestamp past that is now reported instead of wrapping into a different instant.

Closes #995

BREAKING CHANGE: precision_time, precision_timestamp and precision_timestamp_tz convert up to nanoseconds, so plans that were refused now convert and TIME(9) or TIMESTAMP(9) can appear where the type system allowed at most 6.

Summary by CodeRabbit

  • New Features
    • TIME, TIMESTAMP, and timestamp-with-local-time-zone values now support precision up to nanoseconds. Time-with-local-time-zone values retain their existing precision limit.
  • Bug Fixes
    • Timestamp conversions now calculate fractional units exactly and report an error when a value exceeds the supported 64-bit range, rather than wrapping.
    • Nanosecond-precision time and timestamp values now round-trip accurately between Substrait and Calcite.

…anoseconds

SubstraitTypeSystem capped TIME, TIMESTAMP and TIMESTAMP_WITH_LOCAL_TIME_ZONE
at microseconds, so a plan carrying a nanosecond precision_timestamp was
refused although Calcite 1.42 builds such a type the moment the ceiling
allows it, and TimestampString carries the digits.

Raise the ceiling to nanoseconds. Precisions 10 to 12, which Substrait
allows and Calcite clamps rather than reports, stay refused, naming the
bound. Converting back, a value is a 64-bit count of its own unit, so
nanoseconds reach only 2262 where a TimestampString reaches 9999: a
timestamp outside that range is now reported instead of wrapping.

Closes substrait-io#995
@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 01cc4ea6-a5bf-4fd2-80a4-8734a6518cc2

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd1611 and b9a83fd.

📒 Files selected for processing (2)
  • isthmus/src/main/java/io/substrait/isthmus/expression/LiteralConverter.java
  • isthmus/src/test/java/io/substrait/isthmus/CalciteLiteralTest.java

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

Isthmus now supports precision 9 for TIME, TIMESTAMP, and TIMESTAMP_WITH_LOCAL_TIME_ZONE. Timestamp literal conversion uses exact arithmetic and throws IllegalArgumentException when the precision-scaled epoch count exceeds a 64-bit value.

Changes

Precision conversion

Layer / File(s) Summary
Precision limits and validation
isthmus/src/main/java/io/substrait/isthmus/SubstraitTypeSystem.java, isthmus/src/test/java/io/substrait/isthmus/*Test.java
The maximum precision for TIME, TIMESTAMP, and TIMESTAMP_WITH_LOCAL_TIME_ZONE is now 9. Tests cover supported precisions through 9 and rejection of timestamp precisions above 9.
Timestamp literal conversion
isthmus/src/main/java/io/substrait/isthmus/expression/LiteralConverter.java, isthmus/src/test/java/io/substrait/isthmus/CalciteLiteralTest.java
Timestamp conversion uses exact arithmetic for epoch units and reports overflow. Tests cover precision-9 time round-tripping and timestamp values at and beyond the 64-bit nanosecond-count limits.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to b9a83

The change enables nanosecond precision and reports timestamps outside the representable range. No actionable merge-blocking issue is established by the supplied evidence.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.43% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is a valid, concise Conventional Commit title. It accurately identifies the nanosecond precision change for time and timestamp conversion.
Description check ✅ Passed The description provides the rationale, supported precision limits, overflow behavior, linked issue, and BREAKING CHANGE details required by the template.
Linked Issues check ✅ Passed [#995] The PR raises the Calcite maximum for TIME, TIMESTAMP, and TIMESTAMP_WITH_LOCAL_TIME_ZONE to precision 9. Conversion tests cover precision 9 types and literals. Tests cover precisions 10 …
Out of Scope Changes check ✅ Passed The timestamp range checks support the precision-9 conversion required by [#995]. They prevent overflow from changing a timestamp into a different instant, and the tests verify the boundary behavior. …
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

The floored seconds of 1677-09-21 00:12:43 overflow when scaled to nanoseconds
although the value fits once the sub-second part is added back, so a negative
timestamp borrows that second before scaling. Pin both ends of the range and
the nanosecond past each.
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.

isthmus: Substrait→Calcite conversion rejects precision_time / precision_timestamp / precision_timestamp_tz precision > 6

1 participant