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

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new aa8b2f8  [Bug][Refactor] Fix the conflict of temp partition and 
dynamic partition operations (#3201)
aa8b2f8 is described below

commit aa8b2f86c419710d5d39902c06bfaa6f07fe508e
Author: Mingyu Chen <morningman....@gmail.com>
AuthorDate: Fri Mar 27 20:25:15 2020 +0800

    [Bug][Refactor] Fix the conflict of temp partition and dynamic partition 
operations (#3201)
    
    The bug is described in issue: #3200.
    
    This CL solve the problem by:
    1. Refactor the alter operation conflict checking logic by introducing new 
classes `AlterOperations` and `AlterOpType`.
    2. Allow add/drop temporary partition when dynamic partition feature is 
enabled.
    3. Allow modifying table's property when there is temporary partition in 
table.
    4. Make the properties `dynamic_partition.enable` optional, and default is 
true.
---
 .../cn/administrator-guide/dynamic-partition.md    |   2 +-
 .../sql-statements/Data Definition/CREATE TABLE.md |   9 +-
 fe/src/main/java/org/apache/doris/alter/Alter.java | 224 ++++-----------------
 .../java/org/apache/doris/alter/AlterOpType.java   |  62 ++++++
 .../org/apache/doris/alter/AlterOperations.java    | 103 ++++++++++
 .../apache/doris/alter/SchemaChangeHandler.java    |  63 +++++-
 .../org/apache/doris/analysis/AddColumnClause.java |   2 +
 .../apache/doris/analysis/AddColumnsClause.java    |   2 +
 .../apache/doris/analysis/AddPartitionClause.java  |   4 +-
 .../org/apache/doris/analysis/AddRollupClause.java |   9 +-
 .../org/apache/doris/analysis/AlterClause.java     |  12 ++
 .../apache/doris/analysis/AlterClusterClause.java  |   2 +
 .../doris/analysis/AlterLoadErrorUrlClause.java    |   2 +
 .../apache/doris/analysis/AlterTableClause.java    |   7 +
 .../org/apache/doris/analysis/AlterUserClause.java |  11 +-
 .../org/apache/doris/analysis/BackendClause.java   |   3 +
 .../apache/doris/analysis/ColumnRenameClause.java  |   2 +
 .../apache/doris/analysis/CreateIndexClause.java   |   3 +-
 .../apache/doris/analysis/DropColumnClause.java    |   2 +
 .../org/apache/doris/analysis/DropIndexClause.java |   3 +-
 .../apache/doris/analysis/DropPartitionClause.java |   2 +
 .../apache/doris/analysis/DropRollupClause.java    |   2 +
 .../org/apache/doris/analysis/FrontendClause.java  |   2 +
 .../java/org/apache/doris/analysis/IndexDef.java   |   8 +-
 .../apache/doris/analysis/ModifyBrokerClause.java  |   3 +
 .../apache/doris/analysis/ModifyColumnClause.java  |   2 +
 .../doris/analysis/ModifyPartitionClause.java      |   4 +-
 .../analysis/ModifyTablePropertiesClause.java      |   3 +
 .../doris/analysis/PartitionRenameClause.java      |   2 +
 .../doris/analysis/ReorderColumnsClause.java       |   2 +
 .../doris/analysis/ReplacePartitionClause.java     |   2 +
 .../apache/doris/analysis/RollupRenameClause.java  |   2 +
 .../apache/doris/analysis/TableRenameClause.java   |   2 +
 .../java/org/apache/doris/catalog/Catalog.java     |   2 +-
 .../doris/clone/DynamicPartitionScheduler.java     |   1 -
 .../java/org/apache/doris/common/ErrorCode.java    |   2 +-
 .../doris/common/util/DynamicPartitionUtil.java    |   7 +-
 .../java/org/apache/doris/alter/AlterTest.java     | 190 +++++++++++++++++
 .../doris/catalog/DynamicPartitionTableTest.java   |  60 +-----
 .../java/org/apache/doris/utframe/DemoTest.java    |   4 +-
 40 files changed, 552 insertions(+), 277 deletions(-)

diff --git a/docs/documentation/cn/administrator-guide/dynamic-partition.md 
b/docs/documentation/cn/administrator-guide/dynamic-partition.md
index 0ca38ed..bf5d4f4 100644
--- a/docs/documentation/cn/administrator-guide/dynamic-partition.md
+++ b/docs/documentation/cn/administrator-guide/dynamic-partition.md
@@ -42,7 +42,7 @@ under the License.
 
 ### 动态分区属性参数说明:
 
-`dynamic_partition.enable`: 是否开启动态分区特性,可指定为 `TRUE` 或 `FALSE`。
+`dynamic_partition.enable`: 是否开启动态分区特性,可指定为 `TRUE` 或 `FALSE`。如果不填写,默认为 `TRUE`。
 
 
 `dynamic_partition.time_unit`: 动态分区调度的单位,可指定为 `DAY` `WEEK` `MONTH`,当指定为 `DAY` 
时,动态创建的分区名后缀格式为`yyyyMMdd`,例如`20200325`。当指定为 `WEEK` 
时,动态创建的分区名后缀格式为`yyyy_ww`即当前日期属于这一年的第几周,例如 `2020-03-25` 创建的分区名后缀为 `2020_13`, 
表明目前为2020年第13周。当指定为 `MONTH` 时,动态创建的分区名后缀格式为 `yyyyMM`,例如 `202003`。
diff --git a/docs/documentation/cn/sql-reference/sql-statements/Data 
Definition/CREATE TABLE.md 
b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/CREATE 
TABLE.md
index c0d575d..80afc16 100644
--- a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/CREATE 
TABLE.md        
+++ b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/CREATE 
TABLE.md        
@@ -257,13 +257,15 @@ under the License.
       PROPERTIES (
           "dynamic_partition.enable" = "true|false",
           "dynamic_partition.time_unit" = "DAY|WEEK|MONTH",
+          "dynamic_partition.start" = "${integer_value}",
           "dynamic_partitoin.end" = "${integer_value}",
           "dynamic_partition.prefix" = "${string_value}",
           "dynamic_partition.buckets" = "${integer_value}
 ```
-    dynamic_partition.enable: 用于指定表级别的动态分区功能是否开启
+    dynamic_partition.enable: 用于指定表级别的动态分区功能是否开启。默认为 true。
     dynamic_partition.time_unit: 用于指定动态添加分区的时间单位,可选择为DAY(天),WEEK(周),MONTH(月)
-    dynamic_partition.end: 用于指定提前创建的分区数量
+    dynamic_partition.start: 用于指定向前删除多少个分区。值必须小于0。默认为 Integer.MIN_VALUE。
+    dynamic_partition.end: 用于指定提前创建的分区数量。值必须大于0。
     dynamic_partition.prefix: 用于指定创建的分区名前缀,例如分区名前缀为p,则自动创建分区名为p20200108
     dynamic_partition.buckets: 用于指定自动创建的分区分桶数量
 
@@ -524,7 +526,7 @@ under the License.
     PROPERTIES ("storage_type"="column");
 ```
 
-11. 
创建一个动态分区表(需要在FE配置中开启动态分区功能),该表每天提前创建3天的分区,例如今天为`2020-01-08`,则会创建分区名为`p20200108`,
 `p20200109`, `p20200110`, `p20200111`的分区. 分区范围分别为: 
+11. 
创建一个动态分区表(需要在FE配置中开启动态分区功能),该表每天提前创建3天的分区,并删除3天前的分区。例如今天为`2020-01-08`,则会创建分区名为`p20200108`,
 `p20200109`, `p20200110`, `p20200111`的分区. 分区范围分别为: 
 
 ```
 [types: [DATE]; keys: [2020-01-08]; ‥types: [DATE]; keys: [2020-01-09]; )
@@ -554,6 +556,7 @@ under the License.
     PROPERTIES(
     "storage_medium" = "SSD",
     "dynamic_partition.time_unit" = "DAY",
+    "dynamic_partition.start" = "-3",
     "dynamic_partition.end" = "3",
     "dynamic_partition.prefix" = "p",
     "dynamic_partition.buckets" = "32"
diff --git a/fe/src/main/java/org/apache/doris/alter/Alter.java 
b/fe/src/main/java/org/apache/doris/alter/Alter.java
index 4edbbe1..8028023 100644
--- a/fe/src/main/java/org/apache/doris/alter/Alter.java
+++ b/fe/src/main/java/org/apache/doris/alter/Alter.java
@@ -17,29 +17,18 @@
 
 package org.apache.doris.alter;
 
-import org.apache.doris.analysis.AddColumnClause;
-import org.apache.doris.analysis.AddColumnsClause;
 import org.apache.doris.analysis.AddPartitionClause;
-import org.apache.doris.analysis.AddRollupClause;
 import org.apache.doris.analysis.AlterClause;
 import org.apache.doris.analysis.AlterSystemStmt;
-import org.apache.doris.analysis.AlterTableClause;
 import org.apache.doris.analysis.AlterTableStmt;
 import org.apache.doris.analysis.AlterViewStmt;
 import org.apache.doris.analysis.ColumnRenameClause;
-import org.apache.doris.analysis.CreateIndexClause;
 import org.apache.doris.analysis.CreateMaterializedViewStmt;
-import org.apache.doris.analysis.DropColumnClause;
-import org.apache.doris.analysis.DropIndexClause;
 import org.apache.doris.analysis.DropMaterializedViewStmt;
 import org.apache.doris.analysis.DropPartitionClause;
-import org.apache.doris.analysis.DropRollupClause;
-import org.apache.doris.analysis.IndexDef;
-import org.apache.doris.analysis.ModifyColumnClause;
 import org.apache.doris.analysis.ModifyPartitionClause;
 import org.apache.doris.analysis.ModifyTablePropertiesClause;
 import org.apache.doris.analysis.PartitionRenameClause;
-import org.apache.doris.analysis.ReorderColumnsClause;
 import org.apache.doris.analysis.ReplacePartitionClause;
 import org.apache.doris.analysis.RollupRenameClause;
 import org.apache.doris.analysis.TableName;
@@ -47,7 +36,6 @@ import org.apache.doris.analysis.TableRenameClause;
 import org.apache.doris.catalog.Catalog;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Database;
-import org.apache.doris.catalog.Index;
 import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.OlapTable.OlapTableState;
 import org.apache.doris.catalog.Table;
@@ -72,8 +60,6 @@ import org.apache.logging.log4j.Logger;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
 
 public class Alter {
     private static final Logger LOG = LogManager.getLogger(Alter.class);
@@ -167,141 +153,19 @@ public class Alter {
             ErrorReport.reportDdlException(ErrorCode.ERR_BAD_DB_ERROR, dbName);
         }
 
-        // check cluster capacity
-        Catalog.getCurrentSystemInfo().checkClusterCapacity(clusterName);
-
-        // schema change ops can appear several in one alter stmt without 
other alter ops entry
-        boolean hasSchemaChange = false;
-        // materialized view ops (include rollup), if has, should appear one 
and only one add or drop mv entry
-        boolean hasAddMaterializedView = false;
-        boolean hasDropRollup = false;
-        // partition ops, if has, should appear one and only one entry
-        boolean hasPartition = false;
-        // rename ops, if has, should appear one and only one entry
-        boolean hasRename = false;
-        // modify properties ops, if has, should appear one and only one entry
-        boolean hasModifyProp = false;
-
         // check conflict alter ops first
         List<AlterClause> alterClauses = stmt.getOps();
-        // check conflict alter ops first
-
-        // if all alter clauses are DropPartitionClause or DropRollupClause, 
no need to check quota.
-        boolean allIsDropOps = true;
-        for (AlterClause alterClause : alterClauses) {
-            if (!(alterClause instanceof DropPartitionClause)
-                    && !(alterClause instanceof DropRollupClause)) {
-                allIsDropOps = false;
-                break;
-            }
-        }
+        AlterOperations currentAlterOps = new AlterOperations();
+        currentAlterOps.checkConflict(alterClauses);
 
-        if (!allIsDropOps) {
-            // check db quota
+        // check cluster capacity and db quota, only need to check once.
+        if (currentAlterOps.needCheckCapacity()) {
+            Catalog.getCurrentSystemInfo().checkClusterCapacity(clusterName);
             db.checkQuota();
         }
 
-        // synchronized operation must handle outside db write lock
-        boolean needSynchronized = false;
-        boolean needTableStable = false;
-        for (AlterClause alterClause : alterClauses) {
-            if (!needTableStable) {
-                needTableStable = ((AlterTableClause) 
alterClause).isNeedTableStable();
-            }
-            if ((alterClause instanceof AddColumnClause
-                    || alterClause instanceof AddColumnsClause
-                    || alterClause instanceof DropColumnClause
-                    || alterClause instanceof ModifyColumnClause
-                    || alterClause instanceof ReorderColumnsClause
-                    || alterClause instanceof CreateIndexClause
-                    || alterClause instanceof DropIndexClause)
-                    && !hasAddMaterializedView && !hasDropRollup && 
!hasPartition && !hasRename) {
-                hasSchemaChange = true;
-                if (alterClause instanceof CreateIndexClause) {
-                    Table table = db.getTable(dbTableName.getTbl());
-                    if (!(table instanceof OlapTable)) {
-                        throw new AnalysisException("create index only support 
in olap table at current version.");
-                    }
-                    List<Index> indexes = ((OlapTable) table).getIndexes();
-                    IndexDef indexDef = ((CreateIndexClause) 
alterClause).getIndexDef();
-                    Set<String> newColset = new 
TreeSet<>(String.CASE_INSENSITIVE_ORDER);
-                    newColset.addAll(indexDef.getColumns());
-                    for (Index idx : indexes) {
-                        if 
(idx.getIndexName().equalsIgnoreCase(indexDef.getIndexName())) {
-                            throw new AnalysisException("index `" + 
indexDef.getIndexName() + "` already exist.");
-                        }
-                        Set<String> idxSet = new 
TreeSet<>(String.CASE_INSENSITIVE_ORDER);
-                        idxSet.addAll(idx.getColumns());
-                        if (newColset.equals(idxSet)) {
-                            throw new AnalysisException("index for columns (" 
+ String
-                                    .join(",", indexDef.getColumns()) + " ) 
already exist.");
-                        }
-                    }
-                    OlapTable olapTable = (OlapTable) table;
-                    for (String col : indexDef.getColumns()) {
-                        Column column = olapTable.getColumn(col);
-                        if (column != null) {
-                            indexDef.checkColumn(column, 
olapTable.getKeysType());
-                        } else {
-                            throw new AnalysisException("BITMAP column does 
not exist in table. invalid column: "
-                                    + col);
-                        }
-                    }
-                } else if (alterClause instanceof DropIndexClause) {
-                    Table table = db.getTable(dbTableName.getTbl());
-                    if (!(table instanceof OlapTable)) {
-                        throw new AnalysisException("drop index only support 
in olap table at current version.");
-                    }
-                    String indexName = ((DropIndexClause) 
alterClause).getIndexName();
-                    List<Index> indexes = ((OlapTable) table).getIndexes();
-                    Index found = null;
-                    for (Index idx : indexes) {
-                        if (idx.getIndexName().equalsIgnoreCase(indexName)) {
-                            found = idx;
-                            break;
-                        }
-                    }
-                    if (found == null) {
-                            throw new AnalysisException("index " + indexName + 
" does not exist");
-                        }
-                }
-            } else if ((alterClause instanceof AddRollupClause)
-                    && !hasSchemaChange && !hasDropRollup
-                    && !hasPartition && !hasRename && !hasModifyProp) {
-                hasAddMaterializedView = true;
-            } else if (alterClause instanceof DropRollupClause && 
!hasSchemaChange && !hasAddMaterializedView
-                    && !hasPartition && !hasRename && !hasModifyProp) {
-                hasDropRollup = true;
-            } else if (alterClause instanceof AddPartitionClause && 
!hasSchemaChange && !hasAddMaterializedView
-                    && !hasDropRollup && !hasPartition && !hasRename && 
!hasModifyProp) {
-                hasPartition = true;
-            } else if (alterClause instanceof DropPartitionClause && 
!hasSchemaChange && !hasAddMaterializedView && !hasDropRollup
-                    && !hasPartition && !hasRename && !hasModifyProp) {
-                hasPartition = true;
-            } else if (alterClause instanceof ModifyPartitionClause && 
!hasSchemaChange && !hasAddMaterializedView
-                    && !hasDropRollup && !hasPartition && !hasRename && 
!hasModifyProp) {
-                hasPartition = true;
-            } else if ((alterClause instanceof TableRenameClause || 
alterClause instanceof RollupRenameClause
-                    || alterClause instanceof PartitionRenameClause || 
alterClause instanceof ColumnRenameClause)
-                    && !hasSchemaChange && !hasAddMaterializedView && 
!hasDropRollup && !hasPartition && !hasRename
-                    && !hasModifyProp) {
-                hasRename = true;
-            } else if (alterClause instanceof ReplacePartitionClause && 
!hasSchemaChange && !hasAddMaterializedView
-                    && !hasDropRollup && !hasPartition && !hasRename && 
!hasModifyProp) {
-                hasPartition = true;
-            } else if (alterClause instanceof ModifyTablePropertiesClause && 
!hasSchemaChange && !hasAddMaterializedView
-                    && !hasDropRollup && !hasPartition && !hasRename && 
!hasModifyProp) {
-                Map<String, String> properties = alterClause.getProperties();
-                if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY)) {
-                    needSynchronized = true;
-                } else  {
-                    hasModifyProp = true;
-                }
-            } else {
-                throw new DdlException("Conflicting alter clauses. see help 
for more information");
-            }
-        } // end for alter clauses
-
+        // some operations will take long time to process, need to be done 
outside the databse lock
+        boolean needProcessOutsideDatabaseLock = false;
         String tableName = dbTableName.getTbl();
         db.writeLock();
         try {
@@ -313,44 +177,29 @@ public class Alter {
             if (table.getType() != TableType.OLAP) {
                 throw new DdlException("Do not support alter non-OLAP table[" 
+ tableName + "]");
             }
-
             OlapTable olapTable = (OlapTable) table;
 
-            if (olapTable.getPartitions().size() == 0 && !hasPartition) {
-                throw new DdlException("table with empty parition cannot do 
schema change. [" + tableName + "]");
+            if (olapTable.getPartitions().size() == 0 && 
!currentAlterOps.hasPartitionOp()) {
+                throw new DdlException("Table with empty parition cannot do 
schema change. [" + tableName + "]");
             }
 
             if (olapTable.getState() != OlapTableState.NORMAL) {
-                throw new DdlException("Table[" + table.getName() + "]'s state 
is not NORMAL. Do not allow doing ALTER ops");
+                throw new DdlException(
+                        "Table[" + table.getName() + "]'s state is not NORMAL. 
Do not allow doing ALTER ops");
             }
 
-            // schema change job will wait until table become stable
-            if (needTableStable && !hasSchemaChange && 
!hasAddMaterializedView) {
-                // check if all tablets are healthy, and no tablet is in 
tablet scheduler
-                boolean isStable = 
olapTable.isStable(Catalog.getCurrentSystemInfo(),
-                        Catalog.getCurrentCatalog().getTabletScheduler(),
-                        db.getClusterName());
-                if (!isStable) {
-                    throw new DdlException("table [" + olapTable.getName() + 
"] is not stable."
-                            + " Some tablets of this table may not be healthy 
or are being scheduled."
-                            + " You need to repair the table first"
-                            + " or stop cluster balance. See 'help admin;'.");
-                }
-            }
-
-            if (hasSchemaChange || hasModifyProp) {
+            if (currentAlterOps.hasSchemaChangeOp()) {
                 // if modify storage type to v2, do schema change to convert 
all related tablets to segment v2 format
                 schemaChangeHandler.process(alterClauses, clusterName, db, 
olapTable);
-            } else if (hasAddMaterializedView || hasDropRollup) {
+            } else if (currentAlterOps.hasRollupOp()) {
                 materializedViewHandler.process(alterClauses, clusterName, db, 
olapTable);
-            } else if (hasPartition) {
+            } else if (currentAlterOps.hasPartitionOp()) {
                 Preconditions.checkState(alterClauses.size() == 1);
-                // when this is a dynamic partition table, do not allow doing 
partition operation.
-                // TODO(cmy): although some of operation can be done with 
dynamic partition,
-                // but currently we check it strictly to avoid some unexpected 
exception.
-                DynamicPartitionUtil.checkAlterAllowed(olapTable);
                 AlterClause alterClause = alterClauses.get(0);
                 if (alterClause instanceof DropPartitionClause) {
+                    if (!((DropPartitionClause) 
alterClause).isTempPartition()) {
+                        DynamicPartitionUtil.checkAlterAllowed((OlapTable) 
db.getTable(tableName));
+                    }
                     Catalog.getInstance().dropPartition(db, olapTable, 
((DropPartitionClause) alterClause));
                 } else if (alterClause instanceof ReplacePartitionClause) {
                     Catalog.getCurrentCatalog().replaceTempPartition(db, 
tableName, (ReplacePartitionClause) alterClause);
@@ -358,45 +207,50 @@ public class Alter {
                     ModifyPartitionClause clause = ((ModifyPartitionClause) 
alterClause);
                     Map<String, String> properties = clause.getProperties();
                     if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY)) {
-                        needSynchronized = true;
+                        needProcessOutsideDatabaseLock = true;
                     } else {
                         String partitionName = clause.getPartitionName();
-                        Catalog.getInstance().modifyPartition(db, olapTable, 
partitionName, properties);
+                        Catalog.getInstance().modifyPartitionProperty(db, 
olapTable, partitionName, properties);
                     }
+                } else if (alterClause instanceof AddPartitionClause) {
+                    needProcessOutsideDatabaseLock = true;
                 } else {
-                    // add (temp) partition
-                    needSynchronized = true;
+                    throw new DdlException("Invalid alter opertion: " + 
alterClause.getOpType());
                 }
-            } else if (hasRename) {
+            } else if (currentAlterOps.hasRenameOp()) {
                 processRename(db, olapTable, alterClauses);
+            } else if 
(currentAlterOps.contains(AlterOpType.MODIFY_TABLE_PROPERTY_SYNC)) {
+                needProcessOutsideDatabaseLock = true;
+            } else {
+                throw new DdlException("Invalid alter operations: " + 
currentAlterOps);
             }
         } finally {
             db.writeUnlock();
         }
 
         // the following ops should done outside db lock. because it contain 
synchronized create operation
-        if (needSynchronized) {
+        if (needProcessOutsideDatabaseLock) {
             Preconditions.checkState(alterClauses.size() == 1);
             AlterClause alterClause = alterClauses.get(0);
             if (alterClause instanceof AddPartitionClause) {
-                DynamicPartitionUtil.checkAlterAllowed((OlapTable) 
db.getTable(tableName));
-                Catalog.getInstance().addPartition(db, tableName, 
(AddPartitionClause) alterClause);
+                if (!((AddPartitionClause) alterClause).isTempPartition()) {
+                    DynamicPartitionUtil.checkAlterAllowed((OlapTable) 
db.getTable(tableName));
+                }
+                Catalog.getCurrentCatalog().addPartition(db, tableName, 
(AddPartitionClause) alterClause);
             } else if (alterClause instanceof ModifyPartitionClause) {
                 ModifyPartitionClause clause = ((ModifyPartitionClause) 
alterClause);
                 Map<String, String> properties = clause.getProperties();
                 String partitionName = clause.getPartitionName();
                 // currently, only in memory property could reach here
                 
Preconditions.checkState(properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY));
-                if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY)) {
-                    boolean isInMemory = 
Boolean.parseBoolean(properties.get(PropertyAnalyzer.PROPERTIES_INMEMORY));
-                    
((SchemaChangeHandler)schemaChangeHandler).updatePartitionInMemoryMeta(
-                            db, tableName, partitionName, isInMemory);
-                }
+                boolean isInMemory = 
Boolean.parseBoolean(properties.get(PropertyAnalyzer.PROPERTIES_INMEMORY));
+                ((SchemaChangeHandler) 
schemaChangeHandler).updatePartitionInMemoryMeta(
+                        db, tableName, partitionName, isInMemory);
 
                 db.writeLock();
                 try {
-                    OlapTable olapTable = (OlapTable)db.getTable(tableName);
-                    Catalog.getInstance().modifyPartition(db, olapTable, 
partitionName, properties);
+                    OlapTable olapTable = (OlapTable) db.getTable(tableName);
+                    Catalog.getCurrentCatalog().modifyPartitionProperty(db, 
olapTable, partitionName, properties);
                 } finally {
                     db.writeUnlock();
                 }
@@ -404,9 +258,9 @@ public class Alter {
                 Map<String, String> properties = alterClause.getProperties();
                 // currently, only in memory property could reach here
                 
Preconditions.checkState(properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY));
-                
((SchemaChangeHandler)schemaChangeHandler).updateTableInMemoryMeta(db, 
tableName, properties);
+                ((SchemaChangeHandler) 
schemaChangeHandler).updateTableInMemoryMeta(db, tableName, properties);
             } else {
-                Preconditions.checkState(false);
+                throw new DdlException("Invalid alter opertion: " + 
alterClause.getOpType());
             }
         }
     }
diff --git a/fe/src/main/java/org/apache/doris/alter/AlterOpType.java 
b/fe/src/main/java/org/apache/doris/alter/AlterOpType.java
new file mode 100644
index 0000000..6cf112e
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/alter/AlterOpType.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.doris.alter;
+
+public enum AlterOpType {
+    // rollup
+    ADD_ROLLUP,
+    DROP_ROLLUP,
+    // schema change
+    SCHEMA_CHANGE,
+    // partition
+    ADD_PARTITION,
+    DROP_PARTITION,
+    REPLACE_PARTITION,
+    MODIFY_PARTITION,
+    // rename
+    RENAME,
+    // table property
+    MODIFY_TABLE_PROPERTY,
+    MODIFY_TABLE_PROPERTY_SYNC, // Some operations are performed 
synchronously, so we distinguish them by suffix _SYNC
+    // others operation, such as add/drop backend. currently we do not care 
about them
+    ALTER_OTHER,
+
+    INVALID_OP;
+
+    // true means 2 operations have no conflict.
+    public static Boolean[][] COMPATIBITLITY_MATRIX;
+    static {
+        COMPATIBITLITY_MATRIX = new Boolean[INVALID_OP.ordinal() + 
1][INVALID_OP.ordinal() + 1];
+        for (int i = 0; i < INVALID_OP.ordinal(); i++) {
+            for (int j = 0; j < INVALID_OP.ordinal(); j++) {
+                COMPATIBITLITY_MATRIX[i][j] = false;
+            }
+        }
+
+        // rollup can be added or dropped in batch
+        COMPATIBITLITY_MATRIX[ADD_ROLLUP.ordinal()][ADD_ROLLUP.ordinal()] = 
true;
+        COMPATIBITLITY_MATRIX[DROP_ROLLUP.ordinal()][DROP_ROLLUP.ordinal()] = 
true;
+        // schema change, such as add/modify/drop columns can be processed in 
batch
+        
COMPATIBITLITY_MATRIX[SCHEMA_CHANGE.ordinal()][SCHEMA_CHANGE.ordinal()] = true;
+    }
+
+    public boolean needCheckCapacity() {
+        return this == ADD_ROLLUP || this == SCHEMA_CHANGE || this == 
ADD_PARTITION;
+    }
+
+}
diff --git a/fe/src/main/java/org/apache/doris/alter/AlterOperations.java 
b/fe/src/main/java/org/apache/doris/alter/AlterOperations.java
new file mode 100644
index 0000000..ff3af4a
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/alter/AlterOperations.java
@@ -0,0 +1,103 @@
+// 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.alter;
+
+import org.apache.doris.analysis.AlterClause;
+import org.apache.doris.common.DdlException;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Sets;
+
+import java.util.List;
+import java.util.Set;
+
+/*
+ * AlterOperations contains a set alter operations generated from a 
AlterStmt's alter clause.
+ * This class is mainly used to integrate these operation types and check 
whether they have conflicts.
+ */
+public class AlterOperations {
+    private Set<AlterOpType> currentOps = Sets.newHashSet();
+    
+    public AlterOperations() {
+    }
+
+    public Set<AlterOpType> getCurrentOps() {
+        return currentOps;
+    }
+
+    // check the conflicts of the given list of alter clauses
+    public void checkConflict(List<AlterClause> alterClauses) throws 
DdlException {
+        for (AlterClause alterClause : alterClauses) {
+            checkOp(alterClause.getOpType());
+        }
+    }
+
+    // some operations take up disk space. so we need to check the disk 
capacity before processing.
+    // return true if we see these kind of opertions.
+    public boolean needCheckCapacity() {
+        for (AlterOpType currentOp : currentOps) {
+            if (currentOp.needCheckCapacity()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasPartitionOp() {
+        return currentOps.contains(AlterOpType.ADD_PARTITION) || 
currentOps.contains(AlterOpType.DROP_PARTITION)
+                || currentOps.contains(AlterOpType.REPLACE_PARTITION) || 
currentOps.contains(AlterOpType.MODIFY_PARTITION);
+    }
+
+    // MODIFY_TABLE_PROPERTY is also processed by SchemaChangeHandler
+    public boolean hasSchemaChangeOp() {
+        return currentOps.contains(AlterOpType.SCHEMA_CHANGE) || 
currentOps.contains(AlterOpType.MODIFY_TABLE_PROPERTY);
+    }
+
+    public boolean hasRollupOp() {
+        return currentOps.contains(AlterOpType.ADD_ROLLUP) || 
currentOps.contains(AlterOpType.DROP_ROLLUP);
+    }
+
+    public boolean hasRenameOp() {
+        return currentOps.contains(AlterOpType.RENAME);
+    }
+
+    public boolean contains(AlterOpType op) {
+        return currentOps.contains(op);
+    }
+
+    // throw exception if the given operation has conflict with current 
operations.,
+    private void checkOp(AlterOpType opType) throws DdlException {
+        if (currentOps.isEmpty()) {
+            currentOps.add(opType);
+            return;
+        }
+
+        for (AlterOpType currentOp : currentOps) {
+            if 
(!AlterOpType.COMPATIBITLITY_MATRIX[currentOp.ordinal()][opType.ordinal()]) {
+                throw new DdlException("Alter operation " + opType + " 
conflicts with operation " + currentOp);
+            }
+        }
+
+        currentOps.add(opType);
+    }
+
+    @Override
+    public String toString() {
+        return Joiner.on(", ").join(currentOps);
+    }
+}
diff --git a/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java 
b/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java
index ea3c67d..4279f71 100644
--- a/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java
+++ b/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java
@@ -27,6 +27,7 @@ import org.apache.doris.analysis.ColumnPosition;
 import org.apache.doris.analysis.CreateIndexClause;
 import org.apache.doris.analysis.DropColumnClause;
 import org.apache.doris.analysis.DropIndexClause;
+import org.apache.doris.analysis.IndexDef;
 import org.apache.doris.analysis.ModifyColumnClause;
 import org.apache.doris.analysis.ModifyTablePropertiesClause;
 import org.apache.doris.analysis.ReorderColumnsClause;
@@ -1324,10 +1325,6 @@ public class SchemaChangeHandler extends AlterHandler {
     public void process(List<AlterClause> alterClauses, String clusterName, 
Database db, OlapTable olapTable)
             throws UserException {
 
-        if (olapTable.existTempPartitions()) {
-            throw new DdlException("Can not alter table when there are temp 
partitions in table");
-        }
-
         // index id -> index schema
         Map<Long, LinkedList<Column>> indexSchemaMap = new HashMap<>();
         for (Map.Entry<Long, List<Column>> entry : 
olapTable.getIndexIdToSchema().entrySet()) {
@@ -1369,6 +1366,11 @@ public class SchemaChangeHandler extends AlterHandler {
                 }
             }
 
+            // the following operations can not be done when there are temp 
partitions exist.
+            if (olapTable.existTempPartitions()) {
+                throw new DdlException("Can not alter table when there are 
temp partitions in table");
+            }
+
             if (alterClause instanceof AddColumnClause) {
                 // add column
                 processAddColumn((AddColumnClause) alterClause, olapTable, 
indexSchemaMap);
@@ -1388,9 +1390,9 @@ public class SchemaChangeHandler extends AlterHandler {
                 // modify table properties
                 // do nothing, properties are already in propertyMap
             } else if (alterClause instanceof CreateIndexClause) {
-                processAddIndex((CreateIndexClause) alterClause, newIndexes);
+                processAddIndex((CreateIndexClause) alterClause, olapTable, 
newIndexes);
             } else if (alterClause instanceof DropIndexClause) {
-                processDropIndex((DropIndexClause) alterClause, newIndexes);
+                processDropIndex((DropIndexClause) alterClause, olapTable, 
newIndexes);
             } else {
                 Preconditions.checkState(false);
             }
@@ -1590,13 +1592,54 @@ public class SchemaChangeHandler extends AlterHandler {
         }
     }
 
-    private void processAddIndex(CreateIndexClause alterClause, List<Index> 
indexes) {
-        if (alterClause.getIndex() != null) {
-            indexes.add(alterClause.getIndex());
+    private void processAddIndex(CreateIndexClause alterClause, OlapTable 
olapTable, List<Index> newIndexes)
+            throws UserException {
+        if (alterClause.getIndex() == null) {
+            return;
+        }
+
+        List<Index> existedIndexes = olapTable.getIndexes();
+        IndexDef indexDef = alterClause.getIndexDef();
+        Set<String> newColset = Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER);
+        newColset.addAll(indexDef.getColumns());
+        for (Index existedIdx : existedIndexes) {
+            if 
(existedIdx.getIndexName().equalsIgnoreCase(indexDef.getIndexName())) {
+                throw new DdlException("index `" + indexDef.getIndexName() + 
"` already exist.");
+            }
+            Set<String> existedIdxColSet = 
Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER);
+            existedIdxColSet.addAll(existedIdx.getColumns());
+            if (newColset.equals(existedIdxColSet)) {
+                throw new DdlException(
+                        "index for columns (" + String.join(",", 
indexDef.getColumns()) + " ) already exist.");
+            }
+        }
+
+        for (String col : indexDef.getColumns()) {
+            Column column = olapTable.getColumn(col);
+            if (column != null) {
+                indexDef.checkColumn(column, olapTable.getKeysType());
+            } else {
+                throw new DdlException("BITMAP column does not exist in table. 
invalid column: " + col);
+            }
         }
+
+        newIndexes.add(alterClause.getIndex());
     }
 
-    private void processDropIndex(DropIndexClause alterClause, List<Index> 
indexes) {
+    private void processDropIndex(DropIndexClause alterClause, OlapTable 
olapTable, List<Index> indexes) throws DdlException {
+        String indexName = alterClause.getIndexName();
+        List<Index> existedIndexes = olapTable.getIndexes();
+        Index found = null;
+        for (Index existedIdx : existedIndexes) {
+            if (existedIdx.getIndexName().equalsIgnoreCase(indexName)) {
+                found = existedIdx;
+                break;
+            }
+        }
+        if (found == null) {
+            throw new DdlException("index " + indexName + " does not exist");
+        }
+
         Iterator<Index> itr = indexes.iterator();
         while (itr.hasNext()) {
             Index idx  = itr.next();
diff --git a/fe/src/main/java/org/apache/doris/analysis/AddColumnClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AddColumnClause.java
index 16f162f..918baaa 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AddColumnClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AddColumnClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
@@ -54,6 +55,7 @@ public class AddColumnClause extends AlterTableClause {
 
     public AddColumnClause(ColumnDef columnDef, ColumnPosition colPos, String 
rollupName,
                            Map<String, String> properties) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.columnDef = columnDef;
         this.colPos = colPos;
         this.rollupName = rollupName;
diff --git a/fe/src/main/java/org/apache/doris/analysis/AddColumnsClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AddColumnsClause.java
index 4418ee8..c3c52a4 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AddColumnsClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AddColumnsClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
@@ -46,6 +47,7 @@ public class AddColumnsClause extends AlterTableClause {
     }
 
     public AddColumnsClause(List<ColumnDef> columnDefs, String rollupName, 
Map<String, String> properties) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.columnDefs = columnDefs;
         this.rollupName = rollupName;
         this.properties = properties;
diff --git a/fe/src/main/java/org/apache/doris/analysis/AddPartitionClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AddPartitionClause.java
index 62b3da0..23f8a23 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AddPartitionClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AddPartitionClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 
 import java.util.Map;
@@ -46,11 +47,12 @@ public class AddPartitionClause extends AlterTableClause {
                               DistributionDesc distributionDesc,
                               Map<String, String> properties,
                               boolean isTempPartition) {
+        super(AlterOpType.ADD_PARTITION);
         this.partitionDesc = partitionDesc;
         this.distributionDesc = distributionDesc;
         this.properties = properties;
         this.isTempPartition = isTempPartition;
-        
+
         this.needTableStable = false;
     }
 
diff --git a/fe/src/main/java/org/apache/doris/analysis/AddRollupClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AddRollupClause.java
index 809d29a..36d5bcd 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AddRollupClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AddRollupClause.java
@@ -17,14 +17,13 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.FeNameFormat;
 
 import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 import java.util.List;
@@ -43,11 +42,6 @@ public class AddRollupClause extends AlterTableClause {
 
     private Map<String, String> properties;
 
-    public AddRollupClause() {
-        columnNames = Lists.newArrayList();
-        properties = Maps.newHashMap();
-    }
-
     public String getRollupName() {
         return rollupName;
     }
@@ -67,6 +61,7 @@ public class AddRollupClause extends AlterTableClause {
     public AddRollupClause(String rollupName, List<String> columnNames,
                            List<String> dupKeys, String baseRollupName,
                            Map<String, String> properties) {
+        super(AlterOpType.ADD_ROLLUP);
         this.rollupName = rollupName;
         this.columnNames = columnNames;
         this.dupKeys = dupKeys;
diff --git a/fe/src/main/java/org/apache/doris/analysis/AlterClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AlterClause.java
index 0c859a7..3213a6a 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterClause.java
@@ -17,6 +17,8 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
+
 import org.apache.commons.lang.NotImplementedException;
 
 import java.util.Map;
@@ -24,7 +26,17 @@ import java.util.Map;
 // Alter clause.
 public abstract class AlterClause implements ParseNode {
 
+    protected AlterOpType opType;
+
+    public AlterClause(AlterOpType opType) {
+        this.opType = opType;
+    }
+
     public Map<String, String> getProperties() {
         throw new NotImplementedException();
     }
+
+    public AlterOpType getOpType() {
+        return opType;
+    }
 }
diff --git a/fe/src/main/java/org/apache/doris/analysis/AlterClusterClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AlterClusterClause.java
index 5e92d4f..2984a52 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterClusterClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterClusterClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.ErrorCode;
@@ -34,6 +35,7 @@ public class AlterClusterClause extends AlterClause {
     private String password;
 
     public AlterClusterClause(AlterClusterType type, Map<String, String> 
properties) {
+        super(AlterOpType.ALTER_OTHER);
         this.type = type;
         this.properties = properties;
         instanceNum = 0;
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/AlterLoadErrorUrlClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AlterLoadErrorUrlClause.java
index 633ed85..376c4cf 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterLoadErrorUrlClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterLoadErrorUrlClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.util.PrintableMap;
 import org.apache.doris.load.LoadErrorHub;
@@ -38,6 +39,7 @@ public class AlterLoadErrorUrlClause extends AlterClause {
     private LoadErrorHub.Param param;
 
     public AlterLoadErrorUrlClause(Map<String, String> properties) {
+        super(AlterOpType.ALTER_OTHER);
         this.properties = properties;
     }
 
diff --git a/fe/src/main/java/org/apache/doris/analysis/AlterTableClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AlterTableClause.java
index a35291a..7a223be 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterTableClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterTableClause.java
@@ -17,8 +17,15 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
+
 // alter table clause
 public abstract class AlterTableClause extends AlterClause {
+
+    public AlterTableClause(AlterOpType opType) {
+        super(opType);
+    }
+
     // if set to true, the corresponding table should be stable before 
processing this operation on it.
     protected boolean needTableStable = true;
 
diff --git a/fe/src/main/java/org/apache/doris/analysis/AlterUserClause.java 
b/fe/src/main/java/org/apache/doris/analysis/AlterUserClause.java
index debfbf4..07a2e95 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterUserClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterUserClause.java
@@ -17,11 +17,9 @@
 
 package org.apache.doris.analysis;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
+
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -30,6 +28,10 @@ import org.apache.commons.lang.NotImplementedException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 public class AlterUserClause extends AlterClause {
     private static final Logger LOG = 
LogManager.getLogger(AlterUserClause.class);
     private List<String> hostOrIps;
@@ -40,6 +42,7 @@ public class AlterUserClause extends AlterClause {
     private AlterUserType type;
     
     public AlterUserClause(AlterUserType type, List<String> hostOrIps) {
+        super(AlterOpType.ALTER_OTHER);
         this.type = type;
         this.hostOrIps = hostOrIps;
         this.ips = Lists.newArrayList();
diff --git a/fe/src/main/java/org/apache/doris/analysis/BackendClause.java 
b/fe/src/main/java/org/apache/doris/analysis/BackendClause.java
index 31f3ce0..c09ef49 100644
--- a/fe/src/main/java/org/apache/doris/analysis/BackendClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/BackendClause.java
@@ -17,9 +17,11 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Pair;
 import org.apache.doris.system.SystemInfoService;
+
 import com.google.common.base.Preconditions;
 
 import org.apache.commons.lang.NotImplementedException;
@@ -34,6 +36,7 @@ public class BackendClause extends AlterClause {
     protected List<Pair<String, Integer>> hostPortPairs;
 
     protected BackendClause(List<String> hostPorts) {
+        super(AlterOpType.ALTER_OTHER);
         this.hostPorts = hostPorts;
         this.hostPortPairs = new LinkedList<Pair<String, Integer>>();
     }
diff --git a/fe/src/main/java/org/apache/doris/analysis/ColumnRenameClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ColumnRenameClause.java
index c6a67b7..e3d9d69 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ColumnRenameClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ColumnRenameClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.FeNameFormat;
 
@@ -30,6 +31,7 @@ public class ColumnRenameClause extends AlterTableClause {
     private String newColName;
 
     public ColumnRenameClause(String colName, String newColName) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.colName = colName;
         this.newColName = newColName;
         this.needTableStable = false;
diff --git a/fe/src/main/java/org/apache/doris/analysis/CreateIndexClause.java 
b/fe/src/main/java/org/apache/doris/analysis/CreateIndexClause.java
index 97187f4..d1ff400 100644
--- a/fe/src/main/java/org/apache/doris/analysis/CreateIndexClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/CreateIndexClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.catalog.Index;
 import org.apache.doris.common.AnalysisException;
 
@@ -36,10 +37,10 @@ public class CreateIndexClause extends AlterTableClause {
     private Index index;
 
     public CreateIndexClause(TableName tableName, IndexDef indexDef, boolean 
alter) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.tableName = tableName;
         this.indexDef = indexDef;
         this.alter = alter;
-        this.needTableStable = true;
     }
 
     @Override
diff --git a/fe/src/main/java/org/apache/doris/analysis/DropColumnClause.java 
b/fe/src/main/java/org/apache/doris/analysis/DropColumnClause.java
index 14f7061..911a7f5 100644
--- a/fe/src/main/java/org/apache/doris/analysis/DropColumnClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/DropColumnClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
@@ -41,6 +42,7 @@ public class DropColumnClause extends AlterTableClause {
     }
 
     public DropColumnClause(String colName, String rollupName, Map<String, 
String> properties) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.colName = colName;
         this.rollupName = rollupName;
         this.properties = properties;
diff --git a/fe/src/main/java/org/apache/doris/analysis/DropIndexClause.java 
b/fe/src/main/java/org/apache/doris/analysis/DropIndexClause.java
index 40d5665..f5f4a20 100644
--- a/fe/src/main/java/org/apache/doris/analysis/DropIndexClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/DropIndexClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.UserException;
 
@@ -30,10 +31,10 @@ public class DropIndexClause extends AlterTableClause {
     private boolean alter;
 
     public DropIndexClause(String indexName, TableName tableName, boolean 
alter) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.indexName = indexName;
         this.tableName = tableName;
         this.alter = alter;
-        this.needTableStable = true;
     }
 
     public String getIndexName() {
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/DropPartitionClause.java 
b/fe/src/main/java/org/apache/doris/analysis/DropPartitionClause.java
index 90ca887..543bcea 100644
--- a/fe/src/main/java/org/apache/doris/analysis/DropPartitionClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/DropPartitionClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
@@ -33,6 +34,7 @@ public class DropPartitionClause extends AlterTableClause {
     private boolean isTempPartition;
 
     public DropPartitionClause(boolean ifExists, String partitionName, boolean 
isTempPartition) {
+        super(AlterOpType.DROP_PARTITION);
         this.ifExists = ifExists;
         this.partitionName = partitionName;
         this.isTempPartition = isTempPartition;
diff --git a/fe/src/main/java/org/apache/doris/analysis/DropRollupClause.java 
b/fe/src/main/java/org/apache/doris/analysis/DropRollupClause.java
index f8f24e2..5929136 100644
--- a/fe/src/main/java/org/apache/doris/analysis/DropRollupClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/DropRollupClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 
 import com.google.common.base.Strings;
@@ -29,6 +30,7 @@ public class DropRollupClause extends AlterTableClause {
     private Map<String, String> properties;
 
     public DropRollupClause(String rollupName, Map<String, String> properties) 
{
+        super(AlterOpType.DROP_ROLLUP);
         this.rollupName = rollupName;
         this.properties = properties;
         this.needTableStable = false;
diff --git a/fe/src/main/java/org/apache/doris/analysis/FrontendClause.java 
b/fe/src/main/java/org/apache/doris/analysis/FrontendClause.java
index ab631e1..4bfcfef 100644
--- a/fe/src/main/java/org/apache/doris/analysis/FrontendClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/FrontendClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.catalog.Catalog;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
@@ -41,6 +42,7 @@ public class FrontendClause extends AlterClause {
     protected FrontendNodeType role;
 
     protected FrontendClause(String hostPort, FrontendNodeType role) {
+        super(AlterOpType.ALTER_OTHER);
         this.hostPort = hostPort;
         this.role = role;
     }
diff --git a/fe/src/main/java/org/apache/doris/analysis/IndexDef.java 
b/fe/src/main/java/org/apache/doris/analysis/IndexDef.java
index 683cfd6..19a63a9 100644
--- a/fe/src/main/java/org/apache/doris/analysis/IndexDef.java
+++ b/fe/src/main/java/org/apache/doris/analysis/IndexDef.java
@@ -17,9 +17,6 @@
 
 package org.apache.doris.analysis;
 
-import java.util.List;
-import java.util.TreeSet;
-
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.KeysType;
 import org.apache.doris.catalog.PrimitiveType;
@@ -27,6 +24,9 @@ import org.apache.doris.common.AnalysisException;
 
 import com.google.common.base.Strings;
 
+import java.util.List;
+import java.util.TreeSet;
+
 public class IndexDef {
     private String indexName;
     private List<String> columns;
@@ -136,6 +136,8 @@ public class IndexDef {
                         "BITMAP index only used in columns of DUP_KEYS table 
or key columns of"
                                 + " UNIQUE_KEYS/AGG_KEYS table. invalid 
column: " + indexColName);
             }
+        } else {
+            throw new AnalysisException("Unsupported index type: " + 
indexType);
         }
     }
 
diff --git a/fe/src/main/java/org/apache/doris/analysis/ModifyBrokerClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ModifyBrokerClause.java
index 7e00586..c073d5f 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ModifyBrokerClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ModifyBrokerClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Pair;
 import org.apache.doris.system.SystemInfoService;
@@ -24,6 +25,7 @@ import org.apache.doris.system.SystemInfoService;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
+
 import org.apache.commons.lang.NotImplementedException;
 
 import java.util.List;
@@ -44,6 +46,7 @@ public class ModifyBrokerClause extends AlterClause {
     protected Set<Pair<String, Integer>> hostPortPairs;
 
     public ModifyBrokerClause(ModifyOp op, String brokerName, List<String> 
hostPorts) {
+        super(AlterOpType.ALTER_OTHER);
         this.op = op;
         this.brokerName = brokerName;
         this.hostPorts = hostPorts;
diff --git a/fe/src/main/java/org/apache/doris/analysis/ModifyColumnClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ModifyColumnClause.java
index 9f0ace6..9783396 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ModifyColumnClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ModifyColumnClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.common.AnalysisException;
 
@@ -48,6 +49,7 @@ public class ModifyColumnClause extends AlterTableClause {
 
     public ModifyColumnClause(ColumnDef columnDef, ColumnPosition colPos, 
String rollup,
                               Map<String, String> properties) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.columnDef = columnDef;
         this.colPos = colPos;
         this.rollupName = rollup;
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/ModifyPartitionClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ModifyPartitionClause.java
index 5d95ed6..6f9c21f 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ModifyPartitionClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ModifyPartitionClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.util.PrintableMap;
 
@@ -35,13 +36,14 @@ public class ModifyPartitionClause extends AlterTableClause 
{
     }
 
     public ModifyPartitionClause(String partitionName, Map<String, String> 
properties) {
+        super(AlterOpType.MODIFY_PARTITION);
         this.partitionName = partitionName;
         this.properties = properties;
         // ATTN: currently, modify partition only allow 3 kinds of operations:
         // 1. modify replication num
         // 2. modify data property
         // 3. modify in memory
-        // And these 2 operations does not require table to be stable.
+        // And these 3 operations does not require table to be stable.
         // If other kinds of operations be added later, "needTableStable" may 
be changed.
         this.needTableStable = false;
     }
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java
index 71fa4cb..63de337 100644
--- 
a/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java
+++ 
b/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.catalog.TableProperty;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Config;
@@ -32,6 +33,7 @@ public class ModifyTablePropertiesClause extends 
AlterTableClause {
     private Map<String, String> properties;
 
     public ModifyTablePropertiesClause(Map<String, String> properties) {
+        super(AlterOpType.MODIFY_TABLE_PROPERTY);
         this.properties = properties;
     }
 
@@ -87,6 +89,7 @@ public class ModifyTablePropertiesClause extends 
AlterTableClause {
             properties.remove(defaultReplicationNumName);
         } else if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY)) {
             this.needTableStable = false;
+            this.opType = AlterOpType.MODIFY_TABLE_PROPERTY_SYNC;
         } else {
             throw new AnalysisException("Unknown table property: " + 
properties.keySet());
         }
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/PartitionRenameClause.java 
b/fe/src/main/java/org/apache/doris/analysis/PartitionRenameClause.java
index c19dae9..e3cf839 100644
--- a/fe/src/main/java/org/apache/doris/analysis/PartitionRenameClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/PartitionRenameClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.FeNameFormat;
 
@@ -30,6 +31,7 @@ public class PartitionRenameClause extends AlterTableClause {
     private String newPartitionName;
 
     public PartitionRenameClause(String partitionName, String 
newPartitionName) {
+        super(AlterOpType.RENAME);
         this.partitionName = partitionName;
         this.newPartitionName = newPartitionName;
         this.needTableStable = false;
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/ReorderColumnsClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ReorderColumnsClause.java
index d16498b..0d63072 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ReorderColumnsClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ReorderColumnsClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 
 import com.google.common.base.Strings;
@@ -40,6 +41,7 @@ public class ReorderColumnsClause extends AlterTableClause {
     }
 
     public ReorderColumnsClause(List<String> cols, String rollup, Map<String, 
String> properties) {
+        super(AlterOpType.SCHEMA_CHANGE);
         this.columnsByPos = cols;
         this.rollupName = rollup;
         this.properties = properties;
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/ReplacePartitionClause.java 
b/fe/src/main/java/org/apache/doris/analysis/ReplacePartitionClause.java
index a7002ad..ddb347e 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ReplacePartitionClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ReplacePartitionClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.util.PropertyAnalyzer;
 
@@ -53,6 +54,7 @@ public class ReplacePartitionClause extends AlterTableClause {
 
     public ReplacePartitionClause(PartitionNames partitionNames, 
PartitionNames tempPartitionNames,
             Map<String, String> properties) {
+        super(AlterOpType.REPLACE_PARTITION);
         this.partitionNames = partitionNames;
         this.tempPartitionNames = tempPartitionNames;
         this.needTableStable = false;
diff --git a/fe/src/main/java/org/apache/doris/analysis/RollupRenameClause.java 
b/fe/src/main/java/org/apache/doris/analysis/RollupRenameClause.java
index f7a6918..a51dff3 100644
--- a/fe/src/main/java/org/apache/doris/analysis/RollupRenameClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/RollupRenameClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.FeNameFormat;
 
@@ -30,6 +31,7 @@ public class RollupRenameClause extends AlterTableClause {
     private String newRollupName;
 
     public RollupRenameClause(String rollupName, String newRollupName) {
+        super(AlterOpType.RENAME);
         this.rollupName = rollupName;
         this.newRollupName = newRollupName;
         this.needTableStable = false;
diff --git a/fe/src/main/java/org/apache/doris/analysis/TableRenameClause.java 
b/fe/src/main/java/org/apache/doris/analysis/TableRenameClause.java
index 08bf4ba..e35eff7 100644
--- a/fe/src/main/java/org/apache/doris/analysis/TableRenameClause.java
+++ b/fe/src/main/java/org/apache/doris/analysis/TableRenameClause.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.analysis;
 
+import org.apache.doris.alter.AlterOpType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.FeNameFormat;
 
@@ -29,6 +30,7 @@ public class TableRenameClause extends AlterTableClause {
     private String newTableName;
 
     public TableRenameClause(String newTableName) {
+        super(AlterOpType.RENAME);
         this.newTableName = newTableName;
         this.needTableStable = false;
     }
diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java 
b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
index f719e9e..2cbcee2 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -3229,7 +3229,7 @@ public class Catalog {
         }
     }
 
-    public void modifyPartition(Database db, OlapTable olapTable, String 
partitionName, Map<String, String> properties)
+    public void modifyPartitionProperty(Database db, OlapTable olapTable, 
String partitionName, Map<String, String> properties)
             throws DdlException {
         Preconditions.checkArgument(db.isWriteLockHeldByCurrentThread());
         if (olapTable.getState() != OlapTableState.NORMAL) {
diff --git 
a/fe/src/main/java/org/apache/doris/clone/DynamicPartitionScheduler.java 
b/fe/src/main/java/org/apache/doris/clone/DynamicPartitionScheduler.java
index 106ed9c..4df2ed8 100644
--- a/fe/src/main/java/org/apache/doris/clone/DynamicPartitionScheduler.java
+++ b/fe/src/main/java/org/apache/doris/clone/DynamicPartitionScheduler.java
@@ -84,7 +84,6 @@ public class DynamicPartitionScheduler extends MasterDaemon {
         ERROR
     }
 
-
     public DynamicPartitionScheduler(String name, long intervalMs) {
         super(name, intervalMs);
         this.initialize = false;
diff --git a/fe/src/main/java/org/apache/doris/common/ErrorCode.java 
b/fe/src/main/java/org/apache/doris/common/ErrorCode.java
index f3b32dd..9a6ecc8 100644
--- a/fe/src/main/java/org/apache/doris/common/ErrorCode.java
+++ b/fe/src/main/java/org/apache/doris/common/ErrorCode.java
@@ -210,7 +210,7 @@ public enum ErrorCode {
             "Table %s is not a colocated table"),
     ERR_INVALID_OPERATION(5065, new byte[] { '4', '2', '0', '0', '0' }, 
"Operation %s is invalid"),
     ERROR_DYNAMIC_PARTITION_TIME_UNIT(5065, new byte[] {'4', '2', '0', '0', 
'0'},
-            "Unsupported time unit %s. Expect DAY WEEK MONTH."),
+            "Unsupported time unit %s. Expect DAY/WEEK/MONTH."),
     ERROR_DYNAMIC_PARTITION_START_ZERO(5066, new byte[] {'4', '2', '0', '0', 
'0'},
             "Dynamic partition start must less than 0"),
     ERROR_DYNAMIC_PARTITION_START_FORMAT(5066, new byte[] {'4', '2', '0', '0', 
'0'},
diff --git 
a/fe/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java 
b/fe/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java
index 3e45110..03c41d9 100644
--- a/fe/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java
+++ b/fe/src/main/java/org/apache/doris/common/util/DynamicPartitionUtil.java
@@ -36,9 +36,10 @@ import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.FeNameFormat;
 
+import com.google.common.base.Strings;
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import com.google.common.base.Strings;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -145,7 +146,7 @@ public class DynamicPartitionUtil {
                 Strings.isNullOrEmpty(end) &&
                 Strings.isNullOrEmpty(buckets)))) {
             if (Strings.isNullOrEmpty(enable)) {
-                throw new DdlException("Must assign dynamic_partition.enable 
properties");
+                properties.put(DynamicPartitionProperty.ENABLE, "true");
             }
             if (Strings.isNullOrEmpty(timeUnit)) {
                 throw new DdlException("Must assign 
dynamic_partition.time_unit properties");
@@ -225,7 +226,7 @@ public class DynamicPartitionUtil {
         if (tableProperty != null && 
tableProperty.getDynamicPartitionProperty() != null &&
                 tableProperty.getDynamicPartitionProperty().isExist() &&
                 tableProperty.getDynamicPartitionProperty().getEnable()) {
-            throw new DdlException("Cannot modify partition on a Dynamic 
Partition Table, set `dynamic_partition.enable` to false firstly.");
+            throw new DdlException("Cannot add/drop partition on a Dynamic 
Partition Table, set `dynamic_partition.enable` to false firstly.");
         }
     }
 
diff --git a/fe/src/test/java/org/apache/doris/alter/AlterTest.java 
b/fe/src/test/java/org/apache/doris/alter/AlterTest.java
new file mode 100644
index 0000000..a129162
--- /dev/null
+++ b/fe/src/test/java/org/apache/doris/alter/AlterTest.java
@@ -0,0 +1,190 @@
+// 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.alter;
+
+import org.apache.doris.analysis.AlterTableStmt;
+import org.apache.doris.analysis.CreateDbStmt;
+import org.apache.doris.analysis.CreateTableStmt;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.catalog.Database;
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.FeConstants;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.utframe.UtFrameUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Map;
+import java.util.UUID;
+
+public class AlterTest {
+
+    private static String runningDir = "fe/mocked/AlterTest/" + 
UUID.randomUUID().toString() + "/";
+
+    private static ConnectContext connectContext;
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        FeConstants.runningUnitTest = true;
+        FeConstants.default_scheduler_interval_millisecond = 100;
+        Config.dynamic_partition_enable = true;
+        UtFrameUtils.createMinDorisCluster(runningDir);
+
+        // create connect context
+        connectContext = UtFrameUtils.createDefaultCtx();
+        // create database
+        String createDbStmtStr = "create database test;";
+        CreateDbStmt createDbStmt = (CreateDbStmt) 
UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, connectContext);
+        Catalog.getCurrentCatalog().createDb(createDbStmt);
+
+        createTable("CREATE TABLE test.tbl1\n" + 
+                "(\n" + 
+                "    k1 date,\n" + 
+                "    k2 int,\n" + 
+                "    v1 int sum\n" + 
+                ")\n" + 
+                "PARTITION BY RANGE(k1)\n" + 
+                "(\n" + 
+                "    PARTITION p1 values less than('2020-02-01'),\n" + 
+                "    PARTITION p2 values less than('2020-03-01')\n" + 
+                ")\n" + 
+                "DISTRIBUTED BY HASH(k2) BUCKETS 3\n" + 
+                "PROPERTIES('replication_num' = '1');");
+    }
+
+    @AfterClass
+    public static void tearDown() {
+        File file = new File(runningDir);
+        file.delete();
+    }
+
+    private static void createTable(String sql) throws Exception {
+        CreateTableStmt createTableStmt = (CreateTableStmt) 
UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
+        Catalog.getCurrentCatalog().createTable(createTableStmt);
+    }
+
+    private static void alterTable(String sql, boolean expectedException) 
throws Exception {
+        AlterTableStmt alterTableStmt = (AlterTableStmt) 
UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
+        try {
+            Catalog.getCurrentCatalog().alterTable(alterTableStmt);
+            if (expectedException) {
+                Assert.fail();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            if (!expectedException) {
+                Assert.fail();
+            }
+        }
+    }
+
+    @Test
+    public void testConflictAlterOperations() throws Exception {
+        String stmt = "alter table test.tbl1 add partition p3 values less 
than('2020-04-01'), add partition p4 values less than('2020-05-01')";
+        alterTable(stmt, true);
+
+        stmt = "alter table test.tbl1 add partition p3 values less 
than('2020-04-01'), drop partition p4";
+        alterTable(stmt, true);
+
+        stmt = "alter table test.tbl1 drop partition p3, drop partition p4";
+        alterTable(stmt, true);
+
+        stmt = "alter table test.tbl1 drop partition p3, add column k3 int";
+        alterTable(stmt, true);
+
+        // no conflict
+        stmt = "alter table test.tbl1 add column k3 int, add column k4 int";
+        alterTable(stmt, false);
+        waitSchemaChangeJobDone(false);
+        
+        stmt = "alter table test.tbl1 add rollup r1 (k1)";
+        alterTable(stmt, false);
+        waitSchemaChangeJobDone(true);
+
+        stmt = "alter table test.tbl1 add rollup r2 (k1), r3 (k1)";
+        alterTable(stmt, false);
+        waitSchemaChangeJobDone(true);
+        
+        // enable dynamic partition
+        stmt = "alter table test.tbl1 set (\n" + 
+                "'dynamic_partition.enable' = 'true',\n" + 
+                "'dynamic_partition.time_unit' = 'DAY',\n" + 
+                "'dynamic_partition.start' = '-3',\n" + 
+                "'dynamic_partition.end' = '3',\n" + 
+                "'dynamic_partition.prefix' = 'p',\n" + 
+                "'dynamic_partition.buckets' = '3'\n" + 
+                " );";
+        alterTable(stmt, false);
+        Database db = 
Catalog.getCurrentCatalog().getDb("default_cluster:test");
+        OlapTable tbl = (OlapTable)db.getTable("tbl1");
+        
Assert.assertTrue(tbl.getTableProperty().getDynamicPartitionProperty().getEnable());
+        Assert.assertEquals(4, tbl.getIndexIdToSchema().size());
+        
+        // add partition when dynamic partition is enable
+        stmt = "alter table test.tbl1 add partition p3 values less 
than('2020-04-01') distributed by hash(k2) buckets 4 PROPERTIES 
('replication_num' = '1')";
+        alterTable(stmt, true);
+
+        // add temp partition when dynamic partition is enable
+        stmt = "alter table test.tbl1 add temporary partition tp3 values less 
than('2020-04-01') distributed by hash(k2) buckets 4 PROPERTIES 
('replication_num' = '1')";
+        alterTable(stmt, false);
+        Assert.assertEquals(1, tbl.getTempPartitions().size());
+
+        // disable the dynamic partition
+        stmt = "alter table test.tbl1 set ('dynamic_partition.enable' = 
'false')";
+        alterTable(stmt, false);
+        
Assert.assertFalse(tbl.getTableProperty().getDynamicPartitionProperty().getEnable());
+        
+        // add partition when dynamic partition is disable
+        stmt = "alter table test.tbl1 add partition p3 values less 
than('2020-04-01') distributed by hash(k2) buckets 4";
+        alterTable(stmt, false);
+
+        // set table's default replication num
+        Assert.assertEquals(Short.valueOf("1"), 
tbl.getDefaultReplicationNum());
+        stmt = "alter table test.tbl1 set ('default.replication_num' = '3');";
+        alterTable(stmt, false);
+        Assert.assertEquals(Short.valueOf("3"), 
tbl.getDefaultReplicationNum());
+
+        // add partition without set replication num
+        stmt = "alter table test.tbl1 add partition p4 values less 
than('2020-05-01')";
+        alterTable(stmt, true);
+
+        // add partition when dynamic partition is disable
+        stmt = "alter table test.tbl1 add partition p4 values less 
than('2020-05-01') ('replication_num' = '1')";
+        alterTable(stmt, false);
+    }
+
+    private void waitSchemaChangeJobDone(boolean rollupJob) throws 
InterruptedException {
+        Map<Long, AlterJobV2> alterJobs = 
Catalog.getCurrentCatalog().getSchemaChangeHandler().getAlterJobsV2();
+        if (rollupJob) {
+            alterJobs = 
Catalog.getCurrentCatalog().getRollupHandler().getAlterJobsV2();
+        }
+        for (AlterJobV2 alterJobV2 : alterJobs.values()) {
+            while (!alterJobV2.getJobState().isFinalState()) {
+                System.out.println("alter job " + alterJobV2.getJobId() + " is 
running. state: " + alterJobV2.getJobState());
+                Thread.sleep(1000);
+            }
+            System.out.println(alterJobV2.getType() + " alter job " + 
alterJobV2.getJobId() + " is done. state: " + alterJobV2.getJobState());
+            Assert.assertEquals(AlterJobV2.JobState.FINISHED, 
alterJobV2.getJobState());
+        }
+    }
+}
diff --git 
a/fe/src/test/java/org/apache/doris/catalog/DynamicPartitionTableTest.java 
b/fe/src/test/java/org/apache/doris/catalog/DynamicPartitionTableTest.java
index 318e282..c65277e 100644
--- a/fe/src/test/java/org/apache/doris/catalog/DynamicPartitionTableTest.java
+++ b/fe/src/test/java/org/apache/doris/catalog/DynamicPartitionTableTest.java
@@ -1,10 +1,5 @@
 package org.apache.doris.catalog;
 
-import com.google.common.collect.Lists;
-import mockit.Expectations;
-import mockit.Injectable;
-import mockit.Mock;
-import mockit.MockUp;
 import org.apache.doris.analysis.Analyzer;
 import org.apache.doris.analysis.ColumnDef;
 import org.apache.doris.analysis.CreateTableStmt;
@@ -24,6 +19,9 @@ import org.apache.doris.persist.EditLog;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.system.SystemInfoService;
 import org.apache.doris.task.AgentBatchTask;
+
+import com.google.common.collect.Lists;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -36,6 +34,11 @@ import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import mockit.Expectations;
+import mockit.Injectable;
+import mockit.Mock;
+import mockit.MockUp;
+
 public class DynamicPartitionTableTest {
     private TableName dbTableName;
     private String dbName = "testDb";
@@ -154,53 +157,6 @@ public class DynamicPartitionTableTest {
     }
 
     @Test
-    public void testMissEnable(@Injectable SystemInfoService systemInfoService,
-                               @Injectable PaloAuth paloAuth,
-                               @Injectable EditLog editLog) throws 
UserException {
-        new Expectations(catalog) {
-            {
-                catalog.getDb(dbTableName.getDb());
-                minTimes = 0;
-                result = db;
-
-                Catalog.getCurrentSystemInfo();
-                minTimes = 0;
-                result = systemInfoService;
-
-                systemInfoService.checkClusterCapacity(anyString);
-                minTimes = 0;
-                systemInfoService.seqChooseBackendIds(anyInt, true, true, 
anyString);
-                minTimes = 0;
-                result = beIds;
-
-                catalog.getAuth();
-                minTimes = 0;
-                result = paloAuth;
-                paloAuth.checkTblPriv((ConnectContext) any, anyString, 
anyString, PrivPredicate.CREATE);
-                minTimes = 0;
-                result = true;
-
-                catalog.getEditLog();
-                minTimes = 0;
-                result = editLog;
-            }
-        };
-
-        properties.remove(DynamicPartitionProperty.ENABLE);
-
-        CreateTableStmt stmt = new CreateTableStmt(false, false, dbTableName, 
columnDefs, "olap",
-                new KeysDesc(KeysType.AGG_KEYS, columnNames),
-                new RangePartitionDesc(Lists.newArrayList("key1"), 
singleRangePartitionDescs),
-                new HashDistributionDesc(1, Lists.newArrayList("key1")), 
properties, null, "");
-        stmt.analyze(analyzer);
-
-        expectedEx.expect(DdlException.class);
-        expectedEx.expectMessage("Must assign dynamic_partition.enable 
properties");
-
-        catalog.createTable(stmt);
-    }
-
-    @Test
     public void testMissPrefix(@Injectable SystemInfoService systemInfoService,
                                @Injectable PaloAuth paloAuth,
                                @Injectable EditLog editLog) throws 
UserException {
diff --git a/fe/src/test/java/org/apache/doris/utframe/DemoTest.java 
b/fe/src/test/java/org/apache/doris/utframe/DemoTest.java
index dfa293b..499f959 100644
--- a/fe/src/test/java/org/apache/doris/utframe/DemoTest.java
+++ b/fe/src/test/java/org/apache/doris/utframe/DemoTest.java
@@ -109,10 +109,10 @@ public class DemoTest {
         Assert.assertEquals(1, alterJobs.size());
         for (AlterJobV2 alterJobV2 : alterJobs.values()) {
             while (!alterJobV2.getJobState().isFinalState()) {
-                System.out.println("alter job " + alterJobV2.getDbId() + " is 
running. state: " + alterJobV2.getJobState());
+                System.out.println("alter job " + alterJobV2.getJobId() + " is 
running. state: " + alterJobV2.getJobState());
                 Thread.sleep(1000);
             }
-            System.out.println("alter job " + alterJobV2.getDbId() + " is 
done. state: " + alterJobV2.getJobState());
+            System.out.println("alter job " + alterJobV2.getJobId() + " is 
done. state: " + alterJobV2.getJobState());
             Assert.assertEquals(AlterJobV2.JobState.FINISHED, 
alterJobV2.getJobState());
         }
         db.readLock();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to