|  | 
| 17 | 17 | 
 | 
| 18 | 18 | package org.apache.flink.cdc.connectors.paimon.sink.v2; | 
| 19 | 19 | 
 | 
|  | 20 | +import org.apache.flink.cdc.common.data.ArrayData; | 
| 20 | 21 | import org.apache.flink.cdc.common.data.DecimalData; | 
|  | 22 | +import org.apache.flink.cdc.common.data.MapData; | 
| 21 | 23 | import org.apache.flink.cdc.common.data.RecordData; | 
|  | 24 | +import org.apache.flink.cdc.common.data.binary.BinaryArrayData; | 
|  | 25 | +import org.apache.flink.cdc.common.data.binary.BinaryMapData; | 
|  | 26 | +import org.apache.flink.cdc.common.data.binary.BinaryRecordData; | 
| 22 | 27 | import org.apache.flink.cdc.common.event.DataChangeEvent; | 
| 23 | 28 | import org.apache.flink.cdc.common.schema.Column; | 
| 24 | 29 | import org.apache.flink.cdc.common.schema.Schema; | 
| 25 | 30 | import org.apache.flink.cdc.common.types.DataType; | 
| 26 | 31 | import org.apache.flink.cdc.common.types.DataTypeChecks; | 
|  | 32 | +import org.apache.flink.cdc.common.types.DataTypeRoot; | 
|  | 33 | +import org.apache.flink.core.memory.MemorySegment; | 
| 27 | 34 | 
 | 
|  | 35 | +import org.apache.paimon.data.BinaryRow; | 
| 28 | 36 | import org.apache.paimon.data.BinaryString; | 
| 29 | 37 | import org.apache.paimon.data.Decimal; | 
| 30 | 38 | import org.apache.paimon.data.GenericRow; | 
|  | 39 | +import org.apache.paimon.data.InternalRow; | 
| 31 | 40 | import org.apache.paimon.data.Timestamp; | 
|  | 41 | +import org.apache.paimon.memory.MemorySegmentUtils; | 
| 32 | 42 | import org.apache.paimon.types.RowKind; | 
| 33 | 43 | 
 | 
|  | 44 | +import java.nio.ByteBuffer; | 
| 34 | 45 | import java.time.ZoneId; | 
| 35 | 46 | import java.util.ArrayList; | 
| 36 | 47 | import java.util.List; | 
| @@ -118,7 +129,11 @@ private static RecordData.FieldGetter createFieldGetter( | 
| 118 | 129 |                 break; | 
| 119 | 130 |             case ROW: | 
| 120 | 131 |                 final int rowFieldCount = getFieldCount(fieldType); | 
| 121 |  | -                fieldGetter = row -> row.getRow(fieldPos, rowFieldCount); | 
|  | 132 | +                fieldGetter = new BinaryFieldDataGetter(fieldPos, DataTypeRoot.ROW, rowFieldCount); | 
|  | 133 | +                break; | 
|  | 134 | +            case ARRAY: | 
|  | 135 | +            case MAP: | 
|  | 136 | +                fieldGetter = new BinaryFieldDataGetter(fieldPos, fieldType.getTypeRoot()); | 
| 122 | 137 |                 break; | 
| 123 | 138 |             default: | 
| 124 | 139 |                 throw new IllegalArgumentException( | 
| @@ -163,4 +178,121 @@ public static GenericRow convertEventToGenericRow( | 
| 163 | 178 |         } | 
| 164 | 179 |         return genericRow; | 
| 165 | 180 |     } | 
|  | 181 | + | 
|  | 182 | +    /** A helper class for {@link PaimonWriter} to create FieldGetter and GenericRow. */ | 
|  | 183 | +    public static class BinaryFieldDataGetter implements RecordData.FieldGetter { | 
|  | 184 | +        private final int fieldPos; | 
|  | 185 | +        private final DataTypeRoot dataTypeRoot; | 
|  | 186 | +        private final int rowFieldCount; | 
|  | 187 | + | 
|  | 188 | +        BinaryFieldDataGetter(int fieldPos, DataTypeRoot dataTypeRoot) { | 
|  | 189 | +            this(fieldPos, dataTypeRoot, -1); | 
|  | 190 | +        } | 
|  | 191 | + | 
|  | 192 | +        BinaryFieldDataGetter(int fieldPos, DataTypeRoot dataTypeRoot, int rowFieldCount) { | 
|  | 193 | +            this.fieldPos = fieldPos; | 
|  | 194 | +            this.dataTypeRoot = dataTypeRoot; | 
|  | 195 | +            this.rowFieldCount = rowFieldCount; | 
|  | 196 | +        } | 
|  | 197 | + | 
|  | 198 | +        @Override | 
|  | 199 | +        public Object getFieldOrNull(RecordData row) { | 
|  | 200 | +            switch (dataTypeRoot) { | 
|  | 201 | +                case ARRAY: | 
|  | 202 | +                    return getArrayField(row); | 
|  | 203 | +                case MAP: | 
|  | 204 | +                    return getMapField(row); | 
|  | 205 | +                case ROW: | 
|  | 206 | +                    return getRecordField(row); | 
|  | 207 | +                default: | 
|  | 208 | +                    throw new IllegalArgumentException("Unsupported field type: " + dataTypeRoot); | 
|  | 209 | +            } | 
|  | 210 | +        } | 
|  | 211 | + | 
|  | 212 | +        private Object getArrayField(RecordData row) { | 
|  | 213 | +            ArrayData arrayData = row.getArray(fieldPos); | 
|  | 214 | +            if (!(arrayData instanceof BinaryArrayData)) { | 
|  | 215 | +                throw new IllegalArgumentException( | 
|  | 216 | +                        "Expected BinaryArrayData but was " + arrayData.getClass().getSimpleName()); | 
|  | 217 | +            } | 
|  | 218 | +            BinaryArrayData binaryArrayData = (BinaryArrayData) arrayData; | 
|  | 219 | +            return convertSegments( | 
|  | 220 | +                    binaryArrayData.getSegments(), | 
|  | 221 | +                    binaryArrayData.getOffset(), | 
|  | 222 | +                    binaryArrayData.getSizeInBytes(), | 
|  | 223 | +                    MemorySegmentUtils::readArrayData); | 
|  | 224 | +        } | 
|  | 225 | + | 
|  | 226 | +        private Object getMapField(RecordData row) { | 
|  | 227 | +            MapData mapData = row.getMap(fieldPos); | 
|  | 228 | +            if (!(mapData instanceof BinaryMapData)) { | 
|  | 229 | +                throw new IllegalArgumentException( | 
|  | 230 | +                        "Expected BinaryMapData but was " + mapData.getClass().getSimpleName()); | 
|  | 231 | +            } | 
|  | 232 | +            BinaryMapData binaryMapData = (BinaryMapData) mapData; | 
|  | 233 | +            return convertSegments( | 
|  | 234 | +                    binaryMapData.getSegments(), | 
|  | 235 | +                    binaryMapData.getOffset(), | 
|  | 236 | +                    binaryMapData.getSizeInBytes(), | 
|  | 237 | +                    MemorySegmentUtils::readMapData); | 
|  | 238 | +        } | 
|  | 239 | + | 
|  | 240 | +        private Object getRecordField(RecordData row) { | 
|  | 241 | +            RecordData recordData = row.getRow(fieldPos, rowFieldCount); | 
|  | 242 | +            if (!(recordData instanceof BinaryRecordData)) { | 
|  | 243 | +                throw new IllegalArgumentException( | 
|  | 244 | +                        "Expected BinaryRecordData but was " | 
|  | 245 | +                                + recordData.getClass().getSimpleName()); | 
|  | 246 | +            } | 
|  | 247 | +            BinaryRecordData binaryRecordData = (BinaryRecordData) recordData; | 
|  | 248 | +            return convertSegments( | 
|  | 249 | +                    binaryRecordData.getSegments(), | 
|  | 250 | +                    binaryRecordData.getOffset(), | 
|  | 251 | +                    binaryRecordData.getSizeInBytes(), | 
|  | 252 | +                    (segments, offset, sizeInBytes) -> | 
|  | 253 | +                            MemorySegmentUtils.readRowData( | 
|  | 254 | +                                    segments, rowFieldCount, offset, sizeInBytes)); | 
|  | 255 | +        } | 
|  | 256 | + | 
|  | 257 | +        private <T> T convertSegments( | 
|  | 258 | +                MemorySegment[] segments, | 
|  | 259 | +                int offset, | 
|  | 260 | +                int sizeInBytes, | 
|  | 261 | +                SegmentConverter<T> converter) { | 
|  | 262 | +            org.apache.paimon.memory.MemorySegment[] paimonMemorySegments = | 
|  | 263 | +                    new org.apache.paimon.memory.MemorySegment[segments.length]; | 
|  | 264 | +            for (int i = 0; i < segments.length; i++) { | 
|  | 265 | +                MemorySegment currMemorySegment = segments[i]; | 
|  | 266 | +                ByteBuffer byteBuffer = currMemorySegment.wrap(0, currMemorySegment.size()); | 
|  | 267 | + | 
|  | 268 | +                // Allocate a new byte array and copy the data from the ByteBuffer | 
|  | 269 | +                byte[] bytes = new byte[currMemorySegment.size()]; | 
|  | 270 | +                byteBuffer.get(bytes); | 
|  | 271 | + | 
|  | 272 | +                paimonMemorySegments[i] = org.apache.paimon.memory.MemorySegment.wrap(bytes); | 
|  | 273 | +            } | 
|  | 274 | +            return converter.convert(paimonMemorySegments, offset, sizeInBytes); | 
|  | 275 | +        } | 
|  | 276 | + | 
|  | 277 | +        private interface SegmentConverter<T> { | 
|  | 278 | +            T convert( | 
|  | 279 | +                    org.apache.paimon.memory.MemorySegment[] segments, int offset, int sizeInBytes); | 
|  | 280 | +        } | 
|  | 281 | + | 
|  | 282 | +        /** | 
|  | 283 | +         * Gets an instance of {@link InternalRow} from underlying {@link | 
|  | 284 | +         * org.apache.paimon.memory.MemorySegment}. | 
|  | 285 | +         */ | 
|  | 286 | +        public InternalRow readRowData( | 
|  | 287 | +                org.apache.paimon.memory.MemorySegment[] segments, | 
|  | 288 | +                int numFields, | 
|  | 289 | +                int baseOffset, | 
|  | 290 | +                long offsetAndSize) { | 
|  | 291 | +            final int size = ((int) offsetAndSize); | 
|  | 292 | +            int offset = (int) (offsetAndSize >> 32); | 
|  | 293 | +            BinaryRow row = new BinaryRow(numFields); | 
|  | 294 | +            row.pointTo(segments, offset + baseOffset, size); | 
|  | 295 | +            return row; | 
|  | 296 | +        } | 
|  | 297 | +    } | 
| 166 | 298 | } | 
0 commit comments