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]

Reply via email to