OmniSciDB  5ade3759e0
ColumnIR.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, 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 "Codec.h"
19 #include "Execute.h"
20 #include "WindowContext.h"
21 
22 // Code generation routines and helpers for working with column expressions.
23 
24 namespace {
25 
26 // Return the right decoder for a given column expression. Doesn't handle
27 // variable length data. The decoder encapsulates the code generation logic.
28 std::shared_ptr<Decoder> get_col_decoder(const Analyzer::ColumnVar* col_var) {
29  const auto enc_type = col_var->get_compression();
30  const auto& ti = col_var->get_type_info();
31  switch (enc_type) {
32  case kENCODING_NONE: {
33  const auto int_type = ti.is_decimal() ? decimal_to_int_type(ti) : ti.get_type();
34  switch (int_type) {
35  case kBOOLEAN:
36  return std::make_shared<FixedWidthInt>(1);
37  case kTINYINT:
38  return std::make_shared<FixedWidthInt>(1);
39  case kSMALLINT:
40  return std::make_shared<FixedWidthInt>(2);
41  case kINT:
42  return std::make_shared<FixedWidthInt>(4);
43  case kBIGINT:
44  return std::make_shared<FixedWidthInt>(8);
45  case kFLOAT:
46  return std::make_shared<FixedWidthReal>(false);
47  case kDOUBLE:
48  return std::make_shared<FixedWidthReal>(true);
49  case kTIME:
50  case kTIMESTAMP:
51  case kDATE:
52  return std::make_shared<FixedWidthInt>(8);
53  default:
54  CHECK(false);
55  }
56  }
57  case kENCODING_DICT:
58  CHECK(ti.is_string());
59  // For dictionary-encoded columns encoded on less than 4 bytes, we can use
60  // unsigned representation for double the maximum cardinality. The inline
61  // null value is going to be the maximum value of the underlying type.
62  if (ti.get_size() < ti.get_logical_size()) {
63  return std::make_shared<FixedWidthUnsigned>(ti.get_size());
64  }
65  return std::make_shared<FixedWidthInt>(ti.get_size());
66  case kENCODING_FIXED: {
67  const auto bit_width = col_var->get_comp_param();
68  CHECK_EQ(0, bit_width % 8);
69  return std::make_shared<FixedWidthInt>(bit_width / 8);
70  }
72  CHECK(ti.is_date_in_days());
73  return col_var->get_comp_param() == 16 ? std::make_shared<FixedWidthSmallDate>(2)
74  : std::make_shared<FixedWidthSmallDate>(4);
75  }
76  default:
77  abort();
78  }
79 }
80 
81 size_t get_col_bit_width(const Analyzer::ColumnVar* col_var) {
82  const auto& type_info = col_var->get_type_info();
83  return get_bit_width(type_info);
84 }
85 
87  return col_var->get_rte_idx() == -1 ? 0 : col_var->get_rte_idx();
88 }
89 
90 } // namespace
91 
92 std::vector<llvm::Value*> CodeGenerator::codegenColumn(const Analyzer::ColumnVar* col_var,
93  const bool fetch_column,
94  const CompilationOptions& co) {
95  if (col_var->get_rte_idx() <= 0 ||
96  cgen_state_->outer_join_match_found_per_level_.empty() ||
97  !foundOuterJoinMatch(col_var->get_rte_idx())) {
98  return codegenColVar(col_var, fetch_column, true, co);
99  }
100  return codegenOuterJoinNullPlaceholder(col_var, fetch_column, co);
101 }
102 
103 std::vector<llvm::Value*> CodeGenerator::codegenColVar(const Analyzer::ColumnVar* col_var,
104  const bool fetch_column,
105  const bool update_query_plan,
106  const CompilationOptions& co) {
107  const bool hoist_literals = co.hoist_literals_;
108  auto col_id = col_var->get_column_id();
109  const int rte_idx = adjusted_range_table_index(col_var);
110  CHECK_LT(static_cast<size_t>(rte_idx), cgen_state_->frag_offsets_.size());
111  const auto catalog = executor()->getCatalog();
112  CHECK(catalog);
113  if (col_var->get_table_id() > 0) {
114  auto cd = get_column_descriptor(col_id, col_var->get_table_id(), *catalog);
115  if (cd->isVirtualCol) {
116  CHECK(cd->columnName == "rowid");
117  return {codegenRowId(col_var, co)};
118  }
119  auto col_ti = cd->columnType;
120  if (col_ti.get_physical_coord_cols() > 0) {
121  std::vector<llvm::Value*> cols;
122  for (auto i = 0; i < col_ti.get_physical_coord_cols(); i++) {
123  auto cd0 =
124  get_column_descriptor(col_id + i + 1, col_var->get_table_id(), *catalog);
125  auto col0_ti = cd0->columnType;
126  CHECK(!cd0->isVirtualCol);
127  auto col0_var = makeExpr<Analyzer::ColumnVar>(
128  col0_ti, col_var->get_table_id(), cd0->columnId, rte_idx);
129  auto col = codegenColVar(col0_var.get(), fetch_column, false, co);
130  cols.insert(cols.end(), col.begin(), col.end());
131  if (!fetch_column && plan_state_->isLazyFetchColumn(col_var)) {
132  plan_state_->columns_to_not_fetch_.insert(
133  std::make_pair(col_var->get_table_id(), col0_var->get_column_id()));
134  }
135  }
136  if (!fetch_column && plan_state_->isLazyFetchColumn(col_var)) {
137  plan_state_->columns_to_not_fetch_.insert(
138  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
139  } else {
140  plan_state_->columns_to_fetch_.insert(
141  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
142  }
143  return cols;
144  }
145  } else {
146  if (col_var->get_type_info().is_geometry()) {
147  throw std::runtime_error(
148  "Geospatial columns not supported in temporary tables yet");
149  }
150  }
151  const auto grouped_col_lv = resolveGroupedColumnReference(col_var);
152  if (grouped_col_lv) {
153  return {grouped_col_lv};
154  }
155  const int local_col_id = plan_state_->getLocalColumnId(col_var, fetch_column);
156  const auto window_func_context =
158  // only generate the decoding code once; if a column has been previously
159  // fetched in the generated IR, we'll reuse it
160  if (!window_func_context) {
161  auto it = cgen_state_->fetch_cache_.find(local_col_id);
162  if (it != cgen_state_->fetch_cache_.end()) {
163  return {it->second};
164  }
165  }
166  const auto hash_join_lhs = hashJoinLhs(col_var);
167  // Use the already fetched left-hand side of an equi-join if the types are identical.
168  // Currently, types can only be different because of different underlying dictionaries.
169  if (hash_join_lhs && hash_join_lhs->get_type_info() == col_var->get_type_info()) {
170  if (plan_state_->isLazyFetchColumn(col_var)) {
171  plan_state_->columns_to_fetch_.insert(
172  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
173  }
174  return codegen(hash_join_lhs.get(), fetch_column, co);
175  }
176  auto pos_arg = posArg(col_var);
177  if (window_func_context) {
178  pos_arg = codegenWindowPosition(window_func_context, pos_arg);
179  }
180  auto col_byte_stream = colByteStream(col_var, fetch_column, hoist_literals);
181  if (plan_state_->isLazyFetchColumn(col_var)) {
182  if (update_query_plan) {
183  plan_state_->columns_to_not_fetch_.insert(
184  std::make_pair(col_var->get_table_id(), col_var->get_column_id()));
185  }
186  if (rte_idx > 0) {
187  const auto offset = cgen_state_->frag_offsets_[rte_idx];
188  if (offset) {
189  return {cgen_state_->ir_builder_.CreateAdd(pos_arg, offset)};
190  } else {
191  return {pos_arg};
192  }
193  }
194  return {pos_arg};
195  }
196  const auto& col_ti = col_var->get_type_info();
197  if (col_ti.is_string() && col_ti.get_compression() == kENCODING_NONE) {
198  const auto varlen_str_column_lvs =
199  codegenVariableLengthStringColVar(col_byte_stream, pos_arg);
200  if (!window_func_context) {
201  auto it_ok = cgen_state_->fetch_cache_.insert(
202  std::make_pair(local_col_id, varlen_str_column_lvs));
203  CHECK(it_ok.second);
204  }
205  return varlen_str_column_lvs;
206  }
207  if (col_ti.is_array()) {
208  return {col_byte_stream};
209  }
210  if (window_func_context) {
211  return {codegenFixedLengthColVarInWindow(col_var, col_byte_stream, pos_arg)};
212  }
213  const auto fixed_length_column_lv =
214  codegenFixedLengthColVar(col_var, col_byte_stream, pos_arg);
215  auto it_ok = cgen_state_->fetch_cache_.insert(
216  std::make_pair(local_col_id, std::vector<llvm::Value*>{fixed_length_column_lv}));
217  CHECK(it_ok.second);
218  return {it_ok.first->second};
219 }
220 
222  WindowFunctionContext* window_func_context,
223  llvm::Value* pos_arg) {
224  const auto window_position = cgen_state_->emitCall(
225  "row_number_window_func",
226  {cgen_state_->llInt(reinterpret_cast<const int64_t>(window_func_context->output())),
227  pos_arg});
228  window_func_context->setRowNumber(window_position);
229  return window_position;
230 }
231 
232 // Generate code for fixed length column types (number, timestamp or date,
233 // dictionary-encoded string)
235  llvm::Value* col_byte_stream,
236  llvm::Value* pos_arg) {
237  const auto decoder = get_col_decoder(col_var);
238  auto dec_val = decoder->codegenDecode(col_byte_stream, pos_arg, cgen_state_->module_);
239  cgen_state_->ir_builder_.Insert(dec_val);
240  auto dec_type = dec_val->getType();
241  llvm::Value* dec_val_cast{nullptr};
242  const auto& col_ti = col_var->get_type_info();
243  if (dec_type->isIntegerTy()) {
244  auto dec_width = static_cast<llvm::IntegerType*>(dec_type)->getBitWidth();
245  auto col_width = get_col_bit_width(col_var);
246  dec_val_cast = cgen_state_->ir_builder_.CreateCast(
247  static_cast<size_t>(col_width) > dec_width ? llvm::Instruction::CastOps::SExt
248  : llvm::Instruction::CastOps::Trunc,
249  dec_val,
250  get_int_type(col_width, cgen_state_->context_));
251  if ((col_ti.get_compression() == kENCODING_FIXED ||
252  (col_ti.get_compression() == kENCODING_DICT && col_ti.get_size() < 4)) &&
253  !col_ti.get_notnull()) {
254  dec_val_cast = codgenAdjustFixedEncNull(dec_val_cast, col_ti);
255  }
256  } else {
257  CHECK_EQ(kENCODING_NONE, col_ti.get_compression());
258  CHECK(dec_type->isFloatTy() || dec_type->isDoubleTy());
259  if (dec_type->isDoubleTy()) {
260  CHECK(col_ti.get_type() == kDOUBLE);
261  } else if (dec_type->isFloatTy()) {
262  CHECK(col_ti.get_type() == kFLOAT);
263  }
264  dec_val_cast = dec_val;
265  }
266  CHECK(dec_val_cast);
267  return dec_val_cast;
268 }
269 
271  const Analyzer::ColumnVar* col_var,
272  llvm::Value* col_byte_stream,
273  llvm::Value* pos_arg) {
274  const auto orig_bb = cgen_state_->ir_builder_.GetInsertBlock();
275  const auto pos_is_valid =
276  cgen_state_->ir_builder_.CreateICmpSGE(pos_arg, cgen_state_->llInt(int64_t(0)));
277  const auto pos_valid_bb = llvm::BasicBlock::Create(
278  cgen_state_->context_, "window.pos_valid", cgen_state_->row_func_);
279  const auto pos_notvalid_bb = llvm::BasicBlock::Create(
280  cgen_state_->context_, "window.pos_notvalid", cgen_state_->row_func_);
281  cgen_state_->ir_builder_.CreateCondBr(pos_is_valid, pos_valid_bb, pos_notvalid_bb);
282  cgen_state_->ir_builder_.SetInsertPoint(pos_valid_bb);
283  const auto fixed_length_column_lv =
284  codegenFixedLengthColVar(col_var, col_byte_stream, pos_arg);
285  cgen_state_->ir_builder_.CreateBr(pos_notvalid_bb);
286  cgen_state_->ir_builder_.SetInsertPoint(pos_notvalid_bb);
287  const auto window_func_call_phi =
288  cgen_state_->ir_builder_.CreatePHI(fixed_length_column_lv->getType(), 2);
289  window_func_call_phi->addIncoming(fixed_length_column_lv, pos_valid_bb);
290  const auto& col_ti = col_var->get_type_info();
291  const auto null_lv =
292  col_ti.is_fp() ? static_cast<llvm::Value*>(cgen_state_->inlineFpNull(col_ti))
293  : static_cast<llvm::Value*>(cgen_state_->inlineIntNull(col_ti));
294  window_func_call_phi->addIncoming(null_lv, orig_bb);
295  return window_func_call_phi;
296 }
297 
299  llvm::Value* col_byte_stream,
300  llvm::Value* pos_arg) {
301  // real (not dictionary-encoded) strings; store the pointer to the payload
302  auto ptr_and_len =
303  cgen_state_->emitExternalCall("string_decode",
304  get_int_type(64, cgen_state_->context_),
305  {col_byte_stream, pos_arg});
306  // Unpack the pointer + length, see string_decode function.
307  auto str_lv = cgen_state_->emitCall("extract_str_ptr", {ptr_and_len});
308  auto len_lv = cgen_state_->emitCall("extract_str_len", {ptr_and_len});
309  return {ptr_and_len, str_lv, len_lv};
310 }
311 
313  const CompilationOptions& co) {
314  const auto offset_lv = cgen_state_->frag_offsets_[adjusted_range_table_index(col_var)];
315  llvm::Value* start_rowid_lv{nullptr};
316  const auto& table_generation = executor()->getTableGeneration(col_var->get_table_id());
317  if (table_generation.start_rowid > 0) {
318  // Handle the multi-node case: each leaf receives a start rowid used
319  // to offset the local rowid and generate a cluster-wide unique rowid.
320  Datum d;
321  d.bigintval = table_generation.start_rowid;
322  const auto start_rowid = makeExpr<Analyzer::Constant>(kBIGINT, false, d);
323  const auto start_rowid_lvs = codegen(start_rowid.get(), kENCODING_NONE, -1, co);
324  CHECK_EQ(size_t(1), start_rowid_lvs.size());
325  start_rowid_lv = start_rowid_lvs.front();
326  }
327  auto rowid_lv = posArg(col_var);
328  if (offset_lv) {
329  rowid_lv = cgen_state_->ir_builder_.CreateAdd(rowid_lv, offset_lv);
330  } else if (col_var->get_rte_idx() > 0) {
331  auto frag_off_ptr = get_arg_by_name(cgen_state_->row_func_, "frag_row_off");
332  auto input_off_ptr = cgen_state_->ir_builder_.CreateGEP(
333  frag_off_ptr, cgen_state_->llInt(int32_t(col_var->get_rte_idx())));
334  auto rowid_offset_lv = cgen_state_->ir_builder_.CreateLoad(input_off_ptr);
335  rowid_lv = cgen_state_->ir_builder_.CreateAdd(rowid_lv, rowid_offset_lv);
336  }
337  if (table_generation.start_rowid > 0) {
338  CHECK(start_rowid_lv);
339  rowid_lv = cgen_state_->ir_builder_.CreateAdd(rowid_lv, start_rowid_lv);
340  }
341  return rowid_lv;
342 }
343 
344 namespace {
345 
346 SQLTypes get_phys_int_type(const size_t byte_sz) {
347  switch (byte_sz) {
348  case 1:
349  return kBOOLEAN;
350  // TODO: kTINYINT
351  case 2:
352  return kSMALLINT;
353  case 4:
354  return kINT;
355  case 8:
356  return kBIGINT;
357  default:
358  CHECK(false);
359  }
360  return kNULLT;
361 }
362 
363 } // namespace
364 
365 llvm::Value* CodeGenerator::codgenAdjustFixedEncNull(llvm::Value* val,
366  const SQLTypeInfo& col_ti) {
367  CHECK_LT(col_ti.get_size(), col_ti.get_logical_size());
368  const auto col_phys_width = col_ti.get_size() * 8;
369  auto from_typename = "int" + std::to_string(col_phys_width) + "_t";
370  auto adjusted = cgen_state_->ir_builder_.CreateCast(
371  llvm::Instruction::CastOps::Trunc,
372  val,
373  get_int_type(col_phys_width, cgen_state_->context_));
374  if (col_ti.get_compression() == kENCODING_DICT) {
375  from_typename = "u" + from_typename;
376  llvm::Value* from_null{nullptr};
377  switch (col_ti.get_size()) {
378  case 1:
379  from_null = cgen_state_->llInt(std::numeric_limits<uint8_t>::max());
380  break;
381  case 2:
382  from_null = cgen_state_->llInt(std::numeric_limits<uint16_t>::max());
383  break;
384  default:
385  CHECK(false);
386  }
387  return cgen_state_->emitCall(
388  "cast_" + from_typename + "_to_" + numeric_type_name(col_ti) + "_nullable",
389  {adjusted, from_null, cgen_state_->inlineIntNull(col_ti)});
390  }
391  SQLTypeInfo col_phys_ti(get_phys_int_type(col_ti.get_size()),
392  col_ti.get_dimension(),
393  col_ti.get_scale(),
394  false,
396  0,
397  col_ti.get_subtype());
398  return cgen_state_->emitCall(
399  "cast_" + from_typename + "_to_" + numeric_type_name(col_ti) + "_nullable",
400  {adjusted,
401  cgen_state_->inlineIntNull(col_phys_ti),
402  cgen_state_->inlineIntNull(col_ti)});
403 }
404 
405 llvm::Value* CodeGenerator::foundOuterJoinMatch(const ssize_t nesting_level) const {
406  CHECK_GE(nesting_level, ssize_t(0));
407  CHECK_LE(nesting_level,
408  static_cast<ssize_t>(cgen_state_->outer_join_match_found_per_level_.size()));
409  return cgen_state_->outer_join_match_found_per_level_[nesting_level - 1];
410 }
411 
413  const Analyzer::ColumnVar* col_var,
414  const bool fetch_column,
415  const CompilationOptions& co) {
416  const auto grouped_col_lv = resolveGroupedColumnReference(col_var);
417  if (grouped_col_lv) {
418  return {grouped_col_lv};
419  }
420  const auto bb = cgen_state_->ir_builder_.GetInsertBlock();
421  const auto outer_join_args_bb = llvm::BasicBlock::Create(
422  cgen_state_->context_, "outer_join_args", cgen_state_->row_func_);
423  const auto outer_join_nulls_bb = llvm::BasicBlock::Create(
424  cgen_state_->context_, "outer_join_nulls", cgen_state_->row_func_);
425  const auto phi_bb = llvm::BasicBlock::Create(
426  cgen_state_->context_, "outer_join_phi", cgen_state_->row_func_);
427  cgen_state_->ir_builder_.SetInsertPoint(bb);
428  const auto outer_join_match_lv = foundOuterJoinMatch(col_var->get_rte_idx());
429  CHECK(outer_join_match_lv);
430  cgen_state_->ir_builder_.CreateCondBr(
431  outer_join_match_lv, outer_join_args_bb, outer_join_nulls_bb);
432  const auto back_from_outer_join_bb = llvm::BasicBlock::Create(
433  cgen_state_->context_, "back_from_outer_join", cgen_state_->row_func_);
434  cgen_state_->ir_builder_.SetInsertPoint(outer_join_args_bb);
435  Executor::FetchCacheAnchor anchor(cgen_state_);
436  const auto orig_lvs = codegenColVar(col_var, fetch_column, true, co);
437  cgen_state_->ir_builder_.CreateBr(phi_bb);
438  cgen_state_->ir_builder_.SetInsertPoint(outer_join_nulls_bb);
439  const auto& null_ti = col_var->get_type_info();
440  if ((null_ti.is_string() && null_ti.get_compression() == kENCODING_NONE) ||
441  null_ti.is_array() || null_ti.is_geometry()) {
442  throw std::runtime_error("Projection type " + null_ti.get_type_name() +
443  " not supported for outer joins yet");
444  }
445  const auto null_constant = makeExpr<Analyzer::Constant>(null_ti, true, Datum{0});
446  const auto null_target_lvs =
447  codegen(null_constant.get(),
448  false,
451  cgen_state_->ir_builder_.CreateBr(phi_bb);
452  CHECK_EQ(orig_lvs.size(), null_target_lvs.size());
453  cgen_state_->ir_builder_.SetInsertPoint(phi_bb);
454  std::vector<llvm::Value*> target_lvs;
455  for (size_t i = 0; i < orig_lvs.size(); ++i) {
456  const auto target_type = orig_lvs[i]->getType();
457  CHECK_EQ(target_type, null_target_lvs[i]->getType());
458  auto target_phi = cgen_state_->ir_builder_.CreatePHI(target_type, 2);
459  target_phi->addIncoming(orig_lvs[i], outer_join_args_bb);
460  target_phi->addIncoming(null_target_lvs[i], outer_join_nulls_bb);
461  target_lvs.push_back(target_phi);
462  }
463  cgen_state_->ir_builder_.CreateBr(back_from_outer_join_bb);
464  cgen_state_->ir_builder_.SetInsertPoint(back_from_outer_join_bb);
465  return target_lvs;
466 }
467 
469  const Analyzer::ColumnVar* col_var) {
470  auto col_id = col_var->get_column_id();
471  if (col_var->get_rte_idx() >= 0) {
472  return nullptr;
473  }
474  CHECK((col_id == 0) || (col_var->get_rte_idx() >= 0 && col_var->get_table_id() > 0));
475  const auto var = dynamic_cast<const Analyzer::Var*>(col_var);
476  CHECK(var);
477  col_id = var->get_varno();
478  CHECK_GE(col_id, 1);
479  if (var->get_which_row() == Analyzer::Var::kGROUPBY) {
480  CHECK_LE(static_cast<size_t>(col_id), cgen_state_->group_by_expr_cache_.size());
481  return cgen_state_->group_by_expr_cache_[col_id - 1];
482  }
483  return nullptr;
484 }
485 
486 // returns the byte stream argument and the position for the given column
488  const bool fetch_column,
489  const bool hoist_literals) {
490  CHECK_GE(cgen_state_->row_func_->arg_size(), size_t(3));
491  const auto stream_arg_name =
492  "col_buf" + std::to_string(plan_state_->getLocalColumnId(col_var, fetch_column));
493  for (auto& arg : cgen_state_->row_func_->args()) {
494  if (arg.getName() == stream_arg_name) {
495  CHECK(arg.getType() == llvm::Type::getInt8PtrTy(cgen_state_->context_));
496  return &arg;
497  }
498  }
499  CHECK(false);
500  return nullptr;
501 }
502 
503 llvm::Value* CodeGenerator::posArg(const Analyzer::Expr* expr) const {
504  const auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(expr);
505  if (col_var && col_var->get_rte_idx() > 0) {
506  const auto hash_pos_it =
507  cgen_state_->scan_idx_to_hash_pos_.find(col_var->get_rte_idx());
508  CHECK(hash_pos_it != cgen_state_->scan_idx_to_hash_pos_.end());
509  if (hash_pos_it->second->getType()->isPointerTy()) {
510  CHECK(hash_pos_it->second->getType()->getPointerElementType()->isIntegerTy(32));
511  llvm::Value* result = cgen_state_->ir_builder_.CreateLoad(hash_pos_it->second);
512  result = cgen_state_->ir_builder_.CreateSExt(
513  result, get_int_type(64, cgen_state_->context_));
514  return result;
515  }
516  return hash_pos_it->second;
517  }
518  for (auto& arg : cgen_state_->row_func_->args()) {
519  if (arg.getName() == "pos") {
520  CHECK(arg.getType()->isIntegerTy(64));
521  return &arg;
522  }
523  }
524  abort();
525 }
526 
528  const auto uoper = dynamic_cast<const Analyzer::UOper*>(expr);
529  if (!uoper || uoper->get_optype() != kCAST) {
530  return nullptr;
531  }
532  const auto& target_ti = uoper->get_type_info();
533  if (!target_ti.is_integer()) {
534  return nullptr;
535  }
536  return uoper->get_operand();
537 }
538 
539 std::shared_ptr<const Analyzer::Expr> CodeGenerator::hashJoinLhs(
540  const Analyzer::ColumnVar* rhs) const {
541  for (const auto tautological_eq : plan_state_->join_info_.equi_join_tautologies_) {
542  CHECK(IS_EQUIVALENCE(tautological_eq->get_optype()));
543  if (dynamic_cast<const Analyzer::ExpressionTuple*>(
544  tautological_eq->get_left_operand())) {
545  auto lhs_col = hashJoinLhsTuple(rhs, tautological_eq.get());
546  if (lhs_col) {
547  return lhs_col;
548  }
549  } else {
550  auto eq_right_op = tautological_eq->get_right_operand();
551  if (!rhs->get_type_info().is_string()) {
552  eq_right_op = remove_cast_to_int(eq_right_op);
553  }
554  if (!eq_right_op) {
555  eq_right_op = tautological_eq->get_right_operand();
556  }
557  if (*eq_right_op == *rhs) {
558  auto eq_left_op = tautological_eq->get_left_operand();
559  if (!eq_left_op->get_type_info().is_string()) {
560  eq_left_op = remove_cast_to_int(eq_left_op);
561  }
562  if (!eq_left_op) {
563  eq_left_op = tautological_eq->get_left_operand();
564  }
565  if (eq_left_op->get_type_info().is_geometry()) {
566  // skip cast for a geospatial lhs, since the rhs is likely to be a geospatial
567  // physical col without geospatial type info
568  return nullptr;
569  }
570  const auto eq_left_op_col = dynamic_cast<const Analyzer::ColumnVar*>(eq_left_op);
571  CHECK(eq_left_op_col);
572  if (eq_left_op_col->get_rte_idx() != 0) {
573  return nullptr;
574  }
575  if (rhs->get_type_info().is_string()) {
576  return eq_left_op->deep_copy();
577  }
578  return makeExpr<Analyzer::UOper>(
579  rhs->get_type_info(), false, kCAST, eq_left_op->deep_copy());
580  }
581  }
582  }
583  return nullptr;
584 }
585 
586 std::shared_ptr<const Analyzer::ColumnVar> CodeGenerator::hashJoinLhsTuple(
587  const Analyzer::ColumnVar* rhs,
588  const Analyzer::BinOper* tautological_eq) const {
589  const auto lhs_tuple_expr =
590  dynamic_cast<const Analyzer::ExpressionTuple*>(tautological_eq->get_left_operand());
591  const auto rhs_tuple_expr = dynamic_cast<const Analyzer::ExpressionTuple*>(
592  tautological_eq->get_right_operand());
593  CHECK(lhs_tuple_expr && rhs_tuple_expr);
594  const auto& lhs_tuple = lhs_tuple_expr->getTuple();
595  const auto& rhs_tuple = rhs_tuple_expr->getTuple();
596  CHECK_EQ(lhs_tuple.size(), rhs_tuple.size());
597  for (size_t i = 0; i < lhs_tuple.size(); ++i) {
598  if (*rhs_tuple[i] == *rhs) {
599  const auto lhs_col =
600  std::static_pointer_cast<const Analyzer::ColumnVar>(lhs_tuple[i]);
601  return lhs_col->get_rte_idx() == 0 ? lhs_col : nullptr;
602  }
603  }
604  return nullptr;
605 }
#define CHECK_EQ(x, y)
Definition: Logger.h:195
std::shared_ptr< const Analyzer::ColumnVar > hashJoinLhsTuple(const Analyzer::ColumnVar *rhs, const Analyzer::BinOper *tautological_eq) const
Definition: ColumnIR.cpp:586
void d(const SQLTypes expected_type, const std::string &str)
Definition: ImportTest.cpp:268
HOST DEVICE int get_size() const
Definition: sqltypes.h:333
int get_column_id() const
Definition: Analyzer.h:194
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:325
const Analyzer::Expr * remove_cast_to_int(const Analyzer::Expr *expr)
Definition: ColumnIR.cpp:527
Definition: sqltypes.h:51
bool is_fp() const
Definition: sqltypes.h:454
SQLTypes
Definition: sqltypes.h:40
std::shared_ptr< const Analyzer::Expr > hashJoinLhs(const Analyzer::ColumnVar *rhs) const
Definition: ColumnIR.cpp:539
#define IS_EQUIVALENCE(X)
Definition: sqldefs.h:67
llvm::Value * codegenRowId(const Analyzer::ColumnVar *col_var, const CompilationOptions &co)
Definition: ColumnIR.cpp:312
std::vector< llvm::Value * > codegenOuterJoinNullPlaceholder(const Analyzer::ColumnVar *col_var, const bool fetch_column, const CompilationOptions &co)
Definition: ColumnIR.cpp:412
HOST DEVICE int get_scale() const
Definition: sqltypes.h:328
#define CHECK_GE(x, y)
Definition: Logger.h:200
llvm::Value * codgenAdjustFixedEncNull(llvm::Value *, const SQLTypeInfo &)
Definition: ColumnIR.cpp:365
Definition: sqldefs.h:49
virtual std::vector< llvm::Value * > codegenColumn(const Analyzer::ColumnVar *, const bool fetch_column, const CompilationOptions &)
Definition: ColumnIR.cpp:92
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:331
std::shared_ptr< Decoder > get_col_decoder(const Analyzer::ColumnVar *col_var)
Definition: ColumnIR.cpp:28
std::string to_string(char const *&&v)
size_t get_bit_width(const SQLTypeInfo &ti)
llvm::Value * get_arg_by_name(llvm::Function *func, const std::string &name)
Definition: Execute.h:114
size_t get_col_bit_width(const Analyzer::ColumnVar *col_var)
Definition: ColumnIR.cpp:81
void setRowNumber(llvm::Value *row_number)
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:324
int64_t bigintval
Definition: sqltypes.h:126
llvm::Value * foundOuterJoinMatch(const ssize_t nesting_level) const
Definition: ColumnIR.cpp:405
std::vector< llvm::Value * > codegenColVar(const Analyzer::ColumnVar *, const bool fetch_column, const bool update_query_plan, const CompilationOptions &)
Definition: ColumnIR.cpp:103
SQLTypes decimal_to_int_type(const SQLTypeInfo &ti)
Definition: Datum.cpp:268
#define CHECK_LT(x, y)
Definition: Logger.h:197
Definition: sqltypes.h:55
#define CHECK_LE(x, y)
Definition: Logger.h:198
EncodingType get_compression() const
Definition: Analyzer.h:196
int get_rte_idx() const
Definition: Analyzer.h:195
int get_table_id() const
Definition: Analyzer.h:193
llvm::Value * codegenFixedLengthColVarInWindow(const Analyzer::ColumnVar *col_var, llvm::Value *col_byte_stream, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:270
int get_logical_size() const
Definition: sqltypes.h:334
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:77
const int8_t * output() const
llvm::Value * posArg(const Analyzer::Expr *) const
Definition: ColumnIR.cpp:503
#define CHECK(condition)
Definition: Logger.h:187
llvm::Value * colByteStream(const Analyzer::ColumnVar *col_var, const bool fetch_column, const bool hoist_literals)
Definition: ColumnIR.cpp:487
bool is_geometry() const
Definition: sqltypes.h:462
llvm::Value * codegenWindowPosition(WindowFunctionContext *window_func_context, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:221
std::string numeric_type_name(const SQLTypeInfo &ti)
Definition: Execute.h:157
Definition: sqltypes.h:47
SQLTypeInfo columnType
std::vector< llvm::Value * > codegenVariableLengthStringColVar(llvm::Value *col_byte_stream, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:298
llvm::Value * codegenFixedLengthColVar(const Analyzer::ColumnVar *col_var, llvm::Value *col_byte_stream, llvm::Value *pos_arg)
Definition: ColumnIR.cpp:234
SQLTypes get_phys_int_type(const size_t byte_sz)
Definition: ColumnIR.cpp:346
bool is_string() const
Definition: sqltypes.h:450
int adjusted_range_table_index(const Analyzer::ColumnVar *col_var)
Definition: ColumnIR.cpp:86
int get_comp_param() const
Definition: Analyzer.h:197
static WindowFunctionContext * getActiveWindowFunctionContext()
const ColumnDescriptor * get_column_descriptor(const int col_id, const int table_id, const Catalog_Namespace::Catalog &cat)
Definition: Execute.h:139
llvm::Value * resolveGroupedColumnReference(const Analyzer::ColumnVar *)
Definition: ColumnIR.cpp:468
const Expr * get_right_operand() const
Definition: Analyzer.h:436
const Expr * get_left_operand() const
Definition: Analyzer.h:435