Packages

An Elixir DuckDB library

Current section

Files

Jump to
exduckdb c_src duckdb src common row_operations row_heap_scatter.cpp
Raw

c_src/duckdb/src/common/row_operations/row_heap_scatter.cpp

#include "duckdb/common/helper.hpp"
#include "duckdb/common/row_operations/row_operations.hpp"
#include "duckdb/common/types/vector.hpp"
namespace duckdb {
using ValidityBytes = TemplatedValidityMask<uint8_t>;
static void ComputeStringEntrySizes(VectorData &vdata, idx_t entry_sizes[], const idx_t ser_count,
const SelectionVector &sel, const idx_t offset) {
auto strings = (string_t *)vdata.data;
for (idx_t i = 0; i < ser_count; i++) {
auto idx = sel.get_index(i);
auto str_idx = vdata.sel->get_index(idx) + offset;
if (vdata.validity.RowIsValid(str_idx)) {
entry_sizes[i] += sizeof(uint32_t) + strings[str_idx].GetSize();
}
}
}
static void ComputeStructEntrySizes(Vector &v, idx_t entry_sizes[], idx_t vcount, idx_t ser_count,
const SelectionVector &sel, idx_t offset) {
// obtain child vectors
idx_t num_children;
vector<Vector> struct_vectors;
if (v.GetVectorType() == VectorType::DICTIONARY_VECTOR) {
auto &child = DictionaryVector::Child(v);
auto &dict_sel = DictionaryVector::SelVector(v);
auto &children = StructVector::GetEntries(child);
num_children = children.size();
for (auto &struct_child : children) {
Vector struct_vector(*struct_child, dict_sel, vcount);
struct_vectors.push_back(move(struct_vector));
}
} else {
auto &children = StructVector::GetEntries(v);
num_children = children.size();
for (auto &struct_child : children) {
Vector struct_vector(*struct_child);
struct_vectors.push_back(move(struct_vector));
}
}
// add struct validitymask size
const idx_t struct_validitymask_size = (num_children + 7) / 8;
for (idx_t i = 0; i < ser_count; i++) {
entry_sizes[i] += struct_validitymask_size;
}
// compute size of child vectors
for (auto &struct_vector : struct_vectors) {
RowOperations::ComputeEntrySizes(struct_vector, entry_sizes, vcount, ser_count, sel, offset);
}
}
static void ComputeListEntrySizes(Vector &v, VectorData &vdata, idx_t entry_sizes[], idx_t ser_count,
const SelectionVector &sel, idx_t offset) {
auto list_data = ListVector::GetData(v);
auto &child_vector = ListVector::GetEntry(v);
idx_t list_entry_sizes[STANDARD_VECTOR_SIZE];
for (idx_t i = 0; i < ser_count; i++) {
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
if (vdata.validity.RowIsValid(source_idx)) {
auto list_entry = list_data[source_idx];
// make room for list length, list validitymask
entry_sizes[i] += sizeof(list_entry.length);
entry_sizes[i] += (list_entry.length + 7) / 8;
// serialize size of each entry (if non-constant size)
if (!TypeIsConstantSize(ListType::GetChildType(v.GetType()).InternalType())) {
entry_sizes[i] += list_entry.length * sizeof(list_entry.length);
}
// compute size of each the elements in list_entry and sum them
auto entry_remaining = list_entry.length;
auto entry_offset = list_entry.offset;
while (entry_remaining > 0) {
// the list entry can span multiple vectors
auto next = MinValue((idx_t)STANDARD_VECTOR_SIZE, entry_remaining);
// compute and add to the total
std::fill_n(list_entry_sizes, next, 0);
RowOperations::ComputeEntrySizes(child_vector, list_entry_sizes, next, next,
FlatVector::INCREMENTAL_SELECTION_VECTOR, entry_offset);
for (idx_t list_idx = 0; list_idx < next; list_idx++) {
entry_sizes[i] += list_entry_sizes[list_idx];
}
// update for next iteration
entry_remaining -= next;
entry_offset += next;
}
}
}
}
void RowOperations::ComputeEntrySizes(Vector &v, VectorData &vdata, idx_t entry_sizes[], idx_t vcount, idx_t ser_count,
const SelectionVector &sel, idx_t offset) {
const auto physical_type = v.GetType().InternalType();
if (TypeIsConstantSize(physical_type)) {
const auto type_size = GetTypeIdSize(physical_type);
for (idx_t i = 0; i < ser_count; i++) {
entry_sizes[i] += type_size;
}
} else {
switch (physical_type) {
case PhysicalType::VARCHAR:
ComputeStringEntrySizes(vdata, entry_sizes, ser_count, sel, offset);
break;
case PhysicalType::STRUCT:
ComputeStructEntrySizes(v, entry_sizes, vcount, ser_count, sel, offset);
break;
case PhysicalType::LIST:
ComputeListEntrySizes(v, vdata, entry_sizes, ser_count, sel, offset);
break;
default:
// LCOV_EXCL_START
throw NotImplementedException("Column with variable size type %s cannot be serialized to row-format",
v.GetType().ToString());
// LCOV_EXCL_STOP
}
}
}
void RowOperations::ComputeEntrySizes(Vector &v, idx_t entry_sizes[], idx_t vcount, idx_t ser_count,
const SelectionVector &sel, idx_t offset) {
VectorData vdata;
v.Orrify(vcount, vdata);
ComputeEntrySizes(v, vdata, entry_sizes, vcount, ser_count, sel, offset);
}
template <class T>
static void TemplatedHeapScatter(VectorData &vdata, const SelectionVector &sel, idx_t count, idx_t col_idx,
data_ptr_t *key_locations, data_ptr_t *validitymask_locations, idx_t offset) {
auto source = (T *)vdata.data;
if (!validitymask_locations) {
for (idx_t i = 0; i < count; i++) {
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
auto target = (T *)key_locations[i];
Store<T>(source[source_idx], (data_ptr_t)target);
key_locations[i] += sizeof(T);
}
} else {
idx_t entry_idx;
idx_t idx_in_entry;
ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry);
const auto bit = ~(1UL << idx_in_entry);
for (idx_t i = 0; i < count; i++) {
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
auto target = (T *)key_locations[i];
Store<T>(source[source_idx], (data_ptr_t)target);
key_locations[i] += sizeof(T);
// set the validitymask
if (!vdata.validity.RowIsValid(source_idx)) {
*(validitymask_locations[i] + entry_idx) &= bit;
}
}
}
}
static void HeapScatterStringVector(Vector &v, idx_t vcount, const SelectionVector &sel, idx_t ser_count, idx_t col_idx,
data_ptr_t *key_locations, data_ptr_t *validitymask_locations, idx_t offset) {
VectorData vdata;
v.Orrify(vcount, vdata);
auto strings = (string_t *)vdata.data;
if (!validitymask_locations) {
for (idx_t i = 0; i < ser_count; i++) {
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
if (vdata.validity.RowIsValid(source_idx)) {
auto &string_entry = strings[source_idx];
// store string size
Store<uint32_t>(string_entry.GetSize(), key_locations[i]);
key_locations[i] += sizeof(uint32_t);
// store the string
memcpy(key_locations[i], string_entry.GetDataUnsafe(), string_entry.GetSize());
key_locations[i] += string_entry.GetSize();
}
}
} else {
idx_t entry_idx;
idx_t idx_in_entry;
ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry);
const auto bit = ~(1UL << idx_in_entry);
for (idx_t i = 0; i < ser_count; i++) {
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
if (vdata.validity.RowIsValid(source_idx)) {
auto &string_entry = strings[source_idx];
// store string size
Store<uint32_t>(string_entry.GetSize(), key_locations[i]);
key_locations[i] += sizeof(uint32_t);
// store the string
memcpy(key_locations[i], string_entry.GetDataUnsafe(), string_entry.GetSize());
key_locations[i] += string_entry.GetSize();
} else {
// set the validitymask
*(validitymask_locations[i] + entry_idx) &= bit;
}
}
}
}
static void HeapScatterStructVector(Vector &v, idx_t vcount, const SelectionVector &sel, idx_t ser_count, idx_t col_idx,
data_ptr_t *key_locations, data_ptr_t *validitymask_locations, idx_t offset) {
VectorData vdata;
v.Orrify(vcount, vdata);
idx_t num_children;
vector<Vector> struct_vectors;
if (v.GetVectorType() == VectorType::DICTIONARY_VECTOR) {
auto &child = DictionaryVector::Child(v);
auto &dict_sel = DictionaryVector::SelVector(v);
auto &children = StructVector::GetEntries(child);
num_children = children.size();
for (auto &struct_child : children) {
Vector struct_vector(*struct_child, dict_sel, vcount);
struct_vectors.push_back(move(struct_vector));
}
} else {
auto &children = StructVector::GetEntries(v);
num_children = children.size();
for (auto &struct_child : children) {
Vector struct_vector(*struct_child);
struct_vectors.push_back(move(struct_vector));
}
}
// the whole struct itself can be NULL
idx_t entry_idx;
idx_t idx_in_entry;
ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry);
const auto bit = ~(1UL << idx_in_entry);
// struct must have a validitymask for its fields
const idx_t struct_validitymask_size = (num_children + 7) / 8;
data_ptr_t struct_validitymask_locations[STANDARD_VECTOR_SIZE];
for (idx_t i = 0; i < ser_count; i++) {
// initialize the struct validity mask
struct_validitymask_locations[i] = key_locations[i];
memset(struct_validitymask_locations[i], -1, struct_validitymask_size);
key_locations[i] += struct_validitymask_size;
// set whether the whole struct is null
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
if (validitymask_locations && !vdata.validity.RowIsValid(source_idx)) {
*(validitymask_locations[i] + entry_idx) &= bit;
}
}
// now serialize the struct vectors
for (idx_t i = 0; i < struct_vectors.size(); i++) {
auto &struct_vector = struct_vectors[i];
RowOperations::HeapScatter(struct_vector, vcount, sel, ser_count, i, key_locations,
struct_validitymask_locations, offset);
}
}
static void HeapScatterListVector(Vector &v, idx_t vcount, const SelectionVector &sel, idx_t ser_count, idx_t col_no,
data_ptr_t *key_locations, data_ptr_t *validitymask_locations, idx_t offset) {
VectorData vdata;
v.Orrify(vcount, vdata);
idx_t entry_idx;
idx_t idx_in_entry;
ValidityBytes::GetEntryIndex(col_no, entry_idx, idx_in_entry);
auto list_data = ListVector::GetData(v);
auto &child_vector = ListVector::GetEntry(v);
VectorData list_vdata;
child_vector.Orrify(ListVector::GetListSize(v), list_vdata);
auto child_type = ListType::GetChildType(v.GetType()).InternalType();
idx_t list_entry_sizes[STANDARD_VECTOR_SIZE];
data_ptr_t list_entry_locations[STANDARD_VECTOR_SIZE];
for (idx_t i = 0; i < ser_count; i++) {
auto idx = sel.get_index(i);
auto source_idx = vdata.sel->get_index(idx) + offset;
if (!vdata.validity.RowIsValid(source_idx)) {
if (validitymask_locations) {
// set the row validitymask for this column to invalid
ValidityBytes row_mask(validitymask_locations[i]);
row_mask.SetInvalidUnsafe(entry_idx, idx_in_entry);
}
continue;
}
auto list_entry = list_data[source_idx];
// store list length
Store<uint64_t>(list_entry.length, key_locations[i]);
key_locations[i] += sizeof(list_entry.length);
// make room for the validitymask
data_ptr_t list_validitymask_location = key_locations[i];
idx_t entry_offset_in_byte = 0;
idx_t validitymask_size = (list_entry.length + 7) / 8;
memset(list_validitymask_location, -1, validitymask_size);
key_locations[i] += validitymask_size;
// serialize size of each entry (if non-constant size)
data_ptr_t var_entry_size_ptr = nullptr;
if (!TypeIsConstantSize(child_type)) {
var_entry_size_ptr = key_locations[i];
key_locations[i] += list_entry.length * sizeof(idx_t);
}
auto entry_remaining = list_entry.length;
auto entry_offset = list_entry.offset;
while (entry_remaining > 0) {
// the list entry can span multiple vectors
auto next = MinValue((idx_t)STANDARD_VECTOR_SIZE, entry_remaining);
// serialize list validity
for (idx_t entry_idx = 0; entry_idx < next; entry_idx++) {
auto list_idx = list_vdata.sel->get_index(entry_idx) + entry_offset;
if (!list_vdata.validity.RowIsValid(list_idx)) {
*(list_validitymask_location) &= ~(1UL << entry_offset_in_byte);
}
if (++entry_offset_in_byte == 8) {
list_validitymask_location++;
entry_offset_in_byte = 0;
}
}
if (TypeIsConstantSize(child_type)) {
// constant size list entries: set list entry locations
const idx_t type_size = GetTypeIdSize(child_type);
for (idx_t entry_idx = 0; entry_idx < next; entry_idx++) {
list_entry_locations[entry_idx] = key_locations[i];
key_locations[i] += type_size;
}
} else {
// variable size list entries: compute entry sizes and set list entry locations
std::fill_n(list_entry_sizes, next, 0);
RowOperations::ComputeEntrySizes(child_vector, list_entry_sizes, next, next,
FlatVector::INCREMENTAL_SELECTION_VECTOR, entry_offset);
for (idx_t entry_idx = 0; entry_idx < next; entry_idx++) {
list_entry_locations[entry_idx] = key_locations[i];
key_locations[i] += list_entry_sizes[entry_idx];
Store<idx_t>(list_entry_sizes[entry_idx], var_entry_size_ptr);
var_entry_size_ptr += sizeof(idx_t);
}
}
// now serialize to the locations
RowOperations::HeapScatter(child_vector, ListVector::GetListSize(v),
FlatVector::INCREMENTAL_SELECTION_VECTOR, next, 0, list_entry_locations, nullptr,
entry_offset);
// update for next iteration
entry_remaining -= next;
entry_offset += next;
}
}
}
void RowOperations::HeapScatter(Vector &v, idx_t vcount, const SelectionVector &sel, idx_t ser_count, idx_t col_idx,
data_ptr_t *key_locations, data_ptr_t *validitymask_locations, idx_t offset) {
if (TypeIsConstantSize(v.GetType().InternalType())) {
VectorData vdata;
v.Orrify(vcount, vdata);
RowOperations::HeapScatterVData(vdata, v.GetType().InternalType(), sel, ser_count, col_idx, key_locations,
validitymask_locations, offset);
} else {
switch (v.GetType().InternalType()) {
case PhysicalType::VARCHAR:
HeapScatterStringVector(v, vcount, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::STRUCT:
HeapScatterStructVector(v, vcount, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::LIST:
HeapScatterListVector(v, vcount, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
default:
// LCOV_EXCL_START
throw NotImplementedException("Serialization of variable length vector with type %s",
v.GetType().ToString());
// LCOV_EXCL_STOP
}
}
}
void RowOperations::HeapScatterVData(VectorData &vdata, PhysicalType type, const SelectionVector &sel, idx_t ser_count,
idx_t col_idx, data_ptr_t *key_locations, data_ptr_t *validitymask_locations,
idx_t offset) {
switch (type) {
case PhysicalType::BOOL:
case PhysicalType::INT8:
TemplatedHeapScatter<int8_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::INT16:
TemplatedHeapScatter<int16_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::INT32:
TemplatedHeapScatter<int32_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::INT64:
TemplatedHeapScatter<int64_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::UINT8:
TemplatedHeapScatter<uint8_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::UINT16:
TemplatedHeapScatter<uint16_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::UINT32:
TemplatedHeapScatter<uint32_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::UINT64:
TemplatedHeapScatter<uint64_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::INT128:
TemplatedHeapScatter<hugeint_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::FLOAT:
TemplatedHeapScatter<float>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::DOUBLE:
TemplatedHeapScatter<double>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
case PhysicalType::INTERVAL:
TemplatedHeapScatter<interval_t>(vdata, sel, ser_count, col_idx, key_locations, validitymask_locations, offset);
break;
default:
throw NotImplementedException("FIXME: Serialize to of constant type column to row-format");
}
}
} // namespace duckdb