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 5fd21da747e7dd..d149105da35435 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 @@ -199,6 +199,8 @@ supportedCreateStatement | CREATE SQL_BLOCK_RULE (IF NOT EXISTS)? name=identifier properties=propertyClause? #createSqlBlockRule | CREATE ENCRYPTKEY (IF NOT EXISTS)? multipartIdentifier AS STRING_LITERAL #createEncryptkey + | CREATE (DATABASE | SCHEMA) (IF NOT EXISTS)? name=multipartIdentifier + properties=propertyClause? #createDatabase ; supportedAlterStatement @@ -751,9 +753,7 @@ analyzeProperties ; unsupportedCreateStatement - : CREATE (DATABASE | SCHEMA) (IF NOT EXISTS)? name=multipartIdentifier - properties=propertyClause? #createDatabase - | CREATE (GLOBAL | SESSION | LOCAL)? + : CREATE (GLOBAL | SESSION | LOCAL)? (TABLES | AGGREGATE)? FUNCTION (IF NOT EXISTS)? functionIdentifier LEFT_PAREN functionArguments? RIGHT_PAREN RETURNS returnType=dataType (INTERMEDIATE intermediateType=dataType)? diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateDbStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateDbStmt.java index 358ee5e4debef8..c2f1ec260f82ac 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateDbStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateDbStmt.java @@ -52,6 +52,14 @@ public CreateDbStmt(boolean ifNotExists, DbName dbName, Map prop } } + // For nereids + public CreateDbStmt(boolean ifNotExists, DbName dbName, Map properties, Void unused) { + this.ifNotExists = ifNotExists; + this.ctlName = dbName.getCtl(); + this.dbName = dbName.getDb(); + this.properties = properties == null ? new HashMap<>() : properties; + } + public String getFullDbName() { return dbName; } 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 0432e06c335472..b6fcfd4e5de8e0 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 @@ -111,6 +111,7 @@ import org.apache.doris.nereids.DorisParser.ComplexDataTypeContext; import org.apache.doris.nereids.DorisParser.ConstantContext; import org.apache.doris.nereids.DorisParser.CreateCatalogContext; +import org.apache.doris.nereids.DorisParser.CreateDatabaseContext; import org.apache.doris.nereids.DorisParser.CreateEncryptkeyContext; import org.apache.doris.nereids.DorisParser.CreateFileContext; import org.apache.doris.nereids.DorisParser.CreateMTMVContext; @@ -509,6 +510,7 @@ import org.apache.doris.nereids.trees.plans.commands.Command; import org.apache.doris.nereids.trees.plans.commands.Constraint; import org.apache.doris.nereids.trees.plans.commands.CreateCatalogCommand; +import org.apache.doris.nereids.trees.plans.commands.CreateDbCommand; import org.apache.doris.nereids.trees.plans.commands.CreateEncryptkeyCommand; import org.apache.doris.nereids.trees.plans.commands.CreateFileCommand; import org.apache.doris.nereids.trees.plans.commands.CreateJobCommand; @@ -5453,5 +5455,25 @@ public LogicalPlan visitShowConvertLsc(ShowConvertLscContext ctx) { } return new ShowConvertLSCCommand(databaseName); } + + @Override + public LogicalPlan visitCreateDatabase(CreateDatabaseContext ctx) { + boolean ifNotExists = (ctx.IF() != null && ctx.NOT() != null && ctx.EXISTS() != null); + Map properties = visitPropertyClause(ctx.propertyClause()) == null ? Maps.newHashMap() + : visitPropertyClause(ctx.propertyClause()); + List nameParts = visitMultipartIdentifier(ctx.name); + String databaseName = ""; + String catalogName = ""; + if (nameParts.size() == 2) { + // The identifier is in the form "internalcatalog.databasename" + catalogName = nameParts.get(0); + databaseName = nameParts.get(1); + } else if (nameParts.size() == 1) { + // The identifier is in the form "databasename" + databaseName = nameParts.get(0); + } + + return new CreateDbCommand(ifNotExists, new DbName(catalogName, databaseName), properties); + } } 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 1c0cb26f0f0702..b4b04f3097230e 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 @@ -279,5 +279,6 @@ public enum PlanType { SHOW_QUERY_PROFILE_COMMAND, SWITCH_COMMAND, HELP_COMMAND, - USE_COMMAND + USE_COMMAND, + CREATE_DATABASE_COMMAND } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateDbCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateDbCommand.java new file mode 100644 index 00000000000000..05f1ac429eb0dc --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateDbCommand.java @@ -0,0 +1,98 @@ +// 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.analysis.CreateDbStmt; +import org.apache.doris.analysis.DbName; +import org.apache.doris.analysis.StmtType; +import org.apache.doris.catalog.Env; +import org.apache.doris.common.Config; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.FeNameFormat; +import org.apache.doris.common.util.InternalDatabaseUtil; +import org.apache.doris.common.util.PropertyAnalyzer; +import org.apache.doris.datasource.CatalogIf; +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.StmtExecutor; + +import com.google.common.base.Strings; + +import java.util.HashMap; +import java.util.Map; + +/** CreateDbCommand */ +public class CreateDbCommand extends Command implements ForwardWithSync { + private final boolean ifNotExists; + private String ctlName; + private final String dbName; + private final Map properties; + private final DbName dbNameIf; + + /** CreateDbCommand Constructor */ + public CreateDbCommand(boolean ifNotExists, DbName dbName, Map properties) { + super(PlanType.CREATE_DATABASE_COMMAND); + this.ifNotExists = ifNotExists; + this.dbNameIf = dbName; + this.ctlName = dbName.getCtl(); + this.dbName = dbName.getDb(); + this.properties = properties == null ? new HashMap<>() : properties; + + if (Config.force_enable_feature_binlog + && !this.properties.containsKey(PropertyAnalyzer.PROPERTIES_BINLOG_ENABLE)) { + this.properties.put(PropertyAnalyzer.PROPERTIES_BINLOG_ENABLE, "true"); + } + } + + @Override + public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { + if (Strings.isNullOrEmpty(ctlName)) { + ctlName = Env.getCurrentEnv().getCurrentCatalog().getName(); + } + FeNameFormat.checkCatalogName(ctlName); + FeNameFormat.checkDbName(dbName); + InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get()); + if (!Env.getCurrentEnv().getAccessManager() + .checkDbPriv(ConnectContext.get(), ctlName, dbName, PrivPredicate.CREATE)) { + ErrorReport.reportAnalysisException( + ErrorCode.ERR_DBACCESS_DENIED_ERROR, ctx.getQualifiedUser(), dbName); + } + + CatalogIf catalogIf; + if (Strings.isNullOrEmpty(ctlName)) { + catalogIf = Env.getCurrentEnv().getCurrentCatalog(); + } else { + catalogIf = Env.getCurrentEnv().getCatalogMgr().getCatalog(ctlName); + } + CreateDbStmt stmt = new CreateDbStmt(ifNotExists, dbNameIf, properties); + catalogIf.createDb(stmt); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitCreateDatabaseCommand(this, context); + } + + @Override + public StmtType stmtType() { + return StmtType.CREATE; + } +} 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 0f5cafa919227c..6d4d8758b11074 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 @@ -44,6 +44,7 @@ import org.apache.doris.nereids.trees.plans.commands.CleanAllProfileCommand; import org.apache.doris.nereids.trees.plans.commands.Command; import org.apache.doris.nereids.trees.plans.commands.CreateCatalogCommand; +import org.apache.doris.nereids.trees.plans.commands.CreateDbCommand; import org.apache.doris.nereids.trees.plans.commands.CreateEncryptkeyCommand; import org.apache.doris.nereids.trees.plans.commands.CreateFileCommand; import org.apache.doris.nereids.trees.plans.commands.CreateJobCommand; @@ -757,4 +758,9 @@ default R visitUseCommand(UseCommand useCommand, C context) { default R visitAlterDatabaseRenameCommand(AlterDatabaseRenameCommand alterDatabaseRenameCommand, C context) { return visitCommand(alterDatabaseRenameCommand, context); } + + default R visitCreateDatabaseCommand(CreateDbCommand createDatabaseCommand, + C context) { + return visitCommand(createDatabaseCommand, context); + } } diff --git a/regression-test/suites/nereids_p0/create_table/ddl/test_create_database.groovy b/regression-test/suites/nereids_p0/create_table/ddl/test_create_database.groovy new file mode 100644 index 00000000000000..c8d80e9bb08af4 --- /dev/null +++ b/regression-test/suites/nereids_p0/create_table/ddl/test_create_database.groovy @@ -0,0 +1,28 @@ +// 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_create_database") { + + String dbName = "test_nereids_create_database_db" + + checkNereidsExecute("CREATE DATABASE IF NOT EXISTS ${dbName}") + sql """drop database ${dbName}""" + checkNereidsExecute("CREATE DATABASE ${dbName}") + + +}