Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
{
"title": "CREATE TABLE LIKE",
"language": "en"
}
---

<!--
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.
-->

# CREATE TABLE LIKE

## description

Use CREATE TABLE ... LIKE to create an empty table based on the definition of another table, including any column attributes, table partitions and table properties defined in the original table:
Syntax:

```
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [database.]table_name LIKE [database.]table_name
```

Explain:
1. The replicated table structures include Column Defination, Partitions, Table Properties, and so on
2. The SELECT privilege is required on the original table.
3. Support to copy external table such as MySQL.

## Example
1. Under the test1 Database, create an empty table with the same table structure as table1, named table2

CREATE TABLE test1.table2 LIKE test1.table1

2. Under the test2 Database, create an empty table with the same table structure as test1.table1, named table2

CREATE TABLE test2.table2 LIKE test1.table1

3. Under the test1 Database, create an empty table with the same table structure as MySQL's external table1, called table2

CREATE TABLE test1.table2 LIKE test1.table1

## keyword

```
CREATE,TABLE,LIKE

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
{
"title": "CREATE TABLE LIKE",
"language": "zh-CN"
}
---

<!--
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.
-->

# CREATE TABLE LIKE

## description

该语句用于创建一个表结构和另一张表完全相同的空表。
语法:

```
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [database.]table_name LIKE [database.]table_name
```

说明:
1. 复制的表结构包括Column Defination、Partitions、Table Properties等
2. 用户需要对复制的原表有`SELECT`权限
3. 支持复制MySQL等外表

## Example
1. 在test1库下创建一张表结构和table1相同的空表,表名为table2

CREATE TABLE test1.table2 LIKE test1.table1

2. 在test2库下创建一张表结构和test1.table1相同的空表,表名为table2

CREATE TABLE test2.table2 LIKE test1.table1

3. 在test1库下创建一张表结构和MySQL外表table1相同的空表,表名为table2

CREATE TABLE test1.table2 LIKE test1.table1

## keyword

```
CREATE,TABLE,LIKE

```
8 changes: 6 additions & 2 deletions fe/fe-core/src/main/cup/sql_parser.cup
Original file line number Diff line number Diff line change
Expand Up @@ -1097,11 +1097,15 @@ create_stmt ::=
:}*/
/* Function */
| KW_CREATE opt_aggregate:isAggregate KW_FUNCTION function_name:functionName LPAREN func_args_def:args RPAREN
KW_RETURNS type_def:retrunType opt_intermediate_type:intermediateType opt_properties:properties
KW_RETURNS type_def:returnType opt_intermediate_type:intermediateType opt_properties:properties
{:
RESULT = new CreateFunctionStmt(isAggregate, functionName, args, retrunType, intermediateType, properties);
RESULT = new CreateFunctionStmt(isAggregate, functionName, args, returnType, intermediateType, properties);
:}
/* Table */
| KW_CREATE opt_external:isExternal KW_TABLE opt_if_not_exists:ifNotExists table_name:name KW_LIKE table_name:existed_name
{:
RESULT = new CreateTableLikeStmt(ifNotExists, name, existed_name);
:}
| KW_CREATE opt_external:isExternal KW_TABLE opt_if_not_exists:ifNotExists table_name:name
LPAREN column_definition_list:columns RPAREN opt_engine:engineName
opt_keys:keys
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// 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.analysis;

import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* @author wangcong
* @version 1.0
* @date 2020/10/7 10:32 上午
*/
public class CreateTableLikeStmt extends DdlStmt {
private static final Logger LOG = LogManager.getLogger(CreateTableLikeStmt.class);

private final boolean ifNotExists;
private final TableName tableName;
private final TableName existedTableName;

public CreateTableLikeStmt(boolean ifNotExists, TableName tableName, TableName existedTableName) {
this.ifNotExists = ifNotExists;
this.tableName = tableName;
this.existedTableName = existedTableName;
}

public boolean isSetIfNotExists() {
return ifNotExists;
}

public String getDbName() {
return tableName.getDb();
}

public String getTableName() {
return tableName.getTbl();
}

public String getExistedDbName() {
return existedTableName.getDb();
}

public String getExistedTableName() {
return existedTableName.getTbl();
}

@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
existedTableName.analyze(analyzer);
ConnectContext ctx = ConnectContext.get();
if (!Catalog.getCurrentCatalog().getAuth().checkTblPriv(ctx, existedTableName.getDb(),
existedTableName.getTbl(), PrivPredicate.SELECT)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "SELECT");
}

tableName.analyze(analyzer);
FeNameFormat.checkTableName(getTableName());
if (!Catalog.getCurrentCatalog().getAuth().checkTblPriv(ctx, tableName.getDb(),
tableName.getTbl(), PrivPredicate.CREATE)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "CREATE");
}
}

@Override
public String toSql() {
return String.format("CREATE TABLE %s LIKE %s", tableName.toSql(), existedTableName.toSql());
}

@Override
public String toString() {
return toSql();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -561,9 +561,6 @@ public String toString() {

@Override
public boolean needAuditEncryption() {
if (!engineName.equals("olap")) {
return true;
}
return false;
return !engineName.equals("olap");
}
}
57 changes: 55 additions & 2 deletions fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.apache.doris.analysis.CreateDbStmt;
import org.apache.doris.analysis.CreateFunctionStmt;
import org.apache.doris.analysis.CreateMaterializedViewStmt;
import org.apache.doris.analysis.CreateTableLikeStmt;
import org.apache.doris.analysis.CreateTableStmt;
import org.apache.doris.analysis.CreateUserStmt;
import org.apache.doris.analysis.CreateViewStmt;
Expand Down Expand Up @@ -121,6 +122,7 @@
import org.apache.doris.common.util.PropertyAnalyzer;
import org.apache.doris.common.util.QueryableReentrantLock;
import org.apache.doris.common.util.SmallFileMgr;
import org.apache.doris.common.util.SqlParserUtils;
import org.apache.doris.common.util.TimeUtils;
import org.apache.doris.common.util.Util;
import org.apache.doris.consistency.ConsistencyChecker;
Expand Down Expand Up @@ -2274,6 +2276,7 @@ protected void runAfterCatalogReady() {

public void createReplayer() {
replayer = new Daemon("replayer", REPLAY_INTERVAL_MS) {
@Override
protected void runOneCycle() {
boolean err = false;
boolean hasLog = false;
Expand Down Expand Up @@ -2995,7 +2998,25 @@ public void replayRenameDatabase(String dbName, String newDbName) {
LOG.info("replay rename database {} to {}", dbName, newDbName);
}

public void createTable(CreateTableStmt stmt) throws DdlException {
/**
* Following is the step to create an olap table:
* 1. create columns
* 2. create partition info
* 3. create distribution info
* 4. set table id and base index id
* 5. set bloom filter columns
* 6. set and build TableProperty includes:
* 6.1. dynamicProperty
* 6.2. replicationNum
* 6.3. inMemory
* 6.4. storageFormat
* 7. set index meta
* 8. check colocation properties
* 9. create tablet in BE
* 10. add this table to FE's meta
* 11. add this table to ColocateGroup if necessary
*/
public void createTable(CreateTableStmt stmt) throws DdlException {
String engineName = stmt.getEngineName();
String dbName = stmt.getDbName();
String tableName = stmt.getTableName();
Expand Down Expand Up @@ -3055,7 +3076,31 @@ public void createTable(CreateTableStmt stmt) throws DdlException {
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_STORAGE_ENGINE, engineName);
}
Preconditions.checkState(false);
return;
}

public void createTableLike(CreateTableLikeStmt stmt) throws DdlException {
try {
Database db = Catalog.getCurrentCatalog().getDb(stmt.getExistedDbName());
List<String> createTableStmt = Lists.newArrayList();
db.readLock();
try {
Table table = db.getTable(stmt.getExistedTableName());
if (table == null) {
ErrorReport.reportDdlException(ErrorCode.ERR_BAD_TABLE_ERROR, stmt.getExistedTableName());
}
Catalog.getDdlStmt(stmt.getDbName(), table, createTableStmt, null, null, false, false);
if (createTableStmt.isEmpty()) {
ErrorReport.reportDdlException(ErrorCode.ERROR_CREATE_TABLE_LIKE_EMPTY, "CREATE");
}
} finally {
db.readUnlock();
}
CreateTableStmt parsedCreateTableStmt = (CreateTableStmt) SqlParserUtils.parseAndAnalyzeStmt(createTableStmt.get(0), ConnectContext.get());
parsedCreateTableStmt.setTableName(stmt.getTableName());
createTable(parsedCreateTableStmt);
} catch (UserException e) {
throw new DdlException("Failed to execute CREATE TABLE LIKE " + stmt.getExistedTableName() + ". Reason: " + e.getMessage());
}
}

public void addPartition(Database db, String tableName, AddPartitionClause addPartitionClause) throws DdlException {
Expand Down Expand Up @@ -3926,6 +3971,11 @@ private void createHiveTable(Database db, CreateTableStmt stmt) throws DdlExcept

public static void getDdlStmt(Table table, List<String> createTableStmt, List<String> addPartitionStmt,
List<String> createRollupStmt, boolean separatePartition, boolean hidePassword) {
getDdlStmt(null, table, createTableStmt, addPartitionStmt, createRollupStmt, separatePartition, hidePassword);
}

public static void getDdlStmt(String dbName, Table table, List<String> createTableStmt, List<String> addPartitionStmt,
List<String> createRollupStmt, boolean separatePartition, boolean hidePassword) {
StringBuilder sb = new StringBuilder();

// 1. create table
Expand All @@ -3945,6 +3995,9 @@ public static void getDdlStmt(Table table, List<String> createTableStmt, List<St
sb.append("EXTERNAL ");
}
sb.append("TABLE ");
if (!Strings.isNullOrEmpty(dbName)) {
sb.append("`").append(dbName).append("`.");
}
sb.append("`").append(table.getName()).append("` (\n");
int idx = 0;
for (Column column : table.getBaseSchema()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public String getProperties(int tableReplicationNum) {
}
String res = ",\n\"" + ENABLE + "\" = \"" + enable + "\"" +
",\n\"" + TIME_UNIT + "\" = \"" + timeUnit + "\"" +
",\n\"" + TIME_ZONE + "\" = \"" + tz + "\"" +
",\n\"" + TIME_ZONE + "\" = \"" + tz.getID() + "\"" +
",\n\"" + START + "\" = \"" + start + "\"" +
",\n\"" + END + "\" = \"" + end + "\"" +
",\n\"" + PREFIX + "\" = \"" + prefix + "\"" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ public enum ErrorCode {
ERROR_DYNAMIC_PARTITION_REPLICATION_NUM_ZERO(5071, new byte[] {'4', '2', '0', '0', '0'},
"Dynamic partition replication num must greater than 0"),
ERROR_DYNAMIC_PARTITION_REPLICATION_NUM_FORMAT(5072, new byte[] {'4', '2', '0', '0', '0'},
"Invalid dynamic partition replication num: %s.");
"Invalid dynamic partition replication num: %s."),
ERROR_CREATE_TABLE_LIKE_EMPTY(5073, new byte[] {'4', '2', '0', '0', '0'},
"Origin create table stmt is empty");

ErrorCode(int code, byte[] sqlState, String errorMsg) {
this.code = code;
Expand Down
Loading