This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 60b92e43943 branch-3.1: [fix](hive) sync DDL command to other FE 
(#46326) (#51938)
60b92e43943 is described below

commit 60b92e4394349516674a97638fc7c7a2e7b645d0
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Fri Jun 20 10:41:08 2025 +0800

    branch-3.1: [fix](hive) sync DDL command to other FE (#46326) (#51938)
    
    bp #46326
---
 .../main/java/org/apache/doris/catalog/Env.java    | 49 ++++++++++++---
 .../apache/doris/datasource/ExternalCatalog.java   | 59 +++++++++++++++--
 .../apache/doris/datasource/InternalCatalog.java   |  4 +-
 .../doris/datasource/hive/HiveMetadataOps.java     | 53 ++++++++++++----
 .../datasource/iceberg/IcebergMetadataOps.java     | 39 +++++++++---
 .../datasource/operations/ExternalMetadataOps.java | 52 +++++++++++++--
 .../org/apache/doris/journal/JournalEntity.java    |  6 ++
 .../org/apache/doris/persist/CreateDbInfo.java     | 73 ++++++++++++++++++++++
 .../org/apache/doris/persist/CreateTableInfo.java  | 30 ++++++++-
 .../java/org/apache/doris/persist/DropDbInfo.java  | 13 ++++
 .../java/org/apache/doris/persist/DropInfo.java    | 33 ++++++++++
 .../java/org/apache/doris/persist/EditLog.java     | 70 ++++++++++++++-------
 .../org/apache/doris/persist/OperationType.java    |  4 +-
 .../apache/doris/persist/TruncateTableInfo.java    | 26 +++++++-
 .../org/apache/doris/persist/CreateDbInfoTest.java | 72 +++++++++++++++++++++
 15 files changed, 521 insertions(+), 62 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
index 6b17802ef45..d318be5930f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
@@ -211,6 +211,9 @@ import org.apache.doris.persist.BackendReplicasInfo;
 import org.apache.doris.persist.BackendTabletsInfo;
 import org.apache.doris.persist.BinlogGcInfo;
 import org.apache.doris.persist.CleanQueryStatsInfo;
+import org.apache.doris.persist.CreateDbInfo;
+import org.apache.doris.persist.CreateTableInfo;
+import org.apache.doris.persist.DropDbInfo;
 import org.apache.doris.persist.DropPartitionInfo;
 import org.apache.doris.persist.EditLog;
 import org.apache.doris.persist.GlobalVarPersistInfo;
@@ -3271,8 +3274,15 @@ public class Env {
         getInternalCatalog().unprotectCreateDb(db);
     }
 
-    public void replayCreateDb(Database db) {
-        getInternalCatalog().replayCreateDb(db, "");
+    public void replayCreateDb(CreateDbInfo dbInfo) {
+        if (dbInfo.getInternalDb() != null) {
+            getInternalCatalog().replayCreateDb(dbInfo.getInternalDb(), "");
+        } else {
+            ExternalCatalog externalCatalog = (ExternalCatalog) 
catalogMgr.getCatalog(dbInfo.getCtlName());
+            if (externalCatalog != null) {
+                externalCatalog.replayCreateDb(dbInfo.getDbName());
+            }
+        }
     }
 
     public void dropDb(DropDbStmt stmt) throws DdlException {
@@ -3285,8 +3295,16 @@ public class Env {
         catalogIf.dropDb(stmt);
     }
 
-    public void replayDropDb(String dbName, boolean isForceDrop, Long 
recycleTime) throws DdlException {
-        getInternalCatalog().replayDropDb(dbName, isForceDrop, recycleTime);
+    public void replayDropDb(DropDbInfo info) throws DdlException {
+        if (Strings.isNullOrEmpty(info.getCtlName()) || info.getCtlName()
+                .equals(InternalCatalog.INTERNAL_CATALOG_NAME)) {
+            getInternalCatalog().replayDropDb(info.getDbName(), 
info.isForceDrop(), info.getRecycleTime());
+        } else {
+            ExternalCatalog externalCatalog = (ExternalCatalog) 
catalogMgr.getCatalog(info.getCtlName());
+            if (externalCatalog != null) {
+                externalCatalog.replayDropDb(info.getDbName());
+            }
+        }
     }
 
     public void recoverDatabase(RecoverDbStmt recoverStmt) throws DdlException 
{
@@ -4179,8 +4197,16 @@ public class Env {
         }
     }
 
-    public void replayCreateTable(String dbName, Table table) throws 
MetaNotFoundException {
-        getInternalCatalog().replayCreateTable(dbName, table);
+    public void replayCreateTable(CreateTableInfo info) throws 
MetaNotFoundException {
+        if (Strings.isNullOrEmpty(info.getCtlName()) || info.getCtlName()
+                .equals(InternalCatalog.INTERNAL_CATALOG_NAME)) {
+            getInternalCatalog().replayCreateTable(info.getDbName(), 
info.getTable());
+        } else {
+            ExternalCatalog externalCatalog = (ExternalCatalog) 
catalogMgr.getCatalog(info.getCtlName());
+            if (externalCatalog != null) {
+                externalCatalog.replayCreateTable(info.getDbName(), 
info.getTblName());
+            }
+        }
     }
 
     public void replayAlterExternalTableSchema(String dbName, String 
tableName, List<Column> newSchema)
@@ -5899,7 +5925,16 @@ public class Env {
     }
 
     public void replayTruncateTable(TruncateTableInfo info) throws 
MetaNotFoundException {
-        getInternalCatalog().replayTruncateTable(info);
+        if (Strings.isNullOrEmpty(info.getCtl()) || 
info.getCtl().equals(InternalCatalog.INTERNAL_CATALOG_NAME)) {
+            // In previous versions(before 2.1.8), there is no catalog info in 
TruncateTableInfo,
+            // So if the catalog info is empty, we assume it's internal table.
+            getInternalCatalog().replayTruncateTable(info);
+        } else {
+            ExternalCatalog ctl = (ExternalCatalog) 
catalogMgr.getCatalog(info.getCtl());
+            if (ctl != null) {
+                ctl.replayTruncateTable(info);
+            }
+        }
     }
 
     public void createFunction(CreateFunctionStmt stmt) throws UserException {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
index a96221057ea..d89d4582862 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
@@ -59,6 +59,11 @@ import org.apache.doris.datasource.test.TestExternalCatalog;
 import org.apache.doris.datasource.test.TestExternalDatabase;
 import 
org.apache.doris.datasource.trinoconnector.TrinoConnectorExternalDatabase;
 import org.apache.doris.fs.remote.dfs.DFSFileSystem;
+import org.apache.doris.persist.CreateDbInfo;
+import org.apache.doris.persist.CreateTableInfo;
+import org.apache.doris.persist.DropDbInfo;
+import org.apache.doris.persist.DropInfo;
+import org.apache.doris.persist.TruncateTableInfo;
 import org.apache.doris.persist.gson.GsonPostProcessable;
 import org.apache.doris.persist.gson.GsonUtils;
 import org.apache.doris.qe.ConnectContext;
@@ -988,12 +993,20 @@ public abstract class ExternalCatalog
         }
         try {
             metadataOps.createDb(stmt);
+            CreateDbInfo info = new CreateDbInfo(getName(), 
stmt.getFullDbName(), null);
+            Env.getCurrentEnv().getEditLog().logCreateDb(info);
         } catch (Exception e) {
-            LOG.warn("Failed to create a database.", e);
+            LOG.warn("Failed to create database {} in catalog {}.", 
stmt.getFullDbName(), getName(), e);
             throw e;
         }
     }
 
+    public void replayCreateDb(String dbName) {
+        if (metadataOps != null) {
+            metadataOps.afterCreateDb(dbName);
+        }
+    }
+
     @Override
     public void dropDb(DropDbStmt stmt) throws DdlException {
         makeSureInitialized();
@@ -1003,12 +1016,20 @@ public abstract class ExternalCatalog
         }
         try {
             metadataOps.dropDb(stmt);
+            DropDbInfo info = new DropDbInfo(getName(), stmt.getDbName());
+            Env.getCurrentEnv().getEditLog().logDropDb(info);
         } catch (Exception e) {
-            LOG.warn("Failed to drop a database.", e);
+            LOG.warn("Failed to drop database {} in catalog {}", 
stmt.getDbName(), getName(), e);
             throw e;
         }
     }
 
+    public void replayDropDb(String dbName) {
+        if (metadataOps != null) {
+            metadataOps.afterDropDb(dbName);
+        }
+    }
+
     @Override
     public boolean createTable(CreateTableStmt stmt) throws UserException {
         makeSureInitialized();
@@ -1017,13 +1038,25 @@ public abstract class ExternalCatalog
             return false;
         }
         try {
-            return metadataOps.createTable(stmt);
+            boolean res = metadataOps.createTable(stmt);
+            if (!res) {
+                // res == false means the table does not exist before, and we 
create it.
+                CreateTableInfo info = new CreateTableInfo(getName(), 
stmt.getDbName(), stmt.getTableName());
+                Env.getCurrentEnv().getEditLog().logCreateTable(info);
+            }
+            return res;
         } catch (Exception e) {
             LOG.warn("Failed to create a table.", e);
             throw e;
         }
     }
 
+    public void replayCreateTable(String dbName, String tblName) {
+        if (metadataOps != null) {
+            metadataOps.afterCreateTable(dbName, tblName);
+        }
+    }
+
     @Override
     public void dropTable(DropTableStmt stmt) throws DdlException {
         makeSureInitialized();
@@ -1033,12 +1066,20 @@ public abstract class ExternalCatalog
         }
         try {
             metadataOps.dropTable(stmt);
+            DropInfo info = new DropInfo(getName(), stmt.getDbName(), 
stmt.getTableName());
+            Env.getCurrentEnv().getEditLog().logDropTable(info);
         } catch (Exception e) {
             LOG.warn("Failed to drop a table", e);
             throw e;
         }
     }
 
+    public void replayDropTable(String dbName, String tblName) {
+        if (metadataOps != null) {
+            metadataOps.afterDropTable(dbName, tblName);
+        }
+    }
+
     public void unregisterDatabase(String dbName) {
         throw new NotImplementedException("unregisterDatabase not 
implemented");
     }
@@ -1137,12 +1178,22 @@ public abstract class ExternalCatalog
                 partitions = tableRef.getPartitionNames().getPartitionNames();
             }
             metadataOps.truncateTable(tableName.getDb(), tableName.getTbl(), 
partitions);
+            TruncateTableInfo info = new TruncateTableInfo(getName(), 
tableName.getDb(), tableName.getTbl(),
+                    partitions);
+            Env.getCurrentEnv().getEditLog().logTruncateTable(info);
         } catch (Exception e) {
-            LOG.warn("Failed to drop a table", e);
+            LOG.warn("Failed to truncate table {}.{} in catalog {}", 
stmt.getTblRef().getName().getDb(),
+                    stmt.getTblRef().getName().getTbl(), getName(), e);
             throw e;
         }
     }
 
+    public void replayTruncateTable(TruncateTableInfo info) {
+        if (metadataOps != null) {
+            metadataOps.afterTruncateTable(info.getDb(), info.getTable());
+        }
+    }
+
     public void setAutoAnalyzePolicy(String dbName, String tableName, String 
policy) {
         Pair<String, String> key = Pair.of(dbName, tableName);
         if (policy == null) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
index 3657915ae4f..ce6a934b223 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
@@ -153,6 +153,7 @@ import 
org.apache.doris.nereids.trees.plans.commands.info.TableNameInfo;
 import org.apache.doris.persist.AlterDatabasePropertyInfo;
 import org.apache.doris.persist.AutoIncrementIdUpdateLog;
 import org.apache.doris.persist.ColocatePersistInfo;
+import org.apache.doris.persist.CreateDbInfo;
 import org.apache.doris.persist.DatabaseInfo;
 import org.apache.doris.persist.DropDbInfo;
 import org.apache.doris.persist.DropInfo;
@@ -454,7 +455,8 @@ public class InternalCatalog implements CatalogIf<Database> 
{
                 }
                 try {
                     unprotectCreateDb(db);
-                    Env.getCurrentEnv().getEditLog().logCreateDb(db);
+                    CreateDbInfo dbInfo = new 
CreateDbInfo(InternalCatalog.INTERNAL_CATALOG_NAME, db.getName(), db);
+                    Env.getCurrentEnv().getEditLog().logCreateDb(dbInfo);
                 } finally {
                     db.writeUnlock();
                 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
index a4a6b1ebdab..28fb2f73c32 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
@@ -107,7 +107,7 @@ public class HiveMetadataOps implements ExternalMetadataOps 
{
     }
 
     @Override
-    public void createDb(CreateDbStmt stmt) throws DdlException {
+    public void createDbImpl(CreateDbStmt stmt) throws DdlException {
         String fullDbName = stmt.getFullDbName();
         Map<String, String> properties = stmt.getProperties();
         long dbId = Env.getCurrentEnv().getNextId();
@@ -130,7 +130,6 @@ public class HiveMetadataOps implements ExternalMetadataOps 
{
             catalogDatabase.setProperties(properties);
             catalogDatabase.setComment(properties.getOrDefault("comment", ""));
             client.createDatabase(catalogDatabase);
-            catalog.onRefreshCache(true);
         } catch (Exception e) {
             throw new RuntimeException(e.getMessage(), e);
         }
@@ -138,7 +137,12 @@ public class HiveMetadataOps implements 
ExternalMetadataOps {
     }
 
     @Override
-    public void dropDb(DropDbStmt stmt) throws DdlException {
+    public void afterCreateDb(String dbName) {
+        catalog.onRefreshCache(true);
+    }
+
+    @Override
+    public void dropDbImpl(DropDbStmt stmt) throws DdlException {
         String dbName = stmt.getDbName();
         if (!databaseExist(dbName)) {
             if (stmt.isSetIfExists()) {
@@ -150,14 +154,18 @@ public class HiveMetadataOps implements 
ExternalMetadataOps {
         }
         try {
             client.dropDatabase(dbName);
-            catalog.onRefreshCache(true);
         } catch (Exception e) {
             throw new RuntimeException(e.getMessage(), e);
         }
     }
 
     @Override
-    public boolean createTable(CreateTableStmt stmt) throws UserException {
+    public void afterDropDb(String dbName) {
+        catalog.onRefreshCache(true);
+    }
+
+    @Override
+    public boolean createTableImpl(CreateTableStmt stmt) throws UserException {
         String dbName = stmt.getDbName();
         String tblName = stmt.getTableName();
         ExternalDatabase<?> db = catalog.getDbNullable(dbName);
@@ -265,7 +273,6 @@ public class HiveMetadataOps implements ExternalMetadataOps 
{
                         comment);
             }
             client.createTable(hiveTableMeta, stmt.isSetIfNotExists());
-            db.setUnInitialized(true);
         } catch (Exception e) {
             throw new UserException(e.getMessage(), e);
         }
@@ -273,7 +280,15 @@ public class HiveMetadataOps implements 
ExternalMetadataOps {
     }
 
     @Override
-    public void dropTable(DropTableStmt stmt) throws DdlException {
+    public void afterCreateTable(String dbName, String tblName) {
+        ExternalDatabase<?> db = catalog.getDbNullable(dbName);
+        if (db != null) {
+            db.setUnInitialized(true);
+        }
+    }
+
+    @Override
+    public void dropTableImpl(DropTableStmt stmt) throws DdlException {
         String dbName = stmt.getDbName();
         String tblName = stmt.getTableName();
         ExternalDatabase<?> db = catalog.getDbNullable(stmt.getDbName());
@@ -300,14 +315,22 @@ public class HiveMetadataOps implements 
ExternalMetadataOps {
 
         try {
             client.dropTable(dbName, tblName);
-            db.setUnInitialized(true);
         } catch (Exception e) {
             throw new DdlException(e.getMessage(), e);
         }
     }
 
     @Override
-    public void truncateTable(String dbName, String tblName, List<String> 
partitions) throws DdlException {
+    public void afterDropTable(String dbName, String tblName) {
+        ExternalDatabase<?> db = catalog.getDbNullable(dbName);
+        if (db != null) {
+            db.setUnInitialized(true);
+        }
+    }
+
+    @Override
+    public void truncateTableImpl(String dbName, String tblName, List<String> 
partitions)
+            throws DdlException {
         ExternalDatabase<?> db = catalog.getDbNullable(dbName);
         if (db == null) {
             throw new DdlException("Failed to get database: '" + dbName + "' 
in catalog: " + catalog.getName());
@@ -317,9 +340,17 @@ public class HiveMetadataOps implements 
ExternalMetadataOps {
         } catch (Exception e) {
             throw new DdlException(e.getMessage(), e);
         }
+    }
+
+    @Override
+    public void afterTruncateTable(String dbName, String tblName) {
+        // Invalidate cache.
         
Env.getCurrentEnv().getExtMetaCacheMgr().invalidateTableCache(catalog.getId(), 
dbName, tblName);
-        db.setLastUpdateTime(System.currentTimeMillis());
-        db.setUnInitialized(true);
+        ExternalDatabase<?> db = catalog.getDbNullable(dbName);
+        if (db != null) {
+            db.setLastUpdateTime(System.currentTimeMillis());
+            db.setUnInitialized(true);
+        }
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
index 787d706132e..7e11fb9e2c0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
@@ -120,12 +120,11 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
     }
 
     @Override
-    public void createDb(CreateDbStmt stmt) throws DdlException {
+    public void createDbImpl(CreateDbStmt stmt) throws DdlException {
         try {
             preExecutionAuthenticator.execute(() -> {
                 performCreateDb(stmt);
                 return null;
-
             });
         } catch (Exception e) {
             throw new DdlException("Failed to create database: "
@@ -133,6 +132,11 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
         }
     }
 
+    @Override
+    public void afterCreateDb(String dbName) {
+        dorisCatalog.onRefreshCache(true);
+    }
+
     private void performCreateDb(CreateDbStmt stmt) throws DdlException {
         SupportsNamespaces nsCatalog = (SupportsNamespaces) catalog;
         String dbName = stmt.getFullDbName();
@@ -153,11 +157,10 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
             }
         }
         nsCatalog.createNamespace(getNamespace(dbName), properties);
-        dorisCatalog.onRefreshCache(true);
     }
 
     @Override
-    public void dropDb(DropDbStmt stmt) throws DdlException {
+    public void dropDbImpl(DropDbStmt stmt) throws DdlException {
         try {
             preExecutionAuthenticator.execute(() -> {
                 preformDropDb(stmt);
@@ -180,11 +183,15 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
             }
         }
         nsCatalog.dropNamespace(getNamespace(dbName));
+    }
+
+    @Override
+    public void afterDropDb(String dbName) {
         dorisCatalog.onRefreshCache(true);
     }
 
     @Override
-    public boolean createTable(CreateTableStmt stmt) throws UserException {
+    public boolean createTableImpl(CreateTableStmt stmt) throws UserException {
         try {
             preExecutionAuthenticator.execute(() -> performCreateTable(stmt));
         } catch (Exception e) {
@@ -221,12 +228,19 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
         properties.put(ExternalCatalog.DORIS_VERSION, 
ExternalCatalog.DORIS_VERSION_VALUE);
         PartitionSpec partitionSpec = 
IcebergUtils.solveIcebergPartitionSpec(stmt.getPartitionDesc(), schema);
         catalog.createTable(getTableIdentifier(dbName, tableName), schema, 
partitionSpec, properties);
-        db.setUnInitialized(true);
         return false;
     }
 
     @Override
-    public void dropTable(DropTableStmt stmt) throws DdlException {
+    public void afterCreateTable(String dbName, String tblName) {
+        ExternalDatabase<?> db = dorisCatalog.getDbNullable(dbName);
+        if (db != null) {
+            db.setUnInitialized(true);
+        }
+    }
+
+    @Override
+    public void dropTableImpl(DropTableStmt stmt) throws DdlException {
         try {
             preExecutionAuthenticator.execute(() -> {
                 performDropTable(stmt);
@@ -238,6 +252,14 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
         }
     }
 
+    @Override
+    public void afterDropTable(String dbName, String tblName) {
+        ExternalDatabase<?> db = dorisCatalog.getDbNullable(dbName);
+        if (db != null) {
+            db.setUnInitialized(true);
+        }
+    }
+
     private void performDropTable(DropTableStmt stmt) throws DdlException {
         String dbName = stmt.getDbName();
         String tableName = stmt.getTableName();
@@ -260,11 +282,10 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
             }
         }
         catalog.dropTable(getTableIdentifier(dbName, tableName), true);
-        db.setUnInitialized(true);
     }
 
     @Override
-    public void truncateTable(String dbName, String tblName, List<String> 
partitions) {
+    public void truncateTableImpl(String dbName, String tblName, List<String> 
partitions) {
         throw new UnsupportedOperationException("Truncate Iceberg table is not 
supported.");
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
index e5ed129c679..f565f2795e8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
@@ -36,14 +36,29 @@ public interface ExternalMetadataOps {
      * @param stmt
      * @throws DdlException
      */
-    void createDb(CreateDbStmt stmt) throws DdlException;
+    default void createDb(CreateDbStmt stmt) throws DdlException {
+        createDbImpl(stmt);
+        afterCreateDb(stmt.getFullDbName());
+    }
+
+    void createDbImpl(CreateDbStmt stmt) throws DdlException;
+
+    default void afterCreateDb(String dbName) {
+    }
 
     /**
      * drop db in external metastore
      * @param stmt
      * @throws DdlException
      */
-    void dropDb(DropDbStmt stmt) throws DdlException;
+    default void dropDb(DropDbStmt stmt) throws DdlException {
+        dropDbImpl(stmt);
+        afterDropDb(stmt.getCtlName());
+    }
+
+    void dropDbImpl(DropDbStmt stmt) throws DdlException;
+
+    void afterDropDb(String dbName);
 
     /**
      *
@@ -51,14 +66,33 @@ public interface ExternalMetadataOps {
      * @return if set isExists is true, return true if table exists, otherwise 
return false
      * @throws UserException
      */
-    boolean createTable(CreateTableStmt stmt) throws UserException;
+    default boolean createTable(CreateTableStmt stmt) throws UserException {
+        boolean res = createTableImpl(stmt);
+        if (!res) {
+            afterCreateTable(stmt.getDbName(), stmt.getTableName());
+        }
+        return res;
+    }
+
+    boolean createTableImpl(CreateTableStmt stmt) throws UserException;
+
+    default void afterCreateTable(String dbName, String tblName) {
+    }
 
     /**
      *
      * @param stmt
      * @throws DdlException
      */
-    void dropTable(DropTableStmt stmt) throws DdlException;
+    default void dropTable(DropTableStmt stmt) throws DdlException {
+        dropTableImpl(stmt);
+        afterDropTable(stmt.getDbName(), stmt.getTableName());
+    }
+
+    void dropTableImpl(DropTableStmt stmt) throws DdlException;
+
+    default void afterDropTable(String dbName, String tblName) {
+    }
 
     /**
      *
@@ -66,7 +100,15 @@ public interface ExternalMetadataOps {
      * @param tblName
      * @param partitions
      */
-    void truncateTable(String dbName, String tblName, List<String> partitions) 
throws DdlException;
+    default void truncateTable(String dbName, String tblName, List<String> 
partitions) throws DdlException {
+        truncateTableImpl(dbName, tblName, partitions);
+        afterTruncateTable(dbName, tblName);
+    }
+
+    void truncateTableImpl(String dbName, String tblName, List<String> 
partitions) throws DdlException;
+
+    default void afterTruncateTable(String dbName, String tblName) {
+    }
 
     /**
      *
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java 
b/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
index 7527755baab..29096b68ce0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/journal/JournalEntity.java
@@ -81,6 +81,7 @@ import org.apache.doris.persist.CleanLabelOperationLog;
 import org.apache.doris.persist.CleanQueryStatsInfo;
 import org.apache.doris.persist.ColocatePersistInfo;
 import org.apache.doris.persist.ConsistencyCheckInfo;
+import org.apache.doris.persist.CreateDbInfo;
 import org.apache.doris.persist.CreateTableInfo;
 import org.apache.doris.persist.DatabaseInfo;
 import org.apache.doris.persist.DropDbInfo;
@@ -217,6 +218,11 @@ public class JournalEntity implements Writable {
                 isRead = true;
                 break;
             }
+            case OperationType.OP_NEW_CREATE_DB: {
+                data = CreateDbInfo.read(in);
+                isRead = true;
+                break;
+            }
             case OperationType.OP_DROP_DB: {
                 data = DropDbInfo.read(in);
                 isRead = true;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/persist/CreateDbInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/CreateDbInfo.java
new file mode 100644
index 00000000000..522ae021429
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/CreateDbInfo.java
@@ -0,0 +1,73 @@
+// 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.doris.persist;
+
+import org.apache.doris.catalog.Database;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class CreateDbInfo implements Writable {
+
+    @SerializedName("ctl")
+    private String ctlName;
+    @SerializedName("db")
+    private String dbName;
+    @SerializedName("idb")
+    private Database internalDb;
+
+    public CreateDbInfo() {
+        this.ctlName = "";
+        this.dbName = "";
+    }
+
+    public CreateDbInfo(String ctlName, String dbName, Database internalDb) {
+        this.ctlName = ctlName;
+        this.dbName = dbName;
+        this.internalDb = internalDb;
+    }
+
+    public String getCtlName() {
+        return ctlName;
+    }
+
+    public String getDbName() {
+        return dbName;
+    }
+
+    public Database getInternalDb() {
+        return internalDb;
+    }
+
+    public static CreateDbInfo read(DataInput in) throws IOException {
+        String json = Text.readString(in);
+        return GsonUtils.GSON.fromJson(json, CreateDbInfo.class);
+    }
+
+    @Override
+    public void write(DataOutput out) throws IOException {
+        String json = GsonUtils.GSON.toJson(this);
+        Text.writeString(out, json);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/persist/CreateTableInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/CreateTableInfo.java
index 1f2bcc15eb4..eab2f2b872e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/CreateTableInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/CreateTableInfo.java
@@ -23,9 +23,11 @@ import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.FeMetaVersion;
 import org.apache.doris.common.io.Text;
 import org.apache.doris.common.io.Writable;
+import org.apache.doris.datasource.InternalCatalog;
 import org.apache.doris.persist.gson.GsonPostProcessable;
 import org.apache.doris.persist.gson.GsonUtils;
 
+import com.google.common.base.Strings;
 import com.google.gson.annotations.SerializedName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,8 +40,12 @@ import java.util.Objects;
 public class CreateTableInfo implements Writable, GsonPostProcessable {
     public static final Logger LOG = 
LoggerFactory.getLogger(CreateTableInfo.class);
 
+    @SerializedName(value = "ctl")
+    private String ctlName;
     @SerializedName(value = "dbName")
     private String dbName;
+    @SerializedName(value = "tbl")
+    private String tblName;
     @SerializedName(value = "table")
     private Table table;
 
@@ -47,15 +53,33 @@ public class CreateTableInfo implements Writable, 
GsonPostProcessable {
         // for persist
     }
 
+    // for internal table
     public CreateTableInfo(String dbName, Table table) {
+        this.ctlName = InternalCatalog.INTERNAL_CATALOG_NAME;
         this.dbName = dbName;
+        this.tblName = table.getName();
         this.table = table;
     }
 
+    // for external table
+    public CreateTableInfo(String ctlName, String dbName, String tblName) {
+        this.ctlName = ctlName;
+        this.dbName = dbName;
+        this.tblName = tblName;
+    }
+
+    public String getCtlName() {
+        return ctlName;
+    }
+
     public String getDbName() {
         return dbName;
     }
 
+    public String getTblName() {
+        return tblName;
+    }
+
     public Table getTable() {
         return table;
     }
@@ -106,7 +130,11 @@ public class CreateTableInfo implements Writable, 
GsonPostProcessable {
 
     @Override
     public String toString() {
-        return toJson();
+        // In previous versions, ctlName and tblName is not set, so it may be 
null.
+        return String.format("%s.%s.%s",
+                Strings.isNullOrEmpty(ctlName) ? 
InternalCatalog.INTERNAL_CATALOG_NAME : ctlName,
+                dbName,
+                Strings.isNullOrEmpty(tblName) ? table.getName() : tblName);
     }
 
     @Override
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/DropDbInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/DropDbInfo.java
index 190db6a671a..f9d7339ca41 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/DropDbInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/DropDbInfo.java
@@ -30,6 +30,8 @@ import java.io.DataOutput;
 import java.io.IOException;
 
 public class DropDbInfo implements Writable, GsonPostProcessable {
+    @SerializedName(value = "ctl")
+    private String ctlName;
     @SerializedName(value = "dbName")
     private String dbName;
     @SerializedName(value = "forceDrop")
@@ -41,12 +43,23 @@ public class DropDbInfo implements Writable, 
GsonPostProcessable {
         this("", false, 0);
     }
 
+    // for external table
+    public DropDbInfo(String ctlName, String dbName) {
+        this.ctlName = ctlName;
+        this.dbName = dbName;
+    }
+
+    // for internal table
     public DropDbInfo(String dbName, boolean forceDrop, long recycleTime) {
         this.dbName = dbName;
         this.forceDrop = forceDrop;
         this.recycleTime = recycleTime;
     }
 
+    public String getCtlName() {
+        return ctlName;
+    }
+
     public String getDbName() {
         return dbName;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/DropInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/DropInfo.java
index db0688bd6ad..ff80f6ecb17 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/DropInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/DropInfo.java
@@ -21,8 +21,10 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.common.FeMetaVersion;
 import org.apache.doris.common.io.Text;
 import org.apache.doris.common.io.Writable;
+import org.apache.doris.datasource.InternalCatalog;
 import org.apache.doris.persist.gson.GsonUtils;
 
+import com.google.common.base.Strings;
 import com.google.gson.annotations.SerializedName;
 
 import java.io.DataInput;
@@ -30,6 +32,10 @@ import java.io.DataOutput;
 import java.io.IOException;
 
 public class DropInfo implements Writable {
+    @SerializedName(value = "ctl")
+    private String ctl;
+    @SerializedName(value = "db")
+    private String db;
     @SerializedName(value = "dbId")
     private long dbId;
     @SerializedName(value = "tableId")
@@ -50,13 +56,23 @@ public class DropInfo implements Writable {
     public DropInfo() {
     }
 
+    // for external table
+    public DropInfo(String ctl, String db, String tbl) {
+        this.ctl = ctl;
+        this.db = db;
+        this.tableName = tbl;
+    }
+
+    // for internal table
     public DropInfo(long dbId, long tableId, String tableName, boolean isView, 
boolean forceDrop,
             long recycleTime) {
         this(dbId, tableId, tableName, -1L, "", isView, forceDrop, 
recycleTime);
     }
 
+    // for internal table
     public DropInfo(long dbId, long tableId, String tableName, long indexId, 
String indexName, boolean isView,
             boolean forceDrop, long recycleTime) {
+        this.ctl = InternalCatalog.INTERNAL_CATALOG_NAME;
         this.dbId = dbId;
         this.tableId = tableId;
         this.tableName = tableName;
@@ -67,6 +83,14 @@ public class DropInfo implements Writable {
         this.recycleTime = recycleTime;
     }
 
+    public String getCtl() {
+        return ctl;
+    }
+
+    public String getDb() {
+        return db;
+    }
+
     public long getDbId() {
         return this.dbId;
     }
@@ -149,4 +173,13 @@ public class DropInfo implements Writable {
     public static DropInfo fromJson(String json) {
         return GsonUtils.GSON.fromJson(json, DropInfo.class);
     }
+
+    @Override
+    public String toString() {
+        // In previous versions, ctl and db are not set, so they may be null.
+        return String.format("%s.%s.%s",
+                Strings.isNullOrEmpty(ctl) ? 
InternalCatalog.INTERNAL_CATALOG_NAME : ctl,
+                Strings.isNullOrEmpty(db) ? dbId : db,
+                tableName);
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
index a06e2c4b693..d45c3f47917 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
@@ -51,9 +51,11 @@ import org.apache.doris.cooldown.CooldownConfHandler;
 import org.apache.doris.cooldown.CooldownConfList;
 import org.apache.doris.cooldown.CooldownDelete;
 import org.apache.doris.datasource.CatalogLog;
+import org.apache.doris.datasource.ExternalCatalog;
 import org.apache.doris.datasource.ExternalObjectLog;
 import org.apache.doris.datasource.InitCatalogLog;
 import org.apache.doris.datasource.InitDatabaseLog;
+import org.apache.doris.datasource.InternalCatalog;
 import org.apache.doris.datasource.MetaIdMappingsLog;
 import org.apache.doris.ha.MasterInfo;
 import org.apache.doris.insertoverwrite.InsertOverwriteLog;
@@ -100,6 +102,7 @@ import org.apache.doris.system.Frontend;
 import org.apache.doris.transaction.TransactionState;
 import org.apache.doris.transaction.TransactionStatus;
 
+import com.google.common.base.Strings;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -191,12 +194,18 @@ public class EditLog {
                 }
                 case OperationType.OP_CREATE_DB: {
                     Database db = (Database) journal.getData();
-                    env.replayCreateDb(db);
+                    CreateDbInfo info = new 
CreateDbInfo(db.getCatalog().getName(), db.getName(), db);
+                    env.replayCreateDb(info);
+                    break;
+                }
+                case OperationType.OP_NEW_CREATE_DB: {
+                    CreateDbInfo info = (CreateDbInfo) journal.getData();
+                    env.replayCreateDb(info);
                     break;
                 }
                 case OperationType.OP_DROP_DB: {
                     DropDbInfo dropDbInfo = (DropDbInfo) journal.getData();
-                    env.replayDropDb(dropDbInfo.getDbName(), 
dropDbInfo.isForceDrop(), dropDbInfo.getRecycleTime());
+                    env.replayDropDb(dropDbInfo);
                     break;
                 }
                 case OperationType.OP_ALTER_DB: {
@@ -225,28 +234,38 @@ public class EditLog {
                 }
                 case OperationType.OP_CREATE_TABLE: {
                     CreateTableInfo info = (CreateTableInfo) journal.getData();
-                    LOG.info("Begin to unprotect create table. db = " + 
info.getDbName() + " table = " + info.getTable()
-                            .getId());
-                    CreateTableRecord record = new CreateTableRecord(logId, 
info);
-                    env.replayCreateTable(info.getDbName(), info.getTable());
-                    env.getBinlogManager().addCreateTableRecord(record);
+                    LOG.info("Begin to unprotect create table. {}", info);
+                    env.replayCreateTable(info);
+                    if (Strings.isNullOrEmpty(info.getCtlName()) || 
info.getCtlName().equals(
+                            InternalCatalog.INTERNAL_CATALOG_NAME)) {
+                        CreateTableRecord record = new 
CreateTableRecord(logId, info);
+                        env.getBinlogManager().addCreateTableRecord(record);
+                    }
                     break;
                 }
                 case OperationType.OP_ALTER_EXTERNAL_TABLE_SCHEMA: {
                     RefreshExternalTableInfo info = (RefreshExternalTableInfo) 
journal.getData();
-                    LOG.info("Begin to unprotect alter external table schema. 
db = " + info.getDbName() + " table = "
-                            + info.getTableName());
+                    LOG.info("Begin to unprotect alter external table schema. 
db = {} table = {}", info.getDbName(),
+                            info.getTableName());
                     env.replayAlterExternalTableSchema(info.getDbName(), 
info.getTableName(), info.getNewSchema());
                     break;
                 }
                 case OperationType.OP_DROP_TABLE: {
                     DropInfo info = (DropInfo) journal.getData();
-                    Database db = 
Env.getCurrentInternalCatalog().getDbOrMetaException(info.getDbId());
-                    LOG.info("Begin to unprotect drop table. db = " + 
db.getFullName() + " table = "
-                            + info.getTableId());
-                    DropTableRecord record = new DropTableRecord(logId, info);
-                    env.replayDropTable(db, info.getTableId(), 
info.isForceDrop(), info.getRecycleTime());
-                    env.getBinlogManager().addDropTableRecord(record);
+                    LOG.info("Begin to unprotect drop table: {}", info);
+                    if (Strings.isNullOrEmpty(info.getCtl()) || 
info.getCtl().equals(
+                            InternalCatalog.INTERNAL_CATALOG_NAME)) {
+                        Database db = 
Env.getCurrentInternalCatalog().getDbOrMetaException(info.getDbId());
+                        env.replayDropTable(db, info.getTableId(), 
info.isForceDrop(), info.getRecycleTime());
+                        DropTableRecord record = new DropTableRecord(logId, 
info);
+                        env.getBinlogManager().addDropTableRecord(record);
+                    } else {
+                        ExternalCatalog ctl = (ExternalCatalog) 
Env.getCurrentEnv().getCatalogMgr()
+                                .getCatalog(info.getCtl());
+                        if (ctl != null) {
+                            ctl.replayDropTable(info.getDb(), 
info.getTableName());
+                        }
+                    }
                     break;
                 }
                 case OperationType.OP_ADD_PARTITION: {
@@ -1407,8 +1426,8 @@ public class EditLog {
         logEdit(OperationType.OP_SAVE_TRANSACTION_ID, new 
Text(Long.toString(transactionId)));
     }
 
-    public void logCreateDb(Database db) {
-        logEdit(OperationType.OP_CREATE_DB, db);
+    public void logCreateDb(CreateDbInfo info) {
+        logEdit(OperationType.OP_NEW_CREATE_DB, info);
     }
 
     public void logDropDb(DropDbInfo dropDbInfo) {
@@ -1429,8 +1448,11 @@ public class EditLog {
 
     public void logCreateTable(CreateTableInfo info) {
         long logId = logEdit(OperationType.OP_CREATE_TABLE, info);
-        CreateTableRecord record = new CreateTableRecord(logId, info);
-        Env.getCurrentEnv().getBinlogManager().addCreateTableRecord(record);
+        if (Strings.isNullOrEmpty(info.getCtlName()) || info.getCtlName()
+                .equals(InternalCatalog.INTERNAL_CATALOG_NAME)) {
+            CreateTableRecord record = new CreateTableRecord(logId, info);
+            
Env.getCurrentEnv().getBinlogManager().addCreateTableRecord(record);
+        }
     }
 
     public void logRefreshExternalTableSchema(RefreshExternalTableInfo info) {
@@ -1474,8 +1496,10 @@ public class EditLog {
 
     public void logDropTable(DropInfo info) {
         long logId = logEdit(OperationType.OP_DROP_TABLE, info);
-        DropTableRecord record = new DropTableRecord(logId, info);
-        Env.getCurrentEnv().getBinlogManager().addDropTableRecord(record);
+        if (Strings.isNullOrEmpty(info.getCtl()) || 
info.getCtl().equals(InternalCatalog.INTERNAL_CATALOG_NAME)) {
+            DropTableRecord record = new DropTableRecord(logId, info);
+            Env.getCurrentEnv().getBinlogManager().addDropTableRecord(record);
+        }
     }
 
     public void logEraseTable(long tableId) {
@@ -1713,7 +1737,9 @@ public class EditLog {
     public void logTruncateTable(TruncateTableInfo info) {
         long logId = logEdit(OperationType.OP_TRUNCATE_TABLE, info);
         LOG.info("log truncate table, logId:{}, infos: {}", logId, info);
-        Env.getCurrentEnv().getBinlogManager().addTruncateTable(info, logId);
+        if (Strings.isNullOrEmpty(info.getCtl()) || 
info.getCtl().equals(InternalCatalog.INTERNAL_CATALOG_NAME)) {
+            Env.getCurrentEnv().getBinlogManager().addTruncateTable(info, 
logId);
+        }
     }
 
     public void logColocateModifyRepliaAlloc(ColocatePersistInfo info) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
index 6c97606cb24..8636a3dbc5c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/OperationType.java
@@ -27,12 +27,14 @@ public class OperationType {
     // OP_LOCAL_EOF is only for local edit log, to indicate the end of a edit 
log run.
     public static final short OP_LOCAL_EOF = -1;
     public static final short OP_SAVE_NEXTID = 0;
-    public static final short OP_CREATE_DB = 1;
+    @Deprecated
+    public static final short OP_CREATE_DB = 1; // deprecated, use 
OP_NEW_CREATE_DB instead
     public static final short OP_DROP_DB = 2;
     public static final short OP_ALTER_DB = 3;
     public static final short OP_ERASE_DB = 4;
     public static final short OP_RECOVER_DB = 5;
     public static final short OP_RENAME_DB = 6;
+    public static final short OP_NEW_CREATE_DB = 7;
 
     // 10~19 110~119 210~219 ...
     public static final short OP_CREATE_TABLE = 10;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/persist/TruncateTableInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/TruncateTableInfo.java
index b252b2a3823..c9b000297db 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/TruncateTableInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/TruncateTableInfo.java
@@ -33,6 +33,8 @@ import java.util.List;
 import java.util.Map;
 
 public class TruncateTableInfo implements Writable {
+    @SerializedName(value = "ctl")
+    private String ctl;
     @SerializedName(value = "dbId")
     private long dbId;
     @SerializedName(value = "db")
@@ -43,6 +45,9 @@ public class TruncateTableInfo implements Writable {
     private String table;
     @SerializedName(value = "partitions")
     private List<Partition> partitions = Lists.newArrayList();
+    // Only for external table
+    @SerializedName(value = "extParts")
+    private List<String> extPartNames = Lists.newArrayList();
     @SerializedName(value = "isEntireTable")
     private boolean isEntireTable = false;
     @SerializedName(value = "rawSql")
@@ -54,6 +59,7 @@ public class TruncateTableInfo implements Writable {
 
     }
 
+    // for internal table
     public TruncateTableInfo(long dbId, String db, long tblId, String table, 
List<Partition> partitions,
             boolean isEntireTable, String rawSql, List<Partition> 
oldPartitions) {
         this.dbId = dbId;
@@ -68,6 +74,18 @@ public class TruncateTableInfo implements Writable {
         }
     }
 
+    // for external table
+    public TruncateTableInfo(String ctl, String db, String table, List<String> 
partNames) {
+        this.ctl = ctl;
+        this.db = db;
+        this.table = table;
+        this.extPartNames = partNames;
+    }
+
+    public String getCtl() {
+        return ctl;
+    }
+
     public long getDbId() {
         return dbId;
     }
@@ -88,6 +106,10 @@ public class TruncateTableInfo implements Writable {
         return partitions;
     }
 
+    public List<String> getExtPartNames() {
+        return extPartNames;
+    }
+
     public Map<Long, String> getOldPartitions() {
         return oldPartitions == null ? new HashMap<>() : oldPartitions;
     }
@@ -118,13 +140,15 @@ public class TruncateTableInfo implements Writable {
     @Override
     public String toString() {
         return "TruncateTableInfo{"
+                + "ctl=" + ctl
                 + "dbId=" + dbId
                 + ", db='" + db + '\''
                 + ", tblId=" + tblId
                 + ", table='" + table + '\''
                 + ", isEntireTable=" + isEntireTable
                 + ", rawSql='" + rawSql + '\''
-                + ", partitions_size=" + partitions.size()
+                + ", partitions_size=" + (partitions == null ? "0" : 
partitions.size())
+                + ", extPartNames_size=" + (extPartNames == null ? "0" : 
extPartNames.size())
                 + '}';
     }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/persist/CreateDbInfoTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/persist/CreateDbInfoTest.java
new file mode 100644
index 00000000000..881c61065be
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/persist/CreateDbInfoTest.java
@@ -0,0 +1,72 @@
+// 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.doris.persist;
+
+import org.apache.doris.catalog.Database;
+import org.apache.doris.common.FeMetaVersion;
+import org.apache.doris.datasource.InternalCatalog;
+import org.apache.doris.meta.MetaContext;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.nio.file.Files;
+
+public class CreateDbInfoTest {
+    @Test
+    public void testSerialization() throws Exception {
+        MetaContext metaContext = new MetaContext();
+        metaContext.setMetaVersion(FeMetaVersion.VERSION_CURRENT);
+        metaContext.setThreadLocalInfo();
+
+        // 1. Write objects to file
+        File file = new File("./createDbInfo");
+        file.createNewFile();
+        DataOutputStream dos = new 
DataOutputStream(Files.newOutputStream(file.toPath()));
+
+        Database db = new Database(10000, "db1");
+        CreateDbInfo info1 = new 
CreateDbInfo(InternalCatalog.INTERNAL_CATALOG_NAME, db.getName(), db);
+        info1.write(dos);
+
+        CreateDbInfo info2 = new CreateDbInfo("external_catalog", 
"external_db", null);
+        info2.write(dos);
+
+        dos.flush();
+        dos.close();
+
+        // 2. Read objects from file
+        DataInputStream dis = new 
DataInputStream(Files.newInputStream(file.toPath()));
+
+        CreateDbInfo rInfo1 = CreateDbInfo.read(dis);
+        Assert.assertEquals(info1.getCtlName(), rInfo1.getCtlName());
+        Assert.assertEquals(info1.getDbName(), rInfo1.getDbName());
+        Assert.assertEquals(info1.getInternalDb().getId(), 
rInfo1.getInternalDb().getId());
+
+        CreateDbInfo rInfo2 = CreateDbInfo.read(dis);
+        Assert.assertEquals(info2.getCtlName(), rInfo2.getCtlName());
+        Assert.assertEquals(info2.getDbName(), rInfo2.getDbName());
+        Assert.assertNull(rInfo2.getInternalDb());
+
+        // 3. delete files
+        dis.close();
+        file.delete();
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to