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 9a819baaf0a84d..aa02da2b245440 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 @@ -334,6 +334,7 @@ supportedShowStatement | SHOW TABLE CREATION ((FROM | IN) database=multipartIdentifier)? (LIKE STRING_LITERAL)? #showTableCreation | SHOW TABLET STORAGE FORMAT VERBOSE? #showTabletStorageFormat + | SHOW TABLET tabletId=INTEGER_VALUE #showTabletId | SHOW QUERY PROFILE queryIdPath=STRING_LITERAL? limitClause? #showQueryProfile | SHOW CONVERT_LSC ((FROM | IN) database=multipartIdentifier)? #showConvertLsc | SHOW FULL? TABLES ((FROM | IN) database=multipartIdentifier)? wildWhere? #showTables @@ -398,7 +399,6 @@ unsupportedShowStatement sortClause? limitClause? #showAlterTable | SHOW TEMPORARY? PARTITIONS FROM tableName=multipartIdentifier wildWhere? sortClause? limitClause? #showPartitions - | SHOW TABLET tabletId=INTEGER_VALUE #showTabletId | SHOW TABLETS FROM tableName=multipartIdentifier partitionSpec? wildWhere? sortClause? limitClause? #showTabletsFromTable | SHOW BACKUP ((FROM | IN) database=multipartIdentifier)? wildWhere? #showBackup 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 5129c0991a51c5..0ac5872ad17f53 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 @@ -650,6 +650,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowTableCommand; 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.ShowTabletIdCommand; 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; @@ -5957,6 +5958,12 @@ public LogicalPlan visitShowTables(DorisParser.ShowTablesContext ctx) { return new ShowTableCommand(dbName, ctlName, isVerbose); } + @Override + public LogicalPlan visitShowTabletId(DorisParser.ShowTabletIdContext ctx) { + long tabletId = Long.parseLong(ctx.tabletId.getText()); + return new ShowTabletIdCommand(tabletId); + } + @Override public LogicalPlan visitDescribeTable(DorisParser.DescribeTableContext ctx) { TableNameInfo tableName = new TableNameInfo(visitMultipartIdentifier(ctx.multipartIdentifier())); 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 f6a3997dd0fa15..1ea8a1659546da 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 @@ -264,6 +264,7 @@ public enum PlanType { SHOW_SYNC_JOB_COMMAND, SHOW_TABLE_ID_COMMAND, SHOW_TABLES, + SHOW_TABLET_ID_COMMAND, SHOW_TRASH_COMMAND, SHOW_TABLET_STORAGE_FORMAT_COMMAND, SHOW_TRIGGERS_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTabletIdCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTabletIdCommand.java new file mode 100644 index 00000000000000..7abb30ed8663a2 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowTabletIdCommand.java @@ -0,0 +1,205 @@ +// 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.MaterializedIndex; +import org.apache.doris.catalog.OlapTable; +import org.apache.doris.catalog.Partition; +import org.apache.doris.catalog.Replica; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.catalog.Table; +import org.apache.doris.catalog.Tablet; +import org.apache.doris.catalog.TabletInvertedIndex; +import org.apache.doris.catalog.TabletMeta; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.Config; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.FeConstants; +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 org.apache.doris.statistics.query.QueryStatsUtil; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; + +import java.util.List; + +/** + * show tablet id command + */ +public class ShowTabletIdCommand extends ShowCommand { + private final long tabletId; + private String dbName; + + /** + * constructor + */ + public ShowTabletIdCommand(long tabletId) { + super(PlanType.SHOW_TABLET_ID_COMMAND); + this.tabletId = tabletId; + } + + /** + * get meta for show tabletId + */ + public ShowResultSetMetaData getMetaData() { + ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder(); + builder.addColumn(new Column("DbName", ScalarType.createVarchar(30))); + builder.addColumn(new Column("TableName", ScalarType.createVarchar(30))); + builder.addColumn(new Column("PartitionName", ScalarType.createVarchar(30))); + builder.addColumn(new Column("IndexName", ScalarType.createVarchar(30))); + builder.addColumn(new Column("DbId", ScalarType.createVarchar(30))); + builder.addColumn(new Column("TableId", ScalarType.createVarchar(30))); + builder.addColumn(new Column("PartitionId", ScalarType.createVarchar(30))); + builder.addColumn(new Column("IndexId", ScalarType.createVarchar(30))); + builder.addColumn(new Column("IsSync", ScalarType.createVarchar(30))); + builder.addColumn(new Column("Order", ScalarType.createVarchar(30))); + builder.addColumn(new Column("QueryHits", ScalarType.createVarchar(30))); + builder.addColumn(new Column("DetailCmd", ScalarType.createVarchar(30))); + return builder.build(); + } + + /** + * validate + */ + public void validate(ConnectContext ctx) throws AnalysisException { + // check access first + if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "SHOW TABLET"); + } + + dbName = ctx.getDatabase(); + if (Strings.isNullOrEmpty(dbName)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR); + } + } + + private ShowResultSet handleShowTabletId() { + List> rows = Lists.newArrayList(); + Env env = Env.getCurrentEnv(); + TabletInvertedIndex invertedIndex = Env.getCurrentInvertedIndex(); + TabletMeta tabletMeta = invertedIndex.getTabletMeta(tabletId); + Long dbId = tabletMeta != null ? tabletMeta.getDbId() : TabletInvertedIndex.NOT_EXIST_VALUE; + String dbName = FeConstants.null_string; + Long tableId = tabletMeta != null ? tabletMeta.getTableId() : TabletInvertedIndex.NOT_EXIST_VALUE; + String tableName = FeConstants.null_string; + Long partitionId = tabletMeta != null ? tabletMeta.getPartitionId() : TabletInvertedIndex.NOT_EXIST_VALUE; + String partitionName = FeConstants.null_string; + Long indexId = tabletMeta != null ? tabletMeta.getIndexId() : TabletInvertedIndex.NOT_EXIST_VALUE; + String indexName = FeConstants.null_string; + Boolean isSync = true; + long queryHits = 0L; + + int tabletIdx = -1; + // check real meta + do { + Database db = env.getInternalCatalog().getDbNullable(dbId); + if (db == null) { + isSync = false; + break; + } + dbName = db.getFullName(); + Table table = db.getTableNullable(tableId); + if (!(table instanceof OlapTable)) { + isSync = false; + break; + } + if (Config.enable_query_hit_stats) { + MaterializedIndex mi = ((OlapTable) table).getPartition(partitionId).getIndex(indexId); + if (mi != null) { + Tablet t = mi.getTablet(tabletId); + for (Replica r : t.getReplicas()) { + queryHits += QueryStatsUtil.getMergedReplicaStats(r.getId()); + } + } + } + + table.readLock(); + try { + tableName = table.getName(); + OlapTable olapTable = (OlapTable) table; + Partition partition = olapTable.getPartition(partitionId); + if (partition == null) { + isSync = false; + break; + } + partitionName = partition.getName(); + + MaterializedIndex index = partition.getIndex(indexId); + if (index == null) { + isSync = false; + break; + } + indexName = olapTable.getIndexNameById(indexId); + + Tablet tablet = index.getTablet(tabletId); + if (tablet == null) { + isSync = false; + break; + } + + tabletIdx = index.getTabletOrderIdx(tablet.getId()); + + List replicas = tablet.getReplicas(); + for (Replica replica : replicas) { + Replica tmp = invertedIndex.getReplica(tabletId, replica.getBackendIdWithoutException()); + if (tmp == null) { + isSync = false; + break; + } + // use !=, not equals(), because this should be the same object. + if (tmp != replica) { + isSync = false; + break; + } + } + + } finally { + table.readUnlock(); + } + } while (false); + + String detailCmd = String.format("SHOW PROC '/dbs/%d/%d/partitions/%d/%d/%d';", + dbId, tableId, partitionId, indexId, tabletId); + rows.add(Lists.newArrayList(dbName, tableName, partitionName, indexName, + dbId.toString(), tableId.toString(), + partitionId.toString(), indexId.toString(), + isSync.toString(), String.valueOf(tabletIdx), String.valueOf(queryHits), detailCmd)); + return new ShowResultSet(getMetaData(), rows); + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + validate(ctx); + return handleShowTabletId(); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowTabletIdCommand(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 c1c805c4d24d65..5314d5b22973df 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 @@ -150,6 +150,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowTableCommand; 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.ShowTabletIdCommand; 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; @@ -834,4 +835,8 @@ default R visitDescribeCommand(DescribeCommand describeCommand, C context) { default R visitShowTableCommand(ShowTableCommand showTableCommand, C context) { return visitCommand(showTableCommand, context); } + + default R visitShowTabletIdCommand(ShowTabletIdCommand showTabletIdCommand, C context) { + return visitCommand(showTabletIdCommand, context); + } }