From b4db4c2beabc961c328467229d954eaa71e09bed Mon Sep 17 00:00:00 2001 From: Rijesh Kunhi Parambattu Date: Tue, 26 Nov 2024 22:32:27 +0530 Subject: [PATCH] [Enhancement] (nereids)implement showTableStatusCommand in nereids --- .../org/apache/doris/nereids/DorisParser.g4 | 2 +- .../nereids/parser/LogicalPlanBuilder.java | 28 +++ .../doris/nereids/trees/plans/PlanType.java | 1 + .../commands/ShowTableStatusCommand.java | 199 ++++++++++++++++++ .../trees/plans/visitor/CommandVisitor.java | 5 + .../test_nereids_show_table_status.groovy | 52 +++++ 6 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTableStatusCommand.java create mode 100644 regression-test/suites/nereids_p0/show/test_nereids_show_table_status.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 7e89accefca91be..74f9aa13dab3b45 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 @@ -301,6 +301,7 @@ supportedShowStatement (LIKE STRING_LITERAL)? #showTableCreation | SHOW TABLET STORAGE FORMAT VERBOSE? #showTabletStorageFormat | SHOW QUERY PROFILE queryIdPath=STRING_LITERAL #showQueryProfile + | SHOW TABLE STATUS ((FROM | IN) database=multipartIdentifier)? wildWhere? #showTableStatus ; supportedLoadStatement @@ -343,7 +344,6 @@ unsupportedShowStatement | SHOW STORAGE POLICY (USING (FOR policy=identifierOrText)?)? #showStoragePolicy | SHOW STORAGE (VAULT | VAULTS) #showStorageVault | SHOW OPEN TABLES ((FROM | IN) database=multipartIdentifier)? wildWhere? #showOpenTables - | SHOW TABLE STATUS ((FROM | IN) database=multipartIdentifier)? wildWhere? #showTableStatus | SHOW FULL? TABLES ((FROM | IN) database=multipartIdentifier)? wildWhere? #showTables | SHOW FULL? VIEWS ((FROM | IN) database=multipartIdentifier)? wildWhere? #showViews | SHOW CREATE MATERIALIZED VIEW name=multipartIdentifier #showMaterializedView 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 66ee9c33c093a89..9a0ade48c190f58 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 @@ -315,6 +315,7 @@ import org.apache.doris.nereids.DorisParser.ShowSyncJobContext; import org.apache.doris.nereids.DorisParser.ShowTableCreationContext; import org.apache.doris.nereids.DorisParser.ShowTableIdContext; +import org.apache.doris.nereids.DorisParser.ShowTableStatusContext; import org.apache.doris.nereids.DorisParser.ShowTabletStorageFormatContext; import org.apache.doris.nereids.DorisParser.ShowTabletsBelongContext; import org.apache.doris.nereids.DorisParser.ShowTrashContext; @@ -600,6 +601,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowSyncJobCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTableCreationCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTableIdCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowTableStatusCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTabletStorageFormatCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTabletsBelongCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTrashCommand; @@ -5385,5 +5387,31 @@ public LogicalPlan visitUseDatabase(UseDatabaseContext ctx) { return ctx.catalog != null ? new UseCommand(ctx.catalog.getText(), ctx.database.getText()) : new UseCommand(ctx.database.getText()); } + + @Override + public LogicalPlan visitShowTableStatus(ShowTableStatusContext ctx) { + String databaseName = null; + String ctlName = null; + String wild = null; + + if (ctx.database != null) { + List nameParts = visitMultipartIdentifier(ctx.database); + if (nameParts.size() == 1) { + databaseName = nameParts.get(0); + } else if (nameParts.size() == 2) { + ctlName = nameParts.get(0); + databaseName = nameParts.get(1); + } else { + throw new AnalysisException("nameParts in create table should be [ctl.][db.]"); + } + } + + if (ctx.wildWhere() != null) { + if (ctx.wildWhere().LIKE() != null) { + wild = stripQuotes(ctx.wildWhere().STRING_LITERAL().getText()); + } + } + return new ShowTableStatusCommand(ctlName, databaseName, wild); + } } 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 01152dc3d17a71c..e6d7f48ca0225d6 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 @@ -248,6 +248,7 @@ public enum PlanType { SHOW_STATUS_COMMAND, SHOW_STORAGE_ENGINES_COMMAND, SHOW_SYNC_JOB_COMMAND, + SHOW_TABLE_STATUS_COMMAND, SHOW_TABLE_ID_COMMAND, SHOW_TRASH_COMMAND, SHOW_TABLET_STORAGE_FORMAT_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTableStatusCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTableStatusCommand.java new file mode 100644 index 000000000000000..51ffb97e5eefd1f --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTableStatusCommand.java @@ -0,0 +1,199 @@ +// 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.DatabaseIf; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.PrimitiveType; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.catalog.TableIf; +import org.apache.doris.common.CaseSensibility; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.PatternMatcher; +import org.apache.doris.common.PatternMatcherWrapper; +import org.apache.doris.common.util.TimeUtils; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.nereids.trees.plans.PlanType; +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 com.google.common.base.Strings; +import com.google.common.collect.Lists; + +import java.util.List; + +/** + * ShowVariablesCommand + */ +public class ShowTableStatusCommand extends ShowCommand { + private static final ShowResultSetMetaData META_DATA = ShowResultSetMetaData.builder() + .addColumn(new Column("Name", ScalarType.createVarchar(64))) + .addColumn(new Column("Engine", ScalarType.createVarchar(10))) + .addColumn(new Column("Version", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Row_format", ScalarType.createVarchar(64))) + .addColumn(new Column("Rows", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Avg_row_length", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Data_length", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Max_data_length", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Index_length", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Data_free", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Auto_increment", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Create_time", ScalarType.createType(PrimitiveType.DATETIME))) + .addColumn(new Column("Update_time", ScalarType.createType(PrimitiveType.DATETIME))) + .addColumn(new Column("Check_time", ScalarType.createType(PrimitiveType.DATETIME))) + .addColumn(new Column("Collation", ScalarType.createVarchar(64))) + .addColumn(new Column("Checksum", ScalarType.createType(PrimitiveType.BIGINT))) + .addColumn(new Column("Create_options", ScalarType.createVarchar(64))) + .addColumn(new Column("Comment", ScalarType.createVarchar(64))) + .build(); + + private String catalog; + private String db; + private String wild; + + public ShowTableStatusCommand(String catalog, String db, String wild) { + super(PlanType.SHOW_TABLE_STATUS_COMMAND); + this.catalog = catalog; + this.db = db; + this.wild = wild; + } + + public String getCatalog() { + return catalog; + } + + public String getDb() { + return db; + } + + public String getPattern() { + return wild; + } + + public ShowResultSetMetaData getMetaData() { + return META_DATA; + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + if (Strings.isNullOrEmpty(db)) { + db = ctx.getDatabase(); + if (Strings.isNullOrEmpty(db)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR); + } + } + if (Strings.isNullOrEmpty(catalog)) { + catalog = ctx.getDefaultCatalog(); + if (Strings.isNullOrEmpty(catalog)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_NAME_FOR_CATALOG); + } + } + + if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ctx, + catalog, db, PrivPredicate.SHOW)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR, + PrivPredicate.ADMIN.getPrivs().toString(), db); + } + + List> rows = Lists.newArrayList(); + DatabaseIf dbName = ctx.getEnv().getCatalogMgr() + .getCatalogOrAnalysisException(getCatalog()) + .getDbOrAnalysisException(getDb()); + if (dbName != null) { + PatternMatcher matcher = null; + if (getPattern() != null) { + matcher = PatternMatcherWrapper.createMysqlPattern(getPattern(), + CaseSensibility.TABLE.getCaseSensibility()); + } + for (TableIf table : dbName.getTables()) { + if (matcher != null && !matcher.match(table.getName())) { + continue; + } + + // check tbl privs + if (!Env.getCurrentEnv().getAccessManager() + .checkTblPriv(ctx, getCatalog(), + dbName.getFullName(), table.getName(), PrivPredicate.SHOW)) { + continue; + } + List row = Lists.newArrayList(); + // Name + row.add(table.getName()); + // Engine + row.add(table.getEngine()); + // version + row.add(null); + // Row_format + row.add(null); + // Rows + row.add(String.valueOf(table.getCachedRowCount())); + // Avg_row_length + row.add(String.valueOf(table.getAvgRowLength())); + // Data_length + row.add(String.valueOf(table.getDataLength())); + // Max_data_length + row.add(null); + // Index_length + row.add(null); + // Data_free + row.add(null); + // Auto_increment + row.add(null); + // Create_time + row.add(TimeUtils.longToTimeString(table.getCreateTime() * 1000)); + // Update_time + if (table.getUpdateTime() > 0) { + row.add(TimeUtils.longToTimeString(table.getUpdateTime())); + } else { + row.add(null); + } + // Check_time + if (table.getLastCheckTime() > 0) { + row.add(TimeUtils.longToTimeString(table.getLastCheckTime())); + } else { + row.add(null); + } + // Collation + row.add("utf-8"); + // Checksum + row.add(null); + // Create_options + row.add(null); + + row.add(table.getComment()); + rows.add(row); + } + } + // sort by table name + rows.sort((x, y) -> { + return x.get(0).compareTo(y.get(0)); + }); + return new ShowResultSet(getMetaData(), rows); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowTableStatusCommand(this, context); + } + +} 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 ed4a1bdb1b3ee2a..8125462a1a0202f 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 @@ -135,6 +135,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowSyncJobCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTableCreationCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTableIdCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowTableStatusCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTabletStorageFormatCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTabletsBelongCommand; import org.apache.doris.nereids.trees.plans.commands.ShowTrashCommand; @@ -742,4 +743,8 @@ default R visitUseCommand(UseCommand useCommand, C context) { default R visitAlterDatabaseRenameCommand(AlterDatabaseRenameCommand alterDatabaseRenameCommand, C context) { return visitCommand(alterDatabaseRenameCommand, context); } + + default R visitShowTableStatusCommand(ShowTableStatusCommand showTableStatusCommand, C context) { + return visitCommand(showTableStatusCommand, context); + } } diff --git a/regression-test/suites/nereids_p0/show/test_nereids_show_table_status.groovy b/regression-test/suites/nereids_p0/show/test_nereids_show_table_status.groovy new file mode 100644 index 000000000000000..e660e112532ed5c --- /dev/null +++ b/regression-test/suites/nereids_p0/show/test_nereids_show_table_status.groovy @@ -0,0 +1,52 @@ +// 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_nereids_show_table_status") { + def table = "test_nereids_show_table_status" + String dbName = "${table}_db" + sql "CREATE DATABASE IF NOT EXISTS ${dbName}" + sql "use ${dbName}" + // create table and insert data + sql """ drop table if exists ${table} force""" + sql """ + create table ${table} ( + `id` int(11), + `name` varchar(128), + `da` date + ) + engine=olap + duplicate key(id) + partition by range(da)( + PARTITION p3 VALUES LESS THAN ('2023-01-01'), + PARTITION p4 VALUES LESS THAN ('2024-01-01'), + PARTITION p5 VALUES LESS THAN ('2025-01-01') + ) + distributed by hash(id) buckets 2 + properties( + "replication_num"="1", + "light_schema_change"="true" + ); + """ + + + checkNereidsExecute("show table status") + checkNereidsExecute("show table status from ${dbName}") + checkNereidsExecute("show table status from ${dbName} like '%${table}%'") + checkNereidsExecute("show table status from ${dbName} where name='${table}'") + +}