Description
Background
Follows up on the design note in apache/gluten#12164 (Gluten Flink Pending tasks), where retraction semantics is called out as a pending gap:
retraction semantics — this feature is required for group aggregate and join, which has not been implemented, maybe we should introduce the rowkind just as defined in flink, combine it with row vector.
Flink RowData carries a RowKind enum (+I / -U / +U / -D) that distinguishes changelog records — insert / update-before / update-after / delete. Gluten-Flink hands RowData to the velox C++ engine via the RowData → RowVector conversion path, but RowKind is dropped during that conversion today. As a result, the velox side sees every row as +I regardless of the original changelog marker.
Problem
- Sink operators (
PrintSinkFactory, FileSystemSinkFactory, etc.) can't emit correct -U / +U / -D prefixes for upsert / delete streams — outputs are uniformly +I[...].
- Retract aggregations, temporal joins, and other row-kind-aware operators lose the row-kind signal once data crosses into velox.
- Nexmark / E2E tests over upsert streams produce incorrect changelog output.
Proposal
Encode RowKind as a synthetic column that flows through the entire plan and is interpreted at three layers: the Java ↔ C++ boundary, the velox stateful operators that must act on changelog semantics, and the sink layer that emits the changelog prefix.
- Type:
TINYINT (Flink's RowKind enum ordinal: 0=INSERT, 1=UPDATE_BEFORE, 2=UPDATE_AFTER, 3=DELETE).
- Column name: reserved placeholder, invisible to user SQL(
$row_kind).
- Position: trailing column appended by the conversion layer.
The Row-kind-aware operators in velox (retract aggregation, temporal/regular join, top-N, deduplication, etc.) must read it to apply insert / update-before / update-after / delete semantics to their state. Stateful operators that ignore the column would either treat -U / -D as +I (incorrect accumulation) or drop them silently — both wrong.
Preserve the RowKind signal end-to-end across the gluten-flink three-layer architecture (Java / JNI / velox C++), and render the correct +I / -U / +U / -D prefix at the sink layer, establishing the data-carrier foundation for subsequent retract semantics
Design principles: do not pollute velox core data structures, do not pollute the Flink planner, zero intrusion on the Java side.
Task
Gluten version
main branch
Description
Background
Follows up on the design note in apache/gluten#12164 (Gluten Flink Pending tasks), where retraction semantics is called out as a pending gap:
Flink
RowDatacarries aRowKindenum (+I/-U/+U/-D) that distinguishes changelog records — insert / update-before / update-after / delete. Gluten-Flink hands RowData to the velox C++ engine via the RowData → RowVector conversion path, butRowKindis dropped during that conversion today. As a result, the velox side sees every row as+Iregardless of the original changelog marker.Problem
PrintSinkFactory,FileSystemSinkFactory, etc.) can't emit correct-U/+U/-Dprefixes for upsert / delete streams — outputs are uniformly+I[...].Proposal
Encode
RowKindas a synthetic column that flows through the entire plan and is interpreted at three layers: the Java ↔ C++ boundary, the velox stateful operators that must act on changelog semantics, and the sink layer that emits the changelog prefix.TINYINT(Flink'sRowKindenum ordinal: 0=INSERT, 1=UPDATE_BEFORE, 2=UPDATE_AFTER, 3=DELETE).$row_kind).The Row-kind-aware operators in velox (retract aggregation, temporal/regular join, top-N, deduplication, etc.) must read it to apply insert / update-before / update-after / delete semantics to their state. Stateful operators that ignore the column would either treat
-U/-Das+I(incorrect accumulation) or drop them silently — both wrong.Preserve the RowKind signal end-to-end across the gluten-flink three-layer architecture (Java / JNI / velox C++), and render the correct
+I/-U/+U/-Dprefix at the sink layer, establishing the data-carrier foundation for subsequent retract semanticsDesign principles: do not pollute velox core data structures, do not pollute the Flink planner, zero intrusion on the Java side.
Task
ChangelogRowVectordata structure (value + rowKind + appendOnly) + C++ UT$row_kindcolumn; Output boundary: merged RowVector to RowData conversion restores RowKind from the trailing columnGluten version
main branch