From 4134db5ee307441149e450d6f65c271fa89c72f7 Mon Sep 17 00:00:00 2001 From: starocean999 Date: Mon, 3 Mar 2025 14:50:59 +0800 Subject: [PATCH] branch-2.1: [enhancement](nereids)remove dependence on old CreateTableStmt for CreateTableLikeCommand #48007 (#48528) pick from master https://github.com/apache/doris/pull/48007 ### What problem does this PR solve? Issue Number: close #xxx Related PR: #xxx Problem Summary: ### Release note None ### Check List (For Author) - Test - [ ] Regression test - [ ] Unit Test - [ ] Manual test (add detailed scripts or steps below) - [ ] No need to test or manual test. Explain why: - [ ] This is a refactor/code format and no logic has been changed. - [ ] Previous test can cover this change. - [ ] No code files have been changed. - [ ] Other reason - Behavior changed: - [ ] No. - [ ] Yes. - Does this need documentation? - [ ] No. - [ ] Yes. ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label --- .../plans/commands/CreateTableCommand.java | 4 ++ .../commands/CreateTableLikeCommand.java | 72 ++++++++++++++++++- .../plans/commands/info/CreateTableInfo.java | 15 ++++ .../test_create_table_like.groovy | 36 ++++++++++ 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 regression-test/suites/nereids_p0/create_table/test_create_table_like.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java index 00382ea457..8ccce661e2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java @@ -209,6 +209,10 @@ public class CreateTableCommand extends Command implements ForwardWithSync { return ctasQuery.isPresent(); } + public Optional getCtasQuery() { + return ctasQuery; + } + @Override public R accept(PlanVisitor visitor, C context) { return visitor.visitCreateTableCommand(this, context); 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 index a271623ef0..1fd359b859 100644 --- 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 @@ -18,13 +18,27 @@ package org.apache.doris.nereids.trees.plans.commands; import org.apache.doris.analysis.CreateTableLikeStmt; +import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.OlapTable; +import org.apache.doris.catalog.TableIf; +import org.apache.doris.common.DdlException; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.UserException; +import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.trees.plans.PlanType; +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.visitor.PlanVisitor; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.StmtExecutor; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; + +import java.util.List; + /** CreateTableLikeCommand */ public class CreateTableLikeCommand extends Command implements ForwardWithSync { private final CreateTableLikeInfo info; @@ -39,11 +53,67 @@ public class CreateTableLikeCommand extends Command implements ForwardWithSync { executor.checkBlockRules(); info.validate(ctx); CreateTableLikeStmt stmt = info.translateToLegacyStmt(); - Env.getCurrentEnv().createTableLike(stmt); + doRun(stmt, ctx, executor); } @Override public R accept(PlanVisitor visitor, C context) { return visitor.visitCreateTableLikeCommand(this, context); } + + private void doRun(CreateTableLikeStmt stmt, ConnectContext ctx, StmtExecutor executor) throws Exception { + try { + DatabaseIf db = Env.getCurrentInternalCatalog().getDbOrDdlException(stmt.getExistedDbName()); + TableIf table = db.getTableOrDdlException(stmt.getExistedTableName()); + + if (table.getType() == TableIf.TableType.VIEW) { + throw new DdlException("Not support create table from a View"); + } + + List createTableStmt = Lists.newArrayList(); + table.readLock(); + try { + if (table.isManagedTable()) { + if (!CollectionUtils.isEmpty(stmt.getRollupNames())) { + OlapTable olapTable = (OlapTable) table; + for (String rollupIndexName : stmt.getRollupNames()) { + if (!olapTable.hasMaterializedIndex(rollupIndexName)) { + throw new DdlException("Rollup index[" + rollupIndexName + "] not exists in Table[" + + olapTable.getName() + "]"); + } + } + } + } else if (!CollectionUtils.isEmpty(stmt.getRollupNames()) || stmt.isWithAllRollup()) { + throw new DdlException("Table[" + table.getName() + "] is external, not support rollup copy"); + } + + Env.getDdlStmt(stmt, stmt.getDbName(), table, createTableStmt, null, null, false, false, true, -1L, + false, false); + if (createTableStmt.isEmpty()) { + ErrorReport.reportDdlException(ErrorCode.ERROR_CREATE_TABLE_LIKE_EMPTY, "CREATE"); + } + } finally { + table.readUnlock(); + } + + try { + // analyze CreateTableStmt will check create_priv of existedTable, create table like only need + // create_priv of newTable, and select_priv of existedTable, and priv check has done in + // CreateTableStmt/CreateTableCommand, so we skip it + ctx.setSkipAuth(true); + NereidsParser nereidsParser = new NereidsParser(); + CreateTableCommand createTableCommand = (CreateTableCommand) nereidsParser + .parseSingle(createTableStmt.get(0)); + CreateTableInfo createTableInfo = createTableCommand.getCreateTableInfo(); + createTableCommand = new CreateTableCommand(createTableCommand.getCtasQuery(), + createTableInfo.withTableNameAndIfNotExists(stmt.getTableName(), stmt.isIfNotExists())); + createTableCommand.run(ctx, executor); + } finally { + ctx.setSkipAuth(false); + } + } catch (UserException e) { + throw new DdlException("Failed to execute CREATE TABLE LIKE " + stmt.getExistedTableName() + ". Reason: " + + e.getMessage(), e); + } + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java index 58ea028ecc..ac7a4306d1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java @@ -166,6 +166,21 @@ public class CreateTableInfo { this.clusterKeysColumnNames = Utils.copyRequiredList(clusterKeyColumnNames); } + /** + * withTableNameAndIfNotExists + */ + public CreateTableInfo withTableNameAndIfNotExists(String tableName, boolean ifNotExists) { + if (ctasColumns != null) { + return new CreateTableInfo(ifNotExists, isExternal, ctlName, dbName, tableName, ctasColumns, engineName, + keysType, keys, comment, partitionTableInfo, distribution, rollups, properties, extProperties, + clusterKeysColumnNames); + } else { + return new CreateTableInfo(ifNotExists, isExternal, ctlName, dbName, tableName, columns, indexes, + engineName, keysType, keys, comment, partitionTableInfo, distribution, rollups, properties, + extProperties, clusterKeysColumnNames); + } + } + public List getCtasColumns() { return ctasColumns; } diff --git a/regression-test/suites/nereids_p0/create_table/test_create_table_like.groovy b/regression-test/suites/nereids_p0/create_table/test_create_table_like.groovy new file mode 100644 index 0000000000..5da7ba5d57 --- /dev/null +++ b/regression-test/suites/nereids_p0/create_table/test_create_table_like.groovy @@ -0,0 +1,36 @@ +// 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. + +// this suite is for creating table with timestamp datatype in defferent +// case. For example: 'year' and 'Year' datatype should also be valid in definition + +suite("test_create_table_like") { + multi_sql """ + DROP TABLE IF EXISTS test_create_table_like_t1; + CREATE TABLE `test_create_table_like_t1` ( + `id` int NULL, + `m_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE=OLAP + UNIQUE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS AUTO + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + DROP TABLE IF EXISTS test_create_table_like_t2; + CREATE TABLE test_create_table_like_t2 like test_create_table_like_t1; + """ +} \ No newline at end of file