DanielLeens commented on PR #11905:
URL: https://github.com/apache/seatunnel/pull/11905#issuecomment-5379332171

   # What Problem Does This PR Solve?
   - User pain point: Zeta SQL's `EXTRACT()` had two implementation bugs that 
contradicted its own documentation (`docs/en/transforms/sql-functions.md`) — 
`EPOCH` silently overflowed `int` for any date on/after 2038-01-19, and 
`MILLISECOND(S)`/`MICROSECOND(S)` returned only the sub-second remainder 
instead of the documented whole-seconds-inclusive value.
   - Fix approach: widen `EPOCH`'s declared/returned type to `BIGINT`/`Number`, 
fix the millisecond/microsecond math to match docs, and disclose both as 
breaking changes with migration guidance in `incompatible-changes.md` (en/zh).
   - One-sentence summary: this head 
(`2446e2140089a3cde9a7b420cdd97085761f066f`) is completely unchanged since my 
last three reviews on 2026-08-20 and 2026-08-21 — I re-read the full diff from 
scratch again rather than assuming it, and it is byte-identical to what I 
already verified; the only thing genuinely new to check this round is whether 
CI has moved.
   
   # 1. Code Change Review
   
   ## 1.1 Core Logic Analysis
   
   I re-pulled `git diff` against the `dev` merge-base and re-read every 
changed file in full rather than relying on my memory of the previous three 
passes. The diff is unchanged: `DateTimeFunction.extract()`'s return type 
widens `Integer` → `Number`, the `EPOCH` branch drops its `(int)` cast 
(`DateTimeFunction.java:120-136`), `extractMilliseconds`/`extractMicroseconds` 
(`DateTimeFunction.java:618-630`) become whole-seconds-inclusive, and 
`ZetaSQLType.getExtractType()` (`ZetaSQLType.java:319-331`) declares `EPOCH` as 
`BasicType.LONG_TYPE` and every other field as `BasicType.INT_TYPE`.
   
   Re-tracing the value/declared-type consistency chain one more time, since 
it's the one place a mismatch here would cause silent data corruption or a 
`ClassCastException`:
   ```
   ZetaSQLEngine.typeMapping()              ZetaSQLEngine.transformBySQL()
      -> ZetaSQLType.getExpressionType()        -> 
ZetaSQLFunction.computeForValue()
           -> getExtractType(expr)                  -> 
DateTimeFunction.extract(args)
                EPOCH -> LONG_TYPE                        EPOCH -> long (boxed 
Long)
                other -> INT_TYPE                         other -> int (boxed 
Integer)
      -------------------- both independently feed the same SeaTunnelRow 
--------------------
   ```
   Both sides still agree for every field this PR touches; 
`testExtractEpochAfter2038` (`ExtractFunctionTest.java:237-256`) asserts both 
the declared `SqlType.BIGINT` and the raw `long` value together, which is the 
right shape to catch a future regression here.
   
   Since nothing in the source changed, my previously-raised Issue 1 stands 
unchanged too:
   
   - **Issue 1**
     - Location: 
`seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLFunction.java:392-398`
 (`ExtractExpression` branch of `computeForValue`)
     - Problem: unlike the `CaseExpression` branch a few lines below 
(`:404-408`), which runs its computed value through 
`SystemFunction.castAs(value, zetaSQLType.getExpressionType(expression))`, the 
`ExtractExpression` branch returns `DateTimeFunction.extract()`'s result as-is 
with no coercion against `getExtractType()`'s declared type.
     - Potential risk: currently harmless (the two independently-maintained 
sides agree today), but nothing structurally keeps them agreeing — a future 
contributor changing one side without the other would silently produce a 
value/declared-type mismatch that a downstream typed sink or row serializer 
could turn into wrong data or a `ClassCastException`.
     - Best improvement: mirror the `CaseExpression` pattern for defense in 
depth. Non-blocking for this PR.
     - Severity: Low
     - Raised by another reviewer: No (no other reviewer has commented on this 
self-authored PR)
   
   ## 1.2 Compatibility Impact
   **Partially incompatible — explicitly and correctly documented**, unchanged 
from my prior reviews: `EXTRACT(EPOCH ...)`'s declared output type changes 
`INT` → `BIGINT`, and `MILLISECOND(S)`/`MICROSECOND(S)` values change from 
fractional-only to whole-seconds-inclusive. Both are disclosed with concrete 
migration formulas in `docs/en/introduction/concepts/incompatible-changes.md` 
and mirrored in `docs/zh/...`.
   
   ## 1.3 Performance / Side-Effect Analysis
   Negligible — one extra multiply/add per 
`EXTRACT(MILLISECOND(S)|MICROSECOND(S))` evaluation, no new allocations, no 
checkpoint-path impact.
   
   ## 1.4 Error Handling and Logging
   No new error paths; `null` input and unsupported field/type combinations 
behave the same as before this PR.
   
   # 2. Code Quality Assessment
   
   ## 2.1 Coding Standards
   `extractMilliseconds`/`extractMicroseconds` and `getExtractType` all carry 
multi-line Javadoc explaining *why*, matching the repo's comment standards. No 
wildcard imports, formatting matches Spotless/AOSP style.
   
   ## 2.2 Test Coverage and Test Stability
   Deterministic, no flaky-test patterns (no `Thread.sleep`, no wall-clock 
dependence, no shared static state, no container/network I/O):
   - `testExtractEpochAfter2038` targets the exact 2038 overflow scenario, 
asserting both the declared schema type (`SqlType.BIGINT`) and the raw runtime 
value.
   - `testExtractFractionalSecondUnits`/`...ForLocalTimeAndOffsetDateTime` 
cover `LocalDateTime`, `LocalTime`, `OffsetDateTime` for both singular/plural 
field spellings.
   - `testExtractEpochForLocalDateAndOffsetDateTime` covers the 
`LocalDate`/`OffsetDateTime` EPOCH branches.
   - The pre-existing `testDateTimeExtractFunction` assertions were updated in 
place to the new expected values rather than deleted/weakened — the old test 
still verifies meaningful behavior.
   
   Rating: **Stable**.
   
   ## 2.3 Documentation Updates
   `docs/en` and `docs/zh` `incompatible-changes.md` both updated with 
matching, accurate entries and migration guidance. `sql-functions.md` (the 
source of truth this PR now correctly matches) needed no changes.
   
   # 3. Architectural Soundness
   
   ## 3.1 Elegance of the Solution
   Precise fix, not a workaround — makes the implementation match documentation 
that already existed and was already public, rather than inventing new 
semantics.
   
   ## 3.2 Maintainability
   Good, with the Issue 1 gap noted above.
   
   ## 3.3 Extensibility
   Adding a future EXTRACT field is straightforward via the same 
`DateTimeFunction.extract()` switch + `ZetaSQLType.getExtractType()` pair.
   
   ## 3.4 Historical-Version Compatibility
   A genuine, disclosed breaking change (silent int overflow past 2038, 
doc/implementation mismatch), not an accidental compatibility break, disclosed 
exactly as the repo's policy requires. Existing saved jobs whose downstream 
sink has an explicit/inferred `INT` schema for `EXTRACT(EPOCH...)`, or whose 
SQL post-processing relied on the old fractional-only millisecond/microsecond 
value, will see a behavior change on upgrade — that's the correct, intended 
outcome of fixing the bug.
   
   # 4. Issue Summary
   
   | # | Issue | Location | Severity |
   |---|-------|----------|----------|
   | 1 | No defensive `SystemFunction.castAs(...)` coercion between `EXTRACT`'s 
value and declared type | `ZetaSQLFunction.java:392-398` | Low |
   
   # 5. Merge Recommendation
   
   ### Conclusion: Ready to merge after fixes
   
   1. **Blockers**: None on the code itself — this is my fourth full pass on 
this exact head over three days and the source has not changed once. The only 
open item remains procedural, not code: the `Build` check on this head 
(`2446e2140089a3cde9a7b420cdd97085761f066f`) still shows `cancelled` as of this 
review, on the same fork run (`DanielLeens/seatunnel` run `32355489919`) I 
already triaged job-by-job in my previous comment — `Dead links` (unrelated 
pre-existing 404 in `docs/en/transforms/llm.md`), `engine-v2-it (8)` 
(Maven-wrapper `403` from `repo.maven.apache.org`, pure network infra), 
`all-connectors-it-7 (8)` (MySQL CDC fetcher flakiness, unrelated to 
`transform-v2`), and `engine-v2-it (11)`/`transform-v2-it-part-2 (8/11)` 
(cancelled by the same workflow-level cancellation). No new attempt has been 
triggered on this run in the ~24 hours since my last check, so it's still 
sitting cancelled rather than green. None of these lanes touch this diff's 
changed files (`DateTimeFunc
 tion.java`, `ZetaSQLType.java`, `ZetaSQLFunction.java`, the two 
`incompatible-changes.md` docs, `ExtractFunctionTest.java`).
   2. **Recommended fixes — non-blocking**: Issue 1 — add the 
`SystemFunction.castAs(...)` safety net to the `ExtractExpression` branch, 
mirroring `CaseExpression`, as a follow-up hardening.
   
   Overall assessment: unchanged from my prior three passes — this is a 
well-evidenced bug fix that makes the implementation match documentation that 
already existed and was already public, the breaking-change disclosure is 
accurate with a concrete migration path in both locales, and test coverage 
directly targets the exact bug scenario while asserting both the runtime value 
and the declared schema type together. What's still keeping this from an 
unqualified "Ready to merge" is purely that the fork's CI run for this head has 
not been re-attempted since it was cancelled a day ago — please rerun the 
specific failed/cancelled jobs (job-level, not a full rebuild, since none of 
them implicate this diff) and this is good to merge once that run is clean.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to