Packages

An Elixir DuckDB library

Current section

Files

Jump to
exduckdb c_src duckdb src storage table struct_column_data.cpp
Raw

c_src/duckdb/src/storage/table/struct_column_data.cpp

#include "duckdb/storage/table/struct_column_data.hpp"
#include "duckdb/storage/statistics/struct_statistics.hpp"
namespace duckdb {
StructColumnData::StructColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type_p,
ColumnData *parent)
: ColumnData(info, column_index, start_row, move(type_p), parent), validity(info, 0, start_row, this) {
D_ASSERT(type.InternalType() == PhysicalType::STRUCT);
auto &child_types = StructType::GetChildTypes(type);
D_ASSERT(child_types.size() > 0);
// the sub column index, starting at 1 (0 is the validity mask)
idx_t sub_column_index = 1;
for (auto &child_type : child_types) {
sub_columns.push_back(
ColumnData::CreateColumnUnique(info, sub_column_index, start_row, child_type.second, this));
sub_column_index++;
}
}
bool StructColumnData::CheckZonemap(ColumnScanState &state, TableFilter &filter) {
// table filters are not supported yet for struct columns
return false;
}
idx_t StructColumnData::GetMaxEntry() {
return sub_columns[0]->GetMaxEntry();
}
void StructColumnData::InitializeScan(ColumnScanState &state) {
D_ASSERT(state.child_states.empty());
state.row_index = 0;
state.current = nullptr;
// initialize the validity segment
ColumnScanState validity_state;
validity.InitializeScan(validity_state);
state.child_states.push_back(move(validity_state));
// initialize the sub-columns
for (auto &sub_column : sub_columns) {
ColumnScanState child_state;
sub_column->InitializeScan(child_state);
state.child_states.push_back(move(child_state));
}
}
void StructColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) {
D_ASSERT(state.child_states.empty());
state.row_index = row_idx;
state.current = nullptr;
// initialize the validity segment
ColumnScanState validity_state;
validity.InitializeScanWithOffset(validity_state, row_idx);
state.child_states.push_back(move(validity_state));
// initialize the sub-columns
for (auto &sub_column : sub_columns) {
ColumnScanState child_state;
sub_column->InitializeScanWithOffset(child_state, row_idx);
state.child_states.push_back(move(child_state));
}
}
idx_t StructColumnData::Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result) {
auto scan_count = validity.Scan(transaction, vector_index, state.child_states[0], result);
auto &child_entries = StructVector::GetEntries(result);
for (idx_t i = 0; i < sub_columns.size(); i++) {
sub_columns[i]->Scan(transaction, vector_index, state.child_states[i + 1], *child_entries[i]);
}
return scan_count;
}
idx_t StructColumnData::ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates) {
auto scan_count = validity.ScanCommitted(vector_index, state.child_states[0], result, allow_updates);
auto &child_entries = StructVector::GetEntries(result);
for (idx_t i = 0; i < sub_columns.size(); i++) {
sub_columns[i]->ScanCommitted(vector_index, state.child_states[i + 1], *child_entries[i], allow_updates);
}
return scan_count;
}
idx_t StructColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t count) {
auto scan_count = validity.ScanCount(state.child_states[0], result, count);
auto &child_entries = StructVector::GetEntries(result);
for (idx_t i = 0; i < sub_columns.size(); i++) {
sub_columns[i]->ScanCount(state.child_states[i + 1], *child_entries[i], count);
}
return scan_count;
}
void StructColumnData::InitializeAppend(ColumnAppendState &state) {
ColumnAppendState validity_append;
validity.InitializeAppend(validity_append);
state.child_appends.push_back(move(validity_append));
for (auto &sub_column : sub_columns) {
ColumnAppendState child_append;
sub_column->InitializeAppend(child_append);
state.child_appends.push_back(move(child_append));
}
}
void StructColumnData::Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count) {
vector.Normalify(count);
// append the null values
validity.Append(*stats.validity_stats, state.child_appends[0], vector, count);
auto &struct_validity = FlatVector::Validity(vector);
auto &struct_stats = (StructStatistics &)stats;
auto &child_entries = StructVector::GetEntries(vector);
for (idx_t i = 0; i < child_entries.size(); i++) {
if (!struct_validity.AllValid()) {
// we set the child entries of the struct to NULL
// for any values in which the struct itself is NULL
child_entries[i]->Normalify(count);
auto &child_validity = FlatVector::Validity(*child_entries[i]);
child_validity.Combine(struct_validity, count);
}
sub_columns[i]->Append(*struct_stats.child_stats[i], state.child_appends[i + 1], *child_entries[i], count);
}
}
void StructColumnData::RevertAppend(row_t start_row) {
validity.RevertAppend(start_row);
for (auto &sub_column : sub_columns) {
sub_column->RevertAppend(start_row);
}
}
idx_t StructColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &result) {
// fetch validity mask
auto &child_entries = StructVector::GetEntries(result);
// insert any child states that are required
for (idx_t i = state.child_states.size(); i < child_entries.size() + 1; i++) {
ColumnScanState child_state;
state.child_states.push_back(move(child_state));
}
// fetch the validity state
idx_t scan_count = validity.Fetch(state.child_states[0], row_id, result);
// fetch the sub-column states
for (idx_t i = 0; i < child_entries.size(); i++) {
sub_columns[i]->Fetch(state.child_states[i + 1], row_id, *child_entries[i]);
}
return scan_count;
}
void StructColumnData::Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
idx_t offset, idx_t update_count) {
validity.Update(transaction, column_index, update_vector, row_ids, offset, update_count);
auto &child_entries = StructVector::GetEntries(update_vector);
for (idx_t i = 0; i < child_entries.size(); i++) {
sub_columns[i]->Update(transaction, column_index, *child_entries[i], row_ids, offset, update_count);
}
}
void StructColumnData::UpdateColumn(Transaction &transaction, const vector<column_t> &column_path,
Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth) {
// we can never DIRECTLY update a struct column
if (depth >= column_path.size()) {
throw InternalException("Attempting to directly update a struct column - this should not be possible");
}
auto update_column = column_path[depth];
if (update_column == 0) {
// update the validity column
validity.UpdateColumn(transaction, column_path, update_vector, row_ids, update_count, depth + 1);
} else {
if (update_column > sub_columns.size()) {
throw InternalException("Update column_path out of range");
}
sub_columns[update_column - 1]->UpdateColumn(transaction, column_path, update_vector, row_ids, update_count,
depth + 1);
}
}
unique_ptr<BaseStatistics> StructColumnData::GetUpdateStatistics() {
// check if any child column has updates
auto stats = BaseStatistics::CreateEmpty(type);
auto &struct_stats = (StructStatistics &)*stats;
stats->validity_stats = validity.GetUpdateStatistics();
for (idx_t i = 0; i < sub_columns.size(); i++) {
auto child_stats = sub_columns[i]->GetUpdateStatistics();
if (child_stats) {
struct_stats.child_stats[i] = move(child_stats);
}
}
return stats;
}
void StructColumnData::FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
idx_t result_idx) {
// fetch validity mask
auto &child_entries = StructVector::GetEntries(result);
// insert any child states that are required
for (idx_t i = state.child_states.size(); i < child_entries.size() + 1; i++) {
auto child_state = make_unique<ColumnFetchState>();
state.child_states.push_back(move(child_state));
}
// fetch the validity state
validity.FetchRow(transaction, *state.child_states[0], row_id, result, result_idx);
// fetch the sub-column states
for (idx_t i = 0; i < child_entries.size(); i++) {
sub_columns[i]->FetchRow(transaction, *state.child_states[i + 1], row_id, *child_entries[i], result_idx);
}
}
void StructColumnData::CommitDropColumn() {
validity.CommitDropColumn();
for (auto &sub_column : sub_columns) {
sub_column->CommitDropColumn();
}
}
struct StructColumnCheckpointState : public ColumnCheckpointState {
StructColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, TableDataWriter &writer)
: ColumnCheckpointState(row_group, column_data, writer) {
global_stats = make_unique<StructStatistics>(column_data.type);
}
unique_ptr<ColumnCheckpointState> validity_state;
vector<unique_ptr<ColumnCheckpointState>> child_states;
public:
unique_ptr<BaseStatistics> GetStatistics() override {
auto stats = make_unique<StructStatistics>(column_data.type);
D_ASSERT(stats->child_stats.size() == child_states.size());
stats->validity_stats = validity_state->GetStatistics();
for (idx_t i = 0; i < child_states.size(); i++) {
stats->child_stats[i] = child_states[i]->GetStatistics();
D_ASSERT(stats->child_stats[i]);
}
return move(stats);
}
void FlushToDisk() override {
validity_state->FlushToDisk();
for (auto &state : child_states) {
state->FlushToDisk();
}
}
};
unique_ptr<ColumnCheckpointState> StructColumnData::CreateCheckpointState(RowGroup &row_group,
TableDataWriter &writer) {
return make_unique<StructColumnCheckpointState>(row_group, *this, writer);
}
unique_ptr<ColumnCheckpointState> StructColumnData::Checkpoint(RowGroup &row_group, TableDataWriter &writer,
ColumnCheckpointInfo &checkpoint_info) {
auto checkpoint_state = make_unique<StructColumnCheckpointState>(row_group, *this, writer);
checkpoint_state->validity_state = validity.Checkpoint(row_group, writer, checkpoint_info);
for (auto &sub_column : sub_columns) {
checkpoint_state->child_states.push_back(sub_column->Checkpoint(row_group, writer, checkpoint_info));
}
return move(checkpoint_state);
}
void StructColumnData::DeserializeColumn(Deserializer &source) {
validity.DeserializeColumn(source);
for (auto &sub_column : sub_columns) {
sub_column->DeserializeColumn(source);
}
}
void StructColumnData::GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result) {
col_path.push_back(0);
validity.GetStorageInfo(row_group_index, col_path, result);
for (idx_t i = 0; i < sub_columns.size(); i++) {
col_path.back() = i + 1;
sub_columns[i]->GetStorageInfo(row_group_index, col_path, result);
}
}
void StructColumnData::Verify(RowGroup &parent) {
#ifdef DEBUG
ColumnData::Verify(parent);
validity.Verify(parent);
for (auto &sub_column : sub_columns) {
sub_column->Verify(parent);
}
#endif
}
} // namespace duckdb