From 7836e930fee56f4dbfd16a93ef8c8726d921670c Mon Sep 17 00:00:00 2001 From: GentleCold Date: Wed, 4 Dec 2024 17:25:57 +0800 Subject: [PATCH] [Feat](Nereids) support show create repository command (#43902) Issue Number: close #42724 migrate show create repository command to nereids --- .../org/apache/doris/nereids/DorisParser.g4 | 2 +- .../nereids/parser/LogicalPlanBuilder.java | 7 ++ .../doris/nereids/trees/plans/PlanType.java | 1 + .../commands/ShowCreateRepositoryCommand.java | 81 +++++++++++++++++++ .../trees/plans/visitor/CommandVisitor.java | 5 ++ .../show_create_repository_command.groovy | 77 ++++++++++++++++++ 6 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateRepositoryCommand.java create mode 100644 regression-test/suites/nereids_p0/ddl/repository/show_create_repository_command.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 dcc87851196bfb..1fb5897066f021 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 @@ -230,6 +230,7 @@ supportedShowStatement | SHOW ALL? GRANTS #showGrants | SHOW GRANTS FOR userIdentify #showGrantsForUser | SHOW LOAD PROFILE loadIdPath=STRING_LITERAL #showLoadProfile + | SHOW CREATE REPOSITORY FOR identifier #showCreateRepository | SHOW VIEW (FROM |IN) tableName=multipartIdentifier ((FROM | IN) database=identifier)? #showView @@ -300,7 +301,6 @@ unsupportedShowStatement | SHOW STORAGE POLICY (USING (FOR policy=identifierOrText)?)? #showStoragePolicy | SHOW STAGES #showStages | SHOW STORAGE (VAULT | VAULTS) #showStorageVault - | SHOW CREATE REPOSITORY FOR identifier #showCreateRepository | 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 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 705acb4788fda1..9866b410c8fbb0 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 @@ -241,6 +241,7 @@ 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.ShowCreateRepositoryContext; import org.apache.doris.nereids.DorisParser.ShowCreateTableContext; import org.apache.doris.nereids.DorisParser.ShowCreateViewContext; import org.apache.doris.nereids.DorisParser.ShowDeleteContext; @@ -539,6 +540,7 @@ 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.ShowCreateRepositoryCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateTableCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateViewCommand; import org.apache.doris.nereids.trees.plans.commands.ShowDeleteCommand; @@ -4430,6 +4432,11 @@ public RefreshDatabaseCommand visitRefreshDatabase(RefreshDatabaseContext ctx) { throw new ParseException("Only one dot can be in the name: " + String.join(".", parts)); } + @Override + public LogicalPlan visitShowCreateRepository(ShowCreateRepositoryContext ctx) { + return new ShowCreateRepositoryCommand(ctx.identifier().getText()); + } + public LogicalPlan visitShowLastInsert(ShowLastInsertContext ctx) { return new ShowLastInsertCommand(); } 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 5d523ce3c1d425..969b51ee99afe4 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 @@ -206,6 +206,7 @@ public enum PlanType { SHOW_CREATE_CATALOG_COMMAND, SHOW_CREATE_DATABASE_COMMAND, SHOW_CREATE_MATERIALIZED_VIEW_COMMAND, + SHOW_CREATE_REPOSITORY_COMMAND, SHOW_CREATE_TABLE_COMMAND, SHOW_CREATE_VIEW_COMMAND, SHOW_DELETE_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateRepositoryCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateRepositoryCommand.java new file mode 100644 index 00000000000000..8c27e8748fbb72 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowCreateRepositoryCommand.java @@ -0,0 +1,81 @@ +// 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.backup.Repository; +import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.ScalarType; +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.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.collect.Lists; + +import java.util.List; + +/** + * ShowCreateRepositoryCommand + */ +public class ShowCreateRepositoryCommand extends ShowCommand { + private static final ShowResultSetMetaData META_DATA = + ShowResultSetMetaData.builder() + .addColumn(new Column("RepoName", ScalarType.createVarchar(128))) + .addColumn(new Column("CreateStmt", ScalarType.createVarchar(65535))) + .build(); + + private final String repoName; + + public ShowCreateRepositoryCommand(String repoName) { + super(PlanType.SHOW_CREATE_REPOSITORY_COMMAND); + this.repoName = repoName; + } + + private void validate() throws UserException { + // check auth + if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, + PrivPredicate.ADMIN.getPrivs().toString()); + } + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + validate(); + List> rows = Lists.newArrayList(); + Repository repo = Env.getCurrentEnv().getBackupHandler().getRepoMgr().getRepo(repoName); + if (repo == null) { + throw new AnalysisException("repository not exist."); + } + rows.add(Lists.newArrayList(repoName, repo.getCreateStatement())); + return new ShowResultSet(META_DATA, rows); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowCreateRepositoryCommand(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 23ceadbc3168f1..0d8c24086a6bb3 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 @@ -87,6 +87,7 @@ 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.ShowCreateRepositoryCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateTableCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateViewCommand; import org.apache.doris.nereids.trees.plans.commands.ShowDeleteCommand; @@ -354,6 +355,10 @@ default R visitRefreshCatalogCommand(RefreshCatalogCommand refreshCatalogCommand return visitCommand(refreshCatalogCommand, context); } + default R visitShowCreateRepositoryCommand(ShowCreateRepositoryCommand showCreateRepositoryCommand, C context) { + return visitCommand(showCreateRepositoryCommand, context); + } + default R visitShowLastInsertCommand(ShowLastInsertCommand showLastInsertCommand, C context) { return visitCommand(showLastInsertCommand, context); } diff --git a/regression-test/suites/nereids_p0/ddl/repository/show_create_repository_command.groovy b/regression-test/suites/nereids_p0/ddl/repository/show_create_repository_command.groovy new file mode 100644 index 00000000000000..547cd8a6376db6 --- /dev/null +++ b/regression-test/suites/nereids_p0/ddl/repository/show_create_repository_command.groovy @@ -0,0 +1,77 @@ +// 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. + +import org.junit.Assert; + +suite("show_create_repository_command") { + String ak = getS3AK() + String sk = getS3SK() + String endpoint = getS3Endpoint() + String region = getS3Region() + String bucket = context.config.otherConfigs.get("s3BucketName"); + String repoName = "test_show_create_repository" + String readOnlyRepoName = "test_show_create_read_only_repository" + + //cloud-mode + if (isCloudMode()) { + return + } + + try_sql "DROP REPOSITORY `${repoName}`" + try_sql "DROP REPOSITORY `${readOnlyRepoName}`" + + // create S3 repo + sql """CREATE REPOSITORY `${repoName}` + WITH S3 + ON LOCATION "s3://${bucket}/${repoName}" + PROPERTIES + ( + "s3.endpoint" = "http://${endpoint}", + "s3.region" = "${region}", + "s3.access_key" = "${ak}", + "s3.secret_key" = "${sk}" + )""" + + // create S3 read only repo + sql """CREATE READ ONLY REPOSITORY `${readOnlyRepoName}` + WITH S3 + ON LOCATION "s3://${bucket}/${readOnlyRepoName}" + PROPERTIES + ( + "s3.endpoint" = "http://${endpoint}", + "s3.region" = "${region}", + "s3.access_key" = "${ak}", + "s3.secret_key" = "${sk}" + )""" + + def create_repo = checkNereidsExecuteWithResult("""SHOW CREATE REPOSITORY for `${repoName}`;""").toString(); + assertTrue(create_repo.contains("${repoName}")) + assertTrue(create_repo.contains("s3://${bucket}/${repoName}")) + + def create_read_only_repo = checkNereidsExecuteWithResult("""SHOW CREATE REPOSITORY for `${readOnlyRepoName}`;""").toString(); + assertTrue(create_read_only_repo.contains("${readOnlyRepoName}")) + assertTrue(create_read_only_repo.contains("READ ONLY")) + + sql """DROP REPOSITORY `${repoName}`;""" + sql """DROP REPOSITORY `${readOnlyRepoName}`;""" + + try { + sql """SHOW CREATE REPOSITORY for `${repoName}`;""" + } catch (Exception e) { + assertTrue(e.getMessage().contains("repository not exist.")) + } +}