OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HashJoin.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 
18 
22 #include "QueryEngine/Execute.h"
30 
31 #include <sstream>
32 
36 
38  const std::vector<double>& inverse_bucket_sizes_for_dimension,
39  const std::vector<InnerOuter> inner_outer_pairs) {
40  join_buckets.clear();
41 
42  CHECK_EQ(inner_outer_pairs.size(), join_columns.size());
43  CHECK_EQ(join_columns.size(), join_column_types.size());
44  for (size_t i = 0; i < join_columns.size(); i++) {
45  const auto& inner_outer_pair = inner_outer_pairs[i];
46  const auto inner_col = inner_outer_pair.first;
47  const auto& ti = inner_col->get_type_info();
48  const auto elem_ti = ti.get_elem_type();
49  // CHECK(elem_ti.is_fp());
50 
51  join_buckets.emplace_back(JoinBucketInfo{inverse_bucket_sizes_for_dimension,
52  elem_ti.get_type() == kDOUBLE});
53  }
54 }
55 
61  const Analyzer::ColumnVar* hash_col,
62  const std::vector<Fragmenter_Namespace::FragmentInfo>& fragment_info,
63  const Data_Namespace::MemoryLevel effective_memory_level,
64  const int device_id,
65  std::vector<std::shared_ptr<Chunk_NS::Chunk>>& chunks_owner,
66  DeviceAllocator* dev_buff_owner,
67  std::vector<std::shared_ptr<void>>& malloc_owner,
68  Executor* executor,
69  ColumnCacheMap* column_cache) {
70  static std::mutex fragment_fetch_mutex;
71  std::lock_guard<std::mutex> fragment_fetch_lock(fragment_fetch_mutex);
72  try {
73  JoinColumn join_column = ColumnFetcher::makeJoinColumn(executor,
74  *hash_col,
75  fragment_info,
76  effective_memory_level,
77  device_id,
78  dev_buff_owner,
79  /*thread_idx=*/0,
80  chunks_owner,
81  malloc_owner,
82  *column_cache);
83  if (effective_memory_level == Data_Namespace::GPU_LEVEL) {
84  CHECK(dev_buff_owner);
85  auto device_col_chunks_buff = dev_buff_owner->alloc(join_column.col_chunks_buff_sz);
86  dev_buff_owner->copyToDevice(device_col_chunks_buff,
87  join_column.col_chunks_buff,
88  join_column.col_chunks_buff_sz);
89  join_column.col_chunks_buff = device_col_chunks_buff;
90  }
91  return join_column;
92  } catch (...) {
93  throw FailedToFetchColumn();
94  }
95 }
96 
97 namespace {
98 
99 template <typename T>
100 std::string toStringFlat(const HashJoin* hash_table,
101  const ExecutorDeviceType device_type,
102  const int device_id) {
103  auto mem =
104  reinterpret_cast<const T*>(hash_table->getJoinHashBuffer(device_type, device_id));
105  auto memsz = hash_table->getJoinHashBufferSize(device_type, device_id) / sizeof(T);
106  std::string txt;
107  for (size_t i = 0; i < memsz; ++i) {
108  if (i > 0) {
109  txt += ", ";
110  }
111  txt += std::to_string(mem[i]);
112  }
113  return txt;
114 }
115 
116 } // anonymous namespace
117 
118 std::string HashJoin::toStringFlat64(const ExecutorDeviceType device_type,
119  const int device_id) const {
120  return toStringFlat<int64_t>(this, device_type, device_id);
121 }
122 
123 std::string HashJoin::toStringFlat32(const ExecutorDeviceType device_type,
124  const int device_id) const {
125  return toStringFlat<int32_t>(this, device_type, device_id);
126 }
127 
128 std::ostream& operator<<(std::ostream& os, const DecodedJoinHashBufferEntry& e) {
129  os << " {{";
130  bool first = true;
131  for (auto k : e.key) {
132  if (!first) {
133  os << ",";
134  } else {
135  first = false;
136  }
137  os << k;
138  }
139  os << "}, ";
140  os << "{";
141  first = true;
142  for (auto p : e.payload) {
143  if (!first) {
144  os << ", ";
145  } else {
146  first = false;
147  }
148  os << p;
149  }
150  os << "}}";
151  return os;
152 }
153 
154 std::ostream& operator<<(std::ostream& os, const DecodedJoinHashBufferSet& s) {
155  os << "{\n";
156  bool first = true;
157  for (auto e : s) {
158  if (!first) {
159  os << ",\n";
160  } else {
161  first = false;
162  }
163  os << e;
164  }
165  if (!s.empty()) {
166  os << "\n";
167  }
168  os << "}\n";
169  return os;
170 }
171 
172 std::ostream& operator<<(std::ostream& os,
173  const InnerOuterStringOpInfos& inner_outer_string_op_infos) {
174  os << "(" << inner_outer_string_op_infos.first << ", "
175  << inner_outer_string_op_infos.second << ")";
176  return os;
177 }
178 
179 std::string toString(const InnerOuterStringOpInfos& inner_outer_string_op_infos) {
180  std::ostringstream os;
181  os << inner_outer_string_op_infos;
182  return os.str();
183 }
184 
185 std::ostream& operator<<(
186  std::ostream& os,
187  const std::vector<InnerOuterStringOpInfos>& inner_outer_string_op_infos_pairs) {
188  os << "[";
189  bool first_elem = true;
190  for (const auto& inner_outer_string_op_infos : inner_outer_string_op_infos_pairs) {
191  if (!first_elem) {
192  os << ", ";
193  }
194  first_elem = false;
195  os << inner_outer_string_op_infos;
196  }
197  os << "]";
198  return os;
199 }
200 
201 std::string toString(
202  const std::vector<InnerOuterStringOpInfos>& inner_outer_string_op_infos_pairs) {
203  std::ostringstream os;
204  os << inner_outer_string_op_infos_pairs;
205  return os.str();
206 }
207 
209  const std::vector<llvm::Value*>& hash_join_idx_args_in,
210  const bool is_sharded,
211  const bool col_is_nullable,
212  const bool is_bw_eq,
213  const int64_t sub_buff_size,
214  Executor* executor,
215  bool is_bucketized) {
216  AUTOMATIC_IR_METADATA(executor->cgen_state_.get());
217  using namespace std::string_literals;
218 
219  std::string fname(is_bucketized ? "bucketized_hash_join_idx"s : "hash_join_idx"s);
220 
221  if (is_bw_eq) {
222  fname += "_bitwise";
223  }
224  if (is_sharded) {
225  fname += "_sharded";
226  }
227  if (!is_bw_eq && col_is_nullable) {
228  fname += "_nullable";
229  }
230 
231  const auto slot_lv = executor->cgen_state_->emitCall(fname, hash_join_idx_args_in);
232  const auto slot_valid_lv = executor->cgen_state_->ir_builder_.CreateICmpSGE(
233  slot_lv, executor->cgen_state_->llInt(int64_t(0)));
234 
235  auto pos_ptr = hash_join_idx_args_in[0];
236  CHECK(pos_ptr);
237 
238  auto count_ptr = executor->cgen_state_->ir_builder_.CreateAdd(
239  pos_ptr, executor->cgen_state_->llInt(sub_buff_size));
240  auto hash_join_idx_args = hash_join_idx_args_in;
241  hash_join_idx_args[0] = executor->cgen_state_->ir_builder_.CreatePtrToInt(
242  count_ptr, llvm::Type::getInt64Ty(executor->cgen_state_->context_));
243 
244  const auto row_count_lv = executor->cgen_state_->ir_builder_.CreateSelect(
245  slot_valid_lv,
246  executor->cgen_state_->emitCall(fname, hash_join_idx_args),
247  executor->cgen_state_->llInt(int64_t(0)));
248  auto rowid_base_i32 = executor->cgen_state_->ir_builder_.CreateIntToPtr(
249  executor->cgen_state_->ir_builder_.CreateAdd(
250  pos_ptr, executor->cgen_state_->llInt(2 * sub_buff_size)),
251  llvm::Type::getInt32PtrTy(executor->cgen_state_->context_));
252  auto rowid_ptr_i32 = executor->cgen_state_->ir_builder_.CreateGEP(
253  rowid_base_i32->getType()->getScalarType()->getPointerElementType(),
254  rowid_base_i32,
255  slot_lv);
256  return {rowid_ptr_i32, row_count_lv, slot_lv};
257 }
258 
259 llvm::Value* HashJoin::codegenHashTableLoad(const size_t table_idx, Executor* executor) {
260  AUTOMATIC_IR_METADATA(executor->cgen_state_.get());
261  llvm::Value* hash_ptr = nullptr;
262  const auto total_table_count =
263  executor->plan_state_->join_info_.join_hash_tables_.size();
264  CHECK_LT(table_idx, total_table_count);
265  if (total_table_count > 1) {
266  auto hash_tables_ptr =
267  get_arg_by_name(executor->cgen_state_->row_func_, "join_hash_tables");
268  auto hash_pptr =
269  table_idx > 0
270  ? executor->cgen_state_->ir_builder_.CreateGEP(
271  hash_tables_ptr->getType()->getScalarType()->getPointerElementType(),
272  hash_tables_ptr,
273  executor->cgen_state_->llInt(static_cast<int64_t>(table_idx)))
274  : hash_tables_ptr;
275  hash_ptr = executor->cgen_state_->ir_builder_.CreateLoad(
276  hash_pptr->getType()->getPointerElementType(), hash_pptr);
277  } else {
278  hash_ptr = get_arg_by_name(executor->cgen_state_->row_func_, "join_hash_tables");
279  }
280  CHECK(hash_ptr);
281  return hash_ptr;
282 }
283 
285 std::shared_ptr<HashJoin> HashJoin::getInstance(
286  const std::shared_ptr<Analyzer::BinOper> qual_bin_oper,
287  const std::vector<InputTableInfo>& query_infos,
288  const Data_Namespace::MemoryLevel memory_level,
289  const JoinType join_type,
290  const HashType preferred_hash_type,
291  const int device_count,
292  ColumnCacheMap& column_cache,
293  Executor* executor,
294  const HashTableBuildDagMap& hashtable_build_dag_map,
295  const RegisteredQueryHint& query_hint,
296  const TableIdToNodeMap& table_id_to_node_map) {
297  auto timer = DEBUG_TIMER(__func__);
298  std::shared_ptr<HashJoin> join_hash_table;
299  CHECK_GT(device_count, 0);
300  if (!g_enable_bbox_intersect_hashjoin && qual_bin_oper->is_bbox_intersect_oper()) {
301  throw std::runtime_error(
302  "Bounding box intersection disabled, attempting to fall back to loop join");
303  }
304  if (qual_bin_oper->is_bbox_intersect_oper()) {
305  VLOG(1) << "Trying to build geo hash table:";
306  join_hash_table =
308  query_infos,
309  memory_level,
310  join_type,
311  device_count,
312  column_cache,
313  executor,
314  hashtable_build_dag_map,
315  query_hint,
316  table_id_to_node_map);
317  } else if (dynamic_cast<const Analyzer::ExpressionTuple*>(
318  qual_bin_oper->get_left_operand()) ||
319  query_hint.force_baseline_hash_join) {
320  if (query_hint.force_baseline_hash_join) {
321  LOG(INFO) << "A user's query hint forced the join operation to use the Baseline "
322  "hash join layout";
323  }
324  VLOG(1) << "Trying to build keyed hash table:";
325  join_hash_table = BaselineJoinHashTable::getInstance(qual_bin_oper,
326  query_infos,
327  memory_level,
328  join_type,
329  preferred_hash_type,
330  device_count,
331  column_cache,
332  executor,
333  hashtable_build_dag_map,
334  query_hint,
335  table_id_to_node_map);
336  } else {
337  try {
338  VLOG(1) << "Trying to build perfect hash table:";
339  join_hash_table = PerfectJoinHashTable::getInstance(qual_bin_oper,
340  query_infos,
341  memory_level,
342  join_type,
343  preferred_hash_type,
344  device_count,
345  column_cache,
346  executor,
347  hashtable_build_dag_map,
348  query_hint,
349  table_id_to_node_map);
350  } catch (JoinHashTableTooBig& e) {
351  throw e;
352  } catch (TooManyHashEntries& e) {
353  const auto join_quals = coalesce_singleton_equi_join(qual_bin_oper);
354  CHECK_EQ(join_quals.size(), size_t(1));
355  const auto join_qual =
356  std::dynamic_pointer_cast<Analyzer::BinOper>(join_quals.front());
357  VLOG(1) << "Building a perfect join hash table fails: " << e.what();
358  VLOG(1) << "Trying to re-build keyed join hash table";
359  join_hash_table = BaselineJoinHashTable::getInstance(join_qual,
360  query_infos,
361  memory_level,
362  join_type,
363  preferred_hash_type,
364  device_count,
365  column_cache,
366  executor,
367  hashtable_build_dag_map,
368  query_hint,
369  table_id_to_node_map);
370  }
371  }
372  CHECK(join_hash_table);
373  if (VLOGGING(2)) {
374  if (join_hash_table->getMemoryLevel() == Data_Namespace::MemoryLevel::GPU_LEVEL) {
375  for (int device_id = 0; device_id < join_hash_table->getDeviceCount();
376  ++device_id) {
377  if (join_hash_table->getJoinHashBufferSize(ExecutorDeviceType::GPU, device_id) <=
378  1000) {
379  VLOG(2) << "Built GPU hash table: "
380  << join_hash_table->toString(ExecutorDeviceType::GPU, device_id);
381  }
382  }
383  } else {
384  if (join_hash_table->getJoinHashBufferSize(ExecutorDeviceType::CPU) <= 1000) {
385  VLOG(2) << "Built CPU hash table: "
386  << join_hash_table->toString(ExecutorDeviceType::CPU);
387  }
388  }
389  }
390  return join_hash_table;
391 }
392 
393 std::pair<const StringDictionaryProxy*, StringDictionaryProxy*>
395  const Executor* executor,
396  const bool has_string_ops) {
397  const auto inner_col = cols.first;
398  CHECK(inner_col);
399  const auto inner_ti = inner_col->get_type_info();
400  const auto outer_col = dynamic_cast<const Analyzer::ColumnVar*>(cols.second);
401  std::pair<const StringDictionaryProxy*, StringDictionaryProxy*>
402  inner_outer_str_dict_proxies{nullptr, nullptr};
403  if (inner_ti.is_string() && outer_col) {
404  const auto& outer_ti = outer_col->get_type_info();
405  CHECK(outer_ti.is_string());
406  inner_outer_str_dict_proxies.first =
407  executor->getStringDictionaryProxy(inner_ti.getStringDictKey(), true);
408  CHECK(inner_outer_str_dict_proxies.first);
409  inner_outer_str_dict_proxies.second =
410  executor->getStringDictionaryProxy(outer_ti.getStringDictKey(), true);
411  CHECK(inner_outer_str_dict_proxies.second);
412  if (!has_string_ops &&
413  *inner_outer_str_dict_proxies.first == *inner_outer_str_dict_proxies.second) {
414  // Dictionaries are the same - don't need to translate
415  CHECK_EQ(inner_ti.getStringDictKey(), outer_ti.getStringDictKey());
416  inner_outer_str_dict_proxies.first = nullptr;
417  inner_outer_str_dict_proxies.second = nullptr;
418  }
419  }
420  return inner_outer_str_dict_proxies;
421 }
422 
424  const InnerOuter& cols,
425  const InnerOuterStringOpInfos& inner_outer_string_op_infos,
426  ExpressionRange& col_range,
427  const Executor* executor) {
428  const bool has_string_ops = inner_outer_string_op_infos.first.size() ||
429  inner_outer_string_op_infos.second.size();
430  const auto inner_outer_proxies =
431  HashJoin::getStrDictProxies(cols, executor, has_string_ops);
432  const bool translate_dictionary =
433  inner_outer_proxies.first && inner_outer_proxies.second;
434  if (translate_dictionary) {
435  const auto& inner_dict_id = inner_outer_proxies.first->getDictKey();
436  const auto& outer_dict_id = inner_outer_proxies.second->getDictKey();
437  CHECK(has_string_ops || inner_dict_id != outer_dict_id);
438  const auto id_map = executor->getJoinIntersectionStringProxyTranslationMap(
439  inner_outer_proxies.first,
440  inner_outer_proxies.second,
441  inner_outer_string_op_infos.first,
442  inner_outer_string_op_infos.second,
443  executor->getRowSetMemoryOwner());
444  if (!inner_outer_string_op_infos.second.empty()) {
445  // String op was applied to lhs table,
446  // need to expand column range appropriately
447  col_range = ExpressionRange::makeIntRange(
448  std::min(col_range.getIntMin(),
449  static_cast<int64_t>(
450  inner_outer_proxies.second->transientEntryCount() + 1) *
451  -1),
452  col_range.getIntMax(),
453  0,
454  col_range.hasNulls());
455  }
456  return id_map;
457  }
458  return nullptr;
459 }
460 
462  const std::vector<Fragmenter_Namespace::FragmentInfo>& fragments) {
463  auto const fragment_id = [](auto const& frag_info) { return frag_info.fragmentId; };
464  std::vector<int> frag_ids(fragments.size());
465  std::transform(fragments.cbegin(), fragments.cend(), frag_ids.begin(), fragment_id);
466  std::sort(frag_ids.begin(), frag_ids.end());
467  return frag_ids;
468 }
469 
471  const std::vector<InnerOuter>& inner_outer_pairs,
472  const Executor* executor,
473  const std::vector<InnerOuterStringOpInfos>& inner_outer_string_op_infos_pairs) {
474  CHECK(executor);
475  std::vector<const void*> sd_inner_proxy_per_key;
476  std::vector<void*> sd_outer_proxy_per_key;
477  std::vector<ChunkKey> cache_key_chunks; // used for the cache key
478  const bool has_string_op_infos = inner_outer_string_op_infos_pairs.size();
479  if (has_string_op_infos) {
480  CHECK_EQ(inner_outer_pairs.size(), inner_outer_string_op_infos_pairs.size());
481  }
482  size_t string_op_info_pairs_idx = 0;
483  for (const auto& inner_outer_pair : inner_outer_pairs) {
484  const auto inner_col = inner_outer_pair.first;
485  const auto outer_col = inner_outer_pair.second;
486  const auto& inner_ti = inner_col->get_type_info();
487  const auto& outer_ti = outer_col->get_type_info();
488  if (inner_ti.is_string() && outer_ti.is_string() &&
489  inner_ti.is_dict_encoded_string() != outer_ti.is_dict_encoded_string()) {
490  throw std::runtime_error(
491  "Detected a join between dictionary-encoded and none-encoded text columns. "
492  "Please consider applying dictionary-encoding for the other column.");
493  }
494  const auto& inner_column_key = inner_col->getColumnKey();
495  ChunkKey cache_key_chunks_for_column{
496  inner_column_key.db_id, inner_column_key.table_id, inner_column_key.column_id};
497  if (inner_ti.is_string() &&
498  (!(inner_ti.getStringDictKey() == outer_ti.getStringDictKey()) ||
499  (has_string_op_infos &&
500  (inner_outer_string_op_infos_pairs[string_op_info_pairs_idx].first.size() ||
501  inner_outer_string_op_infos_pairs[string_op_info_pairs_idx].second.size())))) {
502  CHECK(outer_ti.is_string());
503  StringDictionaryProxy* sd_inner_proxy{nullptr};
504  StringDictionaryProxy* sd_outer_proxy{nullptr};
505  if (inner_ti.get_compression() == kENCODING_DICT) {
506  sd_inner_proxy = executor->getStringDictionaryProxy(
507  inner_ti.getStringDictKey(), executor->getRowSetMemoryOwner(), true);
508  sd_inner_proxy_per_key.push_back(sd_inner_proxy);
509  }
510  if (outer_ti.get_compression() == kENCODING_DICT) {
511  sd_outer_proxy = executor->getStringDictionaryProxy(
512  outer_ti.getStringDictKey(), executor->getRowSetMemoryOwner(), true);
513  sd_outer_proxy_per_key.push_back(sd_outer_proxy);
514  cache_key_chunks_for_column.push_back(sd_outer_proxy->getGeneration());
515  }
516  } else {
517  sd_inner_proxy_per_key.emplace_back();
518  sd_outer_proxy_per_key.emplace_back();
519  cache_key_chunks_for_column.push_back({-1});
520  }
521  cache_key_chunks.push_back(cache_key_chunks_for_column);
522  string_op_info_pairs_idx++;
523  }
524  return {sd_inner_proxy_per_key, sd_outer_proxy_per_key, cache_key_chunks};
525 }
526 
527 std::vector<const StringDictionaryProxy::IdMap*>
529  const CompositeKeyInfo& composite_key_info,
530  const std::vector<InnerOuterStringOpInfos>& string_op_infos_for_keys,
531  const Executor* executor) {
532  const auto& inner_proxies = composite_key_info.sd_inner_proxy_per_key;
533  const auto& outer_proxies = composite_key_info.sd_outer_proxy_per_key;
534  const size_t num_proxies = inner_proxies.size();
535  CHECK_EQ(num_proxies, outer_proxies.size());
536  std::vector<const StringDictionaryProxy::IdMap*> proxy_translation_maps;
537  proxy_translation_maps.reserve(num_proxies);
538  for (size_t proxy_pair_idx = 0; proxy_pair_idx < num_proxies; ++proxy_pair_idx) {
539  const bool translate_proxies =
540  inner_proxies[proxy_pair_idx] && outer_proxies[proxy_pair_idx];
541  if (translate_proxies) {
542  const auto inner_proxy =
543  reinterpret_cast<const StringDictionaryProxy*>(inner_proxies[proxy_pair_idx]);
544  auto outer_proxy =
545  reinterpret_cast<StringDictionaryProxy*>(outer_proxies[proxy_pair_idx]);
546  CHECK(inner_proxy);
547  CHECK(outer_proxy);
548 
549  CHECK_NE(inner_proxy->getDictKey(), outer_proxy->getDictKey());
550  proxy_translation_maps.emplace_back(
551  executor->getJoinIntersectionStringProxyTranslationMap(
552  inner_proxy,
553  outer_proxy,
554  string_op_infos_for_keys[proxy_pair_idx].first,
555  string_op_infos_for_keys[proxy_pair_idx].second,
556  executor->getRowSetMemoryOwner()));
557  } else {
558  proxy_translation_maps.emplace_back(nullptr);
559  }
560  }
561  return proxy_translation_maps;
562 }
563 
565  const Analyzer::Expr* col_or_string_oper,
566  const std::vector<StringOps_Namespace::StringOpInfo>& string_op_infos,
567  CodeGenerator& code_generator,
568  const CompilationOptions& co) {
569  if (!string_op_infos.empty()) {
570  const auto coerced_col_var =
571  dynamic_cast<const Analyzer::ColumnVar*>(col_or_string_oper);
572  CHECK(coerced_col_var);
573  std::vector<llvm::Value*> codegen_val_vec{
574  code_generator.codegenPseudoStringOper(coerced_col_var, string_op_infos, co)};
575  return codegen_val_vec[0];
576  }
577  return code_generator.codegen(col_or_string_oper, true, co)[0];
578 }
579 
580 std::shared_ptr<Analyzer::ColumnVar> getSyntheticColumnVar(
581  std::string_view table,
582  std::string_view column,
583  int rte_idx,
584  const Catalog_Namespace::Catalog& catalog) {
585  auto tmeta = catalog.getMetadataForTable(std::string(table));
586  CHECK(tmeta);
587 
588  auto cmeta = catalog.getMetadataForColumn(tmeta->tableId, std::string(column));
589  CHECK(cmeta);
590 
591  auto ti = cmeta->columnType;
592 
593  if (ti.is_geometry() && ti.get_type() != kPOINT) {
594  int geoColumnId{0};
595  switch (ti.get_type()) {
596  case kLINESTRING: {
597  geoColumnId = cmeta->columnId + 2;
598  break;
599  }
600  case kPOLYGON: {
601  geoColumnId = cmeta->columnId + 3;
602  break;
603  }
604  case kMULTIPOLYGON: {
605  geoColumnId = cmeta->columnId + 4;
606  break;
607  }
608  default:
609  CHECK(false);
610  }
611  cmeta = catalog.getMetadataForColumn(tmeta->tableId, geoColumnId);
612  CHECK(cmeta);
613  ti = cmeta->columnType;
614  }
615 
616  auto cv = std::make_shared<Analyzer::ColumnVar>(
617  ti,
618  shared::ColumnKey{catalog.getDatabaseId(), tmeta->tableId, cmeta->columnId},
619  rte_idx);
620  return cv;
621 }
622 
624  : public ScalarExprVisitor<std::set<const Analyzer::ColumnVar*>> {
625  protected:
626  std::set<const Analyzer::ColumnVar*> visitColumnVar(
627  const Analyzer::ColumnVar* column) const override {
628  return {column};
629  }
630 
631  std::set<const Analyzer::ColumnVar*> visitColumnVarTuple(
632  const Analyzer::ExpressionTuple* expr_tuple) const override {
633  AllColumnVarsVisitor visitor;
634  std::set<const Analyzer::ColumnVar*> result;
635  for (const auto& expr_component : expr_tuple->getTuple()) {
636  const auto component_rte_set = visitor.visit(expr_component.get());
637  result.insert(component_rte_set.begin(), component_rte_set.end());
638  }
639  return result;
640  }
641 
642  std::set<const Analyzer::ColumnVar*> aggregateResult(
643  const std::set<const Analyzer::ColumnVar*>& aggregate,
644  const std::set<const Analyzer::ColumnVar*>& next_result) const override {
645  auto result = aggregate;
646  result.insert(next_result.begin(), next_result.end());
647  return result;
648  }
649 };
650 
651 void setupSyntheticCaching(std::set<const Analyzer::ColumnVar*> cvs, Executor* executor) {
652  std::unordered_set<shared::TableKey> phys_table_ids;
653  for (auto cv : cvs) {
654  phys_table_ids.insert(cv->getTableKey());
655  }
656 
657  std::unordered_set<PhysicalInput> phys_inputs;
658  for (auto cv : cvs) {
659  const auto& column_key = cv->getColumnKey();
660  phys_inputs.emplace(
661  PhysicalInput{column_key.column_id, column_key.table_id, column_key.db_id});
662  }
663 
664  executor->setupCaching(phys_inputs, phys_table_ids);
665 }
666 
667 std::vector<InputTableInfo> getSyntheticInputTableInfo(
668  std::set<const Analyzer::ColumnVar*> cvs,
669  Executor* executor) {
670  std::unordered_set<shared::TableKey> phys_table_ids;
671  for (auto cv : cvs) {
672  phys_table_ids.insert(cv->getTableKey());
673  }
674 
675  // NOTE(sy): This vector ordering seems to work for now, but maybe we need to
676  // review how rte_idx is assigned for ColumnVars. See for example Analyzer.h
677  // and RelAlgExecutor.cpp and rte_idx there.
678  std::vector<InputTableInfo> query_infos;
679  query_infos.reserve(phys_table_ids.size());
680  for (const auto& table_key : phys_table_ids) {
681  auto td = Catalog_Namespace::get_metadata_for_table(table_key);
682  CHECK(td);
683  query_infos.push_back({table_key, td->fragmenter->getFragmentsForQuery()});
684  }
685 
686  return query_infos;
687 }
688 
690 std::shared_ptr<HashJoin> HashJoin::getSyntheticInstance(
691  std::string_view table1,
692  std::string_view column1,
693  const Catalog_Namespace::Catalog& catalog1,
694  std::string_view table2,
695  std::string_view column2,
696  const Catalog_Namespace::Catalog& catalog2,
697  const Data_Namespace::MemoryLevel memory_level,
698  const HashType preferred_hash_type,
699  const int device_count,
700  ColumnCacheMap& column_cache,
701  Executor* executor) {
702  auto a1 = getSyntheticColumnVar(table1, column1, 0, catalog1);
703  auto a2 = getSyntheticColumnVar(table2, column2, 1, catalog2);
704 
705  auto qual_bin_oper = std::make_shared<Analyzer::BinOper>(kBOOLEAN, kEQ, kONE, a1, a2);
706 
707  std::set<const Analyzer::ColumnVar*> cvs =
708  AllColumnVarsVisitor().visit(qual_bin_oper.get());
709  auto query_infos = getSyntheticInputTableInfo(cvs, executor);
710  setupSyntheticCaching(cvs, executor);
712 
713  auto hash_table = HashJoin::getInstance(qual_bin_oper,
714  query_infos,
715  memory_level,
717  preferred_hash_type,
718  device_count,
719  column_cache,
720  executor,
721  {},
722  query_hint,
723  {});
724  return hash_table;
725 }
726 
728 std::shared_ptr<HashJoin> HashJoin::getSyntheticInstance(
729  const std::shared_ptr<Analyzer::BinOper> qual_bin_oper,
730  const Data_Namespace::MemoryLevel memory_level,
731  const HashType preferred_hash_type,
732  const int device_count,
733  ColumnCacheMap& column_cache,
734  Executor* executor) {
735  std::set<const Analyzer::ColumnVar*> cvs =
736  AllColumnVarsVisitor().visit(qual_bin_oper.get());
737  auto query_infos = getSyntheticInputTableInfo(cvs, executor);
738  setupSyntheticCaching(cvs, executor);
740 
741  auto hash_table = HashJoin::getInstance(qual_bin_oper,
742  query_infos,
743  memory_level,
745  preferred_hash_type,
746  device_count,
747  column_cache,
748  executor,
749  {},
750  query_hint,
751  {});
752  return hash_table;
753 }
754 
755 std::pair<std::string, std::shared_ptr<HashJoin>> HashJoin::getSyntheticInstance(
756  std::vector<std::shared_ptr<Analyzer::BinOper>> qual_bin_opers,
757  const Data_Namespace::MemoryLevel memory_level,
758  const HashType preferred_hash_type,
759  const int device_count,
760  ColumnCacheMap& column_cache,
761  Executor* executor) {
762  std::set<const Analyzer::ColumnVar*> cvs;
763  for (auto& qual : qual_bin_opers) {
764  auto cv = AllColumnVarsVisitor().visit(qual.get());
765  cvs.insert(cv.begin(), cv.end());
766  }
767  auto query_infos = getSyntheticInputTableInfo(cvs, executor);
768  setupSyntheticCaching(cvs, executor);
770  std::shared_ptr<HashJoin> hash_table;
771  std::string error_msg;
772  for (auto& qual : qual_bin_opers) {
773  try {
774  auto candidate_hash_table = HashJoin::getInstance(qual,
775  query_infos,
776  memory_level,
778  preferred_hash_type,
779  device_count,
780  column_cache,
781  executor,
782  {},
783  query_hint,
784  {});
785  if (candidate_hash_table) {
786  hash_table = candidate_hash_table;
787  }
788  } catch (HashJoinFail& e) {
789  error_msg = e.what();
790  continue;
791  }
792  }
793  return std::make_pair(error_msg, hash_table);
794 }
795 
797  const size_t shard_count,
798  const Executor* executor) {
799  if (!g_cluster) {
800  return;
801  }
802  if (table_key.table_id >= 0) {
803  CHECK(executor);
804  const auto inner_td = Catalog_Namespace::get_metadata_for_table(table_key);
805  CHECK(inner_td);
806  if (!shard_count && !table_is_replicated(inner_td)) {
807  throw TableMustBeReplicated(inner_td->tableName);
808  }
809  }
810 }
811 
812 template <typename T>
814  auto* target_expr = expr;
815  if (auto cast_expr = dynamic_cast<const Analyzer::UOper*>(expr)) {
816  target_expr = cast_expr->get_operand();
817  }
818  CHECK(target_expr);
819  return dynamic_cast<const T*>(target_expr);
820 }
821 
822 std::pair<InnerOuter, InnerOuterStringOpInfos> HashJoin::normalizeColumnPair(
823  const Analyzer::Expr* lhs,
824  const Analyzer::Expr* rhs,
825  const TemporaryTables* temporary_tables,
826  const bool is_bbox_intersect) {
827  SQLTypeInfo lhs_ti = lhs->get_type_info();
828  SQLTypeInfo rhs_ti = rhs->get_type_info();
829  if (!is_bbox_intersect) {
830  if (lhs_ti.get_type() != rhs_ti.get_type()) {
831  throw HashJoinFail("Equijoin types must be identical, found: " +
832  lhs_ti.get_type_name() + ", " + rhs_ti.get_type_name());
833  }
834  if (!lhs_ti.is_integer() && !lhs_ti.is_time() && !lhs_ti.is_string() &&
835  !lhs_ti.is_decimal()) {
836  throw HashJoinFail("Cannot apply hash join to inner column type " +
837  lhs_ti.get_type_name());
838  }
839  // Decimal types should be identical.
840  if (lhs_ti.is_decimal() && (lhs_ti.get_scale() != rhs_ti.get_scale() ||
841  lhs_ti.get_precision() != rhs_ti.get_precision())) {
842  throw HashJoinFail("Equijoin with different decimal types");
843  }
844  }
845 
846  const auto lhs_cast = dynamic_cast<const Analyzer::UOper*>(lhs);
847  const auto rhs_cast = dynamic_cast<const Analyzer::UOper*>(rhs);
848  if (lhs_ti.is_string() && (static_cast<bool>(lhs_cast) != static_cast<bool>(rhs_cast) ||
849  (lhs_cast && lhs_cast->get_optype() != kCAST) ||
850  (rhs_cast && rhs_cast->get_optype() != kCAST))) {
851  throw HashJoinFail(
852  "Cannot use hash join for given expression (non-cast unary operator)");
853  }
854  // Casts to decimal are not suported.
855  if (lhs_ti.is_decimal() && (lhs_cast || rhs_cast)) {
856  throw HashJoinFail("Cannot use hash join for given expression (cast to decimal)");
857  }
858  auto lhs_col = getHashJoinColumn<Analyzer::ColumnVar>(lhs);
859  auto rhs_col = getHashJoinColumn<Analyzer::ColumnVar>(rhs);
860 
861  const auto lhs_string_oper = getHashJoinColumn<Analyzer::StringOper>(lhs);
862  const auto rhs_string_oper = getHashJoinColumn<Analyzer::StringOper>(rhs);
863 
864  auto process_string_op_infos = [](const auto& string_oper, auto& col, auto& ti) {
865  std::vector<StringOps_Namespace::StringOpInfo> string_op_infos;
866  if (string_oper) {
867  col = dynamic_cast<const Analyzer::ColumnVar*>(string_oper->getArg(0));
868  if (!col) {
869  // Todo (todd): Allow for non-colvar inputs into string operators for
870  // join predicates
871  // We now guard against non constant/colvar/stringoper inputs
872  // in Analyzer::StringOper::check_operand_types, but keeping this to not
873  // depend on that logic if and when it changes as allowing non-colvar inputs
874  // for hash joins will be additional work on top of allowing them
875  // outside of join predicates
876  throw HashJoinFail(
877  "Hash joins involving string operators currently restricted to column inputs "
878  "(i.e. not case statements).");
879  }
880  ti = col->get_type_info();
881  CHECK(ti.is_dict_encoded_string());
882  const auto chained_string_op_exprs = string_oper->getChainedStringOpExprs();
883  CHECK_GT(chained_string_op_exprs.size(), 0UL);
884  for (const auto& chained_string_op_expr : chained_string_op_exprs) {
885  auto chained_string_op =
886  dynamic_cast<const Analyzer::StringOper*>(chained_string_op_expr.get());
887  CHECK(chained_string_op);
888  StringOps_Namespace::StringOpInfo string_op_info(
889  chained_string_op->get_kind(),
890  chained_string_op->get_type_info(),
891  chained_string_op->getLiteralArgs());
892  string_op_infos.emplace_back(string_op_info);
893  }
894  }
895  return string_op_infos;
896  };
897 
898  auto outer_string_op_infos = process_string_op_infos(lhs_string_oper, lhs_col, lhs_ti);
899  auto inner_string_op_infos = process_string_op_infos(rhs_string_oper, rhs_col, rhs_ti);
900 
901  if (!lhs_col && !rhs_col) {
902  throw HashJoinFail(
903  "Cannot use hash join for given expression (both lhs and rhs are invalid)",
905  }
906 
907  const Analyzer::ColumnVar* inner_col{nullptr};
908  const Analyzer::ColumnVar* outer_col{nullptr};
909  auto outer_ti = lhs_ti;
910  auto inner_ti = rhs_ti;
911  const Analyzer::Expr* outer_expr{lhs};
912  InnerQualDecision inner_qual_decision = InnerQualDecision::UNKNOWN;
913  if (!lhs_col || (rhs_col && lhs_col->get_rte_idx() < rhs_col->get_rte_idx())) {
914  inner_qual_decision = InnerQualDecision::RHS;
915  inner_col = rhs_col;
916  outer_col = lhs_col;
917  } else {
918  inner_qual_decision = InnerQualDecision::LHS;
919  if (lhs_col && lhs_col->get_rte_idx() == 0) {
920  throw HashJoinFail(
921  "Cannot use hash join for given expression (lhs' rte idx is zero)",
922  inner_qual_decision);
923  }
924  inner_col = lhs_col;
925  outer_col = rhs_col;
926  std::swap(outer_ti, inner_ti);
927  std::swap(outer_string_op_infos, inner_string_op_infos);
928  outer_expr = rhs;
929  }
930  if (!inner_col) {
931  throw HashJoinFail("Cannot use hash join for given expression (invalid inner col)",
932  inner_qual_decision);
933  }
934  if (!outer_col) {
935  // check whether outer_col is a constant, i.e., inner_col = K;
936  const auto outer_constant_col = dynamic_cast<const Analyzer::Constant*>(outer_expr);
937  if (outer_constant_col) {
938  throw HashJoinFail(
939  "Cannot use hash join for given expression: try to join with a constant "
940  "value",
941  inner_qual_decision);
942  }
943  MaxRangeTableIndexVisitor rte_idx_visitor;
944  int outer_rte_idx = rte_idx_visitor.visit(outer_expr);
945  // The inner column candidate is not actually inner; the outer
946  // expression contains columns which are at least as deep.
947  if (inner_col->get_rte_idx() <= outer_rte_idx) {
948  throw HashJoinFail(
949  "Cannot use hash join for given expression (inner's rte <= outer's rte)",
950  inner_qual_decision);
951  }
952  }
953  // We need to fetch the actual type information from the catalog since Analyzer
954  // always reports nullable as true for inner table columns in left joins.
955  const auto& column_key = inner_col->getColumnKey();
956  const auto inner_col_cd = get_column_descriptor_maybe(column_key);
957  const auto inner_col_real_ti = get_column_type(
958  column_key.column_id, column_key.table_id, inner_col_cd, temporary_tables);
959  const auto& outer_col_ti =
960  !(dynamic_cast<const Analyzer::FunctionOper*>(lhs)) && outer_col
961  ? outer_col->get_type_info()
962  : outer_ti;
963  // Casts from decimal are not supported.
964  if ((inner_col_real_ti.is_decimal() || outer_col_ti.is_decimal()) &&
965  (lhs_cast || rhs_cast)) {
966  throw HashJoinFail("Cannot use hash join for given expression (cast from decimal)");
967  }
968  if (is_bbox_intersect) {
969  if (!inner_col_real_ti.is_array()) {
970  throw HashJoinFail(
971  "Bounding box intersection only supported for inner columns with array type");
972  }
973  auto is_bounds_array = [](const auto ti) {
974  return ti.is_fixlen_array() && ti.get_size() == 32;
975  };
976  if (!is_bounds_array(inner_col_real_ti)) {
977  throw HashJoinFail(
978  "Bounding box intersection only supported for 4-element double fixed length "
979  "arrays");
980  }
981  if (!(outer_col_ti.get_type() == kPOINT || is_bounds_array(outer_col_ti) ||
982  is_constructed_point(outer_expr))) {
983  throw HashJoinFail(
984  "Bounding box intersection only supported for geometry outer columns of type "
985  "point, "
986  "geometry columns with bounds or constructed points");
987  }
988  } else {
989  if (!(inner_col_real_ti.is_integer() || inner_col_real_ti.is_time() ||
990  inner_col_real_ti.is_decimal() ||
991  (inner_col_real_ti.is_string() &&
992  inner_col_real_ti.get_compression() == kENCODING_DICT))) {
993  throw HashJoinFail(
994  "Can only apply hash join to integer-like types and dictionary encoded "
995  "strings");
996  }
997  }
998 
999  auto normalized_inner_col = inner_col;
1000  auto normalized_outer_col = outer_col ? outer_col : outer_expr;
1001 
1002  const auto& normalized_inner_ti = normalized_inner_col->get_type_info();
1003  const auto& normalized_outer_ti = normalized_outer_col->get_type_info();
1004 
1005  if (normalized_inner_ti.is_string() != normalized_outer_ti.is_string()) {
1006  throw HashJoinFail(std::string("Could not build hash tables for incompatible types " +
1007  normalized_inner_ti.get_type_name() + " and " +
1008  normalized_outer_ti.get_type_name()));
1009  }
1010  return std::make_pair(std::make_pair(normalized_inner_col, normalized_outer_col),
1011  std::make_pair(inner_string_op_infos, outer_string_op_infos));
1012 }
1013 
1014 std::pair<std::vector<InnerOuter>, std::vector<InnerOuterStringOpInfos>>
1016  const TemporaryTables* temporary_tables) {
1017  std::pair<std::vector<InnerOuter>, std::vector<InnerOuterStringOpInfos>> result;
1018  const auto lhs_tuple_expr =
1019  dynamic_cast<const Analyzer::ExpressionTuple*>(condition->get_left_operand());
1020  const auto rhs_tuple_expr =
1021  dynamic_cast<const Analyzer::ExpressionTuple*>(condition->get_right_operand());
1022 
1023  CHECK_EQ(static_cast<bool>(lhs_tuple_expr), static_cast<bool>(rhs_tuple_expr));
1024  if (lhs_tuple_expr) {
1025  const auto& lhs_tuple = lhs_tuple_expr->getTuple();
1026  const auto& rhs_tuple = rhs_tuple_expr->getTuple();
1027  CHECK_EQ(lhs_tuple.size(), rhs_tuple.size());
1028  for (size_t i = 0; i < lhs_tuple.size(); ++i) {
1029  const auto col_pair = normalizeColumnPair(lhs_tuple[i].get(),
1030  rhs_tuple[i].get(),
1031  temporary_tables,
1032  condition->is_bbox_intersect_oper());
1033  result.first.emplace_back(col_pair.first);
1034  result.second.emplace_back(col_pair.second);
1035  }
1036  } else {
1037  CHECK(!lhs_tuple_expr && !rhs_tuple_expr);
1038  const auto col_pair = normalizeColumnPair(condition->get_left_operand(),
1039  condition->get_right_operand(),
1040  temporary_tables,
1041  condition->is_bbox_intersect_oper());
1042  result.first.emplace_back(col_pair.first);
1043  result.second.emplace_back(col_pair.second);
1044  }
1045 
1046  return result;
1047 }
1048 
1049 bool HashJoin::canAccessHashTable(bool allow_hash_table_recycling,
1050  bool invalid_cache_key,
1051  JoinType join_type) {
1052  return g_enable_data_recycler && g_use_hashtable_cache && !invalid_cache_key &&
1053  allow_hash_table_recycling && join_type != JoinType::INVALID;
1054 }
1055 
1057  const Executor* executor,
1058  size_t rowid_size) noexcept {
1059  if (memory_level == Data_Namespace::CPU_LEVEL) {
1060  // we can hold up to 2B hash entries b/c CPU hash table buffer is allocated
1061  // to heap which is a memory region that our buffer manager does not manage
1062  // i.e., can allocate a contiguous memory larger than `max_cpu_slab_size`
1064  } else {
1065  // allocate memory buffer for hash table from data_mgr that considers
1066  // `max_gpu_slab_size` but still it can have up to 2B rows.
1067  CHECK_GT(rowid_size, static_cast<size_t>(0));
1068  return std::min(HashJoin::MAX_NUM_HASH_ENTRIES,
1069  executor->maxGpuSlabSize() / rowid_size);
1070  }
1071 }
1072 
1073 namespace {
1074 
1076  const TemporaryTables* temporary_tables) {
1077  const auto lhs = qual_bin_oper->get_left_operand();
1078  const auto rhs = qual_bin_oper->get_right_operand();
1079  return HashJoin::normalizeColumnPair(lhs, rhs, temporary_tables).first;
1080 }
1081 
1082 } // namespace
1083 
1084 size_t get_shard_count(const Analyzer::BinOper* join_condition,
1085  const Executor* executor) {
1086  const Analyzer::ColumnVar* inner_col{nullptr};
1087  const Analyzer::Expr* outer_col{nullptr};
1088  std::shared_ptr<Analyzer::BinOper> redirected_bin_oper;
1089  try {
1090  std::tie(inner_col, outer_col) =
1091  get_cols(join_condition, executor->getTemporaryTables());
1092  } catch (...) {
1093  return 0;
1094  }
1095  if (!inner_col || !outer_col) {
1096  return 0;
1097  }
1098  return get_shard_count({inner_col, outer_col}, executor);
1099 }
static std::vector< int > collectFragmentIds(const std::vector< Fragmenter_Namespace::FragmentInfo > &fragments)
Definition: HashJoin.cpp:461
static std::shared_ptr< HashJoin > getSyntheticInstance(std::string_view table1, std::string_view column1, const Catalog_Namespace::Catalog &catalog1, std::string_view table2, std::string_view column2, const Catalog_Namespace::Catalog &catalog2, const Data_Namespace::MemoryLevel memory_level, const HashType preferred_hash_type, const int device_count, ColumnCacheMap &column_cache, Executor *executor)
Make hash table from named tables and columns (such as for testing).
Definition: HashJoin.cpp:690
int64_t getIntMin() const
#define CHECK_EQ(x, y)
Definition: Logger.h:301
std::vector< int > ChunkKey
Definition: types.h:36
std::vector< InputTableInfo > getSyntheticInputTableInfo(std::set< const Analyzer::ColumnVar * > cvs, Executor *executor)
Definition: HashJoin.cpp:667
virtual HashJoinMatchingSet codegenMatchingSet(const CompilationOptions &, const size_t)=0
size_t g_num_tuple_threshold_switch_to_baseline
Definition: Execute.cpp:106
JoinType
Definition: sqldefs.h:174
static llvm::Value * codegenHashTableLoad(const size_t table_idx, Executor *executor)
Definition: HashJoin.cpp:259
class for a per-database catalog. also includes metadata for the current database and the current use...
Definition: Catalog.h:143
std::pair< const Analyzer::ColumnVar *, const Analyzer::Expr * > InnerOuter
Definition: HashJoin.h:105
std::string toStringFlat(const HashJoin *hash_table, const ExecutorDeviceType device_type, const int device_id)
Definition: HashJoin.cpp:100
static bool canAccessHashTable(bool allow_hash_table_recycling, bool invalid_cache_key, JoinType join_type)
Definition: HashJoin.cpp:1049
std::vector< const void * > sd_inner_proxy_per_key
Definition: HashJoin.h:127
virtual std::string toStringFlat64(const ExecutorDeviceType device_type, const int device_id) const
Definition: HashJoin.cpp:118
std::list< std::shared_ptr< Analyzer::Expr > > coalesce_singleton_equi_join(const std::shared_ptr< Analyzer::BinOper > &join_qual)
#define LOG(tag)
Definition: Logger.h:285
static void checkHashJoinReplicationConstraint(const shared::TableKey &table_key, const size_t shard_count, const Executor *executor)
Definition: HashJoin.cpp:796
std::ostream & operator<<(std::ostream &os, const SessionInfo &session_info)
Definition: SessionInfo.cpp:57
static JoinColumn makeJoinColumn(Executor *executor, const Analyzer::ColumnVar &hash_col, const std::vector< Fragmenter_Namespace::FragmentInfo > &fragments, const Data_Namespace::MemoryLevel effective_mem_lvl, const int device_id, DeviceAllocator *device_allocator, const size_t thread_idx, std::vector< std::shared_ptr< Chunk_NS::Chunk >> &chunks_owner, std::vector< std::shared_ptr< void >> &malloc_owner, ColumnCacheMap &column_cache)
Creates a JoinColumn struct containing an array of JoinChunk structs.
void setBucketInfo(const std::vector< double > &bucket_sizes_for_dimension, const std::vector< InnerOuter > inner_outer_pairs)
Definition: HashJoin.cpp:37
std::set< const Analyzer::ColumnVar * > aggregateResult(const std::set< const Analyzer::ColumnVar * > &aggregate, const std::set< const Analyzer::ColumnVar * > &next_result) const override
Definition: HashJoin.cpp:642
HOST DEVICE int get_scale() const
Definition: sqltypes.h:396
const Expr * get_right_operand() const
Definition: Analyzer.h:456
bool is_constructed_point(const Analyzer::Expr *expr)
Definition: Execute.h:1699
JoinColumn fetchJoinColumn(const Analyzer::ColumnVar *hash_col, const std::vector< Fragmenter_Namespace::FragmentInfo > &fragment_info, const Data_Namespace::MemoryLevel effective_memory_level, const int device_id, std::vector< std::shared_ptr< Chunk_NS::Chunk >> &chunks_owner, DeviceAllocator *dev_buff_owner, std::vector< std::shared_ptr< void >> &malloc_owner, Executor *executor, ColumnCacheMap *column_cache)
Definition: HashJoin.cpp:60
static std::pair< const StringDictionaryProxy *, StringDictionaryProxy * > getStrDictProxies(const InnerOuter &cols, const Executor *executor, const bool has_string_ops)
Definition: HashJoin.cpp:394
const TableDescriptor * get_metadata_for_table(const ::shared::TableKey &table_key, bool populate_fragmenter)
DEVICE void sort(ARGS &&...args)
Definition: gpu_enabled.h:105
const SQLTypeInfo get_column_type(const int col_id, const int table_id, const ColumnDescriptor *cd, const TemporaryTables *temporary_tables)
Definition: Execute.h:254
Definition: sqldefs.h:48
llvm::Value * codegenPseudoStringOper(const Analyzer::ColumnVar *, const std::vector< StringOps_Namespace::StringOpInfo > &string_op_infos, const CompilationOptions &)
Definition: sqldefs.h:29
Definition: HashTable.h:21
virtual int8_t * alloc(const size_t num_bytes)=0
InnerOuter get_cols(const Analyzer::BinOper *qual_bin_oper, const TemporaryTables *temporary_tables)
Definition: HashJoin.cpp:1075
std::string toString(const QueryDescriptionType &type)
Definition: Types.h:64
T visit(const Analyzer::Expr *expr) const
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:391
static llvm::Value * codegenColOrStringOper(const Analyzer::Expr *col_or_string_oper, const std::vector< StringOps_Namespace::StringOpInfo > &string_op_infos, CodeGenerator &code_generator, const CompilationOptions &co)
Definition: HashJoin.cpp:564
bool g_enable_data_recycler
Definition: Execute.cpp:154
#define CHECK_GT(x, y)
Definition: Logger.h:305
bool is_time() const
Definition: sqltypes.h:577
ExecutorDeviceType
virtual std::string toStringFlat32(const ExecutorDeviceType device_type, const int device_id) const
Definition: HashJoin.cpp:123
std::string to_string(char const *&&v)
std::unordered_map< int, const ResultSetPtr & > TemporaryTables
Definition: InputMetadata.h:31
const std::vector< JoinColumnTypeInfo > join_column_types
Definition: HashJoin.h:111
size_t g_ratio_num_hash_entry_to_num_tuple_switch_to_baseline
Definition: Execute.cpp:107
virtual void copyToDevice(void *device_dst, const void *host_src, const size_t num_bytes) const =0
size_t col_chunks_buff_sz
std::unordered_map< size_t, HashTableBuildDag > HashTableBuildDagMap
const std::vector< std::shared_ptr< Analyzer::Expr > > & getTuple() const
Definition: Analyzer.h:253
llvm::Value * get_arg_by_name(llvm::Function *func, const std::string &name)
Definition: Execute.h:168
std::vector< void * > sd_outer_proxy_per_key
Definition: HashJoin.h:128
bool is_integer() const
Definition: sqltypes.h:565
#define CHECK_NE(x, y)
Definition: Logger.h:302
const ColumnDescriptor * get_column_descriptor_maybe(const shared::ColumnKey &column_key)
Definition: Execute.h:241
static size_t getMaximumNumHashEntriesCanHold(MemoryLevel memory_level, const Executor *executor, size_t rowid_size) noexcept
Definition: HashJoin.cpp:1056
static std::shared_ptr< BoundingBoxIntersectJoinHashTable > getInstance(const std::shared_ptr< Analyzer::BinOper > condition, const std::vector< InputTableInfo > &query_infos, const Data_Namespace::MemoryLevel memory_level, const JoinType join_type, const int device_count, ColumnCacheMap &column_cache, Executor *executor, const HashTableBuildDagMap &hashtable_build_dag_map, const RegisteredQueryHint &query_hint, const TableIdToNodeMap &table_id_to_node_map)
Make hash table from an in-flight SQL query&#39;s parse tree etc.
bool is_bbox_intersect_oper() const
Definition: Analyzer.h:453
static constexpr size_t MAX_NUM_HASH_ENTRIES
Definition: HashJoin.h:136
const ColumnDescriptor * getMetadataForColumn(int tableId, const std::string &colName) const
int8_t * getJoinHashBuffer(const ExecutorDeviceType device_type, const int device_id) const
Definition: HashJoin.h:314
int getDatabaseId() const
Definition: Catalog.h:326
static std::vector< const StringDictionaryProxy::IdMap * > translateCompositeStrDictProxies(const CompositeKeyInfo &composite_key_info, const std::vector< InnerOuterStringOpInfos > &string_op_infos_for_keys, const Executor *executor)
Definition: HashJoin.cpp:528
OUTPUT transform(INPUT const &input, FUNC const &func)
Definition: misc.h:320
bool hasNulls() const
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const int8_t * col_chunks_buff
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
int get_precision() const
Definition: sqltypes.h:394
static ExpressionRange makeIntRange(const int64_t int_min, const int64_t int_max, const int64_t bucket, const bool has_nulls)
static const StringDictionaryProxy::IdMap * translateInnerToOuterStrDictProxies(const InnerOuter &cols, const InnerOuterStringOpInfos &inner_outer_string_op_infos, ExpressionRange &old_col_range, const Executor *executor)
Definition: HashJoin.cpp:423
void setupSyntheticCaching(std::set< const Analyzer::ColumnVar * > cvs, Executor *executor)
Definition: HashJoin.cpp:651
#define VLOGGING(n)
Definition: Logger.h:289
std::unordered_map< shared::TableKey, const RelAlgNode * > TableIdToNodeMap
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
#define CHECK_LT(x, y)
Definition: Logger.h:303
static RegisteredQueryHint defaults()
Definition: QueryHint.h:364
Definition: sqldefs.h:71
Expression class for string functions The &quot;arg&quot; constructor parameter must be an expression that reso...
Definition: Analyzer.h:1601
size_t getJoinHashBufferSize(const ExecutorDeviceType device_type)
Definition: HashJoin.h:300
bool table_is_replicated(const TableDescriptor *td)
std::set< DecodedJoinHashBufferEntry > DecodedJoinHashBufferSet
Definition: HashTable.h:72
std::set< const Analyzer::ColumnVar * > visitColumnVarTuple(const Analyzer::ExpressionTuple *expr_tuple) const override
Definition: HashJoin.cpp:631
bool g_enable_bbox_intersect_hashjoin
Definition: Execute.cpp:105
static std::shared_ptr< BaselineJoinHashTable > getInstance(const std::shared_ptr< Analyzer::BinOper > condition, const std::vector< InputTableInfo > &query_infos, const Data_Namespace::MemoryLevel memory_level, const JoinType join_type, const HashType preferred_hash_type, const int device_count, ColumnCacheMap &column_cache, Executor *executor, const HashTableBuildDagMap &hashtable_build_dag_map, const RegisteredQueryHint &query_hints, const TableIdToNodeMap &table_id_to_node_map)
Make hash table from an in-flight SQL query&#39;s parse tree etc.
std::unordered_map< shared::TableKey, std::unordered_map< int, std::shared_ptr< const ColumnarResults >>> ColumnCacheMap
std::string get_type_name() const
Definition: sqltypes.h:482
static std::shared_ptr< PerfectJoinHashTable > getInstance(const std::shared_ptr< Analyzer::BinOper > qual_bin_oper, const std::vector< InputTableInfo > &query_infos, const Data_Namespace::MemoryLevel memory_level, const JoinType join_type, const HashType preferred_hash_type, const int device_count, ColumnCacheMap &column_cache, Executor *executor, const HashTableBuildDagMap &hashtable_build_dag_map, const RegisteredQueryHint &query_hints, const TableIdToNodeMap &table_id_to_node_map)
Make hash table from an in-flight SQL query&#39;s parse tree etc.
std::shared_ptr< Analyzer::ColumnVar > getSyntheticColumnVar(std::string_view table, std::string_view column, int rte_idx, const Catalog_Namespace::Catalog &catalog)
Definition: HashJoin.cpp:580
bool force_baseline_hash_join
Definition: QueryHint.h:359
int64_t getIntMax() const
std::set< const Analyzer::ColumnVar * > visitColumnVar(const Analyzer::ColumnVar *column) const override
Definition: HashJoin.cpp:626
std::pair< std::vector< StringOps_Namespace::StringOpInfo >, std::vector< StringOps_Namespace::StringOpInfo >> InnerOuterStringOpInfos
Definition: HashJoin.h:107
#define CHECK(condition)
Definition: Logger.h:291
std::set< int32_t > payload
Definition: HashTable.h:23
#define DEBUG_TIMER(name)
Definition: Logger.h:412
static std::pair< InnerOuter, InnerOuterStringOpInfos > normalizeColumnPair(const Analyzer::Expr *lhs, const Analyzer::Expr *rhs, const TemporaryTables *temporary_tables, const bool is_bbox_intersect=false)
Definition: HashJoin.cpp:822
static const T * getHashJoinColumn(const Analyzer::Expr *expr)
Definition: HashJoin.cpp:813
static std::pair< std::vector< InnerOuter >, std::vector< InnerOuterStringOpInfos > > normalizeColumnPairs(const Analyzer::BinOper *condition, const TemporaryTables *temporary_tables)
Definition: HashJoin.cpp:1015
bool g_cluster
const Expr * get_left_operand() const
Definition: Analyzer.h:455
InnerQualDecision
Definition: HashJoin.h:61
const TableDescriptor * getMetadataForTable(const std::string &tableName, const bool populateFragmenter=true) const
Returns a pointer to a const TableDescriptor struct matching the provided tableName.
bool is_string() const
Definition: sqltypes.h:559
std::vector< int64_t > key
Definition: HashTable.h:22
std::vector< JoinBucketInfo > join_buckets
Definition: HashJoin.h:113
bool is_decimal() const
Definition: sqltypes.h:568
size_t get_shard_count(const Analyzer::BinOper *join_condition, const Executor *executor)
Definition: HashJoin.cpp:1084
static std::shared_ptr< HashJoin > getInstance(const std::shared_ptr< Analyzer::BinOper > qual_bin_oper, const std::vector< InputTableInfo > &query_infos, const Data_Namespace::MemoryLevel memory_level, const JoinType join_type, const HashType preferred_hash_type, const int device_count, ColumnCacheMap &column_cache, Executor *executor, const HashTableBuildDagMap &hashtable_build_dag_map, const RegisteredQueryHint &query_hint, const TableIdToNodeMap &table_id_to_node_map)
Make hash table from an in-flight SQL query&#39;s parse tree etc.
Definition: HashJoin.cpp:285
HashType
Definition: HashTable.h:19
DEVICE void swap(ARGS &&...args)
Definition: gpu_enabled.h:114
bool g_use_hashtable_cache
Definition: Execute.cpp:155
const std::vector< JoinColumn > join_columns
Definition: HashJoin.h:110
#define VLOG(n)
Definition: Logger.h:388
static CompositeKeyInfo getCompositeKeyInfo(const std::vector< InnerOuter > &inner_outer_pairs, const Executor *executor, const std::vector< InnerOuterStringOpInfos > &inner_outer_string_op_infos_pairs={})
Definition: HashJoin.cpp:470