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 c8705cc  [MaterializedView] Support dropping materialized view (#3068)
c8705cc is described below

commit c8705ccf1296c50b5196b9521da143155589797b
Author: EmmyMiao87 <522274...@qq.com>
AuthorDate: Wed Mar 11 18:16:24 2020 +0800

    [MaterializedView] Support dropping materialized view (#3068)
    
    `DROP MATERIALIZE VIEW [ IF EXISTS ] <mv_name> ON [db_name].<table_name>`
    
    Parameters:
    
      IF EXISTS: Do not throw an error if the materialized view does not exist. 
A notice is issued in this case.
      mv_name: The name of the materialized view to remove.
      db_name: The name of db to which materialized view belongs.
      table_name: The name of table to which materialized view belongs.
---
 fe/src/main/cup/sql_parser.cup                     |   4 +
 fe/src/main/java/org/apache/doris/alter/Alter.java |  55 ++++++---
 .../doris/alter/MaterializedViewHandler.java       | 134 ++++++++++++++-------
 .../doris/analysis/CreateMaterializedViewStmt.java |  21 +---
 .../doris/analysis/DropMaterializedViewStmt.java   |  88 ++++++++++++++
 .../java/org/apache/doris/catalog/Catalog.java     |   6 +
 .../java/org/apache/doris/catalog/OlapTable.java   |  18 +++
 .../main/java/org/apache/doris/qe/DdlExecutor.java |   3 +
 .../doris/alter/MaterializedViewHandlerTest.java   |  31 +++++
 .../analysis/CreateMaterializedViewStmtTest.java   |  87 +++++++++----
 .../analysis/DropMaterializedViewStmtTest.java     |  69 +++++++++++
 .../planner/MaterializedViewFunctionTest.java      |   4 +-
 12 files changed, 419 insertions(+), 101 deletions(-)

diff --git a/fe/src/main/cup/sql_parser.cup b/fe/src/main/cup/sql_parser.cup
index e8ce8f4..0337f0a 100644
--- a/fe/src/main/cup/sql_parser.cup
+++ b/fe/src/main/cup/sql_parser.cup
@@ -1507,6 +1507,10 @@ drop_stmt ::=
     {:
         RESULT = new AlterTableStmt(tableName, Lists.newArrayList(new 
DropIndexClause(indexName, tableName, false)));
     :}
+    | KW_DROP KW_MATERIALIZED KW_VIEW opt_if_exists:ifExists ident:mvName 
KW_ON table_name:tableName
+    {:
+        RESULT = new DropMaterializedViewStmt(ifExists, mvName, tableName);
+    :}
     ;
 
 // Recover statement
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 766b42b..4edbbe1 100644
--- a/fe/src/main/java/org/apache/doris/alter/Alter.java
+++ b/fe/src/main/java/org/apache/doris/alter/Alter.java
@@ -31,6 +31,7 @@ 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;
@@ -56,6 +57,7 @@ import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.util.DynamicPartitionUtil;
 import org.apache.doris.common.util.PropertyAnalyzer;
@@ -94,7 +96,12 @@ public class Alter {
 
     public void processCreateMaterializedView(CreateMaterializedViewStmt stmt) 
throws DdlException, AnalysisException {
         String tableName = stmt.getBaseIndexName();
-        Database db = Catalog.getInstance().getDb(stmt.getDBName());
+        // check db
+        String dbName = stmt.getDBName();
+        Database db = Catalog.getInstance().getDb(dbName);
+        if (db == null) {
+            ErrorReport.reportDdlException(ErrorCode.ERR_BAD_DB_ERROR, dbName);
+        }
         // check cluster capacity
         
Catalog.getCurrentSystemInfo().checkClusterCapacity(stmt.getClusterName());
         // check db quota
@@ -107,24 +114,44 @@ public class Alter {
                 throw new DdlException("Do not support alter non-OLAP table[" 
+ tableName + "]");
             }
             OlapTable olapTable = (OlapTable) table;
+            olapTable.checkStableAndNormal(db.getClusterName());
+
+            
((MaterializedViewHandler)materializedViewHandler).processCreateMaterializedView(stmt,
 db, olapTable);
+        } finally {
+            db.writeUnlock();
+        }
+    }
 
+    public void processDropMaterializedView(DropMaterializedViewStmt stmt) 
throws DdlException, MetaNotFoundException {
+        // check db
+        String dbName = stmt.getTableName().getDb();
+        Database db = Catalog.getInstance().getDb(dbName);
+        if (db == null) {
+            ErrorReport.reportDdlException(ErrorCode.ERR_BAD_DB_ERROR, dbName);
+        }
+
+        db.writeLock();
+        try {
+            String tableName = stmt.getTableName().getTbl();
+            Table table = db.getTable(tableName);
+            // if table exists
+            if (table == null) {
+                ErrorReport.reportDdlException(ErrorCode.ERR_BAD_TABLE_ERROR, 
tableName);
+            }
+            // check table type
+            if (table.getType() != TableType.OLAP) {
+                throw new DdlException("Do not support non-OLAP table [" + 
tableName + "] when drop materialized view");
+            }
+            // check table state
+            OlapTable olapTable = (OlapTable) table;
             if (olapTable.getState() != OlapTableState.NORMAL) {
                 throw new DdlException("Table[" + table.getName() + "]'s state 
is not NORMAL. "
-                                               + "Do not allow doing 
materialized view");
-            }
-            // 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;'.");
+                        + "Do not allow doing DROP ops");
             }
 
-            
((MaterializedViewHandler)materializedViewHandler).processCreateMaterializedView(stmt,
 db, olapTable);
+            // drop materialized view
+            
((MaterializedViewHandler)materializedViewHandler).processDropMaterializedView(stmt,
 db, olapTable);
+
         } finally {
             db.writeUnlock();
         }
diff --git 
a/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java 
b/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java
index 23724f8..f333dbb 100644
--- a/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java
+++ b/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java
@@ -23,6 +23,7 @@ import org.apache.doris.analysis.AlterClause;
 import org.apache.doris.analysis.CancelAlterTableStmt;
 import org.apache.doris.analysis.CancelStmt;
 import org.apache.doris.analysis.CreateMaterializedViewStmt;
+import org.apache.doris.analysis.DropMaterializedViewStmt;
 import org.apache.doris.analysis.DropRollupClause;
 import org.apache.doris.analysis.MVColumnItem;
 import org.apache.doris.catalog.AggregateType;
@@ -46,6 +47,7 @@ import org.apache.doris.common.DdlException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.FeConstants;
+import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.util.ListComparator;
 import org.apache.doris.common.util.PropertyAnalyzer;
 import org.apache.doris.common.util.Util;
@@ -638,68 +640,31 @@ public class MaterializedViewHandler extends AlterHandler 
{
         return baseIndexId;
     }
 
-    public void processBatchDropRollup(List<AlterClause> dropRollupClauses, 
Database db, OlapTable olapTable) throws DdlException {
+    public void processBatchDropRollup(List<AlterClause> dropRollupClauses, 
Database db, OlapTable olapTable)
+            throws DdlException, MetaNotFoundException {
         db.writeLock();
         try {
-            // just for log
-            Set<String> rollupNameSet = new HashSet<>();
-            Preconditions.checkState(olapTable.getState() == 
OlapTableState.NORMAL, olapTable.getState().name());
-            TabletInvertedIndex invertedIndex = 
Catalog.getCurrentInvertedIndex();
-            long dbId = db.getId();
-            long tableId = olapTable.getId();
-
             // check drop rollup index operation
             for (AlterClause alterClause : dropRollupClauses) {
                 DropRollupClause dropRollupClause = (DropRollupClause) 
alterClause;
-
-                // make sure we got db write lock here.
-                // up to here, table's state can only be NORMAL.
-                String rollupIndexName = dropRollupClause.getRollupName();
-                if (rollupIndexName.equals(olapTable.getName())) {
-                    throw new DdlException("Cannot drop base index by using 
DROP ROLLUP.");
-                }
-
-                if (!olapTable.hasMaterializedIndex(rollupIndexName)) {
-                    throw new DdlException("Rollup index[" + rollupIndexName + 
"] does not exist in table["
-                            + olapTable.getName() + "]");
-                }
-
-                long rollupIndexId = 
olapTable.getIndexIdByName(rollupIndexName);
-                int rollupSchemaHash = 
olapTable.getSchemaHashByIndexId(rollupIndexId);
-                Preconditions.checkState(rollupSchemaHash != -1);
-
-                for (Partition partition : olapTable.getPartitions()) {
-                    MaterializedIndex rollupIndex = 
partition.getIndex(rollupIndexId);
-                    Preconditions.checkNotNull(rollupIndex);
-                }
-
+                checkDropMaterializedView(dropRollupClause.getRollupName(), 
olapTable);
             }
 
-            Set<Long> indexIdSet = new HashSet<>();
             // drop data in memory
+            Set<Long> indexIdSet = new HashSet<>();
+            Set<String> rollupNameSet = new HashSet<>();
             for (AlterClause alterClause : dropRollupClauses) {
                 DropRollupClause dropRollupClause = (DropRollupClause) 
alterClause;
                 String rollupIndexName = dropRollupClause.getRollupName();
-
-                long rollupIndexId = 
olapTable.getIndexIdByName(rollupIndexName);
-                for (Partition partition : olapTable.getPartitions()) {
-                    MaterializedIndex rollupIndex = 
partition.getIndex(rollupIndexId);
-                    // delete rollup index
-                    partition.deleteRollupIndex(rollupIndexId);
-                    // remove tablets from inverted index
-                    for (Tablet tablet : rollupIndex.getTablets()) {
-                        long tabletId = tablet.getId();
-                        invertedIndex.deleteTablet(tabletId);
-                    }
-                }
-                olapTable.deleteIndexInfo(rollupIndexName);
-
+                long rollupIndexId = dropMaterializedView(rollupIndexName, 
olapTable);
                 indexIdSet.add(rollupIndexId);
                 rollupNameSet.add(rollupIndexName);
             }
 
             // batch log drop rollup operation
             EditLog editLog = Catalog.getInstance().getEditLog();
+            long dbId = db.getId();
+            long tableId = olapTable.getId();
             editLog.logBatchDropRollup(new BatchDropInfo(dbId, tableId, 
indexIdSet));
             LOG.info("finished drop rollup index[{}] in table[{}]", 
String.join("", rollupNameSet), olapTable.getName());
         } finally {
@@ -707,6 +672,83 @@ public class MaterializedViewHandler extends AlterHandler {
         }
     }
 
+    public void processDropMaterializedView(DropMaterializedViewStmt 
dropMaterializedViewStmt, Database db,
+            OlapTable olapTable) throws DdlException, MetaNotFoundException {
+        db.writeLock();
+        try {
+            String mvName = dropMaterializedViewStmt.getMvName();
+            // Step1: check drop mv index operation
+            checkDropMaterializedView(mvName, olapTable);
+            // Step2; drop data in memory
+            long mvIndexId = dropMaterializedView(mvName, olapTable);
+            // Step3: log drop mv operation
+            EditLog editLog = Catalog.getInstance().getEditLog();
+            editLog.logDropRollup(new DropInfo(db.getId(), olapTable.getId(), 
mvIndexId));
+            LOG.info("finished drop materialized view [{}] in table [{}]", 
mvName, olapTable.getName());
+        } catch (MetaNotFoundException e) {
+            if (dropMaterializedViewStmt.isIfExists()) {
+                LOG.info(e.getMessage());
+            } else {
+                throw e;
+            }
+        } finally {
+            db.writeUnlock();
+        }
+    }
+
+    /**
+     * Make sure we got db write lock before using this method.
+     * Up to here, table's state can only be NORMAL.
+     *
+     * @param mvName
+     * @param olapTable
+     */
+    private void checkDropMaterializedView(String mvName, OlapTable olapTable)
+            throws DdlException, MetaNotFoundException {
+        Preconditions.checkState(olapTable.getState() == 
OlapTableState.NORMAL, olapTable.getState().name());
+        if (mvName.equals(olapTable.getName())) {
+            throw new DdlException("Cannot drop base index by using DROP 
ROLLUP or DROP MATERIALIZED VIEW.");
+        }
+
+        if (!olapTable.hasMaterializedIndex(mvName)) {
+            throw new MetaNotFoundException(
+                    "Materialized view [" + mvName + "] does not exist in 
table [" + olapTable.getName() + "]");
+        }
+
+        long mvIndexId = olapTable.getIndexIdByName(mvName);
+        int mvSchemaHash = olapTable.getSchemaHashByIndexId(mvIndexId);
+        Preconditions.checkState(mvSchemaHash != -1);
+
+        for (Partition partition : olapTable.getPartitions()) {
+            MaterializedIndex materializedIndex = 
partition.getIndex(mvIndexId);
+            Preconditions.checkNotNull(materializedIndex);
+        }
+    }
+
+    /**
+     * Return mv index id which has been dropped
+     *
+     * @param mvName
+     * @param olapTable
+     * @return
+     */
+    private long dropMaterializedView(String mvName, OlapTable olapTable) {
+        long mvIndexId = olapTable.getIndexIdByName(mvName);
+        TabletInvertedIndex invertedIndex = Catalog.getCurrentInvertedIndex();
+        for (Partition partition : olapTable.getPartitions()) {
+            MaterializedIndex rollupIndex = partition.getIndex(mvIndexId);
+            // delete rollup index
+            partition.deleteRollupIndex(mvIndexId);
+            // remove tablets from inverted index
+            for (Tablet tablet : rollupIndex.getTablets()) {
+                long tabletId = tablet.getId();
+                invertedIndex.deleteTablet(tabletId);
+            }
+        }
+        olapTable.deleteIndexInfo(mvName);
+        return mvIndexId;
+    }
+
     public void replayDropRollup(DropInfo dropInfo, Catalog catalog) {
         Database db = catalog.getDb(dropInfo.getDbId());
         db.writeLock();
@@ -1045,7 +1087,7 @@ public class MaterializedViewHandler extends AlterHandler 
{
 
     @Override
     public void process(List<AlterClause> alterClauses, String clusterName, 
Database db, OlapTable olapTable)
-            throws DdlException, AnalysisException {
+            throws DdlException, AnalysisException, MetaNotFoundException {
 
         if (olapTable.existTempPartitions()) {
             throw new DdlException("Can not alter table when there are temp 
partitions in table");
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java 
b/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java
index 698b3b7..d73bbd1 100644
--- a/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java
@@ -29,7 +29,6 @@ import org.apache.doris.common.UserException;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 import java.util.List;
@@ -135,8 +134,8 @@ public class CreateMaterializedViewStmt extends DdlStmt {
             throw new AnalysisException("The materialized view must contain at 
least one column");
         }
         boolean meetAggregate = false;
-        Set<String> mvKeyColumnNameSet = Sets.newHashSet();
-        Map<String, Set<String>> mvAggColumnNameToFunctionNames = 
Maps.newHashMap();
+        // TODO(ml): support same column with different aggregation function
+        Set<String> mvColumnNameSet = Sets.newHashSet();
         /**
          * 1. The columns of mv must be a single column or a aggregate column 
without any calculate.
          *    Also the children of aggregate column must be a single column 
without any calculate.
@@ -158,9 +157,9 @@ public class CreateMaterializedViewStmt extends DdlStmt {
                     throw new AnalysisException("The aggregate column should 
be after the single column");
                 }
                 SlotRef slotRef = (SlotRef) selectListItem.getExpr();
+                // check duplicate column
                 String columnName = slotRef.getColumnName().toLowerCase();
-                // check duplicate key
-                if (!mvKeyColumnNameSet.add(columnName)) {
+                if (!mvColumnNameSet.add(columnName)) {
                     
ErrorReport.reportAnalysisException(ErrorCode.ERR_DUP_FIELDNAME, columnName);
                 }
                 MVColumnItem mvColumnItem = new MVColumnItem(columnName);
@@ -189,19 +188,11 @@ public class CreateMaterializedViewStmt extends DdlStmt {
                                                         + "Error function: " + 
functionCallExpr.toSqlImpl());
                 }
                 meetAggregate = true;
-                // check duplicate value
+                // check duplicate column
                 String columnName = slotRef.getColumnName().toLowerCase();
-                if (mvKeyColumnNameSet.contains(columnName)) {
+                if (!mvColumnNameSet.add(columnName)) {
                     
ErrorReport.reportAnalysisException(ErrorCode.ERR_DUP_FIELDNAME, columnName);
                 }
-                Set<String> functionNames = 
mvAggColumnNameToFunctionNames.get(columnName);
-                if (functionNames == null) {
-                    functionNames = Sets.newHashSet();
-                }
-                if (!functionNames.add(functionName.toLowerCase())) {
-                    
ErrorReport.reportAnalysisException(ErrorCode.ERR_DUP_FIELDNAME, columnName);
-                }
-                mvAggColumnNameToFunctionNames.put(columnName, functionNames);
 
                 if (beginIndexOfAggregation == -1) {
                     beginIndexOfAggregation = i;
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/DropMaterializedViewStmt.java 
b/fe/src/main/java/org/apache/doris/analysis/DropMaterializedViewStmt.java
new file mode 100644
index 0000000..e416444
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/analysis/DropMaterializedViewStmt.java
@@ -0,0 +1,88 @@
+// 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.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.UserException;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
+
+import com.google.common.base.Strings;
+
+/**
+ * DROP MATERIALIZE VIEW [ IF EXISTS ] <mv_name> ON [db_name].<table_name>
+ *
+ * Parameters
+ * IF EXISTS: Do not throw an error if the materialized view does not exist. A 
notice is issued in this case.
+ * mv_name: The name of the materialized view to remove.
+ * db_name: The name of db to which materialized view belongs.
+ * table_name: The name of table to which materialized view belongs.
+ */
+public class DropMaterializedViewStmt extends DdlStmt {
+
+    private String mvName;
+    private TableName tableName;
+    private boolean ifExists;
+
+    public DropMaterializedViewStmt(boolean ifExists, String mvName, TableName 
tableName) {
+        this.mvName = mvName;
+        this.tableName = tableName;
+        this.ifExists = ifExists;
+    }
+
+    public String getMvName() {
+        return mvName;
+    }
+
+    public TableName getTableName() {
+        return tableName;
+    }
+
+    public boolean isIfExists() {
+        return ifExists;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+        if (Strings.isNullOrEmpty(mvName)) {
+            throw new AnalysisException("The materialized name could not be 
empty or null.");
+        }
+        tableName.analyze(analyzer);
+
+        // check access
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkTblPriv(ConnectContext.get(), 
tableName.getDb(),
+                tableName.getTbl(), PrivPredicate.DROP)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"DROP");
+        }
+    }
+
+    @Override
+    public String toSql() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("DROP MATERIALIZED VIEW ");
+        if (ifExists) {
+            stringBuilder.append("IF EXISTS ");
+        }
+        stringBuilder.append("`").append(mvName).append("` ");
+        stringBuilder.append("ON ").append(tableName.toSql());
+        return stringBuilder.toString();
+    }
+}
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 6e43668..222990f 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -54,6 +54,7 @@ import org.apache.doris.analysis.DistributionDesc;
 import org.apache.doris.analysis.DropClusterStmt;
 import org.apache.doris.analysis.DropDbStmt;
 import org.apache.doris.analysis.DropFunctionStmt;
+import org.apache.doris.analysis.DropMaterializedViewStmt;
 import org.apache.doris.analysis.DropPartitionClause;
 import org.apache.doris.analysis.DropTableStmt;
 import org.apache.doris.analysis.FunctionName;
@@ -105,6 +106,7 @@ import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.FeConstants;
 import org.apache.doris.common.FeMetaVersion;
 import org.apache.doris.common.MarkedCountDownLatch;
+import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.Pair;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.io.Text;
@@ -4894,6 +4896,10 @@ public class Catalog {
         this.alter.processCreateMaterializedView(stmt);
     }
 
+    public void dropMaterializedView(DropMaterializedViewStmt stmt) throws 
DdlException, MetaNotFoundException {
+        this.alter.processDropMaterializedView(stmt);
+    }
+
     /*
      * used for handling CacnelAlterStmt (for client is the CANCEL ALTER
      * command). including SchemaChangeHandler and RollupHandler
diff --git a/fe/src/main/java/org/apache/doris/catalog/OlapTable.java 
b/fe/src/main/java/org/apache/doris/catalog/OlapTable.java
index 56b1a1f..595b8a7 100644
--- a/fe/src/main/java/org/apache/doris/catalog/OlapTable.java
+++ b/fe/src/main/java/org/apache/doris/catalog/OlapTable.java
@@ -1066,6 +1066,24 @@ public class OlapTable extends Table {
         return dataSize;
     }
 
+    public void checkStableAndNormal(String clusterName) throws DdlException {
+        if (state != OlapTableState.NORMAL) {
+            throw new DdlException("Table[" + name + "]'s state is not NORMAL. 
"
+                    + "Do not allow doing materialized view");
+        }
+        // check if all tablets are healthy, and no tablet is in tablet 
scheduler
+        boolean isStable = isStable(Catalog.getCurrentSystemInfo(),
+                Catalog.getCurrentCatalog().getTabletScheduler(),
+                clusterName);
+        if (!isStable) {
+            throw new DdlException("table [" + name + "] 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;'.");
+        }
+    }
+
     public boolean isStable(SystemInfoService infoService, TabletScheduler 
tabletScheduler, String clusterName) {
         int availableBackendsNum = 
infoService.getClusterBackendIds(clusterName, true).size();
         for (Partition partition : idToPartition.values()) {
diff --git a/fe/src/main/java/org/apache/doris/qe/DdlExecutor.java 
b/fe/src/main/java/org/apache/doris/qe/DdlExecutor.java
index ac2a0db..188c1f8 100644
--- a/fe/src/main/java/org/apache/doris/qe/DdlExecutor.java
+++ b/fe/src/main/java/org/apache/doris/qe/DdlExecutor.java
@@ -49,6 +49,7 @@ import org.apache.doris.analysis.DropClusterStmt;
 import org.apache.doris.analysis.DropDbStmt;
 import org.apache.doris.analysis.DropFileStmt;
 import org.apache.doris.analysis.DropFunctionStmt;
+import org.apache.doris.analysis.DropMaterializedViewStmt;
 import org.apache.doris.analysis.DropRepositoryStmt;
 import org.apache.doris.analysis.DropRoleStmt;
 import org.apache.doris.analysis.DropTableStmt;
@@ -101,6 +102,8 @@ public class DdlExecutor {
             catalog.dropTable((DropTableStmt) ddlStmt);
         } else if (ddlStmt instanceof CreateMaterializedViewStmt) {
             catalog.createMaterializedView((CreateMaterializedViewStmt) 
ddlStmt);
+        } else if (ddlStmt instanceof DropMaterializedViewStmt) {
+            catalog.dropMaterializedView((DropMaterializedViewStmt) ddlStmt);
         } else if (ddlStmt instanceof AlterTableStmt) {
             catalog.alterTable((AlterTableStmt) ddlStmt);
         } else if (ddlStmt instanceof AlterViewStmt) {
diff --git 
a/fe/src/test/java/org/apache/doris/alter/MaterializedViewHandlerTest.java 
b/fe/src/test/java/org/apache/doris/alter/MaterializedViewHandlerTest.java
index 3ae3879..585d78b 100644
--- a/fe/src/test/java/org/apache/doris/alter/MaterializedViewHandlerTest.java
+++ b/fe/src/test/java/org/apache/doris/alter/MaterializedViewHandlerTest.java
@@ -273,4 +273,35 @@ public class MaterializedViewHandlerTest {
         }
     }
 
+    @Test
+    public void testCheckDropMaterializedView(@Injectable OlapTable olapTable, 
@Injectable Partition partition,
+            @Injectable MaterializedIndex materializedIndex) {
+        String mvName = "mv_1";
+        new Expectations() {
+            {
+                olapTable.getState();
+                result = OlapTable.OlapTableState.NORMAL;
+                olapTable.getName();
+                result = "table1";
+                olapTable.hasMaterializedIndex(mvName);
+                result = true;
+                olapTable.getIndexIdByName(mvName);
+                result = 1L;
+                olapTable.getSchemaHashByIndexId(1L);
+                result = 1;
+                olapTable.getPartitions();
+                result = Lists.newArrayList(partition);
+                partition.getIndex(1L);
+                result = materializedIndex;
+            }
+        };
+        MaterializedViewHandler materializedViewHandler = new 
MaterializedViewHandler();
+        try {
+            Deencapsulation.invoke(materializedViewHandler, 
"checkDropMaterializedView", mvName, olapTable);
+        } catch (Exception e) {
+            Assert.fail(e.getMessage());
+        }
+
+    }
+
 }
diff --git 
a/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
 
b/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
index 5e58630..de6c5a3 100644
--- 
a/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
+++ 
b/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
@@ -252,8 +252,7 @@ public class CreateMaterializedViewStmtTest {
                                            @Injectable SlotRef slotRef2,
                                            @Injectable FunctionCallExpr 
functionCallExpr,
                                            @Injectable TableRef tableRef,
-                                           @Injectable SelectStmt selectStmt,
-            @Injectable GroupByClause groupByClause) throws UserException {
+                                           @Injectable SelectStmt selectStmt) 
throws UserException {
         SelectList selectList = new SelectList();
         SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
         selectList.addItem(selectListItem1);
@@ -262,8 +261,6 @@ public class CreateMaterializedViewStmtTest {
         OrderByElement orderByElement1 = new OrderByElement(functionCallExpr, 
false, false);
         OrderByElement orderByElement2 = new OrderByElement(slotRef1, false, 
false);
         ArrayList<OrderByElement> orderByElementList = 
Lists.newArrayList(orderByElement1, orderByElement2);
-        List<Expr> groupByList = Lists.newArrayList();
-        groupByList.add(slotRef1);
 
         new Expectations() {
             {
@@ -338,13 +335,58 @@ public class CreateMaterializedViewStmtTest {
     }
 
     @Test
+    public void testDuplicateColumn1(@Injectable SlotRef slotRef1, @Injectable 
SlotRef slotRef2,
+            @Injectable FunctionCallExpr functionCallExpr1, @Injectable 
FunctionCallExpr functionCallExpr2,
+            @Injectable SelectStmt selectStmt) throws UserException {
+        SelectList selectList = new SelectList();
+        SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
+        selectList.addItem(selectListItem1);
+        SelectListItem selectListItem2 = new SelectListItem(functionCallExpr1, 
null);
+        selectList.addItem(selectListItem2);
+        SelectListItem selectListItem3 = new SelectListItem(functionCallExpr2, 
null);
+        selectList.addItem(selectListItem3);
+
+        new Expectations() {
+            {
+                analyzer.getClusterName();
+                result = "default";
+                selectStmt.analyze(analyzer);
+                selectStmt.getSelectList();
+                result = selectList;
+                slotRef1.getColumnName();
+                result = "k1";
+                slotRef2.getColumnName();
+                result = "k2";
+                functionCallExpr1.getFnName().getFunction();
+                result = "sum";
+                functionCallExpr1.getChildren();
+                result = Lists.newArrayList(slotRef2);
+                functionCallExpr1.getChild(0);
+                result = slotRef2;
+                functionCallExpr2.getFnName().getFunction();
+                result = "max";
+                functionCallExpr2.getChildren();
+                result = Lists.newArrayList(slotRef2);
+                functionCallExpr2.getChild(0);
+                result = slotRef2;
+            }
+        };
+        CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
+        try {
+            createMaterializedViewStmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            System.out.print(e.getMessage());
+        }
+    }
+
+    @Test
     public void testOrderByColumnsLessThenGroupByColumns(@Injectable SlotRef 
slotRef1,
                                                          @Injectable SlotRef 
slotRef2,
                                                          @Injectable 
FunctionCallExpr functionCallExpr,
                                                          @Injectable SlotRef 
functionChild0,
                                                          @Injectable TableRef 
tableRef,
-                                                         @Injectable 
SelectStmt selectStmt,
-            @Injectable GroupByClause groupByClause) throws UserException {
+                                                         @Injectable 
SelectStmt selectStmt) throws UserException {
         SelectList selectList = new SelectList();
         SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
         selectList.addItem(selectListItem1);
@@ -355,11 +397,6 @@ public class CreateMaterializedViewStmtTest {
         OrderByElement orderByElement1 = new OrderByElement(slotRef1, false, 
false);
         ArrayList<OrderByElement> orderByElementList = 
Lists.newArrayList(orderByElement1);
 
-
-        List<Expr> groupByList = Lists.newArrayList();
-        groupByList.add(slotRef1);
-        groupByList.add(slotRef2);
-
         new Expectations() {
             {
                 analyzer.getClusterName();
@@ -407,7 +444,7 @@ public class CreateMaterializedViewStmtTest {
                                             @Injectable SlotRef functionChild0,
                                             @Injectable TableRef tableRef,
                                             @Injectable SelectStmt selectStmt,
-            @Injectable GroupByClause groupByClause) throws UserException {
+            @Injectable AggregateInfo aggregateInfo) throws UserException {
         SelectList selectList = new SelectList();
         SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
         selectList.addItem(selectListItem1);
@@ -426,14 +463,12 @@ public class CreateMaterializedViewStmtTest {
         final String columnName4 = "v1";
         final String columnName5 = "sum_v2";
 
-        List<Expr> groupByList = Lists.newArrayList();
-        groupByList.add(slotRef1);
-        groupByList.add(slotRef2);
-        groupByList.add(slotRef3);
         new Expectations() {
             {
                 analyzer.getClusterName();
                 result = "default";
+                selectStmt.getAggInfo();
+                result = aggregateInfo;
                 selectStmt.getSelectList();
                 result = selectList;
                 selectStmt.getTableRefs();
@@ -470,6 +505,7 @@ public class CreateMaterializedViewStmtTest {
         CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
         try {
             createMaterializedViewStmt.analyze(analyzer);
+            Assert.assertEquals(KeysType.AGG_KEYS, 
createMaterializedViewStmt.getMVKeysType());
             List<MVColumnItem> mvColumns = 
createMaterializedViewStmt.getMVColumnItemList();
             Assert.assertEquals(5, mvColumns.size());
             MVColumnItem mvColumn0 = mvColumns.get(0);
@@ -525,6 +561,8 @@ public class CreateMaterializedViewStmtTest {
             {
                 analyzer.getClusterName();
                 result = "default";
+                selectStmt.getAggInfo();
+                result = null;
                 selectStmt.getSelectList();
                 result = selectList;
                 selectStmt.getTableRefs();
@@ -565,6 +603,7 @@ public class CreateMaterializedViewStmtTest {
         CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
         try {
             createMaterializedViewStmt.analyze(analyzer);
+            Assert.assertEquals(KeysType.DUP_KEYS, 
createMaterializedViewStmt.getMVKeysType());
             List<MVColumnItem> mvColumns = 
createMaterializedViewStmt.getMVColumnItemList();
             Assert.assertEquals(4, mvColumns.size());
             MVColumnItem mvColumn0 = mvColumns.get(0);
@@ -599,7 +638,7 @@ public class CreateMaterializedViewStmtTest {
             @Injectable SlotRef functionChild0,
             @Injectable TableRef tableRef,
             @Injectable SelectStmt selectStmt,
-            @Injectable GroupByClause groupByClause) throws UserException {
+            @Injectable AggregateInfo aggregateInfo) throws UserException {
         SelectList selectList = new SelectList();
         SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
         selectList.addItem(selectListItem1);
@@ -613,13 +652,12 @@ public class CreateMaterializedViewStmtTest {
         final String columnName1 = "k1";
         final String columnName2 = "v1";
         final String columnName3 = "sum_v2";
-        List<Expr> groupByList = Lists.newArrayList();
-        groupByList.add(slotRef1);
-        groupByList.add(slotRef2);
         new Expectations() {
             {
                 analyzer.getClusterName();
                 result = "default";
+                selectStmt.getAggInfo();
+                result = aggregateInfo;
                 selectStmt.getSelectList();
                 result = selectList;
                 selectStmt.getTableRefs();
@@ -651,6 +689,7 @@ public class CreateMaterializedViewStmtTest {
         CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
         try {
             createMaterializedViewStmt.analyze(analyzer);
+            Assert.assertEquals(KeysType.AGG_KEYS, 
createMaterializedViewStmt.getMVKeysType());
             List<MVColumnItem> mvColumns = 
createMaterializedViewStmt.getMVColumnItemList();
             Assert.assertEquals(3, mvColumns.size());
             MVColumnItem mvColumn0 = mvColumns.get(0);
@@ -679,17 +718,17 @@ public class CreateMaterializedViewStmtTest {
     public void testDeduplicateMV(@Injectable SlotRef slotRef1,
             @Injectable TableRef tableRef,
             @Injectable SelectStmt selectStmt,
-            @Injectable GroupByClause groupByClause) throws UserException {
+            @Injectable AggregateInfo aggregateInfo) throws UserException {
         SelectList selectList = new SelectList();
         SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
         selectList.addItem(selectListItem1);
         final String columnName1 = "k1";
-        List<Expr> groupByList = Lists.newArrayList();
-        groupByList.add(slotRef1);
         new Expectations() {
             {
                 analyzer.getClusterName();
                 result = "default";
+                selectStmt.getAggInfo();
+                result = aggregateInfo;
                 selectStmt.getSelectList();
                 result = selectList;
                 selectStmt.analyze(analyzer);
@@ -709,7 +748,7 @@ public class CreateMaterializedViewStmtTest {
         CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
         try {
             createMaterializedViewStmt.analyze(analyzer);
-            Assert.assertTrue(KeysType.AGG_KEYS == 
createMaterializedViewStmt.getMVKeysType());
+            Assert.assertEquals(KeysType.AGG_KEYS, 
createMaterializedViewStmt.getMVKeysType());
             List<MVColumnItem> mvSchema = 
createMaterializedViewStmt.getMVColumnItemList();
             Assert.assertEquals(1, mvSchema.size());
             Assert.assertTrue(mvSchema.get(0).isKey());
diff --git 
a/fe/src/test/java/org/apache/doris/analysis/DropMaterializedViewStmtTest.java 
b/fe/src/test/java/org/apache/doris/analysis/DropMaterializedViewStmtTest.java
new file mode 100644
index 0000000..068a031
--- /dev/null
+++ 
b/fe/src/test/java/org/apache/doris/analysis/DropMaterializedViewStmtTest.java
@@ -0,0 +1,69 @@
+// 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.common.ErrorCode;
+import org.apache.doris.common.UserException;
+import org.apache.doris.mysql.privilege.PaloAuth;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import mockit.Expectations;
+import mockit.Injectable;
+import mockit.Mocked;
+
+public class DropMaterializedViewStmtTest {
+
+    @Mocked
+    Analyzer analyzer;
+    @Mocked
+    PaloAuth paloAuth;
+
+    @Test
+    public void testEmptyMVName(@Injectable TableName tableName) {
+        DropMaterializedViewStmt stmt = new DropMaterializedViewStmt(false, 
"", tableName);
+        try {
+            stmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            Assert.assertTrue(e.getMessage().contains("could not be empty"));
+        }
+    }
+
+    @Test
+    public void testNoPermission(@Injectable TableName tableName) {
+        new Expectations() {
+            {
+                paloAuth.checkTblPriv(ConnectContext.get(), tableName.getDb(),
+                        tableName.getTbl(), PrivPredicate.DROP);
+                result = false;
+            }
+        };
+        DropMaterializedViewStmt stmt = new DropMaterializedViewStmt(false, 
"test", tableName);
+        try {
+            stmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            Assert.assertTrue(e.getMessage().contains("Access denied;"));
+        }
+
+    }
+}
diff --git 
a/fe/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java 
b/fe/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java
index 80e6ad4..43be8db 100644
--- 
a/fe/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java
+++ 
b/fe/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java
@@ -135,8 +135,8 @@ public class MaterializedViewFunctionTest {
 
     @Test
     public void testAggQueryOnAggMV1() throws Exception {
-        String createMVSQL = "create materialized view " + EMPS_MV_NAME + " as 
select deptno, sum(salary), max" + ""
-                + "(salary) from " + EMPS_TABLE_NAME + " group by deptno;";
+        String createMVSQL = "create materialized view " + EMPS_MV_NAME + " as 
select deptno, sum(salary), "
+                + "max(commission) from " + EMPS_TABLE_NAME + " group by 
deptno;";
         String query = "select sum(salary), deptno from " + EMPS_TABLE_NAME + 
" group by deptno;";
         
dorisAssert.withMaterializedView(createMVSQL).query(query).explainContains(QUERY_USE_EMPS_MV);
     }


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

Reply via email to