|
19 | 19 |
|
20 | 20 | import org.apache.flink.cdc.common.configuration.Configuration; |
21 | 21 | import org.apache.flink.cdc.common.data.DecimalData; |
| 22 | +import org.apache.flink.cdc.common.data.GenericArrayData; |
| 23 | +import org.apache.flink.cdc.common.data.GenericMapData; |
| 24 | +import org.apache.flink.cdc.common.data.GenericRecordData; |
22 | 25 | import org.apache.flink.cdc.common.data.LocalZonedTimestampData; |
23 | 26 | import org.apache.flink.cdc.common.data.TimestampData; |
24 | 27 | import org.apache.flink.cdc.common.data.ZonedTimestampData; |
@@ -886,6 +889,125 @@ void testMergingWithRouteInBatchMode(ValuesDataSink.SinkApi sinkApi) throws Exce |
886 | 889 | "DataChangeEvent{tableId=default_namespace.default_schema.merged, before=[], after=[4, Donald, 25, student], op=INSERT, meta=()}"); |
887 | 890 | } |
888 | 891 |
|
| 892 | + @ParameterizedTest |
| 893 | + @EnumSource |
| 894 | + void testMergingComplexTypesWithRouteInBatchMode(ValuesDataSink.SinkApi sinkApi) |
| 895 | + throws Exception { |
| 896 | + FlinkPipelineComposer composer = FlinkPipelineComposer.ofMiniCluster(); |
| 897 | + |
| 898 | + // Setup value source |
| 899 | + Configuration sourceConfig = new Configuration(); |
| 900 | + sourceConfig.set( |
| 901 | + ValuesDataSourceOptions.EVENT_SET_ID, |
| 902 | + ValuesDataSourceHelper.EventSetId.CUSTOM_SOURCE_EVENTS); |
| 903 | + sourceConfig.set(ValuesDataSourceOptions.BATCH_MODE_ENABLED, true); |
| 904 | + |
| 905 | + TableId myTable1 = TableId.tableId("default_namespace", "default_schema", "mytable1"); |
| 906 | + TableId myTable2 = TableId.tableId("default_namespace", "default_schema", "mytable2"); |
| 907 | + |
| 908 | + // Table 1 has complex types: ARRAY, MAP, ROW |
| 909 | + Schema table1Schema = |
| 910 | + Schema.newBuilder() |
| 911 | + .physicalColumn("id", DataTypes.INT()) |
| 912 | + .physicalColumn("arr", DataTypes.ARRAY(DataTypes.INT())) |
| 913 | + .physicalColumn("mp", DataTypes.MAP(DataTypes.STRING(), DataTypes.INT())) |
| 914 | + .physicalColumn("rw", DataTypes.ROW(DataTypes.INT(), DataTypes.STRING())) |
| 915 | + .primaryKey("id") |
| 916 | + .build(); |
| 917 | + |
| 918 | + // Table 2 has STRING columns at the same positions, forcing coercion |
| 919 | + Schema table2Schema = |
| 920 | + Schema.newBuilder() |
| 921 | + .physicalColumn("id", DataTypes.INT()) |
| 922 | + .physicalColumn("arr", DataTypes.STRING()) |
| 923 | + .physicalColumn("mp", DataTypes.STRING()) |
| 924 | + .physicalColumn("rw", DataTypes.STRING()) |
| 925 | + .primaryKey("id") |
| 926 | + .build(); |
| 927 | + |
| 928 | + BinaryRecordDataGenerator table1dataGenerator = |
| 929 | + new BinaryRecordDataGenerator( |
| 930 | + table1Schema.getColumnDataTypes().toArray(new DataType[0])); |
| 931 | + BinaryRecordDataGenerator table2dataGenerator = |
| 932 | + new BinaryRecordDataGenerator( |
| 933 | + table2Schema.getColumnDataTypes().toArray(new DataType[0])); |
| 934 | + |
| 935 | + List<Event> events = new ArrayList<>(); |
| 936 | + events.add(new CreateTableEvent(myTable1, table1Schema)); |
| 937 | + events.add(new CreateTableEvent(myTable2, table2Schema)); |
| 938 | + |
| 939 | + // Table 1: insert with complex typed data |
| 940 | + events.add( |
| 941 | + DataChangeEvent.insertEvent( |
| 942 | + myTable1, |
| 943 | + table1dataGenerator.generate( |
| 944 | + new Object[] { |
| 945 | + 1, |
| 946 | + new GenericArrayData(new int[] {10, 20, 30}), |
| 947 | + new GenericMapData( |
| 948 | + Collections.singletonMap( |
| 949 | + BinaryStringData.fromString("key"), 42)), |
| 950 | + GenericRecordData.of(7, BinaryStringData.fromString("hello")) |
| 951 | + }))); |
| 952 | + |
| 953 | + // Table 2: insert with plain strings |
| 954 | + events.add( |
| 955 | + DataChangeEvent.insertEvent( |
| 956 | + myTable2, |
| 957 | + table2dataGenerator.generate( |
| 958 | + new Object[] { |
| 959 | + 2, |
| 960 | + BinaryStringData.fromString("plain_arr"), |
| 961 | + BinaryStringData.fromString("plain_mp"), |
| 962 | + BinaryStringData.fromString("plain_rw") |
| 963 | + }))); |
| 964 | + |
| 965 | + ValuesDataSourceHelper.setSourceEvents(Collections.singletonList(events)); |
| 966 | + |
| 967 | + SourceDef sourceDef = |
| 968 | + new SourceDef(ValuesDataFactory.IDENTIFIER, "Value Source", sourceConfig); |
| 969 | + |
| 970 | + // Setup value sink |
| 971 | + Configuration sinkConfig = new Configuration(); |
| 972 | + sinkConfig.set(ValuesDataSinkOptions.MATERIALIZED_IN_MEMORY, true); |
| 973 | + sinkConfig.set(ValuesDataSinkOptions.SINK_API, sinkApi); |
| 974 | + SinkDef sinkDef = new SinkDef(ValuesDataFactory.IDENTIFIER, "Value Sink", sinkConfig); |
| 975 | + |
| 976 | + // Setup route |
| 977 | + TableId mergedTable = TableId.tableId("default_namespace", "default_schema", "merged"); |
| 978 | + List<RouteDef> routeDef = |
| 979 | + Collections.singletonList( |
| 980 | + new RouteDef( |
| 981 | + "default_namespace.default_schema.mytable[0-9]", |
| 982 | + mergedTable.toString(), |
| 983 | + null, |
| 984 | + null)); |
| 985 | + |
| 986 | + // Setup pipeline |
| 987 | + Configuration pipelineConfig = new Configuration(); |
| 988 | + pipelineConfig.set(PipelineOptions.PIPELINE_PARALLELISM, 1); |
| 989 | + pipelineConfig.set( |
| 990 | + PipelineOptions.PIPELINE_EXECUTION_RUNTIME_MODE, RuntimeExecutionMode.BATCH); |
| 991 | + PipelineDef pipelineDef = |
| 992 | + new PipelineDef( |
| 993 | + sourceDef, |
| 994 | + sinkDef, |
| 995 | + routeDef, |
| 996 | + Collections.emptyList(), |
| 997 | + Collections.emptyList(), |
| 998 | + pipelineConfig); |
| 999 | + |
| 1000 | + // Execute the pipeline |
| 1001 | + PipelineExecution execution = composer.compose(pipelineDef); |
| 1002 | + execution.execute(); |
| 1003 | + String[] outputEvents = outCaptor.toString().trim().split("\n"); |
| 1004 | + assertThat(outputEvents) |
| 1005 | + .containsExactly( |
| 1006 | + "CreateTableEvent{tableId=default_namespace.default_schema.merged, schema=columns={`id` INT,`arr` STRING,`mp` STRING,`rw` STRING}, primaryKeys=id, options=()}", |
| 1007 | + "DataChangeEvent{tableId=default_namespace.default_schema.merged, before=[], after=[1, [10, 20, 30], {key=42}, [7, hello]], op=INSERT, meta=()}", |
| 1008 | + "DataChangeEvent{tableId=default_namespace.default_schema.merged, before=[], after=[2, plain_arr, plain_mp, plain_rw], op=INSERT, meta=()}"); |
| 1009 | + } |
| 1010 | + |
889 | 1011 | @ParameterizedTest |
890 | 1012 | @EnumSource |
891 | 1013 | void testTransformMergingWithRoute(ValuesDataSink.SinkApi sinkApi) throws Exception { |
|
0 commit comments