1#include "duckdb/storage/statistics/list_stats.hpp"
2#include "duckdb/storage/statistics/base_statistics.hpp"
3#include "duckdb/common/field_writer.hpp"
4#include "duckdb/common/string_util.hpp"
5#include "duckdb/common/types/vector.hpp"
6
7namespace duckdb {
8
9void ListStats::Construct(BaseStatistics &stats) {
10 stats.child_stats = unsafe_unique_array<BaseStatistics>(new BaseStatistics[1]);
11 BaseStatistics::Construct(stats&: stats.child_stats[0], type: ListType::GetChildType(type: stats.GetType()));
12}
13
14BaseStatistics ListStats::CreateUnknown(LogicalType type) {
15 auto &child_type = ListType::GetChildType(type);
16 BaseStatistics result(std::move(type));
17 result.InitializeUnknown();
18 result.child_stats[0].Copy(other: BaseStatistics::CreateUnknown(type: child_type));
19 return result;
20}
21
22BaseStatistics ListStats::CreateEmpty(LogicalType type) {
23 auto &child_type = ListType::GetChildType(type);
24 BaseStatistics result(std::move(type));
25 result.InitializeEmpty();
26 result.child_stats[0].Copy(other: BaseStatistics::CreateEmpty(type: child_type));
27 return result;
28}
29
30void ListStats::Copy(BaseStatistics &stats, const BaseStatistics &other) {
31 D_ASSERT(stats.child_stats);
32 D_ASSERT(other.child_stats);
33 stats.child_stats[0].Copy(other: other.child_stats[0]);
34}
35
36const BaseStatistics &ListStats::GetChildStats(const BaseStatistics &stats) {
37 if (stats.GetStatsType() != StatisticsType::LIST_STATS) {
38 throw InternalException("ListStats::GetChildStats called on stats that is not a list");
39 }
40 D_ASSERT(stats.child_stats);
41 return stats.child_stats[0];
42}
43BaseStatistics &ListStats::GetChildStats(BaseStatistics &stats) {
44 if (stats.GetStatsType() != StatisticsType::LIST_STATS) {
45 throw InternalException("ListStats::GetChildStats called on stats that is not a list");
46 }
47 D_ASSERT(stats.child_stats);
48 return stats.child_stats[0];
49}
50
51void ListStats::SetChildStats(BaseStatistics &stats, unique_ptr<BaseStatistics> new_stats) {
52 if (!new_stats) {
53 stats.child_stats[0].Copy(other: BaseStatistics::CreateUnknown(type: ListType::GetChildType(type: stats.GetType())));
54 } else {
55 stats.child_stats[0].Copy(other: *new_stats);
56 }
57}
58
59void ListStats::Merge(BaseStatistics &stats, const BaseStatistics &other) {
60 if (other.GetType().id() == LogicalTypeId::VALIDITY) {
61 return;
62 }
63
64 auto &child_stats = ListStats::GetChildStats(stats);
65 auto &other_child_stats = ListStats::GetChildStats(stats: other);
66 child_stats.Merge(other: other_child_stats);
67}
68
69void ListStats::Serialize(const BaseStatistics &stats, FieldWriter &writer) {
70 auto &child_stats = ListStats::GetChildStats(stats);
71 writer.WriteSerializable(element: child_stats);
72}
73
74BaseStatistics ListStats::Deserialize(FieldReader &reader, LogicalType type) {
75 D_ASSERT(type.InternalType() == PhysicalType::LIST);
76 auto &child_type = ListType::GetChildType(type);
77 BaseStatistics result(std::move(type));
78 result.child_stats[0].Copy(other: reader.ReadRequiredSerializable<BaseStatistics, BaseStatistics>(args: child_type));
79 return result;
80}
81
82string ListStats::ToString(const BaseStatistics &stats) {
83 auto &child_stats = ListStats::GetChildStats(stats);
84 return StringUtil::Format(fmt_str: "[%s]", params: child_stats.ToString());
85}
86
87void ListStats::Verify(const BaseStatistics &stats, Vector &vector, const SelectionVector &sel, idx_t count) {
88 auto &child_stats = ListStats::GetChildStats(stats);
89 auto &child_entry = ListVector::GetEntry(vector);
90 UnifiedVectorFormat vdata;
91 vector.ToUnifiedFormat(count, data&: vdata);
92
93 auto list_data = UnifiedVectorFormat::GetData<list_entry_t>(format: vdata);
94 idx_t total_list_count = 0;
95 for (idx_t i = 0; i < count; i++) {
96 auto idx = sel.get_index(idx: i);
97 auto index = vdata.sel->get_index(idx);
98 auto list = list_data[index];
99 if (vdata.validity.RowIsValid(row_idx: index)) {
100 for (idx_t list_idx = 0; list_idx < list.length; list_idx++) {
101 total_list_count++;
102 }
103 }
104 }
105 SelectionVector list_sel(total_list_count);
106 idx_t list_count = 0;
107 for (idx_t i = 0; i < count; i++) {
108 auto idx = sel.get_index(idx: i);
109 auto index = vdata.sel->get_index(idx);
110 auto list = list_data[index];
111 if (vdata.validity.RowIsValid(row_idx: index)) {
112 for (idx_t list_idx = 0; list_idx < list.length; list_idx++) {
113 list_sel.set_index(idx: list_count++, loc: list.offset + list_idx);
114 }
115 }
116 }
117
118 child_stats.Verify(vector&: child_entry, sel: list_sel, count: list_count);
119}
120
121} // namespace duckdb
122