OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SegmentTree.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <algorithm>
20 #include <cmath>
21 #include <numeric>
22 #include <vector>
23 
24 #ifndef __CUDACC__
25 #include <sstream>
26 #endif
27 
28 #include "SegmentTreeUtils.h"
29 #include "Shared/checked_alloc.h"
30 #include "Shared/sqldefs.h"
31 #include "Shared/sqltypes.h"
32 
33 // A generic segment tree class that builds a segment tree of a given input_col_buf
34 // with a fan_out
35 // depending on what aggregation operator we use, it constructs internal node differently
36 // i.e., for sum aggregation, a parent node becomes a sum of "all" child elements
37 template <typename INPUT_TYPE, typename AGG_TYPE>
38 class SegmentTree {
39  public:
40  SegmentTree(std::vector<const int8_t*> const& input_col_bufs,
41  SQLTypeInfo const& input_col_ti,
42  int32_t const* original_input_col_idx_buf,
43  int64_t const* ordered_input_col_idx_buf,
44  int64_t num_elems,
45  SqlWindowFunctionKind agg_type,
46  size_t fan_out)
47  : input_col_buf_(!input_col_bufs.empty()
48  ? reinterpret_cast<const INPUT_TYPE*>(input_col_bufs.front())
49  : nullptr)
50  , cond_col_buf_(input_col_bufs.size() == 2 ? input_col_bufs[1] : nullptr)
51  , input_col_ti_(input_col_ti)
52  , original_input_col_idx_buf_(original_input_col_idx_buf)
53  , ordered_input_col_idx_buf_(ordered_input_col_idx_buf)
54  , num_elems_(num_elems)
55  , fan_out_(fan_out)
56  , agg_type_(agg_type)
59  , null_val_(inline_null_value<AGG_TYPE>())
61  ? std::numeric_limits<INPUT_TYPE>::max()
63  ? std::numeric_limits<INPUT_TYPE>::min()
64  : 0) {
65  CHECK_GT(num_elems_, (int64_t)0);
66  auto max_tree_height_and_leaf_range = findMaxTreeHeight(num_elems_, fan_out_);
67  leaf_depth_ = max_tree_height_and_leaf_range.first;
68  leaf_range_ = max_tree_height_and_leaf_range.second;
69  // the index of the last elem of the leaf level is the same as the tree's size
70  tree_size_ = leaf_range_.second;
71  leaf_size_ = leaf_range_.second - leaf_range_.first;
72  // for derived aggregate, we maintain both "sum" aggregates and element counts
73  // to compute the value correctly
78  } else {
79  // we can use an array as a segment tree for the rest of aggregates
81  reinterpret_cast<AGG_TYPE*>(checked_malloc(tree_size_ * sizeof(AGG_TYPE)));
82  switch (agg_type_) {
84  buildForCount(0, 0);
85  break;
88  break;
89  default: {
90  if (is_conditional_agg_) {
91  buildForCondAgg(0, 0);
92  } else {
93  build(0, 0);
94  }
95  }
96  }
97  }
98  }
99 
101  if (num_elems_ > 0) {
103  free(derived_aggregated_);
104  } else {
105  free(aggregated_values_);
106  }
107  }
108  }
109 
110  // try to aggregate values of the given query range
111  AGG_TYPE query(const IndexPair& query_range) const {
112  if (query_range.first > query_range.second || query_range.first < 0 ||
113  query_range.second > leaf_size_) {
114  return null_val_;
115  }
116  // todo (yoonmin) : support more derived aggregate functions
118  SumAndCountPair<AGG_TYPE> sum_and_count_pair =
119  searchForDerivedAggregate(query_range, 0, 0, 0, leaf_size_);
120  if (sum_and_count_pair.sum == null_val_) {
121  return null_val_;
122  } else if (sum_and_count_pair.count == 0) {
123  return 0;
124  } else {
125  if (input_col_ti_.is_decimal()) {
126  return (static_cast<double>(sum_and_count_pair.sum) /
127  pow(10, input_col_ti_.get_scale())) /
128  sum_and_count_pair.count;
129  } else {
130  return sum_and_count_pair.sum / sum_and_count_pair.count;
131  }
132  }
133  } else {
134  const auto res = search(query_range, 0, 0, 0, leaf_size_);
135  if (res == null_val_) {
136  switch (agg_type_) {
139  return input_type_null_val_;
140  default:
141  return null_val_;
142  }
143  }
144  return res;
145  }
146  }
147 
148  AGG_TYPE* getAggregatedValues() const { return aggregated_values_; }
149 
151  return derived_aggregated_;
152  }
153 
154  size_t getLeafSize() const { return leaf_size_; }
155 
156  size_t getTreeSize() const { return tree_size_; }
157 
158  size_t getNumElems() const { return num_elems_; }
159 
160  size_t getLeafDepth() const { return leaf_depth_; }
161 
162  size_t getTreeFanout() const { return fan_out_; }
163 
164  IndexPair getLeafRange() const { return leaf_range_; }
165 
166  private:
167  // build a segment tree for a given aggregate function recursively
168  inline AGG_TYPE fetch_col_for_count(size_t const idx) {
170  }
171 
172  inline AGG_TYPE fetch_col_for_non_cond_agg(size_t const idx) {
173  auto const col_val = input_col_buf_[idx];
174  return col_val != input_type_null_val_ ? col_val : null_val_;
175  }
176 
177  inline AGG_TYPE fetch_col_for_cond_agg(size_t const idx) {
178  AGG_TYPE res{null_val_};
179  if (cond_col_buf_[idx] == 1) {
180  auto const col_val = input_col_buf_[idx];
181  res = col_val != input_type_null_val_ ? col_val : null_val_;
182  }
183  return res;
184  }
185 
186  AGG_TYPE build(int64_t cur_node_idx, size_t cur_node_depth) {
187  if (cur_node_idx >= leaf_range_.first && cur_node_idx < leaf_range_.second) {
188  // arrive at leaf level, so try to put a corresponding input column value
189  int64_t input_col_idx = cur_node_idx - leaf_range_.first;
190  if (input_col_idx >= num_elems_) {
191  // fill an invalid value
192  aggregated_values_[cur_node_idx] = invalid_val_;
193  return invalid_val_;
194  }
195  // try to get the current row's column value
196  const auto input_col_idx_ordered = ordered_input_col_idx_buf_[input_col_idx];
197  const auto refined_input_col_idx =
198  original_input_col_idx_buf_[input_col_idx_ordered];
199  aggregated_values_[cur_node_idx] =
200  fetch_col_for_non_cond_agg(refined_input_col_idx);
201  // return the current value to fill a parent node
202  return aggregated_values_[cur_node_idx];
203  }
204 
205  // when reaching here, we need to take care of a node having child nodes,
206  // and we compute an aggregated value from its child nodes
207  std::vector<AGG_TYPE> child_vals =
208  prepareChildValuesforAggregation(cur_node_idx, cur_node_depth);
209 
210  // compute the new aggregated value
211  aggregated_values_[cur_node_idx] = aggregateValue(child_vals);
212 
213  // return the value for the upper-level aggregation
214  return aggregated_values_[cur_node_idx];
215  }
216 
217  AGG_TYPE buildForCondAgg(int64_t cur_node_idx, size_t cur_node_depth) {
218  if (cur_node_idx >= leaf_range_.first && cur_node_idx < leaf_range_.second) {
219  // arrive at leaf level, so try to put a corresponding input column value
220  int64_t input_col_idx = cur_node_idx - leaf_range_.first;
221  if (input_col_idx >= num_elems_) {
222  // fill an invalid value
223  aggregated_values_[cur_node_idx] = invalid_val_;
224  return invalid_val_;
225  }
226  // try to get the current row's column value
227  const auto input_col_idx_ordered = ordered_input_col_idx_buf_[input_col_idx];
228  const auto refined_input_col_idx =
229  original_input_col_idx_buf_[input_col_idx_ordered];
230  aggregated_values_[cur_node_idx] = fetch_col_for_cond_agg(refined_input_col_idx);
231  // return the current value to fill a parent node
232  return aggregated_values_[cur_node_idx];
233  }
234 
235  // when reaching here, we need to take care of a node having child nodes,
236  // and we compute an aggregated value from its child nodes
237  std::vector<AGG_TYPE> child_vals =
238  prepareChildValuesforConditionalAggregation(cur_node_idx, cur_node_depth);
239 
240  // compute the new aggregated value
241  aggregated_values_[cur_node_idx] = aggregateValue(child_vals);
242 
243  // return the value for the upper-level aggregation
244  return aggregated_values_[cur_node_idx];
245  }
246 
247  AGG_TYPE buildForCount(int64_t cur_node_idx, size_t cur_node_depth) {
248  if (cur_node_idx >= leaf_range_.first && cur_node_idx <= leaf_range_.second) {
249  // arrive at leafs, so try to put a corresponding input column value
250  int64_t input_col_idx = cur_node_idx - leaf_range_.first;
251  if (input_col_idx >= num_elems_) {
252  // fill an invalid value
253  aggregated_values_[cur_node_idx] = invalid_val_;
254  return invalid_val_;
255  }
256  // try to get the current row's column value
257  const auto input_col_idx_ordered = ordered_input_col_idx_buf_[input_col_idx];
258  const auto refined_input_col_idx =
259  original_input_col_idx_buf_[input_col_idx_ordered];
260  aggregated_values_[cur_node_idx] = fetch_col_for_count(refined_input_col_idx);
261  // return the current value to fill a parent node
262  return aggregated_values_[cur_node_idx];
263  }
264 
265  // when reaching here, we need to take care of a node having child nodes,
266  // and we compute an aggregated value from its child nodes
267  std::vector<AGG_TYPE> child_vals =
268  prepareChildValuesforAggregationForCount(cur_node_idx, cur_node_depth);
269 
270  // compute the new aggregated value
271  aggregated_values_[cur_node_idx] = aggregateValue(child_vals);
272 
273  // return the value for the upper-level aggregation
274  return aggregated_values_[cur_node_idx];
275  }
276 
277  AGG_TYPE buildForConditionalChangeEvent(int64_t cur_node_idx, size_t cur_node_depth) {
278  if (cur_node_idx >= leaf_range_.first && cur_node_idx <= leaf_range_.second) {
279  int64_t input_col_idx = cur_node_idx - leaf_range_.first;
280  if (input_col_idx >= num_elems_) {
281  aggregated_values_[cur_node_idx] = invalid_val_;
282  return invalid_val_;
283  }
284  auto cur_row_idx =
286  if (input_col_idx == 0) {
287  aggregated_values_[cur_node_idx] = 0;
288  } else {
289  auto prev_row_idx =
290  original_input_col_idx_buf_[ordered_input_col_idx_buf_[input_col_idx - 1]];
291  auto const col_val = input_col_buf_[cur_row_idx];
292  auto const prev_col_val = input_col_buf_[prev_row_idx];
293  aggregated_values_[cur_node_idx] =
294  col_val != input_type_null_val_ && prev_col_val != input_type_null_val_
295  ? col_val != prev_col_val
296  : 0;
297  }
298  return aggregated_values_[cur_node_idx];
299  }
300 
301  // when reaching here, we need to take care of a node having child nodes,
302  // and we compute an aggregated value from its child nodes
303  std::vector<AGG_TYPE> child_vals =
305  cur_node_depth);
306 
307  // compute the new aggregated value
308  aggregated_values_[cur_node_idx] = aggregateValue(child_vals);
309 
310  // return the value for the upper-level aggregation
311  return aggregated_values_[cur_node_idx];
312  }
313 
314  // the logic is exactly the same as normal aggregate case, but has a different
315  // node type: SumAndCountPair
317  size_t cur_node_depth) {
318  if (cur_node_idx >= leaf_range_.first && cur_node_idx <= leaf_range_.second) {
319  int64_t input_col_idx = cur_node_idx - leaf_range_.first;
320  if (input_col_idx >= num_elems_) {
321  derived_aggregated_[cur_node_idx] = {invalid_val_, 0};
322  } else {
323  const auto input_col_idx_ordered = ordered_input_col_idx_buf_[input_col_idx];
324  const auto refined_input_col_idx =
325  original_input_col_idx_buf_[input_col_idx_ordered];
326  auto col_val = input_col_buf_[refined_input_col_idx];
327  if (col_val != input_type_null_val_) {
328  derived_aggregated_[cur_node_idx] = {col_val, 1};
329  } else {
330  derived_aggregated_[cur_node_idx] = {null_val_, 0};
331  }
332  }
333  return derived_aggregated_[cur_node_idx];
334  }
335 
336  std::vector<SumAndCountPair<AGG_TYPE>> child_vals =
337  prepareChildValuesforDerivedAggregate(cur_node_idx, cur_node_depth);
338 
339  derived_aggregated_[cur_node_idx] = aggregateValueForDerivedAggregate(child_vals);
340  return derived_aggregated_[cur_node_idx];
341  }
342 
343  // gather aggregated values of each child node
344  std::vector<AGG_TYPE> prepareChildValuesforAggregation(int64_t parent_idx,
345  size_t cur_node_depth) {
346  std::vector<AGG_TYPE> child_vals(fan_out_);
347  int64_t const offset = cur_node_depth ? parent_idx * fan_out_ + 1 : 1;
348  size_t const next_node_depth = cur_node_depth + 1;
349  for (size_t i = 0; i < fan_out_; ++i) {
350  child_vals[i] = build(offset + i, next_node_depth);
351  }
352  return child_vals;
353  }
354 
355  // gather aggregated values of each child node
357  int64_t parent_idx,
358  size_t cur_node_depth) {
359  std::vector<AGG_TYPE> child_vals(fan_out_);
360  int64_t const offset = cur_node_depth ? parent_idx * fan_out_ + 1 : 1;
361  size_t const next_node_depth = cur_node_depth + 1;
362  for (size_t i = 0; i < fan_out_; ++i) {
363  child_vals[i] = buildForCondAgg(offset + i, next_node_depth);
364  }
365  return child_vals;
366  }
367 
368  // gather aggregated values of each child node
369  std::vector<AGG_TYPE> prepareChildValuesforAggregationForCount(int64_t parent_idx,
370  size_t cur_node_depth) {
371  std::vector<AGG_TYPE> child_vals(fan_out_);
372  int64_t const offset = cur_node_depth ? parent_idx * fan_out_ + 1 : 1;
373  size_t const next_node_depth = cur_node_depth + 1;
374  for (size_t i = 0; i < fan_out_; ++i) {
375  child_vals[i] = buildForCount(offset + i, next_node_depth);
376  }
377  return child_vals;
378  }
379 
380  // gather aggregated values of each child node
382  int64_t const parent_idx,
383  size_t const cur_node_depth) {
384  std::vector<AGG_TYPE> child_vals(fan_out_);
385  int64_t const offset = cur_node_depth ? parent_idx * fan_out_ + 1 : 1;
386  size_t const next_node_depth = cur_node_depth + 1;
387  for (size_t i = 0; i < fan_out_; ++i) {
388  child_vals[i] = buildForConditionalChangeEvent(offset + i, next_node_depth);
389  }
390  return child_vals;
391  }
392 
393  std::vector<SumAndCountPair<AGG_TYPE>> prepareChildValuesforDerivedAggregate(
394  int64_t parent_idx,
395  size_t cur_node_depth) {
396  std::vector<SumAndCountPair<AGG_TYPE>> child_vals(fan_out_);
397  int64_t const offset = cur_node_depth ? parent_idx * fan_out_ + 1 : 1;
398  size_t const next_node_depth = cur_node_depth + 1;
399  for (size_t i = 0; i < fan_out_; ++i) {
400  child_vals[i] = buildForDerivedAggregate(offset + i, next_node_depth);
401  }
402  return child_vals;
403  }
404 
405  // compute aggregated value of the given values depending on the aggregate function
406  AGG_TYPE aggregateValue(const std::vector<AGG_TYPE>& vals) const {
407  // todo (yoonmin) : optimize logic for a non-null column
408  bool all_nulls = true;
410  AGG_TYPE min_val = std::numeric_limits<AGG_TYPE>::max();
411  std::for_each(
412  vals.begin(), vals.end(), [&min_val, &all_nulls, this](const AGG_TYPE val) {
413  if (val != null_val_ && val != invalid_val_) {
414  all_nulls = false;
415  min_val = std::min(min_val, val);
416  }
417  });
418  if (all_nulls) {
419  min_val = null_val_;
420  }
421  return min_val;
422  } else if (agg_type_ == SqlWindowFunctionKind::MAX) {
423  AGG_TYPE max_val = std::numeric_limits<AGG_TYPE>::min();
424  std::for_each(
425  vals.begin(), vals.end(), [&max_val, &all_nulls, this](const AGG_TYPE val) {
426  if (val != null_val_ && val != invalid_val_) {
427  all_nulls = false;
428  max_val = std::max(max_val, val);
429  }
430  });
431  if (all_nulls) {
432  max_val = null_val_;
433  }
434  return max_val;
435  } else {
436  AGG_TYPE agg_val = 0;
437  std::for_each(
438  vals.begin(), vals.end(), [&agg_val, &all_nulls, this](const AGG_TYPE val) {
439  if (val != null_val_) {
440  agg_val += val;
441  all_nulls = false;
442  }
443  });
444  if (all_nulls) {
445  agg_val = null_val_;
446  }
447  return agg_val;
448  }
449  }
450 
451  AGG_TYPE aggregateValueViaColumnAccess(int64_t cur_col_idx, size_t num_visits) const {
452  // todo (yoonmin) : optimize logic for a non-null column
453  bool all_nulls = true;
454  auto end_idx = cur_col_idx + num_visits;
456  AGG_TYPE min_val = std::numeric_limits<AGG_TYPE>::max();
457  for (size_t i = cur_col_idx; i < end_idx; ++i) {
458  AGG_TYPE val = aggregated_values_[i];
459  if (val != null_val_ && val != invalid_val_) {
460  all_nulls = false;
461  min_val = std::min(min_val, val);
462  }
463  }
464  if (all_nulls) {
465  min_val = null_val_;
466  }
467  return min_val;
468  } else if (agg_type_ == SqlWindowFunctionKind::MAX) {
469  AGG_TYPE max_val = std::numeric_limits<AGG_TYPE>::min();
470  for (size_t i = cur_col_idx; i < end_idx; ++i) {
471  AGG_TYPE val = aggregated_values_[i];
472  if (val != null_val_ && val != invalid_val_) {
473  all_nulls = false;
474  max_val = std::max(max_val, val);
475  }
476  }
477  if (all_nulls) {
478  max_val = null_val_;
479  }
480  return max_val;
481  } else {
482  AGG_TYPE agg_val = 0;
483  for (size_t i = cur_col_idx; i < end_idx; ++i) {
484  AGG_TYPE val = aggregated_values_[i];
485  if (val != null_val_) {
486  agg_val += val;
487  all_nulls = false;
488  }
489  }
490  if (all_nulls) {
491  agg_val = null_val_;
492  }
493  return agg_val;
494  }
495  }
496 
498  const std::vector<SumAndCountPair<AGG_TYPE>>& vals) const {
500  bool all_nulls = true;
501  std::for_each(vals.begin(),
502  vals.end(),
503  [&res, &all_nulls, this](const SumAndCountPair<AGG_TYPE>& pair) {
504  if (pair.sum != null_val_ && pair.sum != invalid_val_) {
505  res.sum += pair.sum;
506  res.count += pair.count;
507  all_nulls = false;
508  }
509  });
510  if (all_nulls) {
511  return {null_val_, 0};
512  }
513  return res;
514  }
515 
517  int64_t cur_col_idx,
518  size_t num_visits) const {
520  bool all_nulls = true;
521  auto end_idx = cur_col_idx + num_visits;
522  for (size_t i = cur_col_idx; i < end_idx; ++i) {
523  const SumAndCountPair<AGG_TYPE> cur_pair_val = aggregated_values_[i];
524  if (cur_pair_val.sum != null_val_) {
525  res.sum += cur_pair_val.sum;
526  res.count += cur_pair_val.count;
527  all_nulls = false;
528  }
529  }
530  if (all_nulls) {
531  return {null_val_, 0};
532  }
533  return res;
534  }
535 
536  // search an aggregated value of the given query range
537  // by visiting necessary nodes of the segment tree including leafs
538  AGG_TYPE search(const IndexPair& query_range,
539  int64_t cur_node_idx,
540  size_t cur_node_depth,
541  int64_t search_range_start_idx,
542  int64_t search_range_end_idx) const {
543  if (num_elems_ <= 0) {
544  return null_val_;
545  }
546  if (search_range_end_idx < query_range.first ||
547  query_range.second < search_range_start_idx) {
548  // completely out-of-bound
549  return invalid_val_;
550  } else if (query_range.first <= search_range_start_idx &&
551  search_range_end_idx <= query_range.second) {
552  // perfectly fitted in a range of the current node
553  return aggregated_values_[cur_node_idx];
554  } else {
555  // this node is partially within left and right indexes
556  if (cur_node_depth == leaf_depth_) {
557  // we already reach the leaf level, so do not need to proceed to the next level
558  // and so aggregate the value in the range by using a simple loop
559  size_t num_visits = query_range.second - search_range_start_idx + 1;
561  cur_node_idx, num_visits, null_val_, invalid_val_);
562  } else {
563  // find aggregated value from child nodes
564  int64_t pivot_idx = search_range_start_idx +
565  ((search_range_end_idx - search_range_start_idx) / fan_out_);
566  int64_t child_search_start_idx = search_range_start_idx;
567  int64_t child_search_end_idx = pivot_idx;
568  std::vector<size_t> child_indexes(fan_out_);
569  computeChildIndexes(child_indexes, cur_node_idx, cur_node_depth);
570  std::vector<AGG_TYPE> child_vals(fan_out_);
571  for (size_t i = 0; i < child_indexes.size(); ++i) {
572  child_vals[i] = search(query_range,
573  child_indexes[i],
574  cur_node_depth + 1,
575  child_search_start_idx,
576  child_search_end_idx);
577  child_search_start_idx = child_search_end_idx + 1;
578  child_search_end_idx = child_search_start_idx + pivot_idx;
579  if (child_search_end_idx > search_range_end_idx) {
580  child_search_end_idx = search_range_end_idx;
581  }
582  }
583  return aggregateValue(child_vals);
584  }
585  }
586  }
587 
589  const IndexPair& query_range,
590  int64_t cur_node_idx,
591  size_t cur_node_depth,
592  int64_t search_range_start_idx,
593  int64_t search_range_end_idx) const {
594  if (search_range_end_idx < query_range.first ||
595  query_range.second < search_range_start_idx) {
596  return {invalid_val_, 0};
597  } else if (query_range.first <= search_range_start_idx &&
598  search_range_end_idx <= query_range.second) {
599  return derived_aggregated_[cur_node_idx];
600  } else {
601  if (cur_node_depth == leaf_depth_) {
602  size_t num_visits = query_range.second - search_range_start_idx + 1;
604  cur_node_idx, num_visits, null_val_, invalid_val_);
605  } else {
606  // find aggregated value from child nodes
607  std::vector<int64_t> child_indexes(fan_out_);
608  computeChildIndexes(child_indexes, cur_node_idx, cur_node_depth);
609  std::vector<SumAndCountPair<AGG_TYPE>> child_vals(fan_out_, {invalid_val_, 0});
610  int64_t pivot_idx = search_range_start_idx +
611  ((search_range_end_idx - search_range_start_idx) / fan_out_);
612  int64_t child_search_start_idx = search_range_start_idx;
613  int64_t child_search_end_idx = pivot_idx;
614  for (size_t i = 0; i < child_indexes.size(); ++i) {
615  child_vals[i] = searchForDerivedAggregate(query_range,
616  child_indexes[i],
617  cur_node_depth + 1,
618  child_search_start_idx,
619  child_search_end_idx);
620  child_search_start_idx = child_search_end_idx + 1;
621  child_search_end_idx = child_search_start_idx + pivot_idx;
622  if (child_search_end_idx > search_range_end_idx) {
623  child_search_end_idx = search_range_end_idx;
624  }
625  }
626  return aggregateValueForDerivedAggregate(child_vals);
627  }
628  }
629  }
630 
631  // for prepareChildValuesForAggregate function includes the logic of the
632  // `computeChildIndexes` function internally to reduce # creation of the temporary
633  // vector while building a segment tree, but keep it to use it for `search` function
634  std::vector<int64_t> computeChildIndexes(std::vector<int64_t>& child_indexes,
635  int64_t parent_idx,
636  size_t parent_tree_depth) const {
637  if (parent_tree_depth == 0) {
638  for (size_t i = 0; i < fan_out_; ++i) {
639  child_indexes[i] = i + 1;
640  }
641  } else {
642  int64_t cur_depth_start_offset = parent_idx * fan_out_ + 1;
643  for (size_t i = 0; i < fan_out_; ++i) {
644  child_indexes[i] = cur_depth_start_offset + i;
645  }
646  }
647  return child_indexes;
648  }
649 
650  // a utility function that computes a length and the start node index of a segment tree
651  // to contain 'num_elem' with a given 'fan_out'
652  std::pair<size_t, IndexPair> findMaxTreeHeight(int64_t num_elem, int fan_out) {
653  if (num_elem <= 0) {
654  return std::make_pair(0, std::make_pair(0, 0));
655  }
656  int64_t cur_level_start_offset = 0;
657  size_t depth = 0;
658  IndexPair index_pair = std::make_pair(0, 0);
659  while (true) {
660  size_t maximum_node_at_next_level = pow(fan_out, depth);
661  if (num_elem < maximum_node_at_next_level) {
662  index_pair = std::make_pair(cur_level_start_offset,
663  cur_level_start_offset + maximum_node_at_next_level);
664  return std::make_pair(depth, index_pair);
665  }
666  depth++;
667  cur_level_start_offset += maximum_node_at_next_level;
668  }
669  }
670 
671  // agg input column buffer and its type info
672  const INPUT_TYPE* const input_col_buf_;
673  // to deal with conditional aggregate function
674  const int8_t* const cond_col_buf_;
676  // the following two idx buffers are for accessing the sorted input column
677  // based on our current window function context (i.e., indirect column access)
678  // i-th row -> get indirect idx 'i_idx' from `ordered_input_col_idx_buf_`
679  // and use `i_idx` to get the true row index `t_idx` from `original_input_col_idx_buf_`
680  // and use `t_idx` to get i-th row of the sorted column
681  // otherwise, we can access the column when it keeps sorted values
682  // original index (i.e., row_id) to access input_col_buf
683  const int32_t* const original_input_col_idx_buf_;
684  // ordered index to access sorted input_col_buf
685  const int64_t* const ordered_input_col_idx_buf_;
686  // # input elements
687  int64_t const num_elems_;
688  // tree fanout
689  size_t const fan_out_;
690  // a type of aggregate function
693  INPUT_TYPE const input_type_null_val_;
694  AGG_TYPE const null_val_;
695  // invalid_val is required to fill an empty node for a correct aggregation
696  INPUT_TYPE const invalid_val_;
697  // # nodes in the leaf level
698  size_t leaf_size_;
699  // level of the leaf
700  size_t leaf_depth_;
701  // start ~ end indexes of the leaf level
703  // total number of nodes in the tree
704  size_t tree_size_;
705  // depending on aggregate function, we use different aggregation logic
706  // 1) a segment tree for computing derived aggregates, i.e., avg and stddev
708  // 2) rest of aggregate functions can use a vector of elements
710 };
const int64_t *const ordered_input_col_idx_buf_
Definition: SegmentTree.h:685
AGG_TYPE aggregateValueViaColumnAccess(int64_t cur_col_idx, size_t num_visits) const
Definition: SegmentTree.h:451
SumAndCountPair< AGG_TYPE > * derived_aggregated_
Definition: SegmentTree.h:707
IndexPair getLeafRange() const
Definition: SegmentTree.h:164
SQLTypeInfo const input_col_ti_
Definition: SegmentTree.h:675
size_t const fan_out_
Definition: SegmentTree.h:689
size_t getLeafDepth() const
Definition: SegmentTree.h:160
const INPUT_TYPE *const input_col_buf_
Definition: SegmentTree.h:672
HOST DEVICE int get_scale() const
Definition: sqltypes.h:396
std::vector< AGG_TYPE > prepareChildValuesforConditionalAggregation(int64_t parent_idx, size_t cur_node_depth)
Definition: SegmentTree.h:356
size_t getTreeSize() const
Definition: SegmentTree.h:156
AGG_TYPE buildForConditionalChangeEvent(int64_t cur_node_idx, size_t cur_node_depth)
Definition: SegmentTree.h:277
size_t getLeafSize() const
Definition: SegmentTree.h:154
AGG_TYPE search(const IndexPair &query_range, int64_t cur_node_idx, size_t cur_node_depth, int64_t search_range_start_idx, int64_t search_range_end_idx) const
Definition: SegmentTree.h:538
Constants for Builtin SQL Types supported by HEAVY.AI.
SumAndCountPair< AGG_TYPE > buildForDerivedAggregate(int64_t cur_node_idx, size_t cur_node_depth)
Definition: SegmentTree.h:316
size_t leaf_size_
Definition: SegmentTree.h:698
#define CHECK_GT(x, y)
Definition: Logger.h:305
AGG_TYPE buildForCount(int64_t cur_node_idx, size_t cur_node_depth)
Definition: SegmentTree.h:247
size_t getTreeFanout() const
Definition: SegmentTree.h:162
bool const is_conditional_agg_
Definition: SegmentTree.h:692
AGG_TYPE fetch_col_for_non_cond_agg(size_t const idx)
Definition: SegmentTree.h:172
std::vector< int64_t > computeChildIndexes(std::vector< int64_t > &child_indexes, int64_t parent_idx, size_t parent_tree_depth) const
Definition: SegmentTree.h:634
SumAndCountPair< AGG_TYPE > searchForDerivedAggregate(const IndexPair &query_range, int64_t cur_node_idx, size_t cur_node_depth, int64_t search_range_start_idx, int64_t search_range_end_idx) const
Definition: SegmentTree.h:588
SegmentTree(std::vector< const int8_t * > const &input_col_bufs, SQLTypeInfo const &input_col_ti, int32_t const *original_input_col_idx_buf, int64_t const *ordered_input_col_idx_buf, int64_t num_elems, SqlWindowFunctionKind agg_type, size_t fan_out)
Definition: SegmentTree.h:40
DEVICE TextEncodingDict inline_null_value()
Definition: heavydbTypes.h:279
size_t getNumElems() const
Definition: SegmentTree.h:158
void * checked_malloc(const size_t size)
Definition: checked_alloc.h:45
SumAndCountPair< AGG_TYPE > aggregateValueForDerivedAggregateViaColumnAccess(int64_t cur_col_idx, size_t num_visits) const
Definition: SegmentTree.h:516
AGG_TYPE buildForCondAgg(int64_t cur_node_idx, size_t cur_node_depth)
Definition: SegmentTree.h:217
SumAndCountPair< AGG_TYPE > aggregateValueForDerivedAggregate(const std::vector< SumAndCountPair< AGG_TYPE >> &vals) const
Definition: SegmentTree.h:497
AGG_TYPE query(const IndexPair &query_range) const
Definition: SegmentTree.h:111
std::pair< int64_t, int64_t > IndexPair
AGG_TYPE * getAggregatedValues() const
Definition: SegmentTree.h:148
INPUT_TYPE const input_type_null_val_
Definition: SegmentTree.h:693
std::vector< SumAndCountPair< AGG_TYPE > > prepareChildValuesforDerivedAggregate(int64_t parent_idx, size_t cur_node_depth)
Definition: SegmentTree.h:393
size_t tree_size_
Definition: SegmentTree.h:704
const int32_t *const original_input_col_idx_buf_
Definition: SegmentTree.h:683
AGG_TYPE const null_val_
Definition: SegmentTree.h:694
std::vector< AGG_TYPE > prepareChildValuesforAggregation(int64_t parent_idx, size_t cur_node_depth)
Definition: SegmentTree.h:344
SqlWindowFunctionKind
Definition: sqldefs.h:129
AGG_TYPE fetch_col_for_cond_agg(size_t const idx)
Definition: SegmentTree.h:177
SqlWindowFunctionKind const agg_type_
Definition: SegmentTree.h:691
AGG_TYPE fetch_col_for_count(size_t const idx)
Definition: SegmentTree.h:168
AGG_TYPE build(int64_t cur_node_idx, size_t cur_node_depth)
Definition: SegmentTree.h:186
Common Enum definitions for SQL processing.
std::pair< size_t, IndexPair > findMaxTreeHeight(int64_t num_elem, int fan_out)
Definition: SegmentTree.h:652
SumAndCountPair< AGG_TYPE > * getDerivedAggregatedValues() const
Definition: SegmentTree.h:150
IndexPair leaf_range_
Definition: SegmentTree.h:702
AGG_TYPE aggregateValue(const std::vector< AGG_TYPE > &vals) const
Definition: SegmentTree.h:406
const int8_t *const cond_col_buf_
Definition: SegmentTree.h:674
bool is_decimal() const
Definition: sqltypes.h:570
std::vector< AGG_TYPE > prepareChildValuesforAggregationForCount(int64_t parent_idx, size_t cur_node_depth)
Definition: SegmentTree.h:369
AGG_TYPE * aggregated_values_
Definition: SegmentTree.h:709
size_t leaf_depth_
Definition: SegmentTree.h:700
INPUT_TYPE const invalid_val_
Definition: SegmentTree.h:696
int64_t const num_elems_
Definition: SegmentTree.h:687
std::vector< AGG_TYPE > prepareChildValuesforAggregationForConditionalChangeEvent(int64_t const parent_idx, size_t const cur_node_depth)
Definition: SegmentTree.h:381