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

   Thanks for working on this! I re-derived this review from scratch against 
the current head (`9f534f6800ad6f1a476452e56511bb167726734b`), reading the real 
diff and tracing the type-mapping call chain rather than relying on the PR 
description or prior review notes.
   
   # What Problem Does This PR Solve?
   - **User pain point**: Several JDBC dialects (DB2, Presto, Teradata, 
Vertica) and the generic/deprecated catalog fallback (`JdbcColumnConverter`) 
either threw `UnsupportedOperationException` / 
`CommonError.convertToSeaTunnelTypeError`, or silently dropped the UTC offset 
by folding into `LOCAL_DATE_TIME_TYPE`, whenever a source table had a 
`TIMESTAMP WITH TIME ZONE` / `TIMESTAMPTZ` column. This PR is the tail end of 
the `TIMESTAMP_TZ` migration started by PR #10048 (Postgres) and the broader 
effort recorded in `incompatible-changes.md`.
   - **Fix approach**: Add a `TIMESTAMP_WITH_TIMEZONE → OFFSET_DATE_TIME_TYPE` 
case to `GenericTypeConverter` and `DB2TypeConverter`; add native-type-name 
recognition to `PrestoTypeMapper`, `TeradataTypeMapper`, `VerticaTypeMapper`; 
teach the generic `JdbcColumnConverter` fallback to reclassify a column as 
`TIMESTAMP_WITH_TIMEZONE` from its native type name even when the driver's own 
`DATA_TYPE` code doesn't say so; and add a DB2-for-z/OS-specific value reader 
(`DBTimestamp.toDBString(true)` via reflection) because `ResultSet.getString()` 
strips the offset for that driver's proprietary type.
   - **One-sentence summary**: Closes out `TIMESTAMP_TZ` support for the 
remaining JDBC dialects, but the two dialects with the least mature JDBC 
drivers (Teradata, Vertica) get weaker guarantees than Presto/DB2 got in this 
same PR, and the branch itself is currently unmergeable against `dev`.
   
   # 1. Code Change Review
   
   ## 1.1 Core Logic Analysis
   
   **Files touched (production code)**: `JdbcColumnConverter.java`, 
`GenericTypeConverter.java`, `DB2TypeConverter.java`, `PrestoDialect.java`, 
`PrestoTypeMapper.java`, `TeradataTypeMapper.java`, `VerticaTypeMapper.java`, 
`JdbcFieldTypeUtils.java`.
   
   The critical path is schema discovery (`*TypeMapper.mapping(...)` / 
`*TypeConverter.convert(...)`, invoked once per column at 
catalog/schema-inference time) feeding into per-row value reads 
(`AbstractJdbcRowConverter.toInternal()` → `case TIMESTAMP_TZ: 
JdbcFieldTypeUtils.getOffsetDateTime(rs, idx)`, unchanged in this PR, at 
`AbstractJdbcRowConverter.java:121-125`). If schema discovery gets the type 
wrong, either the column is unreadable (fails fast) or the value reader 
mis-parses it (silently wrong).
   
   **Before/after — `JdbcColumnConverter.java` (the deprecated generic catalog 
fallback, still live — see below):**
   ```java
   // before
   switch (jdbcType) {
       ...
       case TIMESTAMP:
       case TIMESTAMP_WITH_TIMEZONE:
           seaTunnelType = LocalTimeType.LOCAL_DATE_TIME_TYPE;
           break;
   
   // after
   int effectiveJdbcType =
           isTimestampWithTimeZone(nativeType) ? TIMESTAMP_WITH_TIMEZONE : 
jdbcType;
   switch (effectiveJdbcType) {
       ...
       case TIMESTAMP:
           seaTunnelType = LocalTimeType.LOCAL_DATE_TIME_TYPE;
           break;
       case TIMESTAMP_WITH_TIMEZONE:
           seaTunnelType = LocalTimeType.OFFSET_DATE_TIME_TYPE;
           break;
   ```
   `isTimestampWithTimeZone` matches `"TIMESTAMPTZ"` exactly or 
`TIMESTAMP(?:\s*\(\s*\d+\s*\))?\s+WITH\s+TIME\s+ZONE` against the upper-cased 
native type name (`JdbcColumnConverter.java:265-272`).
   
   **Before/after — `GenericTypeConverter.java`:**
   ```java
   // before: no case for Types.TIMESTAMP_WITH_TIMEZONE at all → fell into 
`default:` →
   // log.warn(...) and the builder's dataType is left unset.
   // after:
   case Types.TIMESTAMP_WITH_TIMEZONE:
       builder.dataType(LocalTimeType.OFFSET_DATE_TIME_TYPE);
       builder.scale(typeDefine.getScale());
       break;
   ```
   
   **`PrestoTypeMapper.java` — the interesting fix in this PR:**
   ```java
   String columnType = metadata.getColumnTypeName(colIndex).toUpperCase();
   // Presto can report a precision between TIMESTAMP and WITH TIME ZONE.
   if (columnType.startsWith(PRESTO_TIMESTAMP) && columnType.contains("WITH 
TIME ZONE")) {
       columnType = PRESTO_TIMESTAMP_WITH_TIME_ZONE;
   }
   // VARCHAR(x)      --->      VARCHAR
   if (columnType.indexOf("(") > -1) {
       columnType = columnType.split("\\(")[0];
   }
   ```
   This is correct and necessary: Presto/Trino reports `timestamp(3) with time 
zone`, and the pre-existing generic `split("\\(")[0]` strip (needed for 
`VARCHAR(255)` etc.) would otherwise truncate that string to bare 
`"TIMESTAMP"`, losing the `WITH TIME ZONE` suffix and silently dropping the 
column into the timezone-naive branch. The normalization runs *before* the 
generic paren-strip, so precision-qualified input is handled correctly. 
Verified against 
`TimestampWithTimeZoneTypeMappingTest.testPrestoTimestampWithTimeZone`.
   
   **`TeradataTypeMapper.java` / `VerticaTypeMapper.java` — the same class of 
fix is NOT applied here:**
   ```java
   // TeradataTypeMapper.mapping(), no precision normalization at all:
   String teradataType = metadata.getColumnTypeName(colIndex).toUpperCase();
   switch (teradataType) {
       ...
       case TERADATA_TIMESTAMP_WITH_TIME_ZONE:   // exact-equals "TIMESTAMP 
WITH TIME ZONE"
           return LocalTimeType.OFFSET_DATE_TIME_TYPE;
       default:
           throw CommonError.convertToSeaTunnelTypeError(...);
   }
   ```
   See Issue 1 below — this is an exact `switch`/`equals` match with no 
tolerance for a precision-qualified type name, unlike the Presto fix two files 
away in the same commit.
   
   **`DB2TypeConverter.java`** adds a matching `case` and reconstructs 
`sourceType` as `"TIMESTAMP(%d) WITH TIME ZONE"`; correct and consistent with 
how the rest of the class already models scale.
   
   **`JdbcFieldTypeUtils.java`** adds a `DBTimestamp`-specific branch (checked 
by exact class name, ahead of the generic `Timestamp` branch since `DBTimestamp 
extends Timestamp`) that calls `toDBString(true)` via reflection to recover the 
offset that `ResultSet.getString()` would otherwise strip for this driver, plus 
a `normalizeDb2OffsetDateTimeString` step that truncates DB2's up-to-12-digit 
fractional seconds to the 9 digits `java.time` supports — by truncation, not 
rounding, so the represented instant is never advanced. This part is 
well-reasoned and has a dedicated unit test 
(`JdbcFieldTypeUtilsTest.testGetOffsetDateTimeFromDb2TimestampPreservesOffsetAndTruncatesPicos`)
 that mocks a real `DBTimestamp` and asserts `getString()` is never called — 
good, precise test.
   
   **Key Findings:**
   - The normal read path (source query execution → `AbstractJdbcRowConverter` 
→ `JdbcFieldTypeUtils.getOffsetDateTime`) is squarely hit by this change; this 
is not a defensive/edge-case fix, it's the main path for any table with a 
`TIMESTAMP WITH TIME ZONE` column in the four newly-covered dialects.
   - Db2 and Presto get precision/format-tolerant matching plus dedicated 
value-round-trip tests. Teradata and Vertica get exact-string type-name 
matching and zero value-round-trip tests — the two weakest drivers get the 
least defensive implementation.
   - The fix is precise (not a workaround) for DB2, Presto, and the generic 
`GenericTypeConverter`/`JdbcColumnConverter` cases; for Teradata/Vertica it's a 
partial fix that reproduces the same "precision embedded in 
`getColumnTypeName()`" hazard the PR explicitly solved for Presto two files 
over.
   - Remaining hole: `JdbcFieldTypeUtils.getOffsetDateTime()`'s pre-existing 
generic `Timestamp` fallback (not touched by this PR, but newly reachable for 
Teradata/Vertica since before this PR those dialects could never produce a 
`TIMESTAMP_TZ`-typed column at all) silently falls back to 
`Timestamp.toInstant().atOffset(ZoneOffset.UTC)` — i.e., mislabels a 
JVM-default-timezone-shifted instant as UTC — if 
`parseOffsetDateTimeFromString` throws on whatever string 
`resultSet.getString()` returns for that driver. See Issue 3.
   
   **Runtime path (source-side schema inference → value read, cross-stage 
because the inferred `SeaTunnelDataType` flows into every downstream 
Transform/Sink):**
   ```text
   Job starts, JDBC source schema discovery
     -> CatalogUtils.getTableSchema(metadata, tablePath, dialect)  
[CatalogUtils.java:230-238]
         -> dialect.getJdbcDialectTypeMapper().mappingColumn(metadata, ...)
             -> for Teradata/Vertica/Presto: mappingColumn(BasicTypeDefine) not 
overridden
                -> throws UnsupportedOperationException
         -> catch (UnsupportedOperationException e): columns = 
JdbcColumnConverter.convert(metadata, tablePath)  [CatalogUtils.java:256-257]
             -> isTimestampWithTimeZone(nativeType) reclassifies 
effectiveJdbcType
             -> TIMESTAMP_WITH_TIMEZONE branch now yields OFFSET_DATE_TIME_TYPE 
(was LOCAL_DATE_TIME_TYPE)
     (this is table_path= mode; query= mode instead goes through
      CatalogUtils.getCatalogTable(ResultSetMetaData, typeMapper, sqlQuery) -> 
typeMapper.mapping(metadata, index)
      directly, i.e. TeradataTypeMapper/VerticaTypeMapper/PrestoTypeMapper's 
own exact-match switch — a
      DIFFERENT code path from the tolerant regex above, see Issue 1)
   Row read phase
     -> AbstractJdbcRowConverter.toInternal(), case TIMESTAMP_TZ  
[AbstractJdbcRowConverter.java:121-125]
         -> JdbcFieldTypeUtils.getOffsetDateTime(rs, idx)
             -> DB2: DBTimestamp branch, toDBString(true) via reflection, 
offset preserved
             -> everyone else backed by java.sql.Timestamp: re-read as string, 
parseOffsetDateTimeFromString
                -> on parse failure: silently returns 
Timestamp.toInstant().atOffset(UTC) [JdbcFieldTypeUtils.java:210]
   ```
   
   ## 1.2 Compatibility Impact: **Partially incompatible**
   - This PR is an incremental extension of an already-documented breaking 
change (`docs/en/introduction/concepts/incompatible-changes.md`, "Breaking 
Change: Mapping of timezone-aware timestamp columns to `TIMESTAMP_TZ` type", 
tracked under `#10685`). That entry already frames the general risk (downstream 
sinks expecting `TIMESTAMP` may now get `TIMESTAMP_TZ`).
   - What's new and *not* covered by that entry or by this PR's own doc 
updates: the `JdbcColumnConverter` fallback change is not scoped to 
DB2/Presto/Teradata/Vertica — it changes behavior for **any** dialect that (a) 
has no `mappingColumn(BasicTypeDefine)` override and (b) is read in 
`table_path=` mode, whenever the driver reports a native type name matching the 
new regex or `TIMESTAMPTZ`, or a `DATA_TYPE` code of 
`Types.TIMESTAMP_WITH_TIMEZONE`. Before this PR such a column deterministically 
mapped to `LOCAL_DATE_TIME_TYPE`; after this PR it maps to 
`OFFSET_DATE_TIME_TYPE`. For any already-running job on an unlisted/custom 
dialect that happens to match, this silently changes the inferred schema (and, 
per the existing ledger entry, can change how Iceberg/Hudi/StarRocks sinks 
serialize the column) — with no corresponding bullet added to 
`incompatible-changes.md` for this specific fallback path. See Issue 4.
   - No config option names, defaults, or SPI method signatures were removed or 
renamed. `PrestoDialect.supportsPrimaryKeyMetadata()` overriding the `true` 
default to `false` is additive from an API-contract point of view (the 
interface method already existed with a default), but changes Presto's own 
`table_path=` primary-key-detection behavior — see Issue 6 on scope.
   
   ## 1.3 Performance / Side-Effect Analysis
   - `JdbcFieldTypeUtils.getOffsetDateTime()` resolves 
`obj.getClass().getMethod("toDBString", boolean.class)` via reflection **on 
every row**, for every DB2 `TIMESTAMP WITH TIME ZONE` column 
(`JdbcFieldTypeUtils.java:189`), instead of caching the `Method` once. 
Reflective `getMethod` lookups are not free; for a wide DB2 z/OS extract with 
multiple TZ columns and millions of rows this is avoidable per-row overhead. 
See Issue 5 (Low, not a correctness bug).
   - The new `Pattern` in `JdbcColumnConverter` is a `static final` field, 
compiled once — correct.
   - No new locks, no new network calls, no unbounded buffers introduced.
   
   ## 1.4 Error Handling and Logging
   - The DB2 reflection branch correctly wraps `ReflectiveOperationException | 
ClassCastException` into a `SQLException` with context (`"Failed to read Db2 
timestamp with time zone"`), rather than swallowing it — good.
   - `JdbcColumnConverter`'s `default:` branch now reports `effectiveJdbcType` 
in the exception message instead of the raw `jdbcType` — a good, deliberate 
improvement (the error now reflects the type actually being switched on).
   - No sensitive data is logged; no exceptions are swallowed by this PR's own 
changes.
   - See Issue 3 for the *pre-existing* silent-fallback risk this PR newly 
exposes for Teradata/Vertica (not introduced by this PR, but newly reachable 
and untested for these two dialects).
   
   **Issue 1: Teradata/Vertica precision-qualified `TIMESTAMP(n) WITH TIME 
ZONE` is unrecognized in `query=` mode**
   - **Location:** 
`seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/teradata/TeradataTypeMapper.java:66-101`,
 `.../vertica/VerticaTypeMapper.java:100-180`
   - **Problem description:** Both mappers do an exact `switch`/`equals` 
comparison against `"TIMESTAMP WITH TIME ZONE"` on the upper-cased 
`ResultSetMetaData.getColumnTypeName()` value, with no precision-paren 
tolerance. `PrestoTypeMapper`, touched in this same commit, explicitly guards 
against exactly this hazard (`columnType.startsWith(PRESTO_TIMESTAMP) && 
columnType.contains("WITH TIME ZONE")`, applied before the generic paren-strip) 
because Presto reports `timestamp(3) with time zone`. This mapper is used 
exclusively by `query =` mode source configs 
(`CatalogUtils.getCatalogTable(ResultSetMetaData, typeMapper, sqlQuery)` → 
`typeMapper.mappingColumn(metadata, index)` default impl → `mapping(metadata, 
colIndex)` directly), which is a different code path from the tolerant 
`JdbcColumnConverter` regex fallback used by `table_path=` mode.
   - **Potential risk:** If the Teradata/Vertica JDBC driver ever embeds 
precision in `getColumnTypeName()` for this type (plausible — this PR's own 
`JdbcColumnConverter`-fallback test, 
`testTableMetadataFallbackRecognizesProprietaryTypeCodes`, uses `"TIMESTAMP(6) 
WITH TIME ZONE"` as the illustrative "teradata" input, and `DB2TypeConverter` 
in this same PR constructs source types in the `"TIMESTAMP(%d) WITH TIME ZONE"` 
shape), any `query=`-mode job hits `default:` and throws 
`CommonError.convertToSeaTunnelTypeError` at schema-discovery time — the column 
becomes entirely unreadable via `query=` mode, which is the primary mode 
exercised by this PR's own tests (the Presto e2e test uses `query=`, not 
`table_path=`).
   - **Best improvement:** Apply the same normalization used for Presto 
(strip/normalize an optional `(n)` before the switch) to `TeradataTypeMapper` 
and `VerticaTypeMapper`, or reuse the `TIMESTAMP_WITH_TIME_ZONE_TYPE_NAME` 
regex already added to `JdbcColumnConverter` so all three dialects share one 
tolerant matcher instead of three different heuristics.
   - **Severity:** Medium (not confirmed with a live Teradata/Vertica driver — 
static analysis only, per review scope — but internally inconsistent with the 
PR's own fix pattern and its own test fixtures).
   
   **Issue 2: Merge conflict — PR is not currently mergeable against `dev`**
   - **Location:** GitHub mergeability state (`mergeStateStatus=DIRTY`, 
`mergeable=CONFLICTING`); `compare/dev...9f534f680` reports `status=diverged, 
ahead_by=5, behind_by=45`.
   - **Problem description:** I ran a live check (not cached): `dev`'s 
`seatunnel-e2e/.../JdbcPrestoIT.java` now imports 
`org.apache.seatunnel.e2e.common.util.DependencyJar` and calls 
`DependencyJar.ofClassName(DRIVER_CLASS)` instead of the `driverUrl()` override 
this branch's `JdbcPrestoIT.java` still relies on — confirmed by reading 
`dev`'s copy of the file directly. This is an unrelated upstream 
E2E-infrastructure refactor that happens to touch the exact file this PR 
extends with `testTimestampWithTimeZoneMappingAndValue()`.
   - **Potential risk:** Cannot be merged as-is regardless of code correctness; 
GitHub will block the merge button and a stale rebase risks silently 
reintroducing the old `driverUrl()` pattern dev has since moved away from.
   - **Best improvement:** Sync with the latest `dev`, drop the removed 
`driverUrl()` override, keep the new 
`testTimestampWithTimeZoneMappingAndValue()` method and its imports, adopt 
`DependencyJar`-based resolution, then re-run CI to confirm the Presto E2E 
cases (including the new TZ test) still pass under the new driver-resolution 
mechanism.
   - **Severity:** High (blocks merge outright; independent of all code-quality 
findings above).
   
   **Issue 3: Shared `Timestamp`-string fallback can silently mislabel a 
JVM-shifted instant as UTC, now newly reachable — and untested — for 
Teradata/Vertica**
   - **Location:** 
`seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/JdbcFieldTypeUtils.java:201-212`
 (pre-existing code, not touched by this PR)
   - **Problem description:**
     ```java
     if (obj instanceof Timestamp) {
         String strVal = resultSet.getString(columnIndex);
         if (strVal == null) return null;
         try {
             return parseOffsetDateTimeFromString(strVal);
         } catch (Exception e) {
             // Last resort: use the instant-based conversion (may shift by JVM 
offset)
             return ((Timestamp) obj).toInstant().atOffset(ZoneOffset.UTC);
         }
     }
     ```
     Before this PR, Teradata and Vertica could never produce a 
`TIMESTAMP_TZ`-typed column (both mappers threw 
`CommonError.convertToSeaTunnelTypeError` for `TIMESTAMP WITH TIME ZONE`), so 
this fallback was never exercised for them. This PR makes it the value-read 
path for both dialects, but adds no dedicated test that feeds a realistic 
Teradata/Vertica driver `getString()` output through 
`parseOffsetDateTimeFromString` to prove it actually succeeds — contrast with 
DB2, which got a dedicated `DBTimestamp`-mocking test in this same PR.
     I verified the two most likely real-world formats (Vertica Postgres-style 
`"...-04"` and Teradata `"...+08:00"`) do parse correctly via the existing 
`normalizeOffsetDateTimeString`/direct-ISO paths, so I cannot confirm this 
branch is actually hit in practice — but the absence of any test proving it, 
for a `catch (Exception e)` block whose failure mode is silent data corruption 
rather than a thrown error, is itself the gap.
   - **Potential risk:** If a Teradata/Vertica driver ever returns a 
`getString()` format this parser doesn't recognize, the job does not fail — it 
silently returns a wrong `OffsetDateTime` (JVM-local instant mislabeled as UTC) 
with no log line distinguishing this from a genuine UTC value.
   - **Best improvement:** Add a `log.warn` (or at minimum a code comment) at 
the fallback site noting which dialect/format triggered it, and add a 
`JdbcFieldTypeUtilsTest` case per newly-supported dialect (Teradata, Vertica) 
that exercises `getOffsetDateTime` with a `Timestamp` + a realistic 
driver-formatted string, mirroring the DB2 test already present.
   - **Severity:** Medium.
   
   **Issue 4: `incompatible-changes.md` not extended for this PR's 
newly-covered dialects**
   - **Location:** 
`docs/en/introduction/concepts/incompatible-changes.md:10-23` (existing entry, 
not touched by this PR)
   - **Problem description:** The existing "Breaking Change: Mapping of 
timezone-aware timestamp columns to `TIMESTAMP_TZ` type" entry has a dedicated 
"Connector-specific behavior changes" bullet list for every dialect a prior PR 
touched (Snowflake, StarRocks, Hudi, Xugu, CDC/TiDB, Iceberg). This PR follows 
the same underlying breaking-change pattern for DB2, Presto, Teradata, and 
Vertica, plus the generic `JdbcColumnConverter` fallback (which is broader than 
these four — see 1.2), but adds no bullets to this ledger, and doesn't touch 
this file at all.
   - **Potential risk:** A user auditing `incompatible-changes.md` before 
upgrading (which is the documented, expected workflow — "You need to check this 
document before you upgrade to related version") will not learn that their 
DB2/Presto/Teradata/Vertica `TIMESTAMP WITH TIME ZONE` columns, or any 
custom-dialect column reached via the `JdbcColumnConverter` fallback, now infer 
as `TIMESTAMP_TZ` instead of `TIMESTAMP`/failing outright.
   - **Best improvement:** Add bullets for DB2, Presto, Teradata, Vertica 
following the existing format, and explicitly call out the 
`JdbcColumnConverter` generic-fallback behavior change since it's not scoped to 
a named dialect.
   - **Severity:** Medium.
   
   **Issue 5: DB2 `toDBString` reflection re-resolved every row instead of 
cached**
   - **Location:** 
`seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/JdbcFieldTypeUtils.java:189`
   - **Problem description:** `Method toDBString = 
obj.getClass().getMethod("toDBString", boolean.class);` runs inside 
`getOffsetDateTime()`, called once per row per `TIMESTAMP_TZ` column via 
`AbstractJdbcRowConverter`.
   - **Potential risk:** Unnecessary reflective lookup overhead in the 
row-conversion hot path for high-volume DB2-for-z/OS batch extracts with TZ 
columns. Not a correctness issue.
   - **Best improvement:** Resolve the `Method` once (e.g., a 
lazily-initialized static field guarded by the class-name check) and reuse it 
across rows.
   - **Severity:** Low.
   
   **Issue 6: `PrestoDialect.supportsPrimaryKeyMetadata()` is unrelated to this 
PR's stated scope**
   - **Location:** 
`seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/presto/PrestoDialect.java:43-46`
   - **Problem description:** This flips the default `true` to `false`, meaning 
`CatalogUtils.getTableSchema(metadata, tablePath, dialect)` skips 
`DatabaseMetaData.getPrimaryKeys()` for Presto in `table_path=` mode. It's a 
real, independently-tested fix 
(`TimestampWithTimeZoneTypeMappingTest.testPrestoSkipsUnsupportedPrimaryKeyMetadata`)
 for a genuine gap — `CatalogUtils.getPrimaryKey` propagates any `SQLException` 
from an unsupported `getPrimaryKeys()` call uncaught — but it is not exercised 
by the PR's own e2e test (which uses `query=` mode, so this code path is 
untouched by any test with a live Presto container) and is unrelated to 
`TIMESTAMP_TZ` support.
   - **Potential risk:** Low risk of harm (turning the flag off only skips a 
call that would otherwise likely throw), but it's scope creep that makes the PR 
harder to review/bisect and isn't explained in the PR description.
   - **Best improvement:** Either split this into its own PR/commit with its 
own rationale, or add a sentence to the PR description explaining why it's 
bundled here.
   - **Severity:** Low.
   
   **Issue 7: Undocumented removal of `setAutoCommit(false)` in shared e2e test 
setup**
   - **Location:** 
`seatunnel-e2e/.../connector-jdbc-e2e-part-7/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcPrestoIT.java`
 (`initializeJdbcConnection`)
   - **Problem description:** `this.connection.setAutoCommit(false);` was 
removed with no comment. This affects every test method in the class (shared 
connection setup), not just the new TZ test, and there's no explanation of why 
the explicit transaction mode was dropped.
   - **Potential risk:** Low as-is (Presto's `memory` connector likely doesn't 
support explicit transactions well, so removing this is plausibly a correctness 
fix), but an unexplained behavior change to shared test infrastructure is a 
maintainability trap for the next person touching this file.
   - **Best improvement:** Add a one-line comment explaining why autocommit is 
now left at its default.
   - **Severity:** Low.
   
   # 2. Code Quality Assessment
   
   ## 2.1 Coding Standards
   - All new non-trivial fields/constants have explanatory comments 
(`DB2_TIMESTAMP_CLASS_NAME`, `DB2_TIMESTAMP_WITH_TIME_ZONE_PATTERN`, 
`TIMESTAMP_WITH_TIME_ZONE_TYPE_NAME`, the Presto/Teradata/Vertica constants) — 
good adherence to the "why, not what" standard.
   - `isTimestampWithTimeZone` and `normalizeDb2OffsetDateTimeString` are new 
non-trivial private methods without their own doc comments (single-line `//` 
comments exist at call sites but not on the methods themselves) — minor, 
non-blocking per the "boilerplate exempt" carve-out, but these aren't 
boilerplate; a short Javadoc on each would meet the bar more cleanly. Not 
raised as a numbered issue since the call-site comments already convey intent 
adequately.
   - Test file `TimestampWithTimeZoneTypeMappingTest.java` uses plain `/* ... 
*/` block comments (not Javadoc `/** */`) at class and method level — 
acceptable, not the prohibited single-line-`/** */` style.
   
   ## 2.2 Test Coverage and Test Stability
   - **DB2**: full coverage — type-mapping test 
(`Db2TypeConverterTest.testConvertTimestampWithTimeZone`) and value-round-trip 
test with a mocked real `DBTimestamp` (`JdbcFieldTypeUtilsTest`) that 
specifically asserts `getString()` is never invoked, proving the reflection 
path is actually taken. Strong.
   - **Presto**: type-mapping unit test + a genuine e2e test against a live 
Testcontainers Presto instance 
(`JdbcPrestoIT.testTimestampWithTimeZoneMappingAndValue`), asserting both the 
mapped type and the parsed value against a known-good literal. Strong.
   - **Teradata / Vertica**: only type-mapping unit tests using the bare 
(non-precision-qualified) `"TIMESTAMP WITH TIME ZONE"` / `"TIMESTAMPTZ"` 
strings — no e2e test (no Teradata/Vertica Testcontainers image is realistic to 
run in this repo's CI, understandably), and no `JdbcFieldTypeUtilsTest` 
value-round-trip test at all. Combined with Issue 1 and Issue 3, this means the 
two weakest-covered dialects are also the two with the least tolerant 
implementation.
   - No `Thread.sleep`, no unclosed resources, no order-dependent assertions, 
no floating-point-without-delta, and no non-deterministic assertions found in 
any of the added/modified tests. The e2e readiness signal 
(`given().ignoreExceptions().await()...untilAsserted(...)` polling a `CREATE 
TABLE IF NOT EXISTS _readiness_probe`) is pre-existing and unchanged.
   - **Rating: Risk present** — not because any added test is flaky, but 
because a real Teradata/Vertica regression in Issue 1 or Issue 3 would not be 
caught by this PR's own CI suite (path: `TeradataTypeMapper.java:95-96`, 
`VerticaTypeMapper.java:161-163`, no corresponding e2e or value-level unit 
test).
   
   ## 2.3 Documentation Updates
   - `docs/en/connectors/source/Jdbc.md` and the `zh` equivalent gained a clear 
"Timestamp with time zone" section listing exactly which native types map to 
`TIMESTAMP_TZ`, matching the code (Presto `timestamp(p) with time zone` — 
matches the precision-tolerant Presto fix; Teradata is listed without a `(p)` 
qualifier, consistent with `TeradataTypeMapper`'s exact-match implementation, 
so the doc is at least internally honest about the current code's limitation 
even though it doesn't call it out as a limitation).
   - `docs/en/connectors/sink/Jdbc.md` / `zh` correctly disclose that DB2 
auto-table-creation isn't supported for this type, consistent with 
`DB2TypeConverter.reconvert()` having no `OFFSET_DATE_TIME_TYPE` case.
   - Not updated: `incompatible-changes.md` — see Issue 4.
   
   # 3. Architectural Soundness
   
   ## 3.1 Elegance
   Mixed: DB2 and Presto are **Precise fixes** (root-caused to the actual 
driver quirk, with matching tests). Teradata/Vertica are **partial fixes** — 
they add the SeaTunnel-side type mapping but don't close the same 
driver-format-variance gap the PR closes for Presto in the identical commit, so 
they land closer to a **temporary workaround** for the common case than a fully 
robust fix.
   
   ## 3.2 Maintainability
   Reasonable — each dialect's type name constants and matching logic stay 
localized to its own `TypeMapper`/`TypeConverter` class, consistent with the 
existing per-dialect architecture (no leakage of dialect-specific logic into 
the engine or shared core, in line with this repo's connector guidelines). The 
one exception is `JdbcColumnConverter`'s new `isTimestampWithTimeZone` regex, 
which duplicates (with a superset pattern) the same "precision may be embedded" 
concept that `PrestoTypeMapper` now also implements independently and 
`TeradataTypeMapper`/`VerticaTypeMapper` don't implement at all — three 
different answers to the same problem in one PR is a maintainability smell 
worth converging (see Issue 1's suggested fix).
   
   ## 3.3 Extensibility
   Good — the pattern (add a `TIMESTAMP_WITH_TIME_ZONE` constant + switch case 
per dialect) is easy for the next contributor to replicate for any remaining 
dialect not yet covered.
   
   ## 3.4 Historical-Version Compatibility
   Already-running jobs that read a `TIMESTAMP WITH TIME ZONE`/`TIMESTAMPTZ` 
column through DB2, Presto (bare form), Teradata (bare form), or the 
`GenericTypeConverter` path were previously either broken (threw 
`UnsupportedOperationException`/`CommonError`) or, for the 
`JdbcColumnConverter` fallback specifically, silently returning `LocalDateTime` 
— see 1.2 for the full compatibility classification and Issue 4 for the 
documentation gap this leaves.
   
   # 4. Issue Summary
   
   | Number | Issue | Location | Severity |
   |---|---|---|---|
   | 2 | PR is not mergeable against `dev` (real content conflict in 
`JdbcPrestoIT.java`, caused by unrelated upstream E2E-infra refactor) | GitHub 
mergeability state / `JdbcPrestoIT.java` | High |
   | 1 | Teradata/Vertica `query=`-mode type matching doesn't tolerate 
precision-qualified `TIMESTAMP(n) WITH TIME ZONE`, unlike the Presto fix in the 
same PR | `TeradataTypeMapper.java:66-101`, `VerticaTypeMapper.java:100-180` | 
Medium |
   | 3 | Pre-existing silent UTC-mislabeling fallback newly reachable, and 
untested, for Teradata/Vertica | `JdbcFieldTypeUtils.java:201-212` | Medium |
   | 4 | `incompatible-changes.md` not extended for this PR's dialects / the 
generic fallback change | 
`docs/en/introduction/concepts/incompatible-changes.md` | Medium |
   | 5 | DB2 reflection `Method` lookup re-done every row instead of cached | 
`JdbcFieldTypeUtils.java:189` | Low |
   | 6 | `PrestoDialect.supportsPrimaryKeyMetadata()` is scope creep relative 
to the PR's stated purpose | `PrestoDialect.java:43-46` | Low |
   | 7 | Undocumented removal of `setAutoCommit(false)` in shared e2e test 
setup | `JdbcPrestoIT.java` (`initializeJdbcConnection`) | Low |
   
   # 5. Merge Recommendation
   
   ### Conclusion: Ready to merge after fixes
   
   1. **Blockers** (must be fixed):
      - Issue 2 (High) — sync with `dev` and resolve the `JdbcPrestoIT.java` 
conflict; this alone prevents merging today regardless of everything else.
      - Issue 1 (Medium) — either confirm (with real Teradata/Vertica driver 
testing, which I could not do here per this review's static-analysis-only 
scope) that the exact-match type name is actually correct for both drivers, or 
add the same precision-tolerant normalization Presto got in this PR.
      - Issue 3 (Medium) — at minimum, add value-round-trip tests for 
Teradata/Vertica proving the shared string-parsing fallback handles their 
actual `getString()` output; ideally also add a log line at the silent-fallback 
site.
   
   2. **Recommended fixes** (non-blocking):
      - Issue 4 — extend `incompatible-changes.md` to match the existing 
per-dialect bullet pattern.
      - Issue 5 — cache the DB2 reflection `Method` lookup.
      - Issue 6 — explain or split out the 
`PrestoDialect.supportsPrimaryKeyMetadata()` change.
      - Issue 7 — comment the `setAutoCommit` removal.
   
   **Overall assessment**: The core idea and the 
DB2/Presto/GenericTypeConverter implementations are solid, precisely scoped, 
and well-tested — the DB2 reflection-based offset recovery in particular is a 
careful piece of work with a test that proves the right code path is taken. The 
gap is consistency: the PR fixes a specific "precision embedded in the type 
name" driver quirk for Presto but leaves the identical class of quirk 
unaddressed for Teradata and Vertica, and doesn't add the value-level test 
coverage for those two dialects that would either prove it's a non-issue or 
catch the regression. Given this is genuinely difficult to fully validate 
without live Teradata/Vertica instances, **Option A** (land this PR as-is after 
fixing the merge conflict, and file a fast follow-up specifically for 
Teradata/Vertica precision-tolerance + value-round-trip tests) is a reasonable 
alternative to **Option B** (hold the whole PR until Teradata/Vertica reach 
parity with DB2/Presto) — but Opti
 on B is what I'd request before merge, since the inconsistency is demonstrable 
from the PR's own diff and test fixtures without needing a live driver, and the 
fix (reusing the existing `TIMESTAMP_WITH_TIME_ZONE_TYPE_NAME` regex or the 
Presto normalization pattern) is small.
   
   ---
   This is a technical self-review of my own PR (author = DanielLeens), posted 
as a plain issue comment rather than a GitHub Review because GitHub rejects 
review submissions on one's own PR (422). It does not satisfy the repository's 
human-approval gate; a write-capable maintainer still needs to complete that 
step. CI is currently green (`Build`, `Notify test workflow`, `labeler` all 
`pass` as of this check), so the only hard blocker right now is the `dev` merge 
conflict (Issue 2).
   


-- 
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