You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@flink.apache.org by "yuanoOo (via GitHub)" <gi...@apache.org> on 2024/05/24 07:15:54 UTC

[PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

yuanoOo opened a new pull request, #3360:
URL: https://github.com/apache/flink-cdc/pull/3360

   This closes [FLINK-34545](https://issues.apache.org/jira/browse/FLINK-34545).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "lvyanquan (via GitHub)" <gi...@apache.org>.
lvyanquan commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1839804631


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseUtils.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BigIntType;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.CharType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DataTypeDefaultVisitor;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.DoubleType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.TinyIntType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utilities for conversion from source table to OceanBase table. */
+public class OceanBaseUtils {
+
+    /** Convert a source table to {@link OceanBaseTable}. */
+    public static OceanBaseTable toOceanBaseTable(TableId tableId, Schema schema) {
+
+        List<Column> columns = schema.getColumns();
+        List<String> primaryKeys = schema.primaryKeys();
+        List<OceanBaseColumn> oceanBaseColumns = new ArrayList<>();
+        for (int i = 0; i < columns.size(); i++) {
+            Column column = columns.get(i);
+            OceanBaseColumn.Builder builder =
+                    new OceanBaseColumn.Builder()
+                            .setColumnName(column.getName())
+                            .setOrdinalPosition(i)
+                            .setColumnComment(column.getComment());
+            toOceanBaseDataType(column, primaryKeys.contains(column.getName()), builder);
+            oceanBaseColumns.add(builder.build());
+        }
+
+        OceanBaseTable.Builder tableBuilder =
+                new OceanBaseTable.Builder()
+                        .setDatabaseName(tableId.getSchemaName())
+                        .setTableName(tableId.getTableName())
+                        .setTableType(
+                                CollectionUtils.isNotEmpty(schema.primaryKeys())
+                                        ? OceanBaseTable.TableType.PRIMARY_KEY
+                                        : OceanBaseTable.TableType.DUPLICATE_KEY)
+                        .setColumns(oceanBaseColumns)
+                        .setTableKeys(schema.primaryKeys())
+                        .setPartitionKeys(schema.partitionKeys())

Review Comment:
   I'm not sure here, do we need to add partitionKeys to primaryKeys? 



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseDataSinkOptions.java:
##########
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.annotation.Experimental;
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.ConfigOptions;
+
+import com.alipay.oceanbase.rpc.protocol.payload.impl.direct_load.ObLoadDupActionType;
+
+import java.time.Duration;
+
+/** Options for {@link OceanBaseDataSink}. */
+public class OceanBaseDataSinkOptions {
+    // ------------------------------------------------------------------------------------------
+    // Options for sink connector
+    // ------------------------------------------------------------------------------------------
+    public static final ConfigOption<String> URL =
+            ConfigOptions.key("url")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The connection URL.");
+
+    public static final ConfigOption<String> USERNAME =
+            ConfigOptions.key("username")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The username.");
+
+    public static final ConfigOption<String> PASSWORD =
+            ConfigOptions.key("password")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The password.");
+
+    public static final ConfigOption<String> DRIVER_CLASS_NAME =
+            ConfigOptions.key("driver-class-name")
+                    .stringType()
+                    .defaultValue("com.mysql.cj.jdbc.Driver")
+                    .withDescription(
+                            "JDBC driver class name, use 'com.mysql.cj.jdbc.Driver' by default.");
+
+    public static final ConfigOption<String> DRUID_PROPERTIES =
+            ConfigOptions.key("druid-properties")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Properties for specific connection pool.");
+
+    public static final ConfigOption<Boolean> MEMSTORE_CHECK_ENABLED =
+            ConfigOptions.key("memstore-check.enabled")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription("Whether enable memstore check. Default value is 'true'");
+
+    public static final ConfigOption<Double> MEMSTORE_THRESHOLD =
+            ConfigOptions.key("memstore-check.threshold")
+                    .doubleType()
+                    .defaultValue(0.9)
+                    .withDescription(
+                            "Memory usage threshold ratio relative to the limit value. Default value is '0.9'.");
+
+    public static final ConfigOption<Duration> MEMSTORE_CHECK_INTERVAL =
+            ConfigOptions.key("memstore-check.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription(
+                            "The check interval, over this time, the writer will check if memstore reaches threshold. Default value is '30s'.");
+
+    public static final ConfigOption<Boolean> PARTITION_ENABLED =
+            ConfigOptions.key("partition.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription(
+                            "Whether to enable partition calculation and flush records by partitions. Default value is 'false'.");
+
+    @Experimental
+    public static final ConfigOption<Boolean> DIRECT_LOAD_ENABLED =
+            ConfigOptions.key("direct-load.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("Whether to enable direct load.");
+
+    @Experimental
+    public static final ConfigOption<String> DIRECT_LOAD_HOST =
+            ConfigOptions.key("direct-load.host")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Hostname used in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Integer> DIRECT_LOAD_PORT =
+            ConfigOptions.key("direct-load.port")
+                    .intType()
+                    .defaultValue(2882)
+                    .withDescription("Rpc port number used in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Integer> DIRECT_LOAD_PARALLEL =
+            ConfigOptions.key("direct-load.parallel")
+                    .intType()
+                    .defaultValue(8)
+                    .withDescription("Parallelism of direct load.");
+
+    @Experimental
+    public static final ConfigOption<Long> DIRECT_LOAD_MAX_ERROR_ROWS =
+            ConfigOptions.key("direct-load.max-error-rows")
+                    .longType()
+                    .defaultValue(0L)
+                    .withDescription("Maximum tolerable number of error rows.");
+
+    @Experimental
+    public static final ConfigOption<ObLoadDupActionType> DIRECT_LOAD_DUP_ACTION =
+            ConfigOptions.key("direct-load.dup-action")
+                    .enumType(ObLoadDupActionType.class)
+                    .defaultValue(ObLoadDupActionType.REPLACE)
+                    .withDescription("Action when there is duplicated record in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Duration> DIRECT_LOAD_TIMEOUT =
+            ConfigOptions.key("direct-load.timeout")
+                    .durationType()
+                    .defaultValue(Duration.ofDays(7))
+                    .withDescription("Timeout for direct load task.");
+
+    @Experimental
+    public static final ConfigOption<Duration> DIRECT_LOAD_HEARTBEAT_TIMEOUT =
+            ConfigOptions.key("direct-load.heartbeat-timeout")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription("Client heartbeat timeout in direct load task.");
+
+    public static final ConfigOption<Boolean> SYNC_WRITE =
+            ConfigOptions.key("sync-write")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("Whether to write synchronously.");
+
+    public static final ConfigOption<Duration> BUFFER_FLUSH_INTERVAL =
+            ConfigOptions.key("buffer-flush.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(1))
+                    .withDescription(
+                            "The flush interval, over this time, asynchronous threads will flush data. Default value is '1s'. "
+                                    + "If it's set to zero value like '0', scheduled flushing will be disabled.");
+
+    public static final ConfigOption<Integer> BUFFER_SIZE =
+            ConfigOptions.key("buffer-flush.buffer-size")
+                    .intType()
+                    .defaultValue(1000)
+                    .withDescription("Buffer size. Default value is '1000'.");
+
+    public static final ConfigOption<Integer> MAX_RETRIES =
+            ConfigOptions.key("max-retries")

Review Comment:
   I didn't see any place of using this option, then I found it was used in fink-connector-oceanbase-1.2, so can we use `ConfigOptions.key(ConnectorOptions.MAX_RETRIES.key())` or add some comments to trace it.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseUtils.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BigIntType;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.CharType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DataTypeDefaultVisitor;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.DoubleType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.TinyIntType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utilities for conversion from source table to OceanBase table. */
+public class OceanBaseUtils {
+
+    /** Convert a source table to {@link OceanBaseTable}. */
+    public static OceanBaseTable toOceanBaseTable(TableId tableId, Schema schema) {
+
+        List<Column> columns = schema.getColumns();
+        List<String> primaryKeys = schema.primaryKeys();
+        List<OceanBaseColumn> oceanBaseColumns = new ArrayList<>();
+        for (int i = 0; i < columns.size(); i++) {
+            Column column = columns.get(i);
+            OceanBaseColumn.Builder builder =
+                    new OceanBaseColumn.Builder()
+                            .setColumnName(column.getName())
+                            .setOrdinalPosition(i)
+                            .setColumnComment(column.getComment());

Review Comment:
   Currently, We've support default value in Source, so we can add default value of column here now.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(OceanBaseConnectorOptions connectorOptions) {
+        try {
+            this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);
+            catalog.open();
+        } catch (Exception e) {
+            throw new OceanBaseCatalogException("Fail to init OceanBaseMetadataApplier.", e);
+        }
+    }
+
+    @Override
+    public void applySchemaChange(SchemaChangeEvent event) {

Review Comment:
   Could you add a test for this method?



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupported Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());
+        TableInfo tableInfo =
+                new TableInfo(
+                        oceanBaseTableId,
+                        schema.primaryKeys(),
+                        schema.getColumnNames(),
+                        Lists.newArrayList(),
+                        null);
+
+        return new DataChangeRecord(
+                tableInfo,
+                isDelete ? DataChangeRecord.Type.DELETE : DataChangeRecord.Type.UPSERT,
+                values);
+    }
+
+    /** serializer RecordData to oceanbase data change record. */
+    public Object[] serializerRecord(RecordData recordData, Schema schema) {
+        List<Column> columns = schema.getColumns();
+        Preconditions.checkState(
+                columns.size() == recordData.getArity(),
+                "Column size does not match the data size");
+        Object[] values = new Object[columns.size()];
+
+        for (int i = 0; i < recordData.getArity(); i++) {
+            OceanBaseRowConvert.SerializationConverter converter =

Review Comment:
   We should cache the List of OceanBaseRowConvert.SerializationConverter of specific Schema to avoid creating them for each recordData.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupported Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());
+        TableInfo tableInfo =
+                new TableInfo(
+                        oceanBaseTableId,
+                        schema.primaryKeys(),
+                        schema.getColumnNames(),
+                        Lists.newArrayList(),
+                        null);
+
+        return new DataChangeRecord(
+                tableInfo,
+                isDelete ? DataChangeRecord.Type.DELETE : DataChangeRecord.Type.UPSERT,
+                values);
+    }
+
+    /** serializer RecordData to oceanbase data change record. */
+    public Object[] serializerRecord(RecordData recordData, Schema schema) {

Review Comment:
   Please add a test for this method to ensure that add support types are converted as expected (especially for timestamp related type). 



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(OceanBaseConnectorOptions connectorOptions) {
+        try {
+            this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);
+            catalog.open();
+        } catch (Exception e) {
+            throw new OceanBaseCatalogException("Fail to init OceanBaseMetadataApplier.", e);
+        }
+    }
+
+    @Override
+    public void applySchemaChange(SchemaChangeEvent event) {
+        try {
+            if (event instanceof CreateTableEvent) {
+                applyCreateTableEvent((CreateTableEvent) event);
+            } else if (event instanceof AddColumnEvent) {
+                applyAddColumnEvent((AddColumnEvent) event);
+            } else if (event instanceof DropColumnEvent) {
+                applyDropColumnEvent((DropColumnEvent) event);
+            } else if (event instanceof RenameColumnEvent) {
+                applyRenameColumnEvent((RenameColumnEvent) event);
+            } else if (event instanceof AlterColumnTypeEvent) {

Review Comment:
   We‘ve added `DropTableEvent` and `TruncateTableEvent`, can you help to check if any adjustments should be added here?



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {

Review Comment:
   Please add a test for this class to ensure that it can work as expected when schema evolution happen.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "ChaomingZhangCN (via GitHub)" <gi...@apache.org>.
ChaomingZhangCN commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2547590961

   @yuanoOo Why don't we Implement DataSource to support pipeline reading? 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2172064348

   @GOODBOY008  I made some changes according to your review. Please review these changes. Thank you.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1639167796


##########
docs/content/docs/connectors/pipeline-connectors/oceanbase.md:
##########
@@ -0,0 +1,343 @@
+---
+title: "OceanBase"
+weight: 7
+type: docs
+aliases:
+- /connectors/pipeline-connectors/oceanbase
+---
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# OceanBase Connector
+
+OceanBase connector can be used as the *Data Sink* of the pipeline, and write data to [OceanBase](https://github.com/oceanbase/oceanbase). This document describes how to set up the OceanBase connector.
+
+## What can the connector do?
+* Create table automatically if not exist
+* Schema change synchronization
+* Data synchronization
+
+## Example
+
+The pipeline for reading data from MySQL and sink to OceanBase can be defined as follows:
+
+```yaml
+source:
+  type: mysql
+  hostname: mysql
+  port: 3306
+  username: mysqluser
+  password: mysqlpw
+  tables: mysql_2_oceanbase_test_17l13vc.\.*
+  server-id: 5400-5404
+  server-time-zone: UTC
+
+sink:
+  type: oceanbase
+  url: jdbc:mysql://oceanbase:2881/test
+  username: root@test
+  password:
+
+pipeline:
+  name: MySQL to OceanBase Pipeline
+  parallelism: 1
+```
+
+## Connector Options
+
+<div class="highlight">
+<table class="colwidths-auto docutils">
+    <thead>
+      <tr>
+        <th>Option</th>
+        <th>Required by Table API</th>
+        <th>Default</th>
+        <th>Type</th>
+        <th>Description</th>
+      </tr>
+    </thead>
+    <tbody>
+    <tr>
+      <td>url</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>JDBC url.</td>
+    </tr>
+    <tr>
+      <td>username</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The username.</td>
+    </tr>
+    <tr>
+      <td>password</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The password.</td>
+    </tr>
+    <tr>
+      <td>schema-name</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The schema name or database name.</td>
+    </tr>
+    <tr>
+      <td>table-name</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The table name.</td>
+    </tr>
+    <tr>
+      <td>driver-class-name</td>
+      <td>No</td>
+      <td>com.mysql.cj.jdbc.Driver</td>
+      <td>String</td>
+      <td>The driver class name, use 'com.mysql.cj.jdbc.Driver' by default. If other value is set, you need to introduce the driver manually.</td>

Review Comment:
   Great, I fixed it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuxiqian (via GitHub)" <gi...@apache.org>.
yuxiqian commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2161996630

   Hi @yuanoOo, thanks for your great contribution! Since @whhe is familiar with OceanBase, do you have time to take a look?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1642033832


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/catalog/OceanBaseCatalogFactory.java:
##########
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.catalog;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import com.oceanbase.connector.flink.connection.OceanBaseConnectionProvider;
+import com.oceanbase.connector.flink.dialect.OceanBaseDialect;
+import com.oceanbase.connector.flink.dialect.OceanBaseMySQLDialect;
+import com.oceanbase.connector.flink.dialect.OceanBaseOracleDialect;
+
+/** A {@link OceanBaseCatalogFactory} to create {@link OceanBaseCatalog}. */
+public class OceanBaseCatalogFactory {
+
+    public static OceanBaseCatalog createOceanBaseCatalog(
+            OceanBaseConnectorOptions connectorOptions) throws Exception {
+        try (OceanBaseConnectionProvider connectionProvider =
+                new OceanBaseConnectionProvider(connectorOptions)) {
+            OceanBaseDialect dialect = connectionProvider.getDialect();
+            if (dialect instanceof OceanBaseMySQLDialect) {
+                return new OceanBaseMySQLCatalog(connectorOptions);
+            } else if (dialect instanceof OceanBaseOracleDialect) {
+                return new OceanBaseOracleCatalog(connectorOptions);
+            } else {
+                throw new OceanBaseCatalogException("This tenant is not supported currently");

Review Comment:
   I changed it to: Fail to create OceanBaseCatalog: unknown tenant.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1845963257


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupported Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());
+        TableInfo tableInfo =
+                new TableInfo(
+                        oceanBaseTableId,
+                        schema.primaryKeys(),
+                        schema.getColumnNames(),
+                        Lists.newArrayList(),
+                        null);
+
+        return new DataChangeRecord(
+                tableInfo,
+                isDelete ? DataChangeRecord.Type.DELETE : DataChangeRecord.Type.UPSERT,
+                values);
+    }
+
+    /** serializer RecordData to oceanbase data change record. */
+    public Object[] serializerRecord(RecordData recordData, Schema schema) {

Review Comment:
   It will be covered by the newly added test `org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseEventSerializationSchemaTest#testMixedSchemaAndDataChanges`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1845961470


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseDataSinkOptions.java:
##########
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.annotation.Experimental;
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.ConfigOptions;
+
+import com.alipay.oceanbase.rpc.protocol.payload.impl.direct_load.ObLoadDupActionType;
+
+import java.time.Duration;
+
+/** Options for {@link OceanBaseDataSink}. */
+public class OceanBaseDataSinkOptions {
+    // ------------------------------------------------------------------------------------------
+    // Options for sink connector
+    // ------------------------------------------------------------------------------------------
+    public static final ConfigOption<String> URL =
+            ConfigOptions.key("url")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The connection URL.");
+
+    public static final ConfigOption<String> USERNAME =
+            ConfigOptions.key("username")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The username.");
+
+    public static final ConfigOption<String> PASSWORD =
+            ConfigOptions.key("password")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The password.");
+
+    public static final ConfigOption<String> DRIVER_CLASS_NAME =
+            ConfigOptions.key("driver-class-name")
+                    .stringType()
+                    .defaultValue("com.mysql.cj.jdbc.Driver")
+                    .withDescription(
+                            "JDBC driver class name, use 'com.mysql.cj.jdbc.Driver' by default.");
+
+    public static final ConfigOption<String> DRUID_PROPERTIES =
+            ConfigOptions.key("druid-properties")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Properties for specific connection pool.");
+
+    public static final ConfigOption<Boolean> MEMSTORE_CHECK_ENABLED =
+            ConfigOptions.key("memstore-check.enabled")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription("Whether enable memstore check. Default value is 'true'");
+
+    public static final ConfigOption<Double> MEMSTORE_THRESHOLD =
+            ConfigOptions.key("memstore-check.threshold")
+                    .doubleType()
+                    .defaultValue(0.9)
+                    .withDescription(
+                            "Memory usage threshold ratio relative to the limit value. Default value is '0.9'.");
+
+    public static final ConfigOption<Duration> MEMSTORE_CHECK_INTERVAL =
+            ConfigOptions.key("memstore-check.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription(
+                            "The check interval, over this time, the writer will check if memstore reaches threshold. Default value is '30s'.");
+
+    public static final ConfigOption<Boolean> PARTITION_ENABLED =
+            ConfigOptions.key("partition.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription(
+                            "Whether to enable partition calculation and flush records by partitions. Default value is 'false'.");
+
+    @Experimental
+    public static final ConfigOption<Boolean> DIRECT_LOAD_ENABLED =
+            ConfigOptions.key("direct-load.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("Whether to enable direct load.");
+
+    @Experimental
+    public static final ConfigOption<String> DIRECT_LOAD_HOST =
+            ConfigOptions.key("direct-load.host")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Hostname used in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Integer> DIRECT_LOAD_PORT =
+            ConfigOptions.key("direct-load.port")
+                    .intType()
+                    .defaultValue(2882)
+                    .withDescription("Rpc port number used in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Integer> DIRECT_LOAD_PARALLEL =
+            ConfigOptions.key("direct-load.parallel")
+                    .intType()
+                    .defaultValue(8)
+                    .withDescription("Parallelism of direct load.");
+
+    @Experimental
+    public static final ConfigOption<Long> DIRECT_LOAD_MAX_ERROR_ROWS =
+            ConfigOptions.key("direct-load.max-error-rows")
+                    .longType()
+                    .defaultValue(0L)
+                    .withDescription("Maximum tolerable number of error rows.");
+
+    @Experimental
+    public static final ConfigOption<ObLoadDupActionType> DIRECT_LOAD_DUP_ACTION =
+            ConfigOptions.key("direct-load.dup-action")
+                    .enumType(ObLoadDupActionType.class)
+                    .defaultValue(ObLoadDupActionType.REPLACE)
+                    .withDescription("Action when there is duplicated record in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Duration> DIRECT_LOAD_TIMEOUT =
+            ConfigOptions.key("direct-load.timeout")
+                    .durationType()
+                    .defaultValue(Duration.ofDays(7))
+                    .withDescription("Timeout for direct load task.");
+
+    @Experimental
+    public static final ConfigOption<Duration> DIRECT_LOAD_HEARTBEAT_TIMEOUT =
+            ConfigOptions.key("direct-load.heartbeat-timeout")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription("Client heartbeat timeout in direct load task.");
+
+    public static final ConfigOption<Boolean> SYNC_WRITE =
+            ConfigOptions.key("sync-write")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("Whether to write synchronously.");
+
+    public static final ConfigOption<Duration> BUFFER_FLUSH_INTERVAL =
+            ConfigOptions.key("buffer-flush.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(1))
+                    .withDescription(
+                            "The flush interval, over this time, asynchronous threads will flush data. Default value is '1s'. "
+                                    + "If it's set to zero value like '0', scheduled flushing will be disabled.");
+
+    public static final ConfigOption<Integer> BUFFER_SIZE =
+            ConfigOptions.key("buffer-flush.buffer-size")
+                    .intType()
+                    .defaultValue(1000)
+                    .withDescription("Buffer size. Default value is '1000'.");
+
+    public static final ConfigOption<Integer> MAX_RETRIES =
+            ConfigOptions.key("max-retries")

Review Comment:
   - All options will be passed to fink-connector-oceanbase and then used. See the following code:
   ```
           Configuration config = context.getFactoryConfiguration();
           Map<String, String> configMap = config.toMap();
           OptionUtils.printOptions(IDENTIFIER, configMap);
           
           OceanBaseConnectorOptions connectorOptions = new OceanBaseConnectorOptions(configMap);
           String zoneStr = context.getPipelineConfiguration().get(PIPELINE_LOCAL_TIME_ZONE);
           ZoneId zoneId =
                   PIPELINE_LOCAL_TIME_ZONE.defaultValue().equals(zoneStr)
                           ? ZoneId.systemDefault()
                           : ZoneId.of(zoneStr);
           return new OceanBaseDataSink(connectorOptions, zoneId);
   ```
   - I removed direct-load related options because the direct-load feature has been removed from flink-sql-connector-oceanbase since version 1.4.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(OceanBaseConnectorOptions connectorOptions) {
+        try {
+            this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);
+            catalog.open();
+        } catch (Exception e) {
+            throw new OceanBaseCatalogException("Fail to init OceanBaseMetadataApplier.", e);
+        }
+    }
+
+    @Override
+    public void applySchemaChange(SchemaChangeEvent event) {
+        try {
+            if (event instanceof CreateTableEvent) {
+                applyCreateTableEvent((CreateTableEvent) event);
+            } else if (event instanceof AddColumnEvent) {
+                applyAddColumnEvent((AddColumnEvent) event);
+            } else if (event instanceof DropColumnEvent) {
+                applyDropColumnEvent((DropColumnEvent) event);
+            } else if (event instanceof RenameColumnEvent) {
+                applyRenameColumnEvent((RenameColumnEvent) event);
+            } else if (event instanceof AlterColumnTypeEvent) {

Review Comment:
   Added.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "lvyanquan (via GitHub)" <gi...@apache.org>.
lvyanquan commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1839804631


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseUtils.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BigIntType;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.CharType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DataTypeDefaultVisitor;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.DoubleType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.TinyIntType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utilities for conversion from source table to OceanBase table. */
+public class OceanBaseUtils {
+
+    /** Convert a source table to {@link OceanBaseTable}. */
+    public static OceanBaseTable toOceanBaseTable(TableId tableId, Schema schema) {
+
+        List<Column> columns = schema.getColumns();
+        List<String> primaryKeys = schema.primaryKeys();
+        List<OceanBaseColumn> oceanBaseColumns = new ArrayList<>();
+        for (int i = 0; i < columns.size(); i++) {
+            Column column = columns.get(i);
+            OceanBaseColumn.Builder builder =
+                    new OceanBaseColumn.Builder()
+                            .setColumnName(column.getName())
+                            .setOrdinalPosition(i)
+                            .setColumnComment(column.getComment());
+            toOceanBaseDataType(column, primaryKeys.contains(column.getName()), builder);
+            oceanBaseColumns.add(builder.build());
+        }
+
+        OceanBaseTable.Builder tableBuilder =
+                new OceanBaseTable.Builder()
+                        .setDatabaseName(tableId.getSchemaName())
+                        .setTableName(tableId.getTableName())
+                        .setTableType(
+                                CollectionUtils.isNotEmpty(schema.primaryKeys())
+                                        ? OceanBaseTable.TableType.PRIMARY_KEY
+                                        : OceanBaseTable.TableType.DUPLICATE_KEY)
+                        .setColumns(oceanBaseColumns)
+                        .setTableKeys(schema.primaryKeys())
+                        .setPartitionKeys(schema.partitionKeys())

Review Comment:
   I'm not sure here, do we need to add partitionKeys to primaryKeys(and deduplicate columns)? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1641144855


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.configuration.Configuration;
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(
+            OceanBaseConnectorOptions connectorOptions, Configuration config) throws Exception {
+        this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);

Review Comment:
   It will be used to support schema changes based on offline DDL.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1845962719


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupported Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());
+        TableInfo tableInfo =
+                new TableInfo(
+                        oceanBaseTableId,
+                        schema.primaryKeys(),
+                        schema.getColumnNames(),
+                        Lists.newArrayList(),
+                        null);
+
+        return new DataChangeRecord(
+                tableInfo,
+                isDelete ? DataChangeRecord.Type.DELETE : DataChangeRecord.Type.UPSERT,
+                values);
+    }
+
+    /** serializer RecordData to oceanbase data change record. */
+    public Object[] serializerRecord(RecordData recordData, Schema schema) {
+        List<Column> columns = schema.getColumns();
+        Preconditions.checkState(
+                columns.size() == recordData.getArity(),
+                "Column size does not match the data size");
+        Object[] values = new Object[columns.size()];
+
+        for (int i = 0; i < recordData.getArity(); i++) {
+            OceanBaseRowConvert.SerializationConverter converter =

Review Comment:
   I don't think it's necessary. OceanBaseRowConvert.SerializationConverter is a function `@FunctionalInterface`, such as `(index, val) -> val.getByte(index)`, not a data class. Creating it will not have much impact on performance. What do you think?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1849995102


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/test/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchemaTest.java:
##########
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.DecimalData;
+import org.apache.flink.cdc.common.data.LocalZonedTimestampData;
+import org.apache.flink.cdc.common.data.TimestampData;
+import org.apache.flink.cdc.common.data.binary.BinaryStringData;
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+import org.apache.flink.cdc.runtime.typeutils.BinaryRecordDataGenerator;
+
+import com.oceanbase.connector.flink.table.Record;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/** Tests for {@link OceanBaseEventSerializationSchema}. */
+public class OceanBaseEventSerializationSchemaTest {
+
+    private static final OceanBaseEventSerializationSchema serializer =
+            new OceanBaseEventSerializationSchema(ZoneId.of("+08"));
+
+    @Test
+    public void testMixedSchemaAndDataChanges() throws Exception {
+        // 1. create table1, and insert/delete/update data
+        TableId table1 = TableId.parse("test.tbl1");
+        Schema schema1 =
+                Schema.newBuilder()
+                        .physicalColumn("col1", new IntType(false))
+                        .physicalColumn("col2", new BooleanType())
+                        .physicalColumn("col3", new TimestampType())

Review Comment:
   Added.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2530090932

   @ruanhang1993 Please take a look here when you have some free time.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2472746734

   @lvyanquan Can you take a look here in your free time.
   I checked and the GitHub CI failure seems to be unrelated to this PR.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2424303259

   This pull request has been automatically marked as stale because it has not had recent activity for 60 days. It will be closed in 30 days if no further activity occurs.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1849991842


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupported Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());
+        TableInfo tableInfo =
+                new TableInfo(
+                        oceanBaseTableId,
+                        schema.primaryKeys(),
+                        schema.getColumnNames(),
+                        Lists.newArrayList(),
+                        null);
+
+        return new DataChangeRecord(
+                tableInfo,
+                isDelete ? DataChangeRecord.Type.DELETE : DataChangeRecord.Type.UPSERT,
+                values);
+    }
+
+    /** serializer RecordData to oceanbase data change record. */
+    public Object[] serializerRecord(RecordData recordData, Schema schema) {
+        List<Column> columns = schema.getColumns();
+        Preconditions.checkState(
+                columns.size() == recordData.getArity(),
+                "Column size does not match the data size");
+        Object[] values = new Object[columns.size()];
+
+        for (int i = 0; i < recordData.getArity(); i++) {
+            OceanBaseRowConvert.SerializationConverter converter =

Review Comment:
   Ok,cache added.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1641144855


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.configuration.Configuration;
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(
+            OceanBaseConnectorOptions connectorOptions, Configuration config) throws Exception {
+        this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);

Review Comment:
   Removed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "whhe (via GitHub)" <gi...@apache.org>.
whhe commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1637472845


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupport Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());

Review Comment:
   Better to add null check for tableId.getSchemaName() here.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseDataSinkOptions.java:
##########
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.ConfigOptions;
+
+import com.alipay.oceanbase.rpc.protocol.payload.impl.direct_load.ObLoadDupActionType;
+
+import java.time.Duration;
+
+/** Options for {@link OceanBaseDataSink}. */
+public class OceanBaseDataSinkOptions {
+    // ------------------------------------------------------------------------------------------
+    // Options for sink connector
+    // ------------------------------------------------------------------------------------------
+    public static final ConfigOption<String> URL =
+            ConfigOptions.key("url")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The connection URL.");
+
+    public static final ConfigOption<String> USERNAME =
+            ConfigOptions.key("username")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The username.");
+
+    public static final ConfigOption<String> PASSWORD =
+            ConfigOptions.key("password")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The password.");
+
+    public static final ConfigOption<String> DRIVER_CLASS_NAME =
+            ConfigOptions.key("driver-class-name")
+                    .stringType()
+                    .defaultValue("com.mysql.cj.jdbc.Driver")
+                    .withDescription(
+                            "JDBC driver class name, use 'com.mysql.cj.jdbc.Driver' by default.");
+
+    public static final ConfigOption<String> DRUID_PROPERTIES =
+            ConfigOptions.key("druid-properties")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Properties for specific connection pool.");
+
+    public static final ConfigOption<Boolean> MEMSTORE_CHECK_ENABLED =
+            ConfigOptions.key("memstore-check.enabled")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription("Whether enable memstore check. Default value is 'true'");
+
+    public static final ConfigOption<Double> MEMSTORE_THRESHOLD =
+            ConfigOptions.key("memstore-check.threshold")
+                    .doubleType()
+                    .defaultValue(0.9)
+                    .withDescription(
+                            "Memory usage threshold ratio relative to the limit value. Default value is '0.9'.");
+
+    public static final ConfigOption<Duration> MEMSTORE_CHECK_INTERVAL =
+            ConfigOptions.key("memstore-check.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription(
+                            "The check interval, over this time, the writer will check if memstore reaches threshold. Default value is '30s'.");
+
+    public static final ConfigOption<Boolean> PARTITION_ENABLED =
+            ConfigOptions.key("partition.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription(
+                            "Whether to enable partition calculation and flush records by partitions. Default value is 'false'.");
+
+    public static final ConfigOption<Boolean> DIRECT_LOAD_ENABLED =
+            ConfigOptions.key("direct-load.enabled")

Review Comment:
   Mark 'direct-load' related options as @Experimental.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2268010834

   @GOODBOY008 Please take a look here. Looking forward to your reply.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1641142897


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/factory/OceanBaseDataSinkFactory.java:
##########
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.factory;
+
+import org.apache.flink.cdc.common.annotation.Internal;
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.Configuration;
+import org.apache.flink.cdc.common.factories.DataSinkFactory;
+import org.apache.flink.cdc.common.sink.DataSink;
+import org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseDataSink;
+import org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseDataSinkOptions;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+
+import java.time.ZoneId;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.apache.flink.cdc.common.pipeline.PipelineOptions.PIPELINE_LOCAL_TIME_ZONE;
+
+/** A {@link DataSinkFactory} to create {@link OceanBaseDataSink}. */
+@Internal
+public class OceanBaseDataSinkFactory implements DataSinkFactory {
+
+    @Override
+    public DataSink createDataSink(Context context) {
+        Configuration config = context.getFactoryConfiguration();
+        OceanBaseConnectorOptions connectorOptions =
+                new OceanBaseConnectorOptions(buildOceanBaseOptions(config));
+        String zoneStr = context.getFactoryConfiguration().get(PIPELINE_LOCAL_TIME_ZONE);
+        ZoneId zoneId =
+                PIPELINE_LOCAL_TIME_ZONE.defaultValue().equals(zoneStr)
+                        ? ZoneId.systemDefault()
+                        : ZoneId.of(zoneStr);
+        return new OceanBaseDataSink(connectorOptions, config, zoneId);
+    }
+
+    public Map<String, String> buildOceanBaseOptions(Configuration config) {
+        Optional<String> optional = config.getOptional(OceanBaseDataSinkOptions.PASSWORD);
+        config.remove(OceanBaseDataSinkOptions.PASSWORD);
+        Map<String, String> map = config.toMap();
+        map.put(OceanBaseDataSinkOptions.PASSWORD.key(), optional.orElse(""));

Review Comment:
   @GOODBOY008  This is to avoid NullPointerException when password is empty.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2295824842

   @GOODBOY008 I just resolved the conflict. Please help trigger the github workflow again.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "GOODBOY008 (via GitHub)" <gi...@apache.org>.
GOODBOY008 commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2230043015

   @yuanoOo Please fix dead link in doc , refer : https://github.com/apache/flink-cdc/actions/runs/9869322624/job/27277822806?pr=3360#step:4:721


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2230080527

   @GOODBOY008 After version 3.2 is released, flink-cdc-pipeline-connector-oceanbase-3.2.0.jar will be distributed and the dead link will be activated. I think this issue can be ignored for now.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "GOODBOY008 (via GitHub)" <gi...@apache.org>.
GOODBOY008 commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1639708043


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/factory/OceanBaseDataSinkFactory.java:
##########
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.factory;
+
+import org.apache.flink.cdc.common.annotation.Internal;
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.Configuration;
+import org.apache.flink.cdc.common.factories.DataSinkFactory;
+import org.apache.flink.cdc.common.sink.DataSink;
+import org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseDataSink;
+import org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseDataSinkOptions;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+
+import java.time.ZoneId;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.apache.flink.cdc.common.pipeline.PipelineOptions.PIPELINE_LOCAL_TIME_ZONE;
+
+/** A {@link DataSinkFactory} to create {@link OceanBaseDataSink}. */
+@Internal
+public class OceanBaseDataSinkFactory implements DataSinkFactory {
+
+    @Override
+    public DataSink createDataSink(Context context) {
+        Configuration config = context.getFactoryConfiguration();
+        OceanBaseConnectorOptions connectorOptions =
+                new OceanBaseConnectorOptions(buildOceanBaseOptions(config));
+        String zoneStr = context.getFactoryConfiguration().get(PIPELINE_LOCAL_TIME_ZONE);
+        ZoneId zoneId =
+                PIPELINE_LOCAL_TIME_ZONE.defaultValue().equals(zoneStr)
+                        ? ZoneId.systemDefault()

Review Comment:
   add `OptionUtils.printOptions(IDENTIFIER, config.toMap());` for usr to know the config info.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupport Operation " + op);

Review Comment:
   ```suggestion
                   throw new UnsupportedOperationException("Unsupported Operation " + op);
   ```



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.configuration.Configuration;
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(
+            OceanBaseConnectorOptions connectorOptions, Configuration config) throws Exception {
+        this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);

Review Comment:
   Unused `Configuration config`.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupport Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "schema name cannot be null or empty.");

Review Comment:
   ```suggestion
                   Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
   ```



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/factory/OceanBaseDataSinkFactory.java:
##########
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.factory;
+
+import org.apache.flink.cdc.common.annotation.Internal;
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.Configuration;
+import org.apache.flink.cdc.common.factories.DataSinkFactory;
+import org.apache.flink.cdc.common.sink.DataSink;
+import org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseDataSink;
+import org.apache.flink.cdc.connectors.oceanbase.sink.OceanBaseDataSinkOptions;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+
+import java.time.ZoneId;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.apache.flink.cdc.common.pipeline.PipelineOptions.PIPELINE_LOCAL_TIME_ZONE;
+
+/** A {@link DataSinkFactory} to create {@link OceanBaseDataSink}. */
+@Internal
+public class OceanBaseDataSinkFactory implements DataSinkFactory {
+
+    @Override
+    public DataSink createDataSink(Context context) {
+        Configuration config = context.getFactoryConfiguration();
+        OceanBaseConnectorOptions connectorOptions =
+                new OceanBaseConnectorOptions(buildOceanBaseOptions(config));
+        String zoneStr = context.getFactoryConfiguration().get(PIPELINE_LOCAL_TIME_ZONE);
+        ZoneId zoneId =
+                PIPELINE_LOCAL_TIME_ZONE.defaultValue().equals(zoneStr)
+                        ? ZoneId.systemDefault()
+                        : ZoneId.of(zoneStr);
+        return new OceanBaseDataSink(connectorOptions, config, zoneId);
+    }
+
+    public Map<String, String> buildOceanBaseOptions(Configuration config) {
+        Optional<String> optional = config.getOptional(OceanBaseDataSinkOptions.PASSWORD);
+        config.remove(OceanBaseDataSinkOptions.PASSWORD);
+        Map<String, String> map = config.toMap();
+        map.put(OceanBaseDataSinkOptions.PASSWORD.key(), optional.orElse(""));

Review Comment:
   I do not know why do this?



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/catalog/OceanBaseCatalogFactory.java:
##########
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.catalog;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import com.oceanbase.connector.flink.connection.OceanBaseConnectionProvider;
+import com.oceanbase.connector.flink.dialect.OceanBaseDialect;
+import com.oceanbase.connector.flink.dialect.OceanBaseMySQLDialect;
+import com.oceanbase.connector.flink.dialect.OceanBaseOracleDialect;
+
+/** A {@link OceanBaseCatalogFactory} to create {@link OceanBaseCatalog}. */
+public class OceanBaseCatalogFactory {
+
+    public static OceanBaseCatalog createOceanBaseCatalog(
+            OceanBaseConnectorOptions connectorOptions) throws Exception {
+        try (OceanBaseConnectionProvider connectionProvider =
+                new OceanBaseConnectionProvider(connectorOptions)) {
+            OceanBaseDialect dialect = connectionProvider.getDialect();
+            if (dialect instanceof OceanBaseMySQLDialect) {
+                return new OceanBaseMySQLCatalog(connectorOptions);
+            } else if (dialect instanceof OceanBaseOracleDialect) {
+                return new OceanBaseOracleCatalog(connectorOptions);
+            } else {
+                throw new OceanBaseCatalogException("This tenant is not supported currently");

Review Comment:
   I think we can throw exception msg with direct means.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "leonardBang (via GitHub)" <gi...@apache.org>.
leonardBang merged PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "GOODBOY008 (via GitHub)" <gi...@apache.org>.
GOODBOY008 commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2552692504

   @yuanoOo I will take a look at the end of this week.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "lvyanquan (via GitHub)" <gi...@apache.org>.
lvyanquan commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1839773453


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseDataSinkOptions.java:
##########
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.annotation.Experimental;
+import org.apache.flink.cdc.common.configuration.ConfigOption;
+import org.apache.flink.cdc.common.configuration.ConfigOptions;
+
+import com.alipay.oceanbase.rpc.protocol.payload.impl.direct_load.ObLoadDupActionType;
+
+import java.time.Duration;
+
+/** Options for {@link OceanBaseDataSink}. */
+public class OceanBaseDataSinkOptions {
+    // ------------------------------------------------------------------------------------------
+    // Options for sink connector
+    // ------------------------------------------------------------------------------------------
+    public static final ConfigOption<String> URL =
+            ConfigOptions.key("url")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The connection URL.");
+
+    public static final ConfigOption<String> USERNAME =
+            ConfigOptions.key("username")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The username.");
+
+    public static final ConfigOption<String> PASSWORD =
+            ConfigOptions.key("password")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("The password.");
+
+    public static final ConfigOption<String> DRIVER_CLASS_NAME =
+            ConfigOptions.key("driver-class-name")
+                    .stringType()
+                    .defaultValue("com.mysql.cj.jdbc.Driver")
+                    .withDescription(
+                            "JDBC driver class name, use 'com.mysql.cj.jdbc.Driver' by default.");
+
+    public static final ConfigOption<String> DRUID_PROPERTIES =
+            ConfigOptions.key("druid-properties")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Properties for specific connection pool.");
+
+    public static final ConfigOption<Boolean> MEMSTORE_CHECK_ENABLED =
+            ConfigOptions.key("memstore-check.enabled")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription("Whether enable memstore check. Default value is 'true'");
+
+    public static final ConfigOption<Double> MEMSTORE_THRESHOLD =
+            ConfigOptions.key("memstore-check.threshold")
+                    .doubleType()
+                    .defaultValue(0.9)
+                    .withDescription(
+                            "Memory usage threshold ratio relative to the limit value. Default value is '0.9'.");
+
+    public static final ConfigOption<Duration> MEMSTORE_CHECK_INTERVAL =
+            ConfigOptions.key("memstore-check.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription(
+                            "The check interval, over this time, the writer will check if memstore reaches threshold. Default value is '30s'.");
+
+    public static final ConfigOption<Boolean> PARTITION_ENABLED =
+            ConfigOptions.key("partition.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription(
+                            "Whether to enable partition calculation and flush records by partitions. Default value is 'false'.");
+
+    @Experimental
+    public static final ConfigOption<Boolean> DIRECT_LOAD_ENABLED =
+            ConfigOptions.key("direct-load.enabled")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("Whether to enable direct load.");
+
+    @Experimental
+    public static final ConfigOption<String> DIRECT_LOAD_HOST =
+            ConfigOptions.key("direct-load.host")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription("Hostname used in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Integer> DIRECT_LOAD_PORT =
+            ConfigOptions.key("direct-load.port")
+                    .intType()
+                    .defaultValue(2882)
+                    .withDescription("Rpc port number used in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Integer> DIRECT_LOAD_PARALLEL =
+            ConfigOptions.key("direct-load.parallel")
+                    .intType()
+                    .defaultValue(8)
+                    .withDescription("Parallelism of direct load.");
+
+    @Experimental
+    public static final ConfigOption<Long> DIRECT_LOAD_MAX_ERROR_ROWS =
+            ConfigOptions.key("direct-load.max-error-rows")
+                    .longType()
+                    .defaultValue(0L)
+                    .withDescription("Maximum tolerable number of error rows.");
+
+    @Experimental
+    public static final ConfigOption<ObLoadDupActionType> DIRECT_LOAD_DUP_ACTION =
+            ConfigOptions.key("direct-load.dup-action")
+                    .enumType(ObLoadDupActionType.class)
+                    .defaultValue(ObLoadDupActionType.REPLACE)
+                    .withDescription("Action when there is duplicated record in direct load.");
+
+    @Experimental
+    public static final ConfigOption<Duration> DIRECT_LOAD_TIMEOUT =
+            ConfigOptions.key("direct-load.timeout")
+                    .durationType()
+                    .defaultValue(Duration.ofDays(7))
+                    .withDescription("Timeout for direct load task.");
+
+    @Experimental
+    public static final ConfigOption<Duration> DIRECT_LOAD_HEARTBEAT_TIMEOUT =
+            ConfigOptions.key("direct-load.heartbeat-timeout")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(30))
+                    .withDescription("Client heartbeat timeout in direct load task.");
+
+    public static final ConfigOption<Boolean> SYNC_WRITE =
+            ConfigOptions.key("sync-write")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("Whether to write synchronously.");
+
+    public static final ConfigOption<Duration> BUFFER_FLUSH_INTERVAL =
+            ConfigOptions.key("buffer-flush.interval")
+                    .durationType()
+                    .defaultValue(Duration.ofSeconds(1))
+                    .withDescription(
+                            "The flush interval, over this time, asynchronous threads will flush data. Default value is '1s'. "
+                                    + "If it's set to zero value like '0', scheduled flushing will be disabled.");
+
+    public static final ConfigOption<Integer> BUFFER_SIZE =
+            ConfigOptions.key("buffer-flush.buffer-size")
+                    .intType()
+                    .defaultValue(1000)
+                    .withDescription("Buffer size. Default value is '1000'.");
+
+    public static final ConfigOption<Integer> MAX_RETRIES =
+            ConfigOptions.key("max-retries")

Review Comment:
   I didn't see any place of using this option, then I found it was used in fink-connector-oceanbase-1.2, so we may need to use `ConfigOptions.key(ConnectorOptions.MAX_RETRIES.key())` or add some comments here to trace it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1845962931


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {

Review Comment:
   Added.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "lvyanquan (via GitHub)" <gi...@apache.org>.
lvyanquan commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1847724959


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/test/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplierTest.java:
##########
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.DropTableEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.event.TruncateTableEvent;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.connectors.oceanbase.OceanBaseTestUtils;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+import org.apache.flink.cdc.connectors.oceanbase.testutils.OceanBaseContainer;
+import org.apache.flink.cdc.connectors.oceanbase.utils.OceanBaseTestMySQLCatalog;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.ImmutableMap;
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.flink.cdc.connectors.oceanbase.table.OceanBaseMySQLModeITCase.NETWORK;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/** Tests for {@link OceanBaseMetadataApplier}. */
+public class OceanBaseMetadataApplierTest {
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplierTest.class);
+
+    private OceanBaseMetadataApplier metadataApplier;
+    private OceanBaseTestMySQLCatalog catalog;
+
+    @ClassRule
+    public static final OceanBaseContainer OB_SERVER =
+            OceanBaseTestUtils.createOceanBaseContainerForJdbc()
+                    .withNetwork(NETWORK)
+                    .withNetworkAliases("oceanbase")
+                    .withLogConsumer(new Slf4jLogConsumer(LOG));
+
+    @Before
+    public void setup() throws Exception {
+        final ImmutableMap<String, String> configMap =
+                ImmutableMap.<String, String>builder()
+                        .put("url", OB_SERVER.getJdbcUrl())
+                        .put("username", OB_SERVER.getUsername())
+                        .put("password", OB_SERVER.getPassword())
+                        .build();
+        OceanBaseConnectorOptions connectorOptions = new OceanBaseConnectorOptions(configMap);
+        metadataApplier = new OceanBaseMetadataApplier(connectorOptions);
+        catalog = new OceanBaseTestMySQLCatalog(connectorOptions);
+        catalog.open();
+    }
+
+    @AfterClass
+    public static void close() {
+        OB_SERVER.close();
+    }
+
+    @Test
+    public void testCreateTable() {
+        TableId tableId = TableId.parse("test.tbl1");
+        Schema schema =
+                Schema.newBuilder()
+                        .physicalColumn("col1", new IntType(false))
+                        .physicalColumn("col2", new BooleanType())
+                        .physicalColumn("col3", new LocalZonedTimestampType())
+                        .primaryKey("col1")
+                        .build();
+        CreateTableEvent createTableEvent = new CreateTableEvent(tableId, schema);
+        metadataApplier.applySchemaChange(createTableEvent);
+
+        OceanBaseTable actualTable =
+                catalog.getTable(tableId.getSchemaName(), tableId.getTableName()).orElse(null);
+        assertNotNull(actualTable);
+
+        List<OceanBaseColumn> columns = new ArrayList<>();
+        columns.add(
+                new OceanBaseColumn.Builder()
+                        .setColumnName("col1")
+                        .setOrdinalPosition(0)
+                        .setDataType("int")
+                        .setNumericScale(0)
+                        .setNullable(false)
+                        .build());
+        columns.add(
+                new OceanBaseColumn.Builder()
+                        .setColumnName("col2")
+                        .setOrdinalPosition(1)
+                        .setDataType("tinyint")
+                        .setNumericScale(0)
+                        .setNullable(true)
+                        .build());
+        columns.add(
+                new OceanBaseColumn.Builder()
+                        .setColumnName("col3")
+                        .setOrdinalPosition(2)
+                        .setDataType("datetime")
+                        .setNullable(true)
+                        .build());
+        OceanBaseTable expectTable =
+                new OceanBaseTable.Builder()
+                        .setDatabaseName(tableId.getSchemaName())
+                        .setTableName(tableId.getTableName())
+                        .setTableType(OceanBaseTable.TableType.PRIMARY_KEY)
+                        .setColumns(columns)
+                        .setTableKeys(schema.primaryKeys())
+                        .build();
+
+        System.out.println(expectTable);
+        System.out.println(actualTable);

Review Comment:
   These can be removed.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchema.java:
##########
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.RecordData;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.Event;
+import org.apache.flink.cdc.common.event.OperationType;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.table.DataChangeRecord;
+import com.oceanbase.connector.flink.table.Record;
+import com.oceanbase.connector.flink.table.RecordSerializationSchema;
+import com.oceanbase.connector.flink.table.TableInfo;
+
+import java.time.ZoneId;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A serializer for Event to Record. */
+public class OceanBaseEventSerializationSchema implements RecordSerializationSchema<Event> {
+
+    private final Map<TableId, Schema> schemaMaps = new HashMap<>();
+
+    /** ZoneId from pipeline config to support timestamp with local time zone. */
+    public final ZoneId pipelineZoneId;
+
+    public OceanBaseEventSerializationSchema(ZoneId zoneId) {
+        pipelineZoneId = zoneId;
+    }
+
+    @Override
+    public Record serialize(Event event) {
+        if (event instanceof DataChangeEvent) {
+            return applyDataChangeEvent((DataChangeEvent) event);
+        } else if (event instanceof SchemaChangeEvent) {
+            SchemaChangeEvent schemaChangeEvent = (SchemaChangeEvent) event;
+            TableId tableId = schemaChangeEvent.tableId();
+            if (event instanceof CreateTableEvent) {
+                schemaMaps.put(tableId, ((CreateTableEvent) event).getSchema());
+            } else {
+                if (!schemaMaps.containsKey(tableId)) {
+                    throw new RuntimeException("schema of " + tableId + " is not existed.");
+                }
+                schemaMaps.put(
+                        tableId,
+                        SchemaUtils.applySchemaChangeEvent(
+                                schemaMaps.get(tableId), schemaChangeEvent));
+            }
+        }
+        return null;
+    }
+
+    private Record applyDataChangeEvent(DataChangeEvent event) {
+        TableId tableId = event.tableId();
+        Schema schema = schemaMaps.get(tableId);
+        Preconditions.checkNotNull(schema, event.tableId() + " is not existed");
+        Object[] values;
+        OperationType op = event.op();
+        boolean isDelete = false;
+        switch (op) {
+            case INSERT:
+            case UPDATE:
+            case REPLACE:
+                values = serializerRecord(event.after(), schema);
+                break;
+            case DELETE:
+                values = serializerRecord(event.before(), schema);
+                isDelete = true;
+                break;
+            default:
+                throw new UnsupportedOperationException("Unsupported Operation " + op);
+        }
+        return buildDataChangeRecord(tableId, schema, values, isDelete);
+    }
+
+    private DataChangeRecord buildDataChangeRecord(
+            TableId tableId, Schema schema, Object[] values, boolean isDelete) {
+        Preconditions.checkState(
+                Objects.nonNull(tableId.getSchemaName()), "Schema name cannot be null or empty.");
+        com.oceanbase.connector.flink.table.TableId oceanBaseTableId =
+                new com.oceanbase.connector.flink.table.TableId(
+                        tableId.getSchemaName(), tableId.getTableName());
+        TableInfo tableInfo =
+                new TableInfo(
+                        oceanBaseTableId,
+                        schema.primaryKeys(),
+                        schema.getColumnNames(),
+                        Lists.newArrayList(),
+                        null);
+
+        return new DataChangeRecord(
+                tableInfo,
+                isDelete ? DataChangeRecord.Type.DELETE : DataChangeRecord.Type.UPSERT,
+                values);
+    }
+
+    /** serializer RecordData to oceanbase data change record. */
+    public Object[] serializerRecord(RecordData recordData, Schema schema) {
+        List<Column> columns = schema.getColumns();
+        Preconditions.checkState(
+                columns.size() == recordData.getArity(),
+                "Column size does not match the data size");
+        Object[] values = new Object[columns.size()];
+
+        for (int i = 0; i < recordData.getArity(); i++) {
+            OceanBaseRowConvert.SerializationConverter converter =

Review Comment:
   I think the benefit of reusing this SerializationConverter is that we can reduce the judgments of https://github.com/apache/flink-cdc/pull/3360/files#diff-c42ada3283c29232d90a4184ca6196a7f24194229384773ff49792a5d9667318R75



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/test/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseEventSerializationSchemaTest.java:
##########
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.data.DecimalData;
+import org.apache.flink.cdc.common.data.LocalZonedTimestampData;
+import org.apache.flink.cdc.common.data.TimestampData;
+import org.apache.flink.cdc.common.data.binary.BinaryStringData;
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DataChangeEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.common.utils.SchemaUtils;
+import org.apache.flink.cdc.runtime.typeutils.BinaryRecordDataGenerator;
+
+import com.oceanbase.connector.flink.table.Record;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/** Tests for {@link OceanBaseEventSerializationSchema}. */
+public class OceanBaseEventSerializationSchemaTest {
+
+    private static final OceanBaseEventSerializationSchema serializer =
+            new OceanBaseEventSerializationSchema(ZoneId.of("+08"));
+
+    @Test
+    public void testMixedSchemaAndDataChanges() throws Exception {
+        // 1. create table1, and insert/delete/update data
+        TableId table1 = TableId.parse("test.tbl1");
+        Schema schema1 =
+                Schema.newBuilder()
+                        .physicalColumn("col1", new IntType(false))
+                        .physicalColumn("col2", new BooleanType())
+                        .physicalColumn("col3", new TimestampType())

Review Comment:
   It's better to add a test to cover all supported types like the following:
   https://github.com/apache/flink-cdc/blob/8e6c361f961966c25c9c34ffecdfc87cf2b599a3/flink-cdc-runtime/src/test/java/org/apache/flink/cdc/runtime/typeutils/BinaryRecordDataGeneratorTest.java#L43-L71



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2502563924

   @lvyanquan  I have just resolved the conflict. Please help trigger github ci.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2128951367

   Please trigger the CI again,I have removed the snapshot dependency. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "whhe (via GitHub)" <gi...@apache.org>.
whhe commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1639119977


##########
docs/content/docs/connectors/pipeline-connectors/oceanbase.md:
##########
@@ -0,0 +1,343 @@
+---
+title: "OceanBase"
+weight: 7
+type: docs
+aliases:
+- /connectors/pipeline-connectors/oceanbase
+---
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# OceanBase Connector
+
+OceanBase connector can be used as the *Data Sink* of the pipeline, and write data to [OceanBase](https://github.com/oceanbase/oceanbase). This document describes how to set up the OceanBase connector.
+
+## What can the connector do?
+* Create table automatically if not exist
+* Schema change synchronization
+* Data synchronization
+
+## Example
+
+The pipeline for reading data from MySQL and sink to OceanBase can be defined as follows:
+
+```yaml
+source:
+  type: mysql
+  hostname: mysql
+  port: 3306
+  username: mysqluser
+  password: mysqlpw
+  tables: mysql_2_oceanbase_test_17l13vc.\.*
+  server-id: 5400-5404
+  server-time-zone: UTC
+
+sink:
+  type: oceanbase
+  url: jdbc:mysql://oceanbase:2881/test
+  username: root@test
+  password:
+
+pipeline:
+  name: MySQL to OceanBase Pipeline
+  parallelism: 1
+```
+
+## Connector Options
+
+<div class="highlight">
+<table class="colwidths-auto docutils">
+    <thead>
+      <tr>
+        <th>Option</th>
+        <th>Required by Table API</th>
+        <th>Default</th>
+        <th>Type</th>
+        <th>Description</th>
+      </tr>
+    </thead>
+    <tbody>
+    <tr>
+      <td>url</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>JDBC url.</td>
+    </tr>
+    <tr>
+      <td>username</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The username.</td>
+    </tr>
+    <tr>
+      <td>password</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The password.</td>
+    </tr>
+    <tr>
+      <td>schema-name</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The schema name or database name.</td>
+    </tr>
+    <tr>
+      <td>table-name</td>
+      <td>Yes</td>
+      <td></td>
+      <td>String</td>
+      <td>The table name.</td>
+    </tr>
+    <tr>
+      <td>driver-class-name</td>
+      <td>No</td>
+      <td>com.mysql.cj.jdbc.Driver</td>
+      <td>String</td>
+      <td>The driver class name, use 'com.mysql.cj.jdbc.Driver' by default. If other value is set, you need to introduce the driver manually.</td>

Review Comment:
   The MySQL driver is also excluded in flink cdc jar files, so any driver needs to be introduced manually.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2141342325

   Hello everyone, Is there anyone currently following this PR and willing to do a code review? I will continue to follow up on it.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1849992101


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/test/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplierTest.java:
##########
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.DropTableEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.event.TruncateTableEvent;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.connectors.oceanbase.OceanBaseTestUtils;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+import org.apache.flink.cdc.connectors.oceanbase.testutils.OceanBaseContainer;
+import org.apache.flink.cdc.connectors.oceanbase.utils.OceanBaseTestMySQLCatalog;
+
+import org.apache.flink.shaded.guava31.com.google.common.collect.ImmutableMap;
+import org.apache.flink.shaded.guava31.com.google.common.collect.Lists;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.flink.cdc.connectors.oceanbase.table.OceanBaseMySQLModeITCase.NETWORK;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/** Tests for {@link OceanBaseMetadataApplier}. */
+public class OceanBaseMetadataApplierTest {
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplierTest.class);
+
+    private OceanBaseMetadataApplier metadataApplier;
+    private OceanBaseTestMySQLCatalog catalog;
+
+    @ClassRule
+    public static final OceanBaseContainer OB_SERVER =
+            OceanBaseTestUtils.createOceanBaseContainerForJdbc()
+                    .withNetwork(NETWORK)
+                    .withNetworkAliases("oceanbase")
+                    .withLogConsumer(new Slf4jLogConsumer(LOG));
+
+    @Before
+    public void setup() throws Exception {
+        final ImmutableMap<String, String> configMap =
+                ImmutableMap.<String, String>builder()
+                        .put("url", OB_SERVER.getJdbcUrl())
+                        .put("username", OB_SERVER.getUsername())
+                        .put("password", OB_SERVER.getPassword())
+                        .build();
+        OceanBaseConnectorOptions connectorOptions = new OceanBaseConnectorOptions(configMap);
+        metadataApplier = new OceanBaseMetadataApplier(connectorOptions);
+        catalog = new OceanBaseTestMySQLCatalog(connectorOptions);
+        catalog.open();
+    }
+
+    @AfterClass
+    public static void close() {
+        OB_SERVER.close();
+    }
+
+    @Test
+    public void testCreateTable() {
+        TableId tableId = TableId.parse("test.tbl1");
+        Schema schema =
+                Schema.newBuilder()
+                        .physicalColumn("col1", new IntType(false))
+                        .physicalColumn("col2", new BooleanType())
+                        .physicalColumn("col3", new LocalZonedTimestampType())
+                        .primaryKey("col1")
+                        .build();
+        CreateTableEvent createTableEvent = new CreateTableEvent(tableId, schema);
+        metadataApplier.applySchemaChange(createTableEvent);
+
+        OceanBaseTable actualTable =
+                catalog.getTable(tableId.getSchemaName(), tableId.getTableName()).orElse(null);
+        assertNotNull(actualTable);
+
+        List<OceanBaseColumn> columns = new ArrayList<>();
+        columns.add(
+                new OceanBaseColumn.Builder()
+                        .setColumnName("col1")
+                        .setOrdinalPosition(0)
+                        .setDataType("int")
+                        .setNumericScale(0)
+                        .setNullable(false)
+                        .build());
+        columns.add(
+                new OceanBaseColumn.Builder()
+                        .setColumnName("col2")
+                        .setOrdinalPosition(1)
+                        .setDataType("tinyint")
+                        .setNumericScale(0)
+                        .setNullable(true)
+                        .build());
+        columns.add(
+                new OceanBaseColumn.Builder()
+                        .setColumnName("col3")
+                        .setOrdinalPosition(2)
+                        .setDataType("datetime")
+                        .setNullable(true)
+                        .build());
+        OceanBaseTable expectTable =
+                new OceanBaseTable.Builder()
+                        .setDatabaseName(tableId.getSchemaName())
+                        .setTableName(tableId.getTableName())
+                        .setTableType(OceanBaseTable.TableType.PRIMARY_KEY)
+                        .setColumns(columns)
+                        .setTableKeys(schema.primaryKeys())
+                        .build();
+
+        System.out.println(expectTable);
+        System.out.println(actualTable);

Review Comment:
   Removed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1845961978


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseUtils.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BigIntType;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.CharType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DataTypeDefaultVisitor;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.DoubleType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.TinyIntType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utilities for conversion from source table to OceanBase table. */
+public class OceanBaseUtils {
+
+    /** Convert a source table to {@link OceanBaseTable}. */
+    public static OceanBaseTable toOceanBaseTable(TableId tableId, Schema schema) {
+
+        List<Column> columns = schema.getColumns();
+        List<String> primaryKeys = schema.primaryKeys();
+        List<OceanBaseColumn> oceanBaseColumns = new ArrayList<>();
+        for (int i = 0; i < columns.size(); i++) {
+            Column column = columns.get(i);
+            OceanBaseColumn.Builder builder =
+                    new OceanBaseColumn.Builder()
+                            .setColumnName(column.getName())
+                            .setOrdinalPosition(i)
+                            .setColumnComment(column.getComment());
+            toOceanBaseDataType(column, primaryKeys.contains(column.getName()), builder);
+            oceanBaseColumns.add(builder.build());
+        }
+
+        OceanBaseTable.Builder tableBuilder =
+                new OceanBaseTable.Builder()
+                        .setDatabaseName(tableId.getSchemaName())
+                        .setTableName(tableId.getTableName())
+                        .setTableType(
+                                CollectionUtils.isNotEmpty(schema.primaryKeys())
+                                        ? OceanBaseTable.TableType.PRIMARY_KEY
+                                        : OceanBaseTable.TableType.DUPLICATE_KEY)
+                        .setColumns(oceanBaseColumns)
+                        .setTableKeys(schema.primaryKeys())
+                        .setPartitionKeys(schema.partitionKeys())

Review Comment:
   - Since the connector does not yet support OceanBase partitioned tables, first make partitionKeys part of primaryKeys.
   - I added a check that the primary key is not allowed to be null in oceanbase.



##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseMetadataApplier.java:
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.AddColumnEvent;
+import org.apache.flink.cdc.common.event.AlterColumnTypeEvent;
+import org.apache.flink.cdc.common.event.CreateTableEvent;
+import org.apache.flink.cdc.common.event.DropColumnEvent;
+import org.apache.flink.cdc.common.event.RenameColumnEvent;
+import org.apache.flink.cdc.common.event.SchemaChangeEvent;
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.sink.MetadataApplier;
+import org.apache.flink.cdc.common.utils.Preconditions;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalog;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogException;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseCatalogFactory;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import com.oceanbase.connector.flink.OceanBaseConnectorOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Supports {@link OceanBaseDataSink} to schema evolution. */
+public class OceanBaseMetadataApplier implements MetadataApplier {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseMetadataApplier.class);
+
+    private final OceanBaseCatalog catalog;
+
+    public OceanBaseMetadataApplier(OceanBaseConnectorOptions connectorOptions) {
+        try {
+            this.catalog = OceanBaseCatalogFactory.createOceanBaseCatalog(connectorOptions);
+            catalog.open();
+        } catch (Exception e) {
+            throw new OceanBaseCatalogException("Fail to init OceanBaseMetadataApplier.", e);
+        }
+    }
+
+    @Override
+    public void applySchemaChange(SchemaChangeEvent event) {

Review Comment:
   Added.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2482445463

   @lvyanquan I fixed the above comments, please take a look again.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on code in PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#discussion_r1845962190


##########
flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-oceanbase/src/main/java/org/apache/flink/cdc/connectors/oceanbase/sink/OceanBaseUtils.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.connectors.oceanbase.sink;
+
+import org.apache.flink.cdc.common.event.TableId;
+import org.apache.flink.cdc.common.schema.Column;
+import org.apache.flink.cdc.common.schema.Schema;
+import org.apache.flink.cdc.common.types.BigIntType;
+import org.apache.flink.cdc.common.types.BooleanType;
+import org.apache.flink.cdc.common.types.CharType;
+import org.apache.flink.cdc.common.types.DataType;
+import org.apache.flink.cdc.common.types.DataTypeDefaultVisitor;
+import org.apache.flink.cdc.common.types.DateType;
+import org.apache.flink.cdc.common.types.DecimalType;
+import org.apache.flink.cdc.common.types.DoubleType;
+import org.apache.flink.cdc.common.types.FloatType;
+import org.apache.flink.cdc.common.types.IntType;
+import org.apache.flink.cdc.common.types.LocalZonedTimestampType;
+import org.apache.flink.cdc.common.types.SmallIntType;
+import org.apache.flink.cdc.common.types.TimestampType;
+import org.apache.flink.cdc.common.types.TinyIntType;
+import org.apache.flink.cdc.common.types.VarCharType;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseColumn;
+import org.apache.flink.cdc.connectors.oceanbase.catalog.OceanBaseTable;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utilities for conversion from source table to OceanBase table. */
+public class OceanBaseUtils {
+
+    /** Convert a source table to {@link OceanBaseTable}. */
+    public static OceanBaseTable toOceanBaseTable(TableId tableId, Schema schema) {
+
+        List<Column> columns = schema.getColumns();
+        List<String> primaryKeys = schema.primaryKeys();
+        List<OceanBaseColumn> oceanBaseColumns = new ArrayList<>();
+        for (int i = 0; i < columns.size(); i++) {
+            Column column = columns.get(i);
+            OceanBaseColumn.Builder builder =
+                    new OceanBaseColumn.Builder()
+                            .setColumnName(column.getName())
+                            .setOrdinalPosition(i)
+                            .setColumnComment(column.getComment());

Review Comment:
   Added.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "yuanoOo (via GitHub)" <gi...@apache.org>.
yuanoOo commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2490158237

   @lvyanquan I fixed the above comments, please take a look again.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [FLINK-34545][cdc-pipeline-connector]Add OceanBase pipeline connector to Flink CDC [flink-cdc]

Posted by "lvyanquan (via GitHub)" <gi...@apache.org>.
lvyanquan commented on PR #3360:
URL: https://github.com/apache/flink-cdc/pull/3360#issuecomment-2472981149

   Thanks for @yuanoOo's contribution, I left some comments.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@flink.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org