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 | |
7 | namespace duckdb { |
8 | |
9 | void 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 | |
14 | BaseStatistics 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 | |
22 | BaseStatistics 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 | |
30 | void 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 | |
36 | const 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 | } |
43 | BaseStatistics &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 | |
51 | void 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 | |
59 | void 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 | |
69 | void ListStats::Serialize(const BaseStatistics &stats, FieldWriter &writer) { |
70 | auto &child_stats = ListStats::GetChildStats(stats); |
71 | writer.WriteSerializable(element: child_stats); |
72 | } |
73 | |
74 | BaseStatistics 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 | |
82 | string 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 | |
87 | void 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 | |