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