blob: 6951e6a6d7a838f97e93467427c0364db6f34163 [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.
#include "kudu/common/partial_row.h"
#include <cstring>
#include <ostream>
#include <string>
#include <utility>
#include <glog/logging.h>
#include "kudu/common/common.pb.h"
#include "kudu/common/key_encoder.h"
#include "kudu/common/row.h"
#include "kudu/common/schema.h"
#include "kudu/common/types.h"
#include "kudu/gutil/port.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/util/bitmap.h"
#include "kudu/util/char_util.h"
#include "kudu/util/decimal_util.h"
#include "kudu/util/int128.h"
#include "kudu/util/logging.h"
#ifndef NDEBUG
#include "kudu/util/memory/overwrite.h"
#endif
#include "kudu/util/status.h"
using std::string;
using strings::Substitute;
namespace kudu {
namespace {
Status CheckDateValueInRange(int col_idx, int32_t val, const Schema& schema) {
if (PREDICT_FALSE(!DataTypeTraits<DATE>::IsValidValue(val))) {
const ColumnSchema& col = schema.column(col_idx);
return Status::InvalidArgument(
Substitute("value $0 out of range for date column '$1'", val, col.name()));
}
return Status::OK();
}
} // anonymous namespace
KuduPartialRow::KuduPartialRow(const Schema* schema)
: schema_(schema) {
DCHECK(schema_->initialized());
size_t column_bitmap_size = BitmapSize(schema_->num_columns());
size_t row_size = ContiguousRowHelper::row_size(*schema);
auto dst = new uint8_t[2 * column_bitmap_size + row_size];
isset_bitmap_ = dst;
owned_strings_bitmap_ = isset_bitmap_ + column_bitmap_size;
memset(isset_bitmap_, 0, 2 * column_bitmap_size);
row_data_ = owned_strings_bitmap_ + column_bitmap_size;
#ifndef NDEBUG
OverwriteWithPattern(reinterpret_cast<char*>(row_data_),
row_size, "NEWNEWNEWNEWNEW");
#endif
ContiguousRowHelper::InitNullsBitmap(
*schema_, row_data_, ContiguousRowHelper::non_null_bitmap_size(*schema_));
}
KuduPartialRow::~KuduPartialRow() {
DeallocateOwnedStrings();
// Both the row data and bitmap came from the same allocation.
// The bitmap is at the start of it.
delete [] isset_bitmap_;
}
KuduPartialRow::KuduPartialRow(const KuduPartialRow& other)
: schema_(other.schema_) {
size_t column_bitmap_size = BitmapSize(schema_->num_columns());
size_t row_size = ContiguousRowHelper::row_size(*schema_);
size_t len = 2 * column_bitmap_size + row_size;
isset_bitmap_ = new uint8_t[len];
owned_strings_bitmap_ = isset_bitmap_ + column_bitmap_size;
row_data_ = owned_strings_bitmap_ + column_bitmap_size;
// Copy all bitmaps and row data.
memcpy(isset_bitmap_, other.isset_bitmap_, len);
// Copy owned strings.
for (int col_idx = 0; col_idx < schema_->num_columns(); col_idx++) {
if (BitmapTest(owned_strings_bitmap_, col_idx)) {
ContiguousRow row(schema_, row_data_);
Slice* slice = reinterpret_cast<Slice*>(row.mutable_cell_ptr(col_idx));
auto* data = new uint8_t[slice->size()];
slice->relocate(data);
}
}
}
KuduPartialRow& KuduPartialRow::operator=(KuduPartialRow other) {
std::swap(schema_, other.schema_);
std::swap(isset_bitmap_, other.isset_bitmap_);
std::swap(owned_strings_bitmap_, other.owned_strings_bitmap_);
std::swap(row_data_, other.row_data_);
return *this;
}
template<typename T>
Status KuduPartialRow::Set(const Slice& col_name,
const typename T::cpp_type& val,
bool owned) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return Set<T>(col_idx, val, owned);
}
template<typename T>
Status KuduPartialRow::Set(int col_idx,
const typename T::cpp_type& val,
bool owned) {
const ColumnSchema& col = schema_->column(col_idx);
if (PREDICT_FALSE(col.type_info()->type() != T::type)) {
// TODO: at some point we could allow type coercion here.
return Status::InvalidArgument(
Substitute("invalid type $0 provided for column '$1' (expected $2)",
T::name(),
col.name(), col.type_info()->name()));
}
ContiguousRow row(schema_, row_data_);
// If we're replacing an existing STRING/BINARY value, deallocate the old value.
if (T::physical_type == BINARY) DeallocateStringIfSet(col_idx, col);
// Mark the column as set.
BitmapSet(isset_bitmap_, col_idx);
if (col.is_nullable()) {
row.set_null(col_idx, false);
}
ContiguousRowCell<ContiguousRow> dst(&row, col_idx);
memcpy(dst.mutable_ptr(), &val, sizeof(val));
if (owned) {
BitmapSet(owned_strings_bitmap_, col_idx);
}
return Status::OK();
}
Status KuduPartialRow::Set(int32_t column_idx, const uint8_t* val) {
const ColumnSchema& column_schema = schema()->column(column_idx);
switch (column_schema.type_info()->type()) {
case BOOL: {
RETURN_NOT_OK(SetBool(column_idx, *reinterpret_cast<const bool*>(val)));
break;
}
case INT8: {
RETURN_NOT_OK(SetInt8(column_idx, *reinterpret_cast<const int8_t*>(val)));
break;
}
case INT16: {
RETURN_NOT_OK(SetInt16(column_idx, *reinterpret_cast<const int16_t*>(val)));
break;
}
case INT32: {
RETURN_NOT_OK(SetInt32(column_idx, *reinterpret_cast<const int32_t*>(val)));
break;
}
case INT64: {
RETURN_NOT_OK(SetInt64(column_idx, *reinterpret_cast<const int64_t*>(val)));
break;
}
case FLOAT: {
RETURN_NOT_OK(SetFloat(column_idx, *reinterpret_cast<const float*>(val)));
break;
}
case DOUBLE: {
RETURN_NOT_OK(SetDouble(column_idx, *reinterpret_cast<const double*>(val)));
break;
}
case STRING: {
// TODO(todd) Is reinterpret_cast unsafe here?
RETURN_NOT_OK(SetStringCopy(column_idx, *reinterpret_cast<const Slice*>(val)));
break;
}
case BINARY: {
// TODO(todd) Is reinterpret_cast unsafe here?
RETURN_NOT_OK(SetBinaryCopy(column_idx, *reinterpret_cast<const Slice*>(val)));
break;
}
case VARCHAR: {
RETURN_NOT_OK(SetVarchar(column_idx, *reinterpret_cast<const Slice*>(val)));
break;
}
case UNIXTIME_MICROS: {
RETURN_NOT_OK(SetUnixTimeMicros(column_idx, *reinterpret_cast<const int64_t*>(val)));
break;
}
case DATE: {
RETURN_NOT_OK(SetDate(column_idx, *reinterpret_cast<const int32_t*>(val)));
break;
}
case DECIMAL32: {
RETURN_NOT_OK(Set<TypeTraits<DECIMAL32> >(column_idx,
*reinterpret_cast<const int32_t*>(val)));
break;
}
case DECIMAL64: {
RETURN_NOT_OK(Set<TypeTraits<DECIMAL64> >(column_idx,
*reinterpret_cast<const int64_t*>(val)));
break;
}
case DECIMAL128: {
RETURN_NOT_OK(Set<TypeTraits<DECIMAL128>>(column_idx, UnalignedLoad<int128_t>(val)));
break;
}
default: {
return Status::InvalidArgument("Unknown column type in schema",
column_schema.ToString());
}
}
return Status::OK();
}
void KuduPartialRow::DeallocateStringIfSet(int col_idx, const ColumnSchema& col) {
if (BitmapTest(owned_strings_bitmap_, col_idx)) {
ContiguousRow row(schema_, row_data_);
const Slice* dst;
switch (col.type_info()->type()) {
case BINARY:
dst = schema_->ExtractColumnFromRow<BINARY>(row, col_idx);
break;
case VARCHAR:
dst = schema_->ExtractColumnFromRow<VARCHAR>(row, col_idx);
break;
case STRING:
dst = schema_->ExtractColumnFromRow<STRING>(row, col_idx);
break;
default:
LOG(FATAL) << "Unexpected type " << col.type_info()->type();
break;
}
delete [] dst->data();
BitmapClear(owned_strings_bitmap_, col_idx);
}
}
void KuduPartialRow::DeallocateOwnedStrings() {
for (int i = 0; i < schema_->num_columns(); i++) {
DeallocateStringIfSet(i, schema_->column(i));
}
}
//------------------------------------------------------------
// Setters
//------------------------------------------------------------
Status KuduPartialRow::SetBool(const Slice& col_name, bool val) {
return Set<TypeTraits<BOOL> >(col_name, val);
}
Status KuduPartialRow::SetInt8(const Slice& col_name, int8_t val) {
return Set<TypeTraits<INT8> >(col_name, val);
}
Status KuduPartialRow::SetInt16(const Slice& col_name, int16_t val) {
return Set<TypeTraits<INT16> >(col_name, val);
}
Status KuduPartialRow::SetInt32(const Slice& col_name, int32_t val) {
return Set<TypeTraits<INT32> >(col_name, val);
}
Status KuduPartialRow::SetInt64(const Slice& col_name, int64_t val) {
return Set<TypeTraits<INT64> >(col_name, val);
}
Status KuduPartialRow::SetUnixTimeMicros(const Slice& col_name, int64_t micros_since_utc_epoch) {
return Set<TypeTraits<UNIXTIME_MICROS> >(col_name, micros_since_utc_epoch);
}
Status KuduPartialRow::SetDate(const Slice& col_name, int32_t days_since_unix_epoch) {
return Set<TypeTraits<DATE> >(col_name, days_since_unix_epoch);
}
Status KuduPartialRow::SetFloat(const Slice& col_name, float val) {
return Set<TypeTraits<FLOAT> >(col_name, val);
}
Status KuduPartialRow::SetDouble(const Slice& col_name, double val) {
return Set<TypeTraits<DOUBLE> >(col_name, val);
}
Status KuduPartialRow::SetUnscaledDecimal(const Slice& col_name, int128_t val) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return SetUnscaledDecimal(col_idx, val);
}
Status KuduPartialRow::SetBool(int col_idx, bool val) {
return Set<TypeTraits<BOOL> >(col_idx, val);
}
Status KuduPartialRow::SetInt8(int col_idx, int8_t val) {
return Set<TypeTraits<INT8> >(col_idx, val);
}
Status KuduPartialRow::SetInt16(int col_idx, int16_t val) {
return Set<TypeTraits<INT16> >(col_idx, val);
}
Status KuduPartialRow::SetInt32(int col_idx, int32_t val) {
return Set<TypeTraits<INT32> >(col_idx, val);
}
Status KuduPartialRow::SetInt64(int col_idx, int64_t val) {
return Set<TypeTraits<INT64> >(col_idx, val);
}
Status KuduPartialRow::SetUnixTimeMicros(int col_idx, int64_t micros_since_utc_epoch) {
return Set<TypeTraits<UNIXTIME_MICROS> >(col_idx, micros_since_utc_epoch);
}
Status KuduPartialRow::SetDate(int col_idx, int32_t days_since_unix_epoch) {
RETURN_NOT_OK(CheckDateValueInRange(col_idx, days_since_unix_epoch, *schema_));
return Set<TypeTraits<DATE> >(col_idx, days_since_unix_epoch);
}
Status KuduPartialRow::SetFloat(int col_idx, float val) {
return Set<TypeTraits<FLOAT> >(col_idx, val);
}
Status KuduPartialRow::SetDouble(int col_idx, double val) {
return Set<TypeTraits<DOUBLE> >(col_idx, val);
}
Status CheckDecimalValueInRange(ColumnSchema col, int128_t val) {
int128_t max_val = MaxUnscaledDecimal(col.type_attributes().precision);
int128_t min_val = -max_val;
if (val < min_val || val > max_val) {
return Status::InvalidArgument(
Substitute("value $0 out of range for decimal column '$1'",
DecimalToString(val, col.type_attributes().scale), col.name()));
}
return Status::OK();
}
Status KuduPartialRow::SetUnscaledDecimal(int col_idx, int128_t val) {
const ColumnSchema& col = schema_->column(col_idx);
const DataType col_type = col.type_info()->type();
switch (col_type) {
case DECIMAL32:
RETURN_NOT_OK(CheckDecimalValueInRange(col, val));
return Set<TypeTraits<DECIMAL32> >(col_idx, static_cast<int32_t>(val));
case DECIMAL64:
RETURN_NOT_OK(CheckDecimalValueInRange(col, val));
return Set<TypeTraits<DECIMAL64> >(col_idx, static_cast<int64_t>(val));
case DECIMAL128:
RETURN_NOT_OK(CheckDecimalValueInRange(col, val));
return Set<TypeTraits<DECIMAL128> >(col_idx, static_cast<int128_t>(val));
default:
return Status::InvalidArgument(
Substitute("invalid type $0 provided for column '$1' (expected decimal)",
col.type_info()->name(), col.name()));
}
}
Status KuduPartialRow::SetBinary(const Slice& col_name, const Slice& val) {
return SetBinaryCopy(col_name, val);
}
Status KuduPartialRow::SetString(const Slice& col_name, const Slice& val) {
return SetStringCopy(col_name, val);
}
Status KuduPartialRow::SetVarchar(const Slice& col_name, const Slice& val) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return SetVarchar(col_idx, val);
}
Status KuduPartialRow::SetBinary(int col_idx, const Slice& val) {
return SetBinaryCopy(col_idx, val);
}
Status KuduPartialRow::SetString(int col_idx, const Slice& val) {
return SetStringCopy(col_idx, val);
}
Status KuduPartialRow::SetVarchar(int col_idx, const Slice& val) {
return SetSliceCopy<TypeTraits<VARCHAR> >(col_idx, val);
}
Status KuduPartialRow::SetBinaryCopy(const Slice& col_name, const Slice& val) {
return SetSliceCopy<TypeTraits<BINARY> >(col_name, val);
}
Status KuduPartialRow::SetStringCopy(const Slice& col_name, const Slice& val) {
return SetSliceCopy<TypeTraits<STRING> >(col_name, val);
}
Status KuduPartialRow::SetBinaryCopy(int col_idx, const Slice& val) {
return SetSliceCopy<TypeTraits<BINARY> >(col_idx, val);
}
Status KuduPartialRow::SetStringCopy(int col_idx, const Slice& val) {
return SetSliceCopy<TypeTraits<STRING> >(col_idx, val);
}
Status KuduPartialRow::SetBinaryNoCopy(const Slice& col_name, const Slice& val) {
return Set<TypeTraits<BINARY> >(col_name, val, false);
}
Status KuduPartialRow::SetStringNoCopy(const Slice& col_name, const Slice& val) {
return Set<TypeTraits<STRING> >(col_name, val, false);
}
Status KuduPartialRow::SetBinaryNoCopy(int col_idx, const Slice& val) {
return Set<TypeTraits<BINARY> >(col_idx, val, false);
}
Status KuduPartialRow::SetStringNoCopy(int col_idx, const Slice& val) {
return Set<TypeTraits<STRING> >(col_idx, val, false);
}
Status KuduPartialRow::SetVarcharNoCopyUnsafe(const Slice& col_name, const Slice& val) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return SetVarcharNoCopyUnsafe(col_idx, val);
}
Status KuduPartialRow::SetVarcharNoCopyUnsafe(int col_idx, const Slice& val) {
const auto& col = schema_->column(col_idx);
if (val.size() > col.type_attributes().length * 4) {
return Status::InvalidArgument(
Substitute("Value too long, limit is $0 characters",
col.type_attributes().length));
}
return Set<TypeTraits<VARCHAR> >(col_idx, val);
}
template<typename T>
Status KuduPartialRow::SetSliceCopy(const Slice& col_name, const Slice& val) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return SetSliceCopy<T>(col_idx, val);
}
template<typename T>
Status KuduPartialRow::SetSliceCopy(int col_idx, const Slice& val) {
const auto& col = schema_->column(col_idx);
Slice relocated_val;
switch (T::type) {
case VARCHAR:
relocated_val = UTF8Truncate(val, col.type_attributes().length);
break;
case STRING:
case BINARY:
auto relocated = new uint8_t[val.size()];
memcpy(relocated, val.data(), val.size());
relocated_val = Slice(relocated, val.size());
break;
}
Status s = Set<T>(col_idx, relocated_val, true);
if (!s.ok()) {
delete [] relocated_val.data();
}
return s;
}
Status KuduPartialRow::SetNull(const Slice& col_name) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return SetNull(col_idx);
}
Status KuduPartialRow::SetNull(int col_idx) {
const ColumnSchema& col = schema_->column(col_idx);
if (PREDICT_FALSE(!col.is_nullable())) {
return Status::InvalidArgument("column not nullable", col.ToString());
}
if (col.type_info()->physical_type() == BINARY) DeallocateStringIfSet(col_idx, col);
ContiguousRow row(schema_, row_data_);
row.set_null(col_idx, true);
// Mark the column as set.
BitmapSet(isset_bitmap_, col_idx);
return Status::OK();
}
Status KuduPartialRow::Unset(const Slice& col_name) {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return Unset(col_idx);
}
Status KuduPartialRow::Unset(int col_idx) {
const ColumnSchema& col = schema_->column(col_idx);
if (col.type_info()->physical_type() == BINARY) DeallocateStringIfSet(col_idx, col);
BitmapClear(isset_bitmap_, col_idx);
return Status::OK();
}
//------------------------------------------------------------
// Template instantiations: We instantiate all possible templates to avoid linker issues.
// see: https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
// TODO We can probably remove this when we move to c++11 and can use "extern template"
//------------------------------------------------------------
template
Status KuduPartialRow::SetSliceCopy<TypeTraits<STRING> >(int col_idx, const Slice& val);
template
Status KuduPartialRow::SetSliceCopy<TypeTraits<BINARY> >(int col_idx, const Slice& val);
template
Status KuduPartialRow::SetSliceCopy<TypeTraits<STRING> >(const Slice& col_name, const Slice& val);
template
Status KuduPartialRow::SetSliceCopy<TypeTraits<BINARY> >(const Slice& col_name, const Slice& val);
template
Status KuduPartialRow::Set<TypeTraits<INT8> >(int col_idx,
const TypeTraits<INT8>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT16> >(int col_idx,
const TypeTraits<INT16>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT32> >(int col_idx,
const TypeTraits<INT32>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT64> >(int col_idx,
const TypeTraits<INT64>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT128> >(int col_idx,
const TypeTraits<INT128>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<UNIXTIME_MICROS> >(
int col_idx,
const TypeTraits<UNIXTIME_MICROS>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DATE> >(int col_idx,
const TypeTraits<DATE>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<STRING> >(int col_idx,
const TypeTraits<STRING>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<BINARY> >(int col_idx,
const TypeTraits<BINARY>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<FLOAT> >(int col_idx,
const TypeTraits<FLOAT>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DOUBLE> >(int col_idx,
const TypeTraits<DOUBLE>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<BOOL> >(int col_idx,
const TypeTraits<BOOL>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DECIMAL32> >(int col_idx,
const TypeTraits<DECIMAL32>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DECIMAL64> >(int col_idx,
const TypeTraits<DECIMAL64>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DECIMAL128> >(int col_idx,
const TypeTraits<DECIMAL128>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT8> >(const Slice& col_name,
const TypeTraits<INT8>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT16> >(const Slice& col_name,
const TypeTraits<INT16>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT32> >(const Slice& col_name,
const TypeTraits<INT32>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT64> >(const Slice& col_name,
const TypeTraits<INT64>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<INT128> >(const Slice& col_name,
const TypeTraits<INT128>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<UNIXTIME_MICROS> >(
const Slice& col_name,
const TypeTraits<UNIXTIME_MICROS>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DATE> >(const Slice& col_name,
const TypeTraits<DATE>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<FLOAT> >(const Slice& col_name,
const TypeTraits<FLOAT>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DOUBLE> >(const Slice& col_name,
const TypeTraits<DOUBLE>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<BOOL> >(const Slice& col_name,
const TypeTraits<BOOL>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<STRING> >(const Slice& col_name,
const TypeTraits<STRING>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<BINARY> >(const Slice& col_name,
const TypeTraits<BINARY>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DECIMAL32> >(const Slice& col_name,
const TypeTraits<DECIMAL32>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DECIMAL64> >(const Slice& col_name,
const TypeTraits<DECIMAL64>::cpp_type& val,
bool owned);
template
Status KuduPartialRow::Set<TypeTraits<DECIMAL128> >(const Slice& col_name,
const TypeTraits<DECIMAL128>::cpp_type& val,
bool owned);
//------------------------------------------------------------
// Getters
//------------------------------------------------------------
bool KuduPartialRow::IsColumnSet(int col_idx) const {
DCHECK_GE(col_idx, 0);
DCHECK_LT(col_idx, schema_->num_columns());
return BitmapTest(isset_bitmap_, col_idx);
}
bool KuduPartialRow::IsColumnSet(const Slice& col_name) const {
int col_idx;
CHECK_OK(schema_->FindColumn(col_name, &col_idx));
return IsColumnSet(col_idx);
}
bool KuduPartialRow::IsNull(int col_idx) const {
const ColumnSchema& col = schema_->column(col_idx);
if (!col.is_nullable()) {
return false;
}
if (!IsColumnSet(col_idx)) return false;
ContiguousRow row(schema_, row_data_);
return row.is_null(col_idx);
}
bool KuduPartialRow::IsNull(const Slice& col_name) const {
int col_idx;
CHECK_OK(schema_->FindColumn(col_name, &col_idx));
return IsNull(col_idx);
}
Status KuduPartialRow::GetBool(const Slice& col_name, bool* val) const {
return Get<TypeTraits<BOOL> >(col_name, val);
}
Status KuduPartialRow::GetInt8(const Slice& col_name, int8_t* val) const {
return Get<TypeTraits<INT8> >(col_name, val);
}
Status KuduPartialRow::GetInt16(const Slice& col_name, int16_t* val) const {
return Get<TypeTraits<INT16> >(col_name, val);
}
Status KuduPartialRow::GetInt32(const Slice& col_name, int32_t* val) const {
return Get<TypeTraits<INT32> >(col_name, val);
}
Status KuduPartialRow::GetInt64(const Slice& col_name, int64_t* val) const {
return Get<TypeTraits<INT64> >(col_name, val);
}
Status KuduPartialRow::GetUnixTimeMicros(const Slice& col_name,
int64_t* micros_since_utc_epoch) const {
return Get<TypeTraits<UNIXTIME_MICROS> >(col_name, micros_since_utc_epoch);
}
Status KuduPartialRow::GetDate(const Slice& col_name,
int32_t* days_since_unix_epoch) const {
return Get<TypeTraits<DATE> >(col_name, days_since_unix_epoch);
}
Status KuduPartialRow::GetFloat(const Slice& col_name, float* val) const {
return Get<TypeTraits<FLOAT> >(col_name, val);
}
Status KuduPartialRow::GetDouble(const Slice& col_name, double* val) const {
return Get<TypeTraits<DOUBLE> >(col_name, val);
}
Status KuduPartialRow::GetUnscaledDecimal(const Slice &col_name, int128_t *val) {
// Call the const version of the function.
return const_cast<const KuduPartialRow*>(this)->GetUnscaledDecimal(col_name, val);
}
Status KuduPartialRow::GetUnscaledDecimal(const Slice &col_name, int128_t *val) const {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return GetUnscaledDecimal(col_idx, val);
}
Status KuduPartialRow::GetString(const Slice& col_name, Slice* val) const {
return Get<TypeTraits<STRING> >(col_name, val);
}
Status KuduPartialRow::GetBinary(const Slice& col_name, Slice* val) const {
return Get<TypeTraits<BINARY> >(col_name, val);
}
Status KuduPartialRow::GetVarchar(const Slice& col_name, Slice* val) const {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return GetVarchar(col_idx, val);
}
Status KuduPartialRow::GetBool(int col_idx, bool* val) const {
return Get<TypeTraits<BOOL> >(col_idx, val);
}
Status KuduPartialRow::GetInt8(int col_idx, int8_t* val) const {
return Get<TypeTraits<INT8> >(col_idx, val);
}
Status KuduPartialRow::GetInt16(int col_idx, int16_t* val) const {
return Get<TypeTraits<INT16> >(col_idx, val);
}
Status KuduPartialRow::GetInt32(int col_idx, int32_t* val) const {
return Get<TypeTraits<INT32> >(col_idx, val);
}
Status KuduPartialRow::GetInt64(int col_idx, int64_t* val) const {
return Get<TypeTraits<INT64> >(col_idx, val);
}
Status KuduPartialRow::GetUnixTimeMicros(int col_idx, int64_t* micros_since_utc_epoch) const {
return Get<TypeTraits<UNIXTIME_MICROS> >(col_idx, micros_since_utc_epoch);
}
Status KuduPartialRow::GetDate(int col_idx, int32_t* days_since_unix_epoch) const {
return Get<TypeTraits<DATE> >(col_idx, days_since_unix_epoch);
}
Status KuduPartialRow::GetFloat(int col_idx, float* val) const {
return Get<TypeTraits<FLOAT> >(col_idx, val);
}
Status KuduPartialRow::GetDouble(int col_idx, double* val) const {
return Get<TypeTraits<DOUBLE> >(col_idx, val);
}
Status KuduPartialRow::GetUnscaledDecimal(int col_idx, int128_t *val) {
// Call the const version of the function.
return const_cast<const KuduPartialRow*>(this)->GetUnscaledDecimal(col_idx, val);
}
Status KuduPartialRow::GetUnscaledDecimal(int col_idx, int128_t *val) const {
const ColumnSchema& col = schema_->column(col_idx);
const DataType col_type = col.type_info()->type();
switch (col_type) {
case DECIMAL32:
int32_t i32_val;
RETURN_NOT_OK(Get<TypeTraits<DECIMAL32> >(col_idx, &i32_val));
*val = i32_val;
return Status::OK();
case DECIMAL64:
int64_t i64_val;
RETURN_NOT_OK(Get<TypeTraits<DECIMAL64> >(col_idx, &i64_val));
*val = i64_val;
return Status::OK();
case DECIMAL128:
int128_t i128_val;
RETURN_NOT_OK(Get<TypeTraits<DECIMAL128> >(col_idx, &i128_val));
*val = i128_val;
return Status::OK();
default:
return Status::InvalidArgument(
Substitute("invalid type $0 provided for column '$1' (expected decimal)",
col.type_info()->name(), col.name()));
}
}
Status KuduPartialRow::GetString(int col_idx, Slice* val) const {
return Get<TypeTraits<STRING> >(col_idx, val);
}
Status KuduPartialRow::GetBinary(int col_idx, Slice* val) const {
return Get<TypeTraits<BINARY> >(col_idx, val);
}
Status KuduPartialRow::GetVarchar(int col_idx, Slice* val) const {
return Get<TypeTraits<VARCHAR> >(col_idx, val);
}
template<typename T>
Status KuduPartialRow::Get(const Slice& col_name,
typename T::cpp_type* val) const {
int col_idx;
RETURN_NOT_OK(schema_->FindColumn(col_name, &col_idx));
return Get<T>(col_idx, val);
}
template<typename T>
Status KuduPartialRow::Get(int col_idx, typename T::cpp_type* val) const {
const ColumnSchema& col = schema_->column(col_idx);
if (PREDICT_FALSE(col.type_info()->type() != T::type)) {
// TODO: at some point we could allow type coercion here.
return Status::InvalidArgument(
Substitute("invalid type $0 provided for column '$1' (expected $2)",
T::name(),
col.name(), col.type_info()->name()));
}
if (PREDICT_FALSE(!IsColumnSet(col_idx))) {
return Status::NotFound("column not set");
}
if (col.is_nullable() && IsNull(col_idx)) {
return Status::NotFound("column is NULL");
}
ContiguousRow row(schema_, row_data_);
memcpy(val, row.cell_ptr(col_idx), sizeof(*val));
return Status::OK();
}
//------------------------------------------------------------
// Key-encoding related functions
//------------------------------------------------------------
Status KuduPartialRow::EncodeRowKey(string* encoded_key) const {
// Currently, a row key must be fully specified.
// TODO: allow specifying a prefix of the key, and automatically
// fill the rest with minimum values.
for (int i = 0; i < schema_->num_key_columns(); i++) {
if (PREDICT_FALSE(!IsColumnSet(i))) {
return Status::InvalidArgument("All key columns must be set",
schema_->column(i).name());
}
}
encoded_key->clear();
ContiguousRow row(schema_, row_data_);
for (int i = 0; i < schema_->num_key_columns(); i++) {
bool is_last = i == schema_->num_key_columns() - 1;
const TypeInfo* ti = schema_->column(i).type_info();
GetKeyEncoder<string>(ti).Encode(row.cell_ptr(i), is_last, encoded_key);
}
return Status::OK();
}
string KuduPartialRow::ToEncodedRowKeyOrDie() const {
string ret;
CHECK_OK(EncodeRowKey(&ret));
return ret;
}
//------------------------------------------------------------
// Utility code
//------------------------------------------------------------
bool KuduPartialRow::AllColumnsSet() const {
return BitmapIsAllSet(isset_bitmap_, 0, schema_->num_columns());
}
bool KuduPartialRow::IsKeySet() const {
return BitmapIsAllSet(isset_bitmap_, 0, schema_->num_key_columns());
}
std::string KuduPartialRow::ToString() const {
ScopedDisableRedaction no_redaction;
ContiguousRow row(schema_, row_data_);
std::string ret;
bool first = true;
for (int i = 0; i < schema_->num_columns(); i++) {
if (IsColumnSet(i)) {
if (!first) {
ret.append(", ");
}
schema_->column(i).DebugCellAppend(row.cell(i), &ret);
first = false;
}
}
return ret;
}
//------------------------------------------------------------
// Serialization/deserialization
//------------------------------------------------------------
} // namespace kudu