/root/doris/be/src/exprs/vcondition_expr.cpp
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #include "exprs/vcondition_expr.h" |
19 | | |
20 | | #include <glog/logging.h> |
21 | | |
22 | | #include "core/column/column.h" |
23 | | #include "core/column/column_const.h" |
24 | | #include "exprs/function_context.h" |
25 | | #include "util/simd/bits.h" |
26 | | |
27 | | namespace doris { |
28 | | |
29 | | Status VConditionExpr::prepare(RuntimeState* state, const RowDescriptor& desc, |
30 | 0 | VExprContext* context) { |
31 | 0 | RETURN_IF_ERROR_OR_PREPARED(VExpr::prepare(state, desc, context)); |
32 | 0 | _prepare_finished = true; |
33 | 0 | return Status::OK(); |
34 | 0 | } |
35 | | |
36 | | Status VConditionExpr::open(RuntimeState* state, VExprContext* context, |
37 | 0 | FunctionContext::FunctionStateScope scope) { |
38 | 0 | DCHECK(_prepare_finished); |
39 | 0 | RETURN_IF_ERROR(VExpr::open(state, context, scope)); |
40 | 0 | _open_finished = true; |
41 | 0 | return Status::OK(); |
42 | 0 | } |
43 | | |
44 | 0 | void VConditionExpr::close(VExprContext* context, FunctionContext::FunctionStateScope scope) { |
45 | 0 | DCHECK(_prepare_finished); |
46 | 0 | VExpr::close(context, scope); |
47 | 0 | } |
48 | | |
49 | 0 | std::string VConditionExpr::debug_string() const { |
50 | 0 | std::string result = expr_name() + "("; |
51 | 0 | for (size_t i = 0; i < _children.size(); ++i) { |
52 | 0 | if (i != 0) { |
53 | 0 | result += ", "; |
54 | 0 | } |
55 | 0 | result += _children[i]->debug_string(); |
56 | 0 | } |
57 | 0 | result += ")"; |
58 | 0 | return result; |
59 | 0 | } |
60 | | |
61 | 0 | size_t VConditionExpr::count_true_with_notnull(const ColumnPtr& col) { |
62 | 0 | if (col->only_null()) { |
63 | 0 | return 0; |
64 | 0 | } |
65 | | |
66 | 0 | if (const auto* const_col = check_and_get_column<ColumnConst>(col.get())) { |
67 | | // if is null , get_bool will return false |
68 | | // bool get_bool(size_t n) const override { |
69 | | // return is_null_at(n) ? false : _nested_column->get_bool(n); |
70 | | // } |
71 | 0 | bool is_true = const_col->get_bool(0); |
72 | 0 | return is_true ? col->size() : 0; |
73 | 0 | } |
74 | | |
75 | 0 | auto count = col->size(); |
76 | 0 | if (col->is_nullable()) { |
77 | 0 | const auto* nullable = assert_cast<const ColumnNullable*>(col.get()); |
78 | 0 | const auto* __restrict null_data = nullable->get_null_map_data().data(); |
79 | 0 | const auto* __restrict bool_data = |
80 | 0 | ((const ColumnUInt8&)(nullable->get_nested_column())).get_data().data(); |
81 | |
|
82 | 0 | size_t null_count = count - simd::count_zero_num((const int8_t*)null_data, count); |
83 | |
|
84 | 0 | if (null_count == count) { |
85 | 0 | return 0; |
86 | 0 | } else if (null_count == 0) { |
87 | 0 | size_t true_count = count - simd::count_zero_num((const int8_t*)bool_data, count); |
88 | 0 | return true_count; |
89 | 0 | } else { |
90 | | // In fact, the null_count maybe is different with true_count, but it's no impact |
91 | 0 | return null_count; |
92 | 0 | } |
93 | 0 | } else { |
94 | 0 | const auto* bool_col = assert_cast<const ColumnUInt8*>(col.get()); |
95 | 0 | const auto* __restrict bool_data = bool_col->get_data().data(); |
96 | 0 | return count - simd::count_zero_num((const int8_t*)bool_data, count); |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | 0 | ColumnPtr materialize_column_if_const(const ColumnPtr& column) { |
101 | 0 | return column->convert_to_full_column_if_const(); |
102 | 0 | } |
103 | | |
104 | 0 | ColumnPtr make_nullable_column_if_not(const ColumnPtr& column) { |
105 | 0 | if (is_column_nullable(*column)) return column; |
106 | | |
107 | 0 | return ColumnNullable::create(materialize_column_if_const(column), |
108 | 0 | ColumnUInt8::create(column->size(), 0)); |
109 | 0 | } |
110 | | |
111 | 0 | ColumnPtr get_nested_column(const ColumnPtr& column) { |
112 | 0 | if (auto* nullable = check_and_get_column<ColumnNullable>(*column)) |
113 | 0 | return nullable->get_nested_column_ptr(); |
114 | 0 | else if (const auto* column_const = check_and_get_column<ColumnConst>(*column)) |
115 | 0 | return ColumnConst::create(get_nested_column(column_const->get_data_column_ptr()), |
116 | 0 | column->size()); |
117 | | |
118 | 0 | return column; |
119 | 0 | } |
120 | | |
121 | | Status VectorizedIfExpr::execute_generic(Block& block, const ColumnUInt8* cond_col, |
122 | | const ColumnWithTypeAndName& then_col_type_name, |
123 | | const ColumnWithTypeAndName& else_col_type_name, |
124 | 0 | uint32_t result, size_t input_row_count) const { |
125 | 0 | MutableColumnPtr result_column = block.get_by_position(result).type->create_column(); |
126 | 0 | result_column->reserve(input_row_count); |
127 | |
|
128 | 0 | const IColumn& then_col = *then_col_type_name.column; |
129 | 0 | const IColumn& else_col = *else_col_type_name.column; |
130 | 0 | bool then_is_const = is_column_const(then_col); |
131 | 0 | bool else_is_const = is_column_const(else_col); |
132 | |
|
133 | 0 | const auto& cond_array = cond_col->get_data(); |
134 | |
|
135 | 0 | if (then_is_const && else_is_const) { |
136 | 0 | const IColumn& then_nested_column = |
137 | 0 | assert_cast<const ColumnConst&>(then_col).get_data_column(); |
138 | 0 | const IColumn& else_nested_column = |
139 | 0 | assert_cast<const ColumnConst&>(else_col).get_data_column(); |
140 | 0 | for (size_t i = 0; i < input_row_count; i++) { |
141 | 0 | if (cond_array[i]) |
142 | 0 | result_column->insert_from(then_nested_column, 0); |
143 | 0 | else |
144 | 0 | result_column->insert_from(else_nested_column, 0); |
145 | 0 | } |
146 | 0 | } else if (then_is_const) { |
147 | 0 | const IColumn& then_nested_column = |
148 | 0 | assert_cast<const ColumnConst&>(then_col).get_data_column(); |
149 | |
|
150 | 0 | for (size_t i = 0; i < input_row_count; i++) { |
151 | 0 | if (cond_array[i]) |
152 | 0 | result_column->insert_from(then_nested_column, 0); |
153 | 0 | else |
154 | 0 | result_column->insert_from(else_col, i); |
155 | 0 | } |
156 | 0 | } else if (else_is_const) { |
157 | 0 | const IColumn& else_nested_column = |
158 | 0 | assert_cast<const ColumnConst&>(else_col).get_data_column(); |
159 | |
|
160 | 0 | for (size_t i = 0; i < input_row_count; i++) { |
161 | 0 | if (cond_array[i]) |
162 | 0 | result_column->insert_from(then_col, i); |
163 | 0 | else |
164 | 0 | result_column->insert_from(else_nested_column, 0); |
165 | 0 | } |
166 | 0 | } else { |
167 | 0 | for (size_t i = 0; i < input_row_count; i++) { |
168 | 0 | result_column->insert_from(cond_array[i] ? then_col : else_col, i); |
169 | 0 | } |
170 | 0 | } |
171 | 0 | block.replace_by_position(result, std::move(result_column)); |
172 | 0 | return Status::OK(); |
173 | 0 | } |
174 | | |
175 | | Status VectorizedIfExpr::execute_for_null_then_else(Block& block, |
176 | | const ColumnWithTypeAndName& arg_cond, |
177 | | const ColumnWithTypeAndName& arg_then, |
178 | | const ColumnWithTypeAndName& arg_else, |
179 | | uint32_t result, size_t input_rows_count, |
180 | 0 | bool& handled) const { |
181 | 0 | bool then_is_null = arg_then.column->only_null(); |
182 | 0 | bool else_is_null = arg_else.column->only_null(); |
183 | |
|
184 | 0 | handled = false; |
185 | 0 | if (!then_is_null && !else_is_null) { |
186 | 0 | return Status::OK(); |
187 | 0 | } |
188 | | |
189 | 0 | if (then_is_null && else_is_null) { |
190 | 0 | block.get_by_position(result).column = |
191 | 0 | block.get_by_position(result).type->create_column_const_with_default_value( |
192 | 0 | input_rows_count); |
193 | 0 | handled = true; |
194 | 0 | return Status::OK(); |
195 | 0 | } |
196 | | |
197 | 0 | const auto* cond_col = typeid_cast<const ColumnUInt8*>(arg_cond.column.get()); |
198 | 0 | const ColumnConst* cond_const_col = |
199 | 0 | check_and_get_column_const<ColumnUInt8>(arg_cond.column.get()); |
200 | | |
201 | | /// If then is NULL, we create Nullable column with null mask OR-ed with condition. |
202 | 0 | if (then_is_null) { |
203 | 0 | if (cond_col) { |
204 | 0 | if (is_column_nullable(*arg_else.column)) { // if(cond, null, nullable) |
205 | 0 | auto arg_else_column = arg_else.column; |
206 | 0 | auto result_column = (*std::move(arg_else_column)).mutate(); |
207 | 0 | assert_cast<ColumnNullable&>(*result_column) |
208 | 0 | .apply_null_map(assert_cast<const ColumnUInt8&>(*arg_cond.column)); |
209 | 0 | block.replace_by_position(result, std::move(result_column)); |
210 | 0 | } else { // if(cond, null, not_nullable) |
211 | 0 | block.replace_by_position( |
212 | 0 | result, ColumnNullable::create(materialize_column_if_const(arg_else.column), |
213 | 0 | arg_cond.column)); |
214 | 0 | } |
215 | 0 | } else if (cond_const_col) { |
216 | 0 | if (cond_const_col->get_value<TYPE_BOOLEAN>()) { // if(true, null, else) |
217 | 0 | block.get_by_position(result).column = |
218 | 0 | block.get_by_position(result).type->create_column()->clone_resized( |
219 | 0 | input_rows_count); |
220 | 0 | } else { // if(false, null, else) |
221 | 0 | block.get_by_position(result).column = make_nullable_column_if_not(arg_else.column); |
222 | 0 | } |
223 | 0 | } else { |
224 | 0 | return Status::InternalError( |
225 | 0 | "Illegal column {} of first argument of function {}. Must be ColumnUInt8 " |
226 | 0 | "or ColumnConstUInt8.", |
227 | 0 | arg_cond.column->get_name(), expr_name()); |
228 | 0 | } |
229 | 0 | } else { /// If else is NULL, we create Nullable column with null mask OR-ed with negated condition. |
230 | 0 | if (cond_col) { |
231 | 0 | size_t size = input_rows_count; |
232 | |
|
233 | 0 | if (is_column_nullable(*arg_then.column)) { // if(cond, nullable, NULL) |
234 | 0 | auto arg_then_column = arg_then.column; |
235 | 0 | auto result_column = (*std::move(arg_then_column)).mutate(); |
236 | 0 | assert_cast<ColumnNullable&>(*result_column) |
237 | 0 | .apply_negated_null_map(assert_cast<const ColumnUInt8&>(*arg_cond.column)); |
238 | 0 | block.replace_by_position(result, std::move(result_column)); |
239 | 0 | } else { // if(cond, not_nullable, NULL) |
240 | 0 | const auto& null_map_data = cond_col->get_data(); |
241 | 0 | auto negated_null_map = ColumnUInt8::create(); |
242 | 0 | auto& negated_null_map_data = negated_null_map->get_data(); |
243 | 0 | negated_null_map_data.resize(size); |
244 | |
|
245 | 0 | for (size_t i = 0; i < size; ++i) { |
246 | 0 | negated_null_map_data[i] = !null_map_data[i]; |
247 | 0 | } |
248 | |
|
249 | 0 | block.replace_by_position( |
250 | 0 | result, ColumnNullable::create(materialize_column_if_const(arg_then.column), |
251 | 0 | std::move(negated_null_map))); |
252 | 0 | } |
253 | 0 | } else if (cond_const_col) { |
254 | 0 | if (cond_const_col->get_value<TYPE_BOOLEAN>()) { // if(true, then, NULL) |
255 | 0 | block.get_by_position(result).column = make_nullable_column_if_not(arg_then.column); |
256 | 0 | } else { // if(false, then, NULL) |
257 | 0 | block.get_by_position(result).column = |
258 | 0 | block.get_by_position(result).type->create_column()->clone_resized( |
259 | 0 | input_rows_count); |
260 | 0 | } |
261 | 0 | } else { |
262 | 0 | return Status::InternalError( |
263 | 0 | "Illegal column {} of first argument of function {}. Must be ColumnUInt8 " |
264 | 0 | "or ColumnConstUInt8.", |
265 | 0 | arg_cond.column->get_name(), expr_name()); |
266 | 0 | } |
267 | 0 | } |
268 | 0 | handled = true; |
269 | 0 | return Status::OK(); |
270 | 0 | } |
271 | | |
272 | | Status VectorizedIfExpr::execute_for_nullable_then_else(Block& block, |
273 | | const ColumnWithTypeAndName& arg_cond, |
274 | | const ColumnWithTypeAndName& arg_then, |
275 | | const ColumnWithTypeAndName& arg_else, |
276 | | uint32_t result, size_t input_rows_count, |
277 | 0 | bool& handled) const { |
278 | 0 | auto then_type_is_nullable = arg_then.type->is_nullable(); |
279 | 0 | auto else_type_is_nullable = arg_else.type->is_nullable(); |
280 | 0 | handled = false; |
281 | 0 | if (!then_type_is_nullable && !else_type_is_nullable) { |
282 | 0 | return Status::OK(); |
283 | 0 | } |
284 | | |
285 | 0 | const auto* then_is_nullable = check_and_get_column<ColumnNullable>(*arg_then.column); |
286 | 0 | const auto* else_is_nullable = check_and_get_column<ColumnNullable>(*arg_else.column); |
287 | 0 | bool then_column_is_const_nullable = false; |
288 | 0 | bool else_column_is_const_nullable = false; |
289 | 0 | if (then_type_is_nullable && then_is_nullable == nullptr) { |
290 | | //this case is a const(nullable column) |
291 | 0 | const auto& const_column = assert_cast<const ColumnConst&>(*arg_then.column); |
292 | 0 | then_is_nullable = |
293 | 0 | assert_cast<const ColumnNullable*>(const_column.get_data_column_ptr().get()); |
294 | 0 | then_column_is_const_nullable = true; |
295 | 0 | } |
296 | |
|
297 | 0 | if (else_type_is_nullable && else_is_nullable == nullptr) { |
298 | | //this case is a const(nullable column) |
299 | 0 | const auto& const_column = assert_cast<const ColumnConst&>(*arg_else.column); |
300 | 0 | else_is_nullable = |
301 | 0 | assert_cast<const ColumnNullable*>(const_column.get_data_column_ptr().get()); |
302 | 0 | else_column_is_const_nullable = true; |
303 | 0 | } |
304 | | |
305 | | /** Calculate null mask of result and nested column separately. |
306 | | */ |
307 | 0 | ColumnPtr result_null_mask; |
308 | 0 | { |
309 | | // get null map from column: |
310 | | // a. get_null_map_column_ptr() : it's a real nullable column, so could get it from nullable column |
311 | | // b. create a const_nullmap_column: it's a not nullable column or a const nullable column, contain a const value |
312 | 0 | Block temporary_block; |
313 | 0 | temporary_block.insert(arg_cond); |
314 | 0 | auto then_nested_null_map = |
315 | 0 | (then_type_is_nullable && !then_column_is_const_nullable) |
316 | 0 | ? then_is_nullable->get_null_map_column_ptr() |
317 | 0 | : DataTypeUInt8().create_column_const_with_default_value(input_rows_count); |
318 | 0 | temporary_block.insert( |
319 | 0 | {then_nested_null_map, std::make_shared<DataTypeUInt8>(), "then_column_null_map"}); |
320 | |
|
321 | 0 | auto else_nested_null_map = |
322 | 0 | (else_type_is_nullable && !else_column_is_const_nullable) |
323 | 0 | ? else_is_nullable->get_null_map_column_ptr() |
324 | 0 | : DataTypeUInt8().create_column_const_with_default_value(input_rows_count); |
325 | 0 | temporary_block.insert( |
326 | 0 | {else_nested_null_map, std::make_shared<DataTypeUInt8>(), "else_column_null_map"}); |
327 | 0 | temporary_block.insert( |
328 | 0 | {nullptr, std::make_shared<DataTypeUInt8>(), "result_column_null_map"}); |
329 | |
|
330 | 0 | RETURN_IF_ERROR( |
331 | 0 | _execute_impl_internal(temporary_block, {0, 1, 2}, 3, temporary_block.rows())); |
332 | | |
333 | 0 | result_null_mask = temporary_block.get_by_position(3).column; |
334 | 0 | } |
335 | | |
336 | 0 | ColumnPtr result_nested_column; |
337 | |
|
338 | 0 | { |
339 | 0 | Block temporary_block( |
340 | 0 | {arg_cond, |
341 | 0 | {get_nested_column(arg_then.column), remove_nullable(arg_then.type), ""}, |
342 | 0 | {get_nested_column(arg_else.column), remove_nullable(arg_else.type), ""}, |
343 | 0 | {nullptr, remove_nullable(block.get_by_position(result).type), ""}}); |
344 | |
|
345 | 0 | RETURN_IF_ERROR( |
346 | 0 | _execute_impl_internal(temporary_block, {0, 1, 2}, 3, temporary_block.rows())); |
347 | | |
348 | 0 | result_nested_column = temporary_block.get_by_position(3).column; |
349 | 0 | } |
350 | | |
351 | 0 | auto column = ColumnNullable::create(materialize_column_if_const(result_nested_column), |
352 | 0 | materialize_column_if_const(result_null_mask)); |
353 | 0 | block.replace_by_position(result, std::move(column)); |
354 | 0 | handled = true; |
355 | 0 | return Status::OK(); |
356 | 0 | } |
357 | | |
358 | | Status VectorizedIfExpr::execute_for_null_condition(Block& block, const ColumnNumbers& arguments, |
359 | | const ColumnWithTypeAndName& arg_cond, |
360 | | const ColumnWithTypeAndName& arg_then, |
361 | | const ColumnWithTypeAndName& arg_else, |
362 | 0 | uint32_t result, bool& handled) const { |
363 | 0 | bool cond_is_null = arg_cond.column->only_null(); |
364 | 0 | handled = false; |
365 | |
|
366 | 0 | if (cond_is_null) { |
367 | 0 | block.replace_by_position(result, arg_else.column->clone_resized(arg_cond.column->size())); |
368 | 0 | handled = true; |
369 | 0 | return Status::OK(); |
370 | 0 | } |
371 | | |
372 | 0 | if (const auto* nullable = check_and_get_column<ColumnNullable>(*arg_cond.column)) { |
373 | 0 | DCHECK(remove_nullable(arg_cond.type)->get_primitive_type() == PrimitiveType::TYPE_BOOLEAN); |
374 | | |
375 | | // update nested column by null map |
376 | 0 | const auto* __restrict null_map = nullable->get_null_map_data().data(); |
377 | 0 | auto* __restrict nested_bool_data = |
378 | 0 | ((ColumnUInt8&)(nullable->get_nested_column())).get_data().data(); |
379 | 0 | auto rows = nullable->size(); |
380 | 0 | for (size_t i = 0; i < rows; i++) { |
381 | 0 | nested_bool_data[i] &= !null_map[i]; |
382 | 0 | } |
383 | 0 | auto column_size = block.columns(); |
384 | 0 | block.insert( |
385 | 0 | {nullable->get_nested_column_ptr(), remove_nullable(arg_cond.type), arg_cond.name}); |
386 | |
|
387 | 0 | handled = true; |
388 | 0 | return _execute_impl_internal(block, {column_size, arguments[1], arguments[2]}, result, |
389 | 0 | rows); |
390 | 0 | } |
391 | 0 | return Status::OK(); |
392 | 0 | } |
393 | | |
394 | | Status VectorizedIfExpr::_execute_impl_internal(Block& block, const ColumnNumbers& arguments, |
395 | 0 | uint32_t result, size_t input_rows_count) const { |
396 | 0 | const ColumnWithTypeAndName& arg_then = block.get_by_position(arguments[1]); |
397 | 0 | const ColumnWithTypeAndName& arg_else = block.get_by_position(arguments[2]); |
398 | 0 | ColumnWithTypeAndName& cond_column = block.get_by_position(arguments[0]); |
399 | 0 | cond_column.column = materialize_column_if_const(cond_column.column); |
400 | 0 | const ColumnWithTypeAndName& arg_cond = block.get_by_position(arguments[0]); |
401 | |
|
402 | 0 | Status ret = Status::OK(); |
403 | 0 | bool handled = false; |
404 | 0 | RETURN_IF_ERROR(execute_for_null_condition(block, arguments, arg_cond, arg_then, arg_else, |
405 | 0 | result, handled)); |
406 | | |
407 | 0 | if (!handled) { |
408 | 0 | RETURN_IF_ERROR(execute_for_null_then_else(block, arg_cond, arg_then, arg_else, result, |
409 | 0 | input_rows_count, handled)); |
410 | 0 | } |
411 | | |
412 | 0 | if (!handled) { |
413 | 0 | RETURN_IF_ERROR(execute_for_nullable_then_else(block, arg_cond, arg_then, arg_else, result, |
414 | 0 | input_rows_count, handled)); |
415 | 0 | } |
416 | | |
417 | 0 | if (handled) { |
418 | 0 | return Status::OK(); |
419 | 0 | } |
420 | | |
421 | 0 | const auto* cond_col = assert_cast<const ColumnUInt8*>(arg_cond.column.get()); |
422 | 0 | const ColumnConst* cond_const_col = |
423 | 0 | check_and_get_column_const<ColumnUInt8>(arg_cond.column.get()); |
424 | |
|
425 | 0 | if (cond_const_col) { |
426 | 0 | block.get_by_position(result).column = |
427 | 0 | cond_const_col->get_value<TYPE_BOOLEAN>() ? arg_then.column : arg_else.column; |
428 | 0 | return Status::OK(); |
429 | 0 | } |
430 | | |
431 | 0 | Status vec_exec; |
432 | |
|
433 | 0 | auto call = [&](const auto& type) -> bool { |
434 | 0 | using DataType = std::decay_t<decltype(type)>; |
435 | 0 | vec_exec = execute_basic_type<DataType::PType>(block, cond_col, arg_then, arg_else, result, |
436 | 0 | vec_exec); |
437 | 0 | return true; |
438 | 0 | }; Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE2EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE3EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE4EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE5EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE6EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE7EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE8EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE9EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE28EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE29EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE20EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE30EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE35EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE11EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE25EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE26EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE12EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE27EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE42EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE36EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZNK5doris16VectorizedIfExpr22_execute_impl_internalERNS_5BlockERKSt6vectorIjSaIjEEjmENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE37EEEEEbRKT_ |
439 | |
|
440 | 0 | auto can_use_vec_exec = dispatch_switch_scalar(arg_then.type->get_primitive_type(), call); |
441 | 0 | if (can_use_vec_exec) { |
442 | 0 | return vec_exec; |
443 | 0 | } else { |
444 | 0 | return execute_generic(block, cond_col, arg_then, arg_else, result, input_rows_count); |
445 | 0 | } |
446 | 0 | } |
447 | | |
448 | | Status VectorizedIfExpr::execute_column(VExprContext* context, const Block* block, |
449 | | Selector* selector, size_t count, |
450 | 0 | ColumnPtr& result_column) const { |
451 | 0 | DCHECK(_open_finished || block == nullptr) << debug_string(); |
452 | 0 | DCHECK_EQ(_children.size(), 3) << "IF expr must have three children"; |
453 | |
|
454 | 0 | ColumnPtr cond_column; |
455 | 0 | RETURN_IF_ERROR(_children[0]->execute_column(context, block, selector, count, cond_column)); |
456 | | |
457 | 0 | ColumnPtr then_column; |
458 | 0 | ColumnPtr else_column; |
459 | |
|
460 | 0 | auto true_count = count_true_with_notnull(cond_column); |
461 | 0 | auto item_count = cond_column->size(); |
462 | 0 | if (true_count == item_count) { |
463 | 0 | RETURN_IF_ERROR(_children[1]->execute_column(context, block, selector, count, then_column)); |
464 | 0 | result_column = _data_type->is_nullable() ? make_nullable(then_column) : then_column; |
465 | 0 | return Status::OK(); |
466 | 0 | } else if (true_count == 0) { |
467 | 0 | RETURN_IF_ERROR(_children[2]->execute_column(context, block, selector, count, else_column)); |
468 | 0 | result_column = _data_type->is_nullable() ? make_nullable(else_column) : else_column; |
469 | 0 | return Status::OK(); |
470 | 0 | } |
471 | | |
472 | 0 | RETURN_IF_ERROR(_children[1]->execute_column(context, block, selector, count, then_column)); |
473 | 0 | RETURN_IF_ERROR(_children[2]->execute_column(context, block, selector, count, else_column)); |
474 | | |
475 | 0 | Block temp_block; |
476 | |
|
477 | 0 | temp_block.insert({cond_column, _children[0]->execute_type(block), _children[0]->expr_name()}); |
478 | 0 | temp_block.insert({then_column, _children[1]->execute_type(block), _children[1]->expr_name()}); |
479 | 0 | temp_block.insert({else_column, _children[2]->execute_type(block), _children[2]->expr_name()}); |
480 | | |
481 | | // prepare a column to save result |
482 | 0 | temp_block.insert({nullptr, _data_type, IF_NAME}); |
483 | 0 | RETURN_IF_ERROR(_execute_impl_internal(temp_block, {0, 1, 2}, 3, temp_block.rows())); |
484 | 0 | result_column = temp_block.get_by_position(3).column; |
485 | 0 | DCHECK_EQ(result_column->size(), count); |
486 | 0 | return Status::OK(); |
487 | 0 | } |
488 | | |
489 | | Status VectorizedIfNullExpr::execute_column(VExprContext* context, const Block* block, |
490 | | Selector* selector, size_t count, |
491 | 0 | ColumnPtr& result_column) const { |
492 | 0 | DCHECK(_open_finished || block == nullptr) << debug_string(); |
493 | 0 | DCHECK_EQ(_children.size(), 2) << "IFNULL expr must have two children"; |
494 | |
|
495 | 0 | ColumnPtr first_column; |
496 | 0 | RETURN_IF_ERROR(_children[0]->execute_column(context, block, selector, count, first_column)); |
497 | 0 | first_column = first_column->convert_to_full_column_if_const(); |
498 | |
|
499 | 0 | if (!first_column->is_nullable()) { |
500 | 0 | result_column = first_column; |
501 | 0 | DCHECK(_data_type->is_nullable() == false); |
502 | 0 | return Status::OK(); |
503 | 0 | } |
504 | | |
505 | 0 | if (first_column->only_null()) { |
506 | 0 | RETURN_IF_ERROR( |
507 | 0 | _children[1]->execute_column(context, block, selector, count, result_column)); |
508 | 0 | return Status::OK(); |
509 | 0 | } |
510 | | |
511 | 0 | ColumnPtr second_column; |
512 | 0 | RETURN_IF_ERROR(_children[1]->execute_column(context, block, selector, count, second_column)); |
513 | | |
514 | 0 | const auto& nullable_first_column = assert_cast<const ColumnNullable&>(*first_column); |
515 | |
|
516 | 0 | ColumnPtr cond_column = nullable_first_column.get_null_map_column_ptr(); |
517 | |
|
518 | 0 | ColumnPtr then_column = second_column; |
519 | |
|
520 | 0 | ColumnPtr else_column; |
521 | 0 | DataTypePtr else_type; |
522 | |
|
523 | 0 | if (_data_type->is_nullable()) { |
524 | 0 | else_column = first_column; |
525 | 0 | else_type = _children[0]->execute_type(block); |
526 | 0 | } else { |
527 | 0 | else_column = nullable_first_column.get_nested_column_ptr(); |
528 | 0 | else_type = remove_nullable(_children[0]->execute_type(block)); |
529 | 0 | } |
530 | |
|
531 | 0 | Block temp_block; |
532 | 0 | temp_block.insert({cond_column, std::make_shared<DataTypeUInt8>(), "cond column"}); |
533 | 0 | temp_block.insert({then_column, _children[1]->execute_type(block), _children[1]->expr_name()}); |
534 | 0 | temp_block.insert({else_column, else_type, _children[0]->expr_name()}); |
535 | | |
536 | | // prepare a column to save result |
537 | 0 | temp_block.insert({nullptr, _data_type, IF_NULL_NAME}); |
538 | 0 | RETURN_IF_ERROR(_execute_impl_internal(temp_block, {0, 1, 2}, 3, temp_block.rows())); |
539 | 0 | result_column = temp_block.get_by_position(3).column; |
540 | 0 | DCHECK_EQ(result_column->size(), count); |
541 | 0 | return Status::OK(); |
542 | 0 | } |
543 | | |
544 | | template <typename ColumnType> |
545 | | void insert_result_data(MutableColumnPtr& result_column, ColumnPtr& argument_column, |
546 | | const UInt8* __restrict null_map_data, UInt8* __restrict filled_flag, |
547 | 0 | const size_t input_rows_count) { |
548 | 0 | if (result_column->size() == 0 && input_rows_count) { |
549 | 0 | result_column->resize(input_rows_count); |
550 | 0 | auto* __restrict result_raw_data = |
551 | 0 | assert_cast<ColumnType*>(result_column.get())->get_data().data(); |
552 | 0 | for (int i = 0; i < input_rows_count; i++) { |
553 | 0 | result_raw_data[i] = {}; |
554 | 0 | } |
555 | 0 | } |
556 | 0 | auto* __restrict result_raw_data = |
557 | 0 | assert_cast<ColumnType*>(result_column.get())->get_data().data(); |
558 | 0 | auto* __restrict column_raw_data = |
559 | 0 | assert_cast<const ColumnType*>(argument_column.get())->get_data().data(); |
560 | | |
561 | | // Here it's SIMD thought the compiler automatically also |
562 | | // true: null_map_data[row]==0 && filled_idx[row]==0 |
563 | | // if true, could filled current row data into result column |
564 | 0 | for (size_t row = 0; row < input_rows_count; ++row) { |
565 | 0 | if constexpr (std::is_same_v<ColumnType, ColumnDateV2>) { |
566 | 0 | result_raw_data[row] = binary_cast<uint32_t, DateV2Value<DateV2ValueType>>( |
567 | 0 | result_raw_data[row].to_date_int_val() + |
568 | 0 | column_raw_data[row].to_date_int_val() * |
569 | 0 | uint32_t(!(null_map_data[row] | filled_flag[row]))); |
570 | 0 | } else if constexpr (std::is_same_v<ColumnType, ColumnDateTimeV2>) { |
571 | 0 | result_raw_data[row] = binary_cast<uint64_t, DateV2Value<DateTimeV2ValueType>>( |
572 | 0 | result_raw_data[row].to_date_int_val() + |
573 | 0 | column_raw_data[row].to_date_int_val() * |
574 | 0 | uint64_t(!(null_map_data[row] | filled_flag[row]))); |
575 | 0 | } else if constexpr (std::is_same_v<ColumnType, ColumnTimeStampTz>) { |
576 | 0 | result_raw_data[row] = binary_cast<uint64_t, TimestampTzValue>( |
577 | 0 | result_raw_data[row].to_date_int_val() + |
578 | 0 | column_raw_data[row].to_date_int_val() * |
579 | 0 | uint64_t(!(null_map_data[row] | filled_flag[row]))); |
580 | | } else if constexpr (std::is_same_v<ColumnType, ColumnDate> || |
581 | 0 | std::is_same_v<ColumnType, ColumnDateTime>) { |
582 | 0 | result_raw_data[row] = binary_cast<int64_t, VecDateTimeValue>( |
583 | 0 | binary_cast<VecDateTimeValue, int64_t>(result_raw_data[row]) + |
584 | 0 | binary_cast<VecDateTimeValue, int64_t>(column_raw_data[row]) * |
585 | 0 | int64_t(!(null_map_data[row] | filled_flag[row]))); |
586 | 0 | } else { |
587 | 0 | result_raw_data[row] += |
588 | 0 | column_raw_data[row] * |
589 | 0 | typename ColumnType::value_type(!(null_map_data[row] | filled_flag[row])); |
590 | 0 | } |
591 | |
|
592 | 0 | filled_flag[row] += (!(null_map_data[row] | filled_flag[row])); |
593 | 0 | } |
594 | 0 | } Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE2EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE3EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE4EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE5EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE6EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE7EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE8EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE9EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_13ColumnDecimalILNS_13PrimitiveTypeE28EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_13ColumnDecimalILNS_13PrimitiveTypeE29EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_13ColumnDecimalILNS_13PrimitiveTypeE20EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_13ColumnDecimalILNS_13PrimitiveTypeE30EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_13ColumnDecimalILNS_13PrimitiveTypeE35EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE11EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE25EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE26EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE12EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE27EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE42EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE36EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm Unexecuted instantiation: _ZN5doris18insert_result_dataINS_12ColumnVectorILNS_13PrimitiveTypeE37EEEEEvRNS_3COWINS_7IColumnEE11mutable_ptrIS5_EERNS6_13immutable_ptrIS5_EEPKhPhm |
595 | | |
596 | | Status insert_result_data_bitmap(MutableColumnPtr& result_column, ColumnPtr& argument_column, |
597 | | const UInt8* __restrict null_map_data, |
598 | 0 | UInt8* __restrict filled_flag, const size_t input_rows_count) { |
599 | 0 | if (result_column->size() == 0 && input_rows_count) { |
600 | 0 | result_column->resize(input_rows_count); |
601 | 0 | } |
602 | |
|
603 | 0 | auto* __restrict result_raw_data = |
604 | 0 | reinterpret_cast<ColumnBitmap*>(result_column.get())->get_data().data(); |
605 | 0 | auto* __restrict column_raw_data = |
606 | 0 | reinterpret_cast<const ColumnBitmap*>(argument_column.get())->get_data().data(); |
607 | | |
608 | | // Here it's SIMD thought the compiler automatically also |
609 | | // true: null_map_data[row]==0 && filled_idx[row]==0 |
610 | | // if true, could filled current row data into result column |
611 | 0 | for (size_t row = 0; row < input_rows_count; ++row) { |
612 | 0 | if (!(null_map_data[row] | filled_flag[row])) { |
613 | 0 | result_raw_data[row] = column_raw_data[row]; |
614 | 0 | } |
615 | 0 | filled_flag[row] += (!(null_map_data[row] | filled_flag[row])); |
616 | 0 | } |
617 | 0 | return Status::OK(); |
618 | 0 | } |
619 | | |
620 | | Status filled_result_column(const DataTypePtr& data_type, MutableColumnPtr& result_column, |
621 | | ColumnPtr& argument_column, UInt8* __restrict null_map_data, |
622 | 0 | UInt8* __restrict filled_flag, const size_t input_rows_count) { |
623 | 0 | if (data_type->get_primitive_type() == TYPE_BITMAP) { |
624 | 0 | return insert_result_data_bitmap(result_column, argument_column, null_map_data, filled_flag, |
625 | 0 | input_rows_count); |
626 | 0 | } |
627 | | |
628 | 0 | auto call = [&](const auto& type) -> bool { |
629 | 0 | using DispatchType = std::decay_t<decltype(type)>; |
630 | 0 | insert_result_data<typename DispatchType::ColumnType>( |
631 | 0 | result_column, argument_column, null_map_data, filled_flag, input_rows_count); |
632 | 0 | return true; |
633 | 0 | }; Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE2EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE3EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE4EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE5EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE6EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE7EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE8EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE9EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE28EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE29EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE20EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE30EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE35EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE11EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE25EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE26EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE12EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE27EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE42EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE36EEEEEbRKT_ Unexecuted instantiation: vcondition_expr.cpp:_ZZN5doris20filled_result_columnERKSt10shared_ptrIKNS_9IDataTypeEERNS_3COWINS_7IColumnEE11mutable_ptrIS7_EERNS8_13immutable_ptrIS7_EEPhSF_mENK3$_0clINS_16DispatchDataTypeILNS_13PrimitiveTypeE37EEEEEbRKT_ |
634 | |
|
635 | 0 | if (!dispatch_switch_scalar(data_type->get_primitive_type(), call)) { |
636 | 0 | return Status::InternalError("not support type {} in coalesce", data_type->get_name()); |
637 | 0 | } |
638 | 0 | return Status::OK(); |
639 | 0 | } |
640 | | |
641 | | Status VectorizedCoalesceExpr::execute_column(VExprContext* context, const Block* block, |
642 | | Selector* selector, size_t count, |
643 | 0 | ColumnPtr& return_column) const { |
644 | 0 | DataTypePtr result_type = _data_type; |
645 | 0 | const auto input_rows_count = count; |
646 | |
|
647 | 0 | size_t remaining_rows = input_rows_count; |
648 | 0 | std::vector<uint32_t> record_idx( |
649 | 0 | input_rows_count, |
650 | 0 | 0); //used to save column idx, record the result data of each row from which column |
651 | 0 | std::vector<uint8_t> filled_flags( |
652 | 0 | input_rows_count, |
653 | 0 | 0); //used to save filled flag, in order to check current row whether have filled data |
654 | |
|
655 | 0 | MutableColumnPtr result_column; |
656 | 0 | if (!result_type->is_nullable()) { |
657 | 0 | result_column = result_type->create_column(); |
658 | 0 | } else { |
659 | 0 | result_column = remove_nullable(result_type)->create_column(); |
660 | 0 | } |
661 | | |
662 | | // because now follow below types does not support random position writing, |
663 | | // so insert into result data have two methods, one is for these types, one is for others type remaining |
664 | 0 | bool cannot_random_write = result_column->is_column_string() || |
665 | 0 | result_type->get_primitive_type() == PrimitiveType::TYPE_MAP || |
666 | 0 | result_type->get_primitive_type() == PrimitiveType::TYPE_STRUCT || |
667 | 0 | result_type->get_primitive_type() == PrimitiveType::TYPE_ARRAY || |
668 | 0 | result_type->get_primitive_type() == PrimitiveType::TYPE_JSONB; |
669 | 0 | if (cannot_random_write) { |
670 | 0 | result_column->reserve(input_rows_count); |
671 | 0 | } |
672 | |
|
673 | 0 | auto return_type = std::make_shared<DataTypeUInt8>(); |
674 | 0 | auto null_map = ColumnUInt8::create(input_rows_count, |
675 | 0 | 1); //if null_map_data==1, the current row should be null |
676 | 0 | auto* __restrict null_map_data = null_map->get_data().data(); |
677 | |
|
678 | 0 | auto is_not_null = [](const ColumnPtr& column, size_t size) -> ColumnUInt8::MutablePtr { |
679 | 0 | if (const auto* nullable = check_and_get_column<ColumnNullable>(*column)) { |
680 | | /// Return the negated null map. |
681 | 0 | auto res_column = ColumnUInt8::create(size); |
682 | 0 | const auto* __restrict src_data = nullable->get_null_map_data().data(); |
683 | 0 | auto* __restrict res_data = assert_cast<ColumnUInt8&>(*res_column).get_data().data(); |
684 | |
|
685 | 0 | for (size_t i = 0; i < size; ++i) { |
686 | 0 | res_data[i] = !src_data[i]; |
687 | 0 | } |
688 | 0 | return res_column; |
689 | 0 | } else { |
690 | | /// Since no element is nullable, return a constant one. |
691 | 0 | return ColumnUInt8::create(size, 1); |
692 | 0 | } |
693 | 0 | }; |
694 | |
|
695 | 0 | std::vector<ColumnPtr> original_columns(_children.size()); |
696 | 0 | std::vector<ColumnPtr> argument_not_null_columns(_children.size()); |
697 | |
|
698 | 0 | for (size_t i = 0; i < _children.size() && remaining_rows; ++i) { |
699 | | // Execute child expression to get the argument column. |
700 | 0 | RETURN_IF_ERROR( |
701 | 0 | _children[i]->execute_column(context, block, selector, count, original_columns[i])); |
702 | 0 | original_columns[i] = original_columns[i]->convert_to_full_column_if_const(); |
703 | 0 | argument_not_null_columns[i] = original_columns[i]; |
704 | 0 | if (const auto* nullable = |
705 | 0 | check_and_get_column<const ColumnNullable>(*argument_not_null_columns[i])) { |
706 | 0 | argument_not_null_columns[i] = nullable->get_nested_column_ptr(); |
707 | 0 | } |
708 | |
|
709 | 0 | auto res_column = is_not_null(original_columns[i], input_rows_count); |
710 | |
|
711 | 0 | auto& res_map = res_column->get_data(); |
712 | 0 | auto* __restrict res = res_map.data(); |
713 | | |
714 | | // Here it's SIMD thought the compiler automatically |
715 | | // true: res[j]==1 && null_map_data[j]==1, false: others |
716 | | // if true: remaining_rows--; record_idx[j]=column_idx; null_map_data[j]=0, so the current row could fill result |
717 | 0 | for (size_t j = 0; j < input_rows_count; ++j) { |
718 | 0 | remaining_rows -= (res[j] & null_map_data[j]); |
719 | 0 | record_idx[j] += (res[j] & null_map_data[j]) * i; |
720 | 0 | null_map_data[j] -= (res[j] & null_map_data[j]); |
721 | 0 | } |
722 | |
|
723 | 0 | if (remaining_rows == 0) { |
724 | | //check whether all result data from the same column |
725 | 0 | size_t is_same_column_count = 0; |
726 | 0 | const auto data = record_idx[0]; |
727 | 0 | for (size_t row = 0; row < input_rows_count; ++row) { |
728 | 0 | is_same_column_count += (record_idx[row] == data); |
729 | 0 | } |
730 | |
|
731 | 0 | if (is_same_column_count == input_rows_count) { |
732 | 0 | if (result_type->is_nullable()) { |
733 | 0 | return_column = make_nullable(argument_not_null_columns[i]); |
734 | 0 | } else { |
735 | 0 | return_column = argument_not_null_columns[i]; |
736 | 0 | } |
737 | 0 | return Status::OK(); |
738 | 0 | } |
739 | 0 | } |
740 | | |
741 | 0 | if (!cannot_random_write) { |
742 | | //if not string type, could check one column firstly, |
743 | | //and then fill the not null value in result column, |
744 | | //this method may result in higher CPU cache |
745 | 0 | RETURN_IF_ERROR(filled_result_column(result_type, result_column, |
746 | 0 | argument_not_null_columns[i], null_map_data, |
747 | 0 | filled_flags.data(), input_rows_count)); |
748 | 0 | } |
749 | 0 | } |
750 | | |
751 | 0 | if (cannot_random_write) { |
752 | | //if string type, should according to the record results, fill in result one by one, |
753 | 0 | for (size_t row = 0; row < input_rows_count; ++row) { |
754 | 0 | if (null_map_data[row]) { //should be null |
755 | 0 | result_column->insert_default(); |
756 | 0 | } else { |
757 | 0 | result_column->insert_from(*argument_not_null_columns[record_idx[row]].get(), row); |
758 | 0 | } |
759 | 0 | } |
760 | 0 | } |
761 | |
|
762 | 0 | if (result_type->is_nullable()) { |
763 | 0 | return_column = ColumnNullable::create(std::move(result_column), std::move(null_map)); |
764 | 0 | } else { |
765 | 0 | return_column = std::move(result_column); |
766 | 0 | } |
767 | |
|
768 | | DCHECK_EQ(return_column->size(), count); |
769 | 0 | return Status::OK(); |
770 | 0 | } |
771 | | |
772 | | } // namespace doris |