3030import org .apache .flink .cdc .common .event .TruncateTableEvent ;
3131import org .apache .flink .cdc .common .event .visitor .SchemaChangeEventVisitor ;
3232import org .apache .flink .cdc .common .exceptions .SchemaEvolveException ;
33+ import org .apache .flink .cdc .common .schema .Column ;
3334import org .apache .flink .cdc .common .schema .Schema ;
3435import org .apache .flink .cdc .common .sink .MetadataApplier ;
36+ import org .apache .flink .cdc .common .types .DataType ;
3537import org .apache .flink .cdc .connectors .paimon .sink .utils .TypeUtils ;
3638
3739import org .apache .flink .shaded .guava31 .com .google .common .collect .Sets ;
3840
41+ import org .apache .paimon .CoreOptions ;
3942import org .apache .paimon .catalog .Catalog ;
4043import org .apache .paimon .catalog .Identifier ;
4144import org .apache .paimon .flink .FlinkCatalogFactory ;
4245import org .apache .paimon .options .Options ;
4346import org .apache .paimon .schema .SchemaChange ;
47+ import org .apache .paimon .table .FileStoreTable ;
4448import org .apache .paimon .table .Table ;
4549import org .apache .paimon .table .sink .BatchTableCommit ;
50+ import org .apache .paimon .types .DataTypes ;
4651import org .slf4j .Logger ;
4752import org .slf4j .LoggerFactory ;
4853
5257import java .util .Map ;
5358import java .util .Set ;
5459
60+ import static org .apache .flink .cdc .common .types .DataTypeFamily .BINARY_STRING ;
61+ import static org .apache .flink .cdc .common .types .DataTypeFamily .CHARACTER_STRING ;
5562import static org .apache .flink .cdc .common .utils .Preconditions .checkArgument ;
5663import static org .apache .flink .cdc .common .utils .Preconditions .checkNotNull ;
5764
@@ -149,11 +156,11 @@ private void applyCreateTable(CreateTableEvent event) throws SchemaEvolveExcepti
149156 new org .apache .paimon .schema .Schema .Builder ();
150157 schema .getColumns ()
151158 .forEach (
152- (column ) ->
153- builder . column (
154- column . getName (),
155- TypeUtils . toPaimonDataType (column .getType ()),
156- column . getComment ()) );
159+ (column ) -> {
160+ org . apache . paimon . types . DataType dataType =
161+ convertToBlobIfNeeded ( column , tableOptions );
162+ builder . column (column .getName (), dataType , column . getComment ());
163+ } );
157164 List <String > partitionKeys = new ArrayList <>();
158165 List <String > primaryKeys = schema .primaryKeys ();
159166 if (partitionMaps .containsKey (event .tableId ())) {
@@ -205,10 +212,12 @@ private List<SchemaChange> applyAddColumnEventWithPosition(AddColumnEvent event)
205212 SchemaChangeProvider .add (
206213 columnWithPosition ,
207214 SchemaChange .Move .first (
208- columnWithPosition .getAddColumn ().getName ())));
215+ columnWithPosition .getAddColumn ().getName ()),
216+ tableOptions ));
209217 break ;
210218 case LAST :
211- tableChangeList .addAll (SchemaChangeProvider .add (columnWithPosition ));
219+ tableChangeList .addAll (
220+ SchemaChangeProvider .add (columnWithPosition , tableOptions ));
212221 break ;
213222 case BEFORE :
214223 tableChangeList .addAll (
@@ -225,7 +234,8 @@ private List<SchemaChange> applyAddColumnEventWithPosition(AddColumnEvent event)
225234 SchemaChange .Move .after (
226235 columnWithPosition .getAddColumn ().getName (),
227236 columnWithPosition .getExistedColumnName ());
228- tableChangeList .addAll (SchemaChangeProvider .add (columnWithPosition , after ));
237+ tableChangeList .addAll (
238+ SchemaChangeProvider .add (columnWithPosition , after , tableOptions ));
229239 break ;
230240 default :
231241 throw new SchemaEvolveException (
@@ -253,7 +263,8 @@ private List<SchemaChange> applyAddColumnWithBeforePosition(
253263 columnWithPosition ,
254264 (index == 0 )
255265 ? SchemaChange .Move .first (columnName )
256- : SchemaChange .Move .after (columnName , columnNames .get (index - 1 )));
266+ : SchemaChange .Move .after (columnName , columnNames .get (index - 1 )),
267+ tableOptions );
257268 }
258269
259270 private int checkColumnPosition (String existedColumnName , List <String > columnNames ) {
@@ -303,13 +314,22 @@ private void applyRenameColumn(RenameColumnEvent event) throws SchemaEvolveExcep
303314
304315 private void applyAlterColumnType (AlterColumnTypeEvent event ) throws SchemaEvolveException {
305316 try {
317+ FileStoreTable table =
318+ (FileStoreTable )
319+ catalog .getTable (
320+ new Identifier (
321+ event .tableId ().getSchemaName (),
322+ event .tableId ().getTableName ()));
306323 List <SchemaChange > tableChangeList = new ArrayList <>();
307324 event .getTypeMapping ()
308325 .forEach (
309- (oldName , newType ) ->
310- tableChangeList .add (
311- SchemaChangeProvider .updateColumnType (
312- oldName , newType )));
326+ (columnName , newType ) -> {
327+ // Modifying the primary key data type may lead to exceptions in
328+ // read/write/merge operations.
329+ SchemaChangeProvider .updateColumnType (
330+ table .schema (), columnName , newType , tableOptions )
331+ .ifPresent (tableChangeList ::add );
332+ });
313333 event .getComments ()
314334 .forEach (
315335 (name , comment ) -> {
@@ -359,4 +379,33 @@ private void applyAlterTableComment(AlterTableCommentEvent event) throws SchemaE
359379 private static Identifier tableIdToIdentifier (SchemaChangeEvent event ) {
360380 return new Identifier (event .tableId ().getSchemaName (), event .tableId ().getTableName ());
361381 }
382+
383+ /**
384+ * Convert CDC VARBINARY/BINARY/CHAR/VARCHAR/STRING type to Paimon BLOB type if configured.
385+ *
386+ * @param column The CDC column definition.
387+ * @param tableOptions The table options containing blob-field configuration.
388+ * @return The Paimon DataType (BLOB if configured, otherwise original converted type).
389+ */
390+ private org .apache .paimon .types .DataType convertToBlobIfNeeded (
391+ Column column , Map <String , String > tableOptions ) {
392+ org .apache .paimon .types .DataType dataType = TypeUtils .toPaimonDataType (column .getType ());
393+
394+ // Check if this field should be converted to BLOB type using Paimon's CoreOptions
395+ List <String > blobFields = CoreOptions .blobField (tableOptions );
396+ if (!blobFields .isEmpty () && isSupportedTypeForBlob (column .getType ())) {
397+ if (blobFields .contains (column .getName ())) {
398+ // Convert VARBINARY/BINARY/VARCHAR/STRING to BLOB type
399+ // BLOB type is always nullable in Paimon
400+ return DataTypes .BLOB ();
401+ }
402+ }
403+
404+ return dataType ;
405+ }
406+
407+ /** Check if DataType can be converted to BLOB (BINARY, VARBINARY, CHAR or VARCHAR). */
408+ private boolean isSupportedTypeForBlob (DataType dataType ) {
409+ return dataType .isAnyOf (BINARY_STRING , CHARACTER_STRING );
410+ }
362411}
0 commit comments