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

Code before:
	return sub_columns[0]->GetMaxEntry();
}

void StructColumnData::IterateFields(
    ColumnScanState &state, const std::function<void(ColumnData &, optional_idx, ColumnScanState &, bool)> &callback) {
	if (state.storage_index.IsPushdownExtract()) {
		auto &index_children = state.storage_index.GetChildIndexes();
		D_ASSERT(index_children.size() == 1);
		auto &child_storage_index = index_children[0];
		auto child_index = child_storage_index.GetPrimaryIndex();
		auto &sub_column = *sub_columns[child_index];
		auto &field_state = state.child_states[1];
		D_ASSERT(state.scan_child_column[0]);
		callback(sub_column, optional_idx(), field_state, true);
	} else {
		for (idx_t i = 0; i < sub_columns.size(); i++) {
			auto &sub_column = *sub_columns[i];
			auto &field_state = state.child_states[1 + i];
			callback(sub_column, i, field_state, state.scan_child_column[i]);
		}
	}
}

void StructColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) {
	validity->InitializePrefetch(prefetch_state, scan_state.child_states[0], rows);
	IterateFields(scan_state, [&](ColumnData &field, optional_idx field_vector_index, ColumnScanState &field_state,
	                              bool should_scan) {
		if (!should_scan) {
			return;
		}
		field.InitializePrefetch(prefetch_state, field_state, rows);
	});
}

void StructColumnData::InitializeScan(ColumnScanState &state) {
	state.offset_in_column = 0;
	state.current = nullptr;

	// initialize the validity segment
	validity->InitializeScan(state.child_states[0]);

	// initialize the sub-columns
	IterateFields(
	    state, [&](ColumnData &field, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) {
		    if (!should_scan) {
			    return;
		    }
		    field.InitializeScan(field_state);
	    });
}


Review comment (suggestion):
Not directly related to this PR - but I mostly prefer to use iterators over these callback based interfaces. It looks better and is more flexible:

```cpp
for(auto &scan_field : ScanFields()) {
    scan_field.field;;
    scan_field.scan_state;
    scan_field.child_idx;
    // ...
}
```

Code after:

idx_t StructColumnData::GetMaxEntry() {
	return sub_columns[0]->GetMaxEntry();
}

void StructColumnData::IterateFields(
    ColumnScanState &state,
    const std::function<void(idx_t child_index, optional_idx, ColumnScanState &, bool)> &callback) {
	if (state.storage_index.IsPushdownExtract()) {
		auto &index_children = state.storage_index.GetChildIndexes();
		D_ASSERT(index_children.size() == 1);
		auto &child_storage_index = index_children[0];
		auto child_index = child_storage_index.GetPrimaryIndex();
		auto &field_state = state.child_states[1];
		D_ASSERT(state.scan_child_column[0]);
		callback(child_index, optional_idx(), field_state, true);
	} else {
		for (idx_t i = 0; i < sub_columns.size(); i++) {
			auto &field_state = state.child_states[1 + i];
			callback(i, i, field_state, state.scan_child_column[i]);
		}
	}
}

void StructColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) {
	validity->InitializePrefetch(prefetch_state, scan_state.child_states[0], rows);
	IterateFields(scan_state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state,
	                              bool should_scan) {
		if (!should_scan) {
			return;
		}
		auto &field = *sub_columns[child_index];
		field.InitializePrefetch(prefetch_state, field_state, rows);
	});
}

void StructColumnData::InitializeScan(ColumnScanState &state) {
	state.offset_in_column = 0;
	state.current = nullptr;

	// initialize the validity segment
	validity->InitializeScan(state.child_states[0]);

	// initialize the sub-columns
	IterateFields(
	    state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) {
		    if (!should_scan) {
			    return;
		    }
		    auto &field = *sub_columns[child_index];
		    field.InitializeScan(field_state);