Skip to content

[Sandbox] Drop DatetimeOutputCastRewriter on the analytics-engine route (sql#5420)#21748

Open
mengweieric wants to merge 3 commits into
opensearch-project:mainfrom
mengweieric:experiment/option-a-no-cast-rule
Open

[Sandbox] Drop DatetimeOutputCastRewriter on the analytics-engine route (sql#5420)#21748
mengweieric wants to merge 3 commits into
opensearch-project:mainfrom
mengweieric:experiment/option-a-no-cast-rule

Conversation

@mengweieric
Copy link
Copy Markdown
Contributor

@mengweieric mengweieric commented May 19, 2026

Problem

On the analytics-engine route, the SQL plugin wraps every datetime root column in CAST(<DATE/TIME/TIMESTAMP> AS VARCHAR), and DatetimeOutputCastRewriter translates those casts into DataFusion's to_char extension. Whenever the rewriter's format string and the PPL formatter disagree (e.g. trailing Z, T separator), users see wire-format divergence — opensearch-project/sql#5420.

Solution

Let the analytics engine return real datetime cells. The companion PR opensearch-project/sql#5454 removes the cast rule. The PPL response pipeline already handles datetime → string conversion natively at the formatter layer (ExprTimestampValue.value() etc.), so no engine-side formatting is needed.

Changes

  • Delete DatetimeOutputCastRewriter and its tests.
  • Remove the two convertFragment / convertStandalone callsites in DataFusionFragmentConvertor.
  • Drop the test that asserted the to_char extension was emitted from CAST(... VARCHAR).
  • Strip stale doc comments referencing the rewriter.
  • Keep the TO_CHAR -> to_char function mapping in opensearch_scalar_functions.yaml for any unrelated paths that may still emit TO_CHAR directly.

Verification

1. Unit tests

  • :sandbox:plugins:analytics-backend-datafusion:test — surviving rewriter tests still pass; the deleted rewriter's test class is removed cleanly (no orphan references).
  • :sandbox:plugins:analytics-backend-datafusion:compileJava :compileTestJava — confirms no callsite still references DatetimeOutputCastRewriter.
  • :sandbox:plugins:analytics-backend-datafusion:spotlessJavaCheck.

2. Companion-PR regression net

End-to-end behavior is asserted on the SQL plugin side (opensearch-project/sql#5454) — that side is where the user-visible wire format is observable:

  • DatetimeExtensionTest (PPL V3) + DatetimeExtensionSqlTest (SQL V2): RelNode shape + return-type assertions confirm no CAST(... VARCHAR) wrapper survives post-analysis, and testDatetimeFieldsPreserveStandardTypes asserts JDBC ResultSetMetaData reports DATE / TIME / TIMESTAMP (never VARCHAR) end-to-end.
  • CalciteAnalyticsDatetimeWireFormatIT: parquet-backed force-routed AE integration test asserting schema labels timestamp/date/time (never string) and PPL space-separated values (never T separator, never trailing Z).

3. End-to-end curl wire-format sweep

Driver: /tmp/ae-curl-verify/run-verify.py against a force-routed runTask cluster with this PR's plugin built into the sandbox bundle.

  • Routing proofs_explain confirms parquet index → AE route (LogicalTableScan + lowercase opensearch); legacy probe index → legacy route (CalciteLogicalIndexScan + capital OpenSearch). Routing is binary, no Calcite-fallback.
  • No to_char/CAST(... VARCHAR) in _explain of any datetime projection — confirms the rewriter is gone end-to-end (not just the SQL-plugin cast rule).
  • 11 pinned wire-format queries: equality filter, projection, eval-rebind, min/max/stats, > filter, sort, nanosecond precision, dc().
  • 7 broader queries: where+fields, head+fields, stats min/max, group by date, dc(d), multi-column projection sorted by ts, nanos > filter.

All 18 probes return timestamp/date/time schema labels with space-separated values; no ISO T, no trailing Z, no string labels.

Test plan

  • :sandbox:plugins:analytics-backend-datafusion:compileJava :compileTestJava
  • :sandbox:plugins:analytics-backend-datafusion:spotlessJavaCheck
  • :sandbox:plugins:analytics-backend-datafusion:test
  • Curl wire-format sweep (18/18 PASS) on force-routed AE cluster
  • CI gates
  • AE integration sweep with force-routing on

Companion PR: opensearch-project/sql#5454 (Remove DatetimeOutputCastRule)

@mengweieric mengweieric requested a review from a team as a code owner May 19, 2026 22:58
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

PR Reviewer Guide 🔍

(Review updated until commit b99a1e4)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ No major issues detected

@mengweieric mengweieric force-pushed the experiment/option-a-no-cast-rule branch from 4c7c0f6 to 1433e61 Compare May 19, 2026 23:09
@github-actions
Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 1433e61

@github-actions
Copy link
Copy Markdown
Contributor

✅ Gradle check result for 1433e61: SUCCESS

@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.39%. Comparing base (be29fd0) to head (c4c1995).

Additional details and impacted files
@@             Coverage Diff              @@
##               main   #21748      +/-   ##
============================================
- Coverage     73.48%   73.39%   -0.10%     
+ Complexity    75078    75011      -67     
============================================
  Files          6012     6012              
  Lines        340940   340940              
  Branches      49076    49076              
============================================
- Hits         250543   250228     -315     
- Misses        70409    70803     +394     
+ Partials      19988    19909      -79     

☔ View full report in Codecov by Sentry.
📢 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.

On the analytics-engine route, the SQL plugin wraps every datetime root
column in `CAST(<DATE/TIME/TIMESTAMP> AS VARCHAR)`, and this rewriter
translates those casts into DataFusion's `to_char` extension. Whenever
the rewriter's format string and the PPL formatter disagree (e.g.
trailing `Z`, `T` separator), users see wire-format divergence —
opensearch-project/sql#5420.

Let the analytics engine return real datetime cells. The companion PR
in `opensearch-project/sql` removes the cast rule. The PPL response
pipeline already handles datetime → string conversion natively at the
formatter layer (`ExprTimestampValue.value()` etc.), so no engine-side
formatting is needed.

- Delete `DatetimeOutputCastRewriter` and its tests.
- Remove the two `convertFragment` / `convertStandalone` callsites in
  `DataFusionFragmentConvertor`.
- Drop the test that asserted `to_char` extension was emitted from
  `CAST(... VARCHAR)`.
- Strip stale doc comments referencing the rewriter.
- Keep the `TO_CHAR -> to_char` function mapping in
  `opensearch_scalar_functions.yaml` for any unrelated paths that may
  still emit `TO_CHAR` directly.

Signed-off-by: Eric Wei <mengwei.eric@gmail.com>
@mengweieric mengweieric force-pushed the experiment/option-a-no-cast-rule branch from 1433e61 to c4c1995 Compare May 20, 2026 16:15
@github-actions
Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit c4c1995

@github-actions
Copy link
Copy Markdown
Contributor

✅ Gradle check result for c4c1995: SUCCESS

@github-actions
Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 859a5db

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 859a5db: null

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit b99a1e4

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for b99a1e4: TIMEOUT

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

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