|
19 | 19 | package org.apache.flink.table.planner.plan.nodes.exec.stream; |
20 | 20 |
|
21 | 21 | import org.apache.flink.table.api.ValidationException; |
| 22 | +import org.apache.flink.table.connector.ChangelogMode; |
22 | 23 | import org.apache.flink.table.test.program.SinkTestStep; |
23 | 24 | import org.apache.flink.table.test.program.SourceTestStep; |
24 | 25 | import org.apache.flink.table.test.program.TableTestProgram; |
@@ -133,6 +134,35 @@ public class FromChangelogTestPrograms { |
133 | 134 | + "input => TABLE cdc_stream PARTITION BY id)") |
134 | 135 | .build(); |
135 | 136 |
|
| 137 | + /** Custom op column name via DESCRIPTOR. */ |
| 138 | + public static final TableTestProgram CUSTOM_OP_NAME = |
| 139 | + TableTestProgram.of( |
| 140 | + "from-changelog-custom-op-name", "custom op column name via DESCRIPTOR") |
| 141 | + .setupTableSource( |
| 142 | + SourceTestStep.newBuilder("cdc_stream") |
| 143 | + .addSchema("id INT", "operation STRING", "name STRING") |
| 144 | + .producedValues( |
| 145 | + Row.of(1, "INSERT", "Alice"), |
| 146 | + Row.of(1, "UPDATE_BEFORE", "Alice"), |
| 147 | + Row.of(1, "UPDATE_AFTER", "Alice2")) |
| 148 | + .build()) |
| 149 | + .setupTableSink( |
| 150 | + SinkTestStep.newBuilder("sink") |
| 151 | + .addSchema( |
| 152 | + "id INT NOT NULL", |
| 153 | + "name STRING", |
| 154 | + "PRIMARY KEY (id) NOT ENFORCED") |
| 155 | + .consumedValues( |
| 156 | + Row.ofKind(RowKind.INSERT, 1, "Alice"), |
| 157 | + Row.ofKind(RowKind.UPDATE_BEFORE, 1, "Alice"), |
| 158 | + Row.ofKind(RowKind.UPDATE_AFTER, 1, "Alice2")) |
| 159 | + .build()) |
| 160 | + .runSql( |
| 161 | + "INSERT INTO sink SELECT * FROM FROM_CHANGELOG(" |
| 162 | + + "input => TABLE cdc_stream PARTITION BY id, " |
| 163 | + + "op => DESCRIPTOR(operation))") |
| 164 | + .build(); |
| 165 | + |
136 | 166 | // -------------------------------------------------------------------------------------------- |
137 | 167 | // Table API test |
138 | 168 | // -------------------------------------------------------------------------------------------- |
@@ -163,6 +193,53 @@ public class FromChangelogTestPrograms { |
163 | 193 | "sink") |
164 | 194 | .build(); |
165 | 195 |
|
| 196 | + // -------------------------------------------------------------------------------------------- |
| 197 | + // Round-trip test: FROM_CHANGELOG(TO_CHANGELOG(table)) |
| 198 | + // -------------------------------------------------------------------------------------------- |
| 199 | + |
| 200 | + /** |
| 201 | + * Verifies that FROM_CHANGELOG(TO_CHANGELOG(table)) recovers the original dynamic table. |
| 202 | + * Requires TO_CHANGELOG with row semantics (PR #27911). |
| 203 | + */ |
| 204 | + public static final TableTestProgram ROUND_TRIP = |
| 205 | + TableTestProgram.of( |
| 206 | + "from-changelog-round-trip", |
| 207 | + "FROM_CHANGELOG(TO_CHANGELOG(table)) recovers original table") |
| 208 | + .setupTableSource( |
| 209 | + SourceTestStep.newBuilder("orders") |
| 210 | + .addSchema( |
| 211 | + "id INT NOT NULL", |
| 212 | + "name STRING", |
| 213 | + "PRIMARY KEY (id) NOT ENFORCED") |
| 214 | + .addMode(ChangelogMode.all()) |
| 215 | + .producedValues( |
| 216 | + Row.ofKind(RowKind.INSERT, 1, "Alice"), |
| 217 | + Row.ofKind(RowKind.INSERT, 2, "Bob"), |
| 218 | + Row.ofKind(RowKind.UPDATE_BEFORE, 1, "Alice"), |
| 219 | + Row.ofKind(RowKind.UPDATE_AFTER, 1, "Alice2"), |
| 220 | + Row.ofKind(RowKind.DELETE, 2, "Bob")) |
| 221 | + .build()) |
| 222 | + .setupTableSink( |
| 223 | + SinkTestStep.newBuilder("sink") |
| 224 | + .addSchema( |
| 225 | + "id INT NOT NULL", |
| 226 | + "name STRING", |
| 227 | + "PRIMARY KEY (id) NOT ENFORCED") |
| 228 | + .consumedValues( |
| 229 | + Row.ofKind(RowKind.INSERT, 1, "Alice"), |
| 230 | + Row.ofKind(RowKind.INSERT, 2, "Bob"), |
| 231 | + Row.ofKind(RowKind.UPDATE_BEFORE, 1, "Alice"), |
| 232 | + Row.ofKind(RowKind.UPDATE_AFTER, 1, "Alice2"), |
| 233 | + Row.ofKind(RowKind.DELETE, 2, "Bob")) |
| 234 | + .build()) |
| 235 | + .setupSql( |
| 236 | + "CREATE VIEW changelog_view AS " |
| 237 | + + "SELECT * FROM TO_CHANGELOG(input => TABLE orders)") |
| 238 | + .runSql( |
| 239 | + "INSERT INTO sink SELECT * FROM FROM_CHANGELOG(" |
| 240 | + + "input => TABLE changelog_view PARTITION BY id)") |
| 241 | + .build(); |
| 242 | + |
166 | 243 | // -------------------------------------------------------------------------------------------- |
167 | 244 | // Error validation tests |
168 | 245 | // -------------------------------------------------------------------------------------------- |
|
0 commit comments