OmniSciDB  f17484ade4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StringOpsIR.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 
20 #include "../Shared/funcannotations.h"
21 #include "../Shared/sqldefs.h"
22 #include "Parser/ParserNode.h"
24 #include "StringOps/StringOps.h"
25 
26 #include <boost/locale/conversion.hpp>
27 
28 extern "C" RUNTIME_EXPORT StringView string_decode(int8_t* chunk_iter_, int64_t pos) {
29  auto chunk_iter = reinterpret_cast<ChunkIter*>(chunk_iter_);
30  VarlenDatum vd;
31  bool is_end;
32  ChunkIter_get_nth(chunk_iter, pos, false, &vd, &is_end);
33  CHECK(!is_end);
34  return vd.is_null ? StringView{nullptr, 0u}
35  : StringView{reinterpret_cast<char const*>(vd.pointer), vd.length};
36 }
37 
38 extern "C" RUNTIME_EXPORT StringView string_decompress(const int32_t string_id,
39  const int64_t string_dict_handle) {
40  if (string_id == NULL_INT) {
41  return {nullptr, 0};
42  }
43  auto string_dict_proxy =
44  reinterpret_cast<const StringDictionaryProxy*>(string_dict_handle);
45  auto string_bytes = string_dict_proxy->getStringBytes(string_id);
46  CHECK(string_bytes.first);
47  return {string_bytes.first, string_bytes.second};
48 }
49 
50 extern "C" RUNTIME_EXPORT int32_t string_compress(const StringView string_view,
51  const int64_t string_dict_handle) {
52  std::string_view const sv = string_view.stringView();
53  if (sv.empty()) {
54  return inline_int_null_value<int32_t>();
55  }
56  auto string_dict_proxy = reinterpret_cast<StringDictionaryProxy*>(string_dict_handle);
57  return string_dict_proxy->getOrAddTransient(sv);
58 }
59 
60 extern "C" RUNTIME_EXPORT int32_t
61 apply_string_ops_and_encode(const char* str_ptr,
62  const int32_t str_len,
63  const int64_t string_ops_handle,
64  const int64_t string_dict_handle) {
65  std::string raw_str(str_ptr, str_len);
66  auto string_ops =
67  reinterpret_cast<const StringOps_Namespace::StringOps*>(string_ops_handle);
68  auto string_dict_proxy = reinterpret_cast<StringDictionaryProxy*>(string_dict_handle);
69  const auto result_str = string_ops->operator()(raw_str);
70  if (result_str.empty()) {
71  return inline_int_null_value<int32_t>();
72  }
73  return string_dict_proxy->getOrAddTransient(result_str);
74 }
75 
76 extern "C" RUNTIME_EXPORT int32_t
78  const int32_t str1_len,
79  const char* str2_ptr,
80  const int32_t str2_len,
81  const int64_t string_ops_handle,
82  const int64_t string_dict_handle) {
83  std::string_view raw_str1(str1_ptr, str1_len);
84  std::string_view raw_str2(str2_ptr, str2_len);
85  auto string_ops =
86  reinterpret_cast<const StringOps_Namespace::StringOps*>(string_ops_handle);
87  auto string_dict_proxy = reinterpret_cast<StringDictionaryProxy*>(string_dict_handle);
88  const auto result_str = string_ops->multi_input_eval(raw_str1, raw_str2);
89  if (result_str.empty()) {
90  return inline_int_null_value<int32_t>();
91  }
92  return string_dict_proxy->getOrAddTransient(result_str);
93 }
94 
95 extern "C" RUNTIME_EXPORT int32_t
97  const int64_t source_string_dict_handle,
98  const int64_t dest_string_dict_handle) {
99  const auto source_string_dict_proxy =
100  reinterpret_cast<StringDictionaryProxy*>(source_string_dict_handle);
101  auto dest_string_dict_proxy =
102  reinterpret_cast<StringDictionaryProxy*>(dest_string_dict_handle);
103  // Can we have StringDictionaryProxy::getString return a reference?
104  const auto source_str = source_string_dict_proxy->getString(string_id);
105  if (source_str.empty()) {
106  return inline_int_null_value<int32_t>();
107  }
108  return dest_string_dict_proxy->getIdOfString(source_str);
109 }
110 
111 extern "C" RUNTIME_EXPORT int32_t
113  const int64_t source_string_dict_handle,
114  const int64_t dest_string_dict_handle) {
115  const auto source_string_dict_proxy =
116  reinterpret_cast<StringDictionaryProxy*>(source_string_dict_handle);
117  auto dest_string_dict_proxy =
118  reinterpret_cast<StringDictionaryProxy*>(dest_string_dict_handle);
119  // Can we have StringDictionaryProxy::getString return a reference?
120  const auto source_str = source_string_dict_proxy->getString(string_id);
121  if (source_str.empty()) {
122  return inline_int_null_value<int32_t>();
123  }
124  return dest_string_dict_proxy->getOrAddTransient(source_str);
125 }
126 
127 #define DEF_APPLY_NUMERIC_STRING_OPS(value_type, value_name) \
128  extern "C" RUNTIME_EXPORT ALWAYS_INLINE value_type \
129  apply_numeric_string_ops_##value_name( \
130  const char* str_ptr, const int32_t str_len, const int64_t string_ops_handle) { \
131  const std::string_view raw_str(str_ptr, str_len); \
132  auto string_ops = \
133  reinterpret_cast<const StringOps_Namespace::StringOps*>(string_ops_handle); \
134  const auto result_datum = string_ops->numericEval(raw_str); \
135  return result_datum.value_name##val; \
136  }
137 
138 DEF_APPLY_NUMERIC_STRING_OPS(int8_t, bool)
139 DEF_APPLY_NUMERIC_STRING_OPS(int8_t, tinyint)
140 DEF_APPLY_NUMERIC_STRING_OPS(int16_t, smallint)
141 DEF_APPLY_NUMERIC_STRING_OPS(int32_t, int)
142 DEF_APPLY_NUMERIC_STRING_OPS(int64_t, bigint)
143 DEF_APPLY_NUMERIC_STRING_OPS(float, float)
144 DEF_APPLY_NUMERIC_STRING_OPS(double, double)
145 
146 #undef DEF_APPLY_NUMERIC_STRING_OPS
147 
148 inline int32_t write_string_to_proxy(const std::string& str,
149  const int64_t string_dict_handle) {
150  if (str.empty()) {
151  return inline_int_null_value<int32_t>();
152  }
153  auto string_dict_proxy = reinterpret_cast<StringDictionaryProxy*>(string_dict_handle);
154  return string_dict_proxy->getOrAddTransient(str);
155 }
156 
157 #define DEF_CONVERT_TO_STRING_AND_ENCODE(value_type, value_name) \
158  extern "C" RUNTIME_EXPORT ALWAYS_INLINE int32_t \
159  convert_to_string_and_encode_##value_name(const value_type operand, \
160  const int64_t string_dict_handle) { \
161  return write_string_to_proxy(std::to_string(operand), string_dict_handle); \
162  }
163 
164 DEF_CONVERT_TO_STRING_AND_ENCODE(int8_t, tinyint)
165 DEF_CONVERT_TO_STRING_AND_ENCODE(int16_t, smallint)
167 DEF_CONVERT_TO_STRING_AND_ENCODE(int64_t, bigint)
169 DEF_CONVERT_TO_STRING_AND_ENCODE(double, double)
170 
171 #undef DEF_CONVERT_TO_STRING_AND_ENCODE
172 
173 extern "C" RUNTIME_EXPORT ALWAYS_INLINE int32_t
175  const int64_t string_dict_handle) {
176  return write_string_to_proxy(operand == 1 ? "true" : "false", string_dict_handle);
177 }
178 
179 extern "C" RUNTIME_EXPORT ALWAYS_INLINE int32_t
181  const int32_t precision,
182  const int32_t scale,
183  const int64_t string_dict_handle) {
184  constexpr size_t buf_size = 64;
185  char buf[buf_size]; // Hold "2000-03-01 12:34:56.123456789" and large years.
186  const double v = static_cast<double>(operand) * shared::power10inv(scale);
187  snprintf(buf, buf_size, "%*.*f", precision, scale, v);
188  return write_string_to_proxy(buf, string_dict_handle);
189 }
190 
191 extern "C" RUNTIME_EXPORT ALWAYS_INLINE int32_t
192 convert_to_string_and_encode_time(const int64_t operand,
193  const int64_t string_dict_handle) {
194  constexpr size_t buf_size = 64;
195  char buf[buf_size];
196  shared::formatHMS(buf, buf_size, operand);
197  return write_string_to_proxy(buf, string_dict_handle);
198 }
199 
200 extern "C" RUNTIME_EXPORT ALWAYS_INLINE int32_t
202  const int32_t dimension,
203  const int64_t string_dict_handle) {
204  constexpr size_t buf_size = 64;
205  char buf[buf_size]; // Hold "2000-03-01 12:34:56.123456789" and large years.
206  shared::formatDateTime(buf, buf_size, operand, dimension);
207  return write_string_to_proxy(buf, string_dict_handle);
208 }
209 
210 extern "C" RUNTIME_EXPORT ALWAYS_INLINE int32_t
211 convert_to_string_and_encode_date(const int64_t operand,
212  const int64_t string_dict_handle) {
213  constexpr size_t buf_size = 64;
214  char buf[buf_size]; // Hold "2000-03-01 12:34:56.123456789" and large years.
215  shared::formatDate(buf, buf_size, operand);
216  return write_string_to_proxy(buf, string_dict_handle);
217 }
218 
220  const CompilationOptions& co) {
222  auto str_lv = codegen(expr->get_arg(), true, co);
223  if (str_lv.size() != 3) {
224  CHECK_EQ(size_t(1), str_lv.size());
225  str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(str_lv.front(), 0));
226  str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(str_lv.front(), 1));
227  str_lv.back() = cgen_state_->ir_builder_.CreateTrunc(
228  str_lv.back(), llvm::Type::getInt32Ty(cgen_state_->context_));
230  throw QueryMustRunOnCpu();
231  }
232  }
233  std::vector<llvm::Value*> charlength_args{str_lv[1], str_lv[2]};
234  std::string fn_name("char_length");
235  if (expr->get_calc_encoded_length()) {
236  fn_name += "_encoded";
237  }
238  const bool is_nullable{!expr->get_arg()->get_type_info().get_notnull()};
239  if (is_nullable) {
240  fn_name += "_nullable";
241  charlength_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
242  }
243  return expr->get_calc_encoded_length()
245  fn_name, get_int_type(32, cgen_state_->context_), charlength_args)
246  : cgen_state_->emitCall(fn_name, charlength_args);
247 }
248 
250  const CompilationOptions& co) {
252  auto str_lv = codegen(expr->get_arg(), true, co);
253  CHECK_EQ(size_t(1), str_lv.size());
254  return cgen_state_->emitCall("key_for_string_encoded", str_lv);
255 }
256 
257 std::vector<StringOps_Namespace::StringOpInfo> getStringOpInfos(
258  const Analyzer::StringOper* expr) {
259  std::vector<StringOps_Namespace::StringOpInfo> string_op_infos;
260  auto chained_string_op_exprs = expr->getChainedStringOpExprs();
261  if (chained_string_op_exprs.empty()) {
262  // Likely will change the below to a CHECK but until we have more confidence
263  // that all potential query patterns have nodes that might contain string ops folded,
264  // leaving as an error for now
265  throw std::runtime_error(
266  "Expected folded string operator but found operator unfolded.");
267  }
268  // Consider encapsulating below in an Analyzer::StringOper method to dedup
269  for (const auto& chained_string_op_expr : chained_string_op_exprs) {
270  auto chained_string_op =
271  dynamic_cast<const Analyzer::StringOper*>(chained_string_op_expr.get());
272  CHECK(chained_string_op);
273  StringOps_Namespace::StringOpInfo string_op_info(chained_string_op->get_kind(),
274  chained_string_op->get_type_info(),
275  chained_string_op->getLiteralArgs());
276  string_op_infos.emplace_back(string_op_info);
277  }
278  return string_op_infos;
279 }
280 
281 std::pair<std::vector<llvm::Value*>, std::unique_ptr<CodeGenerator::NullCheckCodegen>>
283  const CompilationOptions& co,
284  const size_t arg_idx,
285  const bool codegen_nullcheck) {
286  CHECK_LT(arg_idx, expr->getArity());
287  const auto& arg_ti = expr->getArg(arg_idx)->get_type_info();
288 
289  auto primary_str_lv = codegen(expr->getArg(arg_idx), true, co);
290  std::unique_ptr<CodeGenerator::NullCheckCodegen> nullcheck_codegen;
291  if (primary_str_lv.size() != 3) {
292  // If this is the case we should have a transient dictionary from a previous op
293  // We can't use the dictionary values without decoding as this op occurs directly
294  // inline on top of whatever operation created the transient dictionary
295  CHECK_EQ(size_t(1), primary_str_lv.size());
296  CHECK(arg_ti.is_dict_encoded_string());
297  const bool is_nullable = !arg_ti.get_notnull();
298  if (codegen_nullcheck && is_nullable) {
299  const auto decoded_input_ti = SQLTypeInfo(kTEXT, is_nullable, kENCODING_DICT);
300  nullcheck_codegen = std::make_unique<CodeGenerator::NullCheckCodegen>(
301  cgen_state_,
302  executor_,
303  primary_str_lv[0],
304  decoded_input_ti,
305  "transient_dict_per_row_nullcheck");
306  }
307  const auto sdp_ptr = reinterpret_cast<int64_t>(executor()->getStringDictionaryProxy(
308  arg_ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true));
309  const auto string_view =
310  cgen_state_->emitExternalCall("string_decompress",
312  {primary_str_lv[0], cgen_state_->llInt(sdp_ptr)});
313  primary_str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(string_view, 0));
314  primary_str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(string_view, 1));
315  primary_str_lv.back() = cgen_state_->ir_builder_.CreateTrunc(
316  primary_str_lv.back(), llvm::Type::getInt32Ty(cgen_state_->context_));
317  }
318  CHECK_EQ(size_t(3), primary_str_lv.size());
319  return std::make_pair(primary_str_lv, std::move(nullcheck_codegen));
320 }
321 
323  const CompilationOptions& co) {
325  CHECK_GE(expr->getArity(), 1UL);
326  const auto non_literals_arity = expr->getNonLiteralsArity();
327  CHECK_GE(non_literals_arity, 1UL);
328  CHECK_LE(non_literals_arity, 2UL);
329  const auto& return_ti = expr->get_type_info();
330  if (g_cluster && return_ti.is_dict_encoded_string()) {
331  throw std::runtime_error(
332  "Cast from none-encoded string to dictionary-encoded not supported for "
333  "distributed queries");
334  }
336  throw QueryMustRunOnCpu();
337  }
338  const auto [primary_str_lv, nullcheck_codegen] =
339  codegenStringFetchAndEncode(expr, co, 0UL, false);
340  CHECK_EQ(size_t(3), primary_str_lv.size());
341 
342  const auto string_op_infos = getStringOpInfos(expr);
343  CHECK(string_op_infos.size());
344 
345  const auto string_ops =
346  executor()->getRowSetMemoryOwner()->getStringOps(string_op_infos);
347  const int64_t string_ops_handle = reinterpret_cast<int64_t>(string_ops);
348  auto string_ops_handle_lv = cgen_state_->llInt(string_ops_handle);
349 
350  if (!return_ti.is_string()) {
351  CHECK_EQ(non_literals_arity, 1UL);
352  std::vector<llvm::Value*> string_oper_lvs{
353  primary_str_lv[1], primary_str_lv[2], string_ops_handle_lv};
354  const auto return_type = return_ti.get_type();
355  std::string fn_call = "apply_numeric_string_ops_";
356  switch (return_type) {
357  case kBOOLEAN: {
358  fn_call += "bool";
359  break;
360  }
361  case kTINYINT:
362  case kSMALLINT:
363  case kINT:
364  case kBIGINT:
365  case kFLOAT:
366  case kDOUBLE: {
367  fn_call += to_lower(toString(return_type));
368  break;
369  }
370  case kNUMERIC:
371  case kDECIMAL:
372  case kTIME:
373  case kTIMESTAMP:
374  case kDATE: {
375  fn_call += "bigint";
376  break;
377  }
378  default: {
379  throw std::runtime_error("Unimplemented type for string-to-numeric translation");
380  }
381  }
382  const auto logical_size = return_ti.get_logical_size() * 8;
383  auto llvm_return_type = return_ti.is_fp()
384  ? get_fp_type(logical_size, cgen_state_->context_)
385  : get_int_type(logical_size, cgen_state_->context_);
386  auto ret = cgen_state_->emitExternalCall(fn_call, llvm_return_type, string_oper_lvs);
387  if (nullcheck_codegen) {
388  ret = nullcheck_codegen->finalize(cgen_state_->inlineNull(return_ti), ret);
389  }
390  return ret;
391  }
392 
393  // If here we are outputing a string dictionary column
394  CHECK(return_ti.is_dict_encoded_string());
395  const int64_t dest_string_proxy_handle =
396  reinterpret_cast<int64_t>(executor()->getStringDictionaryProxy(
397  return_ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true));
398  auto dest_string_proxy_handle_lv = cgen_state_->llInt(dest_string_proxy_handle);
399  if (non_literals_arity == 1UL) {
400  std::vector<llvm::Value*> string_oper_lvs{primary_str_lv[1],
401  primary_str_lv[2],
402  string_ops_handle_lv,
403  dest_string_proxy_handle_lv};
404 
405  auto ret = cgen_state_->emitExternalCall("apply_string_ops_and_encode",
407  string_oper_lvs);
408  if (nullcheck_codegen) {
409  ret = nullcheck_codegen->finalize(cgen_state_->inlineNull(return_ti), ret);
410  }
411  return ret;
412  } else {
413  // For now only CONCAT is supported, which takes up to 2 non-literal string
414  // arguments. In the future (likely when we can codegen the StringOps to enable
415  // generic, multi-branch execution rather than linear chains of functors as we do
416  // today), we will generalize this to functions that take
417  // any number of string and numeric non-literal arguments, in which case
418  // we will need to make apply_multi_input_string_ops_and_encode take
419  // a vector of arguments. For now, however, expecting exactly 2 arguments
420  // suffices.
421  CHECK_EQ(non_literals_arity, 2UL);
424  const auto [secondary_str_lv, secondary_nullcheck_codegen] =
425  codegenStringFetchAndEncode(expr, co, 1UL, false);
426  CHECK_EQ(size_t(3), secondary_str_lv.size());
427  std::vector<llvm::Value*> string_oper_lvs{primary_str_lv[1],
428  primary_str_lv[2],
429  secondary_str_lv[1],
430  secondary_str_lv[2],
431  string_ops_handle_lv,
432  dest_string_proxy_handle_lv};
433  auto ret = cgen_state_->emitExternalCall("apply_multi_input_string_ops_and_encode",
435  string_oper_lvs);
436  if (secondary_nullcheck_codegen) {
437  ret =
438  secondary_nullcheck_codegen->finalize(cgen_state_->inlineNull(return_ti), ret);
439  }
440  if (nullcheck_codegen) {
441  ret = nullcheck_codegen->finalize(cgen_state_->inlineNull(return_ti), ret);
442  }
443  return ret;
444  }
445 }
446 
447 std::unique_ptr<StringDictionaryTranslationMgr> translate_dict_strings(
448  const Analyzer::StringOper* expr,
449  const ExecutorDeviceType device_type,
450  Executor* executor) {
451  const auto& expr_ti = expr->get_type_info();
452  const auto& primary_input_expr_ti = expr->getArg(0)->get_type_info();
453  const auto& dict_id = primary_input_expr_ti.getStringDictKey();
454  const auto string_op_infos = getStringOpInfos(expr);
455  CHECK(string_op_infos.size());
456 
457  if (string_op_infos.back().getReturnType().is_dict_encoded_string()) {
458  // string->string translation
459  auto string_dictionary_translation_mgr =
460  std::make_unique<StringDictionaryTranslationMgr>(
461  dict_id,
462  dict_id,
463  false, // translate_intersection_only
464  expr_ti,
465  string_op_infos,
468  executor->deviceCount(device_type),
469  executor,
470  executor->getDataMgr(),
471  false /* delay_translation */);
472  return string_dictionary_translation_mgr;
473  } else {
474  // string->numeric translation
475  auto string_dictionary_translation_mgr =
476  std::make_unique<StringDictionaryTranslationMgr>(
477  dict_id,
478  expr_ti,
479  string_op_infos,
482  executor->deviceCount(device_type),
483  executor,
484  executor->getDataMgr(),
485  false /* delay_translation */);
486  return string_dictionary_translation_mgr;
487  }
488 }
489 
491  const CompilationOptions& co) {
492  CHECK_GE(expr->getArity(), 1UL);
493  if (expr->requiresPerRowTranslation()) {
494  return codegenPerRowStringOper(expr, co);
495  }
496 
498 
499  auto string_dictionary_translation_mgr =
501 
502  auto str_id_lv = codegen(expr->getArg(0), true, co);
503  CHECK_EQ(size_t(1), str_id_lv.size());
504  const auto& expr_ti = expr->get_type_info();
505 
506  return cgen_state_
507  ->moveStringDictionaryTranslationMgr(std::move(string_dictionary_translation_mgr))
508  ->codegen(str_id_lv[0], expr_ti, true /* add_nullcheck */, co);
509 }
510 
511 // Method below is for join probes, as we cast the StringOper nodes to ColumnVars early to
512 // not special case that codepath (but retain the StringOpInfos, which we use here to
513 // execute the same string ops as we would on a native StringOper node)
515  const Analyzer::ColumnVar* expr,
516  const std::vector<StringOps_Namespace::StringOpInfo>& string_op_infos,
517  const CompilationOptions& co) {
519  const auto& expr_ti = expr->get_type_info();
520  const auto& dict_id = expr_ti.getStringDictKey();
521 
522  auto string_dictionary_translation_mgr =
523  std::make_unique<StringDictionaryTranslationMgr>(
524  dict_id,
525  dict_id,
526  false, // translate_intersection_only
527  expr->get_type_info(),
528  string_op_infos,
531  executor()->deviceCount(co.device_type),
532  executor(),
533  executor()->getDataMgr(),
534  false /* delay_translation */);
535 
536  auto str_id_lv = codegen(expr, true /* fetch_column */, co);
537  CHECK_EQ(size_t(1), str_id_lv.size());
538 
539  return cgen_state_
540  ->moveStringDictionaryTranslationMgr(std::move(string_dictionary_translation_mgr))
541  ->codegen(str_id_lv[0], expr_ti, true /* add_nullcheck */, co);
542 }
543 
545  const CompilationOptions& co) {
547  if (is_unnest(extract_cast_arg(expr->get_arg()))) {
548  throw std::runtime_error("LIKE not supported for unnested expressions");
549  }
550  char escape_char{'\\'};
551  if (expr->get_escape_expr()) {
552  auto escape_char_expr =
553  dynamic_cast<const Analyzer::Constant*>(expr->get_escape_expr());
554  CHECK(escape_char_expr);
555  CHECK(escape_char_expr->get_type_info().is_string());
556  CHECK_EQ(size_t(1), escape_char_expr->get_constval().stringval->size());
557  escape_char = (*escape_char_expr->get_constval().stringval)[0];
558  }
559  auto pattern = dynamic_cast<const Analyzer::Constant*>(expr->get_like_expr());
560  CHECK(pattern);
561  auto fast_dict_like_lv = codegenDictLike(expr->get_own_arg(),
562  pattern,
563  expr->get_is_ilike(),
564  expr->get_is_simple(),
565  escape_char,
566  co);
567  if (fast_dict_like_lv) {
568  return fast_dict_like_lv;
569  }
570  const auto& ti = expr->get_arg()->get_type_info();
571  CHECK(ti.is_string());
572  if (g_enable_watchdog && ti.get_compression() != kENCODING_NONE) {
573  throw WatchdogException(
574  "Cannot do LIKE / ILIKE on this dictionary encoded column, its cardinality is "
575  "too high");
576  }
577  auto str_lv = codegen(expr->get_arg(), true, co);
578  if (str_lv.size() != 3) {
579  CHECK_EQ(size_t(1), str_lv.size());
580  str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(str_lv.front(), 0));
581  str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(str_lv.front(), 1));
582  str_lv.back() = cgen_state_->ir_builder_.CreateTrunc(
583  str_lv.back(), llvm::Type::getInt32Ty(cgen_state_->context_));
585  throw QueryMustRunOnCpu();
586  }
587  }
588  auto like_expr_arg_lvs = codegen(expr->get_like_expr(), true, co);
589  CHECK_EQ(size_t(3), like_expr_arg_lvs.size());
590  const bool is_nullable{!expr->get_arg()->get_type_info().get_notnull()};
591  std::vector<llvm::Value*> str_like_args{
592  str_lv[1], str_lv[2], like_expr_arg_lvs[1], like_expr_arg_lvs[2]};
593  std::string fn_name{expr->get_is_ilike() ? "string_ilike" : "string_like"};
594  if (expr->get_is_simple()) {
595  fn_name += "_simple";
596  } else {
597  str_like_args.push_back(cgen_state_->llInt(int8_t(escape_char)));
598  }
599  if (is_nullable) {
600  fn_name += "_nullable";
601  str_like_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
602  }
603  return cgen_state_->emitCall(fn_name, str_like_args);
604 }
605 
607  Executor* executor) {
608  // If here we are operating on top of one or more string functions, i.e. LOWER(str),
609  // and before running the dictionary LIKE/ILIKE or REGEXP_LIKE,
610  // we need to translate the strings first.
611 
612  // This approach is a temporary solution until we can implement the next stage
613  // of the string translation project, which will broaden the StringOper class to include
614  // operations that operate on strings but do not neccessarily return strings like
615  // LIKE/ILIKE/REGEXP_LIKE/CHAR_LENGTH At this point these aforementioned operators,
616  // including LIKE/ILIKE, will just become part of a StringOps chain (which will also
617  // avoid the overhead of serializing the transformed raw strings from previous string
618  // opers to the dictionary to only read back out and perform LIKE/ILIKE.)
619  CHECK_GT(string_oper->getArity(), 0UL);
620  const auto& string_oper_primary_arg_ti = string_oper->getArg(0)->get_type_info();
621  CHECK(string_oper_primary_arg_ti.is_dict_encoded_string());
622  CHECK_NE(string_oper_primary_arg_ti.getStringDictKey().dict_id, TRANSIENT_DICT_ID);
623  // Note the actual translation below will be cached by RowSetMemOwner
624  translate_dict_strings(string_oper, ExecutorDeviceType::CPU, executor);
625 }
626 
628  const std::shared_ptr<Analyzer::Expr> like_arg,
629  const Analyzer::Constant* pattern,
630  const bool ilike,
631  const bool is_simple,
632  const char escape_char,
633  const CompilationOptions& co) {
635  const auto cast_oper = std::dynamic_pointer_cast<Analyzer::UOper>(like_arg);
636  if (!cast_oper) {
637  return nullptr;
638  }
639  CHECK(cast_oper);
640  CHECK_EQ(kCAST, cast_oper->get_optype());
641  const auto dict_like_arg = cast_oper->get_own_operand();
642  const auto& dict_like_arg_ti = dict_like_arg->get_type_info();
643  if (!dict_like_arg_ti.is_string()) {
644  throw(std::runtime_error("Cast from " + dict_like_arg_ti.get_type_name() + " to " +
645  cast_oper->get_type_info().get_type_name() +
646  " not supported"));
647  }
648  CHECK_EQ(kENCODING_DICT, dict_like_arg_ti.get_compression());
649  const auto sdp = executor()->getStringDictionaryProxy(
650  dict_like_arg_ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true);
651  if (sdp->storageEntryCount() > 200000000) {
652  return nullptr;
653  }
654  if (sdp->getDictKey().isTransientDict()) {
655  // If we have a literal dictionary it was a product
656  // of string ops applied to none-encoded strings, and
657  // will not be populated at codegen-time, so we
658  // cannot use the fast path
659 
660  // Todo(todd): Once string ops support non-string producting
661  // operators (like like/ilike), like/ilike can be chained and
662  // we can avoid the string translation
663  return nullptr;
664  }
665  const auto string_oper = dynamic_cast<const Analyzer::StringOper*>(dict_like_arg.get());
666  if (string_oper) {
667  pre_translate_string_ops(string_oper, executor());
668  }
669  const auto& pattern_ti = pattern->get_type_info();
670  CHECK(pattern_ti.is_string());
671  CHECK_EQ(kENCODING_NONE, pattern_ti.get_compression());
672  const auto& pattern_datum = pattern->get_constval();
673  const auto& pattern_str = *pattern_datum.stringval;
674  const auto matching_ids = sdp->getLike(pattern_str, ilike, is_simple, escape_char);
675  // InIntegerSet requires 64-bit values
676  std::vector<int64_t> matching_ids_64(matching_ids.size());
677  std::copy(matching_ids.begin(), matching_ids.end(), matching_ids_64.begin());
678  const auto in_values = std::make_shared<Analyzer::InIntegerSet>(
679  dict_like_arg, matching_ids_64, dict_like_arg_ti.get_notnull());
680  return codegen(in_values.get(), co);
681 }
682 
683 namespace {
684 
685 std::vector<int32_t> get_compared_ids(const StringDictionaryProxy* dict,
686  const SQLOps compare_operator,
687  const std::string& pattern) {
688  std::vector<int> ret;
689  switch (compare_operator) {
690  case kLT:
691  ret = dict->getCompare(pattern, "<");
692  break;
693  case kLE:
694  ret = dict->getCompare(pattern, "<=");
695  break;
696  case kEQ:
697  case kBW_EQ:
698  ret = dict->getCompare(pattern, "=");
699  break;
700  case kGT:
701  ret = dict->getCompare(pattern, ">");
702  break;
703  case kGE:
704  ret = dict->getCompare(pattern, ">=");
705  break;
706  case kNE:
707  ret = dict->getCompare(pattern, "<>");
708  break;
709  default:
710  std::runtime_error("unsuported operator for string comparision");
711  }
712  return ret;
713 }
714 } // namespace
715 
716 llvm::Value* CodeGenerator::codegenDictStrCmp(const std::shared_ptr<Analyzer::Expr> lhs,
717  const std::shared_ptr<Analyzer::Expr> rhs,
718  const SQLOps compare_operator,
719  const CompilationOptions& co) {
721  auto rhs_cast_oper = std::dynamic_pointer_cast<const Analyzer::UOper>(rhs);
722  auto lhs_cast_oper = std::dynamic_pointer_cast<const Analyzer::UOper>(lhs);
723  auto rhs_col_var = std::dynamic_pointer_cast<const Analyzer::ColumnVar>(rhs);
724  auto lhs_col_var = std::dynamic_pointer_cast<const Analyzer::ColumnVar>(lhs);
725  std::shared_ptr<const Analyzer::UOper> cast_oper;
726  std::shared_ptr<const Analyzer::ColumnVar> col_var;
727  auto compare_opr = compare_operator;
728  if (lhs_col_var && rhs_col_var) {
729  if (lhs_col_var->get_type_info().getStringDictKey() ==
730  rhs_col_var->get_type_info().getStringDictKey()) {
731  if (compare_operator == kEQ || compare_operator == kNE) {
732  // TODO (vraj): implement compare between two dictionary encoded columns which
733  // share a dictionary
734  return nullptr;
735  }
736  }
737  // TODO (vraj): implement compare between two dictionary encoded columns which don't
738  // shared dictionary
739  throw std::runtime_error("Decoding two Dictionary encoded columns will be slow");
740  } else if (lhs_col_var && rhs_cast_oper) {
741  cast_oper.swap(rhs_cast_oper);
742  col_var.swap(lhs_col_var);
743  } else if (lhs_cast_oper && rhs_col_var) {
744  cast_oper.swap(lhs_cast_oper);
745  col_var.swap(rhs_col_var);
746  switch (compare_operator) {
747  case kLT:
748  compare_opr = kGT;
749  break;
750  case kLE:
751  compare_opr = kGE;
752  break;
753  case kGT:
754  compare_opr = kLT;
755  break;
756  case kGE:
757  compare_opr = kLE;
758  default:
759  break;
760  }
761  }
762  if (!cast_oper || !col_var) {
763  return nullptr;
764  }
765  CHECK_EQ(kCAST, cast_oper->get_optype());
766 
767  const auto const_expr =
768  dynamic_cast<Analyzer::Constant*>(cast_oper->get_own_operand().get());
769  if (!const_expr) {
770  // Analyzer casts dictionary encoded columns to none encoded if there is a comparison
771  // between two encoded columns. Which we currently do not handle.
772  return nullptr;
773  }
774  const auto& const_val = const_expr->get_constval();
775 
776  const auto col_ti = col_var->get_type_info();
777  CHECK(col_ti.is_string());
778  CHECK_EQ(kENCODING_DICT, col_ti.get_compression());
779  const auto sdp = executor()->getStringDictionaryProxy(
780  col_ti.getStringDictKey(), executor()->getRowSetMemoryOwner(), true);
781 
782  if (sdp->storageEntryCount() > 200000000) {
783  std::runtime_error("Cardinality for string dictionary is too high");
784  return nullptr;
785  }
786 
787  const auto& pattern_str = *const_val.stringval;
788  const auto matching_ids = get_compared_ids(sdp, compare_opr, pattern_str);
789 
790  // InIntegerSet requires 64-bit values
791  std::vector<int64_t> matching_ids_64(matching_ids.size());
792  std::copy(matching_ids.begin(), matching_ids.end(), matching_ids_64.begin());
793 
794  const auto in_values = std::make_shared<Analyzer::InIntegerSet>(
795  col_var, matching_ids_64, col_ti.get_notnull());
796  return codegen(in_values.get(), co);
797 }
798 
800  const CompilationOptions& co) {
802  if (is_unnest(extract_cast_arg(expr->get_arg()))) {
803  throw std::runtime_error("REGEXP not supported for unnested expressions");
804  }
805  char escape_char{'\\'};
806  if (expr->get_escape_expr()) {
807  auto escape_char_expr =
808  dynamic_cast<const Analyzer::Constant*>(expr->get_escape_expr());
809  CHECK(escape_char_expr);
810  CHECK(escape_char_expr->get_type_info().is_string());
811  CHECK_EQ(size_t(1), escape_char_expr->get_constval().stringval->size());
812  escape_char = (*escape_char_expr->get_constval().stringval)[0];
813  }
814  auto pattern = dynamic_cast<const Analyzer::Constant*>(expr->get_pattern_expr());
815  CHECK(pattern);
816  auto fast_dict_pattern_lv =
817  codegenDictRegexp(expr->get_own_arg(), pattern, escape_char, co);
818  if (fast_dict_pattern_lv) {
819  return fast_dict_pattern_lv;
820  }
821  const auto& ti = expr->get_arg()->get_type_info();
822  CHECK(ti.is_string());
823  if (g_enable_watchdog && ti.get_compression() != kENCODING_NONE) {
824  throw WatchdogException(
825  "Cannot do REGEXP_LIKE on this dictionary encoded column, its cardinality is too "
826  "high");
827  }
828  // Now we know we are working on NONE ENCODED column. So switch back to CPU
830  throw QueryMustRunOnCpu();
831  }
832  auto str_lv = codegen(expr->get_arg(), true, co);
833  if (str_lv.size() != 3) {
834  CHECK_EQ(size_t(1), str_lv.size());
835  str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(str_lv.front(), 0));
836  str_lv.push_back(cgen_state_->ir_builder_.CreateExtractValue(str_lv.front(), 1));
837  str_lv.back() = cgen_state_->ir_builder_.CreateTrunc(
838  str_lv.back(), llvm::Type::getInt32Ty(cgen_state_->context_));
839  }
840  auto regexp_expr_arg_lvs = codegen(expr->get_pattern_expr(), true, co);
841  CHECK_EQ(size_t(3), regexp_expr_arg_lvs.size());
842  const bool is_nullable{!expr->get_arg()->get_type_info().get_notnull()};
843  std::vector<llvm::Value*> regexp_args{
844  str_lv[1], str_lv[2], regexp_expr_arg_lvs[1], regexp_expr_arg_lvs[2]};
845  std::string fn_name("regexp_like");
846  regexp_args.push_back(cgen_state_->llInt(int8_t(escape_char)));
847  if (is_nullable) {
848  fn_name += "_nullable";
849  regexp_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
851  fn_name, get_int_type(8, cgen_state_->context_), regexp_args);
852  }
854  fn_name, get_int_type(1, cgen_state_->context_), regexp_args);
855 }
856 
858  const std::shared_ptr<Analyzer::Expr> pattern_arg,
859  const Analyzer::Constant* pattern,
860  const char escape_char,
861  const CompilationOptions& co) {
863  const auto cast_oper = std::dynamic_pointer_cast<Analyzer::UOper>(pattern_arg);
864  if (!cast_oper) {
865  return nullptr;
866  }
867  CHECK(cast_oper);
868  CHECK_EQ(kCAST, cast_oper->get_optype());
869  const auto dict_regexp_arg = cast_oper->get_own_operand();
870  const auto& dict_regexp_arg_ti = dict_regexp_arg->get_type_info();
871  CHECK(dict_regexp_arg_ti.is_string());
872  CHECK_EQ(kENCODING_DICT, dict_regexp_arg_ti.get_compression());
873  const auto& dict_key = dict_regexp_arg_ti.getStringDictKey();
874  const auto sdp = executor()->getStringDictionaryProxy(
875  dict_key, executor()->getRowSetMemoryOwner(), true);
876  if (sdp->storageEntryCount() > 15000000) {
877  return nullptr;
878  }
879  if (sdp->getDictKey().isTransientDict()) {
880  // If we have a literal dictionary it was a product
881  // of string ops applied to none-encoded strings, and
882  // will not be populated at codegen-time, so we
883  // cannot use the fast path
884 
885  // Todo(todd): Once string ops support non-string producting
886  // operators (like regexp_like), these operators can be chained
887  // and we can avoid the string translation
888  return nullptr;
889  }
890  const auto string_oper =
891  dynamic_cast<const Analyzer::StringOper*>(dict_regexp_arg.get());
892  if (string_oper) {
893  pre_translate_string_ops(string_oper, executor());
894  }
895  const auto& pattern_ti = pattern->get_type_info();
896  CHECK(pattern_ti.is_string());
897  CHECK_EQ(kENCODING_NONE, pattern_ti.get_compression());
898  const auto& pattern_datum = pattern->get_constval();
899  const auto& pattern_str = *pattern_datum.stringval;
900  const auto matching_ids = sdp->getRegexpLike(pattern_str, escape_char);
901  // InIntegerSet requires 64-bit values
902  std::vector<int64_t> matching_ids_64(matching_ids.size());
903  std::copy(matching_ids.begin(), matching_ids.end(), matching_ids_64.begin());
904  const auto in_values = std::make_shared<Analyzer::InIntegerSet>(
905  dict_regexp_arg, matching_ids_64, dict_regexp_arg_ti.get_notnull());
906  return codegen(in_values.get(), co);
907 }
std::string to_lower(const std::string &str)
#define CHECK_EQ(x, y)
Definition: Logger.h:301
std::pair< const char *, size_t > getStringBytes(int32_t string_id) const noexcept
llvm::Value * codegenPerRowStringOper(const Analyzer::StringOper *string_oper, const CompilationOptions &co)
const std::shared_ptr< Analyzer::Expr > get_own_arg() const
Definition: Analyzer.h:1134
RUNTIME_EXPORT int32_t union_translate_string_id_to_other_dict(const int32_t string_id, const int64_t source_string_dict_handle, const int64_t dest_string_dict_handle)
std::vector< int32_t > get_compared_ids(const StringDictionaryProxy *dict, const SQLOps compare_operator, const std::string &pattern)
const Expr * get_escape_expr() const
Definition: Analyzer.h:1064
#define DEF_APPLY_NUMERIC_STRING_OPS(value_type, value_name)
Definition: sqltypes.h:76
__device__ StringView string_decode(int8_t *chunk_iter_, int64_t pos)
CgenState * cgen_state_
bool is_null
Definition: Datum.h:57
std::unique_ptr< StringDictionaryTranslationMgr > translate_dict_strings(const Analyzer::StringOper *expr, const ExecutorDeviceType device_type, Executor *executor)
void pre_translate_string_ops(const Analyzer::StringOper *string_oper, Executor *executor)
const Expr * get_escape_expr() const
Definition: Analyzer.h:1136
SQLOps
Definition: sqldefs.h:28
Definition: sqldefs.h:34
llvm::IRBuilder ir_builder_
Definition: CgenState.h:384
Definition: sqldefs.h:35
#define CHECK_GE(x, y)
Definition: Logger.h:306
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
llvm::Type * get_fp_type(const int width, llvm::LLVMContext &context)
const Expr * get_arg() const
Definition: Analyzer.h:1133
size_t getArity() const
Definition: Analyzer.h:1670
const Analyzer::Expr * extract_cast_arg(const Analyzer::Expr *expr)
Definition: Execute.h:222
std::string getString(int32_t string_id) const
bool requiresPerRowTranslation() const
Definition: Analyzer.h:1700
std::string toString(const QueryDescriptionType &type)
Definition: Types.h:64
int32_t write_string_to_proxy(const std::string &str, const int64_t string_dict_handle)
#define TRANSIENT_DICT_ID
Definition: DbObjectKeys.h:24
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
#define CHECK_GT(x, y)
Definition: Logger.h:305
DEVICE void ChunkIter_get_nth(ChunkIter *it, int n, bool uncompress, VarlenDatum *result, bool *is_end)
Definition: ChunkIter.cpp:182
const Expr * get_arg() const
Definition: Analyzer.h:1061
RUNTIME_EXPORT int32_t apply_multi_input_string_ops_and_encode(const char *str1_ptr, const int32_t str1_len, const char *str2_ptr, const int32_t str2_len, const int64_t string_ops_handle, const int64_t string_dict_handle)
Definition: StringOpsIR.cpp:77
ExecutorDeviceType
size_t formatHMS(char *buf, size_t const max, int64_t const unixtime)
Definition: misc.cpp:96
#define DEF_CONVERT_TO_STRING_AND_ENCODE(value_type, value_name)
int8_t * pointer
Definition: Datum.h:56
#define NULL_INT
std::vector< int32_t > getCompare(const std::string &pattern, const std::string &comp_operator) const
bool get_calc_encoded_length() const
Definition: Analyzer.h:870
llvm::LLVMContext & context_
Definition: CgenState.h:382
llvm::Value * emitExternalCall(const std::string &fname, llvm::Type *ret_type, const std::vector< llvm::Value * > args, const std::vector< llvm::Attribute::AttrKind > &fnattrs={}, const bool has_struct_return=false)
Definition: CgenState.cpp:395
Classes representing a parse tree.
RUNTIME_EXPORT ALWAYS_INLINE int32_t convert_to_string_and_encode_timestamp(const int64_t operand, const int32_t dimension, const int64_t string_dict_handle)
DEVICE auto copy(ARGS &&...args)
Definition: gpu_enabled.h:51
#define CHECK_NE(x, y)
Definition: Logger.h:302
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:65
Executor * executor_
RUNTIME_EXPORT ALWAYS_INLINE int32_t convert_to_string_and_encode_date(const int64_t operand, const int64_t string_dict_handle)
bool g_enable_watchdog
bool get_is_simple() const
Definition: Analyzer.h:1066
std::string_view stringView() const
Definition: Datum.h:44
llvm::Value * codegenDictStrCmp(const std::shared_ptr< Analyzer::Expr >, const std::shared_ptr< Analyzer::Expr >, const SQLOps, const CompilationOptions &co)
llvm::Value * codegenDictRegexp(const std::shared_ptr< Analyzer::Expr > arg, const Analyzer::Constant *pattern, const char escape_char, const CompilationOptions &)
#define AUTOMATIC_IR_METADATA(CGENSTATE)
double power10inv(unsigned const x)
Definition: misc.h:282
int32_t getOrAddTransient(const std::string &)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:217
std::string * stringval
Definition: Datum.h:79
llvm::Constant * inlineNull(const SQLTypeInfo &)
Definition: CgenState.cpp:116
ExecutorDeviceType device_type
#define RUNTIME_EXPORT
std::vector< StringOps_Namespace::StringOpInfo > getStringOpInfos(const Analyzer::StringOper *expr)
Definition: sqldefs.h:33
size_t formatDate(char *buf, size_t const max, int64_t const unixtime)
Definition: misc.cpp:27
RUNTIME_EXPORT ALWAYS_INLINE int32_t convert_to_string_and_encode_decimal(const int64_t operand, const int32_t precision, const int32_t scale, const int64_t string_dict_handle)
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
const Expr * get_pattern_expr() const
Definition: Analyzer.h:1135
#define CHECK_LT(x, y)
Definition: Logger.h:303
Definition: sqltypes.h:79
Definition: sqltypes.h:80
Expression class for string functions The &quot;arg&quot; constructor parameter must be an expression that reso...
Definition: Analyzer.h:1601
#define CHECK_LE(x, y)
Definition: Logger.h:304
RUNTIME_EXPORT int32_t intersect_translate_string_id_to_other_dict(const int32_t string_id, const int64_t source_string_dict_handle, const int64_t dest_string_dict_handle)
Definition: StringOpsIR.cpp:96
RUNTIME_EXPORT int32_t apply_string_ops_and_encode(const char *str_ptr, const int32_t str_len, const int64_t string_ops_handle, const int64_t string_dict_handle)
Definition: StringOpsIR.cpp:61
SqlStringOpKind get_kind() const
Definition: Analyzer.h:1668
const Expr * get_like_expr() const
Definition: Analyzer.h:1063
Datum get_constval() const
Definition: Analyzer.h:348
Definition: sqldefs.h:31
const Expr * get_arg() const
Definition: Analyzer.h:868
llvm::StructType * createStringViewStructType()
size_t formatDateTime(char *buf, size_t const max, int64_t const timestamp, int const dimension, bool use_iso_format)
Definition: misc.cpp:45
std::pair< std::vector< llvm::Value * >, std::unique_ptr< CodeGenerator::NullCheckCodegen > > codegenStringFetchAndEncode(const Analyzer::StringOper *expr, const CompilationOptions &co, const size_t arg_idx, const bool codegen_nullcheck)
RUNTIME_EXPORT ALWAYS_INLINE int32_t convert_to_string_and_encode_time(const int64_t operand, const int64_t string_dict_handle)
RUNTIME_EXPORT ALWAYS_INLINE int32_t convert_to_string_and_encode_bool(const int8_t operand, const int64_t string_dict_handle)
const Expr * get_arg() const
Definition: Analyzer.h:917
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:249
#define CHECK(condition)
Definition: Logger.h:291
Definition: sqldefs.h:30
bool g_cluster
Definition: sqldefs.h:32
const StringDictionaryTranslationMgr * moveStringDictionaryTranslationMgr(std::unique_ptr< const StringDictionaryTranslationMgr > &&str_dict_translation_mgr)
Definition: CgenState.h:199
Definition: sqltypes.h:72
const std::shared_ptr< Analyzer::Expr > get_own_arg() const
Definition: Analyzer.h:1062
bool is_unnest(const Analyzer::Expr *expr)
Definition: Execute.h:1692
HOST DEVICE bool get_notnull() const
Definition: sqltypes.h:398
llvm::Value * codegen(llvm::Value *str_id_input, const SQLTypeInfo &input_ti, const bool add_nullcheck, const CompilationOptions &co) const
#define ALWAYS_INLINE
size_t getNonLiteralsArity() const
Definition: Analyzer.h:1682
std::vector< std::shared_ptr< Analyzer::Expr > > getChainedStringOpExprs() const
Definition: Analyzer.h:1696
const Expr * getArg(const size_t i) const
Definition: Analyzer.h:1684
RUNTIME_EXPORT int32_t string_compress(const StringView string_view, const int64_t string_dict_handle)
Definition: StringOpsIR.cpp:50
bool get_is_ilike() const
Definition: Analyzer.h:1065
const shared::StringDictKey & getStringDictKey() const
Definition: sqltypes.h:1055
llvm::Value * codegenDictLike(const std::shared_ptr< Analyzer::Expr > arg, const Analyzer::Constant *pattern, const bool ilike, const bool is_simple, const char escape_char, const CompilationOptions &)
size_t length
Definition: Datum.h:55
Executor * executor() const
RUNTIME_EXPORT StringView string_decompress(const int32_t string_id, const int64_t string_dict_handle)
Definition: StringOpsIR.cpp:38