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