Repository: duckdb/duckdb
File: src/storage/table/scan_state.cpp (C++)

Code before:
}

std::multimap<Value, RowGroup *> CollectionScanStateHelper::OrderRowGroups(RowGroupSegmentTree *row_groups,
                                                                           column_t column_idx,
                                                                           OrderByStatistics order_by,
                                                                           OrderByColumnType column_type) {
	std::multimap<Value, RowGroup *> ordered_row_groups;
	auto row_group = row_groups->GetRootSegment();
	while (row_group) {
		auto stats = row_group->GetStatistics(column_idx);
		Value comparison_value = RetrieveStat(*stats, order_by, column_type);
		ordered_row_groups.emplace(comparison_value, row_group);
		row_group = row_groups->GetNextSegment(row_group);
	}

	return ordered_row_groups;
}

unordered_map<RowGroup *, RowGroup *>
CollectionScanStateHelper::CreateRowGroupMap(const multimap<Value, RowGroup *> &row_groups,
                                             RowGroupOrderType order_type, RowGroup *&root) {
	if (row_groups.empty()) {
		return {};
	}

	unordered_map<RowGroup *, RowGroup *> row_group_map;

	RowGroup *current_row_group;
	if (order_type == RowGroupOrderType::ASC) {
		root = row_groups.begin()->second;
		current_row_group = root;
		for (auto it = std::next(row_groups.begin()); it != row_groups.end(); ++it) {
			row_group_map[current_row_group] = it->second;
			current_row_group = it->second;
		}
	} else {
		root = row_groups.rbegin()->second;
		current_row_group = root;
		for (auto it = std::next(row_groups.rbegin()); it != row_groups.rend(); ++it) {
			row_group_map[current_row_group] = it->second;
			current_row_group = it->second;
		}
	}

	return row_group_map;
}

CollectionScanState::CollectionScanState(TableScanState &parent_p)
    : row_group(nullptr), vector_index(0), max_row_group_row(0), row_groups(nullptr), max_row(0), batch_index(0),
      valid_sel(STANDARD_VECTOR_SIZE), random(-1), parent(parent_p) {
}

Review comment (suggestion):
Instead of doing this remap, since we have already obtained a (sorted) list of row groups, it would be better to fetch row groups from that list and iterate over that list in-order.

Relying on a re-mapping might be problematic, since we are traversing the row group list multiple times, and the second time might give us different row groups. I'm not sure how this would work out if e.g. another connection appends a new row group to the table while we are scanning it. We should probably add a test for this at the very least.

Code after:

ScanFilterInfo &CollectionScanState::GetFilterInfo() {
	return parent.GetFilterInfo();
}

ScanSamplingInfo &CollectionScanState::GetSamplingInfo() {
	return parent.GetSamplingInfo();
}

TableScanOptions &CollectionScanState::GetOptions() {
	return parent.options;
}

ParallelCollectionScanState::ParallelCollectionScanState()
    : collection(nullptr), current_row_group(nullptr), processed_rows(0) {
}

optional_ptr<RowGroup> ParallelCollectionScanState::GetRootSegment(RowGroupSegmentTree &row_groups) const {
	if (reorderer) {
		return reorderer->GetRootSegment(row_groups);
	}
	return row_groups.GetRootSegment();
}

optional_ptr<RowGroup> ParallelCollectionScanState::GetNextRowGroup(RowGroupSegmentTree &row_groups,
                                                                    optional_ptr<RowGroup> row_group) const {
	if (reorderer) {
		return reorderer->GetNextRowGroup(row_group);
	}
	return row_groups.GetNextSegment(row_group.get());
}

CollectionScanState::CollectionScanState(TableScanState &parent_p)
    : row_group(nullptr), vector_index(0), max_row_group_row(0), row_groups(nullptr), max_row(0), batch_index(0),
      valid_sel(STANDARD_VECTOR_SIZE), random(-1), parent(parent_p) {
}

optional_ptr<RowGroup> CollectionScanState::GetNextRowGroup(optional_ptr<RowGroup> row_group) const {
	if (reorderer) {
		return reorderer->GetNextRowGroup(row_group);
	}
	return row_groups->GetNextSegment(row_group.get());
}

optional_ptr<RowGroup> CollectionScanState::GetNextRowGroup(SegmentLock &l, optional_ptr<RowGroup> row_group) const {
	D_ASSERT(!reorderer);
	return row_groups->GetNextSegment(l, row_group.get());
}

optional_ptr<RowGroup> CollectionScanState::GetRootSegment() const {
	if (reorderer) {