nzw921rx opened a new issue, #10942: URL: https://github.com/apache/seatunnel/issues/10942
### Search before asking - [x] I had searched in the [feature](https://github.com/apache/seatunnel/issues?q=is%3Aissue+label%3A%22Feature%22) and found no similar feature requirement. ### Description ## Background When the same upstream `Record<SeaTunnelRow>` is fanned out into sibling transform branches via `SeaTunnelTransformCollector`, each branch receives the same object reference. If any transform mutates the input row directly (e.g. calling `setField()`, `setTableId()`, `setRowKind()`), sibling branches observe corrupted data. ``` Upstream row → SeaTunnelTransformCollector.collect(record) → output1.received(record) ← same record reference → output2.received(record) ← same record reference ``` ## Current Status This bug has already appeared independently in multiple transforms: | Transform | Status | Detail | |---|---|---| | `ReplaceTransform` | Being fixed by #10941 | Directly calls `inputRow.setField()` | | `TableMergeTransform` | **Still broken** | Directly calls `inputRow.setTableId()` | | `RowKindExtractorTransform` | **Still broken** | Directly calls `inputRow.setRowKind()` | | `FieldEncryptTransform` | Self-fixed | Uses `inputRow.copy()` internally | | `TableRenameTransform` | Self-fixed | Uses `inputRow.copy()` internally | The root cause is that the framework passes a mutable `SeaTunnelRow` to transforms. Each transform developer must independently remember to copy before mutating — an implicit contract that has been repeatedly violated. ## Proposal Change the two transform entry points (`map()` and `flatMap()`) to wrap `SeaTunnelRow` as a read-only `SeaTunnelRowAccessor` before passing it to subclasses. `SeaTunnelRowAccessor` already exists in the codebase and only exposes read methods (`getField()`, `getRowKind()`, etc.) with no setters. ```java // SeaTunnelMapTransform public SeaTunnelRow map(SeaTunnelRow row) { return transformRow(new SeaTunnelRowAccessor(row)); } // SeaTunnelFlatMapTransform public List<SeaTunnelRow> flatMap(SeaTunnelRow row) { return transformRow(new SeaTunnelRowAccessor(row)); } ``` Subclass signature would change from: ```java protected SeaTunnelRow transformRow(SeaTunnelRow inputRow) ``` to: ```java protected SeaTunnelRow transformRow(SeaTunnelRowAccessor inputRow) ``` ## Expected Benefits - **Compile-time enforcement**: transforms receive a read-only object; creating a new `SeaTunnelRow` is required for any modification - **No framework-level copy needed**: mutation is prevented at the API level, zero additional overhead - **All existing and future transforms are automatically protected**: developers don't need to know about fan-out behavior - **Read-only transforms work naturally**: filter, validate, identity transforms use the accessor directly ## Migration 1. Add new method signature `transformRow(SeaTunnelRowAccessor)` 2. Base class `map()` / `flatMap()` wraps input as accessor and calls the new signature 3. Mark old signature `transformRow(SeaTunnelRow)` as `@Deprecated` 4. Migrate existing transforms incrementally Many transforms already use `SeaTunnelRowAccessor` internally via `SingleFieldOutputTransform` / `MultipleFieldOutputTransform` base classes. The remaining transforms that need adaptation are small in number. ## Questions for Discussion 1. Is the `SeaTunnelRowAccessor` approach the right direction, or should we consider framework-level copy instead? 2. Should we deprecate the old signature gradually, or make a breaking change in the next major version? 3. Are there any transforms or use cases where receiving a mutable input is intentionally required? ## Related - #10941 ### Usage Scenario _No response_ ### Related issues _No response_ ### Are you willing to submit a PR? - [x] Yes I am willing to submit a PR! ### Code of Conduct - [x] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) -- 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]
