Skip to content

Fix QTF stitcher precision mismatch on date_nanos fields#22095

Merged
mch2 merged 2 commits into
opensearch-project:mainfrom
vinaykpud:fix/late-mat-stitcher-date-nanos-precision
Jun 11, 2026
Merged

Fix QTF stitcher precision mismatch on date_nanos fields#22095
mch2 merged 2 commits into
opensearch-project:mainfrom
vinaykpud:fix/late-mat-stitcher-date-nanos-precision

Conversation

@vinaykpud

@vinaykpud vinaykpud commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description

ArrowCalciteTypes.toArrow() hardcoded TimeUnit.MILLISECOND for every Calcite TIMESTAMP. Shards emit Timestamp(NANOSECOND) for date_nanos, but the late-materialization Stitcher pre-allocated a TimestampMilliVector for the output. Arrow's copyFromSafe requires identical fixed-width subclasses, so it threw an empty IllegalArgumentException — surfacing to clients as HTTP 400 "Invalid Query".

Fix: branch on Calcite precision — precision == 9 → NANOSECOND, else MILLISECOND.

Query shapes this fixes

Triggered on a multi-shard parquet-backed index with a date_nanos field when the plan includes:

  • projection + sort on the date_nanos column
  • head N (or other top-K)
  • at least one fetch-only field above the anchor

Example PPL:

source = idx | where match(body, 'failed') and service = 'checkout'
             | sort - ts | fields ts, severity, body | head 4

Drop any of those and the LM rewriter declines QTF or the bug doesn't fire.

Tests

  • ArrowCalciteTypesTests — 3 new cases covering precision 3, 9, and default.
  • LateMaterializationDateNanosIT — new 2-shard parquet+lucene IT running the q01-style plan. Pre-fix: HTTP 400. Post-fix: 4 rows in DESC order with sub-millisecond precision preserved.

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@vinaykpud vinaykpud force-pushed the fix/late-mat-stitcher-date-nanos-precision branch from a79bbf3 to b381103 Compare June 10, 2026 07:49
@vinaykpud vinaykpud changed the title fix(analytics-engine): honour Calcite TIMESTAMP precision in QTF Honour Calcite TIMESTAMP precision in QTF Jun 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
📝 TODO sections

🔀 No multiple PR themes
⚡ No major issues detected

@github-actions

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Validate TIMESTAMP precision range

The precision check should validate the range of supported precisions. Calcite
TIMESTAMP precision can be 0-9, but only precision 9 maps to NANOSECOND. Consider
handling other precision values explicitly or documenting the assumption that non-9
precisions default to MILLISECOND.

sandbox/plugins/analytics-engine/src/main/java/org/opensearch/analytics/planner/ArrowCalciteTypes.java [51]

-case TIMESTAMP -> new ArrowType.Timestamp(t.getPrecision() == 9 ? TimeUnit.NANOSECOND : TimeUnit.MILLISECOND, null);
+case TIMESTAMP -> {
+    int precision = t.getPrecision();
+    if (precision == 9) {
+        yield new ArrowType.Timestamp(TimeUnit.NANOSECOND, null);
+    } else if (precision >= 0 && precision <= 3) {
+        yield new ArrowType.Timestamp(TimeUnit.MILLISECOND, null);
+    } else {
+        throw new IllegalArgumentException("Unsupported TIMESTAMP precision: " + precision + " (expected 0-3 or 9)");
+    }
+}
Suggestion importance[1-10]: 4

__

Why: The suggestion raises a valid concern about handling intermediate precision values (4-8), but the proposed solution may be overly restrictive. The current implementation uses a simple binary check (precision 9 vs. others), which aligns with the test cases showing precision 0, 3, and 9 are handled. However, throwing an exception for precisions 4-8 could break existing functionality if those values are used elsewhere in the codebase.

Low

@vinaykpud vinaykpud changed the title Honour Calcite TIMESTAMP precision in QTF Fix QTF stitcher precision mismatch on date_nanos fields Jun 10, 2026
@vinaykpud vinaykpud marked this pull request as ready for review June 10, 2026 07:51
@vinaykpud vinaykpud requested a review from a team as a code owner June 10, 2026 07:51
@vinaykpud vinaykpud force-pushed the fix/late-mat-stitcher-date-nanos-precision branch 2 times, most recently from 3989c62 to db76edf Compare June 10, 2026 07:53
@vinaykpud vinaykpud added skip-changelog skip-diff-analyzer Maintainer to skip code-diff-analyzer check, after reviewing issues in AI analysis. skip-diff-reviewer Maintainer to skip code-diff-reviewer check, after reviewing issues in AI analysis. labels Jun 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Gradle check result for db76edf: SUCCESS

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.48%. Comparing base (a8692f7) to head (db76edf).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main   #22095      +/-   ##
============================================
- Coverage     73.52%   73.48%   -0.05%     
+ Complexity    75682    75673       -9     
============================================
  Files          6038     6038              
  Lines        343009   343011       +2     
  Branches      49348    49348              
============================================
- Hits         252189   252045     -144     
- Misses        70746    70973     +227     
+ Partials      20074    19993      -81     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vinaykpud vinaykpud force-pushed the fix/late-mat-stitcher-date-nanos-precision branch from db76edf to ac69c17 Compare June 10, 2026 23:07
@vinaykpud

Copy link
Copy Markdown
Contributor Author

ArrowCalciteTypes.toArrow() hardcoded TimeUnit.MILLISECOND for every Calcite
TIMESTAMP, so the late-materialization Stitcher pre-allocated a
TimestampMilliVector for the output VSR. Shards correctly emitted
Timestamp(NANOSECOND) for date_nanos fields, and Arrow's
BaseFixedWidthVector.copyFromSafe requires identical fixed-width subclasses,
so it tripped on every shard's response with a message-less
IllegalArgumentException — surfacing to clients as HTTP 400 "Invalid Query".

Plan shape required to fire: multi-shard parquet-backed index with date_nanos +
Timestamp in projection + sort + head N (or other top-K) + at least one
fetch-only field above the anchor. Drop any one and the rewriter declines QTF
or the bug doesn't fire.

Fix: branch on Calcite precision. precision == 9 -> NANOSECOND, else MILLISECOND.
BackendPlanAdapter preserves precision through CAST rewrites, so the value is
reliable (verified via DEBUG plan dump showing TIMESTAMP(9) survives).

- Unit: ArrowCalciteTypesTests adds 3 cases covering precision 3, 9, default.
  The factory uses an extended RelDataTypeSystemImpl that lifts MAX_DATETIME
  precision to 9 — default Calcite caps at 3 and would silently clamp the test
  input.
- IT: LateMaterializationDateNanosIT spins a 2-shard parquet+lucene index with
  date_nanos and runs the q01-style plan (match + sort - ts + head + fetch-only
  field). Pre-fix: HTTP 400 with the exact bug signature. Post-fix: 4 rows in
  DESC order with sub-millisecond precision preserved.

Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
…SHOT

Aligns the local sandbox with the OpenSearch core 3.8 bump (opensearch-project#22090).
The SQL plugin and job-scheduler plugin use a four-segment version scheme
(major.minor.patch.0-SNAPSHOT) tracking core's three-segment 3.8.0.

- sandbox/qa/analytics-engine-rest/build.gradle: jobSchedulerPlugin and
  sqlPlugin zip dependencies pulled from OpenSearch Snapshots.
- sandbox/plugins/test-ppl-frontend/build.gradle: default fallback for
  -PsqlUnifiedQueryVersion (override-able for local sql-repo builds).

Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
@vinaykpud vinaykpud force-pushed the fix/late-mat-stitcher-date-nanos-precision branch from c71786a to 5de9bbc Compare June 11, 2026 00:03
@mch2 mch2 merged commit f221f32 into opensearch-project:main Jun 11, 2026
21 of 22 checks passed
KhishorekumarBS pushed a commit to KhishorekumarBS/OpenSearch that referenced this pull request Jul 3, 2026
…project#22095)

* Honour Calcite TIMESTAMP precision in QTF stitcher output schema

ArrowCalciteTypes.toArrow() hardcoded TimeUnit.MILLISECOND for every Calcite
TIMESTAMP, so the late-materialization Stitcher pre-allocated a
TimestampMilliVector for the output VSR. Shards correctly emitted
Timestamp(NANOSECOND) for date_nanos fields, and Arrow's
BaseFixedWidthVector.copyFromSafe requires identical fixed-width subclasses,
so it tripped on every shard's response with a message-less
IllegalArgumentException — surfacing to clients as HTTP 400 "Invalid Query".

Plan shape required to fire: multi-shard parquet-backed index with date_nanos +
Timestamp in projection + sort + head N (or other top-K) + at least one
fetch-only field above the anchor. Drop any one and the rewriter declines QTF
or the bug doesn't fire.

Fix: branch on Calcite precision. precision == 9 -> NANOSECOND, else MILLISECOND.
BackendPlanAdapter preserves precision through CAST rewrites, so the value is
reliable (verified via DEBUG plan dump showing TIMESTAMP(9) survives).

- Unit: ArrowCalciteTypesTests adds 3 cases covering precision 3, 9, default.
  The factory uses an extended RelDataTypeSystemImpl that lifts MAX_DATETIME
  precision to 9 — default Calcite caps at 3 and would silently clamp the test
  input.
- IT: LateMaterializationDateNanosIT spins a 2-shard parquet+lucene index with
  date_nanos and runs the q01-style plan (match + sort - ts + head + fetch-only
  field). Pre-fix: HTTP 400 with the exact bug signature. Post-fix: 4 rows in
  DESC order with sub-millisecond precision preserved.

Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>

* chore: bump opensearch-sql / opensearch-job-scheduler to 3.8.0.0-SNAPSHOT

Aligns the local sandbox with the OpenSearch core 3.8 bump (opensearch-project#22090).
The SQL plugin and job-scheduler plugin use a four-segment version scheme
(major.minor.patch.0-SNAPSHOT) tracking core's three-segment 3.8.0.

- sandbox/qa/analytics-engine-rest/build.gradle: jobSchedulerPlugin and
  sqlPlugin zip dependencies pulled from OpenSearch Snapshots.
- sandbox/plugins/test-ppl-frontend/build.gradle: default fallback for
  -PsqlUnifiedQueryVersion (override-able for local sql-repo builds).

Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>

---------

Signed-off-by: Vinay Krishna Pudyodu <vinkrish.neo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog skip-diff-analyzer Maintainer to skip code-diff-analyzer check, after reviewing issues in AI analysis. skip-diff-reviewer Maintainer to skip code-diff-reviewer check, after reviewing issues in AI analysis.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants