blob: 246b0e354757c99cb5567de8d12720c48225e255 [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.catalog;
import com.google.common.base.Preconditions;
import org.apache.impala.analysis.LiteralExpr;
import org.apache.impala.common.AnalysisException;
import org.apache.impala.common.ImpalaRuntimeException;
import org.apache.impala.thrift.TColumn;
import org.apache.impala.util.KuduUtil;
import org.apache.kudu.ColumnSchema.CompressionAlgorithm;
import org.apache.kudu.ColumnSchema.Encoding;
import org.apache.kudu.ColumnSchema;
/**
* Represents a Kudu column.
*
* This class extends Column with Kudu-specific information:
* - primary key
* - nullability constraint
* - encoding
* - compression
* - default value
* - desired block size
*/
public class KuduColumn extends Column {
// The name of the column as it appears in Kudu, i.e. not converted to lower case.
private final String kuduName_;
private final boolean isKey_;
private final boolean isNullable_;
private final Encoding encoding_;
private final CompressionAlgorithm compression_;
private final int blockSize_;
// Default value for this column. The expr is a literal of the target column type
// post-analysis. For TIMESTAMPs those are BIGINT values storing the unix time in
// microseconds. Code that references this may need to handle TIMESTAMP specially.
// For that reason, this isn't exposed publicly, e.g. getDefaultValueSql() is used
// to hide this complexity externally.
private final LiteralExpr defaultValue_;
private KuduColumn(String name, Type type, boolean isKey, boolean isNullable,
Encoding encoding, CompressionAlgorithm compression, LiteralExpr defaultValue,
int blockSize, String comment, int position) {
super(name.toLowerCase(), type, comment, position);
Preconditions.checkArgument(defaultValue == null || type == defaultValue.getType()
|| (type.isTimestamp() && defaultValue.getType().isIntegerType()));
kuduName_ = name;
isKey_ = isKey;
isNullable_ = isNullable;
encoding_ = encoding;
compression_ = compression;
defaultValue_ = defaultValue;
blockSize_ = blockSize;
}
public static KuduColumn fromColumnSchema(ColumnSchema colSchema, int position)
throws ImpalaRuntimeException {
Type type = KuduUtil.toImpalaType(colSchema.getType(), colSchema.getTypeAttributes());
Object defaultValue = colSchema.getDefaultValue();
LiteralExpr defaultValueExpr = null;
if (defaultValue != null) {
Type defaultValueType = type.isTimestamp() ? Type.BIGINT : type;
try {
defaultValueExpr = LiteralExpr.create(defaultValue.toString(), defaultValueType);
} catch (AnalysisException e) {
throw new ImpalaRuntimeException(String.format("Error parsing default value: " +
"'%s'", defaultValue), e);
}
Preconditions.checkNotNull(defaultValueExpr);
}
String comment = !colSchema.getComment().isEmpty() ? colSchema.getComment() : null;
return new KuduColumn(colSchema.getName(), type, colSchema.isKey(),
colSchema.isNullable(), colSchema.getEncoding(),
colSchema.getCompressionAlgorithm(), defaultValueExpr,
colSchema.getDesiredBlockSize(), comment, position);
}
public static KuduColumn fromThrift(TColumn column, int position)
throws ImpalaRuntimeException {
Preconditions.checkState(column.isSetIs_key());
Preconditions.checkState(column.isSetIs_nullable());
Type columnType = Type.fromThrift(column.getColumnType());
Encoding encoding = null;
if (column.isSetEncoding()) encoding = KuduUtil.fromThrift(column.getEncoding());
CompressionAlgorithm compression = null;
if (column.isSetCompression()) {
compression = KuduUtil.fromThrift(column.getCompression());
}
LiteralExpr defaultValue = null;
if (column.isSetDefault_value()) {
Type defaultValueType = columnType.isTimestamp() ? Type.BIGINT : columnType;
defaultValue =
LiteralExpr.fromThrift(column.getDefault_value().getNodes().get(0),
defaultValueType);
}
int blockSize = 0;
if (column.isSetBlock_size()) blockSize = column.getBlock_size();
String comment = (column.isSetComment() && !column.getComment().isEmpty()) ?
column.getComment() : null;
return new KuduColumn(column.getKudu_column_name(), columnType, column.isIs_key(),
column.isIs_nullable(), encoding, compression, defaultValue, blockSize, comment,
position);
}
public String getKuduName() { return kuduName_; }
public boolean isKey() { return isKey_; }
public boolean isNullable() { return isNullable_; }
public Encoding getEncoding() { return encoding_; }
public CompressionAlgorithm getCompression() { return compression_; }
public int getBlockSize() { return blockSize_; }
public boolean hasDefaultValue() { return defaultValue_ != null; }
/**
* Returns a SQL string representation of the default value. Similar to calling
* LiteralExpr.toSql(), but this handles TIMESTAMPs specially because
* TIMESTAMP default values are stored as BIGINTs representing unix time in
* microseconds. For TIMESTAMP columns, the returned string is the function to
* convert unix times in microseconds to TIMESTAMPs with the value as its parameter.
*/
public String getDefaultValueSql() {
if (!hasDefaultValue()) return null;
if (!type_.isTimestamp()) return defaultValue_.toSql();
return "unix_micros_to_utc_timestamp(" + defaultValue_.getStringValue() + ")";
}
/**
* Returns a string representation of the default value. This calls getStringValue()
* but is exposed so defaultValue_ can be encapsulated as it has special handling for
* TIMESTAMP column types.
*/
public String getDefaultValueString() {
if (!hasDefaultValue()) return null;
return defaultValue_.getStringValue();
}
@Override
public TColumn toThrift() {
TColumn colDesc = new TColumn(name_, type_.toThrift());
KuduUtil.setColumnOptions(colDesc, isKey_, isNullable_, encoding_, compression_,
defaultValue_, blockSize_, kuduName_);
if (comment_ != null) colDesc.setComment(comment_);
colDesc.setCol_stats(getStats().toThrift());
colDesc.setPosition(position_);
colDesc.setIs_kudu_column(true);
return colDesc;
}
}