1717
1818package org .apache .flink .cdc .connectors .fluss .sink ;
1919
20+ import org .apache .flink .cdc .common .event .AddColumnEvent ;
2021import org .apache .flink .cdc .common .event .CreateTableEvent ;
2122import org .apache .flink .cdc .common .event .DropTableEvent ;
2223import org .apache .flink .cdc .common .event .SchemaChangeEvent ;
2324import org .apache .flink .cdc .common .event .SchemaChangeEventType ;
2425import org .apache .flink .cdc .common .event .SchemaChangeEventTypeFamily ;
2526import org .apache .flink .cdc .common .event .TableId ;
27+ import org .apache .flink .cdc .common .schema .Column ;
2628import org .apache .flink .cdc .common .sink .MetadataApplier ;
2729import org .apache .flink .table .api .ValidationException ;
2830
3133import org .apache .fluss .client .admin .Admin ;
3234import org .apache .fluss .config .Configuration ;
3335import org .apache .fluss .metadata .DatabaseDescriptor ;
36+ import org .apache .fluss .metadata .TableChange ;
3437import org .apache .fluss .metadata .TableDescriptor ;
3538import org .apache .fluss .metadata .TableInfo ;
3639import org .apache .fluss .metadata .TablePath ;
3740import org .slf4j .Logger ;
3841import org .slf4j .LoggerFactory ;
3942
43+ import java .util .ArrayList ;
4044import java .util .Arrays ;
4145import java .util .HashSet ;
4246import java .util .List ;
4751import static org .apache .flink .cdc .common .event .SchemaChangeEventType .CREATE_TABLE ;
4852import static org .apache .flink .cdc .common .event .SchemaChangeEventType .DROP_TABLE ;
4953import static org .apache .flink .cdc .connectors .fluss .utils .FlussConversions .toFlussTable ;
54+ import static org .apache .flink .cdc .connectors .fluss .utils .FlussConversions .toFlussType ;
5055
5156/** {@link MetadataApplier} for fluss. */
5257public class FlussMetaDataApplier implements MetadataApplier {
@@ -58,9 +63,6 @@ public class FlussMetaDataApplier implements MetadataApplier {
5863 private Set <SchemaChangeEventType > enabledEventTypes =
5964 new HashSet <>(Arrays .asList (CREATE_TABLE , DROP_TABLE ));
6065
61- private transient Connection connection ;
62- private transient Admin admin ;
63-
6466 public FlussMetaDataApplier (
6567 Configuration flussClientConfig ,
6668 Map <String , String > tableProperties ,
@@ -92,22 +94,25 @@ public Set<SchemaChangeEventType> getSupportedSchemaEvolutionTypes() {
9294 @ Override
9395 public void applySchemaChange (SchemaChangeEvent schemaChangeEvent ) {
9496 LOG .info ("fluss metadata applier receive schemaChangeEvent {}" , schemaChangeEvent );
95- Admin admin = getAdmin ();
9697 if (schemaChangeEvent instanceof CreateTableEvent ) {
9798 CreateTableEvent createTableEvent = (CreateTableEvent ) schemaChangeEvent ;
98- applyCreateTable (admin , createTableEvent );
99+ applyCreateTable (createTableEvent );
99100 } else if (schemaChangeEvent instanceof DropTableEvent ) {
100101 DropTableEvent dropTableEvent = (DropTableEvent ) schemaChangeEvent ;
101- applyDropTable (admin , dropTableEvent );
102+ applyDropTable (dropTableEvent );
103+ } else if (schemaChangeEvent instanceof AddColumnEvent ) {
104+ AddColumnEvent addColumnEvent = (AddColumnEvent ) schemaChangeEvent ;
105+ applyAddColumnTable (addColumnEvent );
102106 } else {
103107 throw new IllegalArgumentException (
104- "fluss metadata applier only support CreateTableEvent now but receives "
108+ "fluss metadata applier only supports CreateTableEvent and AddColumnEvent now but receives "
105109 + schemaChangeEvent );
106110 }
107111 }
108112
109- private void applyCreateTable (Admin admin , CreateTableEvent event ) {
110- try {
113+ private void applyCreateTable (CreateTableEvent event ) {
114+ try (Connection connection = ConnectionFactory .createConnection (flussClientConfig );
115+ Admin admin = connection .getAdmin ()) {
111116 TableId tableId = event .tableId ();
112117 TablePath tablePath = new TablePath (tableId .getSchemaName (), tableId .getTableName ());
113118 String tableIdentifier = tablePath .getDatabaseName () + "." + tablePath .getTableName ();
@@ -129,8 +134,9 @@ private void applyCreateTable(Admin admin, CreateTableEvent event) {
129134 }
130135 }
131136
132- private void applyDropTable (Admin admin , DropTableEvent event ) {
133- try {
137+ private void applyDropTable (DropTableEvent event ) {
138+ try (Connection connection = ConnectionFactory .createConnection (flussClientConfig );
139+ Admin admin = connection .getAdmin ()) {
134140 TableId tableId = event .tableId ();
135141 TablePath tablePath = new TablePath (tableId .getSchemaName (), tableId .getTableName ());
136142 admin .dropTable (tablePath , true ).get ();
@@ -140,21 +146,36 @@ private void applyDropTable(Admin admin, DropTableEvent event) {
140146 }
141147 }
142148
143- private Admin getAdmin () {
144- if (connection == null ) {
145- connection = ConnectionFactory .createConnection (flussClientConfig );
146- admin = connection .getAdmin ();
147- }
148- return admin ;
149- }
150-
151- @ Override
152- public void close () throws Exception {
153- if (admin != null ) {
154- admin .close ();
155- }
156- if (connection != null ) {
157- connection .close ();
149+ private void applyAddColumnTable (AddColumnEvent event ) {
150+ List <TableChange > tableChanges = new ArrayList <>();
151+ event .getAddedColumns ()
152+ .forEach (
153+ columnWithPosition -> {
154+ if (columnWithPosition .getPosition ()
155+ != AddColumnEvent .ColumnPosition .LAST ) {
156+ throw new IllegalArgumentException (
157+ "Fluss metadata applier only supports LAST position for adding columns now but receives "
158+ + columnWithPosition .getPosition ()
159+ + ". Consider using 'schema.change.behavior' configuration with 'LENIENT' mode to handle schema changes more flexibly." );
160+ }
161+
162+ Column column = columnWithPosition .getAddColumn ();
163+ tableChanges .add (
164+ TableChange .addColumn (
165+ column .getName (),
166+ toFlussType (column .getType ()),
167+ column .getComment (),
168+ TableChange .ColumnPosition .last ()));
169+ });
170+
171+ try (Connection connection = ConnectionFactory .createConnection (flussClientConfig );
172+ Admin admin = connection .getAdmin ()) {
173+ TableId tableId = event .tableId ();
174+ TablePath tablePath = new TablePath (tableId .getSchemaName (), tableId .getTableName ());
175+ admin .alterTable (tablePath , tableChanges , true ).get ();
176+ } catch (Exception e ) {
177+ LOG .error ("Failed to apply schema change {}" , event , e );
178+ throw new RuntimeException (e );
158179 }
159180 }
160181
0 commit comments