| // 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 |