From 045bfcfe3236ba5502086b91546fe94d88ca1627 Mon Sep 17 00:00:00 2001 From: msridhar78 Date: Thu, 14 Nov 2024 07:59:45 +0530 Subject: [PATCH] [Enhancement] (nereids)implement showMaterializedViewCommand in nereids (#43152) Issue Number: close #42738 implement showMaterializedViewCommand in nereids --- .../org/apache/doris/nereids/DorisParser.g4 | 6 +- .../nereids/parser/LogicalPlanBuilder.java | 7 ++ .../doris/nereids/trees/plans/PlanType.java | 1 + .../ShowCreateMaterializedViewCommand.java | 108 ++++++++++++++++++ .../plans/commands/info/TableNameInfo.java | 15 +++ .../trees/plans/visitor/CommandVisitor.java | 6 + .../test_show_create_materialized_view.out | 4 + .../test_show_create_materialized_view.groovy | 47 ++++++++ 8 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateMaterializedViewCommand.java create mode 100644 regression-test/data/query_p0/show/test_show_create_materialized_view.out create mode 100644 regression-test/suites/query_p0/show/test_show_create_materialized_view.groovy diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 8eedc739f28ac1..3e05afb878a0b6 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -198,6 +198,8 @@ supportedShowStatement ((FROM | IN) database=identifier)? #showView | SHOW ROLES #showRoles | SHOW PROC path=STRING_LITERAL #showProc + | SHOW CREATE MATERIALIZED VIEW mvName=identifier + ON tableName=multipartIdentifier #showCreateMaterializedView ; unsupportedOtherStatement @@ -317,9 +319,7 @@ unsupportedShowStatement | SHOW ENCRYPTKEYS ((FROM | IN) database=multipartIdentifier)? wildWhere? #showEncryptKeys | SHOW SYNC JOB ((FROM | IN) database=multipartIdentifier)? #showSyncJob | SHOW TABLE CREATION ((FROM | IN) database=multipartIdentifier)? wildWhere? #showTableCreation - | SHOW LAST INSERT #showLastInsert - | SHOW CREATE MATERIALIZED VIEW mvName=identifier - ON tableName=multipartIdentifier #showCreateMaterializedView + | SHOW LAST INSERT #showLastInsert | SHOW CATALOG RECYCLE BIN wildWhere? #showCatalogRecycleBin | SHOW QUERY STATS ((FOR database=identifier) | (FROM tableName=multipartIdentifier (ALL VERBOSE?)?))? #showQueryStats diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 156df4333d5f28..f9603e516872ee 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -195,6 +195,7 @@ import org.apache.doris.nereids.DorisParser.ShowConfigContext; import org.apache.doris.nereids.DorisParser.ShowConstraintContext; import org.apache.doris.nereids.DorisParser.ShowCreateMTMVContext; +import org.apache.doris.nereids.DorisParser.ShowCreateMaterializedViewContext; import org.apache.doris.nereids.DorisParser.ShowCreateProcedureContext; import org.apache.doris.nereids.DorisParser.ShowProcContext; import org.apache.doris.nereids.DorisParser.ShowProcedureStatusContext; @@ -429,6 +430,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowConfigCommand; import org.apache.doris.nereids.trees.plans.commands.ShowConstraintsCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowCreateMaterializedViewCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand; @@ -4074,4 +4076,9 @@ public LogicalPlan visitShowProc(ShowProcContext ctx) { String path = stripQuotes(ctx.path.getText()); return new ShowProcCommand(path); } + + public LogicalPlan visitShowCreateMaterializedView(ShowCreateMaterializedViewContext ctx) { + List nameParts = visitMultipartIdentifier(ctx.tableName); + return new ShowCreateMaterializedViewCommand(stripQuotes(ctx.mvName.getText()), new TableNameInfo(nameParts)); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index b3c402daa9a1f2..9c4e66d206cedb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -176,6 +176,7 @@ public enum PlanType { PREPARED_COMMAND, EXECUTE_COMMAND, SHOW_CONFIG_COMMAND, + SHOW_CREATE_MATERIALIZED_VIEW_COMMAND, SHOW_PROC_COMMAND, SHOW_ROLE_COMMAND, SHOW_VARIABLES_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateMaterializedViewCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateMaterializedViewCommand.java new file mode 100644 index 00000000000000..4e8c74dba28e3f --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateMaterializedViewCommand.java @@ -0,0 +1,108 @@ +// 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.nereids.trees.plans.commands; + +import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Database; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.MaterializedIndexMeta; +import org.apache.doris.catalog.OlapTable; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.catalog.Table; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.util.Util; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.commands.info.TableNameInfo; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ShowResultSet; +import org.apache.doris.qe.ShowResultSetMetaData; +import org.apache.doris.qe.StmtExecutor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents the command for SHOW CREATE MATERIALIZED VIEW. + */ +public class ShowCreateMaterializedViewCommand extends ShowCommand { + private static final ShowResultSetMetaData MATERIALIZED_VIEW_META_DATA = + ShowResultSetMetaData.builder() + .addColumn(new Column("TableName", ScalarType.createVarchar(20))) + .addColumn(new Column("ViewName", ScalarType.createVarchar(30))) + .addColumn(new Column("CreateStmt", ScalarType.createVarchar(500))) + .build(); + + private final String mvName; + private final TableNameInfo tblNameInfo; + + public ShowCreateMaterializedViewCommand(String mvName, TableNameInfo tableNameInfo) { + super(PlanType.SHOW_CREATE_MATERIALIZED_VIEW_COMMAND); + this.tblNameInfo = tableNameInfo; + this.mvName = mvName; + } + + private void validate(ConnectContext ctx) throws AnalysisException { + tblNameInfo.analyze(ctx); + + // disallow external catalog + Util.prohibitExternalCatalog(tblNameInfo.getCtl(), this.getClass().getSimpleName()); + if (!Env.getCurrentEnv().getAccessManager() + .checkTblPriv(ConnectContext.get(), tblNameInfo.getCtl(), tblNameInfo.getDb(), tblNameInfo.getTbl(), + PrivPredicate.SHOW)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "SHOW CREATE MATERIALIZED", + ConnectContext.get().getQualifiedUser(), + ConnectContext.get().getRemoteIP(), + tblNameInfo.toSql()); + } + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowCreateMaterializedViewCommand(this, context); + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + validate(ctx); + + List> resultRowSet = new ArrayList<>(); + Database db = Env.getCurrentInternalCatalog().getDbOrAnalysisException(tblNameInfo.getDb()); + Table table = db.getTableOrAnalysisException(tblNameInfo.getTbl()); + if (table instanceof OlapTable) { + OlapTable baseTable = ((OlapTable) table); + Long indexIdByName = baseTable.getIndexIdByName(mvName); + if (indexIdByName != null) { + MaterializedIndexMeta meta = baseTable.getIndexMetaByIndexId(indexIdByName); + if (meta != null && meta.getDefineStmt() != null) { + String originStmt = meta.getDefineStmt().originStmt; + List data = new ArrayList<>(); + data.add(tblNameInfo.getTbl()); + data.add(mvName); + data.add(originStmt); + resultRowSet.add(data); + } + } + } + return new ShowResultSet(MATERIALIZED_VIEW_META_DATA, resultRowSet); + } +} + diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/TableNameInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/TableNameInfo.java index 5d0a42e9807191..a0bcc794b6be78 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/TableNameInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/TableNameInfo.java @@ -193,4 +193,19 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(tbl, db, ctl); } + + /** + * toSql + */ + public String toSql() { + StringBuilder stringBuilder = new StringBuilder(); + if (ctl != null && !ctl.equals(InternalCatalog.INTERNAL_CATALOG_NAME)) { + stringBuilder.append("`").append(ctl).append("`."); + } + if (db != null) { + stringBuilder.append("`").append(db).append("`."); + } + stringBuilder.append("`").append(tbl).append("`"); + return stringBuilder.toString(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java index 7d879a8efdf5a3..a74f9bde93a1fc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java @@ -51,6 +51,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowConfigCommand; import org.apache.doris.nereids.trees.plans.commands.ShowConstraintsCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowCreateMaterializedViewCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand; @@ -257,4 +258,9 @@ default R visitShowRolesCommand(ShowRolesCommand showRolesCommand, C context) { default R visitShowProcCommand(ShowProcCommand showProcCommand, C context) { return visitCommand(showProcCommand, context); } + + default R visitShowCreateMaterializedViewCommand(ShowCreateMaterializedViewCommand showCreateMtlzViewCommand, + C context) { + return visitCommand(showCreateMtlzViewCommand, context); + } } diff --git a/regression-test/data/query_p0/show/test_show_create_materialized_view.out b/regression-test/data/query_p0/show/test_show_create_materialized_view.out new file mode 100644 index 00000000000000..040ebf56f29fc5 --- /dev/null +++ b/regression-test/data/query_p0/show/test_show_create_materialized_view.out @@ -0,0 +1,4 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !cmd -- +table_for_mv_test mv_show_create_materialized_view CREATE MATERIALIZED VIEW mv_show_create_materialized_view AS\n SELECT id, name, SUM(value) AS total_value\n FROM table_for_mv_test\n GROUP BY id, name;\n + diff --git a/regression-test/suites/query_p0/show/test_show_create_materialized_view.groovy b/regression-test/suites/query_p0/show/test_show_create_materialized_view.groovy new file mode 100644 index 00000000000000..9550a7fec3dbd2 --- /dev/null +++ b/regression-test/suites/query_p0/show/test_show_create_materialized_view.groovy @@ -0,0 +1,47 @@ +// 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. + +suite("test_show_create_materialized_view", "query,arrow_flight_sql") { + String tableName = "table_for_mv_test"; + String mvName = "mv_show_create_materialized_view"; + try { + sql """DROP TABLE IF EXISTS ${tableName} """ + sql """ + CREATE TABLE IF NOT EXISTS ${tableName} ( + id INT COMMENT "Primary key", + name STRING COMMENT "Name field", + value DECIMAL(10, 2) COMMENT "Value field" + ) + DUPLICATE KEY(id) + DISTRIBUTED BY HASH(id) BUCKETS 5 + PROPERTIES ("replication_num" = "1"); + """ + + createMV("""CREATE MATERIALIZED VIEW ${mvName} AS + SELECT id, name, SUM(value) AS total_value + FROM ${tableName} + GROUP BY id, name; + """) + + checkNereidsExecute("""SHOW CREATE MATERIALIZED VIEW ${mvName} ON ${tableName};""") + qt_cmd("""SHOW CREATE MATERIALIZED VIEW ${mvName} ON ${tableName};""") + + } finally { + sql """DROP MATERIALIZED VIEW IF EXISTS ${mvName}""" + sql """DROP TABLE IF EXISTS ${tableName}""" + } +}