OmniSciDB  c1a53651b2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
WindowFunctionIR.cpp
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 #include "CodeGenerator.h"
18 #include "Execute.h"
19 #include "WindowContext.h"
20 
21 llvm::Value* Executor::codegenWindowFunction(const size_t target_index,
22  const CompilationOptions& co) {
23  AUTOMATIC_IR_METADATA(cgen_state_.get());
24  CodeGenerator code_generator(this);
25 
26  const auto window_func_context =
28  target_index);
29  const auto window_func = window_func_context->getWindowFunction();
30  switch (window_func->getKind()) {
35  // they are always evaluated on the entire partition
36  return code_generator.codegenWindowPosition(window_func_context,
37  code_generator.posArg(nullptr));
38  }
41  // they are always evaluated on the entire partition
42  return cgen_state_->emitCall("percent_window_func",
43  {cgen_state_->llInt(reinterpret_cast<const int64_t>(
44  window_func_context->output())),
45  code_generator.posArg(nullptr)});
46  }
52  // they are always evaluated on the current frame
54  const auto& args = window_func->getArgs();
55  CHECK(!args.empty());
56  const auto arg_lvs = code_generator.codegen(args.front().get(), true, co);
57  CHECK_EQ(arg_lvs.size(), size_t(1));
58  return arg_lvs.front();
59  }
67  // they are always evaluated on the current frame
68  return codegenWindowFunctionAggregate(co);
69  }
73  return codegenWindowNavigationFunctionOnFrame(co);
74  }
75  default: {
76  LOG(FATAL) << "Invalid window function kind";
77  }
78  }
79  return nullptr;
80 }
81 
82 namespace {
83 
85  const SQLTypeInfo& window_func_ti) {
86  std::string agg_name;
87  switch (kind) {
89  agg_name = "agg_min";
90  break;
91  }
93  agg_name = "agg_max";
94  break;
95  }
98  agg_name = "agg_sum";
99  break;
100  }
102  agg_name = "agg_count";
103  break;
104  }
106  agg_name = "agg_count_if";
107  break;
108  }
110  agg_name = "agg_sum_if";
111  break;
112  }
113  default: {
114  LOG(FATAL) << "Invalid window function kind";
115  }
116  }
117  switch (window_func_ti.get_type()) {
118  case kFLOAT: {
119  agg_name += "_float";
120  break;
121  }
122  case kDOUBLE: {
123  agg_name += "_double";
124  break;
125  }
126  default: {
127  break;
128  }
129  }
130  return agg_name;
131 }
132 
134  const auto& args = window_func->getArgs();
135  return ((window_func->getKind() == SqlWindowFunctionKind::COUNT && !args.empty()) ||
136  window_func->getKind() == SqlWindowFunctionKind::AVG)
137  ? args.front()->get_type_info()
138  : window_func->get_type_info();
139 }
140 
141 std::string get_col_type_name_by_size(const size_t size, const bool is_fp) {
142  if (is_fp) {
143  if (size == 4) {
144  return "float";
145  }
146  return "double";
147  }
148  if (size == 1) {
149  return "int8_t";
150  } else if (size == 2) {
151  return "int16_t";
152  } else if (size == 4) {
153  return "int32_t";
154  }
155  return "int64_t";
156 }
157 
158 llvm::Value* get_null_value_by_size(CgenState* cgen_state, SQLTypeInfo col_ti) {
159  if (col_ti.is_fp()) {
160  if (col_ti.get_type() == kFLOAT) {
161  return cgen_state->llFp(inline_fp_null_value<float>());
162  } else {
163  return cgen_state->llFp(inline_fp_null_value<double>());
164  }
165  } else if (col_ti.is_dict_encoded_string()) {
166  if (col_ti.get_size() == 2) {
167  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
168  } else {
169  CHECK_EQ(col_ti.get_size(), 4);
170  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
171  }
172  } else {
173  switch (col_ti.get_type()) {
174  case kBOOLEAN:
175  case kTINYINT:
176  return cgen_state->llInt((int8_t)inline_int_null_value<int8_t>());
177  case kSMALLINT:
178  return cgen_state->llInt((int16_t)inline_int_null_value<int16_t>());
179  case kINT:
180  return cgen_state->llInt((int32_t)inline_int_null_value<int32_t>());
181  case kTIME:
182  case kTIMESTAMP:
183  if (col_ti.get_compression() == kENCODING_FIXED) {
184  return cgen_state->llInt((int64_t)(inline_fixed_encoding_null_val(col_ti)));
185  }
186  case kBIGINT:
187  case kDATE:
188  case kINTERVAL_DAY_TIME:
190  case kDECIMAL:
191  case kNUMERIC:
192  return cgen_state->llInt((int64_t)inline_int_null_value<int64_t>());
193  default:
194  abort();
195  }
196  return cgen_state->llInt(inline_int_null_val(col_ti));
197  }
198 }
199 
201  SQLTypeInfo col_ti) {
202  if (col_ti.is_fp()) {
203  if (col_ti.get_type() == kFLOAT) {
204  return cgen_state->llFp(inline_fp_null_value<float>());
205  } else {
206  return cgen_state->llFp(inline_fp_null_value<double>());
207  }
208  } else {
209  llvm::Value* ret_val{nullptr};
210  if (col_ti.get_compression() == kENCODING_FIXED ||
212  ret_val = cgen_state->llInt(inline_fixed_encoding_null_val(col_ti));
213  } else {
214  ret_val = cgen_state->llInt(inline_int_null_val(col_ti));
215  }
216  size_t ret_val_col_size_in_bytes = col_ti.get_logical_size() * 8;
217  if (ret_val->getType()->getIntegerBitWidth() > ret_val_col_size_in_bytes) {
218  return cgen_state->castToTypeIn(ret_val, ret_val_col_size_in_bytes);
219  }
220  return ret_val;
221  }
222 }
223 
224 } // namespace
225 
227  AUTOMATIC_IR_METADATA(cgen_state_.get());
228  const auto window_func_context =
230  const auto window_func = window_func_context->getWindowFunction();
231  const auto arg_ti = get_adjusted_window_type_info(window_func);
232  llvm::Type* aggregate_state_type =
233  arg_ti.get_type() == kFLOAT
234  ? llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0)
235  : llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
236  const auto aggregate_state_i64 = cgen_state_->llInt(
237  reinterpret_cast<const int64_t>(window_func_context->aggregateState()));
238  return cgen_state_->ir_builder_.CreateIntToPtr(aggregate_state_i64,
239  aggregate_state_type);
240 }
241 
243  AUTOMATIC_IR_METADATA(cgen_state_.get());
244  const auto reset_state_false_bb = codegenWindowResetStateControlFlow();
245  auto aggregate_state = aggregateWindowStatePtr();
246  llvm::Value* aggregate_state_count = nullptr;
247  const auto window_func_context =
249  const auto window_func = window_func_context->getWindowFunction();
250  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
251  const auto aggregate_state_count_i64 = cgen_state_->llInt(
252  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
253  const auto pi64_type =
254  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
255  aggregate_state_count =
256  cgen_state_->ir_builder_.CreateIntToPtr(aggregate_state_count_i64, pi64_type);
257  }
258  codegenWindowFunctionStateInit(aggregate_state);
259  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
260  const auto count_zero = cgen_state_->llInt(int64_t(0));
261  cgen_state_->emitCall("agg_id", {aggregate_state_count, count_zero});
262  }
263  cgen_state_->ir_builder_.CreateBr(reset_state_false_bb);
264  cgen_state_->ir_builder_.SetInsertPoint(reset_state_false_bb);
266  return codegenWindowFunctionAggregateCalls(aggregate_state, co);
267 }
268 
270  AUTOMATIC_IR_METADATA(cgen_state_.get());
271  const auto window_func_context =
273  const auto bitset = cgen_state_->llInt(
274  reinterpret_cast<const int64_t>(window_func_context->partitionStart()));
275  const auto min_val = cgen_state_->llInt(int64_t(0));
276  const auto max_val = cgen_state_->llInt(window_func_context->elementCount() - 1);
277  const auto null_val = cgen_state_->llInt(inline_int_null_value<int64_t>());
278  const auto null_bool_val = cgen_state_->llInt<int8_t>(inline_int_null_value<int8_t>());
279  CodeGenerator code_generator(this);
280  const auto reset_state =
281  code_generator.toBool(cgen_state_->emitCall("bit_is_set",
282  {bitset,
283  code_generator.posArg(nullptr),
284  min_val,
285  max_val,
286  null_val,
287  null_bool_val}));
288  const auto reset_state_true_bb = llvm::BasicBlock::Create(
289  cgen_state_->context_, "reset_state.true", cgen_state_->current_func_);
290  const auto reset_state_false_bb = llvm::BasicBlock::Create(
291  cgen_state_->context_, "reset_state.false", cgen_state_->current_func_);
292  cgen_state_->ir_builder_.CreateCondBr(
293  reset_state, reset_state_true_bb, reset_state_false_bb);
294  cgen_state_->ir_builder_.SetInsertPoint(reset_state_true_bb);
295  return reset_state_false_bb;
296 }
297 
298 void Executor::codegenWindowFunctionStateInit(llvm::Value* aggregate_state) {
299  AUTOMATIC_IR_METADATA(cgen_state_.get());
300  const auto window_func_context =
302  const auto window_func = window_func_context->getWindowFunction();
303  const auto window_func_ti = get_adjusted_window_type_info(window_func);
304  const auto window_func_null_val =
305  window_func_ti.is_fp()
306  ? cgen_state_->inlineFpNull(window_func_ti)
307  : cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(window_func_ti), 64);
308  llvm::Value* window_func_init_val;
309  const auto window_func_kind = window_func_context->getWindowFunction()->getKind();
310  if (window_func_kind == SqlWindowFunctionKind::COUNT ||
311  window_func_kind == SqlWindowFunctionKind::COUNT_IF) {
312  switch (window_func_ti.get_type()) {
313  case kFLOAT: {
314  window_func_init_val = cgen_state_->llFp(float(0));
315  break;
316  }
317  case kDOUBLE: {
318  window_func_init_val = cgen_state_->llFp(double(0));
319  break;
320  }
321  default: {
322  window_func_init_val = cgen_state_->llInt(int64_t(0));
323  break;
324  }
325  }
326  } else {
327  window_func_init_val = window_func_null_val;
328  }
329  const auto pi32_type =
330  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
331  switch (window_func_ti.get_type()) {
332  case kDOUBLE: {
333  cgen_state_->emitCall("agg_id_double", {aggregate_state, window_func_init_val});
334  break;
335  }
336  case kFLOAT: {
337  aggregate_state =
338  cgen_state_->ir_builder_.CreateBitCast(aggregate_state, pi32_type);
339  cgen_state_->emitCall("agg_id_float", {aggregate_state, window_func_init_val});
340  break;
341  }
342  default: {
343  cgen_state_->emitCall("agg_id", {aggregate_state, window_func_init_val});
344  break;
345  }
346  }
347 }
348 
350  const CompilationOptions& co) {
351  AUTOMATIC_IR_METADATA(cgen_state_.get());
352  const auto window_func_context =
354  const auto window_func = window_func_context->getWindowFunction();
355  const auto window_func_kind = window_func->getKind();
356  const auto& args = window_func->getArgs();
357  CHECK(args.size() >= 1 && args.size() <= 3);
358  CodeGenerator code_generator(this);
359 
360  const auto target_col_ti = args.front()->get_type_info();
361  const auto target_col_size = target_col_ti.get_size();
362  const auto target_col_type_name =
363  get_col_type_name_by_size(target_col_size, target_col_ti.is_fp());
364  const auto target_col_logical_type_name = get_col_type_name_by_size(
365  window_func->get_type_info().get_size(), window_func->get_type_info().is_fp());
366 
367  // when target_column is fixed encoded, we store the actual column value by
368  // considering it, but our resultset analyzer only considers the type without encoding
369  // scheme so we handle them separately
370  auto logical_null_val_lv =
371  get_null_value_by_size(cgen_state_.get(), window_func->get_type_info());
372  auto target_col_null_val_lv =
373  get_null_value_by_size_with_encoding(cgen_state_.get(), target_col_ti);
374  if (window_func_context->elementCount() == 0) {
375  // we do not need to generate a code for an empty input table
376  return target_col_null_val_lv;
377  }
378 
379  auto [frame_start_bound_expr_lv, frame_end_bound_expr_lv] =
380  codegenFrameBoundRange(window_func, code_generator, co);
381 
382  auto current_row_pos_lv = code_generator.posArg(nullptr);
383  auto partition_index_lv =
384  codegenCurrentPartitionIndex(window_func_context, current_row_pos_lv);
385 
386  // load window function input expression; target_column
387  size_t target_col_size_in_byte = target_col_size * 8;
388  llvm::Type* col_buf_ptr_type =
389  target_col_ti.is_fp()
390  ? get_fp_type(target_col_size_in_byte, cgen_state_->context_)
391  : get_int_type(target_col_size_in_byte, cgen_state_->context_);
392  auto col_buf_type = llvm::PointerType::get(col_buf_ptr_type, 0);
393  auto target_col_buf_ptr_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
394  window_func_context->getColumnBufferForWindowFunctionExpressions().front()));
395  auto target_col_buf_lv =
396  cgen_state_->ir_builder_.CreateIntToPtr(target_col_buf_ptr_lv, col_buf_type);
397 
398  // prepare various buffer ptrs related to the window partition
399  auto partition_buf_ptrs =
400  codegenLoadPartitionBuffers(window_func_context, partition_index_lv);
401 
402  // null value of the ordering column
403  const auto order_key_buf_ti =
404  window_func_context->getOrderKeyColumnBufferTypes().front();
405  auto const ordering_spec = window_func->getCollation().front();
406  auto order_key_col_null_val_lv =
407  get_null_value_by_size_with_encoding(cgen_state_.get(), order_key_buf_ti);
408 
409  // load ordering column
410  auto [order_col_type_name, order_key_buf_ptr_lv] =
411  codegenLoadOrderKeyBufPtr(window_func_context);
412 
413  // null range
414  auto [null_start_pos_lv, null_end_pos_lv] =
415  codegenFrameNullRange(window_func_context, partition_index_lv);
416 
417  // compute a row index of the current row w.r.t the window frame it belongs to
418  std::string row_idx_on_frame_func = "compute_";
419  row_idx_on_frame_func += order_col_type_name;
420  row_idx_on_frame_func += ordering_spec.is_desc ? "_greater_equal" : "_less_equal";
421  row_idx_on_frame_func += "_current_row_idx_in_frame";
422  auto int64_t_one_val_lv = cgen_state_->llInt((int64_t)1);
423  auto nulls_first_lv = cgen_state_->llBool(ordering_spec.nulls_first);
424  auto cur_row_idx_in_frame_lv =
425  cgen_state_->emitCall(row_idx_on_frame_func,
426  {partition_buf_ptrs.num_elem_current_partition_lv,
427  current_row_pos_lv,
428  order_key_buf_ptr_lv,
429  partition_buf_ptrs.target_partition_rowid_ptr_lv,
430  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
431  order_key_col_null_val_lv,
432  nulls_first_lv,
433  null_start_pos_lv,
434  null_end_pos_lv});
435 
436  // compute frame bound for the current row
437  auto const int64_t_zero_val_lv = cgen_state_->llInt((int64_t)0);
439  frame_start_bound_expr_lv,
440  frame_end_bound_expr_lv,
441  window_func->hasRangeModeFraming() ? current_row_pos_lv : cur_row_idx_in_frame_lv,
442  nullptr,
443  window_func->hasRangeModeFraming()
444  ? int64_t_zero_val_lv
445  : partition_buf_ptrs.current_partition_start_offset_lv,
446  int64_t_zero_val_lv,
447  int64_t_one_val_lv,
448  partition_buf_ptrs.num_elem_current_partition_lv,
449  order_key_buf_ptr_lv,
450  "",
451  partition_buf_ptrs.target_partition_rowid_ptr_lv,
452  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
453  nulls_first_lv,
454  null_start_pos_lv,
455  null_end_pos_lv};
456  auto [frame_start_bound_lv, frame_end_bound_lv] =
457  codegenWindowFrameBounds(window_func_context,
458  window_func->getFrameStartBound(),
459  window_func->getFrameEndBound(),
460  order_key_col_null_val_lv,
462  code_generator);
463 
464  // apply offset
465  llvm::Value* modified_cur_row_idx_in_frame_lv{nullptr};
466  auto const offset_lv =
467  cgen_state_->castToTypeIn(code_generator.codegen(args[1].get(), true, co)[0], 64);
468  switch (window_func_kind) {
470  modified_cur_row_idx_in_frame_lv =
471  cgen_state_->ir_builder_.CreateSub(cur_row_idx_in_frame_lv, offset_lv);
472  break;
474  modified_cur_row_idx_in_frame_lv =
475  cgen_state_->ir_builder_.CreateAdd(cur_row_idx_in_frame_lv, offset_lv);
476  break;
478  auto candidate_row_idx =
479  cgen_state_->ir_builder_.CreateAdd(frame_start_bound_lv, offset_lv);
480  auto out_of_frame_bound_lv =
481  cgen_state_->ir_builder_.CreateICmpSGT(candidate_row_idx, frame_end_bound_lv);
482  // return null if the candidate_row_idx is out of frame bounds
483  modified_cur_row_idx_in_frame_lv = cgen_state_->ir_builder_.CreateSelect(
484  out_of_frame_bound_lv, cgen_state_->llInt((int64_t)-1), candidate_row_idx);
485  break;
486  }
487  default:
488  UNREACHABLE() << "Unsupported window function to navigate a window frame.";
489  }
490  CHECK(modified_cur_row_idx_in_frame_lv);
491 
492  // get the target column value in the frame w.r.t the offset
493  std::string target_func_name = "get_";
494  target_func_name += target_col_type_name + "_value_";
495  target_func_name += target_col_logical_type_name + "_type_";
496  target_func_name += "in_frame";
497  auto res_lv =
498  cgen_state_->emitCall(target_func_name,
499  {modified_cur_row_idx_in_frame_lv,
500  frame_start_bound_lv,
501  frame_end_bound_lv,
502  target_col_buf_lv,
503  partition_buf_ptrs.target_partition_rowid_ptr_lv,
504  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
505  logical_null_val_lv,
506  target_col_null_val_lv});
507  if (target_col_ti.get_compression() == kENCODING_DATE_IN_DAYS) {
508  res_lv = cgen_state_->emitCall(
509  "encode_date",
510  {res_lv, logical_null_val_lv, cgen_state_->llInt((int64_t)kSecsPerDay)});
511  }
512  CHECK(res_lv);
513  return res_lv;
514 }
515 
517  const Analyzer::WindowFrame* frame_bound,
518  CodeGenerator& code_generator,
519  const CompilationOptions& co) {
520  auto needs_bound_expr_codegen = [](const Analyzer::WindowFrame* window_frame) {
521  return window_frame->getBoundType() == SqlWindowFrameBoundType::EXPR_FOLLOWING ||
522  window_frame->getBoundType() == SqlWindowFrameBoundType::EXPR_PRECEDING;
523  };
524  const auto order_col_ti = window_func->getOrderKeys().front()->get_type_info();
525  auto encode_date_col_val = [&order_col_ti, this](llvm::Value* bound_expr_lv) {
526  if (order_col_ti.get_comp_param() == 16) {
527  return cgen_state_->emitCall(
528  "fixed_width_date_encode_noinline",
529  {bound_expr_lv,
530  cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(SQLTypeInfo(kSMALLINT)),
531  32),
532  cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT))});
533  } else {
534  return cgen_state_->emitCall("fixed_width_date_encode_noinline",
535  {bound_expr_lv,
536  cgen_state_->inlineIntNull(SQLTypeInfo(kINT)),
537  cgen_state_->inlineIntNull(SQLTypeInfo(kBIGINT))});
538  }
539  };
540  llvm::Value* bound_expr_lv{nullptr};
541  if (needs_bound_expr_codegen(frame_bound)) {
542  auto bound_expr = frame_bound->getBoundExpr();
543  if (auto dateadd_expr = dynamic_cast<const Analyzer::DateaddExpr*>(bound_expr)) {
544  if (dateadd_expr->get_datetime_expr()->get_type_info().is_encoded_timestamp()) {
545  dateadd_expr->set_fixed_encoding_null_val();
546  }
547  }
548  auto bound_expr_lvs = code_generator.codegen(bound_expr, true, co);
549  bound_expr_lv = bound_expr_lvs.front();
550  if (order_col_ti.is_date() && window_func->hasRangeModeFraming()) {
551  if (g_cluster) {
552  throw std::runtime_error(
553  "Range mode with date type ordering column is not supported yet.");
554  }
555  bound_expr_lv = encode_date_col_val(bound_expr_lv);
556  }
557  if (frame_bound->getBoundExpr()->get_type_info().get_size() != 8) {
558  bound_expr_lv = cgen_state_->castToTypeIn(bound_expr_lv, 64);
559  }
560  } else {
561  bound_expr_lv = cgen_state_->llInt((int64_t)-1);
562  }
563  CHECK(bound_expr_lv);
564  return bound_expr_lv;
565 }
566 
567 llvm::Value* Executor::codegenFrameBound(bool for_start_bound,
568  bool for_range_mode,
569  bool for_window_frame_naviation,
570  const Analyzer::WindowFrame* frame_bound,
571  bool is_timestamp_type_frame,
572  llvm::Value* order_key_null_val,
574  const auto bound_type = frame_bound->getBoundType();
575  auto adjust_frame_end_bound = [&](llvm::Value* target_bound_lv) {
576  return cgen_state_->ir_builder_.CreateSub(target_bound_lv, args.int64_t_one_val_lv);
577  };
579  CHECK(for_start_bound) << "frame end cannot be UNBOUNDED PRECEDING";
580  return args.int64_t_zero_val_lv;
581  } else if (bound_type == SqlWindowFrameBoundType::UNBOUNDED_FOLLOWING) {
582  CHECK(!for_start_bound) << "frame start cannot be UNBOUNDED FOLLOWING";
583  // adjust frame bound w.r.t the open frame interval if necessary
584  return for_window_frame_naviation
585  ? adjust_frame_end_bound(args.num_elem_current_partition_lv)
587  }
588  std::vector<llvm::Value*> func_args;
589  std::string op_name =
590  bound_type == SqlWindowFrameBoundType::EXPR_FOLLOWING ? "add" : "sub";
591  if (!for_range_mode) {
592  llvm::Value* current_row_bound_expr_lv{nullptr};
593  if (for_window_frame_naviation) {
594  // we already know a current row's index in (ordered) window frame in this case
595  auto bound_expr =
596  for_start_bound ? args.frame_start_bound_expr_lv : args.frame_end_bound_expr_lv;
597  if (bound_type == SqlWindowFrameBoundType::EXPR_FOLLOWING) {
598  current_row_bound_expr_lv =
599  cgen_state_->ir_builder_.CreateAdd(args.current_row_pos_lv, bound_expr);
600  } else if (bound_type == SqlWindowFrameBoundType::EXPR_PRECEDING) {
601  current_row_bound_expr_lv =
602  cgen_state_->ir_builder_.CreateSub(args.current_row_pos_lv, bound_expr);
603  } else {
605  current_row_bound_expr_lv = args.current_row_pos_lv;
606  }
607  // adjust frame bound w.r.t the open frame interval
608  if (for_start_bound) {
609  return cgen_state_->ir_builder_.CreateSelect(
610  cgen_state_->ir_builder_.CreateICmpSLT(current_row_bound_expr_lv,
611  args.int64_t_zero_val_lv),
612  args.int64_t_zero_val_lv,
613  current_row_bound_expr_lv);
614  } else {
615  return cgen_state_->ir_builder_.CreateSelect(
616  cgen_state_->ir_builder_.CreateICmpSGE(current_row_bound_expr_lv,
618  adjust_frame_end_bound(args.num_elem_current_partition_lv),
619  current_row_bound_expr_lv);
620  }
621  } else {
622  std::string func_class = for_start_bound ? "start" : "end";
623  auto const func_name = "compute_row_mode_" + func_class + "_index_" + op_name;
624  func_args = prepareRowModeFuncArgs(for_start_bound, bound_type, args);
625  current_row_bound_expr_lv = cgen_state_->emitCall(func_name, func_args);
626  }
627  return current_row_bound_expr_lv;
628  } else {
629  std::string func_class = for_start_bound ? "lower" : "upper";
630  auto const func_name = getFramingFuncName(
631  func_class,
632  args.order_type_col_name,
633  op_name,
634  bound_type != SqlWindowFrameBoundType::CURRENT_ROW && is_timestamp_type_frame);
635  func_args = prepareRangeModeFuncArgs(
636  for_start_bound, frame_bound, is_timestamp_type_frame, order_key_null_val, args);
637  auto frame_bound_lv = cgen_state_->emitCall(func_name, func_args);
638  if (!for_start_bound && for_window_frame_naviation) {
639  // adjust frame end bound w.r.t the open frame interval
640  frame_bound_lv = cgen_state_->ir_builder_.CreateSelect(
641  cgen_state_->ir_builder_.CreateICmpSGE(frame_bound_lv,
643  adjust_frame_end_bound(args.num_elem_current_partition_lv),
644  frame_bound_lv);
645  }
646  return frame_bound_lv;
647  }
648 }
649 
651  WindowFunctionContext* window_func_context) const {
652  const auto window_func = window_func_context->getWindowFunction();
653  return window_func->getOrderKeys().front()->get_type_info();
654 }
655 
656 size_t Executor::getOrderKeySize(WindowFunctionContext* window_func_context) const {
657  const auto order_key_size = getFirstOrderColTypeInfo(window_func_context).get_size();
658  return order_key_size;
659 }
660 
662  WindowFunctionContext* window_func_context) const {
663  auto const order_key_size = getOrderKeySize(window_func_context);
664  auto const order_key_ptr =
665  window_func_context->getWindowFunction()->getOrderKeys().front();
666  CHECK(order_key_ptr);
667  return get_col_type_name_by_size(order_key_size,
668  order_key_ptr->get_type_info().is_fp());
669 }
670 
672  WindowFunctionContext* window_func_context,
673  CodeGenerator& code_generator,
675  llvm::Value* current_col_value_ptr_lv{nullptr};
676  const auto order_key_size_in_byte = getOrderKeySize(window_func_context) * 8;
677  auto const order_key_ptr =
678  window_func_context->getWindowFunction()->getOrderKeys().front();
679  CHECK(order_key_ptr);
680  auto const order_col_ti = order_key_ptr->get_type_info();
681  auto const order_col_llvm_type =
682  order_col_ti.is_fp() ? get_fp_type(order_key_size_in_byte, cgen_state_->context_)
683  : get_int_type(order_key_size_in_byte, cgen_state_->context_);
684  if (!window_func_context->getWindowFunction()->isFrameNavigateWindowFunction()) {
685  auto rowid_in_partition_lv = code_generator.codegenWindowPosition(
686  window_func_context, args.current_row_pos_lv);
687  current_col_value_ptr_lv = cgen_state_->ir_builder_.CreateGEP(
688  order_col_llvm_type, args.order_key_buf_ptr_lv, rowid_in_partition_lv);
689  } else {
690  current_col_value_ptr_lv = cgen_state_->ir_builder_.CreateGEP(
691  order_col_llvm_type, args.order_key_buf_ptr_lv, args.current_row_pos_lv);
692  }
693  return cgen_state_->ir_builder_.CreateLoad(
694  current_col_value_ptr_lv->getType()->getPointerElementType(),
695  current_col_value_ptr_lv,
696  "current_col_value");
697 }
698 
700  const WindowFunctionContext* window_func_context,
701  llvm::Value* current_row_pos_lv) {
702  const auto pi64_type =
703  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
704  const auto pi32_type =
705  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
706  auto row_pos_lv = current_row_pos_lv;
707  if (window_func_context->getWindowFunction()->isFrameNavigateWindowFunction()) {
708  // `current_row_pos_lv` indicates the index of the current row, but to figure out it's
709  // index of window partition it belongs to, we need a special approach especially for
710  // window framing navigation function for instance, when we have five rows having two
711  // columns pc and val such as (2,1), (2,2), (2,3), (1,1), (1,2), we build a OneToMany
712  // Perfect Hash Table as: offset: 0 2 / count: 2 3 / payload: i1, i2, i3, i4, i5 where
713  // i1 ~ i3 and i4 ~ i5 are rows for partition 1 (i.e., pc = 1) and 2 (i.e., prc = 2),
714  // respectively. But when processing the first row (2, 1), the original
715  // `current_row_pos_lv` stands for zero so computing which partitions it belongs to is
716  // hard unless hashing the value at runtime. Even if we do hash, we cannot know the
717  // exact hash slot unless we do binary + linear searches multiple times (via payload
718  // buffer and the ordered payload buffer) i.e., when the row (1,2) is assigned to the
719  // partition[4], we cannot find the hash slot index '4' by using `current_row_pos_lv`
720  // unless doing a costly operation like a linear search over the entire window
721  // partition Instead, we collect a hash slot that each row is assigned to and keep
722  // this info at the payload buffer `hash_slot_idx_ptr_lv` and use it for computing
723  // window frame navigation functions
724  auto* const hash_slot_idx_ptr =
725  window_func_context->payload() + window_func_context->elementCount();
726  auto hash_slot_idx_buf_lv =
727  cgen_state_->llInt(reinterpret_cast<int64_t>(hash_slot_idx_ptr));
728  auto hash_slot_idx_ptr_lv =
729  cgen_state_->ir_builder_.CreateIntToPtr(hash_slot_idx_buf_lv, pi32_type);
730  auto hash_slot_idx_load_lv = cgen_state_->ir_builder_.CreateGEP(
731  hash_slot_idx_ptr_lv->getType()->getPointerElementType(),
732  hash_slot_idx_ptr_lv,
733  current_row_pos_lv);
734  row_pos_lv = cgen_state_->castToTypeIn(
735  cgen_state_->ir_builder_.CreateLoad(
736  hash_slot_idx_load_lv->getType()->getPointerElementType(),
737  hash_slot_idx_load_lv,
738  "cur_row_hash_slot_idx"),
739  64);
740  }
741  auto partition_count_lv = cgen_state_->llInt(window_func_context->partitionCount());
742  auto partition_num_count_buf_lv = cgen_state_->llInt(
743  reinterpret_cast<int64_t>(window_func_context->partitionNumCountBuf()));
744  auto partition_num_count_ptr_lv =
745  cgen_state_->ir_builder_.CreateIntToPtr(partition_num_count_buf_lv, pi64_type);
746  return cgen_state_->emitCall(
747  "compute_int64_t_lower_bound",
748  {partition_count_lv, row_pos_lv, partition_num_count_ptr_lv});
749 }
750 
751 std::string Executor::getFramingFuncName(const std::string& bound_type,
752  const std::string& order_col_type,
753  const std::string& op_type,
754  bool for_timestamp_type) const {
755  auto target_val_type = for_timestamp_type ? "int64_t" : order_col_type;
756  auto null_type = for_timestamp_type ? "int64_t" : order_col_type;
757  return "range_mode_" + target_val_type + "_" + order_col_type + "_" + null_type + "_" +
758  op_type + "_frame_" + bound_type + "_bound";
759 }
760 
761 std::vector<llvm::Value*> Executor::prepareRowModeFuncArgs(
762  bool for_start_bound,
763  SqlWindowFrameBoundType bound_type,
764  const WindowFrameBoundFuncArgs& args) const {
765  std::vector<llvm::Value*> frame_args{args.current_row_pos_lv,
767  if (bound_type == SqlWindowFrameBoundType::CURRENT_ROW) {
768  frame_args.push_back(args.int64_t_zero_val_lv);
769  } else {
770  frame_args.push_back(for_start_bound ? args.frame_start_bound_expr_lv
771  : args.frame_end_bound_expr_lv);
772  if (bound_type == SqlWindowFrameBoundType::EXPR_FOLLOWING) {
773  frame_args.push_back(args.num_elem_current_partition_lv);
774  }
775  }
776  return frame_args;
777 }
778 
779 std::vector<llvm::Value*> Executor::prepareRangeModeFuncArgs(
780  bool for_start_bound,
781  const Analyzer::WindowFrame* frame_bound,
782  bool is_timestamp_type_frame,
783  llvm::Value* order_key_null_val,
784  const WindowFrameBoundFuncArgs& args) const {
785  llvm::Value* bound_expr_lv =
786  for_start_bound ? args.frame_start_bound_expr_lv : args.frame_end_bound_expr_lv;
787  llvm::Value* target_val_lv =
788  frame_bound->isCurrentRowBound() || !is_timestamp_type_frame
789  ? args.current_col_value_lv
790  : bound_expr_lv;
791  llvm::Value* frame_bound_val_lv =
792  frame_bound->isCurrentRowBound() || is_timestamp_type_frame
793  ? args.int64_t_zero_val_lv
794  : bound_expr_lv;
795  std::vector<llvm::Value*> frame_args{args.num_elem_current_partition_lv,
796  target_val_lv,
800  frame_bound_val_lv,
801  order_key_null_val,
802  args.nulls_first_lv,
803  args.null_start_pos_lv,
804  args.null_end_pos_lv};
805  return frame_args;
806 }
807 
808 std::pair<llvm::Value*, llvm::Value*> Executor::codegenFrameNullRange(
809  WindowFunctionContext* window_func_context,
810  llvm::Value* partition_index_lv) const {
811  const auto pi64_type =
812  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
813  const auto null_start_pos_buf = cgen_state_->llInt(
814  reinterpret_cast<int64_t>(window_func_context->getNullValueStartPos()));
815  const auto null_start_pos_buf_ptr =
816  cgen_state_->ir_builder_.CreateIntToPtr(null_start_pos_buf, pi64_type);
817  const auto null_start_pos_ptr =
818  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
819  null_start_pos_buf_ptr,
820  partition_index_lv);
821  auto null_start_pos_lv = cgen_state_->ir_builder_.CreateLoad(
822  null_start_pos_ptr->getType()->getPointerElementType(),
823  null_start_pos_ptr,
824  "null_start_pos");
825  const auto null_end_pos_buf = cgen_state_->llInt(
826  reinterpret_cast<int64_t>(window_func_context->getNullValueEndPos()));
827  const auto null_end_pos_buf_ptr =
828  cgen_state_->ir_builder_.CreateIntToPtr(null_end_pos_buf, pi64_type);
829  const auto null_end_pos_ptr = cgen_state_->ir_builder_.CreateGEP(
830  get_int_type(64, cgen_state_->context_), null_end_pos_buf_ptr, partition_index_lv);
831  auto null_end_pos_lv = cgen_state_->ir_builder_.CreateLoad(
832  null_end_pos_ptr->getType()->getPointerElementType(),
833  null_end_pos_ptr,
834  "null_end_pos");
835  return std::make_pair(null_start_pos_lv, null_end_pos_lv);
836 }
837 
838 std::pair<std::string, llvm::Value*> Executor::codegenLoadOrderKeyBufPtr(
839  WindowFunctionContext* window_func_context) const {
840  auto const order_key_ti =
841  window_func_context->getWindowFunction()->getOrderKeys().front()->get_type_info();
842  auto const order_key_size = order_key_ti.get_size();
843  auto const order_col_type_name = get_col_type_name_by_size(
844  order_key_size,
845  window_func_context->getOrderKeyColumnBufferTypes().front().is_fp());
846  size_t order_key_size_in_byte = order_key_size * 8;
847  auto const order_key_type =
848  order_key_ti.is_fp() ? get_fp_type(order_key_size_in_byte, cgen_state_->context_)
849  : get_int_type(order_key_size_in_byte, cgen_state_->context_);
850  auto const order_key_buf_type = llvm::PointerType::get(order_key_type, 0);
851  auto const order_key_buf = cgen_state_->llInt(
852  reinterpret_cast<int64_t>(window_func_context->getOrderKeyColumnBuffers().front()));
853  auto const order_key_buf_ptr_lv =
854  cgen_state_->ir_builder_.CreateIntToPtr(order_key_buf, order_key_buf_type);
855  return std::make_pair(order_col_type_name, order_key_buf_ptr_lv);
856 }
857 
859  WindowFunctionContext* window_func_context,
860  llvm::Value* partition_index_lv) const {
861  WindowPartitionBufferPtrs bufferPtrs;
862  const auto pi64_type =
863  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
864  const auto pi32_type =
865  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
866 
867  // partial sum of # elems of partitions
868  auto partition_start_offset_buf_lv = cgen_state_->llInt(
869  reinterpret_cast<int64_t>(window_func_context->partitionStartOffset()));
870  auto partition_start_offset_ptr_lv =
871  cgen_state_->ir_builder_.CreateIntToPtr(partition_start_offset_buf_lv, pi64_type);
872 
873  // get start offset of the current partition
874  auto current_partition_start_offset_ptr_lv =
875  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
876  partition_start_offset_ptr_lv,
877  partition_index_lv);
878  bufferPtrs.current_partition_start_offset_lv = cgen_state_->ir_builder_.CreateLoad(
879  current_partition_start_offset_ptr_lv->getType()->getPointerElementType(),
880  current_partition_start_offset_ptr_lv);
881 
882  // row_id buf of the current partition
883  const auto partition_rowid_buf_lv =
884  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->payload()));
885  const auto partition_rowid_ptr_lv =
886  cgen_state_->ir_builder_.CreateIntToPtr(partition_rowid_buf_lv, pi32_type);
887  bufferPtrs.target_partition_rowid_ptr_lv =
888  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
889  partition_rowid_ptr_lv,
891 
892  // row_id buf of ordered current partition
893  const auto sorted_rowid_lv = cgen_state_->llInt(
894  reinterpret_cast<int64_t>(window_func_context->sortedPartition()));
895  const auto sorted_rowid_ptr_lv =
896  cgen_state_->ir_builder_.CreateIntToPtr(sorted_rowid_lv, pi64_type);
898  cgen_state_->ir_builder_.CreateGEP(get_int_type(64, cgen_state_->context_),
899  sorted_rowid_ptr_lv,
901 
902  // # elems per partition
903  const auto partition_count_buf =
904  cgen_state_->llInt(reinterpret_cast<int64_t>(window_func_context->counts()));
905  auto partition_count_buf_ptr_lv =
906  cgen_state_->ir_builder_.CreateIntToPtr(partition_count_buf, pi32_type);
907 
908  // # elems of the given partition
909  const auto num_elem_current_partition_ptr =
910  cgen_state_->ir_builder_.CreateGEP(get_int_type(32, cgen_state_->context_),
911  partition_count_buf_ptr_lv,
912  partition_index_lv);
913  bufferPtrs.num_elem_current_partition_lv = cgen_state_->castToTypeIn(
914  cgen_state_->ir_builder_.CreateLoad(
915  num_elem_current_partition_ptr->getType()->getPointerElementType(),
916  num_elem_current_partition_ptr),
917  64);
918  return bufferPtrs;
919 }
920 
921 std::pair<llvm::Value*, llvm::Value*> Executor::codegenFrameBoundRange(
922  const Analyzer::WindowFunction* window_func,
923  CodeGenerator& code_generator,
924  const CompilationOptions& co) {
925  const auto frame_start_bound = window_func->getFrameStartBound();
926  const auto frame_end_bound = window_func->getFrameEndBound();
927  auto frame_start_bound_expr_lv =
928  codegenFrameBoundExpr(window_func, frame_start_bound, code_generator, co);
929  auto frame_end_bound_expr_lv =
930  codegenFrameBoundExpr(window_func, frame_end_bound, code_generator, co);
931  CHECK(frame_start_bound_expr_lv);
932  CHECK(frame_end_bound_expr_lv);
933  return std::make_pair(frame_start_bound_expr_lv, frame_end_bound_expr_lv);
934 }
935 
936 std::pair<llvm::Value*, llvm::Value*> Executor::codegenWindowFrameBounds(
937  WindowFunctionContext* window_func_context,
938  const Analyzer::WindowFrame* frame_start_bound,
939  const Analyzer::WindowFrame* frame_end_bound,
940  llvm::Value* order_key_col_null_val_lv,
942  CodeGenerator& code_generator) {
943  const auto window_func = window_func_context->getWindowFunction();
944  CHECK(window_func);
945  const auto is_timestamp_type_frame = frame_start_bound->hasTimestampTypeFrameBound() ||
946  frame_end_bound->hasTimestampTypeFrameBound();
947 
948  if (window_func->hasRangeModeFraming()) {
949  CHECK(window_func_context->getOrderKeyColumnBuffers().size() == 1);
950  CHECK(window_func->getOrderKeys().size() == 1UL);
951  CHECK(window_func_context->getOrderKeyColumnBuffers().size() == 1UL);
952  args.order_type_col_name = getOrderKeyTypeName(window_func_context);
953  args.current_col_value_lv =
954  codegenLoadCurrentValueFromColBuf(window_func_context, code_generator, args);
955  }
956 
957  auto get_order_key_null_val = [is_timestamp_type_frame,
958  &order_key_col_null_val_lv,
959  this](const Analyzer::WindowFrame* frame_bound) {
960  return is_timestamp_type_frame && !frame_bound->isCurrentRowBound()
961  ? cgen_state_->castToTypeIn(order_key_col_null_val_lv, 64)
962  : order_key_col_null_val_lv;
963  };
964  auto frame_start_bound_lv =
965  codegenFrameBound(true,
966  window_func->hasRangeModeFraming(),
967  window_func->isFrameNavigateWindowFunction(),
968  frame_start_bound,
969  is_timestamp_type_frame,
970  get_order_key_null_val(frame_start_bound),
971  args);
972  auto frame_end_bound_lv =
973  codegenFrameBound(false,
974  window_func->hasRangeModeFraming(),
975  window_func->isFrameNavigateWindowFunction(),
976  frame_end_bound,
977  is_timestamp_type_frame,
978  get_order_key_null_val(frame_end_bound),
979  args);
980  CHECK(frame_start_bound_lv);
981  CHECK(frame_end_bound_lv);
982  return std::make_pair(frame_start_bound_lv, frame_end_bound_lv);
983 }
984 
985 llvm::Value* Executor::codegenWindowFunctionAggregateCalls(llvm::Value* aggregate_state,
986  const CompilationOptions& co) {
987  AUTOMATIC_IR_METADATA(cgen_state_.get());
988  const auto window_func_context =
990  const auto window_func = window_func_context->getWindowFunction();
991  const auto window_func_ti = get_adjusted_window_type_info(window_func);
992  const auto window_func_null_val =
993  window_func_ti.is_fp()
994  ? cgen_state_->inlineFpNull(window_func_ti)
995  : cgen_state_->castToTypeIn(cgen_state_->inlineIntNull(window_func_ti), 64);
996  if (window_func_context->elementCount() == 0) {
997  // we do not need to generate a code for an empty input table
998  return window_func->getKind() == SqlWindowFunctionKind::AVG
999  ? cgen_state_->inlineFpNull(SQLTypeInfo(SQLTypes::kDOUBLE))
1000  : window_func_null_val;
1001  }
1002  const auto& args = window_func->getArgs();
1003  CodeGenerator code_generator(this);
1004  if (window_func_context->needsToBuildAggregateTree()) {
1005  // compute an aggregated value for each row of the window frame by using segment tree
1006  // when constructing a window context, we build a necessary segment tree (so called
1007  // `aggregate tree`) to query the aggregated value of the specific window frame
1008  const auto pi64_type =
1009  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1010  const auto ppi64_type = llvm::PointerType::get(
1011  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0), 0);
1012 
1013  auto [frame_start_bound_expr_lv, frame_end_bound_expr_lv] =
1014  codegenFrameBoundRange(window_func, code_generator, co);
1015 
1016  // compute aggregated value over the computed frame range
1017  auto current_row_pos_lv = code_generator.posArg(nullptr);
1018  auto partition_index_lv =
1019  codegenCurrentPartitionIndex(window_func_context, current_row_pos_lv);
1020 
1021  // ordering column buffer
1022  const auto target_col_ti = args.front()->get_type_info();
1023  const auto target_col_size = target_col_ti.get_size();
1024  const auto col_type_name =
1025  get_col_type_name_by_size(target_col_size, target_col_ti.is_fp());
1026 
1027  const auto partition_buf_ptrs =
1028  codegenLoadPartitionBuffers(window_func_context, partition_index_lv);
1029 
1030  auto [order_col_type_name, order_key_buf_ptr_lv] =
1031  codegenLoadOrderKeyBufPtr(window_func_context);
1032 
1033  // null value of the ordering column
1034  const auto order_key_buf_ti =
1035  window_func_context->getOrderKeyColumnBufferTypes().front();
1036  auto const ordering_spec = window_func->getCollation().front();
1037  llvm::Value* order_key_col_null_val_lv{nullptr};
1038  switch (order_key_buf_ti.get_type()) {
1039  case kDATE:
1040  case kTIMESTAMP:
1041  case kTIME: {
1042  if (order_key_buf_ti.get_compression() == kENCODING_FIXED ||
1043  order_key_buf_ti.get_compression() == kENCODING_DATE_IN_DAYS) {
1044  auto null_val = inline_fixed_encoding_null_val(order_key_buf_ti);
1045  order_key_col_null_val_lv = cgen_state_->llInt((int32_t)null_val);
1046  break;
1047  }
1048  }
1049  default: {
1050  order_key_col_null_val_lv = cgen_state_->inlineNull(order_key_buf_ti);
1051  break;
1052  }
1053  }
1054 
1055  auto [null_start_pos_lv, null_end_pos_lv] =
1056  codegenFrameNullRange(window_func_context, partition_index_lv);
1057  auto nulls_first_lv = cgen_state_->llBool(ordering_spec.nulls_first);
1058 
1060  frame_start_bound_expr_lv,
1061  frame_end_bound_expr_lv,
1062  current_row_pos_lv,
1063  nullptr,
1064  partition_buf_ptrs.current_partition_start_offset_lv,
1065  cgen_state_->llInt((int64_t)0),
1066  cgen_state_->llInt((int64_t)1),
1067  partition_buf_ptrs.num_elem_current_partition_lv,
1068  order_key_buf_ptr_lv,
1069  "",
1070  partition_buf_ptrs.target_partition_rowid_ptr_lv,
1071  partition_buf_ptrs.target_partition_sorted_rowid_ptr_lv,
1072  nulls_first_lv,
1073  null_start_pos_lv,
1074  null_end_pos_lv};
1075  auto [frame_start_bound_lv, frame_end_bound_lv] =
1076  codegenWindowFrameBounds(window_func_context,
1077  window_func->getFrameStartBound(),
1078  window_func->getFrameEndBound(),
1079  order_key_col_null_val_lv,
1081  code_generator);
1082 
1083  // codegen to send a query with frame bound to aggregate tree searcher
1084  llvm::Value* aggregation_trees_lv{nullptr};
1085  llvm::Value* invalid_val_lv{nullptr};
1086  llvm::Value* null_val_lv{nullptr};
1087  std::string aggregation_tree_search_func_name{"search_"};
1088  std::string aggregation_tree_getter_func_name{"get_"};
1089 
1090  // prepare null values and aggregate_tree getter and searcher depending on
1091  // a type of the ordering column
1092  auto agg_expr_ti = args.front()->get_type_info();
1093  if (agg_expr_ti.is_fp()) {
1094  if (window_func->getKind() == SqlWindowFunctionKind::MIN) {
1095  invalid_val_lv = cgen_state_->llFp(std::numeric_limits<double>::max());
1096  } else if (window_func->getKind() == SqlWindowFunctionKind::MAX) {
1097  invalid_val_lv = cgen_state_->llFp(std::numeric_limits<double>::lowest());
1098  } else {
1099  invalid_val_lv = cgen_state_->llFp((double)0);
1100  }
1101  null_val_lv = cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE));
1102  aggregation_tree_search_func_name += "double";
1103  aggregation_tree_getter_func_name += "double";
1104  } else {
1105  if (window_func->getKind() == SqlWindowFunctionKind::MIN) {
1106  invalid_val_lv = cgen_state_->llInt(std::numeric_limits<int64_t>::max());
1107  } else if (window_func->getKind() == SqlWindowFunctionKind::MAX) {
1108  invalid_val_lv = cgen_state_->llInt(std::numeric_limits<int64_t>::lowest());
1109  } else {
1110  invalid_val_lv = cgen_state_->llInt((int64_t)0);
1111  }
1112  null_val_lv = cgen_state_->llInt(inline_int_null_value<int64_t>());
1113  aggregation_tree_search_func_name += "int64_t";
1114  aggregation_tree_getter_func_name += "integer";
1115  }
1116 
1117  // derived aggregation has a different code path
1118  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1119  aggregation_tree_search_func_name += "_derived";
1120  aggregation_tree_getter_func_name += "_derived";
1121  }
1122 
1123  // get a buffer holding aggregate trees for each partition
1124  if (agg_expr_ti.is_fp()) {
1125  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1126  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1127  window_func_context->getDerivedAggregationTreesForDoubleTypeWindowExpr()));
1128  } else {
1129  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1130  window_func_context->getAggregationTreesForDoubleTypeWindowExpr()));
1131  }
1132  } else {
1133  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1134  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1135  window_func_context->getDerivedAggregationTreesForIntegerTypeWindowExpr()));
1136  } else {
1137  aggregation_trees_lv = cgen_state_->llInt(reinterpret_cast<int64_t>(
1138  window_func_context->getAggregationTreesForIntegerTypeWindowExpr()));
1139  }
1140  }
1141 
1142  CHECK(aggregation_trees_lv);
1143  CHECK(invalid_val_lv);
1144  aggregation_tree_search_func_name += "_aggregation_tree";
1145  aggregation_tree_getter_func_name += "_aggregation_tree";
1146 
1147  // get the aggregate tree of the current partition from a window context
1148  auto aggregation_trees_ptr =
1149  cgen_state_->ir_builder_.CreateIntToPtr(aggregation_trees_lv, ppi64_type);
1150  auto target_aggregation_tree_lv = cgen_state_->emitCall(
1151  aggregation_tree_getter_func_name, {aggregation_trees_ptr, partition_index_lv});
1152 
1153  // a depth of segment tree
1154  const auto tree_depth_buf = cgen_state_->llInt(
1155  reinterpret_cast<int64_t>(window_func_context->getAggregateTreeDepth()));
1156  const auto tree_depth_buf_ptr =
1157  cgen_state_->ir_builder_.CreateIntToPtr(tree_depth_buf, pi64_type);
1158  const auto current_partition_tree_depth_buf_ptr = cgen_state_->ir_builder_.CreateGEP(
1159  get_int_type(64, cgen_state_->context_), tree_depth_buf_ptr, partition_index_lv);
1160  const auto current_partition_tree_depth_lv = cgen_state_->ir_builder_.CreateLoad(
1161  current_partition_tree_depth_buf_ptr->getType()->getPointerElementType(),
1162  current_partition_tree_depth_buf_ptr);
1163 
1164  // a fanout of the current partition's segment tree
1165  const auto aggregation_tree_fanout_lv = cgen_state_->llInt(
1166  static_cast<int64_t>(window_func_context->getAggregateTreeFanout()));
1167 
1168  // agg_type
1169  const auto agg_type_lv =
1170  cgen_state_->llInt(static_cast<int32_t>(window_func->getKind()));
1171 
1172  // send a query to the aggregate tree with the frame range:
1173  // `frame_start_bound_lv` ~ `frame_end_bound_lv`
1174  auto res_lv =
1175  cgen_state_->emitCall(aggregation_tree_search_func_name,
1176  {target_aggregation_tree_lv,
1177  frame_start_bound_lv,
1178  frame_end_bound_lv,
1179  current_partition_tree_depth_lv,
1180  aggregation_tree_fanout_lv,
1181  cgen_state_->llBool(agg_expr_ti.is_decimal()),
1182  cgen_state_->llInt((int64_t)agg_expr_ti.get_scale()),
1183  invalid_val_lv,
1184  null_val_lv,
1185  agg_type_lv});
1186 
1187  // handling returned null value if exists
1188  std::string null_handler_func_name{"handle_null_val_"};
1189  std::vector<llvm::Value*> null_handler_args{res_lv, null_val_lv};
1190 
1191  // determine null_handling function's name
1192  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1193  // average aggregate function returns a value as a double
1194  // (and our search* function also returns a double)
1195  if (agg_expr_ti.is_fp()) {
1196  // fp type: double null value
1197  null_handler_func_name += "double_double";
1198  } else {
1199  // non-fp type: int64_t null type
1200  null_handler_func_name += "double_int64_t";
1201  }
1202  } else if (agg_expr_ti.is_fp()) {
1203  // fp type: double null value
1204  null_handler_func_name += "double_double";
1205  } else {
1206  // non-fp type: int64_t null type
1207  null_handler_func_name += "int64_t_int64_t";
1208  }
1209  null_handler_func_name += "_window_framing_agg";
1210 
1211  // prepare null_val
1212  if (window_func->getKind() == SqlWindowFunctionKind::COUNT) {
1213  if (agg_expr_ti.is_fp()) {
1214  null_handler_args.push_back(cgen_state_->llFp((double)0));
1215  } else {
1216  null_handler_args.push_back(cgen_state_->llInt((int64_t)0));
1217  }
1218  } else if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1219  null_handler_args.push_back(cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE)));
1220  } else {
1221  null_handler_args.push_back(cgen_state_->castToTypeIn(window_func_null_val, 64));
1222  }
1223  res_lv = cgen_state_->emitCall(null_handler_func_name, null_handler_args);
1224 
1225  // when AGG_TYPE is double, we get a double type return value we expect an integer
1226  // type value for the count aggregation
1227  if (window_func->getKind() == SqlWindowFunctionKind::COUNT && agg_expr_ti.is_fp()) {
1228  return cgen_state_->ir_builder_.CreateFPToSI(
1229  res_lv, get_int_type(64, cgen_state_->context_));
1230  }
1231  return res_lv;
1232  } else {
1233  auto agg_name = get_window_agg_name(window_func->getKind(), window_func_ti);
1234  Analyzer::Expr* arg_target_expr;
1235  std::vector<llvm::Value*> agg_func_args{aggregate_state};
1236  auto modified_window_func_null_val = window_func_null_val;
1237  if (args.empty() ||
1238  (window_func->getKind() == SqlWindowFunctionKind::COUNT &&
1239  dynamic_cast<Analyzer::Constant*>(args.front().get()) != nullptr)) {
1240  // a count aggregation without an expression: COUNT(1) or COUNT(*)
1241  agg_func_args.push_back(cgen_state_->llInt(int64_t(1)));
1242  } else {
1243  // we use #base_agg_func_name##_skip_val agg function
1244  // i.e.,int64_t agg_sum_skip_val(int64_t* agg, int64_t val, int64_t skip_val)
1245  arg_target_expr = args.front().get();
1246  const auto arg_lvs = code_generator.codegen(arg_target_expr, true, co);
1247  CHECK_EQ(arg_lvs.size(), size_t(1));
1248  // handling current row's value
1249  auto crt_val = arg_lvs.front();
1250  if ((window_func->getKind() == SqlWindowFunctionKind::SUM ||
1251  window_func->getKind() == SqlWindowFunctionKind::SUM_IF) &&
1252  !window_func_ti.is_fp()) {
1253  crt_val = code_generator.codegenCastBetweenIntTypes(
1254  arg_lvs.front(), args.front()->get_type_info(), window_func_ti, false);
1255  }
1256  agg_func_args.push_back(window_func_ti.get_type() == kFLOAT
1257  ? crt_val
1258  : cgen_state_->castToTypeIn(crt_val, 64));
1259  // handle null value and conditional value for conditional aggregates if necessary
1260  llvm::Value* cond_lv{nullptr};
1261  if (window_function_conditional_aggregate(window_func->getKind())) {
1262  switch (window_func->getKind()) {
1264  // COUNT_IF has a single condition expr which is always bool type
1265  modified_window_func_null_val = cgen_state_->castToTypeIn(
1266  cgen_state_->inlineNull(SQLTypeInfo(kTINYINT)), 64);
1267  break;
1269  // FP type input col uses its own null value depending on the type
1270  // otherwise (integer type input col), we use 8-byte type
1271  if (args.front()->get_type_info().is_integer()) {
1272  agg_func_args[1] = cgen_state_->castToTypeIn(agg_func_args[1], 64);
1273  // keep the null value but casting its type to 8-byte
1274  modified_window_func_null_val =
1275  cgen_state_->castToTypeIn(window_func_null_val, 64);
1276  }
1277  auto cond_expr_lv = code_generator.codegen(args[1].get(), true, co).front();
1278  cond_lv =
1279  codegenConditionalAggregateCondValSelector(cond_expr_lv, kSUM_IF, co);
1280  }
1281  default:
1282  break;
1283  }
1284  }
1285  agg_name += "_skip_val";
1286  agg_func_args.push_back(modified_window_func_null_val);
1287  if (cond_lv) {
1288  agg_func_args.push_back(cond_lv);
1289  }
1290  }
1291  cgen_state_->emitCall(agg_name, agg_func_args);
1292  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1293  codegenWindowAvgEpilogue(agg_func_args[1], window_func_null_val);
1294  }
1295  return codegenAggregateWindowState();
1296  }
1297 }
1298 
1299 void Executor::codegenWindowAvgEpilogue(llvm::Value* crt_val,
1300  llvm::Value* window_func_null_val) {
1301  AUTOMATIC_IR_METADATA(cgen_state_.get());
1302  const auto window_func_context =
1304  const auto window_func = window_func_context->getWindowFunction();
1305  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1306  const auto pi32_type =
1307  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
1308  const auto pi64_type =
1309  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1310  const auto aggregate_state_type =
1311  window_func_ti.get_type() == kFLOAT ? pi32_type : pi64_type;
1312  const auto aggregate_state_count_i64 = cgen_state_->llInt(
1313  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
1314  auto aggregate_state_count = cgen_state_->ir_builder_.CreateIntToPtr(
1315  aggregate_state_count_i64, aggregate_state_type);
1316  std::string agg_count_func_name = "agg_count";
1317  switch (window_func_ti.get_type()) {
1318  case kFLOAT: {
1319  agg_count_func_name += "_float";
1320  break;
1321  }
1322  case kDOUBLE: {
1323  agg_count_func_name += "_double";
1324  break;
1325  }
1326  default: {
1327  break;
1328  }
1329  }
1330  agg_count_func_name += "_skip_val";
1331  cgen_state_->emitCall(agg_count_func_name,
1332  {aggregate_state_count, crt_val, window_func_null_val});
1333 }
1334 
1336  AUTOMATIC_IR_METADATA(cgen_state_.get());
1337  const auto pi32_type =
1338  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0);
1339  const auto pi64_type =
1340  llvm::PointerType::get(get_int_type(64, cgen_state_->context_), 0);
1341  const auto window_func_context =
1343  const Analyzer::WindowFunction* window_func = window_func_context->getWindowFunction();
1344  const auto window_func_ti = get_adjusted_window_type_info(window_func);
1345  const auto aggregate_state_type =
1346  window_func_ti.get_type() == kFLOAT ? pi32_type : pi64_type;
1347  auto aggregate_state = aggregateWindowStatePtr();
1348  if (window_func->getKind() == SqlWindowFunctionKind::AVG) {
1349  const auto aggregate_state_count_i64 = cgen_state_->llInt(
1350  reinterpret_cast<const int64_t>(window_func_context->aggregateStateCount()));
1351  auto aggregate_state_count = cgen_state_->ir_builder_.CreateIntToPtr(
1352  aggregate_state_count_i64, aggregate_state_type);
1353  const auto double_null_lv = cgen_state_->inlineFpNull(SQLTypeInfo(kDOUBLE));
1354  switch (window_func_ti.get_type()) {
1355  case kFLOAT: {
1356  return cgen_state_->emitCall(
1357  "load_avg_float", {aggregate_state, aggregate_state_count, double_null_lv});
1358  }
1359  case kDOUBLE: {
1360  return cgen_state_->emitCall(
1361  "load_avg_double", {aggregate_state, aggregate_state_count, double_null_lv});
1362  }
1363  case kDECIMAL: {
1364  return cgen_state_->emitCall(
1365  "load_avg_decimal",
1366  {aggregate_state,
1367  aggregate_state_count,
1368  double_null_lv,
1369  cgen_state_->llInt<int32_t>(window_func_ti.get_scale())});
1370  }
1371  default: {
1372  return cgen_state_->emitCall(
1373  "load_avg_int", {aggregate_state, aggregate_state_count, double_null_lv});
1374  }
1375  }
1376  }
1377  if (window_func->getKind() == SqlWindowFunctionKind::COUNT) {
1378  return cgen_state_->ir_builder_.CreateLoad(
1379  aggregate_state->getType()->getPointerElementType(), aggregate_state);
1380  }
1381  switch (window_func_ti.get_type()) {
1382  case kFLOAT: {
1383  return cgen_state_->emitCall("load_float", {aggregate_state});
1384  }
1385  case kDOUBLE: {
1386  return cgen_state_->emitCall("load_double", {aggregate_state});
1387  }
1388  default: {
1389  return cgen_state_->ir_builder_.CreateLoad(
1390  aggregate_state->getType()->getPointerElementType(), aggregate_state);
1391  }
1392  }
1393 }
1394 
1396  llvm::Value* cond_lv,
1397  SQLAgg const aggKind,
1398  CompilationOptions const& co) const {
1399  llvm::Value* res_cond_lv{nullptr};
1400  switch (aggKind) {
1401  case kSUM_IF:
1402  if (cond_lv->getType()->isIntegerTy(1)) {
1403  // cond_expr returns i1 type val, just need to cast to i8 type
1404  // i.e., cond_expr IS NULL
1405  res_cond_lv = cgen_state_->castToTypeIn(cond_lv, 8);
1406  } else {
1407  CHECK(cond_lv->getType()->isIntegerTy(8));
1408  // cond_expr may have null value instead of upcasted bool (i1-type) value
1409  // so we have to correctly set true condition
1410  // i.e., i8 @gt_int32_t_nullable_lhs(..., i64 -2147483648, i8 -128)
1411  // has one of the following i8-type values: 1, 0, -128
1412  auto true_cond_lv =
1413  cgen_state_->ir_builder_.CreateICmpEQ(cond_lv, cgen_state_->llInt((int8_t)1));
1414  res_cond_lv = cgen_state_->ir_builder_.CreateSelect(
1415  true_cond_lv, cgen_state_->llInt((int8_t)1), cgen_state_->llInt((int8_t)0));
1416  }
1417  break;
1418  default:
1419  break;
1420  }
1421  return res_cond_lv;
1422 }
std::string get_col_type_name_by_size(const size_t size, const bool is_fp)
static constexpr int64_t kSecsPerDay
bool hasRangeModeFraming() const
Definition: Analyzer.h:2610
SqlWindowFrameBoundType
Definition: sqldefs.h:150
bool isCurrentRowBound() const
Definition: Analyzer.h:2503
SQLAgg
Definition: sqldefs.h:73
#define CHECK_EQ(x, y)
Definition: Logger.h:301
llvm::Value * castToTypeIn(llvm::Value *val, const size_t bit_width)
Definition: CgenState.cpp:149
SqlWindowFunctionKind getKind() const
Definition: Analyzer.h:2576
llvm::Value * num_elem_current_partition_lv
Definition: WindowContext.h:94
HOST DEVICE int get_size() const
Definition: sqltypes.h:393
bool hasTimestampTypeFrameBound() const
Definition: Analyzer.h:2495
std::pair< std::string, llvm::Value * > codegenLoadOrderKeyBufPtr(WindowFunctionContext *window_func_context) const
std::pair< llvm::Value *, llvm::Value * > codegenFrameNullRange(WindowFunctionContext *window_func_context, llvm::Value *partition_index_lv) const
llvm::Value * current_col_value_lv
Definition: WindowContext.h:90
bool isFrameNavigateWindowFunction() const
Definition: Analyzer.h:2630
llvm::Value * codegenCurrentPartitionIndex(const WindowFunctionContext *window_func_context, llvm::Value *current_row_pos_lv)
Definition: sqltypes.h:66
int64_t * getNullValueEndPos() const
bool window_function_conditional_aggregate(const SqlWindowFunctionKind kind)
Definition: WindowContext.h:59
llvm::Value * current_partition_start_offset_lv
#define LOG(tag)
Definition: Logger.h:285
llvm::Value * current_row_pos_lv
Definition: WindowContext.h:89
llvm::Value * target_partition_rowid_ptr_lv
Definition: WindowContext.h:97
bool is_fp() const
Definition: sqltypes.h:584
llvm::Value * codegenFrameBound(bool for_start_bound, bool for_range_mode, bool for_window_frame_naviation, const Analyzer::WindowFrame *frame_bound, bool is_timestamp_type_frame, llvm::Value *order_key_null_val, const WindowFrameBoundFuncArgs &args)
llvm::Value * frame_end_bound_expr_lv
Definition: WindowContext.h:88
llvm::Value * num_elem_current_partition_lv
llvm::Value * nulls_first_lv
Definition: WindowContext.h:99
const std::vector< SQLTypeInfo > & getOrderKeyColumnBufferTypes() const
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:580
#define UNREACHABLE()
Definition: Logger.h:337
llvm::Value * aggregateWindowStatePtr()
size_t elementCount() const
llvm::Type * get_fp_type(const int width, llvm::LLVMContext &context)
std::string getFramingFuncName(const std::string &bound_type, const std::string &order_col_type, const std::string &op_type, bool for_timestamp_type) const
const int32_t * counts() const
const Analyzer::WindowFrame * getFrameStartBound() const
Definition: Analyzer.h:2588
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:381
llvm::Value * target_partition_sorted_rowid_ptr_lv
const Analyzer::WindowFrame * getFrameEndBound() const
Definition: Analyzer.h:2595
llvm::Value * target_partition_rowid_ptr_lv
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
const std::vector< std::shared_ptr< Analyzer::Expr > > & getOrderKeys() const
Definition: Analyzer.h:2584
static WindowFunctionContext * getActiveWindowFunctionContext(Executor *executor)
std::string get_window_agg_name(const SqlWindowFunctionKind kind, const SQLTypeInfo &window_func_ti)
int64_t * getNullValueStartPos() const
const int64_t * partitionStartOffset() const
size_t partitionCount() const
SqlWindowFrameBoundType getBoundType() const
Definition: Analyzer.h:2488
llvm::Value * codegenWindowPosition(const WindowFunctionContext *window_func_context, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:227
llvm::Value * null_start_pos_lv
static const WindowProjectNodeContext * get(Executor *executor)
const std::vector< std::shared_ptr< Analyzer::Expr > > & getArgs() const
Definition: Analyzer.h:2578
int get_logical_size() const
Definition: sqltypes.h:403
std::vector< llvm::Value * > prepareRangeModeFuncArgs(bool for_start_bound, const Analyzer::WindowFrame *frame_bound, bool is_timestamp_type_frame, llvm::Value *order_key_null_val, const WindowFrameBoundFuncArgs &frame_args) const
const SQLTypeInfo getFirstOrderColTypeInfo(WindowFunctionContext *window_func_context) const
const WindowFunctionContext * activateWindowFunctionContext(Executor *executor, const size_t target_index) const
std::pair< llvm::Value *, llvm::Value * > codegenWindowFrameBounds(WindowFunctionContext *window_func_context, const Analyzer::WindowFrame *frame_start_bound, const Analyzer::WindowFrame *frame_end_bound, llvm::Value *order_key_col_null_val_lv, WindowFrameBoundFuncArgs &args, CodeGenerator &code_generator)
llvm::Value * codegenCastBetweenIntTypes(llvm::Value *operand_lv, const SQLTypeInfo &operand_ti, const SQLTypeInfo &ti, bool upscale=true)
Definition: CastIR.cpp:427
const Analyzer::Expr * getBoundExpr() const
Definition: Analyzer.h:2490
llvm::ConstantFP * llFp(const float v) const
Definition: CgenState.h:246
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
llvm::Value * current_partition_start_offset_lv
Definition: WindowContext.h:91
Definition: sqltypes.h:70
llvm::Value * codegenLoadCurrentValueFromColBuf(WindowFunctionContext *window_func_context, CodeGenerator &code_generator, WindowFrameBoundFuncArgs &args) const
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:389
llvm::Value * target_partition_sorted_rowid_ptr_lv
Definition: WindowContext.h:98
const std::string getOrderKeyTypeName(WindowFunctionContext *window_func_context) const
llvm::Value * codegenConditionalAggregateCondValSelector(llvm::Value *cond_lv, SQLAgg const aggKind, CompilationOptions const &co) const
void codegenWindowFunctionStateInit(llvm::Value *aggregate_state)
constexpr float inline_fp_null_value< float >()
std::pair< llvm::Value *, llvm::Value * > codegenFrameBoundRange(const Analyzer::WindowFunction *window_func, CodeGenerator &code_generator, const CompilationOptions &co)
const std::vector< const int8_t * > & getOrderKeyColumnBuffers() const
void codegenWindowAvgEpilogue(llvm::Value *crt_val, llvm::Value *window_func_null_val)
constexpr double inline_fp_null_value< double >()
llvm::Value * null_end_pos_lv
const int64_t * partitionNumCountBuf() const
llvm::Value * toBool(llvm::Value *)
Definition: LogicalIR.cpp:343
SqlWindowFunctionKind
Definition: sqldefs.h:120
llvm::Value * codegenAggregateWindowState()
llvm::Value * codegenWindowNavigationFunctionOnFrame(const CompilationOptions &co)
llvm::Value * codegenFrameBoundExpr(const Analyzer::WindowFunction *window_func, const Analyzer::WindowFrame *frame_bound, CodeGenerator &code_generator, const CompilationOptions &co)
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:242
llvm::Value * codegenWindowFunctionAggregate(const CompilationOptions &co)
llvm::Value * order_key_buf_ptr_lv
Definition: WindowContext.h:95
#define CHECK(condition)
Definition: Logger.h:291
llvm::Value * int64_t_zero_val_lv
Definition: WindowContext.h:92
const int64_t * sortedPartition() const
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
int64_t inline_fixed_encoding_null_val(const SQL_TYPE_INFO &ti)
bool g_cluster
const Analyzer::WindowFunction * getWindowFunction() const
bool is_dict_encoded_string() const
Definition: sqltypes.h:632
Definition: sqltypes.h:62
const int32_t * payload() const
llvm::Value * get_null_value_by_size(CgenState *cgen_state, SQLTypeInfo col_ti)
size_t getOrderKeySize(WindowFunctionContext *window_func_context) const
llvm::Value * int64_t_one_val_lv
Definition: WindowContext.h:93
WindowPartitionBufferPtrs codegenLoadPartitionBuffers(WindowFunctionContext *window_func_context, llvm::Value *partition_index_lv) const
llvm::Value * codegenWindowFunctionAggregateCalls(llvm::Value *aggregate_state, const CompilationOptions &co)
llvm::Value * frame_start_bound_expr_lv
Definition: WindowContext.h:87
llvm::Value * codegenWindowFunction(const size_t target_index, const CompilationOptions &co)
std::string order_type_col_name
Definition: WindowContext.h:96
llvm::BasicBlock * codegenWindowResetStateControlFlow()
llvm::Value * get_null_value_by_size_with_encoding(CgenState *cgen_state, SQLTypeInfo col_ti)
std::vector< llvm::Value * > prepareRowModeFuncArgs(bool for_start_bound, SqlWindowFrameBoundType bound_type, const WindowFrameBoundFuncArgs &args) const
SQLTypeInfo get_adjusted_window_type_info(const Analyzer::WindowFunction *window_func)