This is an automated email from the ASF dual-hosted git repository.
starocean999 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 84f0eefaa66 [Feat](Nereids) support show databases command (#48941)
84f0eefaa66 is described below
commit 84f0eefaa6606f7c53ab9b386b51813db5ca0659
Author: Jensen <[email protected]>
AuthorDate: Wed Mar 19 11:51:10 2025 +0800
[Feat](Nereids) support show databases command (#48941)
---
.../antlr4/org/apache/doris/nereids/DorisParser.g4 | 2 +-
.../doris/nereids/parser/LogicalPlanBuilder.java | 20 +++
.../apache/doris/nereids/trees/plans/PlanType.java | 1 +
.../trees/plans/commands/ShowDatabasesCommand.java | 165 +++++++++++++++++++++
.../trees/plans/visitor/CommandVisitor.java | 5 +
.../plans/commands/ShowDatabasesCommandTest.java | 82 ++++++++++
.../java/org/apache/doris/qe/StmtExecutorTest.java | 11 --
7 files changed, 274 insertions(+), 12 deletions(-)
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 7abf3e8b4ad..4af3af59ac2 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
@@ -342,6 +342,7 @@ supportedShowStatement
| SHOW FULL? TABLES ((FROM | IN) database=multipartIdentifier)? wildWhere?
#showTables
| SHOW FULL? VIEWS ((FROM | IN) database=multipartIdentifier)? wildWhere?
#showViews
| SHOW TABLE STATUS ((FROM | IN) database=multipartIdentifier)? wildWhere?
#showTableStatus
+ | SHOW (DATABASES | SCHEMAS) (FROM catalog=identifier)? wildWhere?
#showDatabases
;
supportedLoadStatement
@@ -387,7 +388,6 @@ unsupportedShowStatement
| SHOW CREATE statementScope? FUNCTION functionIdentifier
LEFT_PAREN functionArguments? RIGHT_PAREN
((FROM | IN) database=multipartIdentifier)?
#showCreateFunction
- | SHOW (DATABASES | SCHEMAS) (FROM catalog=identifier)? wildWhere?
#showDatabases
| SHOW FULL? (COLUMNS | FIELDS) (FROM | IN) tableName=multipartIdentifier
((FROM | IN) database=multipartIdentifier)? wildWhere?
#showColumns
| SHOW LOAD WARNINGS ((((FROM | IN) database=multipartIdentifier)?
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 62574ee0f68..18c0f00dc7e 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
@@ -629,6 +629,7 @@ import
org.apache.doris.nereids.trees.plans.commands.ShowDataCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDataSkewCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDataTypesCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDatabaseIdCommand;
+import org.apache.doris.nereids.trees.plans.commands.ShowDatabasesCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDeleteCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDiagnoseTabletCommand;
import
org.apache.doris.nereids.trees.plans.commands.ShowDynamicPartitionCommand;
@@ -6073,6 +6074,25 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
return new ShowTabletIdCommand(tabletId);
}
+ @Override
+ public LogicalPlan visitShowDatabases(DorisParser.ShowDatabasesContext
ctx) {
+ String ctlName = null;
+ if (ctx.catalog != null) {
+ ctlName = ctx.catalog.getText();
+ }
+
+ if (ctx.wildWhere() != null) {
+ if (ctx.wildWhere().LIKE() != null) {
+ return new ShowDatabasesCommand(ctlName,
+
stripQuotes(ctx.wildWhere().STRING_LITERAL().getText()), null);
+ } else {
+ Expression expr = (Expression)
ctx.wildWhere().expression().accept(this);
+ return new ShowDatabasesCommand(ctlName, null, expr);
+ }
+ }
+ return new ShowDatabasesCommand(ctlName, null, null);
+ }
+
@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 f3c670e9017..f61752ce934 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
@@ -235,6 +235,7 @@ public enum PlanType {
SHOW_CREATE_REPOSITORY_COMMAND,
SHOW_CREATE_TABLE_COMMAND,
SHOW_CREATE_VIEW_COMMAND,
+ SHOW_DATABASES_COMMAND,
SHOW_DATABASE_ID_COMMAND,
SHOW_DATA_COMMAND,
SHOW_DATA_SKEW_COMMAND,
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowDatabasesCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowDatabasesCommand.java
new file mode 100644
index 00000000000..5a296cb8c16
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowDatabasesCommand.java
@@ -0,0 +1,165 @@
+// 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.Env;
+import org.apache.doris.catalog.InfoSchemaDb;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.cluster.ClusterNamespace;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.CaseSensibility;
+import org.apache.doris.common.PatternMatcher;
+import org.apache.doris.common.PatternMatcherWrapper;
+import org.apache.doris.datasource.CatalogIf;
+import org.apache.doris.datasource.InternalCatalog;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.nereids.analyzer.UnboundSlot;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.commands.info.AliasInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.TableNameInfo;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.nereids.util.Utils;
+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 com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * ShowDatabasesCommand
+ */
+public class ShowDatabasesCommand extends ShowCommand {
+ private static final String DB_COL = "Database";
+ private static final String ORI_DB_COL = "SCHEMA_NAME";
+ private static final ShowResultSetMetaData META_DATA =
ShowResultSetMetaData.builder()
+ .addColumn(new Column(DB_COL,
ScalarType.createVarchar(20)))
+ .build();
+
+ private String catalog;
+ private final String likePattern;
+ private final Expression whereClause;
+
+ /**
+ * ShowDatabasesCommand
+ */
+ public ShowDatabasesCommand(String catalog, String likePattern, Expression
whereClause) {
+ super(PlanType.SHOW_DATABASES_COMMAND);
+ this.catalog = catalog;
+ this.likePattern = likePattern;
+ this.whereClause = whereClause;
+ }
+
+ /**
+ * validate
+ */
+ public void validate(ConnectContext ctx) throws AnalysisException {
+ if (Strings.isNullOrEmpty(catalog)) {
+ catalog = ctx.getDefaultCatalog();
+ if (Strings.isNullOrEmpty(catalog)) {
+ catalog = InternalCatalog.INTERNAL_CATALOG_NAME;
+ }
+ }
+ }
+
+ /**
+ * replaceColumnNameVisitor
+ * replace column name to real column name
+ */
+ private static class ReplaceColumnNameVisitor extends
DefaultExpressionRewriter<Void> {
+ @Override
+ public Expression visitUnboundSlot(UnboundSlot slot, Void context) {
+ if
(slot.getName().toLowerCase(Locale.ROOT).equals(DB_COL.toLowerCase(Locale.ROOT)))
{
+ return UnboundSlot.quoted(ORI_DB_COL);
+ }
+ return slot;
+ }
+ }
+
+ private ShowResultSet execute(ConnectContext ctx, StmtExecutor executor,
String whereClause) {
+ List<AliasInfo> selectList = new ArrayList<>();
+ selectList.add(AliasInfo.of(ORI_DB_COL, DB_COL));
+
+ TableNameInfo fullTblName = new TableNameInfo(catalog,
InfoSchemaDb.DATABASE_NAME, "schemata");
+
+ LogicalPlan plan = Utils.buildLogicalPlan(selectList, fullTblName,
whereClause);
+ List<List<String>> rows = Utils.executePlan(ctx, executor, plan);
+ return new ShowResultSet(META_DATA, rows);
+ }
+
+ @Override
+ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor)
throws Exception {
+ validate(ctx);
+ if (whereClause != null) {
+ Expression rewrited = whereClause.accept(new
ReplaceColumnNameVisitor(), null);
+ String whereCondition = " WHERE `CATALOG_NAME` = '" + catalog
+ + "' AND " + rewrited.toSql();
+ return execute(ctx, executor, whereCondition);
+ }
+ List<List<String>> rows = Lists.newArrayList();
+ CatalogIf catalogIf = ctx.getCatalog(catalog);
+ if (catalogIf == null) {
+ throw new AnalysisException("No catalog found with name " +
catalog);
+ }
+ List<String> dbNames = catalogIf.getDbNames();
+ PatternMatcher matcher = null;
+ if (likePattern != null) {
+ matcher = PatternMatcherWrapper.createMysqlPattern(likePattern,
+ CaseSensibility.DATABASE.getCaseSensibility());
+ }
+ Set<String> dbNameSet = Sets.newTreeSet();
+ for (String fullName : dbNames) {
+ final String db = ClusterNamespace.getNameFromFullName(fullName);
+ // Filter dbname
+ if (matcher != null && !matcher.match(db)) {
+ continue;
+ }
+
+ if
(!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(),
catalog,
+ fullName, PrivPredicate.SHOW)) {
+ continue;
+ }
+
+ dbNameSet.add(db);
+ }
+
+ for (String dbName : dbNameSet) {
+ rows.add(Lists.newArrayList(dbName));
+ }
+
+ rows.sort(Comparator.comparing(x -> x.get(0)));
+ return new ShowResultSet(META_DATA, rows);
+ }
+
+ @Override
+ public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+ return visitor.visitShowDatabasesCommand(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 0844700f942..2a16d81ad20 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
@@ -126,6 +126,7 @@ import
org.apache.doris.nereids.trees.plans.commands.ShowDataCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDataSkewCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDataTypesCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDatabaseIdCommand;
+import org.apache.doris.nereids.trees.plans.commands.ShowDatabasesCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDeleteCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowDiagnoseTabletCommand;
import
org.apache.doris.nereids.trees.plans.commands.ShowDynamicPartitionCommand;
@@ -853,6 +854,10 @@ public interface CommandVisitor<R, C> {
return visitCommand(showTableStatusCommand, context);
}
+ default R visitShowDatabasesCommand(ShowDatabasesCommand
showDatabasesCommand, C context) {
+ return visitCommand(showDatabasesCommand, context);
+ }
+
default R visitShowTableCommand(ShowTableCommand showTableCommand, C
context) {
return visitCommand(showTableCommand, context);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowDatabasesCommandTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowDatabasesCommandTest.java
new file mode 100644
index 00000000000..384aa9f68ac
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowDatabasesCommandTest.java
@@ -0,0 +1,82 @@
+// 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.CatalogMocker;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.datasource.CatalogMgr;
+import org.apache.doris.datasource.InternalCatalog;
+import org.apache.doris.mysql.privilege.AccessControllerManager;
+import org.apache.doris.nereids.analyzer.UnboundSlot;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
+import org.apache.doris.qe.ConnectContext;
+
+import mockit.Expectations;
+import mockit.Mocked;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ShowDatabasesCommandTest {
+ private static final String internalCtl =
InternalCatalog.INTERNAL_CATALOG_NAME;
+
+ @Mocked
+ private Env env;
+ @Mocked
+ private AccessControllerManager accessManager;
+ @Mocked
+ private ConnectContext ctx;
+ @Mocked
+ private InternalCatalog catalog;
+ @Mocked
+ private CatalogMgr catalogMgr;
+
+ @Test
+ void testValidate() {
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessManager;
+
+ env.getCatalogMgr();
+ minTimes = 0;
+ result = catalogMgr;
+
+ catalogMgr.getCatalog(anyString);
+ minTimes = 0;
+ result = catalog;
+ }
+ };
+ EqualTo equalTo = new EqualTo(new UnboundSlot("schema_name"),
+ new StringLiteral(CatalogMocker.TEST_DB_NAME));
+
+ // normal
+ ShowDatabasesCommand command = new ShowDatabasesCommand(internalCtl,
null, equalTo);
+ Assertions.assertDoesNotThrow(() -> command.validate(ctx));
+
+ // catalog is null
+ ShowDatabasesCommand command2 = new ShowDatabasesCommand(null, null,
equalTo);
+ Assertions.assertDoesNotThrow(() -> command2.validate(ctx));
+ }
+}
+
diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java
b/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java
index 8ab187315d8..d484b53bff5 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java
@@ -30,7 +30,6 @@ import org.apache.doris.analysis.SetStmt;
import org.apache.doris.analysis.ShowAuthorStmt;
import org.apache.doris.analysis.ShowStmt;
import org.apache.doris.analysis.SqlParser;
-import org.apache.doris.analysis.StatementBase;
import org.apache.doris.analysis.UseStmt;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.Config;
@@ -544,16 +543,6 @@ public class StmtExecutorTest {
Assert.assertEquals(QueryState.MysqlStateType.OK,
state.getStateType());
}
- @Test
- public void testStmtWithUserInfo(@Mocked StatementBase stmt, @Mocked
ConnectContext context) throws Exception {
- StmtExecutor stmtExecutor = new StmtExecutor(ctx, stmt);
- Deencapsulation.setField(stmtExecutor, "parsedStmt", null);
- Deencapsulation.setField(stmtExecutor, "originStmt", new
OriginStatement("show databases;", 0));
- stmtExecutor.execute();
- StatementBase newstmt = Deencapsulation.getField(stmtExecutor,
"parsedStmt");
- Assert.assertNotNull(newstmt.getUserInfo());
- }
-
@Test
public void testSetFail(@Mocked SetStmt setStmt, @Mocked SqlParser parser,
@Mocked SetExecutor executor) throws Exception {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]