From e840102e9990541ab412e0a78849e8d2bf545097 Mon Sep 17 00:00:00 2001 From: feiniaofeiafei <53502832+feiniaofeiafei@users.noreply.github.com> Date: Sun, 28 Apr 2024 12:15:01 +0800 Subject: [PATCH] [Feat](nereids)nereids support create table like (#34025) nereids support create table like statement. e.g. CREATE TABLE test1.table2 LIKE test1.table1 --- .../org/apache/doris/nereids/DorisParser.g4 | 3 + .../nereids/parser/LogicalPlanBuilder.java | 20 +++++ .../doris/nereids/trees/plans/PlanType.java | 4 +- .../commands/CreateTableLikeCommand.java | 49 ++++++++++++ .../commands/info/CreateTableLikeInfo.java | 77 +++++++++++++++++++ .../trees/plans/visitor/CommandVisitor.java | 5 ++ .../ddl_p0/test_create_table_like_nereids.out | 20 +++++ .../test_create_table_like_nereids.groovy | 75 ++++++++++++++++++ 8 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java create mode 100644 regression-test/data/ddl_p0/test_create_table_like_nereids.out create mode 100644 regression-test/suites/ddl_p0/test_create_table_like_nereids.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 764a562518..f3f712742e 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 @@ -65,6 +65,9 @@ statementBase (COMMENT STRING_LITERAL)? AS query #createView | ALTER VIEW name=multipartIdentifier (LEFT_PAREN cols=simpleColumnDefs RIGHT_PAREN)? AS query #alterView + | CREATE (EXTERNAL)? TABLE (IF NOT EXISTS)? name=multipartIdentifier + LIKE existedTable=multipartIdentifier + (WITH ROLLUP (rollupNames=identifierList)?)? #createTableLike | explain? INSERT (INTO | OVERWRITE TABLE) (tableName=multipartIdentifier | DORIS_INTERNAL_TABLE_ID LEFT_PAREN tableId=INTEGER_VALUE RIGHT_PAREN) partitionSpec? // partition define 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 e44609d75f..76bd599708 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 @@ -78,6 +78,7 @@ import org.apache.doris.nereids.DorisParser.CreateMTMVContext; import org.apache.doris.nereids.DorisParser.CreateProcedureContext; import org.apache.doris.nereids.DorisParser.CreateRowPolicyContext; import org.apache.doris.nereids.DorisParser.CreateTableContext; +import org.apache.doris.nereids.DorisParser.CreateTableLikeContext; import org.apache.doris.nereids.DorisParser.CreateViewContext; import org.apache.doris.nereids.DorisParser.CteContext; import org.apache.doris.nereids.DorisParser.DataTypeWithNullableContext; @@ -364,6 +365,7 @@ import org.apache.doris.nereids.trees.plans.commands.CreateMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.CreatePolicyCommand; import org.apache.doris.nereids.trees.plans.commands.CreateProcedureCommand; import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand; +import org.apache.doris.nereids.trees.plans.commands.CreateTableLikeCommand; import org.apache.doris.nereids.trees.plans.commands.CreateViewCommand; import org.apache.doris.nereids.trees.plans.commands.DeleteFromCommand; import org.apache.doris.nereids.trees.plans.commands.DeleteFromUsingCommand; @@ -393,6 +395,7 @@ import org.apache.doris.nereids.trees.plans.commands.info.CancelMTMVTaskInfo; import org.apache.doris.nereids.trees.plans.commands.info.ColumnDefinition; import org.apache.doris.nereids.trees.plans.commands.info.CreateMTMVInfo; import org.apache.doris.nereids.trees.plans.commands.info.CreateTableInfo; +import org.apache.doris.nereids.trees.plans.commands.info.CreateTableLikeInfo; import org.apache.doris.nereids.trees.plans.commands.info.CreateViewInfo; import org.apache.doris.nereids.trees.plans.commands.info.DMLCommandType; import org.apache.doris.nereids.trees.plans.commands.info.DefaultValue; @@ -3499,4 +3502,21 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor { public Object visitUnsupported(UnsupportedContext ctx) { return UnsupportedCommand.INSTANCE; } + + @Override + public LogicalPlan visitCreateTableLike(CreateTableLikeContext ctx) { + List nameParts = visitMultipartIdentifier(ctx.name); + List existedTableNameParts = visitMultipartIdentifier(ctx.existedTable); + ArrayList rollupNames = Lists.newArrayList(); + boolean withAllRollUp = false; + if (ctx.WITH() != null && ctx.rollupNames != null) { + rollupNames = new ArrayList<>(visitIdentifierList(ctx.rollupNames)); + } else if (ctx.WITH() != null && ctx.rollupNames == null) { + withAllRollUp = true; + } + CreateTableLikeInfo info = new CreateTableLikeInfo(ctx.EXISTS() != null, + new TableNameInfo(nameParts), new TableNameInfo(existedTableNameParts), + rollupNames, withAllRollUp); + return new CreateTableLikeCommand(info); + } } 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 3db3ffa3d9..4aeecdfd50 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 @@ -153,6 +153,6 @@ public enum PlanType { SHOW_CREATE_PROCEDURE_COMMAND, CREATE_VIEW_COMMAND, ALTER_VIEW_COMMAND, - - UNSUPPORTED_COMMAND + UNSUPPORTED_COMMAND, + CREATE_TABLE_LIKE_COMMAND } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java new file mode 100644 index 0000000000..a271623ef0 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java @@ -0,0 +1,49 @@ +// 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.CreateTableLikeStmt; +import org.apache.doris.catalog.Env; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.commands.info.CreateTableLikeInfo; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.StmtExecutor; + +/** CreateTableLikeCommand */ +public class CreateTableLikeCommand extends Command implements ForwardWithSync { + private final CreateTableLikeInfo info; + + public CreateTableLikeCommand(CreateTableLikeInfo info) { + super(PlanType.CREATE_TABLE_LIKE_COMMAND); + this.info = info; + } + + @Override + public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { + executor.checkBlockRules(); + info.validate(ctx); + CreateTableLikeStmt stmt = info.translateToLegacyStmt(); + Env.getCurrentEnv().createTableLike(stmt); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitCreateTableLikeCommand(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java new file mode 100644 index 0000000000..5428898d40 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java @@ -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. + +package org.apache.doris.nereids.trees.plans.commands.info; + +import org.apache.doris.analysis.CreateTableLikeStmt; +import org.apache.doris.catalog.Env; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.DdlException; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.FeNameFormat; +import org.apache.doris.common.util.Util; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; + +import java.util.ArrayList; + +/** CreateTableLikeInfo */ +public class CreateTableLikeInfo { + private final boolean ifNotExists; + private final TableNameInfo tableName; + private final TableNameInfo existedTableName; + private final ArrayList rollupNames; + private final boolean withAllRollup; + + public CreateTableLikeInfo(boolean ifNotExists, TableNameInfo tableName, TableNameInfo existedTableName, + ArrayList rollupNames, boolean withAllRollup) { + this.ifNotExists = ifNotExists; + this.tableName = tableName; + this.existedTableName = existedTableName; + this.rollupNames = rollupNames; + this.withAllRollup = withAllRollup; + } + + public CreateTableLikeStmt translateToLegacyStmt() throws DdlException { + return new CreateTableLikeStmt(ifNotExists, tableName.transferToTableName(), + existedTableName.transferToTableName(), rollupNames, withAllRollup); + } + + /** validate */ + public void validate(ConnectContext ctx) throws AnalysisException { + existedTableName.analyze(ctx); + // disallow external catalog + Util.prohibitExternalCatalog(existedTableName.getCtl(), "CreateTableLikeStmt"); + //check privilege + if (!Env.getCurrentEnv().getAccessManager() + .checkTblPriv(ctx, existedTableName.getCtl(), existedTableName.getDb(), + existedTableName.getTbl(), PrivPredicate.SELECT)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "SELECT"); + } + + tableName.analyze(ctx); + // disallow external catalog + Util.prohibitExternalCatalog(tableName.getCtl(), "CreateTableLikeStmt"); + FeNameFormat.checkTableName(tableName.getTbl()); + //check privilege + if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, tableName.getCtl(), tableName.getDb(), + tableName.getTbl(), PrivPredicate.CREATE)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "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 f82dd1a794..2aafd94ee4 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 @@ -27,6 +27,7 @@ import org.apache.doris.nereids.trees.plans.commands.CreateMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.CreatePolicyCommand; import org.apache.doris.nereids.trees.plans.commands.CreateProcedureCommand; import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand; +import org.apache.doris.nereids.trees.plans.commands.CreateTableLikeCommand; import org.apache.doris.nereids.trees.plans.commands.CreateViewCommand; import org.apache.doris.nereids.trees.plans.commands.DeleteFromCommand; import org.apache.doris.nereids.trees.plans.commands.DeleteFromUsingCommand; @@ -171,4 +172,8 @@ public interface CommandVisitor { default R visitUnsupportedCommand(UnsupportedCommand unsupportedCommand, C context) { return visitCommand(unsupportedCommand, context); } + + default R visitCreateTableLikeCommand(CreateTableLikeCommand createTableLikeCommand, C context) { + return visitCommand(createTableLikeCommand, context); + } } diff --git a/regression-test/data/ddl_p0/test_create_table_like_nereids.out b/regression-test/data/ddl_p0/test_create_table_like_nereids.out new file mode 100644 index 0000000000..4ecbecb150 --- /dev/null +++ b/regression-test/data/ddl_p0/test_create_table_like_nereids.out @@ -0,0 +1,20 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !test_without_roll_up -- +1 1 2 +1 1 4 +1 3 6 +2 1 3 +2 1 4 +2 1 7 +2 3 5 +2 3 9 +2 4 2 +3 2 8 +3 5 \N +3 5 6 +3 5 6 +3 5 8 +4 5 6 +6 \N 6 +6 7 1 + diff --git a/regression-test/suites/ddl_p0/test_create_table_like_nereids.groovy b/regression-test/suites/ddl_p0/test_create_table_like_nereids.groovy new file mode 100644 index 0000000000..c1a0f74e03 --- /dev/null +++ b/regression-test/suites/ddl_p0/test_create_table_like_nereids.groovy @@ -0,0 +1,75 @@ +// 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_create_table_like_nereids") { + sql "SET enable_nereids_planner=true;" + sql "SET enable_fallback_to_original_planner=false;" + + sql "drop table if exists mal_test_create_table_like" + sql """create table mal_test_create_table_like(pk int, a int, b int) distributed by hash(pk) buckets 10 + properties('replication_num' = '1');""" + sql """insert into mal_test_create_table_like values(2,1,3),(1,1,2),(3,5,6),(6,null,6),(4,5,6),(2,1,4),(2,3,5),(1,1,4) + ,(3,5,6),(3,5,null),(6,7,1),(2,1,7),(2,4,2),(2,3,9),(1,3,6),(3,5,8),(3,2,8);""" + sql "sync" + sql "alter table mal_test_create_table_like add rollup ru1(a,pk);" + sleep(2000) + sql "alter table mal_test_create_table_like add rollup ru2(b,pk);" + sleep(2000) + + // no rollup + sql "drop table if exists table_like" + sql "CREATE TABLE table_like LIKE mal_test_create_table_like;" + sql """insert into table_like values(2,1,3),(1,1,2),(3,5,6),(6,null,6),(4,5,6),(2,1,4),(2,3,5),(1,1,4) + ,(3,5,6),(3,5,null),(6,7,1),(2,1,7),(2,4,2),(2,3,9),(1,3,6),(3,5,8),(3,2,8);""" + "sync" + qt_test_without_roll_up "select * from table_like order by pk,a,b;" + + // with all rollup + sql "drop table if exists table_like_with_roll_up" + sql "CREATE TABLE table_like_with_roll_up LIKE mal_test_create_table_like with rollup;" + explain { + sql ("select sum(a) from table_like_with_roll_up group by a") + contains "ru1" + } ; + explain { + sql ("select sum(b) from table_like_with_roll_up group by b,pk ;") + contains "ru2" + } ; + + // with partial rollup + sql "drop table if exists table_like_with_partial_roll_up;" + sql "CREATE TABLE table_like_with_partial_roll_up LIKE mal_test_create_table_like with rollup (ru1);" + sql "select * from table_like_with_partial_roll_up order by pk, a, b" + explain { + sql("select sum(a) from table_like_with_partial_roll_up group by a") + contains("ru1") + } ; + explain { + sql ("select sum(b) from table_like_with_partial_roll_up group by b,pk ;") + notContains "ru2" + } ; + sql """insert into table_like_with_partial_roll_up values(2,1,3),(1,1,2),(3,5,6),(6,null,6),(4,5,6),(2,1,4),(2,3,5),(1,1,4) + ,(3,5,6),(3,5,null),(6,7,1),(2,1,7),(2,4,2),(2,3,9),(1,3,6),(3,5,8),(3,2,8);""" + sql "sync" + sleep(2000) + sql "select sum(a) from table_like_with_partial_roll_up group by a order by 1" + + // test if not exists + sql "drop table if exists table_like_with_partial_roll_up_exists" + sql """CREATE TABLE if not exists table_like_with_partial_roll_up_exists + LIKE mal_test_create_table_like with rollup (ru1);""" +} \ No newline at end of file