1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/common/vector_operations/aggregate_executor.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/exception.hpp"
12#include "duckdb/common/types/vector.hpp"
13#include "duckdb/common/vector_operations/vector_operations.hpp"
14
15namespace duckdb {
16
17class AggregateExecutor {
18private:
19 template <class STATE_TYPE, class INPUT_TYPE, class OP>
20 static inline void UnaryFlatLoop(INPUT_TYPE *__restrict idata, STATE_TYPE **__restrict states, nullmask_t &nullmask,
21 idx_t count) {
22 if (OP::IgnoreNull() && nullmask.any()) {
23 // potential NULL values and NULL values are ignored
24 for (idx_t i = 0; i < count; i++) {
25 if (!nullmask[i]) {
26 OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(states[i], idata, nullmask, i);
27 }
28 }
29 } else {
30 // quick path: no NULL values or NULL values are not ignored
31 for (idx_t i = 0; i < count; i++) {
32 OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(states[i], idata, nullmask, i);
33 }
34 }
35 }
36 template <class STATE_TYPE, class INPUT_TYPE, class OP>
37 static inline void UnaryScatterLoop(INPUT_TYPE *__restrict idata, STATE_TYPE **__restrict states,
38 const SelectionVector &isel, const SelectionVector &ssel, nullmask_t &nullmask,
39 idx_t count) {
40 if (OP::IgnoreNull() && nullmask.any()) {
41 // potential NULL values and NULL values are ignored
42 for (idx_t i = 0; i < count; i++) {
43 auto idx = isel.get_index(i);
44 auto sidx = ssel.get_index(i);
45 if (!nullmask[idx]) {
46 OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(states[sidx], idata, nullmask, idx);
47 }
48 }
49 } else {
50 // quick path: no NULL values or NULL values are not ignored
51 for (idx_t i = 0; i < count; i++) {
52 auto idx = isel.get_index(i);
53 auto sidx = ssel.get_index(i);
54 OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(states[sidx], idata, nullmask, idx);
55 }
56 }
57 }
58
59 template <class STATE_TYPE, class INPUT_TYPE, class OP, bool HAS_SEL_VECTOR>
60 static inline void UnaryUpdateLoop(INPUT_TYPE *__restrict idata, STATE_TYPE *__restrict state, idx_t count,
61 nullmask_t &nullmask, const SelectionVector *__restrict sel_vector) {
62 if (OP::IgnoreNull() && nullmask.any()) {
63 // potential NULL values and NULL values are ignored
64 for (idx_t i = 0; i < count; i++) {
65 auto idx = HAS_SEL_VECTOR ? sel_vector->get_index(i) : i;
66 if (!nullmask[idx]) {
67 OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(state, idata, nullmask, idx);
68 }
69 }
70 } else {
71 // quick path: no NULL values or NULL values are not ignored
72 for (idx_t i = 0; i < count; i++) {
73 auto idx = HAS_SEL_VECTOR ? sel_vector->get_index(i) : i;
74 OP::template Operation<INPUT_TYPE, STATE_TYPE, OP>(state, idata, nullmask, idx);
75 }
76 }
77 }
78
79 template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
80 static inline void BinaryScatterLoop(A_TYPE *__restrict adata, B_TYPE *__restrict bdata,
81 STATE_TYPE **__restrict states, idx_t count, const SelectionVector &asel,
82 const SelectionVector &bsel, const SelectionVector &ssel,
83 nullmask_t &anullmask, nullmask_t &bnullmask) {
84 if (OP::IgnoreNull() && (anullmask.any() || bnullmask.any())) {
85 // potential NULL values and NULL values are ignored
86 for (idx_t i = 0; i < count; i++) {
87 auto aidx = asel.get_index(i);
88 auto bidx = bsel.get_index(i);
89 auto sidx = ssel.get_index(i);
90 if (!anullmask[aidx] && !bnullmask[bidx]) {
91 OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(states[sidx], adata, bdata, anullmask,
92 bnullmask, aidx, bidx);
93 }
94 }
95 } else {
96 // quick path: no NULL values or NULL values are not ignored
97 for (idx_t i = 0; i < count; i++) {
98 auto aidx = asel.get_index(i);
99 auto bidx = bsel.get_index(i);
100 auto sidx = ssel.get_index(i);
101 OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(states[sidx], adata, bdata, anullmask, bnullmask,
102 aidx, bidx);
103 }
104 }
105 }
106
107 template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
108 static inline void BinaryUpdateLoop(A_TYPE *__restrict adata, B_TYPE *__restrict bdata,
109 STATE_TYPE *__restrict state, idx_t count, const SelectionVector &asel,
110 const SelectionVector &bsel, nullmask_t &anullmask, nullmask_t &bnullmask) {
111 if (OP::IgnoreNull() && (anullmask.any() || bnullmask.any())) {
112 // potential NULL values and NULL values are ignored
113 for (idx_t i = 0; i < count; i++) {
114 auto aidx = asel.get_index(i);
115 auto bidx = bsel.get_index(i);
116 if (!anullmask[aidx] && !bnullmask[bidx]) {
117 OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(state, adata, bdata, anullmask, bnullmask,
118 aidx, bidx);
119 }
120 }
121 } else {
122 // quick path: no NULL values or NULL values are not ignored
123 for (idx_t i = 0; i < count; i++) {
124 auto aidx = asel.get_index(i);
125 auto bidx = bsel.get_index(i);
126 OP::template Operation<A_TYPE, B_TYPE, STATE_TYPE, OP>(state, adata, bdata, anullmask, bnullmask, aidx,
127 bidx);
128 }
129 }
130 }
131
132public:
133 template <class STATE_TYPE, class INPUT_TYPE, class OP>
134 static void UnaryScatter(Vector &input, Vector &states, idx_t count) {
135 if (input.vector_type == VectorType::CONSTANT_VECTOR && states.vector_type == VectorType::CONSTANT_VECTOR) {
136 if (OP::IgnoreNull() && ConstantVector::IsNull(input)) {
137 // constant NULL input in function that ignores NULL values
138 return;
139 }
140 // regular constant: get first state
141 auto idata = ConstantVector::GetData<INPUT_TYPE>(input);
142 auto sdata = ConstantVector::GetData<STATE_TYPE *>(states);
143 OP::template ConstantOperation<INPUT_TYPE, STATE_TYPE, OP>(*sdata, idata, ConstantVector::Nullmask(input),
144 count);
145 } else if (input.vector_type == VectorType::FLAT_VECTOR && states.vector_type == VectorType::FLAT_VECTOR) {
146 auto idata = FlatVector::GetData<INPUT_TYPE>(input);
147 auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
148 UnaryFlatLoop<STATE_TYPE, INPUT_TYPE, OP>(idata, sdata, FlatVector::Nullmask(input), count);
149 } else {
150 VectorData idata, sdata;
151 input.Orrify(count, idata);
152 states.Orrify(count, sdata);
153 UnaryScatterLoop<STATE_TYPE, INPUT_TYPE, OP>((INPUT_TYPE *)idata.data, (STATE_TYPE **)sdata.data,
154 *idata.sel, *sdata.sel, *idata.nullmask, count);
155 }
156 }
157
158 template <class STATE_TYPE, class INPUT_TYPE, class OP>
159 static void UnaryUpdate(Vector &input, data_ptr_t state, idx_t count) {
160 switch (input.vector_type) {
161 case VectorType::CONSTANT_VECTOR: {
162 if (OP::IgnoreNull() && ConstantVector::IsNull(input)) {
163 return;
164 }
165 auto idata = ConstantVector::GetData<INPUT_TYPE>(input);
166 OP::template ConstantOperation<INPUT_TYPE, STATE_TYPE, OP>((STATE_TYPE *)state, idata,
167 ConstantVector::Nullmask(input), count);
168 break;
169 }
170 case VectorType::FLAT_VECTOR: {
171 auto idata = FlatVector::GetData<INPUT_TYPE>(input);
172 UnaryUpdateLoop<STATE_TYPE, INPUT_TYPE, OP, false>(idata, (STATE_TYPE *)state, count,
173 FlatVector::Nullmask(input), nullptr);
174 break;
175 }
176 default: {
177 VectorData idata;
178 input.Orrify(count, idata);
179 UnaryUpdateLoop<STATE_TYPE, INPUT_TYPE, OP, true>((INPUT_TYPE *)idata.data, (STATE_TYPE *)state, count,
180 *idata.nullmask, idata.sel);
181 break;
182 }
183 }
184 }
185
186 template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
187 static void BinaryScatter(Vector &a, Vector &b, Vector &states, idx_t count) {
188 VectorData adata, bdata, sdata;
189
190 a.Orrify(count, adata);
191 b.Orrify(count, bdata);
192 states.Orrify(count, sdata);
193
194 BinaryScatterLoop<STATE_TYPE, A_TYPE, B_TYPE, OP>((A_TYPE *)adata.data, (B_TYPE *)bdata.data,
195 (STATE_TYPE **)sdata.data, count, *adata.sel, *bdata.sel,
196 *sdata.sel, *adata.nullmask, *bdata.nullmask);
197 }
198
199 template <class STATE_TYPE, class A_TYPE, class B_TYPE, class OP>
200 static void BinaryUpdate(Vector &a, Vector &b, data_ptr_t state, idx_t count) {
201 VectorData adata, bdata;
202
203 a.Orrify(count, adata);
204 b.Orrify(count, bdata);
205
206 BinaryUpdateLoop<STATE_TYPE, A_TYPE, B_TYPE, OP>((A_TYPE *)adata.data, (B_TYPE *)bdata.data,
207 (STATE_TYPE *)state, count, *adata.sel, *bdata.sel,
208 *adata.nullmask, *bdata.nullmask);
209 }
210
211 template <class STATE_TYPE, class OP> static void Combine(Vector &source, Vector &target, idx_t count) {
212 auto sdata = FlatVector::GetData<STATE_TYPE>(source);
213 auto tdata = FlatVector::GetData<STATE_TYPE *>(target);
214
215 for (idx_t i = 0; i < count; i++) {
216 OP::template Combine<STATE_TYPE, OP>(sdata[i], tdata[i]);
217 }
218 }
219
220 template <class STATE_TYPE, class RESULT_TYPE, class OP>
221 static void Finalize(Vector &states, Vector &result, idx_t count) {
222 if (states.vector_type == VectorType::CONSTANT_VECTOR) {
223 result.vector_type = VectorType::CONSTANT_VECTOR;
224
225 auto sdata = ConstantVector::GetData<STATE_TYPE *>(states);
226 auto rdata = ConstantVector::GetData<RESULT_TYPE>(result);
227 OP::template Finalize<RESULT_TYPE, STATE_TYPE>(result, *sdata, rdata, ConstantVector::Nullmask(result), 0);
228 } else {
229 assert(states.vector_type == VectorType::FLAT_VECTOR);
230 result.vector_type = VectorType::FLAT_VECTOR;
231
232 auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
233 auto rdata = FlatVector::GetData<RESULT_TYPE>(result);
234 for (idx_t i = 0; i < count; i++) {
235 OP::template Finalize<RESULT_TYPE, STATE_TYPE>(result, sdata[i], rdata, FlatVector::Nullmask(result),
236 i);
237 }
238 }
239 }
240
241 template <class STATE_TYPE, class OP> static void Destroy(Vector &states, idx_t count) {
242 auto sdata = FlatVector::GetData<STATE_TYPE *>(states);
243 for (idx_t i = 0; i < count; i++) {
244 OP::template Destroy<STATE_TYPE>(sdata[i]);
245 }
246 }
247};
248
249} // namespace duckdb
250