blob: cecb214c0bd0a162cc8f841276bc70e5cef797fe [file] [log] [blame]
// 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.impala.analysis;
import java.util.List;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.impala.authorization.Privilege;
import org.apache.impala.catalog.FeTable;
import org.apache.impala.catalog.KuduTable;
import org.apache.impala.common.AnalysisException;
import org.apache.impala.common.Pair;
import org.apache.impala.thrift.TAccessEvent;
import org.apache.impala.thrift.TCatalogObjectType;
import org.apache.impala.thrift.TCreateTableLikeParams;
import org.apache.impala.thrift.THdfsFileFormat;
import org.apache.impala.thrift.TSortingOrder;
import org.apache.impala.thrift.TTableName;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
/**
* Represents a CREATE TABLE LIKE statement which creates a new table based on
* a copy of an existing table definition.
*/
public class CreateTableLikeStmt extends StatementBase {
private final TableName tableName_;
private final List<String> sortColumns_;
private final TSortingOrder sortingOrder_;
private final TableName srcTableName_;
private final boolean isExternal_;
private final String comment_;
private final THdfsFileFormat fileFormat_;
private final HdfsUri location_;
private final boolean ifNotExists_;
// Set during analysis
private String dbName_;
private String srcDbName_;
private String owner_;
// Server name needed for privileges. Set during analysis.
private String serverName_;
/**
* Builds a CREATE TABLE LIKE statement
* @param tableName - Name of the new table
* @param sortProperties - A pair, containing the list of columns to sort by during
* inserts and the order used in SORT BY queries.
* @param srcTableName - Name of the source table (table to copy)
* @param isExternal - If true, the table's data will be preserved if dropped.
* @param comment - Comment to attach to the table
* @param fileFormat - File format of the table
* @param location - The HDFS location of where the table data will stored.
* @param ifNotExists - If true, no errors are thrown if the table already exists
*/
public CreateTableLikeStmt(TableName tableName,
Pair<List<String>, TSortingOrder> sortProperties, TableName srcTableName,
boolean isExternal, String comment, THdfsFileFormat fileFormat, HdfsUri location,
boolean ifNotExists) {
Preconditions.checkNotNull(tableName);
Preconditions.checkNotNull(srcTableName);
this.tableName_ = tableName;
this.sortColumns_ = sortProperties.first;
this.sortingOrder_ = sortProperties.second;
this.srcTableName_ = srcTableName;
this.isExternal_ = isExternal;
this.comment_ = comment;
this.fileFormat_ = fileFormat;
this.location_ = location;
this.ifNotExists_ = ifNotExists;
}
public String getTbl() { return tableName_.getTbl(); }
public String getSrcTbl() { return srcTableName_.getTbl(); }
public boolean isExternal() { return isExternal_; }
public boolean getIfNotExists() { return ifNotExists_; }
public THdfsFileFormat getFileFormat() { return fileFormat_; }
public HdfsUri getLocation() { return location_; }
public TSortingOrder getSortingOrder() { return sortingOrder_; }
/**
* Can only be called after analysis, returns the name of the database the table will
* be created within.
*/
public String getDb() {
Preconditions.checkNotNull(dbName_);
return dbName_;
}
/**
* Can only be called after analysis, returns the name of the database the table will
* be created within.
*/
public String getSrcDb() {
Preconditions.checkNotNull(srcDbName_);
return srcDbName_;
}
public String getOwner() {
Preconditions.checkNotNull(owner_);
return owner_;
}
@Override
public String toSql(ToSqlOptions options) {
StringBuilder sb = new StringBuilder("CREATE ");
if (isExternal_) sb.append("EXTERNAL ");
sb.append("TABLE ");
if (ifNotExists_) sb.append("IF NOT EXISTS ");
if (tableName_.getDb() != null) sb.append(tableName_.getDb() + ".");
sb.append(tableName_.getTbl() + " ");
if (sortColumns_ != null && !sortColumns_.isEmpty()) {
sb.append(String.format("SORT BY %s (%s) ", sortingOrder_.toString(),
Joiner.on(",").join(sortColumns_)));
}
sb.append("LIKE ");
if (srcTableName_.getDb() != null) sb.append(srcTableName_.getDb() + ".");
sb.append(srcTableName_.getTbl());
if (comment_ != null) sb.append(" COMMENT '" + comment_ + "'");
if (fileFormat_ != null) sb.append(" STORED AS " + fileFormat_);
if (location_ != null) sb.append(" LOCATION '" + location_ + "'");
return sb.toString();
}
public TCreateTableLikeParams toThrift() {
TCreateTableLikeParams params = new TCreateTableLikeParams();
params.setTable_name(new TTableName(getDb(), getTbl()));
params.setSrc_table_name(new TTableName(getSrcDb(), getSrcTbl()));
params.setOwner(getOwner());
params.setIs_external(isExternal());
params.setComment(comment_);
if (fileFormat_ != null) params.setFile_format(fileFormat_);
params.setLocation(location_ == null ? null : location_.toString());
params.setIf_not_exists(getIfNotExists());
params.setSort_columns(sortColumns_);
params.setServer_name(serverName_);
params.setSorting_order(sortingOrder_);
return params;
}
@Override
public void collectTableRefs(List<TableRef> tblRefs) {
tblRefs.add(new TableRef(tableName_.toPath(), null));
tblRefs.add(new TableRef(srcTableName_.toPath(), null));
}
@Override
public void analyze(Analyzer analyzer) throws AnalysisException {
Preconditions.checkState(tableName_ != null && !tableName_.isEmpty());
Preconditions.checkState(srcTableName_ != null && !srcTableName_.isEmpty());
// We currently don't support creating a Kudu table using a CREATE TABLE LIKE
// statement (see IMPALA-4052).
if (fileFormat_ == THdfsFileFormat.KUDU) {
throw new AnalysisException("CREATE TABLE LIKE is not supported for Kudu tables");
}
// Make sure the source table exists and the user has permission to access it.
FeTable srcTable = analyzer.getTable(srcTableName_, Privilege.VIEW_METADATA);
analyzer.ensureTableNotFullAcid(srcTable);
analyzer.ensureTableNotBucketed(srcTable);
if (KuduTable.isKuduTable(srcTable.getMetaStoreTable())) {
throw new AnalysisException("Cloning a Kudu table using CREATE TABLE LIKE is " +
"not supported.");
}
srcDbName_ = srcTable.getDb().getName();
analyzer.getFqTableName(tableName_).analyze();
dbName_ = analyzer.getTargetDbName(tableName_);
owner_ = analyzer.getUserShortName();
// Set the servername here if authorization is enabled because analyzer_ is not
// available in the toThrift() method.
serverName_ = analyzer.getServerName();
if (analyzer.dbContainsTable(dbName_, tableName_.getTbl(), Privilege.CREATE) &&
!ifNotExists_) {
throw new AnalysisException(Analyzer.TBL_ALREADY_EXISTS_ERROR_MSG +
String.format("%s.%s", dbName_, getTbl()));
}
analyzer.addAccessEvent(new TAccessEvent(dbName_ + "." + tableName_.getTbl(),
TCatalogObjectType.TABLE, Privilege.CREATE.toString()));
if (location_ != null) {
location_.analyze(analyzer, Privilege.ALL, FsAction.READ_WRITE);
}
if (sortColumns_ != null) {
TableDef.analyzeSortColumns(sortColumns_, srcTable, sortingOrder_);
}
}
}