blob: 75adf75ed82ba7585335ae68b8e0e15358ae02eb [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.
#pragma once
#include <cstddef>
#include <sstream>
#include <string>
#include "olap/key_coder.h"
#include "olap/olap_common.h"
#include "olap/olap_define.h"
#include "olap/row_cursor_cell.h"
#include "olap/tablet_schema.h"
#include "olap/types.h"
#include "olap/utils.h"
#include "runtime/collection_value.h"
#include "runtime/map_value.h"
#include "util/hash_util.hpp"
#include "util/slice.h"
#include "vec/common/arena.h"
#include "vec/json/path_in_data.h"
namespace doris {
#include "common/compile_check_begin.h"
// A Field is used to represent a column in memory format.
// User can use this class to access or deal with column data in memory.
class Field {
public:
Field(const TabletColumn& column)
: _type_info(get_type_info(&column)),
_desc(column),
_length(column.length()),
_key_coder(get_key_coder(column.type())),
_name(column.name()),
_index_size(column.index_length()),
_is_nullable(column.is_nullable()),
_unique_id(column.unique_id()),
_parent_unique_id(column.parent_unique_id()),
_is_extracted_column(column.is_extracted_column()),
_path(column.path_info_ptr()) {}
virtual ~Field() = default;
size_t size() const { return _type_info->size(); }
size_t length() const { return _length; }
size_t field_size() const { return size() + 1; }
size_t index_size() const { return _index_size; }
int32_t unique_id() const { return _unique_id; }
int32_t parent_unique_id() const { return _parent_unique_id; }
bool is_extracted_column() const { return _is_extracted_column; }
const std::string& name() const { return _name; }
const vectorized::PathInDataPtr& path() const { return _path; }
virtual void set_to_max(char* buf) const { return _type_info->set_to_max(buf); }
virtual void set_to_zone_map_max(char* buf) const { set_to_max(buf); }
virtual void set_to_min(char* buf) const { return _type_info->set_to_min(buf); }
virtual void set_to_zone_map_min(char* buf) const { set_to_min(buf); }
void set_long_text_buf(char** buf) { _long_text_buf = buf; }
// This function allocate memory from arena, other than allocate_memory
// reserve memory from continuous memory.
virtual char* allocate_value(vectorized::Arena& arena) const {
return arena.alloc(_type_info->size());
}
virtual char* allocate_zone_map_value(vectorized::Arena& arena) const {
return allocate_value(arena);
}
virtual size_t get_variable_len() const { return 0; }
virtual void modify_zone_map_index(char*) const {}
virtual Field* clone() const {
auto* local = new Field(_desc);
this->clone(local);
return local;
}
// Only compare column content, without considering nullptr condition.
// RETURNS:
// 0 means equal,
// -1 means left less than right,
// 1 means left bigger than right
int compare(const void* left, const void* right) const { return _type_info->cmp(left, right); }
// Compare two types of cell.
// This function differs compare in that this function compare cell which
// will consider the condition which cell may be nullptr. While compare only
// compare column content without considering nullptr condition.
// Only compare column content, without considering nullptr condition.
// RETURNS:
// 0 means equal,
// -1 means left less than right,
// 1 means left bigger than right
template <typename LhsCellType, typename RhsCellType>
int compare_cell(const LhsCellType& lhs, const RhsCellType& rhs) const {
bool l_null = lhs.is_null();
bool r_null = rhs.is_null();
if (l_null != r_null) {
return l_null ? -1 : 1;
}
return l_null ? 0 : _type_info->cmp(lhs.cell_ptr(), rhs.cell_ptr());
}
// Copy source cell's content to destination cell directly.
// For string type, this function assume that destination has
// enough space and copy source content into destination without
// memory allocation.
template <typename DstCellType, typename SrcCellType>
void direct_copy(DstCellType* dst, const SrcCellType& src) const {
bool is_null = src.is_null();
dst->set_is_null(is_null);
if (is_null) {
return;
}
if (type() == FieldType::OLAP_FIELD_TYPE_STRING) {
auto dst_slice = reinterpret_cast<Slice*>(dst->mutable_cell_ptr());
auto src_slice = reinterpret_cast<const Slice*>(src.cell_ptr());
if (dst_slice->size < src_slice->size) {
*_long_text_buf = static_cast<char*>(realloc(*_long_text_buf, src_slice->size));
dst_slice->data = *_long_text_buf;
dst_slice->size = src_slice->size;
}
}
return _type_info->direct_copy(dst->mutable_cell_ptr(), src.cell_ptr());
}
// deep copy source cell' content to destination cell.
// For string type, this will allocate data form arena,
// and copy source's content.
template <typename DstCellType, typename SrcCellType>
void deep_copy(DstCellType* dst, const SrcCellType& src, vectorized::Arena& arena) const {
bool is_null = src.is_null();
dst->set_is_null(is_null);
if (is_null) {
return;
}
_type_info->deep_copy(dst->mutable_cell_ptr(), src.cell_ptr(), arena);
}
// used by init scan key stored in string format
// value_string should end with '\0'
Status from_string(char* buf, const std::string& value_string, const int precision = 0,
const int scale = 0) const {
if (type() == FieldType::OLAP_FIELD_TYPE_STRING && !value_string.empty()) {
auto slice = reinterpret_cast<Slice*>(buf);
if (slice->size < value_string.size()) {
*_long_text_buf = static_cast<char*>(realloc(*_long_text_buf, value_string.size()));
slice->data = *_long_text_buf;
slice->size = value_string.size();
}
}
return _type_info->from_string(buf, value_string, precision, scale);
}
// convert inner value to string
// performance is not considered, only for debug use
std::string to_string(const char* src) const { return _type_info->to_string(src); }
template <typename CellType>
std::string debug_string(const CellType& cell) const {
std::stringstream ss;
if (cell.is_null()) {
ss << "(null)";
} else {
ss << _type_info->to_string(cell.cell_ptr());
}
return ss.str();
}
FieldType type() const { return _type_info->type(); }
const TypeInfo* type_info() const { return _type_info.get(); }
bool is_nullable() const { return _is_nullable; }
// similar to `full_encode_ascending`, but only encode part (the first `index_size` bytes) of the value.
// only applicable to string type
void encode_ascending(const void* value, std::string* buf) const {
_key_coder->encode_ascending(value, _index_size, buf);
}
// encode the provided `value` into `buf`.
void full_encode_ascending(const void* value, std::string* buf) const {
_key_coder->full_encode_ascending(value, buf);
}
void add_sub_field(std::unique_ptr<Field> sub_field) {
_sub_fields.emplace_back(std::move(sub_field));
}
Field* get_sub_field(size_t i) const { return _sub_fields[i].get(); }
size_t get_sub_field_count() const { return _sub_fields.size(); }
void set_precision(int32_t precision) { _precision = precision; }
void set_scale(int32_t scale) { _scale = scale; }
int32_t get_precision() const { return _precision; }
int32_t get_scale() const { return _scale; }
const TabletColumn& get_desc() const { return _desc; }
int32_t get_unique_id() const {
return is_extracted_column() ? parent_unique_id() : unique_id();
}
protected:
TypeInfoPtr _type_info;
TabletColumn _desc;
// unit : byte
// except for strings, other types have fixed lengths
// Note that, the struct type itself has fixed length, but due to
// its number of subfields is a variable, so the actual length of
// a struct field is not fixed.
size_t _length;
// Since the length of the STRING type cannot be determined,
// only dynamic memory can be used. Arena cannot realize realloc.
// The schema information is shared globally. Therefore,
// dynamic memory can only be managed in thread local mode.
// The memory will be created and released in rowcursor.
char** _long_text_buf = nullptr;
char* allocate_string_value(vectorized::Arena& arena) const {
char* type_value = arena.alloc(sizeof(Slice));
auto slice = reinterpret_cast<Slice*>(type_value);
slice->size = _length;
slice->data = arena.alloc(slice->size);
return type_value;
}
void clone(Field* other) const {
other->_type_info = clone_type_info(this->_type_info.get());
other->_key_coder = this->_key_coder;
other->_name = this->_name;
other->_index_size = this->_index_size;
other->_is_nullable = this->_is_nullable;
other->_sub_fields.clear();
other->_precision = this->_precision;
other->_scale = this->_scale;
other->_unique_id = this->_unique_id;
other->_parent_unique_id = this->_parent_unique_id;
other->_is_extracted_column = this->_is_extracted_column;
for (const auto& f : _sub_fields) {
Field* item = f->clone();
other->add_sub_field(std::unique_ptr<Field>(item));
}
}
private:
// maximum length of Field, unit : bytes
// usually equal to length, except for variable-length strings
const KeyCoder* _key_coder;
std::string _name;
size_t _index_size;
bool _is_nullable;
std::vector<std::unique_ptr<Field>> _sub_fields;
int32_t _precision;
int32_t _scale;
int32_t _unique_id;
int32_t _parent_unique_id;
bool _is_extracted_column = false;
vectorized::PathInDataPtr _path;
};
class MapField : public Field {
public:
MapField(const TabletColumn& column) : Field(column) {}
size_t get_variable_len() const override { return _length; }
};
class StructField : public Field {
public:
StructField(const TabletColumn& column) : Field(column) {}
size_t get_variable_len() const override {
size_t variable_len = _length;
for (size_t i = 0; i < get_sub_field_count(); i++) {
variable_len += get_sub_field(i)->get_variable_len();
}
return variable_len;
}
};
class ArrayField : public Field {
public:
ArrayField(const TabletColumn& column) : Field(column) {}
size_t get_variable_len() const override { return _length; }
};
class CharField : public Field {
public:
CharField(const TabletColumn& column) : Field(column) {}
size_t get_variable_len() const override { return _length; }
CharField* clone() const override {
auto* local = new CharField(_desc);
Field::clone(local);
return local;
}
char* allocate_value(vectorized::Arena& arena) const override {
return Field::allocate_string_value(arena);
}
void set_to_max(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
slice->size = _length;
memset(slice->data, 0xFF, slice->size);
}
// To prevent zone map cost too many memory, if varchar length
// longer than `MAX_ZONE_MAP_INDEX_SIZE`. we just allocate
// `MAX_ZONE_MAP_INDEX_SIZE` of memory
char* allocate_zone_map_value(vectorized::Arena& arena) const override {
char* type_value = arena.alloc(sizeof(Slice));
auto slice = reinterpret_cast<Slice*>(type_value);
slice->size = MAX_ZONE_MAP_INDEX_SIZE > _length ? _length : MAX_ZONE_MAP_INDEX_SIZE;
slice->data = arena.alloc(slice->size);
return type_value;
}
// only varchar filed need modify zone map index when zone map max_value
// index longer than `MAX_ZONE_MAP_INDEX_SIZE`. so here we add one
// for the last byte
// In UTF8 encoding, here do not appear 0xff in last byte
void modify_zone_map_index(char* src) const override {
auto slice = reinterpret_cast<Slice*>(src);
if (slice->size == MAX_ZONE_MAP_INDEX_SIZE) {
slice->mutable_data()[slice->size - 1] += 1;
}
}
void set_to_zone_map_max(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
size_t length = _length < MAX_ZONE_MAP_INDEX_SIZE ? _length : MAX_ZONE_MAP_INDEX_SIZE;
slice->size = length;
memset(slice->data, 0xFF, slice->size);
}
};
class VarcharField : public Field {
public:
VarcharField(const TabletColumn& column) : Field(column) {}
size_t get_variable_len() const override { return _length - OLAP_VARCHAR_MAX_BYTES; }
VarcharField* clone() const override {
auto* local = new VarcharField(_desc);
Field::clone(local);
return local;
}
char* allocate_value(vectorized::Arena& arena) const override {
return Field::allocate_string_value(arena);
}
// To prevent zone map cost too many memory, if varchar length
// longer than `MAX_ZONE_MAP_INDEX_SIZE`. we just allocate
// `MAX_ZONE_MAP_INDEX_SIZE` of memory
char* allocate_zone_map_value(vectorized::Arena& arena) const override {
char* type_value = arena.alloc(sizeof(Slice));
auto slice = reinterpret_cast<Slice*>(type_value);
slice->size = MAX_ZONE_MAP_INDEX_SIZE > _length ? _length : MAX_ZONE_MAP_INDEX_SIZE;
slice->data = arena.alloc(slice->size);
return type_value;
}
// only varchar/string filed need modify zone map index when zone map max_value
// index longer than `MAX_ZONE_MAP_INDEX_SIZE`. so here we add one
// for the last byte
// In UTF8 encoding, here do not appear 0xff in last byte
void modify_zone_map_index(char* src) const override {
auto slice = reinterpret_cast<Slice*>(src);
if (slice->size == MAX_ZONE_MAP_INDEX_SIZE) {
slice->mutable_data()[slice->size - 1] += 1;
}
}
void set_to_max(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
slice->size = _length - OLAP_VARCHAR_MAX_BYTES;
memset(slice->data, 0xFF, slice->size);
}
void set_to_zone_map_max(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
size_t length = _length < MAX_ZONE_MAP_INDEX_SIZE ? _length : MAX_ZONE_MAP_INDEX_SIZE;
slice->size = length - OLAP_VARCHAR_MAX_BYTES;
memset(slice->data, 0xFF, slice->size);
}
};
class StringField : public Field {
public:
StringField(const TabletColumn& column) : Field(column) {}
StringField* clone() const override {
auto* local = new StringField(_desc);
Field::clone(local);
return local;
}
char* allocate_value(vectorized::Arena& arena) const override {
return Field::allocate_string_value(arena);
}
char* allocate_zone_map_value(vectorized::Arena& arena) const override {
char* type_value = arena.alloc(sizeof(Slice));
auto slice = reinterpret_cast<Slice*>(type_value);
slice->size = MAX_ZONE_MAP_INDEX_SIZE;
slice->data = arena.alloc(slice->size);
return type_value;
}
void set_to_max(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
memset(slice->data, 0xFF, slice->size);
}
// only varchar/string filed need modify zone map index when zone map max_value
// index longer than `MAX_ZONE_MAP_INDEX_SIZE`. so here we add one
// for the last byte
// In UTF8 encoding, here do not appear 0xff in last byte
void modify_zone_map_index(char* src) const override {
auto slice = reinterpret_cast<Slice*>(src);
if (slice->size == MAX_ZONE_MAP_INDEX_SIZE) {
slice->mutable_data()[slice->size - 1] += 1;
}
}
void set_to_zone_map_max(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
memset(slice->data, 0xFF, slice->size);
}
void set_to_zone_map_min(char* ch) const override {
auto slice = reinterpret_cast<Slice*>(ch);
memset(slice->data, 0x00, slice->size);
}
};
class BitmapAggField : public Field {
public:
BitmapAggField(const TabletColumn& column) : Field(column) {}
BitmapAggField* clone() const override {
auto* local = new BitmapAggField(_desc);
Field::clone(local);
return local;
}
};
class QuantileStateAggField : public Field {
public:
QuantileStateAggField(const TabletColumn& column) : Field(column) {}
QuantileStateAggField* clone() const override {
auto* local = new QuantileStateAggField(_desc);
Field::clone(local);
return local;
}
};
class AggStateField : public Field {
public:
AggStateField(const TabletColumn& column) : Field(column) {}
AggStateField* clone() const override {
auto* local = new AggStateField(_desc);
Field::clone(local);
return local;
}
};
class HllAggField : public Field {
public:
HllAggField(const TabletColumn& column) : Field(column) {}
HllAggField* clone() const override {
auto* local = new HllAggField(_desc);
Field::clone(local);
return local;
}
};
class FieldFactory {
public:
static Field* create(const TabletColumn& column) {
// for key column
if (column.is_key()) {
switch (column.type()) {
case FieldType::OLAP_FIELD_TYPE_CHAR:
return new CharField(column);
case FieldType::OLAP_FIELD_TYPE_VARCHAR:
case FieldType::OLAP_FIELD_TYPE_STRING:
return new StringField(column);
case FieldType::OLAP_FIELD_TYPE_STRUCT: {
auto* local = new StructField(column);
for (uint32_t i = 0; i < column.get_subtype_count(); i++) {
std::unique_ptr<Field> sub_field(
FieldFactory::create(column.get_sub_column(i)));
local->add_sub_field(std::move(sub_field));
}
return local;
}
case FieldType::OLAP_FIELD_TYPE_ARRAY: {
std::unique_ptr<Field> item_field(FieldFactory::create(column.get_sub_column(0)));
auto* local = new ArrayField(column);
local->add_sub_field(std::move(item_field));
return local;
}
case FieldType::OLAP_FIELD_TYPE_MAP: {
std::unique_ptr<Field> key_field(FieldFactory::create(column.get_sub_column(0)));
std::unique_ptr<Field> val_field(FieldFactory::create(column.get_sub_column(1)));
auto* local = new MapField(column);
local->add_sub_field(std::move(key_field));
local->add_sub_field(std::move(val_field));
return local;
}
case FieldType::OLAP_FIELD_TYPE_DECIMAL:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL32:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL64:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL128I:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL256:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DATETIMEV2: {
Field* field = new Field(column);
field->set_precision(column.precision());
field->set_scale(column.frac());
return field;
}
default:
return new Field(column);
}
}
// for value column
switch (column.aggregation()) {
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_NONE:
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_SUM:
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_MIN:
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_MAX:
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_REPLACE:
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_REPLACE_IF_NOT_NULL:
switch (column.type()) {
case FieldType::OLAP_FIELD_TYPE_CHAR:
return new CharField(column);
case FieldType::OLAP_FIELD_TYPE_VARCHAR:
return new VarcharField(column);
case FieldType::OLAP_FIELD_TYPE_STRING:
return new StringField(column);
case FieldType::OLAP_FIELD_TYPE_STRUCT: {
auto* local = new StructField(column);
for (uint32_t i = 0; i < column.get_subtype_count(); i++) {
std::unique_ptr<Field> sub_field(
FieldFactory::create(column.get_sub_column(i)));
local->add_sub_field(std::move(sub_field));
}
return local;
}
case FieldType::OLAP_FIELD_TYPE_ARRAY: {
std::unique_ptr<Field> item_field(FieldFactory::create(column.get_sub_column(0)));
auto* local = new ArrayField(column);
local->add_sub_field(std::move(item_field));
return local;
}
case FieldType::OLAP_FIELD_TYPE_MAP: {
DCHECK(column.get_subtype_count() == 2);
auto* local = new MapField(column);
std::unique_ptr<Field> key_field(FieldFactory::create(column.get_sub_column(0)));
std::unique_ptr<Field> value_field(FieldFactory::create(column.get_sub_column(1)));
local->add_sub_field(std::move(key_field));
local->add_sub_field(std::move(value_field));
return local;
}
case FieldType::OLAP_FIELD_TYPE_DECIMAL:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL32:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL64:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL128I:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DECIMAL256:
[[fallthrough]];
case FieldType::OLAP_FIELD_TYPE_DATETIMEV2: {
Field* field = new Field(column);
field->set_precision(column.precision());
field->set_scale(column.frac());
return field;
}
default:
return new Field(column);
}
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_HLL_UNION:
return new HllAggField(column);
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_BITMAP_UNION:
return new BitmapAggField(column);
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_QUANTILE_UNION:
return new QuantileStateAggField(column);
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_GENERIC:
return new AggStateField(column);
case FieldAggregationMethod::OLAP_FIELD_AGGREGATION_UNKNOWN:
CHECK(false) << ", value column no agg type";
return nullptr;
}
return nullptr;
}
static Field* create_by_type(const FieldType& type) {
TabletColumn column(FieldAggregationMethod::OLAP_FIELD_AGGREGATION_NONE, type);
return create(column);
}
};
#include "common/compile_check_end.h"
} // namespace doris