diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml
index fbe37acece5..e971e95a4af 100644
--- a/.github/workflows/backend.yml
+++ b/.github/workflows/backend.yml
@@ -736,6 +736,30 @@ jobs:
         env:
           MAVEN_OPTS: -Xmx4096m
 
+  jdbc-connectors-it-part-4:
+    needs: [ changes, sanity-check ]
+    if: needs.changes.outputs.api == 'true'
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        java: [ '8', '11' ]
+        os: [ 'ubuntu-latest' ]
+    timeout-minutes: 90
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up JDK ${{ matrix.java }}
+        uses: actions/setup-java@v3
+        with:
+          java-version: ${{ matrix.java }}
+          distribution: 'temurin'
+          cache: 'maven'
+      - name: run jdbc connectors integration test (part-4)
+        if: needs.changes.outputs.api == 'true'
+        run: |
+          ./mvnw -B -T 1C verify -DskipUT=true -DskipIT=false -D"license.skipAddThirdParty"=true --no-snapshot-updates -pl :connector-jdbc-e2e-part-4 -am -Pci
+        env:
+          MAVEN_OPTS: -Xmx4096m
+
   kafka-connector-it:
     needs: [ changes, sanity-check ]
     if: needs.changes.outputs.api == 'true'
diff --git a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/CatalogTable.java b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/CatalogTable.java
index 3aa50335910..1be6de02841 100644
--- a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/CatalogTable.java
+++ b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/CatalogTable.java
@@ -38,6 +38,8 @@ public final class CatalogTable implements Serializable {
 
     private final String comment;
 
+    private final String catalogName;
+
     public static CatalogTable of(
             TableIdentifier tableId,
             TableSchema tableSchema,
@@ -47,17 +49,38 @@ public static CatalogTable of(
         return new CatalogTable(tableId, tableSchema, options, partitionKeys, comment);
     }
 
+    public static CatalogTable of(
+            TableIdentifier tableId,
+            TableSchema tableSchema,
+            Map<String, String> options,
+            List<String> partitionKeys,
+            String comment,
+            String catalogName) {
+        return new CatalogTable(tableId, tableSchema, options, partitionKeys, comment, catalogName);
+    }
+
     private CatalogTable(
             TableIdentifier tableId,
             TableSchema tableSchema,
             Map<String, String> options,
             List<String> partitionKeys,
             String comment) {
+        this(tableId, tableSchema, options, partitionKeys, comment, "");
+    }
+
+    private CatalogTable(
+            TableIdentifier tableId,
+            TableSchema tableSchema,
+            Map<String, String> options,
+            List<String> partitionKeys,
+            String comment,
+            String catalogName) {
         this.tableId = tableId;
         this.tableSchema = tableSchema;
         this.options = options;
         this.partitionKeys = partitionKeys;
         this.comment = comment;
+        this.catalogName = catalogName;
     }
 
     public TableIdentifier getTableId() {
@@ -80,6 +103,10 @@ public String getComment() {
         return comment;
     }
 
+    public String getCatalogName() {
+        return catalogName;
+    }
+
     @Override
     public String toString() {
         return "CatalogTable{"
diff --git a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/Column.java b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/Column.java
index b528996a3ae..bec10b3d758 100644
--- a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/Column.java
+++ b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/Column.java
@@ -23,6 +23,7 @@
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.Map;
 
 /**
  * Represent the column of {@link TableSchema}.
@@ -54,6 +55,24 @@ public abstract class Column implements Serializable {
 
     protected final String comment;
 
+    /** Field type in the database * */
+    protected final String sourceType;
+
+    /** Unsigned bit * */
+    protected final boolean isUnsigned;
+
+    /** Whether to use the 0 bit * */
+    protected final boolean isZeroFill;
+
+    /** Bit length * */
+    protected final Long bitLen;
+
+    /** integer may be cross the border * */
+    protected final Long longColumnLength;
+
+    /** your options * */
+    protected final Map<String, Object> options;
+
     protected Column(
             String name,
             SeaTunnelDataType<?> dataType,
@@ -61,12 +80,46 @@ protected Column(
             boolean nullable,
             Object defaultValue,
             String comment) {
+        this(
+                name,
+                dataType,
+                columnLength,
+                nullable,
+                defaultValue,
+                comment,
+                null,
+                false,
+                false,
+                null,
+                0L,
+                null);
+    }
+
+    protected Column(
+            String name,
+            SeaTunnelDataType<?> dataType,
+            Integer columnLength,
+            boolean nullable,
+            Object defaultValue,
+            String comment,
+            String sourceType,
+            boolean isUnsigned,
+            boolean isZeroFill,
+            Long bitLen,
+            Long longColumnLength,
+            Map<String, Object> options) {
         this.name = name;
         this.dataType = dataType;
         this.columnLength = columnLength;
         this.nullable = nullable;
         this.defaultValue = defaultValue;
         this.comment = comment;
+        this.sourceType = sourceType;
+        this.isUnsigned = isUnsigned;
+        this.isZeroFill = isZeroFill;
+        this.bitLen = bitLen;
+        this.longColumnLength = longColumnLength;
+        this.options = options;
     }
 
     /**
diff --git a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/PhysicalColumn.java b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/PhysicalColumn.java
index bc379e35546..164752d4686 100644
--- a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/PhysicalColumn.java
+++ b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/catalog/PhysicalColumn.java
@@ -23,6 +23,8 @@
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
+import java.util.Map;
+
 /** Representation of a physical column. */
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
@@ -38,6 +40,34 @@ protected PhysicalColumn(
         super(name, dataType, columnLength, nullable, defaultValue, comment);
     }
 
+    protected PhysicalColumn(
+            String name,
+            SeaTunnelDataType<?> dataType,
+            Integer columnLength,
+            boolean nullable,
+            Object defaultValue,
+            String comment,
+            String sourceType,
+            boolean isUnsigned,
+            boolean isZeroFill,
+            Long bitLen,
+            Long longColumnLength,
+            Map<String, Object> options) {
+        super(
+                name,
+                dataType,
+                columnLength,
+                nullable,
+                defaultValue,
+                comment,
+                sourceType,
+                isUnsigned,
+                isZeroFill,
+                bitLen,
+                longColumnLength,
+                options);
+    }
+
     public static PhysicalColumn of(
             String name,
             SeaTunnelDataType<?> dataType,
@@ -48,6 +78,34 @@ public static PhysicalColumn of(
         return new PhysicalColumn(name, dataType, columnLength, nullable, defaultValue, comment);
     }
 
+    public static PhysicalColumn of(
+            String name,
+            SeaTunnelDataType<?> dataType,
+            Integer columnLength,
+            boolean nullable,
+            Object defaultValue,
+            String comment,
+            String sourceType,
+            boolean isUnsigned,
+            boolean isZeroFill,
+            Long bitLen,
+            Map<String, Object> options,
+            Long longColumnLength) {
+        return new PhysicalColumn(
+                name,
+                dataType,
+                columnLength,
+                nullable,
+                defaultValue,
+                comment,
+                sourceType,
+                isUnsigned,
+                isZeroFill,
+                bitLen,
+                longColumnLength,
+                options);
+    }
+
     @Override
     public boolean isPhysical() {
         return true;
@@ -55,11 +113,35 @@ public boolean isPhysical() {
 
     @Override
     public Column copy(SeaTunnelDataType<?> newType) {
-        return PhysicalColumn.of(name, newType, columnLength, nullable, defaultValue, comment);
+        return PhysicalColumn.of(
+                name,
+                newType,
+                columnLength,
+                nullable,
+                defaultValue,
+                comment,
+                sourceType,
+                isUnsigned,
+                isZeroFill,
+                bitLen,
+                options,
+                longColumnLength);
     }
 
     @Override
     public Column copy() {
-        return PhysicalColumn.of(name, dataType, columnLength, nullable, defaultValue, comment);
+        return PhysicalColumn.of(
+                name,
+                dataType,
+                columnLength,
+                nullable,
+                defaultValue,
+                comment,
+                sourceType,
+                isUnsigned,
+                isZeroFill,
+                bitLen,
+                options,
+                longColumnLength);
     }
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/AbstractJdbcCatalog.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/AbstractJdbcCatalog.java
index 28da8143252..66e23a2f21e 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/AbstractJdbcCatalog.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/AbstractJdbcCatalog.java
@@ -64,10 +64,16 @@ public abstract class AbstractJdbcCatalog implements Catalog {
     protected final String suffix;
     protected final String defaultUrl;
 
+    protected final Optional<String> defaultSchema;
+
     protected Connection defaultConnection;
 
     public AbstractJdbcCatalog(
-            String catalogName, String username, String pwd, JdbcUrlUtil.UrlInfo urlInfo) {
+            String catalogName,
+            String username,
+            String pwd,
+            JdbcUrlUtil.UrlInfo urlInfo,
+            String defaultSchema) {
 
         checkArgument(StringUtils.isNotBlank(username));
         urlInfo.getDefaultDatabase()
@@ -78,10 +84,10 @@ public AbstractJdbcCatalog(
         this.defaultDatabase = urlInfo.getDefaultDatabase().get();
         this.username = username;
         this.pwd = pwd;
-        String baseUrl = urlInfo.getUrlWithoutDatabase();
-        this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
+        this.baseUrl = urlInfo.getUrlWithoutDatabase();
         this.defaultUrl = urlInfo.getOrigin();
         this.suffix = urlInfo.getSuffix();
+        this.defaultSchema = Optional.ofNullable(defaultSchema);
     }
 
     @Override
@@ -246,6 +252,13 @@ public void createTable(TablePath tablePath, CatalogTable table, boolean ignoreI
         if (!databaseExists(tablePath.getDatabaseName())) {
             throw new DatabaseNotExistException(catalogName, tablePath.getDatabaseName());
         }
+        if (defaultSchema.isPresent()) {
+            tablePath =
+                    new TablePath(
+                            tablePath.getDatabaseName(),
+                            defaultSchema.get(),
+                            tablePath.getTableName());
+        }
         if (!createTableInternal(tablePath, table) && !ignoreIfExists) {
             throw new TableAlreadyExistException(catalogName, tablePath);
         }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/JdbcCatalogOptions.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/JdbcCatalogOptions.java
index 3a664079aa5..712eefacb84 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/JdbcCatalogOptions.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/JdbcCatalogOptions.java
@@ -43,6 +43,27 @@ public interface JdbcCatalogOptions {
                     .noDefaultValue()
                     .withDescription("Password to use when connecting to the database server.");
 
+    Option<String> SCHEMA =
+            Options.key("schema")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription(
+                            "for databases that support the schema parameter, give it priority.");
+
     OptionRule.Builder BASE_RULE =
-            OptionRule.builder().required(BASE_URL).required(USERNAME, PASSWORD);
+            OptionRule.builder().required(BASE_URL).required(USERNAME, PASSWORD).optional(SCHEMA);
+
+    Option<String> TABLE_PREFIX =
+            Options.key("tablePrefix")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription(
+                            "The table prefix name added when the table is automatically created");
+
+    Option<String> TABLE_SUFFIX =
+            Options.key("tableSuffix")
+                    .stringType()
+                    .noDefaultValue()
+                    .withDescription(
+                            "The table suffix name added when the table is automatically created");
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalog.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalog.java
index 463c7a8bf76..267a68f0eef 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalog.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalog.java
@@ -35,6 +35,7 @@
 import com.mysql.cj.MysqlType;
 import com.mysql.cj.jdbc.result.ResultSetImpl;
 import com.mysql.cj.util.StringUtils;
+import lombok.extern.slf4j.Slf4j;
 
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
@@ -48,14 +49,18 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+@Slf4j
 public class MySqlCatalog extends AbstractJdbcCatalog {
 
     protected static final Set<String> SYS_DATABASES = new HashSet<>(4);
+    private final String SELECT_COLUMNS =
+            "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME ='%s'";
 
     static {
         SYS_DATABASES.add("information_schema");
@@ -68,7 +73,7 @@ public class MySqlCatalog extends AbstractJdbcCatalog {
 
     public MySqlCatalog(
             String catalogName, String username, String pwd, JdbcUrlUtil.UrlInfo urlInfo) {
-        super(catalogName, username, pwd, urlInfo);
+        super(catalogName, username, pwd, urlInfo, null);
         this.connectionMap = new ConcurrentHashMap<>();
     }
 
@@ -127,7 +132,8 @@ public List<String> listTables(String databaseName)
         }
 
         String dbUrl = getUrlFromDatabaseName(databaseName);
-        try (PreparedStatement ps = getConnection(dbUrl).prepareStatement("SHOW TABLES;")) {
+        Connection connection = getConnection(dbUrl);
+        try (PreparedStatement ps = connection.prepareStatement("SHOW TABLES;")) {
 
             ResultSet rs = ps.executeQuery();
 
@@ -155,40 +161,21 @@ public CatalogTable getTable(TablePath tablePath)
         Connection conn = getConnection(dbUrl);
         try {
             DatabaseMetaData metaData = conn.getMetaData();
+
             Optional<PrimaryKey> primaryKey =
                     getPrimaryKey(metaData, tablePath.getDatabaseName(), tablePath.getTableName());
             List<ConstraintKey> constraintKeys =
                     getConstraintKeys(
                             metaData, tablePath.getDatabaseName(), tablePath.getTableName());
-            Map<String, Object> columnsDefaultValue = getColumnsDefaultValue(tablePath, conn);
-
-            try (PreparedStatement ps =
-                    conn.prepareStatement(
-                            String.format(
-                                    "SELECT * FROM %s WHERE 1 = 0;",
-                                    tablePath.getFullNameWithQuoted()))) {
-                ResultSetMetaData tableMetaData = ps.getMetaData();
-                TableSchema.Builder builder = TableSchema.builder();
+            String sql =
+                    String.format(
+                            SELECT_COLUMNS, tablePath.getDatabaseName(), tablePath.getTableName());
+            try (PreparedStatement ps = conn.prepareStatement(sql);
+                    ResultSet resultSet = ps.executeQuery(); ) {
 
-                // add column
-                for (int i = 1; i <= tableMetaData.getColumnCount(); i++) {
-                    String columnName = tableMetaData.getColumnName(i);
-                    SeaTunnelDataType<?> type = fromJdbcType(tableMetaData, i);
-                    int columnDisplaySize = tableMetaData.getColumnDisplaySize(i);
-                    String comment = tableMetaData.getColumnLabel(i);
-                    boolean isNullable =
-                            tableMetaData.isNullable(i) == ResultSetMetaData.columnNullable;
-                    Object defaultValue = columnsDefaultValue.get(columnName);
-
-                    PhysicalColumn physicalColumn =
-                            PhysicalColumn.of(
-                                    columnName,
-                                    type,
-                                    columnDisplaySize,
-                                    isNullable,
-                                    defaultValue,
-                                    comment);
-                    builder.column(physicalColumn);
+                TableSchema.Builder builder = TableSchema.builder();
+                while (resultSet.next()) {
+                    buildTable(resultSet, builder);
                 }
                 // add primary key
                 primaryKey.ifPresent(builder::primaryKey);
@@ -202,7 +189,8 @@ public CatalogTable getTable(TablePath tablePath)
                         builder.build(),
                         buildConnectorOptions(tablePath),
                         Collections.emptyList(),
-                        "");
+                        "",
+                        "mysql");
             }
 
         } catch (Exception e) {
@@ -211,6 +199,67 @@ public CatalogTable getTable(TablePath tablePath)
         }
     }
 
+    private void buildTable(ResultSet resultSet, TableSchema.Builder builder) throws SQLException {
+        String columnName = resultSet.getString("COLUMN_NAME");
+        String sourceType = resultSet.getString("COLUMN_TYPE");
+        String typeName = resultSet.getString("DATA_TYPE").toUpperCase();
+        int precision = resultSet.getInt("NUMERIC_PRECISION");
+        int scale = resultSet.getInt("NUMERIC_SCALE");
+        long columnLength = resultSet.getLong("CHARACTER_MAXIMUM_LENGTH");
+        long octetLength = resultSet.getLong("CHARACTER_OCTET_LENGTH");
+        if (sourceType.toLowerCase(Locale.ROOT).contains("unsigned")) {
+            typeName += "_UNSIGNED";
+        }
+        SeaTunnelDataType<?> type = fromJdbcType(typeName, precision, scale);
+        String comment = resultSet.getString("COLUMN_COMMENT");
+        Object defaultValue = resultSet.getObject("COLUMN_DEFAULT");
+        String isNullableStr = resultSet.getString("IS_NULLABLE");
+        boolean isNullable = isNullableStr.equals("YES");
+        long bitLen = 0;
+        MysqlType mysqlType = MysqlType.valueOf(typeName);
+        switch (mysqlType) {
+            case BIT:
+                bitLen = precision;
+                break;
+            case CHAR:
+            case VARCHAR:
+                columnLength = octetLength;
+                break;
+            case BINARY:
+            case VARBINARY:
+                // Uniform conversion to bits
+                bitLen = octetLength * 4 * 8L;
+                break;
+            case BLOB:
+            case TINYBLOB:
+            case MEDIUMBLOB:
+            case LONGBLOB:
+                bitLen = columnLength << 3;
+                break;
+            case JSON:
+                columnLength = 4 * 1024 * 1024 * 1024L;
+                break;
+            default:
+                break;
+        }
+
+        PhysicalColumn physicalColumn =
+                PhysicalColumn.of(
+                        columnName,
+                        type,
+                        0,
+                        isNullable,
+                        defaultValue,
+                        comment,
+                        sourceType,
+                        sourceType.contains("unsigned"),
+                        sourceType.contains("zerofill"),
+                        bitLen,
+                        null,
+                        columnLength);
+        builder.column(physicalColumn);
+    }
+
     public static Map<String, Object> getColumnsDefaultValue(TablePath tablePath, Connection conn) {
         StringBuilder queryBuf = new StringBuilder("SHOW FULL COLUMNS FROM ");
         queryBuf.append(StringUtils.quoteIdentifier(tablePath.getTableName(), "`", false));
@@ -235,13 +284,16 @@ public static Map<String, Object> getColumnsDefaultValue(TablePath tablePath, Co
     }
 
     // todo: If the origin source is mysql, we can directly use create table like to create the
-    // target table?
     @Override
     protected boolean createTableInternal(TablePath tablePath, CatalogTable table)
             throws CatalogException {
         String dbUrl = getUrlFromDatabaseName(tablePath.getDatabaseName());
-        String createTableSql = MysqlCreateTableSqlBuilder.builder(tablePath, table).build();
-        try (PreparedStatement ps = getConnection(dbUrl).prepareStatement(createTableSql)) {
+
+        String createTableSql =
+                MysqlCreateTableSqlBuilder.builder(tablePath, table).build(table.getCatalogName());
+        Connection connection = getConnection(dbUrl);
+        log.info("create table sql: {}", createTableSql);
+        try (PreparedStatement ps = connection.prepareStatement(createTableSql)) {
             return ps.execute();
         } catch (Exception e) {
             throw new CatalogException(
@@ -252,11 +304,10 @@ protected boolean createTableInternal(TablePath tablePath, CatalogTable table)
     @Override
     protected boolean dropTableInternal(TablePath tablePath) throws CatalogException {
         String dbUrl = getUrlFromDatabaseName(tablePath.getDatabaseName());
+        Connection connection = getConnection(dbUrl);
         try (PreparedStatement ps =
-                getConnection(dbUrl)
-                        .prepareStatement(
-                                String.format(
-                                        "DROP TABLE %s IF EXIST;", tablePath.getFullName()))) {
+                connection.prepareStatement(
+                        String.format("DROP TABLE IF EXISTS %s;", tablePath.getFullName()))) {
             // Will there exist concurrent drop for one table?
             return ps.execute();
         } catch (SQLException e) {
@@ -309,6 +360,14 @@ private SeaTunnelDataType<?> fromJdbcType(ResultSetMetaData metadata, int colInd
         return new MysqlDataTypeConvertor().toSeaTunnelType(mysqlType, dataTypeProperties);
     }
 
+    private SeaTunnelDataType<?> fromJdbcType(String typeName, int precision, int scale) {
+        MysqlType mysqlType = MysqlType.getByName(typeName);
+        Map<String, Object> dataTypeProperties = new HashMap<>();
+        dataTypeProperties.put(MysqlDataTypeConvertor.PRECISION, precision);
+        dataTypeProperties.put(MysqlDataTypeConvertor.SCALE, scale);
+        return new MysqlDataTypeConvertor().toSeaTunnelType(mysqlType, dataTypeProperties);
+    }
+
     @SuppressWarnings("MagicNumber")
     private Map<String, String> buildConnectorOptions(TablePath tablePath) {
         Map<String, String> options = new HashMap<>(8);
@@ -321,6 +380,7 @@ private Map<String, String> buildConnectorOptions(TablePath tablePath) {
     }
 
     private String getUrlFromDatabaseName(String databaseName) {
-        return baseUrl + databaseName + suffix;
+        String url = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
+        return url + databaseName + suffix;
     }
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogFactory.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogFactory.java
index 014af151c8e..8d3a76bed69 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogFactory.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogFactory.java
@@ -37,9 +37,11 @@
 @AutoService(Factory.class)
 public class MySqlCatalogFactory implements CatalogFactory {
 
+    public static final String IDENTIFIER = "MySQL";
+
     @Override
     public String factoryIdentifier() {
-        return "MySQL";
+        return IDENTIFIER;
     }
 
     @Override
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlCreateTableSqlBuilder.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlCreateTableSqlBuilder.java
index 9a015ca7395..cec934bcb01 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlCreateTableSqlBuilder.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlCreateTableSqlBuilder.java
@@ -23,10 +23,14 @@
 import org.apache.seatunnel.api.table.catalog.PrimaryKey;
 import org.apache.seatunnel.api.table.catalog.TablePath;
 import org.apache.seatunnel.api.table.catalog.TableSchema;
+import org.apache.seatunnel.api.table.type.DecimalType;
+import org.apache.seatunnel.api.table.type.SqlType;
 
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 
+import com.mysql.cj.MysqlType;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -111,12 +115,12 @@ public MysqlCreateTableSqlBuilder comment(String comment) {
         return this;
     }
 
-    public String build() {
+    public String build(String catalogName) {
         List<String> sqls = new ArrayList<>();
         sqls.add(
                 String.format(
                         "CREATE TABLE IF NOT EXISTS %s (\n%s\n)",
-                        tableName, buildColumnsIdentifySql()));
+                        tableName, buildColumnsIdentifySql(catalogName)));
         if (engine != null) {
             sqls.add("ENGINE = " + engine);
         }
@@ -132,10 +136,10 @@ public String build() {
         return String.join(" ", sqls) + ";";
     }
 
-    private String buildColumnsIdentifySql() {
+    private String buildColumnsIdentifySql(String catalogName) {
         List<String> columnSqls = new ArrayList<>();
         for (Column column : columns) {
-            columnSqls.add("\t" + buildColumnIdentifySql(column));
+            columnSqls.add("\t" + buildColumnIdentifySql(column, catalogName));
         }
         if (primaryKey != null) {
             columnSqls.add("\t" + buildPrimaryKeySql());
@@ -145,22 +149,79 @@ private String buildColumnsIdentifySql() {
                 if (StringUtils.isBlank(constraintKey.getConstraintName())) {
                     continue;
                 }
-                columnSqls.add("\t" + buildConstraintKeySql(constraintKey));
+                //                columnSqls.add("\t" + buildConstraintKeySql(constraintKey));
             }
         }
         return String.join(", \n", columnSqls);
     }
 
-    private String buildColumnIdentifySql(Column column) {
+    private String buildColumnIdentifySql(Column column, String catalogName) {
         final List<String> columnSqls = new ArrayList<>();
-        // Column name
         columnSqls.add(column.getName());
-        // Column type
-        columnSqls.add(
-                mysqlDataTypeConvertor.toConnectorType(column.getDataType(), null).getName());
-        // Column length
-        if (column.getColumnLength() != null) {
-            columnSqls.add("(" + column.getColumnLength() + ")");
+        if (StringUtils.equals(catalogName, "mysql")) {
+            columnSqls.add(column.getSourceType());
+        } else {
+            // Column name
+            SqlType dataType = column.getDataType().getSqlType();
+            boolean isBytes = StringUtils.equals(dataType.name(), SqlType.BYTES.name());
+            Long columnLength = column.getLongColumnLength();
+            Long bitLen = column.getBitLen();
+            if (isBytes) {
+                if (bitLen >= 0 && bitLen <= 64) {
+                    columnSqls.add(MysqlType.BIT.getName());
+                    columnSqls.add("(" + (bitLen == 0 ? 1 : bitLen) + ")");
+                } else {
+                    bitLen = bitLen == -1 ? bitLen : bitLen >> 3;
+                    if (bitLen >= 0 && bitLen <= 255) {
+                        columnSqls.add(MysqlType.TINYBLOB.getName());
+                    } else if (bitLen <= 16383) {
+                        columnSqls.add(MysqlType.BLOB.getName());
+                    } else if (bitLen <= 16777215) {
+                        columnSqls.add(MysqlType.MEDIUMBLOB.getName());
+                    } else {
+                        columnSqls.add(MysqlType.LONGBLOB.getName());
+                    }
+                }
+            } else {
+                if (columnLength >= 16383 && columnLength <= 65535) {
+                    columnSqls.add(MysqlType.TEXT.getName());
+                } else if (columnLength >= 65535 && columnLength <= 16777215) {
+                    columnSqls.add(MysqlType.MEDIUMTEXT.getName());
+                } else if (columnLength > 16777215 || columnLength == -1) {
+                    columnSqls.add(MysqlType.LONGTEXT.getName());
+                } else {
+                    // Column type
+                    columnSqls.add(
+                            mysqlDataTypeConvertor
+                                    .toConnectorType(column.getDataType(), null)
+                                    .getName());
+                    // Column length
+                    // add judge is need column legth
+                    if (column.getColumnLength() != null) {
+                        final String name =
+                                mysqlDataTypeConvertor
+                                        .toConnectorType(column.getDataType(), null)
+                                        .getName();
+                        String fieSql = "";
+                        List<String> list = new ArrayList<>();
+                        list.add(MysqlType.VARCHAR.getName());
+                        list.add(MysqlType.CHAR.getName());
+                        list.add(MysqlType.BIGINT.getName());
+                        list.add(MysqlType.INT.getName());
+                        if (StringUtils.equals(name, MysqlType.DECIMAL.getName())) {
+                            DecimalType decimalType = (DecimalType) column.getDataType();
+                            fieSql =
+                                    String.format(
+                                            "(%d, %d)",
+                                            decimalType.getPrecision(), decimalType.getScale());
+                            columnSqls.add(fieSql);
+                        } else if (list.contains(name)) {
+                            fieSql = "(" + column.getLongColumnLength() + ")";
+                            columnSqls.add(fieSql);
+                        }
+                    }
+                }
+            }
         }
         // nullable
         if (column.isNullable()) {
@@ -168,14 +229,11 @@ private String buildColumnIdentifySql(Column column) {
         } else {
             columnSqls.add("NOT NULL");
         }
-        // default value
-        if (column.getDefaultValue() != null) {
-            columnSqls.add("DEFAULT '" + column.getDefaultValue() + "'");
-        }
-        // comment
+        // TODO support default value
         if (column.getComment() != null) {
             columnSqls.add("COMMENT '" + column.getComment() + "'");
         }
+
         return String.join(" ", columnSqls);
     }
 
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlDataTypeConvertor.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlDataTypeConvertor.java
index e30025c4e71..16e5b87d303 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlDataTypeConvertor.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MysqlDataTypeConvertor.java
@@ -168,7 +168,9 @@ public MysqlType toConnectorType(
         SqlType sqlType = seaTunnelDataType.getSqlType();
         // todo: verify
         switch (sqlType) {
-            case ARRAY:
+                // from pg array not support
+                //            case ARRAY:
+                //                return MysqlType.ENUM;
             case MAP:
             case ROW:
             case STRING:
@@ -196,9 +198,9 @@ public MysqlType toConnectorType(
             case DATE:
                 return MysqlType.DATE;
             case TIME:
-                return MysqlType.DATETIME;
+                return MysqlType.TIME;
             case TIMESTAMP:
-                return MysqlType.TIMESTAMP;
+                return MysqlType.DATETIME;
             default:
                 throw new JdbcConnectorException(
                         CommonErrorCode.UNSUPPORTED_DATA_TYPE,
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalog.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalog.java
new file mode 100644
index 00000000000..261f4f7fb6f
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalog.java
@@ -0,0 +1,361 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.oracle;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.ConstraintKey;
+import org.apache.seatunnel.api.table.catalog.PhysicalColumn;
+import org.apache.seatunnel.api.table.catalog.PrimaryKey;
+import org.apache.seatunnel.api.table.catalog.TableIdentifier;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.api.table.catalog.TableSchema;
+import org.apache.seatunnel.api.table.catalog.exception.CatalogException;
+import org.apache.seatunnel.api.table.catalog.exception.DatabaseNotExistException;
+import org.apache.seatunnel.api.table.catalog.exception.TableNotExistException;
+import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.AbstractJdbcCatalog;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_BFILE;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_BLOB;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_CHAR;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_CLOB;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_LONG;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_LONG_RAW;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_NCHAR;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_NCLOB;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_NVARCHAR2;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_RAW;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_ROWID;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleDataTypeConvertor.ORACLE_VARCHAR2;
+
+@Slf4j
+public class OracleCatalog extends AbstractJdbcCatalog {
+    private static final OracleDataTypeConvertor DATA_TYPE_CONVERTOR =
+            new OracleDataTypeConvertor();
+    private static final List<String> EXCLUDED_SCHEMAS =
+            Collections.unmodifiableList(
+                    Arrays.asList(
+                            "APPQOSSYS",
+                            "AUDSYS",
+                            "CTXSYS",
+                            "DVSYS",
+                            "DBSFWUSER",
+                            "DBSNMP",
+                            "GSMADMIN_INTERNAL",
+                            "LBACSYS",
+                            "MDSYS",
+                            "OJVMSYS",
+                            "OLAPSYS",
+                            "ORDDATA",
+                            "ORDSYS",
+                            "OUTLN",
+                            "SYS",
+                            "SYSTEM",
+                            "WMSYS",
+                            "XDB",
+                            "EXFSYS",
+                            "SYSMAN"));
+
+    private static final String SELECT_COLUMNS_SQL =
+            "SELECT\n"
+                    + "    cols.COLUMN_NAME,\n"
+                    + "    CASE \n"
+                    + "        WHEN cols.data_type LIKE 'INTERVAL%%' THEN 'INTERVAL'\n"
+                    + "        ELSE REGEXP_SUBSTR(cols.data_type, '^[^(]+')\n"
+                    + "    END as TYPE_NAME,\n"
+                    + "    cols.data_type || \n"
+                    + "        CASE \n"
+                    + "            WHEN cols.data_type IN ('VARCHAR2', 'CHAR') THEN '(' || cols.data_length || ')'\n"
+                    + "            WHEN cols.data_type IN ('NUMBER') AND cols.data_precision IS NOT NULL AND cols.data_scale IS NOT NULL THEN '(' || cols.data_precision || ', ' || cols.data_scale || ')'\n"
+                    + "            WHEN cols.data_type IN ('NUMBER') AND cols.data_precision IS NOT NULL AND cols.data_scale IS NULL THEN '(' || cols.data_precision || ')'\n"
+                    + "            WHEN cols.data_type IN ('RAW') THEN '(' || cols.data_length || ')'\n"
+                    + "        END AS FULL_TYPE_NAME,\n"
+                    + "    cols.data_length AS COLUMN_LENGTH,\n"
+                    + "    cols.data_precision AS COLUMN_PRECISION,\n"
+                    + "    cols.data_scale AS COLUMN_SCALE,\n"
+                    + "    com.comments AS COLUMN_COMMENT,\n"
+                    + "    cols.data_default AS DEFAULT_VALUE,\n"
+                    + "    CASE cols.nullable WHEN 'N' THEN 'NO' ELSE 'YES' END AS IS_NULLABLE\n"
+                    + "FROM\n"
+                    + "    all_tab_columns cols\n"
+                    + "LEFT JOIN \n"
+                    + "    all_col_comments com ON cols.table_name = com.table_name AND cols.column_name = com.column_name AND cols.owner = com.owner\n"
+                    + "WHERE \n"
+                    + "    cols.owner = '%s'\n"
+                    + "    AND cols.table_name = '%s'\n"
+                    + "ORDER BY \n"
+                    + "    cols.column_id \n";
+
+    public OracleCatalog(
+            String catalogName,
+            String username,
+            String pwd,
+            JdbcUrlUtil.UrlInfo urlInfo,
+            String defaultSchema) {
+        super(catalogName, username, pwd, urlInfo, defaultSchema);
+    }
+
+    @Override
+    public List<String> listDatabases() throws CatalogException {
+        try (PreparedStatement ps =
+                defaultConnection.prepareStatement("SELECT name FROM v$database")) {
+
+            List<String> databases = new ArrayList<>();
+            ResultSet rs = ps.executeQuery();
+
+            while (rs.next()) {
+                String databaseName = rs.getString(1);
+                databases.add(databaseName);
+            }
+            return databases;
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed listing database in catalog %s", this.catalogName), e);
+        }
+    }
+
+    @Override
+    protected boolean createTableInternal(TablePath tablePath, CatalogTable table)
+            throws CatalogException {
+        String createTableSql = new OracleCreateTableSqlBuilder(table).build(tablePath);
+        String[] createTableSqls = createTableSql.split(";");
+        for (String sql : createTableSqls) {
+            log.info("create table sql: {}", sql);
+            try (PreparedStatement ps = defaultConnection.prepareStatement(sql)) {
+                ps.execute();
+            } catch (Exception e) {
+                throw new CatalogException(
+                        String.format("Failed creating table %s", tablePath.getFullName()), e);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean dropTableInternal(TablePath tablePath) throws CatalogException {
+        return false;
+    }
+
+    @Override
+    protected boolean createDatabaseInternal(String databaseName) {
+        return false;
+    }
+
+    @Override
+    protected boolean dropDatabaseInternal(String databaseName) throws CatalogException {
+        return false;
+    }
+
+    @Override
+    public boolean tableExists(TablePath tablePath) throws CatalogException {
+        try {
+            return databaseExists(tablePath.getDatabaseName())
+                    && listTables(tablePath.getDatabaseName())
+                            .contains(tablePath.getSchemaAndTableName().toUpperCase());
+        } catch (DatabaseNotExistException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public List<String> listTables(String databaseName)
+            throws CatalogException, DatabaseNotExistException {
+        if (!databaseExists(databaseName)) {
+            throw new DatabaseNotExistException(this.catalogName, databaseName);
+        }
+
+        try (PreparedStatement ps =
+                defaultConnection.prepareStatement(
+                        "SELECT OWNER, TABLE_NAME FROM ALL_TABLES\n"
+                                + "WHERE TABLE_NAME NOT LIKE 'MDRT_%'\n"
+                                + "  AND TABLE_NAME NOT LIKE 'MDRS_%'\n"
+                                + "  AND TABLE_NAME NOT LIKE 'MDXT_%'\n"
+                                + "  AND (TABLE_NAME NOT LIKE 'SYS_IOT_OVER_%' AND IOT_NAME IS NULL)")) {
+
+            ResultSet rs = ps.executeQuery();
+            List<String> tables = new ArrayList<>();
+            while (rs.next()) {
+                if (EXCLUDED_SCHEMAS.contains(rs.getString(1))) {
+                    continue;
+                }
+                tables.add(rs.getString(1) + "." + rs.getString(2));
+            }
+
+            return tables;
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed listing database in catalog %s", catalogName), e);
+        }
+    }
+
+    @Override
+    public CatalogTable getTable(TablePath tablePath)
+            throws CatalogException, TableNotExistException {
+        if (!tableExists(tablePath)) {
+            throw new TableNotExistException(catalogName, tablePath);
+        }
+
+        try {
+            DatabaseMetaData metaData = defaultConnection.getMetaData();
+            Optional<PrimaryKey> primaryKey =
+                    getPrimaryKey(
+                            metaData,
+                            tablePath.getDatabaseName(),
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName());
+            List<ConstraintKey> constraintKeys =
+                    getConstraintKeys(
+                            metaData,
+                            tablePath.getDatabaseName(),
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName());
+
+            String sql =
+                    String.format(
+                            SELECT_COLUMNS_SQL,
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName());
+            try (PreparedStatement ps = defaultConnection.prepareStatement(sql);
+                    ResultSet resultSet = ps.executeQuery()) {
+                TableSchema.Builder builder = TableSchema.builder();
+                // add column
+                while (resultSet.next()) {
+                    buildColumn(resultSet, builder);
+                }
+
+                // add primary key
+                primaryKey.ifPresent(builder::primaryKey);
+                // add constraint key
+                constraintKeys.forEach(builder::constraintKey);
+                TableIdentifier tableIdentifier =
+                        TableIdentifier.of(
+                                catalogName,
+                                tablePath.getDatabaseName(),
+                                tablePath.getSchemaName(),
+                                tablePath.getTableName());
+                return CatalogTable.of(
+                        tableIdentifier,
+                        builder.build(),
+                        buildConnectorOptions(tablePath),
+                        Collections.emptyList(),
+                        "");
+            }
+
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed getting table %s", tablePath.getFullName()), e);
+        }
+    }
+
+    private void buildColumn(ResultSet resultSet, TableSchema.Builder builder) throws SQLException {
+        String columnName = resultSet.getString("COLUMN_NAME");
+        String typeName = resultSet.getString("TYPE_NAME");
+        String fullTypeName = resultSet.getString("FULL_TYPE_NAME");
+        long columnLength = resultSet.getLong("COLUMN_LENGTH");
+        long columnPrecision = resultSet.getLong("COLUMN_PRECISION");
+        long columnScale = resultSet.getLong("COLUMN_SCALE");
+        String columnComment = resultSet.getString("COLUMN_COMMENT");
+        Object defaultValue = resultSet.getObject("DEFAULT_VALUE");
+        boolean isNullable = resultSet.getString("IS_NULLABLE").equals("YES");
+
+        SeaTunnelDataType<?> type = fromJdbcType(typeName, columnPrecision, columnScale);
+        long bitLen = 0;
+        switch (typeName) {
+            case ORACLE_LONG:
+            case ORACLE_ROWID:
+            case ORACLE_NCLOB:
+            case ORACLE_CLOB:
+                columnLength = -1;
+                break;
+            case ORACLE_RAW:
+                bitLen = 2000 * 8;
+                break;
+            case ORACLE_BLOB:
+            case ORACLE_LONG_RAW:
+            case ORACLE_BFILE:
+                bitLen = -1;
+                break;
+            case ORACLE_CHAR:
+            case ORACLE_NCHAR:
+            case ORACLE_NVARCHAR2:
+            case ORACLE_VARCHAR2:
+            default:
+                break;
+        }
+
+        PhysicalColumn physicalColumn =
+                PhysicalColumn.of(
+                        columnName,
+                        type,
+                        0,
+                        isNullable,
+                        defaultValue,
+                        columnComment,
+                        fullTypeName,
+                        false,
+                        false,
+                        bitLen,
+                        null,
+                        columnLength);
+        builder.column(physicalColumn);
+    }
+
+    @SuppressWarnings("unchecked")
+    private SeaTunnelDataType<?> fromJdbcType(ResultSetMetaData metadata, int colIndex)
+            throws SQLException {
+        String columnType = metadata.getColumnTypeName(colIndex);
+        Map<String, Object> dataTypeProperties = new HashMap<>();
+        dataTypeProperties.put(OracleDataTypeConvertor.PRECISION, metadata.getPrecision(colIndex));
+        dataTypeProperties.put(OracleDataTypeConvertor.SCALE, metadata.getScale(colIndex));
+        return DATA_TYPE_CONVERTOR.toSeaTunnelType(columnType, dataTypeProperties);
+    }
+
+    private SeaTunnelDataType<?> fromJdbcType(String typeName, long precision, long scale) {
+        Map<String, Object> dataTypeProperties = new HashMap<>();
+        dataTypeProperties.put(OracleDataTypeConvertor.PRECISION, precision);
+        dataTypeProperties.put(OracleDataTypeConvertor.SCALE, scale);
+        return DATA_TYPE_CONVERTOR.toSeaTunnelType(typeName, dataTypeProperties);
+    }
+
+    @SuppressWarnings("MagicNumber")
+    private Map<String, String> buildConnectorOptions(TablePath tablePath) {
+        Map<String, String> options = new HashMap<>(8);
+        options.put("connector", "jdbc");
+        options.put("url", baseUrl);
+        options.put("table-name", tablePath.getSchemaAndTableName());
+        options.put("username", username);
+        options.put("password", pwd);
+        return options;
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalogFactory.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalogFactory.java
new file mode 100644
index 00000000000..4ea5242835c
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalogFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.oracle;
+
+import org.apache.seatunnel.api.configuration.ReadonlyConfig;
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.api.configuration.util.OptionValidationException;
+import org.apache.seatunnel.api.table.catalog.Catalog;
+import org.apache.seatunnel.api.table.factory.CatalogFactory;
+import org.apache.seatunnel.api.table.factory.Factory;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.JdbcCatalogOptions;
+
+import com.google.auto.service.AutoService;
+
+import java.util.Optional;
+
+@AutoService(Factory.class)
+public class OracleCatalogFactory implements CatalogFactory {
+
+    @Override
+    public String factoryIdentifier() {
+        return "Oracle";
+    }
+
+    @Override
+    public Catalog createCatalog(String catalogName, ReadonlyConfig options) {
+        String urlWithDatabase = options.get(JdbcCatalogOptions.BASE_URL);
+        JdbcUrlUtil.UrlInfo urlInfo = OracleURLParser.parse(urlWithDatabase);
+        Optional<String> defaultDatabase = urlInfo.getDefaultDatabase();
+        if (!defaultDatabase.isPresent()) {
+            throw new OptionValidationException(JdbcCatalogOptions.BASE_URL);
+        }
+        return new OracleCatalog(
+                catalogName,
+                options.get(JdbcCatalogOptions.USERNAME),
+                options.get(JdbcCatalogOptions.PASSWORD),
+                urlInfo,
+                options.get(JdbcCatalogOptions.SCHEMA));
+    }
+
+    @Override
+    public OptionRule optionRule() {
+        return JdbcCatalogOptions.BASE_RULE.build();
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCreateTableSqlBuilder.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCreateTableSqlBuilder.java
new file mode 100644
index 00000000000..984dd93e6a6
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCreateTableSqlBuilder.java
@@ -0,0 +1,170 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.oracle;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.Column;
+import org.apache.seatunnel.api.table.catalog.PrimaryKey;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.api.table.type.DecimalType;
+import org.apache.seatunnel.api.table.type.SqlType;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+public class OracleCreateTableSqlBuilder {
+
+    private List<Column> columns;
+    private PrimaryKey primaryKey;
+    private OracleDataTypeConvertor oracleDataTypeConvertor;
+    private String sourceCatalogName;
+
+    public OracleCreateTableSqlBuilder(CatalogTable catalogTable) {
+        this.columns = catalogTable.getTableSchema().getColumns();
+        this.primaryKey = catalogTable.getTableSchema().getPrimaryKey();
+        this.oracleDataTypeConvertor = new OracleDataTypeConvertor();
+        this.sourceCatalogName = catalogTable.getCatalogName();
+    }
+
+    public String build(TablePath tablePath) {
+        StringBuilder createTableSql = new StringBuilder();
+        createTableSql
+                .append("CREATE TABLE ")
+                .append(tablePath.getSchemaAndTableName())
+                .append(" (\n");
+
+        List<String> columnSqls =
+                columns.stream().map(this::buildColumnSql).collect(Collectors.toList());
+
+        // Add primary key directly in the create table statement
+        if (primaryKey != null
+                && primaryKey.getColumnNames() != null
+                && primaryKey.getColumnNames().size() > 0) {
+            columnSqls.add(buildPrimaryKeySql(primaryKey));
+        }
+
+        createTableSql.append(String.join(",\n", columnSqls));
+        createTableSql.append("\n)");
+
+        List<String> commentSqls =
+                columns.stream()
+                        .filter(column -> StringUtils.isNotBlank(column.getComment()))
+                        .map(
+                                column ->
+                                        buildColumnCommentSql(
+                                                column, tablePath.getSchemaAndTableName()))
+                        .collect(Collectors.toList());
+
+        if (!commentSqls.isEmpty()) {
+            createTableSql.append(";\n");
+            createTableSql.append(String.join(";\n", commentSqls));
+        }
+
+        return createTableSql.toString();
+    }
+
+    private String buildColumnSql(Column column) {
+        StringBuilder columnSql = new StringBuilder();
+        columnSql.append(column.getName()).append(" ");
+
+        String columnType =
+                sourceCatalogName.equals("oracle")
+                        ? column.getSourceType()
+                        : buildColumnType(column);
+        columnSql.append(columnType);
+
+        if (!column.isNullable()) {
+            columnSql.append(" NOT NULL");
+        }
+
+        //        if (column.getDefaultValue() != null) {
+        //            columnSql.append(" DEFAULT
+        // '").append(column.getDefaultValue().toString()).append("'");
+        //        }
+
+        return columnSql.toString();
+    }
+
+    private String buildColumnType(Column column) {
+        SqlType sqlType = column.getDataType().getSqlType();
+        Long columnLength = column.getLongColumnLength();
+        Long bitLen = column.getBitLen();
+        switch (sqlType) {
+            case BYTES:
+                if (bitLen < 0 || bitLen > 2000) {
+                    return "BLOB";
+                } else {
+                    return "RAW(" + bitLen + ")";
+                }
+            case STRING:
+                if (columnLength > 0 && columnLength < 4000) {
+                    return "VARCHAR2(" + columnLength + " CHAR)";
+                } else {
+                    return "CLOB";
+                }
+            default:
+                String type = oracleDataTypeConvertor.toConnectorType(column.getDataType(), null);
+                if (type.equals("NUMBER")) {
+                    if (column.getDataType() instanceof DecimalType) {
+                        DecimalType decimalType = (DecimalType) column.getDataType();
+                        return "NUMBER("
+                                + decimalType.getPrecision()
+                                + ","
+                                + decimalType.getScale()
+                                + ")";
+                    } else {
+                        return "NUMBER";
+                    }
+                }
+                return type;
+        }
+    }
+
+    private String buildPrimaryKeySql(PrimaryKey primaryKey) {
+        String randomSuffix = UUID.randomUUID().toString().replace("-", "").substring(0, 4);
+        String columnNamesString = String.join(", ", primaryKey.getColumnNames());
+
+        // In Oracle database, the maximum length for an identifier is 30 characters.
+        String primaryKeyStr = primaryKey.getPrimaryKey();
+        if (primaryKeyStr.length() > 25) {
+            primaryKeyStr = primaryKeyStr.substring(0, 25);
+        }
+
+        return "CONSTRAINT "
+                + primaryKeyStr
+                + "_"
+                + randomSuffix
+                + " PRIMARY KEY ("
+                + columnNamesString
+                + ")";
+    }
+
+    private String buildColumnCommentSql(Column column, String tableName) {
+        StringBuilder columnCommentSql = new StringBuilder();
+        columnCommentSql.append("COMMENT ON COLUMN ").append(tableName).append(".");
+        columnCommentSql
+                .append(column.getName())
+                .append(" IS '")
+                .append(column.getComment())
+                .append("'");
+        return columnCommentSql.toString();
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleDataTypeConvertor.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleDataTypeConvertor.java
new file mode 100644
index 00000000000..cd42a05e0d3
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleDataTypeConvertor.java
@@ -0,0 +1,200 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.oracle;
+
+import org.apache.seatunnel.api.table.catalog.DataTypeConvertException;
+import org.apache.seatunnel.api.table.catalog.DataTypeConvertor;
+import org.apache.seatunnel.api.table.type.BasicType;
+import org.apache.seatunnel.api.table.type.DecimalType;
+import org.apache.seatunnel.api.table.type.LocalTimeType;
+import org.apache.seatunnel.api.table.type.PrimitiveByteArrayType;
+import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
+import org.apache.seatunnel.api.table.type.SqlType;
+import org.apache.seatunnel.common.exception.CommonErrorCode;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.exception.JdbcConnectorException;
+
+import org.apache.commons.collections4.MapUtils;
+
+import com.google.auto.service.AutoService;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@AutoService(DataTypeConvertor.class)
+public class OracleDataTypeConvertor implements DataTypeConvertor<String> {
+
+    public static final String PRECISION = "precision";
+    public static final String SCALE = "scale";
+    public static final Integer DEFAULT_PRECISION = 38;
+    public static final Integer DEFAULT_SCALE = 18;
+
+    // ============================data types=====================
+    public static final String ORACLE_UNKNOWN = "UNKNOWN";
+    // -------------------------number----------------------------
+    public static final String ORACLE_BINARY_DOUBLE = "BINARY_DOUBLE";
+    public static final String ORACLE_BINARY_FLOAT = "BINARY_FLOAT";
+    public static final String ORACLE_NUMBER = "NUMBER";
+    public static final String ORACLE_FLOAT = "FLOAT";
+    public static final String ORACLE_REAL = "REAL";
+    public static final String ORACLE_INTEGER = "INTEGER";
+    // -------------------------string----------------------------
+    public static final String ORACLE_CHAR = "CHAR";
+    public static final String ORACLE_VARCHAR2 = "VARCHAR2";
+    public static final String ORACLE_NCHAR = "NCHAR";
+    public static final String ORACLE_NVARCHAR2 = "NVARCHAR2";
+    public static final String ORACLE_LONG = "LONG";
+    public static final String ORACLE_ROWID = "ROWID";
+    public static final String ORACLE_CLOB = "CLOB";
+    public static final String ORACLE_NCLOB = "NCLOB";
+    // ------------------------------time-------------------------
+    public static final String ORACLE_DATE = "DATE";
+    public static final String ORACLE_TIMESTAMP = "TIMESTAMP";
+    public static final String ORACLE_TIMESTAMP_WITH_LOCAL_TIME_ZONE =
+            "TIMESTAMP WITH LOCAL TIME ZONE";
+    // ------------------------------blob-------------------------
+    public static final String ORACLE_BLOB = "BLOB";
+    public static final String ORACLE_BFILE = "BFILE";
+    public static final String ORACLE_RAW = "RAW";
+    public static final String ORACLE_LONG_RAW = "LONG RAW";
+
+    @Override
+    public SeaTunnelDataType<?> toSeaTunnelType(String connectorDataType) {
+        return toSeaTunnelType(connectorDataType, Collections.emptyMap());
+    }
+
+    @Override
+    public SeaTunnelDataType<?> toSeaTunnelType(
+            String connectorDataType, Map<String, Object> dataTypeProperties)
+            throws DataTypeConvertException {
+        checkNotNull(connectorDataType, "Oracle Type cannot be null");
+        connectorDataType = normalizeTimestamp(connectorDataType);
+        switch (connectorDataType) {
+            case ORACLE_INTEGER:
+                return BasicType.INT_TYPE;
+            case ORACLE_FLOAT:
+                // The float type will be converted to DecimalType(10, -127),
+                // which will lose precision in the spark engine
+                return new DecimalType(38, 18);
+            case ORACLE_NUMBER:
+                int precision =
+                        MapUtils.getInteger(dataTypeProperties, PRECISION, DEFAULT_PRECISION);
+                int scale = MapUtils.getInteger(dataTypeProperties, SCALE, DEFAULT_SCALE);
+                if (scale == 0) {
+                    if (precision == 1) {
+                        return BasicType.BOOLEAN_TYPE;
+                    }
+                    if (precision <= 9) {
+                        return BasicType.INT_TYPE;
+                    }
+                    if (precision <= 18) {
+                        return BasicType.LONG_TYPE;
+                    }
+                }
+                return new DecimalType(38, 18);
+            case ORACLE_BINARY_DOUBLE:
+                return BasicType.DOUBLE_TYPE;
+            case ORACLE_BINARY_FLOAT:
+            case ORACLE_REAL:
+                return BasicType.FLOAT_TYPE;
+            case ORACLE_CHAR:
+            case ORACLE_NCHAR:
+            case ORACLE_NVARCHAR2:
+            case ORACLE_VARCHAR2:
+            case ORACLE_LONG:
+            case ORACLE_ROWID:
+            case ORACLE_NCLOB:
+            case ORACLE_CLOB:
+                return BasicType.STRING_TYPE;
+            case ORACLE_DATE:
+                return LocalTimeType.LOCAL_DATE_TYPE;
+            case ORACLE_TIMESTAMP:
+            case ORACLE_TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+                return LocalTimeType.LOCAL_DATE_TIME_TYPE;
+            case ORACLE_BLOB:
+            case ORACLE_RAW:
+            case ORACLE_LONG_RAW:
+            case ORACLE_BFILE:
+                return PrimitiveByteArrayType.INSTANCE;
+                // Doesn't support yet
+            case ORACLE_UNKNOWN:
+            default:
+                throw new JdbcConnectorException(
+                        CommonErrorCode.UNSUPPORTED_OPERATION,
+                        String.format("Doesn't support ORACLE type '%s' yet.", connectorDataType));
+        }
+    }
+
+    @Override
+    public String toConnectorType(
+            SeaTunnelDataType<?> seaTunnelDataType, Map<String, Object> dataTypeProperties)
+            throws DataTypeConvertException {
+        checkNotNull(seaTunnelDataType, "seaTunnelDataType cannot be null");
+        SqlType sqlType = seaTunnelDataType.getSqlType();
+        switch (sqlType) {
+            case TINYINT:
+            case SMALLINT:
+            case INT:
+                return ORACLE_INTEGER;
+            case BIGINT:
+                return ORACLE_NUMBER;
+            case FLOAT:
+                return ORACLE_FLOAT;
+            case DOUBLE:
+                return ORACLE_BINARY_DOUBLE;
+            case DECIMAL:
+                return ORACLE_NUMBER;
+            case BOOLEAN:
+                return ORACLE_NUMBER;
+            case STRING:
+                return ORACLE_VARCHAR2;
+            case DATE:
+                return ORACLE_DATE;
+            case TIMESTAMP:
+                return ORACLE_TIMESTAMP_WITH_LOCAL_TIME_ZONE;
+            case BYTES:
+                return ORACLE_BLOB;
+            default:
+                throw new UnsupportedOperationException(
+                        String.format(
+                                "Doesn't support SeaTunnel type '%s' yet.", seaTunnelDataType));
+        }
+    }
+
+    public static String normalizeTimestamp(String oracleType) {
+        // Create a pattern to match TIMESTAMP followed by an optional (0-9)
+        String pattern = "^TIMESTAMP(\\([0-9]\\))?$";
+        // Create a Pattern object
+        Pattern r = Pattern.compile(pattern);
+        // Now create matcher object.
+        Matcher m = r.matcher(oracleType);
+        if (m.find()) {
+            return "TIMESTAMP";
+        } else {
+            return oracleType;
+        }
+    }
+
+    @Override
+    public String getIdentity() {
+        return "Oracle";
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleURLParser.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleURLParser.java
new file mode 100644
index 00000000000..adcb5236de5
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleURLParser.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.seatunnel.connectors.seatunnel.jdbc.catalog.oracle;
+
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class OracleURLParser {
+    private static final Pattern ORACLE_URL_PATTERN =
+            Pattern.compile(
+                    "^(?<url>jdbc:oracle:thin:@(//)?(?<host>[^:]+):(?<port>\\d+)[:/])(?<database>.+?)((?<suffix>\\?.*)?)$");
+
+    public static JdbcUrlUtil.UrlInfo parse(String url) {
+        Matcher matcher = ORACLE_URL_PATTERN.matcher(url);
+        if (matcher.find()) {
+            String urlWithoutDatabase = matcher.group("url");
+            String host = matcher.group("host");
+            Integer port = Integer.valueOf(matcher.group("port"));
+            String database = matcher.group("database");
+            String suffix = Optional.ofNullable(matcher.group("suffix")).orElse("");
+            return new JdbcUrlUtil.UrlInfo(url, urlWithoutDatabase, host, port, database, suffix);
+        }
+        throw new IllegalArgumentException("The jdbc url format is incorrect: " + url);
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalog.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalog.java
new file mode 100644
index 00000000000..e3507666d08
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalog.java
@@ -0,0 +1,441 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.psql;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.ConstraintKey;
+import org.apache.seatunnel.api.table.catalog.PhysicalColumn;
+import org.apache.seatunnel.api.table.catalog.PrimaryKey;
+import org.apache.seatunnel.api.table.catalog.TableIdentifier;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.api.table.catalog.TableSchema;
+import org.apache.seatunnel.api.table.catalog.exception.CatalogException;
+import org.apache.seatunnel.api.table.catalog.exception.DatabaseNotExistException;
+import org.apache.seatunnel.api.table.catalog.exception.TableNotExistException;
+import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.AbstractJdbcCatalog;
+
+import com.mysql.cj.MysqlType;
+import com.mysql.cj.jdbc.result.ResultSetImpl;
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_BIT;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_BYTEA;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_CHAR;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_CHARACTER;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_CHARACTER_VARYING;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_GEOGRAPHY;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_GEOMETRY;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_INTERVAL;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_TEXT;
+
+@Slf4j
+public class PostgresCatalog extends AbstractJdbcCatalog {
+
+    private static final String SELECT_COLUMNS_SQL =
+            "SELECT \n"
+                    + "    a.attname AS column_name, \n"
+                    + "\t\tt.typname as type_name,\n"
+                    + "    CASE \n"
+                    + "        WHEN t.typname = 'varchar' THEN t.typname || '(' || (a.atttypmod - 4) || ')'\n"
+                    + "        WHEN t.typname = 'bpchar' THEN 'char' || '(' || (a.atttypmod - 4) || ')'\n"
+                    + "        WHEN t.typname = 'numeric' OR t.typname = 'decimal' THEN t.typname || '(' || ((a.atttypmod - 4) >> 16) || ', ' || ((a.atttypmod - 4) & 65535) || ')'\n"
+                    + "        WHEN t.typname = 'bit' OR t.typname = 'bit varying' THEN t.typname || '(' || (a.atttypmod - 4) || ')'\n"
+                    + "        ELSE t.typname\n"
+                    + "    END AS full_type_name,\n"
+                    + "    CASE\n"
+                    + "        WHEN t.typname IN ('varchar', 'bpchar', 'bit', 'bit varying') THEN a.atttypmod - 4\n"
+                    + "        WHEN t.typname IN ('numeric', 'decimal') THEN (a.atttypmod - 4) >> 16\n"
+                    + "        ELSE NULL\n"
+                    + "    END AS column_length,\n"
+                    + "\t\tCASE\n"
+                    + "        WHEN t.typname IN ('numeric', 'decimal') THEN (a.atttypmod - 4) & 65535\n"
+                    + "        ELSE NULL\n"
+                    + "    END AS column_scale,\n"
+                    + "\t\td.description AS column_comment,\n"
+                    + "\t\tpg_get_expr(ad.adbin, ad.adrelid) AS default_value,\n"
+                    + "\t\tCASE WHEN a.attnotnull THEN 'NO' ELSE 'YES' END AS is_nullable\n"
+                    + "FROM \n"
+                    + "    pg_class c\n"
+                    + "    JOIN pg_namespace n ON c.relnamespace = n.oid\n"
+                    + "    JOIN pg_attribute a ON a.attrelid = c.oid\n"
+                    + "    JOIN pg_type t ON a.atttypid = t.oid\n"
+                    + "    LEFT JOIN pg_description d ON c.oid = d.objoid AND a.attnum = d.objsubid\n"
+                    + "    LEFT JOIN pg_attrdef ad ON a.attnum = ad.adnum AND a.attrelid = ad.adrelid\n"
+                    + "WHERE \n"
+                    + "    n.nspname = '%s'\n"
+                    + "    AND c.relname = '%s'\n"
+                    + "    AND a.attnum > 0\n"
+                    + "ORDER BY \n"
+                    + "    a.attnum;";
+
+    protected static final Set<String> SYS_DATABASES = new HashSet<>(9);
+
+    static {
+        SYS_DATABASES.add("information_schema");
+        SYS_DATABASES.add("pg_catalog");
+        SYS_DATABASES.add("root");
+        SYS_DATABASES.add("pg_toast");
+        SYS_DATABASES.add("pg_temp_1");
+        SYS_DATABASES.add("pg_toast_temp_1");
+        SYS_DATABASES.add("postgres");
+        SYS_DATABASES.add("template0");
+        SYS_DATABASES.add("template1");
+    }
+
+    protected final Map<String, Connection> connectionMap;
+
+    public PostgresCatalog(
+            String catalogName,
+            String username,
+            String pwd,
+            JdbcUrlUtil.UrlInfo urlInfo,
+            String defaultSchema) {
+        super(catalogName, username, pwd, urlInfo, defaultSchema);
+        this.connectionMap = new ConcurrentHashMap<>();
+    }
+
+    public Connection getConnection(String url) {
+        if (connectionMap.containsKey(url)) {
+            return connectionMap.get(url);
+        }
+        try {
+            Connection connection = DriverManager.getConnection(url, username, pwd);
+            connectionMap.put(url, connection);
+            return connection;
+        } catch (SQLException e) {
+            throw new CatalogException(String.format("Failed connecting to %s via JDBC.", url), e);
+        }
+    }
+
+    @Override
+    public void close() throws CatalogException {
+        for (Map.Entry<String, Connection> entry : connectionMap.entrySet()) {
+            try {
+                entry.getValue().close();
+            } catch (SQLException e) {
+                throw new CatalogException(
+                        String.format("Failed to close %s via JDBC.", entry.getKey()), e);
+            }
+        }
+        super.close();
+    }
+
+    @Override
+    public List<String> listDatabases() throws CatalogException {
+        try (PreparedStatement ps =
+                defaultConnection.prepareStatement("select datname from pg_database;")) {
+
+            List<String> databases = new ArrayList<>();
+            ResultSet rs = ps.executeQuery();
+
+            while (rs.next()) {
+                String databaseName = rs.getString(1);
+                if (!SYS_DATABASES.contains(databaseName)) {
+                    databases.add(rs.getString(1));
+                }
+            }
+
+            return databases;
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed listing database in catalog %s", this.catalogName), e);
+        }
+    }
+
+    @Override
+    public List<String> listTables(String databaseName)
+            throws CatalogException, DatabaseNotExistException {
+        if (!databaseExists(databaseName)) {
+            throw new DatabaseNotExistException(this.catalogName, databaseName);
+        }
+
+        String dbUrl = getUrlFromDatabaseName(databaseName);
+        Connection connection = getConnection(dbUrl);
+        try (PreparedStatement ps =
+                connection.prepareStatement(
+                        "SELECT table_schema, table_name FROM information_schema.tables;")) {
+
+            ResultSet rs = ps.executeQuery();
+
+            List<String> tables = new ArrayList<>();
+
+            while (rs.next()) {
+                String schemaName = rs.getString("table_schema");
+                String tableName = rs.getString("table_name");
+                if (org.apache.commons.lang3.StringUtils.isNotBlank(schemaName)
+                        && !SYS_DATABASES.contains(schemaName)) {
+                    tables.add(schemaName + "." + tableName);
+                }
+            }
+
+            return tables;
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed listing database in catalog %s", catalogName), e);
+        }
+    }
+
+    @Override
+    public CatalogTable getTable(TablePath tablePath)
+            throws CatalogException, TableNotExistException {
+        if (!tableExists(tablePath)) {
+            throw new TableNotExistException(catalogName, tablePath);
+        }
+
+        String dbUrl = getUrlFromDatabaseName(tablePath.getDatabaseName());
+        Connection conn = getConnection(dbUrl);
+        try {
+            DatabaseMetaData metaData = conn.getMetaData();
+            Optional<PrimaryKey> primaryKey =
+                    getPrimaryKey(
+                            metaData,
+                            tablePath.getDatabaseName(),
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName());
+            List<ConstraintKey> constraintKeys =
+                    getConstraintKeys(
+                            metaData,
+                            tablePath.getDatabaseName(),
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName());
+
+            String sql =
+                    String.format(
+                            SELECT_COLUMNS_SQL,
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName());
+            try (PreparedStatement ps = conn.prepareStatement(sql);
+                    ResultSet resultSet = ps.executeQuery()) {
+                TableSchema.Builder builder = TableSchema.builder();
+
+                // add column
+                while (resultSet.next()) {
+                    buildColumn(resultSet, builder);
+                }
+
+                // add primary key
+                primaryKey.ifPresent(builder::primaryKey);
+                // add constraint key
+                constraintKeys.forEach(builder::constraintKey);
+                TableIdentifier tableIdentifier =
+                        TableIdentifier.of(
+                                catalogName,
+                                tablePath.getDatabaseName(),
+                                tablePath.getSchemaName(),
+                                tablePath.getTableName());
+                return CatalogTable.of(
+                        tableIdentifier,
+                        builder.build(),
+                        buildConnectorOptions(tablePath),
+                        Collections.emptyList(),
+                        "",
+                        "postgres");
+            }
+
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed getting table %s", tablePath.getFullName()), e);
+        }
+    }
+
+    private void buildColumn(ResultSet resultSet, TableSchema.Builder builder) throws SQLException {
+        String columnName = resultSet.getString("column_name");
+        String typeName = resultSet.getString("type_name");
+        String fullTypeName = resultSet.getString("full_type_name");
+        long columnLength = resultSet.getLong("column_length");
+        long columnScale = resultSet.getLong("column_scale");
+        String columnComment = resultSet.getString("column_comment");
+        Object defaultValue = resultSet.getObject("default_value");
+        boolean isNullable = resultSet.getString("is_nullable").equals("YES");
+
+        if (defaultValue != null && defaultValue.toString().contains("regclass"))
+            defaultValue = null;
+
+        SeaTunnelDataType<?> type = fromJdbcType(typeName, columnLength, columnScale);
+        long bitLen = 0;
+        switch (typeName) {
+            case PG_BYTEA:
+                bitLen = -1;
+                break;
+            case PG_TEXT:
+                columnLength = -1;
+                break;
+            case PG_INTERVAL:
+                columnLength = 50;
+                break;
+            case PG_GEOMETRY:
+            case PG_GEOGRAPHY:
+                columnLength = 255;
+                break;
+            case PG_BIT:
+                bitLen = columnLength;
+                break;
+            case PG_CHAR:
+            case PG_CHARACTER:
+            case PG_CHARACTER_VARYING:
+            default:
+                break;
+        }
+
+        PhysicalColumn physicalColumn =
+                PhysicalColumn.of(
+                        columnName,
+                        type,
+                        0,
+                        isNullable,
+                        defaultValue,
+                        columnComment,
+                        fullTypeName,
+                        false,
+                        false,
+                        bitLen,
+                        null,
+                        columnLength);
+        builder.column(physicalColumn);
+    }
+
+    @Override
+    protected boolean createTableInternal(TablePath tablePath, CatalogTable table)
+            throws CatalogException {
+        String createTableSql = new PostgresCreateTableSqlBuilder(table).build(tablePath);
+        String dbUrl = getUrlFromDatabaseName(tablePath.getDatabaseName());
+        Connection conn = getConnection(dbUrl);
+        log.info("create table sql: {}", createTableSql);
+        try (PreparedStatement ps = conn.prepareStatement(createTableSql)) {
+            ps.execute();
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed creating table %s", tablePath.getFullName()), e);
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean dropTableInternal(TablePath tablePath) throws CatalogException {
+        String dbUrl = getUrlFromDatabaseName(tablePath.getDatabaseName());
+
+        String schemaName = tablePath.getSchemaName();
+        String tableName = tablePath.getTableName();
+
+        String sql = "DROP TABLE IF EXISTS \"" + schemaName + "\".\"" + tableName + "\"";
+        Connection connection = getConnection(dbUrl);
+        try (PreparedStatement ps = connection.prepareStatement(sql)) {
+            // Will there exist concurrent drop for one table?
+            return ps.execute();
+        } catch (SQLException e) {
+            throw new CatalogException(
+                    String.format("Failed dropping table %s", tablePath.getFullName()), e);
+        }
+    }
+
+    @Override
+    protected boolean createDatabaseInternal(String databaseName) throws CatalogException {
+        String sql = "CREATE DATABASE \"" + databaseName + "\"";
+        try (PreparedStatement ps = defaultConnection.prepareStatement(sql)) {
+            return ps.execute();
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format(
+                            "Failed creating database %s in catalog %s",
+                            databaseName, this.catalogName),
+                    e);
+        }
+    }
+
+    @Override
+    public boolean tableExists(TablePath tablePath) throws CatalogException {
+        try {
+            return databaseExists(tablePath.getDatabaseName())
+                    && listTables(tablePath.getDatabaseName())
+                            .contains(tablePath.getSchemaAndTableName());
+        } catch (DatabaseNotExistException e) {
+            return false;
+        }
+    }
+
+    @Override
+    protected boolean dropDatabaseInternal(String databaseName) throws CatalogException {
+        String sql = "DROP DATABASE IF EXISTS \"" + databaseName + "\"";
+        try (PreparedStatement ps = defaultConnection.prepareStatement(sql)) {
+            return ps.execute();
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format(
+                            "Failed dropping database %s in catalog %s",
+                            databaseName, this.catalogName),
+                    e);
+        }
+    }
+
+    /**
+     * @see MysqlType
+     * @see ResultSetImpl#getObjectStoredProc(int, int)
+     */
+    @SuppressWarnings("unchecked")
+    private SeaTunnelDataType<?> fromJdbcType(ResultSetMetaData metadata, int colIndex)
+            throws SQLException {
+        String columnTypeName = metadata.getColumnTypeName(colIndex);
+        Map<String, Object> dataTypeProperties = new HashMap<>();
+        dataTypeProperties.put(
+                PostgresDataTypeConvertor.PRECISION, metadata.getPrecision(colIndex));
+        dataTypeProperties.put(PostgresDataTypeConvertor.SCALE, metadata.getScale(colIndex));
+        return new PostgresDataTypeConvertor().toSeaTunnelType(columnTypeName, dataTypeProperties);
+    }
+
+    private SeaTunnelDataType<?> fromJdbcType(String typeName, long precision, long scale) {
+        Map<String, Object> dataTypeProperties = new HashMap<>();
+        dataTypeProperties.put(PostgresDataTypeConvertor.PRECISION, precision);
+        dataTypeProperties.put(PostgresDataTypeConvertor.SCALE, scale);
+        return new PostgresDataTypeConvertor().toSeaTunnelType(typeName, dataTypeProperties);
+    }
+
+    @SuppressWarnings("MagicNumber")
+    private Map<String, String> buildConnectorOptions(TablePath tablePath) {
+        Map<String, String> options = new HashMap<>(8);
+        options.put("connector", "jdbc");
+        options.put("url", baseUrl + tablePath.getDatabaseName());
+        options.put("table-name", tablePath.getFullName());
+        options.put("username", username);
+        options.put("password", pwd);
+        return options;
+    }
+
+    private String getUrlFromDatabaseName(String databaseName) {
+        String url = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
+        return url + databaseName + suffix;
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalogFactory.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalogFactory.java
new file mode 100644
index 00000000000..4db852960ed
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalogFactory.java
@@ -0,0 +1,62 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.psql;
+
+import org.apache.seatunnel.api.configuration.ReadonlyConfig;
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.api.configuration.util.OptionValidationException;
+import org.apache.seatunnel.api.table.catalog.Catalog;
+import org.apache.seatunnel.api.table.factory.CatalogFactory;
+import org.apache.seatunnel.api.table.factory.Factory;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.JdbcCatalogOptions;
+
+import com.google.auto.service.AutoService;
+
+import java.util.Optional;
+
+@AutoService(Factory.class)
+public class PostgresCatalogFactory implements CatalogFactory {
+    public static final String IDENTIFIER = "Postgres";
+
+    @Override
+    public String factoryIdentifier() {
+        return IDENTIFIER;
+    }
+
+    @Override
+    public Catalog createCatalog(String catalogName, ReadonlyConfig options) {
+        String urlWithDatabase = options.get(JdbcCatalogOptions.BASE_URL);
+        JdbcUrlUtil.UrlInfo urlInfo = JdbcUrlUtil.getUrlInfo(urlWithDatabase);
+        Optional<String> defaultDatabase = urlInfo.getDefaultDatabase();
+        if (!defaultDatabase.isPresent()) {
+            throw new OptionValidationException(JdbcCatalogOptions.BASE_URL);
+        }
+        return new PostgresCatalog(
+                catalogName,
+                options.get(JdbcCatalogOptions.USERNAME),
+                options.get(JdbcCatalogOptions.PASSWORD),
+                urlInfo,
+                options.get(JdbcCatalogOptions.SCHEMA));
+    }
+
+    @Override
+    public OptionRule optionRule() {
+        return JdbcCatalogOptions.BASE_RULE.build();
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCreateTableSqlBuilder.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCreateTableSqlBuilder.java
new file mode 100644
index 00000000000..85f4468bef9
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCreateTableSqlBuilder.java
@@ -0,0 +1,144 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.psql;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.Column;
+import org.apache.seatunnel.api.table.catalog.PrimaryKey;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.api.table.type.DecimalType;
+import org.apache.seatunnel.api.table.type.SqlType;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_BYTEA;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresDataTypeConvertor.PG_NUMERIC;
+
+public class PostgresCreateTableSqlBuilder {
+    private List<Column> columns;
+    private PrimaryKey primaryKey;
+    private PostgresDataTypeConvertor postgresDataTypeConvertor;
+    private String sourceCatalogName;
+
+    public PostgresCreateTableSqlBuilder(CatalogTable catalogTable) {
+        this.columns = catalogTable.getTableSchema().getColumns();
+        this.primaryKey = catalogTable.getTableSchema().getPrimaryKey();
+        this.postgresDataTypeConvertor = new PostgresDataTypeConvertor();
+        this.sourceCatalogName = catalogTable.getCatalogName();
+    }
+
+    public String build(TablePath tablePath) {
+        StringBuilder createTableSql = new StringBuilder();
+        createTableSql
+                .append("CREATE TABLE IF NOT EXISTS ")
+                .append(tablePath.getSchemaAndTableName())
+                .append(" (\n");
+
+        List<String> columnSqls =
+                columns.stream().map(this::buildColumnSql).collect(Collectors.toList());
+
+        createTableSql.append(String.join(",\n", columnSqls));
+        createTableSql.append("\n);");
+
+        List<String> commentSqls =
+                columns.stream()
+                        .filter(column -> StringUtils.isNotBlank(column.getComment()))
+                        .map(
+                                columns ->
+                                        buildColumnCommentSql(
+                                                columns, tablePath.getSchemaAndTableName()))
+                        .collect(Collectors.toList());
+
+        if (!commentSqls.isEmpty()) {
+            createTableSql.append("\n");
+            createTableSql.append(String.join(";\n", commentSqls)).append(";");
+        }
+
+        return createTableSql.toString();
+    }
+
+    private String buildColumnSql(Column column) {
+        StringBuilder columnSql = new StringBuilder();
+        columnSql.append(column.getName()).append(" ");
+
+        // For simplicity, assume the column type in SeaTunnelDataType is the same as in PostgreSQL
+        String columnType =
+                sourceCatalogName.equals("postgres")
+                        ? column.getSourceType()
+                        : buildColumnType(column);
+        columnSql.append(columnType);
+
+        // Add NOT NULL if column is not nullable
+        if (!column.isNullable()) {
+            columnSql.append(" NOT NULL");
+        }
+
+        // Add primary key directly after the column if it is a primary key
+        if (primaryKey != null && primaryKey.getColumnNames().contains(column.getName())) {
+            columnSql.append(" PRIMARY KEY");
+        }
+
+        // Add default value if exists
+        //        if (column.getDefaultValue() != null) {
+        //            columnSql.append(" DEFAULT
+        // '").append(column.getDefaultValue().toString()).append("'");
+        //        }
+
+        return columnSql.toString();
+    }
+
+    private String buildColumnType(Column column) {
+        SqlType sqlType = column.getDataType().getSqlType();
+        Long columnLength = column.getLongColumnLength();
+        switch (sqlType) {
+            case BYTES:
+                return PG_BYTEA;
+            case STRING:
+                if (columnLength > 0 && columnLength < 10485760) {
+                    return "varchar(" + columnLength + ")";
+                } else {
+                    return "text";
+                }
+            default:
+                String type = postgresDataTypeConvertor.toConnectorType(column.getDataType(), null);
+                if (type.equals(PG_NUMERIC)) {
+                    DecimalType decimalType = (DecimalType) column.getDataType();
+                    return "numeric("
+                            + decimalType.getPrecision()
+                            + ","
+                            + decimalType.getScale()
+                            + ")";
+                }
+                return type;
+        }
+    }
+
+    private String buildColumnCommentSql(Column column, String tableName) {
+        StringBuilder columnCommentSql = new StringBuilder();
+        columnCommentSql.append("COMMENT ON COLUMN ").append(tableName).append(".");
+        columnCommentSql
+                .append(column.getName())
+                .append(" IS '")
+                .append(column.getComment())
+                .append("'");
+        return columnCommentSql.toString();
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresDataTypeConvertor.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresDataTypeConvertor.java
index 81bf5ca0665..c87a2fc1188 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresDataTypeConvertor.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresDataTypeConvertor.java
@@ -65,41 +65,46 @@ public class PostgresDataTypeConvertor implements DataTypeConvertor<String> {
     // float <=> float8
     // boolean <=> bool
     // decimal <=> numeric
-    private static final String PG_SMALLSERIAL = "smallserial";
-    private static final String PG_SERIAL = "serial";
-    private static final String PG_BIGSERIAL = "bigserial";
-    private static final String PG_BYTEA = "bytea";
-    private static final String PG_BYTEA_ARRAY = "_bytea";
-    private static final String PG_SMALLINT = "int2";
-    private static final String PG_SMALLINT_ARRAY = "_int2";
-    private static final String PG_INTEGER = "int4";
-    private static final String PG_INTEGER_ARRAY = "_int4";
-    private static final String PG_BIGINT = "int8";
-    private static final String PG_BIGINT_ARRAY = "_int8";
-    private static final String PG_REAL = "float4";
-    private static final String PG_REAL_ARRAY = "_float4";
-    private static final String PG_DOUBLE_PRECISION = "float8";
-    private static final String PG_DOUBLE_PRECISION_ARRAY = "_float8";
-    private static final String PG_NUMERIC = "numeric";
-    private static final String PG_NUMERIC_ARRAY = "_numeric";
-    private static final String PG_BOOLEAN = "bool";
-    private static final String PG_BOOLEAN_ARRAY = "_bool";
-    private static final String PG_TIMESTAMP = "timestamp";
-    private static final String PG_TIMESTAMP_ARRAY = "_timestamp";
-    private static final String PG_TIMESTAMPTZ = "timestamptz";
-    private static final String PG_TIMESTAMPTZ_ARRAY = "_timestamptz";
-    private static final String PG_DATE = "date";
-    private static final String PG_DATE_ARRAY = "_date";
-    private static final String PG_TIME = "time";
-    private static final String PG_TIME_ARRAY = "_time";
-    private static final String PG_TEXT = "text";
-    private static final String PG_TEXT_ARRAY = "_text";
-    private static final String PG_CHAR = "bpchar";
-    private static final String PG_CHAR_ARRAY = "_bpchar";
-    private static final String PG_CHARACTER = "character";
-    private static final String PG_CHARACTER_ARRAY = "_character";
-    private static final String PG_CHARACTER_VARYING = "varchar";
-    private static final String PG_CHARACTER_VARYING_ARRAY = "_varchar";
+    public static final String PG_SMALLSERIAL = "smallserial";
+    public static final String PG_SERIAL = "serial";
+    public static final String PG_BIGSERIAL = "bigserial";
+    public static final String PG_BYTEA = "bytea";
+
+    public static final String PG_BIT = "bit";
+    public static final String PG_BYTEA_ARRAY = "_bytea";
+    public static final String PG_SMALLINT = "int2";
+    public static final String PG_SMALLINT_ARRAY = "_int2";
+    public static final String PG_INTEGER = "int4";
+    public static final String PG_INTEGER_ARRAY = "_int4";
+    public static final String PG_BIGINT = "int8";
+    public static final String PG_BIGINT_ARRAY = "_int8";
+    public static final String PG_REAL = "float4";
+    public static final String PG_REAL_ARRAY = "_float4";
+    public static final String PG_DOUBLE_PRECISION = "float8";
+    public static final String PG_DOUBLE_PRECISION_ARRAY = "_float8";
+    public static final String PG_NUMERIC = "numeric";
+    public static final String PG_NUMERIC_ARRAY = "_numeric";
+    public static final String PG_BOOLEAN = "bool";
+    public static final String PG_BOOLEAN_ARRAY = "_bool";
+    public static final String PG_TIMESTAMP = "timestamp";
+    public static final String PG_TIMESTAMP_ARRAY = "_timestamp";
+    public static final String PG_TIMESTAMPTZ = "timestamptz";
+    public static final String PG_TIMESTAMPTZ_ARRAY = "_timestamptz";
+    public static final String PG_DATE = "date";
+    public static final String PG_DATE_ARRAY = "_date";
+    public static final String PG_TIME = "time";
+    public static final String PG_TIME_ARRAY = "_time";
+    public static final String PG_TEXT = "text";
+    public static final String PG_TEXT_ARRAY = "_text";
+    public static final String PG_CHAR = "bpchar";
+    public static final String PG_CHAR_ARRAY = "_bpchar";
+    public static final String PG_CHARACTER = "character";
+    public static final String PG_CHARACTER_ARRAY = "_character";
+    public static final String PG_CHARACTER_VARYING = "varchar";
+    public static final String PG_CHARACTER_VARYING_ARRAY = "_varchar";
+    public static final String PG_INTERVAL = "interval";
+    public static final String PG_GEOMETRY = "geometry";
+    public static final String PG_GEOGRAPHY = "geography";
 
     @Override
     public SeaTunnelDataType<?> toSeaTunnelType(String connectorDataType) {
@@ -117,6 +122,7 @@ public SeaTunnelDataType<?> toSeaTunnelType(
             case PG_BOOLEAN_ARRAY:
                 return ArrayType.BOOLEAN_ARRAY_TYPE;
             case PG_BYTEA:
+            case PG_BIT:
                 return PrimitiveByteArrayType.INSTANCE;
             case PG_BYTEA_ARRAY:
                 return ArrayType.BYTE_ARRAY_TYPE;
@@ -151,6 +157,9 @@ public SeaTunnelDataType<?> toSeaTunnelType(
             case PG_CHARACTER:
             case PG_CHARACTER_VARYING:
             case PG_TEXT:
+            case PG_INTERVAL:
+            case PG_GEOMETRY:
+            case PG_GEOGRAPHY:
                 return BasicType.STRING_TYPE;
             case PG_CHAR_ARRAY:
             case PG_CHARACTER_ARRAY:
@@ -158,6 +167,7 @@ public SeaTunnelDataType<?> toSeaTunnelType(
             case PG_TEXT_ARRAY:
                 return ArrayType.STRING_ARRAY_TYPE;
             case PG_TIMESTAMP:
+            case PG_TIMESTAMPTZ:
                 return LocalTimeType.LOCAL_DATE_TIME_TYPE;
             case PG_TIME:
                 return LocalTimeType.LOCAL_TIME_TYPE;
@@ -166,7 +176,6 @@ public SeaTunnelDataType<?> toSeaTunnelType(
 
             case PG_TIMESTAMP_ARRAY:
             case PG_NUMERIC_ARRAY:
-            case PG_TIMESTAMPTZ:
             case PG_TIMESTAMPTZ_ARRAY:
             case PG_TIME_ARRAY:
             case PG_DATE_ARRAY:
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalog.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalog.java
index f376f47af11..ea04c60bff5 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalog.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalog.java
@@ -32,8 +32,11 @@
 import org.apache.seatunnel.common.utils.JdbcUrlUtil;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.AbstractJdbcCatalog;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 
+import lombok.extern.slf4j.Slf4j;
+
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.DriverManager;
@@ -50,6 +53,7 @@
 import java.util.Optional;
 import java.util.Set;
 
+@Slf4j
 public class SqlServerCatalog extends AbstractJdbcCatalog {
 
     private static final Set<String> SYS_DATABASES = new HashSet<>(4);
@@ -62,8 +66,12 @@ public class SqlServerCatalog extends AbstractJdbcCatalog {
     }
 
     public SqlServerCatalog(
-            String catalogName, String username, String pwd, JdbcUrlUtil.UrlInfo urlInfo) {
-        super(catalogName, username, pwd, urlInfo);
+            String catalogName,
+            String username,
+            String pwd,
+            JdbcUrlUtil.UrlInfo urlInfo,
+            String defaultSchema) {
+        super(catalogName, username, pwd, urlInfo, defaultSchema);
     }
 
     @Override
@@ -135,6 +143,15 @@ public CatalogTable getTable(TablePath tablePath)
         if (!tableExists(tablePath)) {
             throw new TableNotExistException(catalogName, tablePath);
         }
+        String tableSql =
+                StringUtils.isNotEmpty(tablePath.getTableName())
+                        ? "AND tbl.name = '" + tablePath.getTableName() + "'"
+                        : "";
+
+        String columnSql =
+                String.format(
+                        "    SELECT tbl.name AS table_name, \n           col.name AS column_name, \n           ext.value AS comment, \n           col.column_id AS column_id, \n           types.name AS type, \n           col.max_length AS max_length, \n           col.precision AS precision, \n           col.scale AS scale, \n           col.is_nullable AS is_nullable, \n def.definition AS default_value\n     FROM sys.tables tbl \nINNER JOIN sys.columns col \n        ON tbl.object_id = col.object_id \n LEFT JOIN sys.types types \n        ON col.user_type_id = types.user_type_id \n LEFT JOIN sys.extended_properties ext \n        ON ext.major_id = col.object_id and ext.minor_id = col.column_id \n   LEFT JOIN sys.default_constraints def ON col.default_object_id = def.object_id \n    AND ext.minor_id = col.column_id \n       AND ext.name = 'MS_Description' \n     WHERE schema_name(tbl.schema_id) = '%s' \n       %s \n  ORDER BY tbl.name, col.column_id",
+                        tablePath.getSchemaName(), tableSql);
 
         String dbUrl = getUrlFromDatabaseName(tablePath.getDatabaseName());
         try (Connection conn = DriverManager.getConnection(dbUrl, username, pwd)) {
@@ -152,40 +169,13 @@ public CatalogTable getTable(TablePath tablePath)
                             tablePath.getSchemaName(),
                             tablePath.getTableName());
 
-            try (PreparedStatement ps =
-                    conn.prepareStatement(
-                            String.format(
-                                    "SELECT * FROM %s WHERE 1 = 0;",
-                                    tablePath.getFullNameWithQuoted("\"")))) {
-                ResultSetMetaData tableMetaData = ps.getMetaData();
+            try (PreparedStatement ps = conn.prepareStatement(columnSql);
+                    ResultSet resultSet = ps.executeQuery(); ) {
                 TableSchema.Builder builder = TableSchema.builder();
-                // add column
-                for (int i = 1; i <= tableMetaData.getColumnCount(); i++) {
-                    String columnName = tableMetaData.getColumnName(i);
-                    SeaTunnelDataType<?> type = fromJdbcType(tableMetaData, i);
-                    int columnDisplaySize = tableMetaData.getColumnDisplaySize(i);
-                    String comment = tableMetaData.getColumnLabel(i);
-                    boolean isNullable =
-                            tableMetaData.isNullable(i) == ResultSetMetaData.columnNullable;
-                    Object defaultValue =
-                            getColumnDefaultValue(
-                                            metaData,
-                                            tablePath.getDatabaseName(),
-                                            tablePath.getSchemaName(),
-                                            tablePath.getTableName(),
-                                            columnName)
-                                    .orElse(null);
-
-                    PhysicalColumn physicalColumn =
-                            PhysicalColumn.of(
-                                    columnName,
-                                    type,
-                                    columnDisplaySize,
-                                    isNullable,
-                                    defaultValue,
-                                    comment);
-                    builder.column(physicalColumn);
+                while (resultSet.next()) {
+                    buildTable(resultSet, builder);
                 }
+
                 // add primary key
                 primaryKey.ifPresent(builder::primaryKey);
                 // add constraint key
@@ -201,7 +191,8 @@ public CatalogTable getTable(TablePath tablePath)
                         builder.build(),
                         buildConnectorOptions(tablePath),
                         Collections.emptyList(),
-                        "");
+                        "",
+                        "sqlserver");
             }
 
         } catch (Exception e) {
@@ -210,10 +201,111 @@ public CatalogTable getTable(TablePath tablePath)
         }
     }
 
+    private void buildTable(ResultSet resultSet, TableSchema.Builder builder) throws SQLException {
+        String columnName = resultSet.getString("column_name");
+        String sourceType = resultSet.getString("type");
+        //        String typeName = resultSet.getString("DATA_TYPE").toUpperCase();
+        int precision = resultSet.getInt("precision");
+        int scale = resultSet.getInt("scale");
+        long columnLength = resultSet.getLong("max_length");
+        SeaTunnelDataType<?> type = fromJdbcType(sourceType, precision, scale);
+        String comment = resultSet.getString("comment");
+        Object defaultValue = resultSet.getObject("default_value");
+        if (defaultValue != null) {
+            defaultValue =
+                    defaultValue.toString().replace("(", "").replace("'", "").replace(")", "");
+        }
+        boolean isNullable = resultSet.getBoolean("is_nullable");
+        long bitLen = 0;
+        StringBuilder sb = new StringBuilder(sourceType);
+        Pair<SqlServerType, Map<String, Object>> parse = SqlServerType.parse(sourceType);
+        switch (parse.getLeft()) {
+            case BINARY:
+            case VARBINARY:
+                // Uniform conversion to bits
+                if (columnLength != -1) {
+                    bitLen = columnLength * 4 * 8;
+                    sourceType = sb.append("(").append(columnLength).append(")").toString();
+                } else {
+                    sourceType = sb.append("(").append("max").append(")").toString();
+                    bitLen = columnLength;
+                }
+                break;
+            case TIMESTAMP:
+                bitLen = columnLength << 3;
+                break;
+            case VARCHAR:
+            case NCHAR:
+            case NVARCHAR:
+            case CHAR:
+                if (columnLength != -1) {
+                    sourceType = sb.append("(").append(columnLength).append(")").toString();
+                } else {
+                    sourceType = sb.append("(").append("max").append(")").toString();
+                }
+                break;
+            case DECIMAL:
+            case NUMERIC:
+                sourceType =
+                        sb.append("(")
+                                .append(precision)
+                                .append(",")
+                                .append(scale)
+                                .append(")")
+                                .toString();
+                break;
+            case TEXT:
+                columnLength = Integer.MAX_VALUE;
+                break;
+            case NTEXT:
+                columnLength = Integer.MAX_VALUE >> 1;
+                break;
+            case IMAGE:
+                bitLen = Integer.MAX_VALUE * 8L;
+                break;
+            default:
+                break;
+        }
+        PhysicalColumn physicalColumn =
+                PhysicalColumn.of(
+                        columnName,
+                        type,
+                        0,
+                        isNullable,
+                        defaultValue,
+                        comment,
+                        sourceType,
+                        false,
+                        false,
+                        bitLen,
+                        null,
+                        columnLength);
+        builder.column(physicalColumn);
+    }
+
+    private SeaTunnelDataType<?> fromJdbcType(String typeName, int precision, int scale) {
+        Pair<SqlServerType, Map<String, Object>> pair = SqlServerType.parse(typeName);
+        Map<String, Object> dataTypeProperties = new HashMap<>();
+        dataTypeProperties.put(SqlServerDataTypeConvertor.PRECISION, precision);
+        dataTypeProperties.put(SqlServerDataTypeConvertor.SCALE, scale);
+        return new SqlServerDataTypeConvertor().toSeaTunnelType(pair.getLeft(), dataTypeProperties);
+    }
+
     @Override
     protected boolean createTableInternal(TablePath tablePath, CatalogTable table)
             throws CatalogException {
-        throw new UnsupportedOperationException("Unsupported create table");
+
+        String createTableSql =
+                SqlServerCreateTableSqlBuilder.builder(tablePath, table).build(tablePath, table);
+        log.info("create table sql: {}", createTableSql);
+        try (Connection conn = DriverManager.getConnection(defaultUrl, username, pwd);
+                PreparedStatement ps = conn.prepareStatement(createTableSql)) {
+            System.out.println(createTableSql);
+            return ps.execute();
+        } catch (Exception e) {
+            throw new CatalogException(
+                    String.format("Failed creating table %s", tablePath.getFullName()), e);
+        }
     }
 
     @Override
@@ -222,7 +314,8 @@ protected boolean dropTableInternal(TablePath tablePath) throws CatalogException
         try (Connection conn = DriverManager.getConnection(dbUrl, username, pwd);
                 PreparedStatement ps =
                         conn.prepareStatement(
-                                String.format("DROP TABLE IF EXIST %s", tablePath.getFullName()))) {
+                                String.format(
+                                        "DROP TABLE IF EXISTS %s", tablePath.getFullName()))) {
             // Will there exist concurrent drop for one table?
             return ps.execute();
         } catch (SQLException e) {
@@ -289,4 +382,9 @@ private Map<String, String> buildConnectorOptions(TablePath tablePath) {
     private String getUrlFromDatabaseName(String databaseName) {
         return baseUrl + ";databaseName=" + databaseName + ";" + suffix;
     }
+
+    private String getCreateTableSql(TablePath tablePath, CatalogTable table) {
+
+        return "";
+    }
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogFactory.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogFactory.java
index a59b7e399f3..9ddd035b2ad 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogFactory.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogFactory.java
@@ -32,10 +32,11 @@
 
 @AutoService(Factory.class)
 public class SqlServerCatalogFactory implements CatalogFactory {
+    public static final String IDENTIFIER = "SqlServer";
 
     @Override
     public String factoryIdentifier() {
-        return "SqlServer";
+        return IDENTIFIER;
     }
 
     @Override
@@ -50,7 +51,8 @@ public Catalog createCatalog(String catalogName, ReadonlyConfig options) {
                 catalogName,
                 options.get(JdbcCatalogOptions.USERNAME),
                 options.get(JdbcCatalogOptions.PASSWORD),
-                urlInfo);
+                urlInfo,
+                options.get(JdbcCatalogOptions.SCHEMA));
     }
 
     @Override
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCreateTableSqlBuilder.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCreateTableSqlBuilder.java
new file mode 100644
index 00000000000..cf100075ad1
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCreateTableSqlBuilder.java
@@ -0,0 +1,310 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.Column;
+import org.apache.seatunnel.api.table.catalog.ConstraintKey;
+import org.apache.seatunnel.api.table.catalog.PrimaryKey;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.api.table.catalog.TableSchema;
+import org.apache.seatunnel.api.table.type.DecimalType;
+import org.apache.seatunnel.api.table.type.SqlType;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class SqlServerCreateTableSqlBuilder {
+
+    private final String tableName;
+    private List<Column> columns;
+
+    private String comment;
+
+    private String engine;
+    private String charset;
+    private String collate;
+
+    private PrimaryKey primaryKey;
+
+    private List<ConstraintKey> constraintKeys;
+
+    private SqlServerDataTypeConvertor sqlServerDataTypeConvertor;
+
+    private SqlServerCreateTableSqlBuilder(String tableName) {
+        checkNotNull(tableName, "tableName must not be null");
+        this.tableName = tableName;
+        this.sqlServerDataTypeConvertor = new SqlServerDataTypeConvertor();
+    }
+
+    public static SqlServerCreateTableSqlBuilder builder(
+            TablePath tablePath, CatalogTable catalogTable) {
+        checkNotNull(tablePath, "tablePath must not be null");
+        checkNotNull(catalogTable, "catalogTable must not be null");
+
+        TableSchema tableSchema = catalogTable.getTableSchema();
+        checkNotNull(tableSchema, "tableSchema must not be null");
+
+        return new SqlServerCreateTableSqlBuilder(tablePath.getTableName())
+                .comment(catalogTable.getComment())
+                // todo: set charset and collate
+                .engine(null)
+                .charset(null)
+                .primaryKey(tableSchema.getPrimaryKey())
+                .constraintKeys(tableSchema.getConstraintKeys())
+                .addColumn(tableSchema.getColumns());
+    }
+
+    public SqlServerCreateTableSqlBuilder addColumn(List<Column> columns) {
+        checkArgument(CollectionUtils.isNotEmpty(columns), "columns must not be empty");
+        this.columns = columns;
+        return this;
+    }
+
+    public SqlServerCreateTableSqlBuilder primaryKey(PrimaryKey primaryKey) {
+        this.primaryKey = primaryKey;
+        return this;
+    }
+
+    public SqlServerCreateTableSqlBuilder constraintKeys(List<ConstraintKey> constraintKeys) {
+        this.constraintKeys = constraintKeys;
+        return this;
+    }
+
+    public SqlServerCreateTableSqlBuilder engine(String engine) {
+        this.engine = engine;
+        return this;
+    }
+
+    public SqlServerCreateTableSqlBuilder charset(String charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    public SqlServerCreateTableSqlBuilder collate(String collate) {
+        this.collate = collate;
+        return this;
+    }
+
+    public SqlServerCreateTableSqlBuilder comment(String comment) {
+        this.comment = comment;
+        return this;
+    }
+
+    public String build(TablePath tablePath, CatalogTable catalogTable) {
+        List<String> sqls = new ArrayList<>();
+        String sqlTableName = tablePath.getFullName();
+        Map<String, String> columnComments = new HashMap<>();
+        sqls.add(
+                String.format(
+                        "IF OBJECT_ID('%s', 'U') IS NULL \n"
+                                + "BEGIN \n"
+                                + "CREATE TABLE %s ( \n%s\n)",
+                        sqlTableName,
+                        sqlTableName,
+                        buildColumnsIdentifySql(catalogTable.getCatalogName(), columnComments)));
+        if (engine != null) {
+            sqls.add("ENGINE = " + engine);
+        }
+        if (charset != null) {
+            sqls.add("DEFAULT CHARSET = " + charset);
+        }
+        if (collate != null) {
+            sqls.add("COLLATE = " + collate);
+        }
+        String sqlTableSql = String.join(" ", sqls) + ";";
+        StringBuilder tableAndColumnComment = new StringBuilder();
+        if (comment != null) {
+            sqls.add("COMMENT = '" + comment + "'");
+            tableAndColumnComment.append(
+                    String.format(
+                            "EXEC %s.sys.sp_addextendedproperty 'MS_Description', N'%s', 'schema', N'%s', 'table', N'%s';\n",
+                            tablePath.getDatabaseName(),
+                            comment,
+                            tablePath.getSchemaName(),
+                            tablePath.getTableName()));
+        }
+        String columnComment =
+                "EXEC %s.sys.sp_addextendedproperty 'MS_Description', N'%s', 'schema', N'%s', 'table', N'%s', 'column', N'%s';\n";
+        columnComments.forEach(
+                (fieldName, com) -> {
+                    tableAndColumnComment.append(
+                            String.format(
+                                    columnComment,
+                                    tablePath.getDatabaseName(),
+                                    com,
+                                    tablePath.getSchemaName(),
+                                    tablePath.getTableName(),
+                                    fieldName));
+                });
+        return String.join("\n", sqlTableSql, tableAndColumnComment.toString(), "END");
+    }
+
+    private String buildColumnsIdentifySql(String catalogName, Map<String, String> columnComments) {
+        List<String> columnSqls = new ArrayList<>();
+        for (Column column : columns) {
+            columnSqls.add("\t" + buildColumnIdentifySql(column, catalogName, columnComments));
+        }
+        if (primaryKey != null) {
+            columnSqls.add("\t" + buildPrimaryKeySql());
+        }
+        if (CollectionUtils.isNotEmpty(constraintKeys)) {
+            for (ConstraintKey constraintKey : constraintKeys) {
+                if (StringUtils.isBlank(constraintKey.getConstraintName())) {
+                    continue;
+                }
+            }
+        }
+        return String.join(", \n", columnSqls);
+    }
+
+    private String buildColumnIdentifySql(
+            Column column, String catalogName, Map<String, String> columnComments) {
+        final List<String> columnSqls = new ArrayList<>();
+        columnSqls.add(column.getName());
+        String tyNameDef = "";
+        if (StringUtils.equals(catalogName, "sqlserver")) {
+            columnSqls.add(column.getSourceType());
+        } else {
+            // Column name
+            SqlType dataType = column.getDataType().getSqlType();
+            boolean isBytes = StringUtils.equals(dataType.name(), SqlType.BYTES.name());
+            Long columnLength = column.getLongColumnLength();
+            Long bitLen = column.getBitLen();
+            bitLen = bitLen == -1 || bitLen <= 8 ? bitLen : bitLen >> 3;
+            if (isBytes) {
+                if (bitLen > 8000 || bitLen == -1) {
+                    columnSqls.add(SqlServerType.VARBINARY.getName());
+                } else {
+                    columnSqls.add(SqlServerType.BINARY.getName());
+                    tyNameDef = SqlServerType.BINARY.getName();
+                }
+                columnSqls.add("(" + (bitLen == -1 || bitLen > 8000 ? "max)" : bitLen + ")"));
+            } else {
+                // Add column type
+                SqlServerType sqlServerType =
+                        sqlServerDataTypeConvertor.toConnectorType(column.getDataType(), null);
+                String typeName = sqlServerType.getName();
+                String fieldSuffixSql = null;
+                tyNameDef = typeName;
+                // Add column length
+                if (StringUtils.equals(SqlServerType.VARCHAR.getName(), typeName)) {
+                    if (columnLength > 8000 || columnLength == -1) {
+                        columnSqls.add(typeName);
+                        fieldSuffixSql = "(max)";
+                    } else if (columnLength > 4000) {
+                        columnSqls.add(SqlServerType.VARCHAR.getName());
+                        fieldSuffixSql = "(" + columnLength + ")";
+                    } else {
+                        columnSqls.add(SqlServerType.NVARCHAR.getName());
+                        if (columnLength > 0) {
+                            fieldSuffixSql = "(" + columnLength + ")";
+                        }
+                    }
+                    columnSqls.add(fieldSuffixSql);
+                } else if (StringUtils.equals(SqlServerType.DECIMAL.getName(), typeName)) {
+                    columnSqls.add(typeName);
+                    DecimalType decimalType = (DecimalType) column.getDataType();
+                    columnSqls.add(
+                            String.format(
+                                    "(%d, %d)",
+                                    decimalType.getPrecision(), decimalType.getScale()));
+                } else {
+                    columnSqls.add(typeName);
+                }
+            }
+        }
+        // nullable
+        if (column.isNullable()) {
+            columnSqls.add("NULL");
+        } else {
+            columnSqls.add("NOT NULL");
+        }
+        // default value
+        //        if (column.getDefaultValue() != null) {
+        //            String defaultValue = "'" + column.getDefaultValue().toString() + "'";
+        //            if (StringUtils.equals(SqlServerType.BINARY.getName(), tyNameDef)
+        //                    && defaultValue.contains("b'")) {
+        //                String rep = defaultValue.replace("b", "").replace("'", "");
+        //                defaultValue = "0x" + Integer.toHexString(Integer.parseInt(rep));
+        //            } else if (StringUtils.equals(SqlServerType.BIT.getName(), tyNameDef)
+        //                    && defaultValue.contains("b'")) {
+        //                defaultValue = defaultValue.replace("b", "").replace("'", "");
+        //            }
+        //            columnSqls.add("DEFAULT " + defaultValue);
+        //        }
+        // comment
+        if (column.getComment() != null) {
+            columnComments.put(column.getName(), column.getComment());
+        }
+
+        return String.join(" ", columnSqls);
+    }
+
+    private String buildPrimaryKeySql() {
+        //                        .map(columnName -> "`" + columnName + "`")
+        String key = String.join(", ", primaryKey.getColumnNames());
+        // add sort type
+        return String.format("PRIMARY KEY (%s)", key);
+    }
+
+    private String buildConstraintKeySql(ConstraintKey constraintKey) {
+        ConstraintKey.ConstraintType constraintType = constraintKey.getConstraintType();
+        String indexColumns =
+                constraintKey.getColumnNames().stream()
+                        .map(
+                                constraintKeyColumn -> {
+                                    if (constraintKeyColumn.getSortType() == null) {
+                                        return String.format(
+                                                "`%s`", constraintKeyColumn.getColumnName());
+                                    }
+                                    return String.format(
+                                            "`%s` %s",
+                                            constraintKeyColumn.getColumnName(),
+                                            constraintKeyColumn.getSortType().name());
+                                })
+                        .collect(Collectors.joining(", "));
+        String keyName = null;
+        switch (constraintType) {
+            case KEY:
+                keyName = "KEY";
+                break;
+            case UNIQUE_KEY:
+                keyName = "UNIQUE KEY";
+                break;
+            case FOREIGN_KEY:
+                keyName = "FOREIGN KEY";
+                // todo:
+                break;
+            default:
+                throw new UnsupportedOperationException(
+                        "Unsupported constraint type: " + constraintType);
+        }
+        return String.format(
+                "%s `%s` (%s)", keyName, constraintKey.getConstraintName(), indexColumns);
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerDataTypeConvertor.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerDataTypeConvertor.java
index e04be54a56b..afad20c67c1 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerDataTypeConvertor.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerDataTypeConvertor.java
@@ -132,9 +132,9 @@ public SqlServerType toConnectorType(
             case DATE:
                 return SqlServerType.DATE;
             case TIME:
-                return SqlServerType.DATETIME;
+                return SqlServerType.TIME;
             case TIMESTAMP:
-                return SqlServerType.TIMESTAMP;
+                return SqlServerType.DATETIME2;
             default:
                 throw new JdbcConnectorException(
                         CommonErrorCode.UNSUPPORTED_DATA_TYPE,
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParser.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParser.java
index 94b0bde5abf..fa8ed1869d4 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParser.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParser.java
@@ -77,12 +77,16 @@ public static JdbcUrlUtil.UrlInfo parse(String url) {
 
         String suffix =
                 props.entrySet().stream()
+                        .filter(
+                                e ->
+                                        !e.getKey().equals("databaseName")
+                                                && !e.getKey().equals("database"))
                         .map(e -> e.getKey() + "=" + e.getValue())
-                        .collect(Collectors.joining(";", ";", ""));
+                        .collect(Collectors.joining(";", "", ""));
         suffix = Optional.ofNullable(suffix).orElse("");
         return new JdbcUrlUtil.UrlInfo(
                 url,
-                String.format("jdbc:sqlserver://%s:%s", serverName, port) + suffix,
+                String.format("jdbc:sqlserver://%s:%s", serverName, port) + ";" + suffix,
                 serverName,
                 port,
                 dbInstance,
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcOptions.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcOptions.java
index 24ae0580f32..f5d1613c53e 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcOptions.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcOptions.java
@@ -74,7 +74,7 @@ public interface JdbcOptions {
     Option<Integer> BATCH_INTERVAL_MS =
             Options.key("batch_interval_ms")
                     .intType()
-                    .defaultValue(1000)
+                    .defaultValue(0)
                     .withDescription("batch interval milliSecond");
 
     Option<Boolean> IS_EXACTLY_ONCE =
@@ -122,6 +122,23 @@ public interface JdbcOptions {
                     .defaultValue(false)
                     .withDescription("support upsert by query primary_key exist");
 
+    Option<Boolean> ENABLE_UPSERT =
+            Options.key("enable_upsert")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription("enable upsert by primary_keys exist");
+    Option<Boolean> IS_PRIMARY_KEY_UPDATED =
+            Options.key("is_primary_key_updated")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription(
+                            "is the primary key updated when performing an update operation");
+    Option<Boolean> SUPPORT_UPSERT_BY_INSERT_ONLY =
+            Options.key("support_upsert_by_insert_only")
+                    .booleanType()
+                    .defaultValue(false)
+                    .withDescription("support upsert by insert only");
+
     /** source config */
     Option<String> PARTITION_COLUMN =
             Options.key("partition_column")
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcSinkConfig.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcSinkConfig.java
index f7a3cd29109..af24a9a6b03 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcSinkConfig.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/config/JdbcSinkConfig.java
@@ -25,10 +25,12 @@
 import java.io.Serializable;
 import java.util.List;
 
-import static org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcOptions.SUPPORT_UPSERT_BY_QUERY_PRIMARY_KEY_EXIST;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcOptions.ENABLE_UPSERT;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcOptions.IS_PRIMARY_KEY_UPDATED;
+import static org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcOptions.SUPPORT_UPSERT_BY_INSERT_ONLY;
 
 @Data
-@Builder(builderClassName = "Builder")
+@Builder
 public class JdbcSinkConfig implements Serializable {
     private static final long serialVersionUID = 2L;
 
@@ -38,17 +40,21 @@ public class JdbcSinkConfig implements Serializable {
     private String database;
     private String table;
     private List<String> primaryKeys;
-    private boolean supportUpsertByQueryPrimaryKeyExist;
+    private boolean enableUpsert;
+    @Builder.Default private boolean isPrimaryKeyUpdated = true;
+    private boolean supportUpsertByInsertOnly;
 
     public static JdbcSinkConfig of(ReadonlyConfig config) {
-        JdbcSinkConfig.Builder builder = JdbcSinkConfig.builder();
+        JdbcSinkConfigBuilder builder = JdbcSinkConfig.builder();
         builder.jdbcConnectionConfig(JdbcConnectionConfig.of(config));
         builder.isExactlyOnce(config.get(JdbcOptions.IS_EXACTLY_ONCE));
         config.getOptional(JdbcOptions.PRIMARY_KEYS).ifPresent(builder::primaryKeys);
         config.getOptional(JdbcOptions.DATABASE).ifPresent(builder::database);
         config.getOptional(JdbcOptions.TABLE).ifPresent(builder::table);
-        config.getOptional(SUPPORT_UPSERT_BY_QUERY_PRIMARY_KEY_EXIST)
-                .ifPresent(builder::supportUpsertByQueryPrimaryKeyExist);
+        config.getOptional(ENABLE_UPSERT).ifPresent(builder::enableUpsert);
+        config.getOptional(IS_PRIMARY_KEY_UPDATED).ifPresent(builder::isPrimaryKeyUpdated);
+        config.getOptional(SUPPORT_UPSERT_BY_INSERT_ONLY)
+                .ifPresent(builder::supportUpsertByInsertOnly);
         config.getOptional(JdbcOptions.QUERY).ifPresent(builder::simpleSql);
         return builder.build();
     }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/JdbcOutputFormatBuilder.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/JdbcOutputFormatBuilder.java
index 78e8814392f..cd752d43960 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/JdbcOutputFormatBuilder.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/JdbcOutputFormatBuilder.java
@@ -17,6 +17,7 @@
 
 package org.apache.seatunnel.connectors.seatunnel.jdbc.internal;
 
+import org.apache.seatunnel.api.table.catalog.TablePath;
 import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
 import org.apache.seatunnel.api.table.type.SeaTunnelRow;
 import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
@@ -55,7 +56,11 @@ public JdbcOutputFormat build() {
         JdbcOutputFormat.StatementExecutorFactory statementExecutorFactory;
 
         final String database = jdbcSinkConfig.getDatabase();
-        final String table = jdbcSinkConfig.getTable();
+        final String table =
+                dialect.extractTableName(
+                        TablePath.of(
+                                jdbcSinkConfig.getDatabase() + "." + jdbcSinkConfig.getTable()));
+
         final List<String> primaryKeys = jdbcSinkConfig.getPrimaryKeys();
         if (StringUtils.isNotBlank(jdbcSinkConfig.getSimpleSql())) {
             statementExecutorFactory =
@@ -76,7 +81,9 @@ public JdbcOutputFormat build() {
                                     table,
                                     seaTunnelRowType,
                                     primaryKeys.toArray(new String[0]),
-                                    jdbcSinkConfig.isSupportUpsertByQueryPrimaryKeyExist());
+                                    jdbcSinkConfig.isEnableUpsert(),
+                                    jdbcSinkConfig.isPrimaryKeyUpdated(),
+                                    jdbcSinkConfig.isSupportUpsertByInsertOnly());
         }
 
         return new JdbcOutputFormat(
@@ -104,7 +111,9 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createUpsertBufferedExec
             String table,
             SeaTunnelRowType rowType,
             String[] pkNames,
-            boolean supportUpsertByQueryPrimaryKeyExist) {
+            boolean enableUpsert,
+            boolean isPrimaryKeyUpdated,
+            boolean supportUpsertByInsertOnly) {
         int[] pkFields = Arrays.stream(pkNames).mapToInt(rowType::indexOf).toArray();
         SeaTunnelDataType[] pkTypes =
                 Arrays.stream(pkFields)
@@ -123,7 +132,9 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createUpsertBufferedExec
                         pkNames,
                         pkTypes,
                         keyExtractor,
-                        supportUpsertByQueryPrimaryKeyExist);
+                        enableUpsert,
+                        isPrimaryKeyUpdated,
+                        supportUpsertByInsertOnly);
         return new BufferReducedBatchStatementExecutor(
                 upsertExecutor, deleteExecutor, keyExtractor, Function.identity());
     }
@@ -136,17 +147,44 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createUpsertExecutor(
             String[] pkNames,
             SeaTunnelDataType[] pkTypes,
             Function<SeaTunnelRow, SeaTunnelRow> keyExtractor,
-            boolean supportUpsertByQueryPrimaryKeyExist) {
-        Optional<String> upsertSQL =
-                dialect.getUpsertStatement(database, table, rowType.getFieldNames(), pkNames);
-        if (upsertSQL.isPresent()) {
-            return createSimpleExecutor(upsertSQL.get(), rowType, dialect.getRowConverter());
+            boolean enableUpsert,
+            boolean isPrimaryKeyUpdated,
+            boolean supportUpsertByInsertOnly) {
+        if (supportUpsertByInsertOnly) {
+            return createInsertOnlyExecutor(dialect, database, table, rowType);
         }
-        if (supportUpsertByQueryPrimaryKeyExist) {
+        if (enableUpsert) {
+            Optional<String> upsertSQL =
+                    dialect.getUpsertStatement(database, table, rowType.getFieldNames(), pkNames);
+            if (upsertSQL.isPresent()) {
+                return createSimpleExecutor(upsertSQL.get(), rowType, dialect.getRowConverter());
+            }
             return createInsertOrUpdateByQueryExecutor(
-                    dialect, database, table, rowType, pkNames, pkTypes, keyExtractor);
+                    dialect,
+                    database,
+                    table,
+                    rowType,
+                    pkNames,
+                    pkTypes,
+                    keyExtractor,
+                    isPrimaryKeyUpdated);
         }
-        return createInsertOrUpdateExecutor(dialect, database, table, rowType, pkNames);
+        return createInsertOrUpdateExecutor(
+                dialect, database, table, rowType, pkNames, isPrimaryKeyUpdated);
+    }
+
+    private static JdbcBatchStatementExecutor<SeaTunnelRow> createInsertOnlyExecutor(
+            JdbcDialect dialect, String database, String table, SeaTunnelRowType rowType) {
+
+        return new SimpleBatchStatementExecutor(
+                connection ->
+                        FieldNamedPreparedStatement.prepareStatement(
+                                connection,
+                                dialect.getInsertIntoStatement(
+                                        database, table, rowType.getFieldNames()),
+                                rowType.getFieldNames()),
+                rowType,
+                dialect.getRowConverter());
     }
 
     private static JdbcBatchStatementExecutor<SeaTunnelRow> createInsertOrUpdateExecutor(
@@ -154,7 +192,8 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createInsertOrUpdateExec
             String database,
             String table,
             SeaTunnelRowType rowType,
-            String[] pkNames) {
+            String[] pkNames,
+            boolean isPrimaryKeyUpdated) {
 
         return new InsertOrUpdateBatchStatementExecutor(
                 connection ->
@@ -167,7 +206,11 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createInsertOrUpdateExec
                         FieldNamedPreparedStatement.prepareStatement(
                                 connection,
                                 dialect.getUpdateStatement(
-                                        database, table, rowType.getFieldNames(), pkNames),
+                                        database,
+                                        table,
+                                        rowType.getFieldNames(),
+                                        pkNames,
+                                        isPrimaryKeyUpdated),
                                 rowType.getFieldNames()),
                 rowType,
                 dialect.getRowConverter());
@@ -180,7 +223,8 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createInsertOrUpdateByQu
             SeaTunnelRowType rowType,
             String[] pkNames,
             SeaTunnelDataType[] pkTypes,
-            Function<SeaTunnelRow, SeaTunnelRow> keyExtractor) {
+            Function<SeaTunnelRow, SeaTunnelRow> keyExtractor,
+            boolean isPrimaryKeyUpdated) {
         SeaTunnelRowType keyRowType = new SeaTunnelRowType(pkNames, pkTypes);
         return new InsertOrUpdateBatchStatementExecutor(
                 connection ->
@@ -198,7 +242,11 @@ private static JdbcBatchStatementExecutor<SeaTunnelRow> createInsertOrUpdateByQu
                         FieldNamedPreparedStatement.prepareStatement(
                                 connection,
                                 dialect.getUpdateStatement(
-                                        database, table, rowType.getFieldNames(), pkNames),
+                                        database,
+                                        table,
+                                        rowType.getFieldNames(),
+                                        pkNames,
+                                        isPrimaryKeyUpdated),
                                 rowType.getFieldNames()),
                 keyRowType,
                 keyExtractor,
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/JdbcDialect.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/JdbcDialect.java
index e8967fce08f..8a0b31a5eeb 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/JdbcDialect.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/JdbcDialect.java
@@ -17,6 +17,7 @@
 
 package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect;
 
+import org.apache.seatunnel.api.table.catalog.TablePath;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcSourceConfig;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.converter.JdbcRowConverter;
 
@@ -109,7 +110,21 @@ default String getInsertIntoStatement(String database, String tableName, String[
      * @return the dialects {@code UPDATE} statement.
      */
     default String getUpdateStatement(
-            String database, String tableName, String[] fieldNames, String[] conditionFields) {
+            String database,
+            String tableName,
+            String[] fieldNames,
+            String[] conditionFields,
+            boolean isPrimaryKeyUpdated) {
+
+        fieldNames =
+                Arrays.stream(fieldNames)
+                        .filter(
+                                fieldName ->
+                                        isPrimaryKeyUpdated
+                                                || !Arrays.asList(conditionFields)
+                                                        .contains(fieldName))
+                        .toArray(String[]::new);
+
         String setClause =
                 Arrays.stream(fieldNames)
                         .map(fieldName -> format("%s = :%s", quoteIdentifier(fieldName), fieldName))
@@ -200,4 +215,8 @@ default ResultSetMetaData getResultSetMetaData(
         PreparedStatement ps = conn.prepareStatement(jdbcSourceConfig.getQuery());
         return ps.getMetaData();
     }
+
+    default String extractTableName(TablePath tablePath) {
+        return tablePath.getSchemaAndTableName();
+    }
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/mysql/MysqlDialect.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/mysql/MysqlDialect.java
index 128b8ae4be9..c71dc3f76a1 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/mysql/MysqlDialect.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/mysql/MysqlDialect.java
@@ -17,6 +17,7 @@
 
 package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.mysql;
 
+import org.apache.seatunnel.api.table.catalog.TablePath;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.converter.JdbcRowConverter;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialect;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialectTypeMapper;
@@ -78,4 +79,9 @@ public PreparedStatement creatPreparedStatement(
         statement.setFetchSize(Integer.MIN_VALUE);
         return statement;
     }
+
+    @Override
+    public String extractTableName(TablePath tablePath) {
+        return tablePath.getTableName();
+    }
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/sqlserver/SqlserverJdbcRowConverter.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/sqlserver/SqlserverJdbcRowConverter.java
index 1c22737b657..717293e4f36 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/sqlserver/SqlserverJdbcRowConverter.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/sqlserver/SqlserverJdbcRowConverter.java
@@ -17,12 +17,100 @@
 
 package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.sqlserver;
 
+import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
+import org.apache.seatunnel.api.table.type.SeaTunnelRow;
+import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
+import org.apache.seatunnel.api.table.type.SqlType;
+import org.apache.seatunnel.common.exception.CommonErrorCode;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.exception.JdbcConnectorException;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.converter.AbstractJdbcRowConverter;
 
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
 public class SqlserverJdbcRowConverter extends AbstractJdbcRowConverter {
 
     @Override
     public String converterName() {
         return "Sqlserver";
     }
+
+    public PreparedStatement toExternal(
+            SeaTunnelRowType rowType, SeaTunnelRow row, PreparedStatement statement)
+            throws SQLException {
+        for (int fieldIndex = 0; fieldIndex < rowType.getTotalFields(); fieldIndex++) {
+            SeaTunnelDataType<?> seaTunnelDataType = rowType.getFieldType(fieldIndex);
+            int statementIndex = fieldIndex + 1;
+            Object fieldValue = row.getField(fieldIndex);
+            if (fieldValue == null && seaTunnelDataType.getSqlType() != SqlType.BYTES) {
+                statement.setObject(statementIndex, null);
+                continue;
+            }
+
+            switch (seaTunnelDataType.getSqlType()) {
+                case STRING:
+                    statement.setString(statementIndex, (String) row.getField(fieldIndex));
+                    break;
+                case BOOLEAN:
+                    statement.setBoolean(statementIndex, (Boolean) row.getField(fieldIndex));
+                    break;
+                case TINYINT:
+                    statement.setByte(statementIndex, (Byte) row.getField(fieldIndex));
+                    break;
+                case SMALLINT:
+                    statement.setShort(statementIndex, (Short) row.getField(fieldIndex));
+                    break;
+                case INT:
+                    statement.setInt(statementIndex, (Integer) row.getField(fieldIndex));
+                    break;
+                case BIGINT:
+                    statement.setLong(statementIndex, (Long) row.getField(fieldIndex));
+                    break;
+                case FLOAT:
+                    statement.setFloat(statementIndex, (Float) row.getField(fieldIndex));
+                    break;
+                case DOUBLE:
+                    statement.setDouble(statementIndex, (Double) row.getField(fieldIndex));
+                    break;
+                case DECIMAL:
+                    statement.setBigDecimal(statementIndex, (BigDecimal) row.getField(fieldIndex));
+                    break;
+                case DATE:
+                    LocalDate localDate = (LocalDate) row.getField(fieldIndex);
+                    statement.setDate(statementIndex, java.sql.Date.valueOf(localDate));
+                    break;
+                case TIME:
+                    LocalTime localTime = (LocalTime) row.getField(fieldIndex);
+                    statement.setTime(statementIndex, java.sql.Time.valueOf(localTime));
+                    break;
+                case TIMESTAMP:
+                    LocalDateTime localDateTime = (LocalDateTime) row.getField(fieldIndex);
+                    statement.setTimestamp(
+                            statementIndex, java.sql.Timestamp.valueOf(localDateTime));
+                    break;
+                case BYTES:
+                    if (row.getField(fieldIndex) == null) {
+                        statement.setBytes(statementIndex, new byte[0]);
+                        break;
+                    }
+                    statement.setBytes(statementIndex, (byte[]) row.getField(fieldIndex));
+                    break;
+                case NULL:
+                    statement.setNull(statementIndex, java.sql.Types.NULL);
+                    break;
+                case MAP:
+                case ARRAY:
+                case ROW:
+                default:
+                    throw new JdbcConnectorException(
+                            CommonErrorCode.UNSUPPORTED_DATA_TYPE,
+                            "Unexpected value: " + seaTunnelDataType);
+            }
+        }
+        return statement;
+    }
 }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSink.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSink.java
index eec473512b7..c23619b5aad 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSink.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSink.java
@@ -34,10 +34,10 @@
 import org.apache.seatunnel.api.table.catalog.CatalogOptions;
 import org.apache.seatunnel.api.table.catalog.CatalogTable;
 import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.api.table.factory.CatalogFactory;
 import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
 import org.apache.seatunnel.api.table.type.SeaTunnelRow;
 import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
-import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.tidb.TiDBCatalogFactory;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcSinkConfig;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.exception.JdbcConnectorException;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialect;
@@ -58,6 +58,7 @@
 import java.util.Optional;
 
 import static org.apache.seatunnel.api.common.SeaTunnelAPIErrorCode.HANDLE_SAVE_MODE_FAILED;
+import static org.apache.seatunnel.api.table.factory.FactoryUtil.discoverFactory;
 
 @AutoService(SeaTunnelSink.class)
 public class JdbcSink
@@ -189,28 +190,36 @@ public DataSaveMode getUserConfigSaveMode() {
     public void handleSaveMode(DataSaveMode saveMode) {
         if (catalogTable != null) {
             Map<String, String> catalogOptions = config.get(CatalogOptions.CATALOG_OPTIONS);
-            if (catalogOptions != null
-                    && TiDBCatalogFactory.IDENTIFIER.equalsIgnoreCase(
-                            catalogOptions.get(CommonOptions.FACTORY_ID.key()))) {
+            if (catalogOptions != null) {
+                String factoryId = catalogOptions.get(CommonOptions.FACTORY_ID.key());
                 if (StringUtils.isBlank(jdbcSinkConfig.getDatabase())) {
                     return;
                 }
-                try (Catalog catalog =
-                        new TiDBCatalogFactory()
-                                .createCatalog(
-                                        TiDBCatalogFactory.IDENTIFIER,
-                                        ReadonlyConfig.fromMap(new HashMap<>(catalogOptions)))) {
-                    catalog.open();
-                    TablePath tablePath =
-                            TablePath.of(jdbcSinkConfig.getDatabase(), jdbcSinkConfig.getTable());
-                    if (!catalog.databaseExists(jdbcSinkConfig.getDatabase())) {
-                        catalog.createDatabase(tablePath, true);
+                CatalogFactory catalogFactory =
+                        discoverFactory(
+                                Thread.currentThread().getContextClassLoader(),
+                                CatalogFactory.class,
+                                factoryId);
+                if (catalogFactory != null) {
+                    try (Catalog catalog =
+                            catalogFactory.createCatalog(
+                                    catalogFactory.factoryIdentifier(),
+                                    ReadonlyConfig.fromMap(new HashMap<>(catalogOptions)))) {
+                        catalog.open();
+                        TablePath tablePath =
+                                TablePath.of(
+                                        jdbcSinkConfig.getDatabase()
+                                                + "."
+                                                + jdbcSinkConfig.getTable());
+                        if (!catalog.databaseExists(jdbcSinkConfig.getDatabase())) {
+                            catalog.createDatabase(tablePath, true);
+                        }
+                        if (!catalog.tableExists(tablePath)) {
+                            catalog.createTable(tablePath, catalogTable, true);
+                        }
+                    } catch (Exception e) {
+                        throw new JdbcConnectorException(HANDLE_SAVE_MODE_FAILED, e);
                     }
-                    if (!catalog.tableExists(tablePath)) {
-                        catalog.createTable(tablePath, catalogTable, true);
-                    }
-                } catch (Exception e) {
-                    throw new JdbcConnectorException(HANDLE_SAVE_MODE_FAILED, e);
                 }
             }
         }
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkFactory.java b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkFactory.java
index a9bb1c15554..61c9b9c8ad1 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkFactory.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/sink/JdbcSinkFactory.java
@@ -20,17 +20,21 @@
 import org.apache.seatunnel.api.configuration.ReadonlyConfig;
 import org.apache.seatunnel.api.configuration.util.OptionRule;
 import org.apache.seatunnel.api.sink.DataSaveMode;
+import org.apache.seatunnel.api.table.catalog.CatalogOptions;
 import org.apache.seatunnel.api.table.catalog.CatalogTable;
 import org.apache.seatunnel.api.table.catalog.PrimaryKey;
+import org.apache.seatunnel.api.table.catalog.TableIdentifier;
 import org.apache.seatunnel.api.table.connector.TableSink;
 import org.apache.seatunnel.api.table.factory.Factory;
 import org.apache.seatunnel.api.table.factory.TableFactoryContext;
 import org.apache.seatunnel.api.table.factory.TableSinkFactory;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.JdbcCatalogOptions;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcSinkConfig;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialect;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialectLoader;
 
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 
 import com.google.auto.service.AutoService;
 
@@ -70,10 +74,49 @@ public String factoryIdentifier() {
     public TableSink createSink(TableFactoryContext context) {
         ReadonlyConfig config = context.getOptions();
         CatalogTable catalogTable = context.getCatalogTable();
+        Map<String, String> catalogOptions = config.get(CatalogOptions.CATALOG_OPTIONS);
         Optional<String> optionalTable = config.getOptional(TABLE);
         if (!optionalTable.isPresent()) {
+            catalogOptions = catalogOptions == null ? new HashMap<>() : catalogOptions;
+            String prefix = catalogOptions.get(JdbcCatalogOptions.TABLE_PREFIX.key());
+            String suffix = catalogOptions.get(JdbcCatalogOptions.TABLE_SUFFIX.key());
+            if (StringUtils.isNotEmpty(prefix) || StringUtils.isNotEmpty(suffix)) {
+                TableIdentifier tableId = catalogTable.getTableId();
+                String tableName =
+                        StringUtils.isNotEmpty(prefix)
+                                ? prefix + tableId.getTableName()
+                                : tableId.getTableName();
+                tableName = StringUtils.isNotEmpty(suffix) ? tableName + suffix : tableName;
+                TableIdentifier newTableId =
+                        TableIdentifier.of(
+                                tableId.getCatalogName(),
+                                tableId.getDatabaseName(),
+                                tableId.getSchemaName(),
+                                tableName);
+                catalogTable =
+                        CatalogTable.of(
+                                newTableId,
+                                catalogTable.getTableSchema(),
+                                catalogTable.getOptions(),
+                                catalogTable.getPartitionKeys(),
+                                catalogTable.getCatalogName());
+            }
             Map<String, String> map = config.toMap();
-            map.put(TABLE.key(), catalogTable.getTableId().getTableName());
+            if (StringUtils.isNotBlank(catalogOptions.get(JdbcCatalogOptions.SCHEMA.key()))) {
+                map.put(
+                        TABLE.key(),
+                        catalogOptions.get(JdbcCatalogOptions.SCHEMA.key())
+                                + "."
+                                + catalogTable.getTableId().getTableName());
+            } else if (StringUtils.isNotBlank(catalogTable.getTableId().getSchemaName())) {
+                map.put(
+                        TABLE.key(),
+                        catalogTable.getTableId().getSchemaName()
+                                + "."
+                                + catalogTable.getTableId().getTableName());
+            } else {
+                map.put(TABLE.key(), catalogTable.getTableId().getTableName());
+            }
 
             PrimaryKey primaryKey = catalogTable.getTableSchema().getPrimaryKey();
             if (primaryKey != null && !CollectionUtils.isEmpty(primaryKey.getColumnNames())) {
@@ -87,13 +130,14 @@ public TableSink createSink(TableFactoryContext context) {
                 JdbcDialectLoader.load(
                         sinkConfig.getJdbcConnectionConfig().getUrl(),
                         sinkConfig.getJdbcConnectionConfig().getCompatibleMode());
+        CatalogTable finalCatalogTable = catalogTable;
         return () ->
                 new JdbcSink(
                         options,
                         sinkConfig,
                         dialect,
                         DataSaveMode.KEEP_SCHEMA_AND_DATA,
-                        catalogTable);
+                        finalCatalogTable);
     }
 
     @Override
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogTest.java b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogTest.java
new file mode 100644
index 00000000000..daf87b3693a
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/mysql/MySqlCatalogTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.mysql;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver.SqlServerCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver.SqlServerURLParser;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@Disabled("Please Test it in your local environment")
+class MySqlCatalogTest {
+
+    static JdbcUrlUtil.UrlInfo sqlParse =
+            SqlServerURLParser.parse("jdbc:sqlserver://127.0.0.1:1434;database=TestDB");
+    static JdbcUrlUtil.UrlInfo MysqlUrlInfo =
+            JdbcUrlUtil.getUrlInfo("jdbc:mysql://127.0.0.1:33061/liuliTest?useSSL=false");
+    static JdbcUrlUtil.UrlInfo pg =
+            JdbcUrlUtil.getUrlInfo("jdbc:postgresql://127.0.0.1:5432/liulitest");
+    static TablePath tablePathSQL;
+    static TablePath tablePathMySql;
+    static TablePath tablePathPG;
+    static TablePath tablePathOracle;
+    private static String databaseName = "liuliTest";
+    private static String schemaName = "dbo";
+    private static String tableName = "AllDataTest";
+
+    static SqlServerCatalog sqlServerCatalog;
+    static MySqlCatalog mySqlCatalog;
+    static PostgresCatalog postgresCatalog;
+
+    static CatalogTable postgresCatalogTable;
+    static CatalogTable mySqlCatalogTable;
+    static CatalogTable sqlServerCatalogTable;
+
+    @Test
+    void listDatabases() {}
+
+    @Test
+    void listTables() {}
+
+    @Test
+    void getColumnsDefaultValue() {}
+
+    @BeforeAll
+    static void before() {
+        tablePathSQL = TablePath.of(databaseName, "sqlserver_to_mysql");
+        tablePathMySql = TablePath.of(databaseName, "mysql_to_mysql");
+        tablePathPG = TablePath.of(databaseName, "pg_to_mysql");
+        tablePathOracle = TablePath.of(databaseName, "oracle_to_mysql");
+        sqlServerCatalog = new SqlServerCatalog("sqlserver", "sa", "root@123", sqlParse, null);
+        mySqlCatalog = new MySqlCatalog("mysql", "root", "root@123", MysqlUrlInfo);
+        postgresCatalog = new PostgresCatalog("postgres", "postgres", "postgres", pg, null);
+        mySqlCatalog.open();
+        sqlServerCatalog.open();
+        postgresCatalog.open();
+    }
+
+    @Test
+    @Order(1)
+    void getTable() {
+        postgresCatalogTable =
+                postgresCatalog.getTable(
+                        TablePath.of("liulitest", "public", "pg_types_table_no_array"));
+        mySqlCatalogTable = mySqlCatalog.getTable(TablePath.of("liuliTest", "AllTypeCol"));
+        sqlServerCatalogTable =
+                sqlServerCatalog.getTable(TablePath.of("TestDB", "dbo", "AllDataTest"));
+    }
+
+    @Test
+    @Order(2)
+    void createTableInternal() {
+        mySqlCatalog.createTable(tablePathMySql, mySqlCatalogTable, true);
+        mySqlCatalog.createTable(tablePathPG, postgresCatalogTable, true);
+        mySqlCatalog.createTable(tablePathSQL, sqlServerCatalogTable, true);
+    }
+
+    @Disabled
+    // Manually dropping tables
+    @Test
+    void dropTableInternal() {
+        mySqlCatalog.dropTable(tablePathSQL, true);
+        mySqlCatalog.dropTable(tablePathMySql, true);
+        mySqlCatalog.dropTable(tablePathPG, true);
+    }
+
+    @Test
+    void createDatabaseInternal() {}
+
+    @Test
+    void dropDatabaseInternal() {}
+
+    @AfterAll
+    static void after() {
+        sqlServerCatalog.close();
+        mySqlCatalog.close();
+        postgresCatalog.close();
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalogTest.java b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalogTest.java
new file mode 100644
index 00000000000..6b8c49bc0ab
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/oracle/OracleCatalogTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.oracle;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.mysql.MySqlCatalog;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+@Disabled("Please Test it in your local environment")
+class OracleCatalogTest {
+    @Test
+    void testCatalog() {
+        OracleCatalog catalog =
+                new OracleCatalog(
+                        "oracle",
+                        "test",
+                        "oracle",
+                        OracleURLParser.parse("jdbc:oracle:thin:@127.0.0.1:1521:xe"),
+                        null);
+
+        catalog.open();
+
+        MySqlCatalog mySqlCatalog =
+                new MySqlCatalog(
+                        "mysql",
+                        "root",
+                        "root@123",
+                        JdbcUrlUtil.getUrlInfo("jdbc:mysql://127.0.0.1:33062/mingdongtest"));
+
+        mySqlCatalog.open();
+
+        CatalogTable table1 =
+                mySqlCatalog.getTable(TablePath.of("mingdongtest", "all_types_table_02"));
+
+        List<String> strings = catalog.listDatabases();
+        System.out.println(strings);
+
+        List<String> strings1 = catalog.listTables("XE");
+
+        CatalogTable table = catalog.getTable(TablePath.of("XE", "TEST", "PG_TYPES_TABLE_CP1"));
+
+        catalog.createTableInternal(new TablePath("XE", "TEST", "TEST003"), table);
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalogTest.java b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalogTest.java
new file mode 100644
index 00000000000..badab864fc3
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/psql/PostgresCatalogTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.psql;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.mysql.MySqlCatalog;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+@Disabled("Please Test it in your local environment")
+class PostgresCatalogTest {
+
+    @Test
+    void testCatalog() {
+        JdbcUrlUtil.UrlInfo urlInfo =
+                JdbcUrlUtil.getUrlInfo("jdbc:postgresql://127.0.0.1:5432/liulitest");
+        PostgresCatalog catalog =
+                new PostgresCatalog("postgres", "postgres", "postgres", urlInfo, null);
+
+        catalog.open();
+
+        MySqlCatalog mySqlCatalog =
+                new MySqlCatalog(
+                        "mysql",
+                        "root",
+                        "root@123",
+                        JdbcUrlUtil.getUrlInfo("jdbc:mysql://127.0.0.1:33062/mingdongtest"));
+
+        mySqlCatalog.open();
+
+        CatalogTable table1 =
+                mySqlCatalog.getTable(TablePath.of("mingdongtest", "all_types_table_02"));
+
+        CatalogTable table =
+                catalog.getTable(TablePath.of("st_test", "public", "all_types_table_02"));
+        System.out.println("find table: " + table);
+
+        catalog.createTableInternal(
+                new TablePath("liulitest", "public", "all_types_table_02"), table);
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sql/MysqlCreateTableSqlBuilderTest.java b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sql/MysqlCreateTableSqlBuilderTest.java
index 3f84de199eb..3de5c65bf8d 100644
--- a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sql/MysqlCreateTableSqlBuilderTest.java
+++ b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sql/MysqlCreateTableSqlBuilderTest.java
@@ -89,16 +89,17 @@ public void testBuild() {
                         new ArrayList<>(),
                         "User table");
 
-        String createTableSql = MysqlCreateTableSqlBuilder.builder(tablePath, catalogTable).build();
+        String createTableSql =
+                MysqlCreateTableSqlBuilder.builder(tablePath, catalogTable).build("mysql");
+        // create table sql is change; The old unit tests are no longer applicable
         String expect =
                 "CREATE TABLE IF NOT EXISTS test_table (\n"
-                        + "\tid BIGINT (22) NOT NULL COMMENT 'id', \n"
-                        + "\tname VARCHAR (128) NOT NULL COMMENT 'name', \n"
-                        + "\tage INT NULL COMMENT 'age', \n"
-                        + "\tcreateTime TIMESTAMP (3) NULL COMMENT 'createTime', \n"
-                        + "\tlastUpdateTime TIMESTAMP (3) NULL COMMENT 'lastUpdateTime', \n"
-                        + "\tPRIMARY KEY (`id`), \n"
-                        + "\tKEY `name` (`name`)\n"
+                        + "\tid null NOT NULL COMMENT 'id', \n"
+                        + "\tname null NOT NULL COMMENT 'name', \n"
+                        + "\tage null NULL COMMENT 'age', \n"
+                        + "\tcreateTime null NULL COMMENT 'createTime', \n"
+                        + "\tlastUpdateTime null NULL COMMENT 'lastUpdateTime', \n"
+                        + "\tPRIMARY KEY (`id`)\n"
                         + ") COMMENT = 'User table';";
         CONSOLE.println(expect);
         Assertions.assertEquals(expect, createTableSql);
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogTest.java b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogTest.java
new file mode 100644
index 00000000000..5e457910f03
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerCatalogTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.mysql.MySqlCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresCatalog;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.util.List;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@Disabled("Please Test it in your local environment")
+class SqlServerCatalogTest {
+
+    static JdbcUrlUtil.UrlInfo sqlParse =
+            SqlServerURLParser.parse("jdbc:sqlserver://127.0.0.1:1434;database=TestDB");
+    static JdbcUrlUtil.UrlInfo MysqlUrlInfo =
+            JdbcUrlUtil.getUrlInfo("jdbc:mysql://127.0.0.1:33061/liuliTest?useSSL=false");
+    static JdbcUrlUtil.UrlInfo pg =
+            JdbcUrlUtil.getUrlInfo("jdbc:postgresql://127.0.0.1:5432/liulitest");
+    static TablePath tablePathSQL;
+    static TablePath tablePathMySql;
+    static TablePath tablePathPG;
+    static TablePath tablePathOracle;
+    private static String databaseName = "TestDB";
+    private static String schemaName = "dbo";
+    private static String tableName = "AllDataTest";
+
+    static SqlServerCatalog sqlServerCatalog;
+    static MySqlCatalog mySqlCatalog;
+    static PostgresCatalog postgresCatalog;
+
+    static CatalogTable postgresCatalogTable;
+    static CatalogTable mySqlCatalogTable;
+    static CatalogTable sqlServerCatalogTable;
+
+    @BeforeAll
+    static void before() {
+        tablePathSQL = TablePath.of(databaseName, schemaName, "sqlserver_to_sqlserver");
+        tablePathMySql = TablePath.of(databaseName, schemaName, "mysql_to_sqlserver");
+        tablePathPG = TablePath.of(databaseName, schemaName, "pg_to_sqlserver");
+        tablePathOracle = TablePath.of(databaseName, schemaName, "oracle_to_sqlserver");
+        sqlServerCatalog = new SqlServerCatalog("sqlserver", "sa", "root@123", sqlParse, null);
+        mySqlCatalog = new MySqlCatalog("mysql", "root", "root@123", MysqlUrlInfo);
+        postgresCatalog = new PostgresCatalog("postgres", "postgres", "postgres", pg, null);
+        mySqlCatalog.open();
+        sqlServerCatalog.open();
+        postgresCatalog.open();
+    }
+
+    @Test
+    void listDatabases() {
+        List<String> list = sqlServerCatalog.listDatabases();
+    }
+
+    @Test
+    void listTables() {
+        List<String> list = sqlServerCatalog.listTables(databaseName);
+    }
+
+    @Test
+    void tableExists() {
+
+        //        boolean b = sqlServerCatalog.tableExists(tablePath);
+    }
+
+    @Test
+    @Order(1)
+    void getTable() {
+        postgresCatalogTable =
+                postgresCatalog.getTable(
+                        TablePath.of("liulitest", "public", "pg_types_table_no_array"));
+        mySqlCatalogTable = mySqlCatalog.getTable(TablePath.of("liuliTest", "AllTypeCol"));
+        sqlServerCatalogTable =
+                sqlServerCatalog.getTable(TablePath.of("TestDB", "dbo", "AllDataTest"));
+    }
+
+    @Test
+    @Order(2)
+    void createTableInternal() {
+        sqlServerCatalog.createTable(tablePathMySql, mySqlCatalogTable, true);
+        sqlServerCatalog.createTable(tablePathPG, postgresCatalogTable, true);
+        sqlServerCatalog.createTable(tablePathSQL, sqlServerCatalogTable, true);
+    }
+
+    @Disabled
+    // Manually dropping tables
+    @Test
+    void dropTableInternal() {
+        sqlServerCatalog.dropTable(tablePathSQL, true);
+        sqlServerCatalog.dropTable(tablePathMySql, true);
+        sqlServerCatalog.dropTable(tablePathPG, true);
+    }
+
+    @Test
+    void createDatabaseInternal() {}
+
+    @Test
+    void dropDatabaseInternal() {}
+
+    @AfterAll
+    static void after() {
+        sqlServerCatalog.close();
+        mySqlCatalog.close();
+        postgresCatalog.close();
+    }
+}
diff --git a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParserTest.java b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParserTest.java
new file mode 100644
index 00000000000..a48b61ab0e5
--- /dev/null
+++ b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/sqlserver/SqlServerURLParserTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver;
+
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class SqlServerURLParserTest {
+    @Test
+    public void testParse() {
+        String url =
+                "jdbc:sqlserver://localhost:1433;databaseName=myDB;encrypt=true;trustServerCertificate=false;loginTimeout=30;";
+        JdbcUrlUtil.UrlInfo urlInfo = SqlServerURLParser.parse(url);
+        assertEquals("localhost", urlInfo.getHost());
+        assertEquals(1433, urlInfo.getPort());
+        assertEquals(url, urlInfo.getOrigin());
+        assertEquals(
+                "encrypt=true;trustServerCertificate=false;loginTimeout=30", urlInfo.getSuffix());
+        assertEquals("myDB", urlInfo.getDefaultDatabase().get());
+        assertEquals(
+                "jdbc:sqlserver://localhost:1433;encrypt=true;trustServerCertificate=false;loginTimeout=30",
+                urlInfo.getUrlWithoutDatabase());
+    }
+}
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mongodb-e2e/src/test/resources/mongodbcdc_to_mysql.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mongodb-e2e/src/test/resources/mongodbcdc_to_mysql.conf
index 7e4a492390b..48bc0cd0203 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mongodb-e2e/src/test/resources/mongodbcdc_to_mysql.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mongodb-e2e/src/test/resources/mongodbcdc_to_mysql.conf
@@ -22,7 +22,7 @@ env {
   # You can set engine configuration here
   execution.parallelism = 1
   job.mode = "STREAMING"
-  execution.checkpoint.interval = 5000
+  checkpoint.interval = 5000
 }
 
 source {
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mysql-e2e/src/test/resources/mysqlcdc_to_mysql.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mysql-e2e/src/test/resources/mysqlcdc_to_mysql.conf
index e8d85aecc5c..0adf2f7e64d 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mysql-e2e/src/test/resources/mysqlcdc_to_mysql.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-mysql-e2e/src/test/resources/mysqlcdc_to_mysql.conf
@@ -22,7 +22,7 @@ env {
   # You can set engine configuration here
   execution.parallelism = 1
   job.mode = "STREAMING"
-  execution.checkpoint.interval = 5000
+  checkpoint.interval = 5000
 }
 
 source {
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-sqlserver-e2e/src/test/resources/sqlservercdc_to_console.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-sqlserver-e2e/src/test/resources/sqlservercdc_to_console.conf
index c4ac06877b1..9d3f041ede1 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-sqlserver-e2e/src/test/resources/sqlservercdc_to_console.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-sqlserver-e2e/src/test/resources/sqlservercdc_to_console.conf
@@ -51,8 +51,8 @@ sink {
     user = "sa"
     password = "Password!"
     generate_sink_sql = true
-    database = ""
-    table = "column_type_test.dbo.full_types_sink"
+    database = "column_type_test"
+    table = "dbo.full_types_sink"
     batch_size = 1
     primary_keys = ["id"]
   }
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/pom.xml b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/pom.xml
index 81ecdc29882..8628e2b80b6 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/pom.xml
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/pom.xml
@@ -52,8 +52,30 @@
             <version>${testcontainer.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>oracle-xe</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>mysql</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
 
         <!-- drivers -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc8</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.postgresql</groupId>
             <artifactId>postgresql</artifactId>
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSinkCDCChangelogIT.java b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSinkCDCChangelogIT.java
index 2a29c1cb5fe..dd812efb12b 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSinkCDCChangelogIT.java
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSinkCDCChangelogIT.java
@@ -126,6 +126,16 @@ public void testSinkCDCChangelog(TestContainer container)
                 Stream.<List<Object>>of(Arrays.asList(1L, "A_1", 100), Arrays.asList(3L, "C", 100))
                         .collect(Collectors.toSet());
         Assertions.assertIterableEquals(expected, actual);
+        try (Connection connection =
+                DriverManager.getConnection(
+                        postgreSQLContainer.getJdbcUrl(),
+                        postgreSQLContainer.getUsername(),
+                        postgreSQLContainer.getPassword())) {
+            try (Statement statement = connection.createStatement()) {
+                statement.execute("truncate table sink");
+                log.info("testSinkCDCChangelog truncate table sink");
+            }
+        }
     }
 
     private void initializeJdbcTable() {
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_postgres_source_and_sink.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_postgres_source_and_sink.conf
index 1c7417f8a55..f3293f44e61 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_postgres_source_and_sink.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_postgres_source_and_sink.conf
@@ -41,7 +41,7 @@ sink {
     password = test
     generate_sink_sql = true
     database = test
-    table = "public.pg_e2e_sink_table"
+    table = public.pg_e2e_sink_table
     primary_keys = ["gid"]
   }
 }
\ No newline at end of file
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_sink_cdc_changelog.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_sink_cdc_changelog.conf
index 5a48476171e..e0742a04f4c 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_sink_cdc_changelog.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-3/src/test/resources/jdbc_sink_cdc_changelog.conf
@@ -66,7 +66,7 @@ sink {
         password = test
         generate_sink_sql = true
         database = test
-        table = "public.sink"
+        table = public.sink
         primary_keys = ["pk_id"]
     }
 }
\ No newline at end of file
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/pom.xml b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/pom.xml
new file mode 100644
index 00000000000..99bbff4fa23
--- /dev/null
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.seatunnel</groupId>
+        <artifactId>connector-jdbc-e2e</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>connector-jdbc-e2e-part-4</artifactId>
+    <name>SeaTunnel : E2E : Connector V2 : Jdbc : Part 4</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.seatunnel</groupId>
+            <artifactId>connector-jdbc-e2e-common</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- jdbc containers -->
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.snowflake</groupId>
+            <artifactId>snowflake-jdbc</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>mssqlserver</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>oracle-xe</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>mysql</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- drivers -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc8</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.microsoft.sqlserver</groupId>
+            <artifactId>mssql-jdbc</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.vertica.jdbc</groupId>
+            <artifactId>vertica-jdbc</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcMySqlCreateTableIT.java b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcMySqlCreateTableIT.java
new file mode 100644
index 00000000000..cdc6fe1992a
--- /dev/null
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcMySqlCreateTableIT.java
@@ -0,0 +1,471 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.common.exception.SeaTunnelRuntimeException;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.mysql.MySqlCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleURLParser;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver.SqlServerCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver.SqlServerURLParser;
+import org.apache.seatunnel.e2e.common.TestResource;
+import org.apache.seatunnel.e2e.common.TestSuiteBase;
+import org.apache.seatunnel.e2e.common.container.ContainerExtendedFactory;
+import org.apache.seatunnel.e2e.common.container.EngineType;
+import org.apache.seatunnel.e2e.common.container.TestContainer;
+import org.apache.seatunnel.e2e.common.junit.DisabledOnContainer;
+import org.apache.seatunnel.e2e.common.junit.TestContainerExtension;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestTemplate;
+import org.testcontainers.containers.Container;
+import org.testcontainers.containers.MSSQLServerContainer;
+import org.testcontainers.containers.MySQLContainer;
+import org.testcontainers.containers.OracleContainer;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.lifecycle.Startables;
+import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.DockerLoggerFactory;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.stream.Stream;
+
+@Slf4j
+@DisabledOnContainer(
+        value = {},
+        type = {EngineType.SPARK, EngineType.FLINK},
+        disabledReason = "Currently SPARK and FLINK do not support cdc")
+public class JdbcMySqlCreateTableIT extends TestSuiteBase implements TestResource {
+    private static final String SQLSERVER_IMAGE = "mcr.microsoft.com/mssql/server:2022-latest";
+    private static final String SQLSERVER_CONTAINER_HOST = "sqlserver";
+    private static final int SQLSERVER_CONTAINER_PORT = 14333;
+    private static final String DRIVER_CLASS = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
+
+    private static final String PG_IMAGE = "postgis/postgis";
+    private static final String PG_DRIVER_JAR =
+            "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.3.3/postgresql-42.3.3.jar";
+    private static final String PG_JDBC_JAR =
+            "https://repo1.maven.org/maven2/net/postgis/postgis-jdbc/2.5.1/postgis-jdbc-2.5.1.jar";
+    private static final String PG_GEOMETRY_JAR =
+            "https://repo1.maven.org/maven2/net/postgis/postgis-geometry/2.5.1/postgis-geometry-2.5.1.jar";
+
+    private static final String MYSQL_IMAGE = "mysql:latest";
+    private static final String MYSQL_CONTAINER_HOST = "mysql-e2e";
+    private static final String MYSQL_DATABASE = "auto";
+
+    private static final String MYSQL_USERNAME = "root";
+    private static final String PASSWORD = "Abc!@#135_seatunnel";
+    private static final int MYSQL_PORT = 33061;
+    //    private static final String MYSQL_URL = "jdbc:mysql://" + HOST + ":%s/%s?useSSL=false";
+
+    private static final String MYSQL_DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
+
+    private static final String ORACLE_IMAGE = "gvenzl/oracle-xe:21-slim-faststart";
+    private static final String ORACLE_NETWORK_ALIASES = "e2e_oracleDb";
+    private static final String ORACLE_DRIVER_CLASS = "oracle.jdbc.OracleDriver";
+    private static final int ORACLE_PORT = 15211;
+    //    private static final String ORACLE_URL = "jdbc:oracle:thin:@" + HOST + ":%s/%s";
+    private static final String USERNAME = "testUser";
+    private static final String DATABASE = "TESTUSER";
+
+    private PostgreSQLContainer<?> POSTGRESQL_CONTAINER;
+
+    private MSSQLServerContainer<?> sqlserver_container;
+    private MySQLContainer<?> mysql_container;
+    private OracleContainer oracle_container;
+
+    private static final String mysqlCheck =
+            "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema = 'auto' AND table_name = 'mysql_auto_create_mysql') AS table_exists";
+    private static final String sqlserverCheck =
+            "IF EXISTS (\n"
+                    + "    SELECT 1\n"
+                    + "    FROM testauto.sys.tables t\n"
+                    + "    JOIN testauto.sys.schemas s ON t.schema_id = s.schema_id\n"
+                    + "    WHERE t.name = 'mysql_auto_create_sql' AND s.name = 'dbo'\n"
+                    + ")\n"
+                    + "    SELECT 1 AS table_exists;\n"
+                    + "ELSE\n"
+                    + "    SELECT 0 AS table_exists;";
+    private static final String pgCheck =
+            "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'mysql_auto_create_pg') AS table_exists;\n";
+    private static final String oracleCheck =
+            "SELECT CASE WHEN EXISTS(SELECT 1 FROM user_tables WHERE table_name = 'mysql_auto_create_oracle') THEN 1 ELSE 0 END AS table_exists FROM DUAL;\n";
+
+    String driverSqlServerUrl() {
+        return "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/9.4.1.jre8/mssql-jdbc-9.4.1.jre8.jar";
+    }
+
+    private static final String CREATE_SQL_DATABASE =
+            "IF NOT EXISTS (\n"
+                    + "   SELECT name \n"
+                    + "   FROM sys.databases \n"
+                    + "   WHERE name = N'testauto'\n"
+                    + ")\n"
+                    + "CREATE DATABASE testauto;\n";
+
+    private static final String CREATE_TABLE_SQL =
+            "CREATE TABLE IF NOT EXISTS mysql_auto_create\n"
+                    + "(\n  "
+                    + "`id` int(11) NOT NULL AUTO_INCREMENT,\n"
+                    + "  `f_binary` binary(64) DEFAULT NULL,\n"
+                    + "  `f_smallint` smallint(6) DEFAULT NULL,\n"
+                    + "  `f_smallint_unsigned` smallint(5) unsigned DEFAULT NULL,\n"
+                    + "  `f_mediumint` mediumint(9) DEFAULT NULL,\n"
+                    + "  `f_mediumint_unsigned` mediumint(8) unsigned DEFAULT NULL,\n"
+                    + "  `f_int` int(11) DEFAULT NULL,\n"
+                    + "  `f_int_unsigned` int(10) unsigned DEFAULT NULL,\n"
+                    + "  `f_integer` int(11) DEFAULT NULL,\n"
+                    + "  `f_integer_unsigned` int(10) unsigned DEFAULT NULL,\n"
+                    + "  `f_bigint` bigint(20) DEFAULT NULL,\n"
+                    + "  `f_bigint_unsigned` bigint(20) unsigned DEFAULT NULL,\n"
+                    + "  `f_numeric` decimal(10,0) DEFAULT NULL,\n"
+                    + "  `f_decimal` decimal(10,0) DEFAULT NULL,\n"
+                    + "  `f_float` float DEFAULT NULL,\n"
+                    + "  `f_double` double DEFAULT NULL,\n"
+                    + "  `f_double_precision` double DEFAULT NULL,\n"
+                    + "  `f_tinytext` tinytext COLLATE utf8mb4_unicode_ci,\n"
+                    + "  `f_varchar` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,\n"
+                    + "  `f_datetime` datetime DEFAULT NULL,\n"
+                    + "  `f_timestamp` timestamp NULL DEFAULT NULL,\n"
+                    + "  `f_bit1` bit(1) DEFAULT NULL,\n"
+                    + "  `f_bit64` bit(64) DEFAULT NULL,\n"
+                    + "  `f_char` char(1) COLLATE utf8mb4_unicode_ci DEFAULT NULL,\n"
+                    + "  `f_enum` enum('enum1','enum2','enum3') COLLATE utf8mb4_unicode_ci DEFAULT NULL,\n"
+                    + "  `f_real` double DEFAULT NULL,\n"
+                    + "  `f_tinyint` tinyint(4) DEFAULT NULL,\n"
+                    + "  `f_bigint8` bigint(8) DEFAULT NULL,\n"
+                    + "  `f_bigint1` bigint(1) DEFAULT NULL,\n"
+                    + "  `f_data` date DEFAULT NULL,\n"
+                    + "  PRIMARY KEY (`id`)\n"
+                    + ");";
+
+    private String getInsertSql =
+            "INSERT INTO mysql_auto_create"
+                    + "(id, f_binary, f_smallint, f_smallint_unsigned, f_mediumint, f_mediumint_unsigned, f_int, f_int_unsigned, f_integer, f_integer_unsigned, f_bigint, f_bigint_unsigned, f_numeric, f_decimal, f_float, f_double, f_double_precision, f_tinytext, f_varchar, f_datetime, f_timestamp, f_bit1, f_bit64, f_char, f_enum, f_real, f_tinyint, f_bigint8, f_bigint1, f_data)\n"
+                    + "VALUES(575, 0x654458436C70336B7357000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 194, 549, 633, 835, 719, 253, 742, 265, 806, 736, 474, 254, 120.8, 476.42, 264.95, 'In other words, Navicat provides the ability for data in different databases and/or schemas to be kept up-to-date so that each repository contains the same information.', 'jF9X70ZqH4', '2011-10-20 23:10:08', '2017-09-10 19:33:51', 1, b'0001001101100000001010010100010111000010010110110101110011111100', 'u', 'enum2', 876.55, 25, 503, 1, '2011-03-06');\n";
+
+    @TestContainerExtension
+    private final ContainerExtendedFactory extendedSqlServerFactory =
+            container -> {
+                Container.ExecResult extraCommands =
+                        container.execInContainer(
+                                "bash",
+                                "-c",
+                                "mkdir -p /tmp/seatunnel/plugins/Jdbc/lib && cd /tmp/seatunnel/plugins/Jdbc/lib && curl -O "
+                                        + PG_DRIVER_JAR
+                                        + " && curl -O "
+                                        + PG_JDBC_JAR
+                                        + " && curl -O "
+                                        + PG_GEOMETRY_JAR
+                                        + " && curl -O "
+                                        + MYSQL_DRIVER_CLASS
+                                        + " && curl -O "
+                                        + ORACLE_DRIVER_CLASS
+                                        + " && curl -O "
+                                        + driverSqlserverUrl()
+                                        + " && curl -O "
+                                        + driverMySqlUrl()
+                                        + " && curl -O "
+                                        + driverOracleUrl());
+                //                Assertions.assertEquals(0, extraCommands.getExitCode());
+            };
+
+    String driverMySqlUrl() {
+        return "https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.32/mysql-connector-j-8.0.32.jar";
+    }
+
+    String driverOracleUrl() {
+        return "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc8/12.2.0.1/ojdbc8-12.2.0.1.jar";
+    }
+
+    String driverSqlserverUrl() {
+        return "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/9.4.1.jre8/mssql-jdbc-9.4.1.jre8.jar";
+    }
+
+    void initContainer() throws ClassNotFoundException {
+        DockerImageName imageName = DockerImageName.parse(SQLSERVER_IMAGE);
+        sqlserver_container =
+                new MSSQLServerContainer<>(imageName)
+                        .withNetwork(TestSuiteBase.NETWORK)
+                        .withNetworkAliases(SQLSERVER_CONTAINER_HOST)
+                        .withPassword(PASSWORD)
+                        .acceptLicense()
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(
+                                        DockerLoggerFactory.getLogger(SQLSERVER_IMAGE)));
+
+        sqlserver_container.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", SQLSERVER_CONTAINER_PORT, 1433)));
+
+        try {
+            Class.forName(sqlserver_container.getDriverClassName());
+        } catch (ClassNotFoundException e) {
+            throw new SeaTunnelRuntimeException(
+                    JdbcITErrorCode.DRIVER_NOT_FOUND, "Not found suitable driver for mssql", e);
+        }
+
+        // ============= PG
+        POSTGRESQL_CONTAINER =
+                new PostgreSQLContainer<>(
+                                DockerImageName.parse(PG_IMAGE)
+                                        .asCompatibleSubstituteFor("postgres"))
+                        .withNetwork(TestSuiteBase.NETWORK)
+                        .withNetworkAliases("postgresql")
+                        .withDatabaseName("pg")
+                        .withUsername(USERNAME)
+                        .withPassword(PASSWORD)
+                        .withCommand("postgres -c max_prepared_transactions=100")
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(DockerLoggerFactory.getLogger(PG_IMAGE)));
+        POSTGRESQL_CONTAINER.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", 54323, 5432)));
+        //        Startables.deepStart(Stream.of(POSTGRESQL_CONTAINER)).join();
+        log.info("PostgreSQL container started");
+        Class.forName(POSTGRESQL_CONTAINER.getDriverClassName());
+
+        log.info("pg data initialization succeeded. Procedure");
+        DockerImageName mysqlImageName = DockerImageName.parse(MYSQL_IMAGE);
+        mysql_container =
+                new MySQLContainer<>(mysqlImageName)
+                        .withUsername(MYSQL_USERNAME)
+                        .withPassword(PASSWORD)
+                        .withDatabaseName(MYSQL_DATABASE)
+                        .withNetwork(NETWORK)
+                        .withNetworkAliases(MYSQL_CONTAINER_HOST)
+                        .withExposedPorts(MYSQL_PORT)
+                        .waitingFor(Wait.forHealthcheck())
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(DockerLoggerFactory.getLogger(MYSQL_IMAGE)));
+
+        mysql_container.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", MYSQL_PORT, 3306)));
+        DockerImageName oracleImageName = DockerImageName.parse(ORACLE_IMAGE);
+        oracle_container =
+                new OracleContainer(oracleImageName)
+                        .withDatabaseName(DATABASE)
+                        .withUsername(USERNAME)
+                        .withPassword(PASSWORD)
+                        .withNetwork(NETWORK)
+                        .withNetworkAliases(ORACLE_NETWORK_ALIASES)
+                        .withExposedPorts(ORACLE_PORT)
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(DockerLoggerFactory.getLogger(ORACLE_IMAGE)));
+        oracle_container.withCommand(
+                "bash",
+                "-c",
+                "echo \"CREATE USER admin IDENTIFIED BY admin; GRANT DBA TO admin;\" | sqlplus / as sysdba");
+        oracle_container.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", ORACLE_PORT, 1521)));
+        Startables.deepStart(
+                        Stream.of(
+                                POSTGRESQL_CONTAINER,
+                                sqlserver_container,
+                                mysql_container,
+                                oracle_container))
+                .join();
+    }
+
+    @Override
+    @BeforeAll
+    public void startUp() throws Exception {
+        initContainer();
+        initializeSqlJdbcTable();
+        initializeJdbcTable();
+    }
+
+    static JdbcUrlUtil.UrlInfo sqlParse =
+            SqlServerURLParser.parse("jdbc:sqlserver://localhost:14333;database=testauto");
+    static JdbcUrlUtil.UrlInfo MysqlUrlInfo =
+            JdbcUrlUtil.getUrlInfo("jdbc:mysql://localhost:33061/auto?useSSL=false");
+    static JdbcUrlUtil.UrlInfo pg = JdbcUrlUtil.getUrlInfo("jdbc:postgresql://localhost:54323/pg");
+    static JdbcUrlUtil.UrlInfo oracle =
+            OracleURLParser.parse("jdbc:oracle:thin:@localhost:15211/TESTUSER");
+
+    @TestTemplate
+    public void testAutoCreateTable(TestContainer container)
+            throws IOException, InterruptedException {
+        TablePath tablePathMySql = TablePath.of("auto", "mysql_auto_create");
+        TablePath tablePathMySql_Mysql = TablePath.of("auto", "mysql_auto_create_mysql");
+        TablePath tablePathSQL = TablePath.of("testauto", "dbo", "mysql_auto_create_sql");
+        TablePath tablePathPG = TablePath.of("pg", "public", "mysql_auto_create_pg");
+        TablePath tablePathOracle = TablePath.of("TESTUSER", "mysql_auto_create_oracle");
+
+        SqlServerCatalog sqlServerCatalog =
+                new SqlServerCatalog("sqlserver", "sa", PASSWORD, sqlParse, "dbo");
+        MySqlCatalog mySqlCatalog = new MySqlCatalog("mysql", "root", PASSWORD, MysqlUrlInfo);
+        PostgresCatalog postgresCatalog =
+                new PostgresCatalog("postgres", "testUser", PASSWORD, pg, "public");
+        OracleCatalog oracleCatalog =
+                new OracleCatalog("oracle", "admin", "admin", oracle, "TESTUSER");
+        mySqlCatalog.open();
+        sqlServerCatalog.open();
+        postgresCatalog.open();
+        //        oracleCatalog.open();
+
+        CatalogTable mysqlTable = mySqlCatalog.getTable(tablePathMySql);
+
+        sqlServerCatalog.createTable(tablePathSQL, mysqlTable, true);
+        postgresCatalog.createTable(tablePathPG, mysqlTable, true);
+        //        oracleCatalog.createTable(tablePathOracle, mysqlTable, true);
+        mySqlCatalog.createTable(tablePathMySql_Mysql, mysqlTable, true);
+
+        Assertions.assertTrue(checkMysql(mysqlCheck));
+        //        Assertions.assertTrue(checkOracle(oracleCheck));
+        Assertions.assertTrue(checkSqlServer(sqlserverCheck));
+        Assertions.assertTrue(checkPG(pgCheck));
+
+        // delete table
+        log.info("delete table");
+        mySqlCatalog.dropTable(tablePathMySql_Mysql, true);
+        sqlServerCatalog.dropTable(tablePathSQL, true);
+        postgresCatalog.dropTable(tablePathPG, true);
+        //        oracleCatalog.dropTable(tablePathOracle, true);
+        mySqlCatalog.dropTable(tablePathMySql, true);
+
+        sqlServerCatalog.close();
+        mySqlCatalog.close();
+        postgresCatalog.close();
+        // delete table
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+
+        sqlserver_container.close();
+        mysql_container.close();
+        oracle_container.close();
+        POSTGRESQL_CONTAINER.close();
+    }
+
+    private Connection getJdbcSqlServerConnection() throws SQLException {
+        return DriverManager.getConnection(
+                sqlserver_container.getJdbcUrl(),
+                sqlserver_container.getUsername(),
+                sqlserver_container.getPassword());
+    }
+
+    private Connection getJdbcMySqlConnection() throws SQLException {
+        return DriverManager.getConnection(
+                mysql_container.getJdbcUrl(),
+                mysql_container.getUsername(),
+                mysql_container.getPassword());
+    }
+
+    private Connection getJdbcPgConnection() throws SQLException {
+        return DriverManager.getConnection(
+                POSTGRESQL_CONTAINER.getJdbcUrl(),
+                POSTGRESQL_CONTAINER.getUsername(),
+                POSTGRESQL_CONTAINER.getPassword());
+    }
+
+    private Connection getJdbcOracleConnection() throws SQLException {
+        return DriverManager.getConnection(
+                oracle_container.getJdbcUrl(),
+                oracle_container.getUsername(),
+                oracle_container.getPassword());
+    }
+
+    private void initializeSqlJdbcTable() {
+        try (Connection connection = getJdbcSqlServerConnection()) {
+            Statement statement = connection.createStatement();
+            statement.execute(CREATE_SQL_DATABASE);
+            //            statement.executeBatch();
+        } catch (SQLException e) {
+            throw new RuntimeException("Initializing PostgreSql table failed!", e);
+        }
+    }
+
+    private void initializeJdbcTable() {
+        try (Connection connection = getJdbcMySqlConnection()) {
+            Statement statement = connection.createStatement();
+            statement.execute(CREATE_TABLE_SQL);
+            statement.execute(getInsertSql);
+
+            //            statement.executeBatch();
+        } catch (SQLException e) {
+            throw new RuntimeException("Initializing PostgreSql table failed!", e);
+        }
+    }
+
+    private boolean checkMysql(String sql) {
+        try (Connection connection = getJdbcMySqlConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getBoolean(1);
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private boolean checkPG(String sql) {
+        try (Connection connection = getJdbcPgConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getBoolean(1);
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private boolean checkSqlServer(String sql) {
+        try (Connection connection = getJdbcSqlServerConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getInt(1) == 1;
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private boolean checkOracle(String sql) {
+        try (Connection connection = getJdbcOracleConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getInt(1) == 1;
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSqlServerCreateTableIT.java b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSqlServerCreateTableIT.java
new file mode 100644
index 00000000000..35a2338b260
--- /dev/null
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/connector-jdbc-e2e-part-4/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/JdbcSqlServerCreateTableIT.java
@@ -0,0 +1,482 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc;
+
+import org.apache.seatunnel.api.table.catalog.CatalogTable;
+import org.apache.seatunnel.api.table.catalog.TablePath;
+import org.apache.seatunnel.common.exception.SeaTunnelRuntimeException;
+import org.apache.seatunnel.common.utils.JdbcUrlUtil;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.mysql.MySqlCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.oracle.OracleURLParser;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.psql.PostgresCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver.SqlServerCatalog;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.catalog.sqlserver.SqlServerURLParser;
+import org.apache.seatunnel.e2e.common.TestResource;
+import org.apache.seatunnel.e2e.common.TestSuiteBase;
+import org.apache.seatunnel.e2e.common.container.ContainerExtendedFactory;
+import org.apache.seatunnel.e2e.common.container.EngineType;
+import org.apache.seatunnel.e2e.common.container.TestContainer;
+import org.apache.seatunnel.e2e.common.junit.DisabledOnContainer;
+import org.apache.seatunnel.e2e.common.junit.TestContainerExtension;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestTemplate;
+import org.testcontainers.containers.Container;
+import org.testcontainers.containers.MSSQLServerContainer;
+import org.testcontainers.containers.MySQLContainer;
+import org.testcontainers.containers.OracleContainer;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.lifecycle.Startables;
+import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.DockerLoggerFactory;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.stream.Stream;
+
+@Slf4j
+@DisabledOnContainer(
+        value = {},
+        type = {EngineType.SPARK, EngineType.FLINK},
+        disabledReason = "Currently SPARK and FLINK do not support cdc")
+public class JdbcSqlServerCreateTableIT extends TestSuiteBase implements TestResource {
+
+    private static final String SQLSERVER_IMAGE = "mcr.microsoft.com/mssql/server:2022-latest";
+    private static final String SQLSERVER_CONTAINER_HOST = "sqlserver-e2e";
+    private static final int SQLSERVER_CONTAINER_PORT = 1433;
+    private static final String SQLSERVER_URL =
+            "jdbc:sqlserver://" + AbstractJdbcIT.HOST + ":%s;encrypt=false;";
+    private static final String DRIVER_CLASS = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
+
+    private static final String CREATE_DATABASE =
+            "IF NOT EXISTS (\n"
+                    + "   SELECT name \n"
+                    + "   FROM sys.databases \n"
+                    + "   WHERE name = N'testauto'\n"
+                    + ")\n"
+                    + "CREATE DATABASE testauto;\n";
+
+    private static final String CREATE_TABLE_SQL =
+            "IF NOT EXISTS (SELECT * FROM testauto.sys.tables WHERE name = 'sqlserver_auto_create' AND schema_id = SCHEMA_ID('dbo'))\n"
+                    + "BEGIN\n"
+                    + "CREATE TABLE testauto.dbo.sqlserver_auto_create (\n"
+                    + "  c1 bigint  NOT NULL,\n"
+                    + "  c2 bit  NULL,\n"
+                    + "  c3 decimal(18)  NULL,\n"
+                    + "  c4 decimal(18,2)  NULL,\n"
+                    + "  c5 real  NULL,\n"
+                    + "  c6 float(53)  NULL,\n"
+                    + "  c7 int  NULL,\n"
+                    + "  c8 money  NULL,\n"
+                    + "  c9 numeric(18)  NULL,\n"
+                    + "  c10 numeric(18,2)  NULL,\n"
+                    + "  c11 real  NULL,\n"
+                    + "  c12 smallint  NULL,\n"
+                    + "  c13 smallmoney  NULL,\n"
+                    + "  c14 tinyint  NULL,\n"
+                    + "  c15 char(10)   NULL,\n"
+                    + "  c16 varchar(50)   NULL,\n"
+                    + "  c17 varchar(max)   NULL,\n"
+                    + "  c18 text   NULL,\n"
+                    + "  c19 nchar(10)   NULL,\n"
+                    + "  c20 nvarchar(50)   NULL,\n"
+                    + "  c21 nvarchar(max)   NULL,\n"
+                    + "  c22 ntext   NULL,\n"
+                    + "  c25 varbinary(max)  NULL,\n"
+                    + "  c26 image  NULL,\n"
+                    + "  c27 datetime  NULL,\n"
+                    + "  c28 datetime2(7)  NULL,\n"
+                    + "  c29 datetimeoffset(7)  NULL,\n"
+                    + "  c30 smalldatetime  NULL,\n"
+                    + "  c31 date  NULL,\n"
+                    + "  PRIMARY KEY CLUSTERED (c1)\n"
+                    + ")  \n"
+                    + "END";
+
+    private String username;
+
+    private String password;
+
+    private String getInsertSql =
+            "INSERT INTO testauto.dbo.sqlserver_auto_create\n"
+                    + "(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c25, c26, c27, c28, c29, c30, c31)\n"
+                    + "VALUES(8, 1, 714, 876.63, 368.74686, 61.59519333775628, 97, 7.1403, 497, 727.56, 303.78827, 654, 620.8399, 181, N'qEVAoi6KLU', N'1Y7QDYF6me', N'Navicat allows you to transfer data from one database and/or schema to another with detailed analytical process. Instead of wondering when your next vacation is, maybe you should set up a life you don’t need to escape from. I will greet this day with love in my heart. HTTP Tunneling is a method for connecting to a server that uses the same protocol (http://) and the same port (port 80) as a web server does. Export Wizard allows you to export data from tables, collections, views, or query results to any available formats. Always keep your eyes open. Keep watching. Because whatever you see can inspire you. After logged in the Navicat Cloud feature, the Navigation pane will be divided into Navicat Cloud and My Connections sections. Navicat Cloud could not connect and access your databases. By which it means, it could only store your connection settings, queries, model files, and virtual group; your database passwords and data (e.g. tables, views, etc) will not be stored to Navicat Cloud. Always keep your eyes open. Keep watching. Because whatever you see can inspire you. With its well-designed Graphical User Interface(GUI), Navicat lets you quickly and easily create, organize, access and share information in a secure and easy way. Anyone who has ever made anything of importance was disciplined. After logged in the Navicat Cloud feature, the Navigation pane will be divided into Navicat Cloud and My Connections sections. If you wait, all that happens is you get older. Navicat Data Modeler enables you to build high-quality conceptual, logical and physical data models for a wide variety of audiences. Navicat Monitor requires a repository to store alerts and metrics for historical analysis. There is no way to happiness. Happiness is the way. To connect to a database or schema, simply double-click it in the pane. Anyone who has never made a mistake has never tried anything new. If your Internet Service Provider (ISP) does not provide direct access to its server, Secure Tunneling Protocol (SSH) / HTTP is another solution. Navicat 15 has added support for the system-wide dark mode. You will succeed because most people are lazy. Success consists of going from failure to failure without loss of enthusiasm. SSH serves to prevent such vulnerabilities and allows you to access a remote server''s shell without compromising security. Navicat provides a wide range advanced features, such as compelling code editing capabilities, smart code-completion, SQL formatting, and more. Navicat provides powerful tools for working with queries: Query Editor for editing the query text directly, and Query Builder, Find Builder or Aggregate Builder for building queries visually. The Synchronize to Database function will give you a full picture of all database differences. If the plan doesn’t work, change the plan, but never the goal. You can select any connections, objects or projects, and then select the corresponding buttons on the Information Pane. The Main Window consists of several toolbars and panes for you to work on connections, database objects and advanced tools. Actually it is just in an idea when feel oneself can achieve and cannot achieve. The Main Window consists of several toolbars and panes for you to work on connections, database objects and advanced tools. After logged in the Navicat Cloud feature, the Navigation pane will be divided into Navicat Cloud and My Connections sections. Anyone who has never made a mistake has never tried anything new. Navicat Monitor is a safe, simple and agentless remote server monitoring tool that is packed with powerful features to make your monitoring effective as possible. The Main Window consists of several toolbars and panes for you to work on connections, database objects and advanced tools. Navicat provides a wide range advanced features, such as compelling code editing capabilities, smart code-completion, SQL formatting, and more. Champions keep playing until they get it right. If it scares you, it might be a good thing to try. It can also manage cloud databases such as Amazon Redshift, Amazon RDS, Alibaba Cloud. Features in Navicat are sophisticated enough to provide professional developers for all their specific needs, yet easy to learn for users who are new to database server. To connect to a database or schema, simply double-click it in the pane. A query is used to extract data from the database in a readable format according to the user''s request. To successfully establish a new connection to local/remote server - no matter via SSL or SSH, set the database login information in the General tab. SQL Editor allows you to create and edit SQL text, prepare and execute selected queries. Navicat is a multi-connections Database Administration tool allowing you to connect to MySQL, Oracle, PostgreSQL, SQLite, SQL Server, MariaDB and/or MongoDB databases, making database administration to multiple kinds of database so easy. Secure Sockets Layer(SSL) is a protocol for transmitting private documents via the Internet. I may not have gone where I intended to go, but I think I have ended up where I needed to be. Navicat Cloud provides a cloud service for synchronizing connections, queries, model files and virtual group information from Navicat, other Navicat family members, different machines and different platforms. To connect to a database or schema, simply double-click it in the pane. With its well-designed Graphical User Interface(GUI), Navicat lets you quickly and easily create, organize, access and share information in a secure and easy way. I may not have gone where I intended to go, but I think I have ended up where I needed to be. Anyone who has ever made anything of importance was disciplined. Actually it is just in an idea when feel oneself can achieve and cannot achieve. Instead of wondering when your next vacation is, maybe you should set up a life you don’t need to escape from. It wasn’t raining when Noah built the ark. You must be the change you wish to see in the world. SQL Editor allows you to create and edit SQL text, prepare and execute selected queries. Navicat provides a wide range advanced features, such as compelling code editing capabilities, smart code-completion, SQL formatting, and more. To start working with your server in Navicat, you should first establish a connection or several connections using the Connection window. SSH serves to prevent such vulnerabilities and allows you to access a remote server''s shell without compromising security. In the Objects tab, you can use the List List, Detail Detail and ER Diagram ER Diagram buttons to change the object view. Genius is an infinite capacity for taking pains. Typically, it is employed as an encrypted version of Telnet. Secure Sockets Layer(SSL) is a protocol for transmitting private documents via the Internet. You cannot save people, you can just love them. You cannot save people, you can just love them. Navicat provides a wide range advanced features, such as compelling code editing capabilities, smart code-completion, SQL formatting, and more. To connect to a database or schema, simply double-click it in the pane. Navicat provides a wide range advanced features, such as compelling code editing capabilities, smart code-completion, SQL formatting, and more. Navicat Monitor requires a repository to store alerts and metrics for historical analysis. How we spend our days is, of course, how we spend our lives. Instead of wondering when your next vacation is, maybe you should set up a life you don’t need to escape from. To start working with your server in Navicat, you should first establish a connection or several connections using the Connection window. Always keep your eyes open. Keep watching. Because whatever you see can inspire you. Navicat Data Modeler enables you to build high-quality conceptual, logical and physical data models for a wide variety of audiences. Navicat Cloud could not connect and access your databases. By which it means, it could only store your connection settings, queries, model files, and virtual group; your database passwords and data (e.g. tables, views, etc) will not be stored to Navicat Cloud. I may not have gone where I intended to go, but I think I have ended up where I needed to be. The reason why a great man is great is that he resolves to be a great man. Export Wizard allows you to export data from tables, collections, views, or query results to any available formats. Navicat 15 has added support for the system-wide dark mode. Actually it is just in an idea when feel oneself can achieve and cannot achieve. SSH serves to prevent such vulnerabilities and allows you to access a remote server''s shell without compromising security. Difficult circumstances serve as a textbook of life for people. Flexible settings enable you to set up a custom key for comparison and synchronization. It collects process metrics such as CPU load, RAM usage, and a variety of other resources over SSH/SNMP. It wasn’t raining when Noah built the ark. SQL Editor allows you to create and edit SQL text, prepare and execute selected queries. You can select any connections, objects or projects, and then select the corresponding buttons on the Information Pane.', N'Actually it is just in an idea when feel oneself can achieve and cannot achieve. A man is not old until regrets take the place of dreams. With its well-designed Graphical User Interface(GUI), Navicat lets you quickly and easily create, organize, access and share information in a secure and easy way.', N'j8OKNCrsFb', N'KTLmoNjIiI', N'All the Navicat Cloud objects are located under different projects. You can share the project to other Navicat Cloud accounts for collaboration. Navicat Data Modeler is a powerful and cost-effective database design tool which helps you build high-quality conceptual, logical and physical data models. After logged in the Navicat Cloud feature, the Navigation pane will be divided into Navicat Cloud and My Connections sections. Navicat Cloud provides a cloud service for synchronizing connections, queries, model files and virtual group information from Navicat, other Navicat family members, different machines and different platforms. Secure Sockets Layer(SSL) is a protocol for transmitting private documents via the Internet. To successfully establish a new connection to local/remote server - no matter via SSL, SSH or HTTP, set the database login information in the General tab. Champions keep playing until they get it right. It is used while your ISPs do not allow direct connections, but allows establishing HTTP connections. With its well-designed Graphical User Interface(GUI), Navicat lets you quickly and easily create, organize, access and share information in a secure and easy way. Navicat allows you to transfer data from one database and/or schema to another with detailed analytical process. You must be the change you wish to see in the world. Navicat provides a wide range advanced features, such as compelling code editing capabilities, smart code-completion, SQL formatting, and more. Anyone who has never made a mistake has never tried anything new. Navicat allows you to transfer data from one database and/or schema to another with detailed analytical process. I may not have gone where I intended to go, but I think I have ended up where I needed to be. Typically, it is employed as an encrypted version of Telnet. Secure SHell (SSH) is a program to log in into another computer over a network, execute commands on a remote server, and move files from one machine to another. Success consists of going from failure to failure without loss of enthusiasm. Sometimes you win, sometimes you learn. Navicat 15 has added support for the system-wide dark mode. It provides strong authentication and secure encrypted communications between two hosts, known as SSH Port Forwarding (Tunneling), over an insecure network.', N'To connect to a database or schema, simply double-click it in the pane. If you wait, all that happens is you get older. Always keep your eyes open. Keep watching. Because whatever you see can inspire you. Import Wizard allows you to import data to tables/collections from CSV, TXT, XML, DBF and more. Success consists of going from failure to failure without loss of enthusiasm. A query is used to extract data from the database in a readable format according to the user''s request. Anyone who has never made a mistake has never tried anything new. To successfully establish a new connection to local/remote server - no matter via SSL or SSH, set the database login information in the General tab. SQL Editor allows you to create and edit SQL text, prepare and execute selected queries. Navicat Monitor is a safe, simple and agentless remote server monitoring tool that is packed with powerful features to make your monitoring effective as possible. I will greet this day with love in my heart. How we spend our days is, of course, how we spend our lives. You can select any connections, objects or projects, and then select the corresponding buttons on the Information Pane. Remember that failure is an event, not a person. The Information Pane shows the detailed object information, project activities, the DDL of database objects, object dependencies, membership of users/roles and preview. Navicat authorizes you to make connection to remote servers running on different platforms (i.e. Windows, macOS, Linux and UNIX), and supports PAM and GSSAPI authentication. Secure Sockets Layer(SSL) is a protocol for transmitting private documents via the Internet. The Information Pane shows the detailed object information, project activities, the DDL of database objects, object dependencies, membership of users/roles and preview. You can select any connections, objects or projects, and then select the corresponding buttons on the Information Pane. The On Startup feature allows you to control what tabs appear when you launch Navicat. The first step is as good as half over. Always keep your eyes open. Keep watching. Because whatever you see can inspire you. Champions keep playing until they get it right. If the Show objects under schema in navigation pane option is checked at the Preferences window, all database objects are also displayed in the pane. To successfully establish a new connection to local/remote server - no matter via SSL, SSH or HTTP, set the database login information in the General tab. It provides strong authentication and secure encrypted communications between two hosts, known as SSH Port Forwarding (Tunneling), over an insecure network. Navicat is a multi-connections Database Administration tool allowing you to connect to MySQL, Oracle, PostgreSQL, SQLite, SQL Server, MariaDB and/or MongoDB databases, making database administration to multiple kinds of database so easy. It wasn’t raining when Noah built the ark. A comfort zone is a beautiful place, but nothing ever grows there. Navicat Cloud provides a cloud service for synchronizing connections, queries, model files and virtual group information from Navicat, other Navicat family members, different machines and different platforms. The past has no power over the present moment. Creativity is intelligence having fun. Navicat authorizes you to make connection to remote servers running on different platforms (i.e. Windows, macOS, Linux and UNIX), and supports PAM and GSSAPI authentication. HTTP Tunneling is a method for connecting to a server that uses the same protocol (http://) and the same port (port 80) as a web server does. Difficult circumstances serve as a textbook of life for people. A comfort zone is a beautiful place, but nothing ever grows there. I may not have gone where I intended to go, but I think I have ended up where I needed to be. It wasn’t raining when Noah built the ark. Navicat Cloud could not connect and access your databases. By which it means, it could only store your connection settings, queries, model files, and virtual group; your database passwords and data (e.g. tables, views, etc) will not be stored to Navicat Cloud. What you get by achieving your goals is not as important as what you become by achieving your goals. Difficult circumstances serve as a textbook of life for people. There is no way to happiness. Happiness is the way. Genius is an infinite capacity for taking pains. If the plan doesn’t work, change the plan, but never the goal. Genius is an infinite capacity for taking pains.', 0xFFD8FFE000104A46494600010100000100010000FFDB004300080606070605080707070909080A0C140D0C0B0B0C1912130F141D1A1F1E1D1A1C1C20242E2720222C231C1C2837292C30313434341F27393D38323C2E333432FFDB0043010909090C0B0C180D0D1832211C213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232FFC00011080140014003012200021101031101FFC4001C0001010003000301000000000000000000000705060801020304FFC400441000010302020605070A0309010000000000010203040506110712213141B23651617172153542748191B113142223326282A1C1D152C2F016172433535493A2D2E1FFC4001A010100030101010000000000000000000000030405020601FFC400311101000201020306040602030000000000000102030411051231213233517181133441D114156191B1C152A12442F0FFDA000C03010002110311003F00A8000CB42000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031376C4D66B1ECB857C5149FE922EB3FB3E8A66B976EE34FAED2ED0C6E54A1B64F3A6796B4AF48D3BD32D6FD09F1E97365EDA55DD715EDD214604827D2E5D9CEFA8B7D1313AA4D77FC150F9B34B57C45FA7456F54EC63D3F98B1F966A3CBFDA5FC36458C130A4D2FB55CD6D65A1513D27C3367EE6AA7EA6DB67C7161BD3DB14158914EECB286A1351CABD49C157B115487268F3E38DED5476C37AF586C4002B2300000035CC478D2DD862AA1A7AD86AA47CACD76AC2C6AA226796DCDC8754C76C96E5AC6F2FB5ACDA7686C60D0FF00BDAB0FFB4B97FC6CFF00D99FC398B2DB89D93AD124CC7C2A88E8E6444764BB953255D84B7D366A579AD5DA1D5B15EB1BCC33A0020700000000003E35752CA3A39EAA4472B218DD2391BBD511335CBDC693FDED587FDA5CBFE367FEC971E0C997B691BBAAD2D6EEC37C06A763D20DA6FF00758EDD4B4F5AC9A4472A3A56311BB133E0E5EA36C39C98AF8E796F1B496ACD676900070E40000000000000000000000FCD5F5F4D6CA09AB6AE548A085BACF72FF5BD57622088999DA0EAF171B951DAA89F575D3B21819BDCE5DFD889C57B1091626D255C2E6E7D35A95F45499AA7CA22E52BD3B57D1F67BCC1E29C515789AE4E9A473994AC5CA0833D8C4EB5EB72F153027A0D270FAE388B64ED9FE1A1874F15EDB7579739CF72B9CAAAE55CD55576AA9E0D830EE0EBAE247A3E9A248A95172754CBB189DDC5CBDDEDC8A45B345963A4622D73E7AE932DBACE58D9EC46AE7F9A96336B70E19DAD3DBE5092F9E94EC945C1D110612C3D4EC4632CB42A89FEA428F5F7BB353DA4C2D87E46EABACB6F44FBB4ED6FC10A9F9B63FF001945F8BAF939D416DB968C30FD6B55695B350C9B72589EAE6AAF6A3B3F722A133C4983AE786A4D6A8624D48E5C99531A7D155EA5EA5FEB696F06BB0E69DAB3B4FEA9699E97EC86430B6906E1637B29EB1CFACB7A6CD472E6F8D3EEAAFC176756459ADD71A4BAD0C7594533658244CD1C9C3B17A97B0E68366C198AE6C35736A48E73ADF33B29E3DF97DF4ED4FCD3675655F5BA0AE489BE38DADFCA3CD822D1CD5EABD83D63919344C9637A3E37B51CD735734545DCA87B1E7D9E122D2EF9E6DFEAEBCCA574916977CF36FF00575E652F70DF988F74FA6F1213B32787EF75187EF305C29F6EA2E52333D8F62EF6FF005C723180F496AC5A26B3D25A531131B4BA6682BA9EE541056D2BF5E09988F63BB3F73F411FD19E29F27D7791AAE4CA9AA5D9C2E72FD893ABB9DF1CBAD4B01E5755A79C1926B3D3E8CACB8E71DB600057460000C7DF7A3D72F5597914E6E3A46FBD1EB97AACBC8A7371B9C23B965ED27496DBA35E9C51F824E452E842F46BD38A3F049C8A5D0ABC57C78F4FBA2D577FD80019AAC00000000000000000000120D286237565C9B65A77AFCDE9575A6C9763E45E1F853F355EA2A379B8B2D166ACB83F25482257A22F15E09ED5C90E6F9A692A2792695EAF92472BDEE5DEAAAB9AA9ABC2F045AF3927E9FCAD6971EF3CD3F47A1BB603C17E5F9D6BEBDAE6DBA17648DDCB3BBA93B138AFB138E5A9DB6825BA5CE9A861FF00327912345EACD77FB379D1D6FA082D96F828A99BAB0C0C46353F55ED5DE5DE23AA9C34E5A7594FA8CB348DA3ACBED1451C10B2186364713111AD631A888D44DC8889B90F700F3ACE00000F8D552C15B4B25354C4D96191BAAF639334543EC044EDDB039FF18E1A7E19BD3A06E6EA49915F4EF5FE1E2D5ED4FD9789AF17AC7D644BCE16A8D4667514A8B3C59266AB926D4F6A67B3AF2221476CAFB8AAA51515454E4B92FC8C4AECBBF243D368B53F1716F69ED8EAD3C3979E9BCAAFA2DBF3ABAD32DAA77AACB47B62555DAB1AF0F62FE4A886FE4A702E11C4768C41057D452B29E9B55CC952495359CD54E0899EDCF25DB96E2AC626BA2919A671CEF13E4A59E2BCFBD4245A5DF3CDBFD5D7994AE922D2EF9E6DFEAEBCCA77C37E623DDF74DE242767DA6A59E9E385F2C6AD64ECF948D57739B9AA669ED453E25629F0CB71268B6DAD89A9F3EA763DF4EEEB5D7766DEE5F8E46F67CF187966DD26765FC99229B6E9422AA2A2A2AA2A6E542EB80F142621B324750FCEBE95119367BDE9C1FEDE3DBEC214F63A37B98F6AB5CD5C95AA992A2F5192C3F7BA8C3F7982E14FB751729199EC7B177B7FAE3911EB34D19F1ED1D63A39CD8FE257F574703F3D05753DCA820ADA57EBC13311EC7767EE7E83CBCC4C4ED2CBE80000C7DF7A3D72F5597914E6E3A46FBD1EB97AACBC8A7371B9C23B965ED27496DBA35E9C51F824E452E842F46BD38A3F049C8A5D0ABC57C78F4FBA2D577FD80019AAC00000000000000000000D0F4AD5CB4F8661A46B9116A67447275B5A99FC7548D14AD2FCDAD5B6A83F82391FEF544FE526A7A5E1D4E5D3C7EAD3D346D8E1BE68AADA95588E6AD7A66DA48736F63DDB13F2D62CA4EB4454C8CB35C2AB2DB254246BF85A8BFCE514C7E237E6D44FE9D8A7A8B6F924001490000000000A88A992ED43C22235A88888889B111381E4000000245A5DF3CDBFD5D7994AE922D2EF9E6DFEAEBCCA5EE1BF311EE9F4DE242765F700F41ED9E0773B88117DC03D07B6781DCEE3478B7831EBFD4AC6AFB91EAD2749D85BE6D51E5DA48FEA6672254B53D17F07772F1EDEF27074DD5D2C35D492D2D4C692432B558F6AF14539F3135826C397A96865CDD1FDA8645F4D8BB97BF82F6A0E1BAAE7AFC2B758FE1F74D979A3967AC365D1AE29F265C7C91572654954EFAA739764727ECED89DF9769643978B9E00C53FDA0B47C854C99DC29511B2AAEF91BC1FFA2F6F7A10713D2ED3F1ABEFF747AAC5FF00786DC0031D4D8FBEF47AE5EAB2F229CDC748DF7A3D72F5597914E6E37384772CBDA4E92DB746BD38A3F049C8A5D085E8D7A7147E093914BA1578AF8F1E9F745AAEFF00B00033558000000000000000000011DD2DBF3C4B46CCB751B573EF7BFF00634028BA5D8952F36F9783A9D5BEE77FF49D1EA7433FF1EAD4C1E1C2D7A2C6A3707AAA7A552F55F7221BB1A2E8A25D7C293B38C756F4F7B5ABFA9BD1E7F59E3DFD59F9BC4900056460000000000000000122D2EF9E6DFEAEBCCA574916977CF36FF575E652F70DF988F74FA6F1213B2FB807A0F6CF03B9DC408BEE01E83DB3C0EE771A3C5BC18F5FEA56357DC8F56C86B58DB0CB712595CD89A9F3EA7CDF4EEEB5E2DEE5F8E46CA0C3C792D8ED17AF5851ADA6B3BC397DEC746F731ED56B9AB92B5532545EA32162BCD4586EF05C29B6BA35C9CC55C91ED5DED5FEB7E4BC0DDB49D85BE6D51E5DA48FEA6672254B53D17F07772F1EDEF2707A9C5929A8C5CDF49EAD5A5A3257774BDBAE14D75B7C15D48FD78266EB357E28BDA8B9A2F71FA88DE8D714F932E3E48AB932A4AA77D539CBB2393F676C4EFCBB4B21E6F55A79C1926BF4FA3372E39C76D98FBEF47AE5EAB2F229CDC748DF7A3D72F5597914E6E35384772CB5A4E92DB746BD38A3F049C8A5D085E8D7A7147E093914BA1578AF8F1E9F745AAEFF00B000335580000000000000000000135D2F522BA82D9589BA395F12FE24454E452505F71EDBBCA583AB98D4CE485A93B3667F676AFE599023D170CBF360E5F2968E96DBD36F254B443588B1DD289576A2B256A7BD17E0D29E41B47D744B5E2FA557B91B154A2D3BD57EF6597FD91A5E4CCE278F973CCF9AB6A6BB64DFCC001415C000000003D5AF63F3D4735D92AB5725CF254E07A54D445474B2D4CEE46C51315EF72F0444CD4E709EE9572DD6A2E31CD2C13CD23A45746F5454D65CF2CD0B9A4D1CEA37EDDB64D8B0CE4DDD280845AF1E628A79A1822AE75566E463639D88FD655D889ADF6BF32EACD7F936FCA6AEBE49ADABBB3E391C6A74B7D3CC734C76BE65C538FABD8916977CF36FF575E652BA48B4BBE79B7FABAF3292F0DF988F775A6F1213B2FB807A0F6CF03B9DC408BEE01E83DB3C0EE771A3C5BC18F5FEA56357DC8F56C80030141F1ABA586BA925A5A98D248656AB1ED5E28A73E626B04D872F52D0CB9BA3FB50C8BE9B1772F7F05ED43A24D6B1B6196E24B2B9B1353E7D4F9BE9DDD6BC5BDCBF1C8BDA0D57C1C9B5BBB3FF00B74F832F25B69E9281973C018A7FB4168F90A9933B852A236555DF23783FF45EDEF421AF63A37B98F6AB5CD5C95AA992A2F5190B15E6A2C37782E14DB5D1AE4E62AE48F6AEF6AFF5BF25E06D6B34D19F1ED1D63A2EE6C7F12BB7D5D017DE8F5CBD565E4539B8E88ACB8535D7075657523F5E09A8A57357F0AE68BDA8B9A2F71CEE54E131315BC4F9A1D246D12DB746BD38A3F049C8A5D085E8D7A7147E093914BA1538AF8F1E9F745AAEFF00B0003355800000000000000000001E1CD6BDAAD72239AA992A2A668A873A624B43AC5882AE8151518C7E712AF162ED6AFBBF3453A30D174958656ED6B4B9D2C7AD5746DFA4889B5F16F54F66D5F797F876A23165E5B74958D364E5B6D3F5465AE731C8E6AAA391734545DA8A5FB06E248F11D8D92B9EDF9E4288CA9626F4770765D4B967EF4E0400C958EF95B87EE4CADA27A23D1355EC77D97B7A950D8D6E97F114DA3AC745CCD8BE257F5747835FC398C2D789226A412A4557966FA6917E92777F1276A7B723603CD5E96A5B96D1B4B32D59ACED2000E5F000D4716E3BA2C3F1494D4CE654DCB2C92245CDB1AF5BD7F4DFDDBCEF1E2BE5B72D2379755ACDA76862B4A3889B4B6E6D969E4FF115393A6CBD18D3877AAA7B917AC909F6ABABA8AFAB96AEAA574B3CAED67BDDBD54F9318E91ED631AAE7397246A266AABD47A8D3608C18E29FBB4F1638C75D9B6E8E2CEEB9E2A867735160A2FAF7AAFF17A09DF9EDF617335AC1187530ED8238E56E5593E52D42F145E0DF626CEFCCD94C0D767F8D9A663A47642867C9CF7ECE8122D2EF9E6DFEAEBCCA574916977CF36FF00575E653AE1BF311EEFBA6F1213B2FB807A0F6CF03B9DC408BEE01E83DB3C0EE771A3C5BC18F5FEA56357DC8F56C80030140000125D27616F9B547976923FA999C8952D4F45FC1DDCBC7B7BC9C1D37574B0D7524B4B531A490CAD563DABC514E7CC4D609B0E5EA5A1973747F6A1917D362EE5EFE0BDA86FF0DD573D7E15BAC7F0D0D365E68E59EB0CB612C51E4DB7DCAD156FFF0009554F2FC92AAEC8E4D45FC9DB13BF2ED35100D0AE3AD6D368FAAC456226663EADB746BD38A3F049C8A5D085E8D7A7147E093914BA185C57C78F4FBA86ABBFEC000CD560000000000000000000000004871EE047DBE496EF6A8D5D48E557CF0B536C2BC5C9F77E1DDBA787509A1E25D19D0DD1CFAAB53D94554BB56354FAA7AF727D9F66CEC36747C4A2239337EFF75CC3A9DA396E8DB5CE6391CD554722E68A8BB514DAAD7A45C456C8D235A9655C6D4C91B54DD754FC48A8E5F6A98DBAE15BDD955CB5B6F99B1B76FCB3135E3CBAF593627B72530C6ACD7167AF6ED685B98ADE3CD4C8B4C13237EBACB1BDDD6CA856A7E6D513E97E7731529ECD1C6FE0B2542BD3DC8D4266083F2FD36FBF2FFB947F87C7E4DA2EBA41C457563A3755A52C4EDECA56EA7FDB6BBF33570676CF83AF97BD57D2D0BDB03B2FAF9BE8332EB455DFECCC9E23160AFD2B0936AD23C9822B1A3FC0AFA47C77ABB44AD9D36D3D3BD36B3EFB93AFA9386FDFBB3385F47D6FB03995552A9595EDDA9239B93235FBA9D7DABB7B8DC0C7D6711E789C78BA79A9E6D473472D000192A8122D2EF9E6DFEAEBCCA574916977CF36FF00575E652F70DF988F74FA6F1213B2FB807A0F6CF03B9DC408BEE01E83DB3C0EE771A3C5BC18F5FEA56357DC8F56C80030140000035AC6D865B892CAE6C4D4F9F53E6FA7775AF16F72FC723650778F25B1DA2F5EB0FB5B4D677872FBD8E8DEE63DAAD7357256AA64A8BD47828FA4EC2DF36A8F2ED247F5333912A5A9E8BF83BB978F6F79383D560CD5CD8E2F56B63BC5EBCD0DB746BD38A3F049C8A5D085E8D7A7147E093914BA189C57C78F4FBA8EABBFEC000CD5600000000000000000000000000000C7D5D86D15EED6AAB6524CFF00E27C2D577BF2CCC803EC5A6BDB1244CC746B52600C2F2FDAB4B13C32BDBF071E19A3EC2D1BB59B6A6AAFDE9A4727B95C6CC097F119BFCE7F7977F12FE72C751582CF6E735F476CA48646EC491B126B27E2DE644022B5A6D3BCCEEE26667A8003E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFD9, 0xFFD8FFE000104A46494600010100000100010000FFDB004300080606070605080707070909080A0C140D0C0B0B0C1912130F141D1A1F1E1D1A1C1C20242E2720222C231C1C2837292C30313434341F27393D38323C2E333432FFDB0043010909090C0B0C180D0D1832211C213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232FFC00011080140014003012200021101031101FFC4001C0001000301010101010000000000000000000506070804030201FFC40049100100010302020507070906040700000000010203040511063107213641615171727481B1B2121314152223911735547393A1B3C1D224528292D1F03242626325335355A2A4E2FFC400190101000301010000000000000000000000000304050201FFC400251101000201030304030100000000000000000102030411321231332141718113226151FFDA000C03010002110311003F00D24064AD000000000000000000000000000000000000000000000000000000000000000004F5472DC0148C8E94347C4C9B98F7F0353B77AD5534574556A8DE2639C7FC6F9FE56342FD1352FD9D1FD697F064FF00117E6C7FEAF622B40E20C1E23D3E733066B8A69AA68AEDDC888AE89F18899F3A551CC4C4ED29226263780078F400000011FAD6B389A0E99733F36AAA2D5131114D11BD554CF2888EF9553F2B1A17E89A97ECE8FEB775C57B46F58716C95ACED32BD8A4E374A1A46664DBC7C7C0D4EE5EB954534514DAA37999FF001AED1D71CB6797A5A9CA1ED6F5B719079751CEB5A669D919D7A9AEAB562DCDCAA28889AA623C9BA9DF958D0BF44D4BF6747F5BDAE3BDFD6B0F2D92B5E52BD8AA689D20695AF6A96F4FC5C7CDA2F5C8AA62ABB45314F546FDD54F916B796A5AB3B5A1ED6D168DE001CBA000000054758E91348D1755BFA764E3E6D77ACCC45555BA289A677889EADEA8F2BC5F958D0BF44D4BF6747F5A58C192637884739A913B4CAF63E183976F3F031B32D45516F22D537688AA3AE22A8898DFC7ADF745D9D800F40000000000000019A749DC2FF396FEBEC3B7F6E888A72A9A639C728AFD9CA7C36F232C74E5CB745EB55DAB94C576EBA669AA9AA378989E712C138C786EBE1BD6ABB34C4CE25EDEBC7AE7FBBDF4CF8C72FC27BDA3A4CDBC744A86A716D3D70FEF06F11D5C39AE517ABAA7E877B6A322988DFECF755B79639FE3E56F74574DCA29AE8AA2AA2A8DE9AA99DE263CB0E626B1D187134E4E3CE859773EF6CD3F2B1A667AEAA3BE9F67778798D5E1DE3AE0D2E5DA7A25A300CE5F0000145E9238A3EABD3BEAAC4B9B666553F6EAA67AEDDBEFF6CF5C79B7F0778E937B4561C5EF14AF54A91C7DC4DF5F6B33631AE7CAC0C599A6D4C4F557577D5FCA3C23C552167E08E18AF88B5889BD44FD031E62ABF57F7BC94479FDDBF835FF005C54FE432FF6C97FECAE1D19F0ACE359FAF732DFDEDDA76C5A663AE9A279D7EDE51E1BF95A3BF94D34D14C534C4534C46D1111B4443FAC8C992725BAA5A98E914AF4C21B8B7B23AB7AB57EE73D3A178B7B23AB7AB57EE73D2F68B8CA9EAF942D9D1BF6DF0FD0B9F04B7261BD1BF6DF0FD0B9F04B7243ACF27D25D270FB00545A00000060DC7FDB8D4FD2A3F874AB4B2F1FF6E353F4A8FE1D2AD36B170AFC43232739F974570D765B48F52B3F0425117C35D96D23D4ACFC109463DF94B56BC6001CBA00000000000000010BC53C3F6B88F45BB8756D4DFA7EDD8B93FF002D71CBD93CA5343DADA6B3BC3C988B46D2E65C8C7BB8993731EFDB9B77AD553457455CE2639C3F787977F0332CE5E35C9B77ACD715D154774C34CE93B85FE72DFD7D876FEDD1114E5534C738E515FB394F86DE4658D9C592325376564A4E3B6CE89E1CD72CF10E8B633ED6D4D557D9BB6E277F915C738FE71E13095615C0DC4F3C3DACC517EB9FA064CC517A3BA89EEAFD9DFE133E0DD62626378EB865E7C5F8EDFC6861C9F92BFD004299E1D6355C7D134ABFA8654FDDDAA778A639D73DD4C78CCB9EB54D4B2357D4F233F2AADEF5FAFE54EDCA23944478446D1EC5A3A43E279D6B56FA0E357BE0E255311B72B97394D5E68E51EDF2A98D4D2E1E8AF54F7966EA32F5DB68ED0F4E9F8191A9EA1630B168F977EF5514D31FCE7C239BA0787B44B1C3FA359C0B1B4CD31F2AED7B6DF395CF3ABFDF7442AFD1BF0ACE9983F5B6651B65E4D3F754CC75DBB7FEB3CFCDB78AF8ADAACDD73D31DA1634D8BA63AA7BC802A2D21B8B7B23AB7AB57EE73D3A178B7B23AB7AB57EE73D34745C654357CA16CE8DFB6F87E85CF825B930DE8DFB6F87E85CF825B921D6793E92E9387D802A2D000000306E3FEDC6A7E951FC3A55A5978FFB71A9FA547F0E9569B58B857E2191939CFCBA2B86BB2DA47A959F821288BE1AECB691EA567E084A31EFCA5AB5E3000E5D0000000000000000003F372DD17AD576AE5315DBAE99A6AA6A8DE26279C4B01E2EE1DB9C37ADDCC6DA6716E6F731EB9EFA37E533E58E53EC9EF74020B8B7876DF126897317AA326DFDE63D73DD5EDCA7C2794FE3DC9F4F97F1DBD7B4A0CF8BAEBE9DDCFCD8BA35E269D4B4E9D272AE6F958B4C7CD4CCF5D76FFD69EA8F34C78B20BD66E63DFB962F51345DB754D15D1573A6A89DA625E9D2B52BFA46A98F9F8D3B5DB15FCA8F18E531E698DE3DAD2CD8E3253651C59271DB7749299D21F134E8BA47D0B1AE6D9B99134C4C4F5DBB7CA6AF3F747B67B960B3AEE0DEE1E8D6FE76230FE666ECCF7C6DCE3CFBC4C6DE560BAEEB17F5DD632350BFD5372AFB34F7514C754447B1434D87AAFBDBB42E6A32F4D768F7472E1C01C2BF5F6A7F4BCAA2274FC5AA26B8AA3AAE55CE29F37299F0EAEF57748D2B235AD52C6062D3BDCBB56DBF7531DF54F84475BA0B47D2B1F44D2AC69F8B1F776A9DA6A9E75CF7D53E332B5A9CDD15E98EF2ADA7C5D73BCF687B8065B480010DC5BD91D5BD5ABF739E9D0BC5BD91D5BD5ABF739E9A3A2E32A1ABE50B6746FDB7C3F42E7C12DC986F46FDB7C3F42E7C12DC90EB3C9F49749C3EC0151680000018371FF6E353F4A8FE1D2AD2CBC7FDB8D4FD2A3F874AB4DAC5C2BF10C8C9CE7E5D15C35D96D23D4ACFC109445F0D765B48F52B3F042518F7E52D5AF180072E800000000000000000000198F49DC2FBC7D7F876FAE36A72A9A63F0AFDD13ECF165EE9BBD66DE458B966F514D76AE5334574551BC55131B4C4B02E2EE1DAF86F5CB98D1BD58D73EF31EB9EFA26794F8C729FC7BDA3A4CDD51D12A1A9C5B4F5C3C14EB39B4E87568F177FB1D57A2F4D3DFF002B6E5E6EFDBCAF00BDF471C2D1AAE7CEAB9746F898B5C7CDD33CAE5CE7F84754FB63C566F6AE3ACDA55EB59BDA2AB8F47DC2BF5169BF4DCAA36CFCAA6266263AED51CE29F3F7CFB23B972063DEF37B754B56958AC6D000E5D00021B8B7B23AB7AB57EE73D3A178B7B23AB7AB57EE73D34745C654357CA16CE8DFB6F87E85CF825B930DE8DFB6F87E85CF825B921D6793E92E9387D802A2D000000306E3FEDC6A7E951FC3A55A5978FF00B71A9FA547F0E9569B58B857E2191939CFCBA2B86BB2DA47A959F821288BE1AECB691EA567E084A31EFCA5AB5E3000E5D0000000000000000000000C9FA5CFCE5A6FEA6BF7C35864FD2E7E72D37F535FBE1634BE5841A9F1CB396CFD16764ABF5AAFDD4B186CFD16764ABF5AAFDD4AE6B3C6A9A5F22EE032DA400000087E2CA66AE12D5A23F45B93FB9CF2E91D62CFD2744CFB1FFAB8D728FC6998737347453FACC286AE3F685A3A3BAE69E39D3E37DA2A8B913FB3A9BB39F783B263178C34BB957544DF8A3FCDF67F9BA0916B63F789FE25D24FE9200A6B4000000C0F8EEBF97C6DA9CFFDCA63F0A2985752BC4D91F4BE28D52F44EF1564DC889F08AA623F74229B78E36A4431EF3BDA65D17C3B4CD1C31A4D3546D31876627FC909379F06CFD1B4FC6B1B6DF376A9A36F34443D0C5B4EF332D7AC6D1000F1E8000000000000000000000C9FA5CFCE5A6FEA6BF7C35864FD2E7E72D37F535FBE1634BE5841A9F1CB396CFD16764ABF5AAFDD4B186CFD16764ABF5AAFDD4AE6B3C6A9A5F22EE032DA40000004C44C6D3D70E6DD5B0A74DD5F330A63FF0022F556E3CD13D5FB9D24C77A52D1E70F5EB7A9514CFCD6653B55311D515D31113F8C6DFBD6F477DAF35FF557555DEB13FE28F62F578F916EFDB9DAE5BAA2BA67C9313BC3A474ECEB5A9E9D8F9D6277B57EDC574F86F1CBCF1C9CD4BD700F1AD1A255F566A354C605CAB7A2E6DBFCD553CF7FFA67F77E2B3AAC537AEF1DE1069B2452DB4F696C83F16AEDBBD6A9BB6AE5372DD51BD35513BC4C784BF6CB6880008FD7353B7A3E89979F72A88F99B7334EFDF572A63DB3B43DB76EDBB36AABB76E536EDD31BD55573B44478CB1CE3FE32A35DBB4E9DA7D754E0DAABE5575F2F9EABBBFC31FEFB92E1C5392DB7B22CB92295DFDD489999999999999E73291E1FC29D438874FC588DFE72FD1157A3BEF3FBB746B43E8AB45AAFEA77F58B94FDD635336AD4CC73B95475EDE6A67FF00943572DFA2932CDC75EABC435B018AD7000000000000000000000000193F4B9F9CB4DFD4D7EF86B0C9FA5CFCE5A6FEA6BF7C2C697CB08353E39672D9FA2CEC957EB55FBA9630D9FA2CEC957EB55FBA95CD678D534BE45DC065B4800000046EBDA2E3F106917B4FC999A62BEBA2B88DE68AA39551FEFCA921EC4CC4EF0F262263697376ADA4E668BA8DCC1CEB5345DA394F7571DD5533DF12F13A275DE1DD3B88B0FE8F9D6779A77F9BBB4F5576E7C27F972651AE746FACE99555730E9FAC31E3AE26D47DB8F3D1CE7D9BB4F16A6B78DADE92CECBA7B56778F5841E91C4BABE873FF87E6DCB76FBED4ED5513FE19EAF6C75ADF8BD2DE7D14ED97A663DE9F2DAAEAB7EFF0094CF6ED9BB8F76AB57ADD76EE533B554574CC4C4F8C4BF09AD8B1DFD6611D72DEBE912D3E7A5F9DBAB43EBF5BFFF000F0E5F4B5A9DC8DB134FC5B3E3726AB93FC99F0E234D8A3D9D4EA324FBA5756E24D635B9DB50CEBB768EEB71B5347F96368F6A29F4B18F7F2AF53671ECDCBD76AFF868B74CD554FB2175D07A32D5350AE9BBA9FF0061C6E7F26769BB579A3BBDBD7E0EED6A638F5F47115BE49F4F556B40D033788B52A70F0E9EAE772ECC7D9B74F967FD3BDBEE93A663E8DA5D8C0C5A76B5669DB79E754F7D53E333D6FE693A3E0E89854E26058A6D5B8EB99FF9AB9F2D53DF2F73373E79CB3B4766861C318E379EE00AE9C000000000000000000000000000000000000000000001F0C9C2C5CDA3E4656359BF47F76EDB8AA3F7A22F70570DDF9DEBD231E27FE889A3DD309E1D45AD1DA5CCD6B3DE158FC9DF0AFF00ED7FFD8BBFD4F558E0BE1BC7AFE551A4634CFF00DC89AE3F0AB74E8F672DE7DE5E7E3A47B43E38D898D876A2D62E3DAB16E39516A88A63F087D81C3B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007FFD9, '2006-02-27 05:15:03.000', '2019-08-14 17:36:43.000', N'2003-05-14 08:07:42 +00:00', '1900-06-19 00:00:00.000', '2005-05-29');\n";
+
+    private static final String PG_IMAGE = "postgis/postgis";
+    private static final String PG_DRIVER_JAR =
+            "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.3.3/postgresql-42.3.3.jar";
+    private static final String PG_JDBC_JAR =
+            "https://repo1.maven.org/maven2/net/postgis/postgis-jdbc/2.5.1/postgis-jdbc-2.5.1.jar";
+    private static final String PG_GEOMETRY_JAR =
+            "https://repo1.maven.org/maven2/net/postgis/postgis-geometry/2.5.1/postgis-geometry-2.5.1.jar";
+
+    private static final String MYSQL_IMAGE = "mysql:latest";
+    private static final String MYSQL_CONTAINER_HOST = "mysql-e2e";
+    private static final String MYSQL_DATABASE = "auto";
+
+    private static final String MYSQL_USERNAME = "root";
+    private static final String MYSQL_PASSWORD = "Abc!@#135_seatunnel";
+    private static final int MYSQL_PORT = 3306;
+    //    private static final String MYSQL_URL = "jdbc:mysql://" + HOST + ":%s/%s?useSSL=false";
+
+    private static final String MYSQL_DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
+
+    private static final String ORACLE_IMAGE = "gvenzl/oracle-xe:21-slim-faststart";
+    private static final String ORACLE_NETWORK_ALIASES = "e2e_oracleDb";
+    private static final String ORACLE_DRIVER_CLASS = "oracle.jdbc.OracleDriver";
+    private static final int ORACLE_PORT = 1521;
+    //    private static final String ORACLE_URL = "jdbc:oracle:thin:@" + HOST + ":%s/%s";
+    private static final String USERNAME = "testUser";
+    private static final String PASSWORD = "Abc!@#135_seatunnel";
+    private static final String DATABASE = "TESTUSER";
+    private static final String SOURCE_TABLE = "E2E_TABLE_SOURCE";
+    private static final String SINK_TABLE = "E2E_TABLE_SINK";
+
+    private PostgreSQLContainer<?> POSTGRESQL_CONTAINER;
+
+    private MSSQLServerContainer<?> sqlserver_container;
+    private MySQLContainer<?> mysql_container;
+    private OracleContainer oracle_container;
+
+    private static final String mysqlCheck =
+            "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema = 'auto' AND table_name = 'sqlserver_auto_create_mysql') AS table_exists";
+    private static final String sqlserverCheck =
+            "IF EXISTS (\n"
+                    + "    SELECT 1\n"
+                    + "    FROM testauto.sys.tables t\n"
+                    + "    JOIN testauto.sys.schemas s ON t.schema_id = s.schema_id\n"
+                    + "    WHERE t.name = 'sqlserver_auto_create_sql' AND s.name = 'dbo'\n"
+                    + ")\n"
+                    + "    SELECT 1 AS table_exists;\n"
+                    + "ELSE\n"
+                    + "    SELECT 0 AS table_exists;";
+    private static final String pgCheck =
+            "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'sqlserver_auto_create_pg') AS table_exists;\n";
+    private static final String oracleCheck =
+            "SELECT CASE WHEN EXISTS(SELECT 1 FROM user_tables WHERE table_name = 'sqlserver_auto_create_oracle') THEN 1 ELSE 0 END AS table_exists FROM DUAL;\n";
+
+    String driverMySqlUrl() {
+        return "https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.32/mysql-connector-j-8.0.32.jar";
+    }
+
+    String driverOracleUrl() {
+        return "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc8/12.2.0.1/ojdbc8-12.2.0.1.jar";
+    }
+
+    String driverSqlserverUrl() {
+        return "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/9.4.1.jre8/mssql-jdbc-9.4.1.jre8.jar";
+    }
+
+    static JdbcUrlUtil.UrlInfo sqlParse =
+            SqlServerURLParser.parse("jdbc:sqlserver://localhost:1433;database=testauto");
+    static JdbcUrlUtil.UrlInfo MysqlUrlInfo =
+            JdbcUrlUtil.getUrlInfo("jdbc:mysql://localhost:3306/auto?useSSL=false");
+    static JdbcUrlUtil.UrlInfo pg = JdbcUrlUtil.getUrlInfo("jdbc:postgresql://localhost:5432/pg");
+    static JdbcUrlUtil.UrlInfo oracle =
+            OracleURLParser.parse("jdbc:oracle:thin:@localhost:1521/TESTUSER");
+
+    @TestContainerExtension
+    private final ContainerExtendedFactory extendedSqlServerFactory =
+            container -> {
+                Container.ExecResult extraCommands =
+                        container.execInContainer(
+                                "bash",
+                                "-c",
+                                "mkdir -p /tmp/seatunnel/plugins/Jdbc/lib && cd /tmp/seatunnel/plugins/Jdbc/lib && curl -O "
+                                        + PG_DRIVER_JAR
+                                        + " && curl -O "
+                                        + PG_JDBC_JAR
+                                        + " && curl -O "
+                                        + PG_GEOMETRY_JAR
+                                        + " && curl -O "
+                                        + MYSQL_DRIVER_CLASS
+                                        + " && curl -O "
+                                        + ORACLE_DRIVER_CLASS
+                                        + " && curl -O "
+                                        + driverSqlserverUrl()
+                                        + " && curl -O "
+                                        + driverMySqlUrl()
+                                        + " && curl -O "
+                                        + driverOracleUrl());
+                //                Assertions.assertEquals(0, extraCommands.getExitCode());
+            };
+
+    void initContainer() throws ClassNotFoundException {
+        DockerImageName imageName = DockerImageName.parse(SQLSERVER_IMAGE);
+        sqlserver_container =
+                new MSSQLServerContainer<>(imageName)
+                        .withNetwork(TestSuiteBase.NETWORK)
+                        .withNetworkAliases(SQLSERVER_CONTAINER_HOST)
+                        .withPassword(PASSWORD)
+                        .acceptLicense()
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(
+                                        DockerLoggerFactory.getLogger(SQLSERVER_IMAGE)));
+
+        sqlserver_container.setPortBindings(
+                Lists.newArrayList(
+                        String.format(
+                                "%s:%s", SQLSERVER_CONTAINER_PORT, SQLSERVER_CONTAINER_PORT)));
+
+        try {
+            Class.forName(sqlserver_container.getDriverClassName());
+        } catch (ClassNotFoundException e) {
+            throw new SeaTunnelRuntimeException(
+                    JdbcITErrorCode.DRIVER_NOT_FOUND, "Not found suitable driver for mssql", e);
+        }
+
+        username = sqlserver_container.getUsername();
+        password = sqlserver_container.getPassword();
+        // ============= PG
+        POSTGRESQL_CONTAINER =
+                new PostgreSQLContainer<>(
+                                DockerImageName.parse(PG_IMAGE)
+                                        .asCompatibleSubstituteFor("postgres"))
+                        .withNetwork(TestSuiteBase.NETWORK)
+                        .withNetworkAliases("postgre-e2e")
+                        .withDatabaseName("pg")
+                        .withUsername(USERNAME)
+                        .withPassword(PASSWORD)
+                        .withCommand("postgres -c max_prepared_transactions=100")
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(DockerLoggerFactory.getLogger(PG_IMAGE)));
+        POSTGRESQL_CONTAINER.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", 5432, 5432)));
+
+        log.info("PostgreSQL container started");
+        Class.forName(POSTGRESQL_CONTAINER.getDriverClassName());
+
+        log.info("pg data initialization succeeded. Procedure");
+        DockerImageName mysqlImageName = DockerImageName.parse(MYSQL_IMAGE);
+        mysql_container =
+                new MySQLContainer<>(mysqlImageName)
+                        .withUsername(MYSQL_USERNAME)
+                        .withPassword(MYSQL_PASSWORD)
+                        .withDatabaseName(MYSQL_DATABASE)
+                        .withNetwork(NETWORK)
+                        .withNetworkAliases(MYSQL_CONTAINER_HOST)
+                        .withExposedPorts(MYSQL_PORT)
+                        .waitingFor(Wait.forHealthcheck())
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(DockerLoggerFactory.getLogger(MYSQL_IMAGE)));
+
+        mysql_container.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", MYSQL_PORT, MYSQL_PORT)));
+
+        DockerImageName oracleImageName = DockerImageName.parse(ORACLE_IMAGE);
+        oracle_container =
+                new OracleContainer(oracleImageName)
+                        .withDatabaseName(DATABASE)
+                        .withUsername(USERNAME)
+                        .withPassword(PASSWORD)
+                        .withNetwork(NETWORK)
+                        .withNetworkAliases(ORACLE_NETWORK_ALIASES)
+                        .withExposedPorts(ORACLE_PORT)
+                        .withLogConsumer(
+                                new Slf4jLogConsumer(DockerLoggerFactory.getLogger(ORACLE_IMAGE)));
+        oracle_container.withCommand(
+                "bash",
+                "-c",
+                "echo \"CREATE USER admin IDENTIFIED BY admin; GRANT DBA TO admin;\" | sqlplus / as sysdba");
+        oracle_container.setPortBindings(
+                Lists.newArrayList(String.format("%s:%s", ORACLE_PORT, ORACLE_PORT)));
+        Startables.deepStart(
+                        Stream.of(
+                                POSTGRESQL_CONTAINER,
+                                sqlserver_container,
+                                mysql_container,
+                                oracle_container))
+                .join();
+
+        log.info(" container is up ");
+    }
+
+    @Override
+    @BeforeAll
+    public void startUp() throws Exception {
+        initContainer();
+
+        initializeJdbcTable();
+    }
+
+    @TestTemplate
+    public void testAutoCreateTable(TestContainer container)
+            throws IOException, InterruptedException {
+
+        TablePath tablePathSQL = TablePath.of("testauto", "dbo", "sqlserver_auto_create");
+        TablePath tablePathSQL_Sql = TablePath.of("testauto", "dbo", "sqlserver_auto_create_sql");
+        TablePath tablePathMySql = TablePath.of("auto", "sqlserver_auto_create_mysql");
+        TablePath tablePathPG = TablePath.of("pg", "public", "sqlserver_auto_create_pg");
+        TablePath tablePathOracle = TablePath.of("TESTUSER", "sqlserver_auto_create_oracle");
+
+        SqlServerCatalog sqlServerCatalog =
+                new SqlServerCatalog("sqlserver", "sa", password, sqlParse, "dbo");
+        MySqlCatalog mySqlCatalog = new MySqlCatalog("mysql", "root", PASSWORD, MysqlUrlInfo);
+        PostgresCatalog postgresCatalog =
+                new PostgresCatalog("postgres", "testUser", PASSWORD, pg, "public");
+        OracleCatalog oracleCatalog =
+                new OracleCatalog("oracle", "admin", "admin", oracle, "TESTUSER");
+        mySqlCatalog.open();
+        sqlServerCatalog.open();
+        postgresCatalog.open();
+        //        oracleCatalog.open();
+
+        CatalogTable sqlServerCatalogTable = sqlServerCatalog.getTable(tablePathSQL);
+
+        sqlServerCatalog.createTable(tablePathSQL_Sql, sqlServerCatalogTable, true);
+        postgresCatalog.createTable(tablePathPG, sqlServerCatalogTable, true);
+        //        oracleCatalog.createTable(tablePathOracle, sqlServerCatalogTable, true);
+        mySqlCatalog.createTable(tablePathMySql, sqlServerCatalogTable, true);
+
+        Assertions.assertTrue(checkMysql(mysqlCheck));
+        //        Assertions.assertTrue(checkOracle(oracleCheck));
+        Assertions.assertTrue(checkSqlServer(sqlserverCheck));
+        Assertions.assertTrue(checkPG(pgCheck));
+
+        // delete table
+        log.info("delete table");
+        sqlServerCatalog.dropTable(tablePathSQL_Sql, true);
+        sqlServerCatalog.dropTable(tablePathSQL, true);
+        postgresCatalog.dropTable(tablePathPG, true);
+        //        oracleCatalog.dropTable(tablePathOracle, true);
+        mySqlCatalog.dropTable(tablePathMySql, true);
+
+        sqlServerCatalog.close();
+        mySqlCatalog.close();
+        postgresCatalog.close();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (sqlserver_container != null) {
+            sqlserver_container.close();
+        }
+        if (mysql_container != null) {
+            mysql_container.close();
+        }
+        if (oracle_container != null) {
+            oracle_container.close();
+        }
+        if (POSTGRESQL_CONTAINER != null) {
+            POSTGRESQL_CONTAINER.close();
+        }
+    }
+
+    private Connection getJdbcSqlServerConnection() throws SQLException {
+        return DriverManager.getConnection(
+                sqlserver_container.getJdbcUrl(),
+                sqlserver_container.getUsername(),
+                sqlserver_container.getPassword());
+    }
+
+    private Connection getJdbcMySqlConnection() throws SQLException {
+        return DriverManager.getConnection(
+                mysql_container.getJdbcUrl(),
+                mysql_container.getUsername(),
+                mysql_container.getPassword());
+    }
+
+    private Connection getJdbcPgConnection() throws SQLException {
+        return DriverManager.getConnection(
+                POSTGRESQL_CONTAINER.getJdbcUrl(),
+                POSTGRESQL_CONTAINER.getUsername(),
+                POSTGRESQL_CONTAINER.getPassword());
+    }
+
+    private Connection getJdbcOracleConnection() throws SQLException {
+        return DriverManager.getConnection(
+                oracle_container.getJdbcUrl(),
+                oracle_container.getUsername(),
+                oracle_container.getPassword());
+    }
+
+    private void initializeJdbcTable() {
+        try (Connection connection = getJdbcSqlServerConnection()) {
+            Statement statement = connection.createStatement();
+            statement.execute(CREATE_DATABASE);
+            statement.execute(CREATE_TABLE_SQL);
+            statement.execute(getInsertSql);
+            //            statement.executeBatch();
+        } catch (SQLException e) {
+            throw new RuntimeException("Initializing PostgreSql table failed!", e);
+        }
+    }
+
+    private boolean checkMysql(String sql) {
+        try (Connection connection = getJdbcMySqlConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getBoolean(1);
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private boolean checkPG(String sql) {
+        try (Connection connection = getJdbcPgConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getBoolean(1);
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private boolean checkSqlServer(String sql) {
+        try (Connection connection = getJdbcSqlServerConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getInt(1) == 1;
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private boolean checkOracle(String sql) {
+        try (Connection connection = getJdbcOracleConnection()) {
+            ResultSet resultSet = connection.createStatement().executeQuery(sql);
+            boolean tableExists = false;
+            if (resultSet.next()) {
+                tableExists = resultSet.getInt(1) == 1;
+            }
+            return tableExists;
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/pom.xml b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/pom.xml
index f803a4c61e8..0b3e18bdbf2 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/pom.xml
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/pom.xml
@@ -31,6 +31,7 @@
         <module>connector-jdbc-e2e-part-1</module>
         <module>connector-jdbc-e2e-part-2</module>
         <module>connector-jdbc-e2e-part-3</module>
+        <module>connector-jdbc-e2e-part-4</module>
     </modules>
 
     <dependencyManagement>
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/java/org/apache/seatunnel/e2e/connector/kafka/CanalToKafkaIT.java b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/java/org/apache/seatunnel/e2e/connector/kafka/CanalToKafkaIT.java
index 0d8bb567ae4..9afe0ce332f 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/java/org/apache/seatunnel/e2e/connector/kafka/CanalToKafkaIT.java
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/java/org/apache/seatunnel/e2e/connector/kafka/CanalToKafkaIT.java
@@ -293,6 +293,17 @@ public void testCanalFormatKafkaCdcToPgsql(TestContainer container)
                         Arrays.asList(107, "rocks", "box of assorted rocks", "7.88"),
                         Arrays.asList(108, "jacket", "water resistent black wind breaker", "0.1"));
         Assertions.assertIterableEquals(expected, actual);
+
+        try (Connection connection =
+                DriverManager.getConnection(
+                        POSTGRESQL_CONTAINER.getJdbcUrl(),
+                        POSTGRESQL_CONTAINER.getUsername(),
+                        POSTGRESQL_CONTAINER.getPassword())) {
+            try (Statement statement = connection.createStatement()) {
+                statement.execute("truncate table sink");
+                LOG.info("testCanalFormatKafkaCdcToPgsql truncate table sink");
+            }
+        }
     }
 
     private void initKafkaConsumer() {
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/resources/canalFormatIT/kafka_source_canal_cdc_to_pgsql.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/resources/canalFormatIT/kafka_source_canal_cdc_to_pgsql.conf
index 9ce69a2344c..2f7249dbdbd 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/resources/canalFormatIT/kafka_source_canal_cdc_to_pgsql.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-kafka-e2e/src/test/resources/canalFormatIT/kafka_source_canal_cdc_to_pgsql.conf
@@ -47,13 +47,14 @@ source {
 
 sink {
   Jdbc {
+
     driver = org.postgresql.Driver
     url = "jdbc:postgresql://postgresql:5432/test?loggerLevel=OFF"
     user = test
     password = test
     generate_sink_sql = true
-    database = public
-    table = sink
+    database = test
+    table = public.sink
     primary_keys = ["id"]
   }
 }
\ No newline at end of file
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/java/org/apache/seatunnel/e2e/connector/pulsar/CanalToPulsarIT.java b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/java/org/apache/seatunnel/e2e/connector/pulsar/CanalToPulsarIT.java
index 716bd7dc90e..ec8fd481380 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/java/org/apache/seatunnel/e2e/connector/pulsar/CanalToPulsarIT.java
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/java/org/apache/seatunnel/e2e/connector/pulsar/CanalToPulsarIT.java
@@ -337,5 +337,16 @@ void testCanalFormatMessages(TestContainer container)
                         Arrays.asList(107, "rocks", "box of assorted rocks", "7.88"),
                         Arrays.asList(108, "jacket", "water resistent black wind breaker", "0.1"));
         Assertions.assertIterableEquals(expected, actual);
+
+        try (Connection connection =
+                DriverManager.getConnection(
+                        POSTGRESQL_CONTAINER.getJdbcUrl(),
+                        POSTGRESQL_CONTAINER.getUsername(),
+                        POSTGRESQL_CONTAINER.getPassword())) {
+            try (Statement statement = connection.createStatement()) {
+                statement.execute("truncate table sink");
+                LOG.info("testSinkCDCChangelog truncate table sink");
+            }
+        }
     }
 }
diff --git a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/resources/cdc_canal_pulsar_to_pg.conf b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/resources/cdc_canal_pulsar_to_pg.conf
index c287be67658..3ace667579e 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/resources/cdc_canal_pulsar_to_pg.conf
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-pulsar-e2e/src/test/resources/cdc_canal_pulsar_to_pg.conf
@@ -58,8 +58,8 @@ sink {
     user = test
     password = test
     generate_sink_sql = true
-    database = public
-    table = sink
+    database = test
+    table = public.sink
     primary_keys = ["id"]
   }
 }