You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2021/11/12 07:12:53 UTC

[incubator-doris] branch master updated: [Alter] Support alter table engine type from MySQL to ODBC (#6993)

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 3d81665  [Alter] Support alter table engine type from MySQL to ODBC (#6993)
3d81665 is described below

commit 3d8166504af9e91d51be59f812577d0377b7d0b3
Author: Mingyu Chen <mo...@gmail.com>
AuthorDate: Fri Nov 12 15:12:41 2021 +0800

    [Alter] Support alter table engine type from MySQL to ODBC (#6993)
    
    Support alter table engine type from MySQL to ODBC:
    
    ```
    ALTER TABLE tbl MODIFY ENGINE TO odbc PROPERTIES("driver" = "odbc");
    ```
---
 .../sql-statements/Data Definition/ALTER TABLE.md  | 10 +++
 .../sql-statements/Data Definition/ALTER TABLE.md  | 11 +++
 fe/fe-core/src/main/cup/sql_parser.cup             |  4 ++
 .../main/java/org/apache/doris/alter/Alter.java    | 64 ++++++++++++++++--
 .../java/org/apache/doris/alter/AlterOpType.java   |  2 +
 .../org/apache/doris/analysis/AlterTableStmt.java  |  9 +--
 .../apache/doris/analysis/ModifyEngineClause.java  | 79 ++++++++++++++++++++++
 .../java/org/apache/doris/catalog/OdbcTable.java   | 19 +++---
 .../org/apache/doris/journal/JournalEntity.java    |  6 ++
 .../java/org/apache/doris/persist/EditLog.java     |  9 +++
 .../persist/ModifyTableEngineOperationLog.java     | 67 ++++++++++++++++++
 .../org/apache/doris/persist/OperationType.java    |  1 +
 .../java/org/apache/doris/alter/AlterTest.java     | 46 ++++++++++++-
 13 files changed, 308 insertions(+), 19 deletions(-)

diff --git a/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md b/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md
index e11a924..5bad553 100644
--- a/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md	
+++ b/docs/en/sql-reference/sql-statements/Data Definition/ALTER TABLE.md	
@@ -208,6 +208,12 @@ under the License.
         grammer:
             MODIFY COLUMN col1 COMMENT "new column comment"
 
+	12. Modify engine type
+
+        Only the MySQL type can be changed to the ODBC type. The value of driver is the name of the driver in the odbc.init configuration.
+
+        grammar:
+            MODIFY ENGINE TO odbc PROPERTIES("driver" = "MySQL");
      
     Rename supports modification of the following names:
     1. Modify the table name
@@ -395,6 +401,10 @@ under the License.
     20. Modify column comment
 
         ALTER TABLE example_db.my_table MODIFY COLUMN k1 COMMENT "k1", MODIFY COLUMN k2 COMMENT "k2";
+
+    21. Modify engine Type
+
+        ALTER TABLE example_db.mysql_table MODIFY ENGINE TO odbc PROPERTIES("driver" = "MySQL");
         
     [rename]
     1. Modify the table named table1 to table2
diff --git a/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md b/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md
index b29a083..039c0f8 100644
--- a/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md	
+++ b/docs/zh-CN/sql-reference/sql-statements/Data Definition/ALTER TABLE.md	
@@ -206,6 +206,13 @@ under the License.
         语法:
             MODIFY COLUMN col1 COMMENT "new column comment"
 
+	12. 修改引擎类型
+
+		仅支持将 MySQL 类型修改为 ODBC 类型。driver 的值为 odbc.init 配置中的 driver 名称。
+
+		语法:
+			MODIFY ENGINE TO odbc PROPERTIES("driver" = "MySQL");
+
     rename 支持对以下名称进行修改:
     1. 修改表名
         语法:
@@ -390,6 +397,10 @@ under the License.
     20. 修改列注释
 
         ALTER TABLE example_db.my_table MODIFY COLUMN k1 COMMENT "k1", MODIFY COLUMN k2 COMMENT "k2";
+
+	21. 修改引擎类型
+
+		ALTER TABLE example_db.mysql_table MODIFY ENGINE TO odbc PROPERTIES("driver" = "MySQL");
     
     [rename]
     1. 将名为 table1 的表修改为 table2
diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup
index be00fd2..fc81a60 100644
--- a/fe/fe-core/src/main/cup/sql_parser.cup
+++ b/fe/fe-core/src/main/cup/sql_parser.cup
@@ -1077,6 +1077,10 @@ alter_table_clause ::=
     {:
         RESULT = new ModifyColumnCommentClause(colName, comment);
     :}
+    | KW_MODIFY KW_ENGINE KW_TO ident:engine opt_properties:properties
+    {:
+        RESULT = new ModifyEngineClause(engine, properties);
+    :}
     ;
 
 opt_enable_feature_properties ::=
diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
index bf1a0c8..ee8a049 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
@@ -28,6 +28,7 @@ import org.apache.doris.analysis.DropMaterializedViewStmt;
 import org.apache.doris.analysis.DropPartitionClause;
 import org.apache.doris.analysis.ModifyColumnCommentClause;
 import org.apache.doris.analysis.ModifyDistributionClause;
+import org.apache.doris.analysis.ModifyEngineClause;
 import org.apache.doris.analysis.ModifyPartitionClause;
 import org.apache.doris.analysis.ModifyTableCommentClause;
 import org.apache.doris.analysis.ModifyTablePropertiesClause;
@@ -41,6 +42,8 @@ import org.apache.doris.catalog.Catalog;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.DataProperty;
 import org.apache.doris.catalog.Database;
+import org.apache.doris.catalog.MysqlTable;
+import org.apache.doris.catalog.OdbcTable;
 import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.OlapTable.OlapTableState;
 import org.apache.doris.catalog.Partition;
@@ -59,17 +62,19 @@ import org.apache.doris.persist.AlterViewInfo;
 import org.apache.doris.persist.BatchModifyPartitionsInfo;
 import org.apache.doris.persist.ModifyCommentOperationLog;
 import org.apache.doris.persist.ModifyPartitionInfo;
+import org.apache.doris.persist.ModifyTableEngineOperationLog;
 import org.apache.doris.persist.ReplaceTableOperationLog;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.thrift.TOdbcTableType;
 import org.apache.doris.thrift.TTabletType;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -278,8 +283,7 @@ public class Alter {
     }
 
     private void processAlterExternalTable(AlterTableStmt stmt, Table externalTable, Database db) throws UserException {
-        stmt.rewriteAlterClause(externalTable);
-
+        stmt.checkExternalTableOperationAllow(externalTable);
         // check conflict alter ops first
         List<AlterClause> alterClauses = stmt.getOps();
         AlterOperations currentAlterOps = new AlterOperations();
@@ -288,7 +292,57 @@ public class Alter {
             processRename(db, externalTable, alterClauses);
         } else if (currentAlterOps.hasSchemaChangeOp()) {
             schemaChangeHandler.processExternalTable(alterClauses, db, externalTable);
+        } else if (currentAlterOps.contains(AlterOpType.MODIFY_ENGINE)) {
+            ModifyEngineClause modifyEngineClause = (ModifyEngineClause) alterClauses.get(0);
+            processModifyEngine(db, externalTable, modifyEngineClause);
+        }
+    }
+
+    public void processModifyEngine(Database db, Table externalTable, ModifyEngineClause clause) throws DdlException {
+        if (externalTable.getType() != TableType.MYSQL) {
+            throw new DdlException("Only support modify table engine from MySQL to ODBC");
+        }
+
+        processModifyEngineInternal(db, externalTable, clause.getProperties());
+        ModifyTableEngineOperationLog log = new ModifyTableEngineOperationLog(db.getId(),
+                externalTable.getId(), clause.getProperties());
+        Catalog.getCurrentCatalog().getEditLog().logModifyTableEngine(log);
+        LOG.info("modify table {}'s engine from MySQL to ODBC", externalTable.getName());
+    }
+
+    public void replayProcessModifyEngine(ModifyTableEngineOperationLog log) {
+        Database db = Catalog.getCurrentCatalog().getDbNullable(log.getDbId());
+        if (db == null) {
+            return;
+        }
+        MysqlTable mysqlTable = (MysqlTable) db.getTableNullable(log.getTableId());
+        if (mysqlTable == null) {
+            return;
+        }
+        processModifyEngineInternal(db, mysqlTable, log.getProperties());
+    }
+
+    private void processModifyEngineInternal(Database db, Table externalTable, Map<String, String> prop) {
+        MysqlTable mysqlTable = (MysqlTable) externalTable;
+        Map<String, String> newProp = Maps.newHashMap(prop);
+        newProp.put(OdbcTable.ODBC_HOST, mysqlTable.getHost());
+        newProp.put(OdbcTable.ODBC_PORT, mysqlTable.getPort());
+        newProp.put(OdbcTable.ODBC_USER, mysqlTable.getUserName());
+        newProp.put(OdbcTable.ODBC_PASSWORD, mysqlTable.getPasswd());
+        newProp.put(OdbcTable.ODBC_DATABASE, mysqlTable.getMysqlDatabaseName());
+        newProp.put(OdbcTable.ODBC_TABLE, mysqlTable.getMysqlTableName());
+        newProp.put(OdbcTable.ODBC_TYPE, TOdbcTableType.MYSQL.name());
+
+        // create a new odbc table with same id and name
+        OdbcTable odbcTable = null;
+        try {
+            odbcTable = new OdbcTable(mysqlTable.getId(), mysqlTable.getName(), mysqlTable.getBaseSchema(), newProp);
+        } catch (DdlException e) {
+            LOG.warn("Should not happen", e);
+            return;
         }
+        db.dropTable(mysqlTable.getName());
+        db.createTable(odbcTable);
     }
 
     public void processAlterTable(AlterTableStmt stmt) throws UserException {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/AlterOpType.java b/fe/fe-core/src/main/java/org/apache/doris/alter/AlterOpType.java
index 7f8ddac..2641d7c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/alter/AlterOpType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/alter/AlterOpType.java
@@ -40,10 +40,12 @@ public enum AlterOpType {
     MODIFY_DISTRIBUTION,
     MODIFY_TABLE_COMMENT,
     MODIFY_COLUMN_COMMENT,
+    MODIFY_ENGINE,
     INVALID_OP; // INVALID_OP must be the last one
 
     // true means 2 operations have no conflict.
     public static Boolean[][] COMPATIBILITY_MATRIX;
+
     static {
         COMPATIBILITY_MATRIX = new Boolean[INVALID_OP.ordinal() + 1][INVALID_OP.ordinal() + 1];
         for (int i = 0; i < INVALID_OP.ordinal(); i++) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java
index ca19188..152b32b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java
@@ -149,7 +149,7 @@ public class AlterTableStmt extends DdlStmt {
         ops = clauses;
     }
 
-    public void rewriteAlterClause(Table table) throws UserException {
+    public void checkExternalTableOperationAllow(Table table) throws UserException {
         List<AlterClause> clauses = new ArrayList<>();
         for (AlterClause alterClause : ops) {
             if (alterClause instanceof TableRenameClause ||
@@ -157,11 +157,12 @@ public class AlterTableStmt extends DdlStmt {
                     alterClause instanceof AddColumnsClause ||
                     alterClause instanceof DropColumnClause ||
                     alterClause instanceof ModifyColumnClause ||
-                    alterClause instanceof ReorderColumnsClause) {
+                    alterClause instanceof ReorderColumnsClause ||
+                    alterClause instanceof ModifyEngineClause) {
                 clauses.add(alterClause);
             } else {
-                throw new AnalysisException( table.getType().toString() + " [" + table.getName() + "] " +
-                          "do not support " + alterClause.getOpType().toString() + " clause now");
+                throw new AnalysisException(table.getType().toString() + " [" + table.getName() + "] " +
+                        "do not support " + alterClause.getOpType().toString() + " clause now");
             }
         }
         ops = clauses;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyEngineClause.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyEngineClause.java
new file mode 100644
index 0000000..be0eec7
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ModifyEngineClause.java
@@ -0,0 +1,79 @@
+// 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.analysis;
+
+import org.apache.doris.alter.AlterOpType;
+import org.apache.doris.catalog.OdbcTable;
+import org.apache.doris.catalog.Table;
+import org.apache.doris.common.AnalysisException;
+
+import com.google.common.base.Strings;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Map;
+
+// MODIFY ENGINE TO odbc PROPERTIES("driver" = "Oracle 19 ODBC driver")
+public class ModifyEngineClause extends AlterTableClause {
+    private static final Logger LOG = LogManager.getLogger(ModifyEngineClause.class);
+    private String engine;
+    private Map<String, String> properties;
+
+    public ModifyEngineClause(String engine, Map<String, String> properties) {
+        super(AlterOpType.MODIFY_ENGINE);
+        this.engine = engine;
+        this.properties = properties;
+    }
+
+    public String getEngine() {
+        return engine;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return this.properties;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws AnalysisException {
+        if (Strings.isNullOrEmpty(engine)) {
+            throw new AnalysisException("Engine name is missing");
+        }
+
+        if (!engine.equalsIgnoreCase(Table.TableType.ODBC.name())) {
+            throw new AnalysisException("Only support alter table engine from MySQL to ODBC");
+        }
+
+        if (properties == null || !properties.containsKey(OdbcTable.ODBC_DRIVER)) {
+            throw new AnalysisException("Need specify 'driver' property");
+        }
+    }
+
+    @Override
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("MODIFY ENGINE TO ").append(engine);
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        return toSql();
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OdbcTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OdbcTable.java
index 05d2ee6..9283555 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OdbcTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OdbcTable.java
@@ -46,18 +46,19 @@ import java.util.Map;
 public class OdbcTable extends Table {
     private static final Logger LOG = LogManager.getLogger(OlapTable.class);
 
-    private static final String ODBC_CATALOG_RESOURCE = "odbc_catalog_resource";
-    private static final String ODBC_HOST = "host";
-    private static final String ODBC_PORT = "port";
-    private static final String ODBC_USER = "user";
-    private static final String ODBC_PASSWORD = "password";
-    private static final String ODBC_DATABASE = "database";
-    private static final String ODBC_TABLE = "table";
-    private static final String ODBC_DRIVER = "driver";
-    private static final String ODBC_TYPE = "odbc_type";
+    public static final String ODBC_CATALOG_RESOURCE = "odbc_catalog_resource";
+    public static final String ODBC_HOST = "host";
+    public static final String ODBC_PORT = "port";
+    public static final String ODBC_USER = "user";
+    public static final String ODBC_PASSWORD = "password";
+    public static final String ODBC_DATABASE = "database";
+    public static final String ODBC_TABLE = "table";
+    public static final String ODBC_DRIVER = "driver";
+    public static final String ODBC_TYPE = "odbc_type";
 
     // map now odbc external table Doris support now
     private static Map<String, TOdbcTableType> TABLE_TYPE_MAP;
+
     static {
         Map<String, TOdbcTableType> tempMap = new HashMap<>();
         tempMap.put("oracle", TOdbcTableType.ORACLE);
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 d386ae0..cc7d89d 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
@@ -73,6 +73,7 @@ import org.apache.doris.persist.LdapInfo;
 import org.apache.doris.persist.ModifyCommentOperationLog;
 import org.apache.doris.persist.ModifyPartitionInfo;
 import org.apache.doris.persist.ModifyTableDefaultDistributionBucketNumOperationLog;
+import org.apache.doris.persist.ModifyTableEngineOperationLog;
 import org.apache.doris.persist.ModifyTablePropertyOperationLog;
 import org.apache.doris.persist.OperationType;
 import org.apache.doris.persist.PartitionPersistInfo;
@@ -652,6 +653,11 @@ public class JournalEntity implements Writable {
                 isRead = true;
                 break;
             }
+            case OperationType.OP_MODIFY_TABLE_ENGINE: {
+                data = ModifyTableEngineOperationLog.read(in);
+                isRead = true;
+                break;
+            }
             default: {
                 IOException e = new IOException();
                 LOG.error("UNKNOWN Operation Type {}", opCode, e);
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 c3f18ec..24871e0 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
@@ -861,6 +861,11 @@ public class EditLog {
                     catalog.getSqlBlockRuleMgr().replayDrop(log.getRuleNames());
                     break;
                 }
+                case OperationType.OP_MODIFY_TABLE_ENGINE: {
+                    ModifyTableEngineOperationLog log = (ModifyTableEngineOperationLog) journal.getData();
+                    catalog.getAlterInstance().replayProcessModifyEngine(log);
+                    break;
+                }
                 default: {
                     IOException e = new IOException();
                     LOG.error("UNKNOWN Operation Type {}", opCode, e);
@@ -1494,4 +1499,8 @@ public class EditLog {
     public void logDropSqlBlockRule(List<String> ruleNames) {
         logEdit(OperationType.OP_DROP_SQL_BLOCK_RULE, new DropSqlBlockRuleOperationLog(ruleNames));
     }
+
+    public void logModifyTableEngine(ModifyTableEngineOperationLog log) {
+        logEdit(OperationType.OP_MODIFY_TABLE_ENGINE, log);
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/ModifyTableEngineOperationLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/ModifyTableEngineOperationLog.java
new file mode 100644
index 0000000..d5cf73c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/ModifyTableEngineOperationLog.java
@@ -0,0 +1,67 @@
+// 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.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;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ModifyTableEngineOperationLog implements Writable {
+
+    @SerializedName(value = "dbId")
+    private long dbId;
+    @SerializedName(value = "tableId")
+    private long tableId;
+    @SerializedName(value = "properties")
+    private Map<String, String> properties = new HashMap<>();
+
+    public ModifyTableEngineOperationLog(long dbId, long tableId, Map<String, String> properties) {
+        this.dbId = dbId;
+        this.tableId = tableId;
+        this.properties = properties;
+    }
+
+    public long getDbId() {
+        return dbId;
+    }
+
+    public long getTableId() {
+        return tableId;
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    @Override
+    public void write(DataOutput out) throws IOException {
+        Text.writeString(out, GsonUtils.GSON.toJson(this));
+    }
+
+    public static ModifyTableEngineOperationLog read(DataInput in) throws IOException {
+        return GsonUtils.GSON.fromJson(Text.readString(in), ModifyTableEngineOperationLog.class);
+    }
+}
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 7a92808..2a5f3a2 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
@@ -67,6 +67,7 @@ public class OperationType {
     public static final short OP_BATCH_DROP_ROLLUP = 124;
     public static final short OP_REMOVE_ALTER_JOB_V2 = 125;
     public static final short OP_MODIFY_COMMENT = 126;
+    public static final short OP_MODIFY_TABLE_ENGINE = 127;
 
     // 30~39 130~139 230~239 ...
     // load job for only hadoop load
diff --git a/fe/fe-core/src/test/java/org/apache/doris/alter/AlterTest.java b/fe/fe-core/src/test/java/org/apache/doris/alter/AlterTest.java
index 92a05d9..42d5d48 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/alter/AlterTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/alter/AlterTest.java
@@ -22,9 +22,12 @@ import org.apache.doris.analysis.CreateDbStmt;
 import org.apache.doris.analysis.CreateTableStmt;
 import org.apache.doris.analysis.DateLiteral;
 import org.apache.doris.catalog.Catalog;
+import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.DataProperty;
 import org.apache.doris.catalog.Database;
 import org.apache.doris.catalog.MaterializedIndex;
+import org.apache.doris.catalog.MysqlTable;
+import org.apache.doris.catalog.OdbcTable;
 import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.Partition;
 import org.apache.doris.catalog.PrimitiveType;
@@ -178,8 +181,8 @@ public class AlterTest {
     }
 
     private static void alterTable(String sql, boolean expectedException) throws Exception {
-        AlterTableStmt alterTableStmt = (AlterTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
         try {
+            AlterTableStmt alterTableStmt = (AlterTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
             Catalog.getCurrentCatalog().alterTable(alterTableStmt);
             if (expectedException) {
                 Assert.fail();
@@ -823,4 +826,45 @@ public class AlterTest {
         odbc_table = db.getTableNullable("odbc_table");
         Assert.assertNull(odbc_table);
     }
+
+    @Test
+    public void testModifyTableEngine() throws Exception {
+        String createOlapTblStmt = "CREATE TABLE test.mysql_table (\n" +
+                "  `k1` date NULL COMMENT \"\",\n" +
+                "  `k2` int NULL COMMENT \"\",\n" +
+                "  `k3` smallint NULL COMMENT \"\",\n" +
+                "  `v1` varchar(2048) NULL COMMENT \"\",\n" +
+                "  `v2` datetime NULL COMMENT \"\"\n" +
+                ") ENGINE=MYSQL\n" +
+                "PROPERTIES (\n" +
+                "\"host\" = \"172.16.0.1\",\n" +
+                "\"port\" = \"3306\",\n" +
+                "\"user\" = \"cmy\",\n" +
+                "\"password\" = \"abc\",\n" +
+                "\"database\" = \"db1\",\n" +
+                "\"table\" = \"tbl1\"" +
+                ");";
+        createTable(createOlapTblStmt);
+
+        Database db = Catalog.getCurrentCatalog().getDbNullable("default_cluster:test");
+        MysqlTable mysqlTable = db.getTableOrMetaException("mysql_table", Table.TableType.MYSQL);
+
+        String alterEngineStmt = "alter table test.mysql_table modify engine to odbc";
+        alterTable(alterEngineStmt, true);
+
+        alterEngineStmt = "alter table test.mysql_table modify engine to odbc properties(\"driver\" = \"MySQL\")";
+        alterTable(alterEngineStmt, false);
+
+        OdbcTable odbcTable = (OdbcTable) db.getTableNullable(mysqlTable.getId());
+        Assert.assertEquals("mysql_table", odbcTable.getName());
+        List<Column> schema = odbcTable.getBaseSchema();
+        Assert.assertEquals(5, schema.size());
+        Assert.assertEquals("172.16.0.1", odbcTable.getHost());
+        Assert.assertEquals("3306", odbcTable.getPort());
+        Assert.assertEquals("cmy", odbcTable.getUserName());
+        Assert.assertEquals("abc", odbcTable.getPasswd());
+        Assert.assertEquals("db1", odbcTable.getOdbcDatabaseName());
+        Assert.assertEquals("tbl1", odbcTable.getOdbcTableName());
+        Assert.assertEquals("MySQL", odbcTable.getOdbcDriver());
+    }
 }

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