OmniSciDB  eb3a3d0a03
 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 2017 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CodeGenerator.h"
18 #include "Execute.h"
19 
20 #include "../Shared/funcannotations.h"
21 #include "../Shared/sqldefs.h"
22 #include "Parser/ParserNode.h"
23 
24 #include <boost/locale/conversion.hpp>
25 
26 extern "C" RUNTIME_EXPORT uint64_t string_decode(int8_t* chunk_iter_, int64_t pos) {
27  auto chunk_iter = reinterpret_cast<ChunkIter*>(chunk_iter_);
28  VarlenDatum vd;
29  bool is_end;
30  ChunkIter_get_nth(chunk_iter, pos, false, &vd, &is_end);
31  CHECK(!is_end);
32  return vd.is_null ? 0
33  : (reinterpret_cast<uint64_t>(vd.pointer) & 0xffffffffffff) |
34  (static_cast<uint64_t>(vd.length) << 48);
35 }
36 
37 extern "C" RUNTIME_EXPORT uint64_t string_decompress(const int32_t string_id,
38  const int64_t string_dict_handle) {
39  if (string_id == NULL_INT) {
40  return 0;
41  }
42  auto string_dict_proxy =
43  reinterpret_cast<const StringDictionaryProxy*>(string_dict_handle);
44  auto string_bytes = string_dict_proxy->getStringBytes(string_id);
45  CHECK(string_bytes.first);
46  return (reinterpret_cast<uint64_t>(string_bytes.first) & 0xffffffffffff) |
47  (static_cast<uint64_t>(string_bytes.second) << 48);
48 }
49 
50 extern "C" RUNTIME_EXPORT int32_t string_compress(const int64_t ptr_and_len,
51  const int64_t string_dict_handle) {
52  std::string raw_str(reinterpret_cast<char*>(extract_str_ptr_noinline(ptr_and_len)),
53  extract_str_len_noinline(ptr_and_len));
54  auto string_dict_proxy =
55  reinterpret_cast<const StringDictionaryProxy*>(string_dict_handle);
56  return string_dict_proxy->getIdOfString(raw_str);
57 }
58 
59 extern "C" RUNTIME_EXPORT int32_t lower_encoded(int32_t string_id,
60  int64_t string_dict_proxy_address) {
61  StringDictionaryProxy* string_dict_proxy =
62  reinterpret_cast<StringDictionaryProxy*>(string_dict_proxy_address);
63  auto str = string_dict_proxy->getString(string_id);
64  return string_dict_proxy->getOrAddTransient(boost::locale::to_lower(str));
65 }
66 
68  const CompilationOptions& co) {
70  auto str_lv = codegen(expr->get_arg(), true, co);
71  if (str_lv.size() != 3) {
72  CHECK_EQ(size_t(1), str_lv.size());
73  if (g_enable_watchdog) {
74  throw WatchdogException(
75  "LENGTH / CHAR_LENGTH on dictionary-encoded strings would be slow");
76  }
77  str_lv.push_back(cgen_state_->emitCall("extract_str_ptr", {str_lv.front()}));
78  str_lv.push_back(cgen_state_->emitCall("extract_str_len", {str_lv.front()}));
79  if (co.device_type == ExecutorDeviceType::GPU) {
80  throw QueryMustRunOnCpu();
81  }
82  }
83  std::vector<llvm::Value*> charlength_args{str_lv[1], str_lv[2]};
84  std::string fn_name("char_length");
85  if (expr->get_calc_encoded_length()) {
86  fn_name += "_encoded";
87  }
88  const bool is_nullable{!expr->get_arg()->get_type_info().get_notnull()};
89  if (is_nullable) {
90  fn_name += "_nullable";
91  charlength_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
92  }
93  return expr->get_calc_encoded_length()
94  ? cgen_state_->emitExternalCall(
95  fn_name, get_int_type(32, cgen_state_->context_), charlength_args)
96  : cgen_state_->emitCall(fn_name, charlength_args);
97 }
98 
100  const CompilationOptions& co) {
102  auto str_lv = codegen(expr->get_arg(), true, co);
103  CHECK_EQ(size_t(1), str_lv.size());
104  return cgen_state_->emitCall("key_for_string_encoded", str_lv);
105 }
106 
108  const CompilationOptions& co) {
111  throw QueryMustRunOnCpu();
112  }
113 
114  auto str_id_lv = codegen(expr->get_arg(), true, co);
115  CHECK_EQ(size_t(1), str_id_lv.size());
116 
117  const auto string_dictionary_proxy = executor()->getStringDictionaryProxy(
118  expr->get_type_info().get_comp_param(), executor()->getRowSetMemoryOwner(), true);
119  CHECK(string_dictionary_proxy);
120 
121  std::vector<llvm::Value*> args{
122  str_id_lv[0],
123  cgen_state_->llInt(reinterpret_cast<int64_t>(string_dictionary_proxy))};
124 
126  "lower_encoded", get_int_type(32, cgen_state_->context_), args);
127 }
128 
130  const CompilationOptions& co) {
132  if (is_unnest(extract_cast_arg(expr->get_arg()))) {
133  throw std::runtime_error("LIKE not supported for unnested expressions");
134  }
135  char escape_char{'\\'};
136  if (expr->get_escape_expr()) {
137  auto escape_char_expr =
138  dynamic_cast<const Analyzer::Constant*>(expr->get_escape_expr());
139  CHECK(escape_char_expr);
140  CHECK(escape_char_expr->get_type_info().is_string());
141  CHECK_EQ(size_t(1), escape_char_expr->get_constval().stringval->size());
142  escape_char = (*escape_char_expr->get_constval().stringval)[0];
143  }
144  auto pattern = dynamic_cast<const Analyzer::Constant*>(expr->get_like_expr());
145  CHECK(pattern);
146  auto fast_dict_like_lv = codegenDictLike(expr->get_own_arg(),
147  pattern,
148  expr->get_is_ilike(),
149  expr->get_is_simple(),
150  escape_char,
151  co);
152  if (fast_dict_like_lv) {
153  return fast_dict_like_lv;
154  }
155  const auto& ti = expr->get_arg()->get_type_info();
156  CHECK(ti.is_string());
157  if (g_enable_watchdog && ti.get_compression() != kENCODING_NONE) {
158  throw WatchdogException(
159  "Cannot do LIKE / ILIKE on this dictionary encoded column, its cardinality is "
160  "too high");
161  }
162  auto str_lv = codegen(expr->get_arg(), true, co);
163  if (str_lv.size() != 3) {
164  CHECK_EQ(size_t(1), str_lv.size());
165  str_lv.push_back(cgen_state_->emitCall("extract_str_ptr", {str_lv.front()}));
166  str_lv.push_back(cgen_state_->emitCall("extract_str_len", {str_lv.front()}));
167  if (co.device_type == ExecutorDeviceType::GPU) {
168  throw QueryMustRunOnCpu();
169  }
170  }
171  auto like_expr_arg_lvs = codegen(expr->get_like_expr(), true, co);
172  CHECK_EQ(size_t(3), like_expr_arg_lvs.size());
173  const bool is_nullable{!expr->get_arg()->get_type_info().get_notnull()};
174  std::vector<llvm::Value*> str_like_args{
175  str_lv[1], str_lv[2], like_expr_arg_lvs[1], like_expr_arg_lvs[2]};
176  std::string fn_name{expr->get_is_ilike() ? "string_ilike" : "string_like"};
177  if (expr->get_is_simple()) {
178  fn_name += "_simple";
179  } else {
180  str_like_args.push_back(cgen_state_->llInt(int8_t(escape_char)));
181  }
182  if (is_nullable) {
183  fn_name += "_nullable";
184  str_like_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
185  }
186  return cgen_state_->emitCall(fn_name, str_like_args);
187 }
188 
190  const std::shared_ptr<Analyzer::Expr> like_arg,
191  const Analyzer::Constant* pattern,
192  const bool ilike,
193  const bool is_simple,
194  const char escape_char,
195  const CompilationOptions& co) {
197  const auto cast_oper = std::dynamic_pointer_cast<Analyzer::UOper>(like_arg);
198  if (!cast_oper) {
199  return nullptr;
200  }
201  CHECK(cast_oper);
202  CHECK_EQ(kCAST, cast_oper->get_optype());
203  const auto dict_like_arg = cast_oper->get_own_operand();
204  const auto& dict_like_arg_ti = dict_like_arg->get_type_info();
205  if (!dict_like_arg_ti.is_string()) {
206  throw(std::runtime_error("Cast from " + dict_like_arg_ti.get_type_name() + " to " +
207  cast_oper->get_type_info().get_type_name() +
208  " not supported"));
209  }
210  CHECK_EQ(kENCODING_DICT, dict_like_arg_ti.get_compression());
211  const auto sdp = executor()->getStringDictionaryProxy(
212  dict_like_arg_ti.get_comp_param(), executor()->getRowSetMemoryOwner(), true);
213  if (sdp->storageEntryCount() > 200000000) {
214  return nullptr;
215  }
216  const auto& pattern_ti = pattern->get_type_info();
217  CHECK(pattern_ti.is_string());
218  CHECK_EQ(kENCODING_NONE, pattern_ti.get_compression());
219  const auto& pattern_datum = pattern->get_constval();
220  const auto& pattern_str = *pattern_datum.stringval;
221  const auto matching_ids = sdp->getLike(pattern_str, ilike, is_simple, escape_char);
222  // InIntegerSet requires 64-bit values
223  std::vector<int64_t> matching_ids_64(matching_ids.size());
224  std::copy(matching_ids.begin(), matching_ids.end(), matching_ids_64.begin());
225  const auto in_values = std::make_shared<Analyzer::InIntegerSet>(
226  dict_like_arg, matching_ids_64, dict_like_arg_ti.get_notnull());
227  return codegen(in_values.get(), co);
228 }
229 
230 namespace {
231 
232 std::vector<int32_t> get_compared_ids(const StringDictionaryProxy* dict,
233  const SQLOps compare_operator,
234  const std::string& pattern) {
235  std::vector<int> ret;
236  switch (compare_operator) {
237  case kLT:
238  ret = dict->getCompare(pattern, "<");
239  break;
240  case kLE:
241  ret = dict->getCompare(pattern, "<=");
242  break;
243  case kEQ:
244  case kBW_EQ:
245  ret = dict->getCompare(pattern, "=");
246  break;
247  case kGT:
248  ret = dict->getCompare(pattern, ">");
249  break;
250  case kGE:
251  ret = dict->getCompare(pattern, ">=");
252  break;
253  case kNE:
254  ret = dict->getCompare(pattern, "<>");
255  break;
256  default:
257  std::runtime_error("unsuported operator for string comparision");
258  }
259  return ret;
260 }
261 } // namespace
262 
263 llvm::Value* CodeGenerator::codegenDictStrCmp(const std::shared_ptr<Analyzer::Expr> lhs,
264  const std::shared_ptr<Analyzer::Expr> rhs,
265  const SQLOps compare_operator,
266  const CompilationOptions& co) {
268  auto rhs_cast_oper = std::dynamic_pointer_cast<const Analyzer::UOper>(rhs);
269  auto lhs_cast_oper = std::dynamic_pointer_cast<const Analyzer::UOper>(lhs);
270  auto rhs_col_var = std::dynamic_pointer_cast<const Analyzer::ColumnVar>(rhs);
271  auto lhs_col_var = std::dynamic_pointer_cast<const Analyzer::ColumnVar>(lhs);
272  std::shared_ptr<const Analyzer::UOper> cast_oper;
273  std::shared_ptr<const Analyzer::ColumnVar> col_var;
274  auto compare_opr = compare_operator;
275  if (lhs_col_var && rhs_col_var) {
276  if (lhs_col_var->get_type_info().get_comp_param() ==
277  rhs_col_var->get_type_info().get_comp_param()) {
278  if (compare_operator == kEQ || compare_operator == kNE) {
279  // TODO (vraj): implement compare between two dictionary encoded columns which
280  // share a dictionary
281  return nullptr;
282  }
283  }
284  // TODO (vraj): implement compare between two dictionary encoded columns which don't
285  // shared dictionary
286  throw std::runtime_error("Decoding two Dictionary encoded columns will be slow");
287  } else if (lhs_col_var && rhs_cast_oper) {
288  cast_oper.swap(rhs_cast_oper);
289  col_var.swap(lhs_col_var);
290  } else if (lhs_cast_oper && rhs_col_var) {
291  cast_oper.swap(lhs_cast_oper);
292  col_var.swap(rhs_col_var);
293  switch (compare_operator) {
294  case kLT:
295  compare_opr = kGT;
296  break;
297  case kLE:
298  compare_opr = kGE;
299  break;
300  case kGT:
301  compare_opr = kLT;
302  break;
303  case kGE:
304  compare_opr = kLE;
305  default:
306  break;
307  }
308  }
309  if (!cast_oper || !col_var) {
310  return nullptr;
311  }
312  CHECK_EQ(kCAST, cast_oper->get_optype());
313 
314  const auto const_expr =
315  dynamic_cast<Analyzer::Constant*>(cast_oper->get_own_operand().get());
316  if (!const_expr) {
317  // Analyzer casts dictionary encoded columns to none encoded if there is a comparison
318  // between two encoded columns. Which we currently do not handle.
319  return nullptr;
320  }
321  const auto& const_val = const_expr->get_constval();
322 
323  const auto col_ti = col_var->get_type_info();
324  CHECK(col_ti.is_string());
325  CHECK_EQ(kENCODING_DICT, col_ti.get_compression());
326  const auto sdp = executor()->getStringDictionaryProxy(
327  col_ti.get_comp_param(), executor()->getRowSetMemoryOwner(), true);
328 
329  if (sdp->storageEntryCount() > 200000000) {
330  std::runtime_error("Cardinality for string dictionary is too high");
331  return nullptr;
332  }
333 
334  const auto& pattern_str = *const_val.stringval;
335  const auto matching_ids = get_compared_ids(sdp, compare_opr, pattern_str);
336 
337  // InIntegerSet requires 64-bit values
338  std::vector<int64_t> matching_ids_64(matching_ids.size());
339  std::copy(matching_ids.begin(), matching_ids.end(), matching_ids_64.begin());
340 
341  const auto in_values = std::make_shared<Analyzer::InIntegerSet>(
342  col_var, matching_ids_64, col_ti.get_notnull());
343  return codegen(in_values.get(), co);
344 }
345 
347  const CompilationOptions& co) {
349  if (is_unnest(extract_cast_arg(expr->get_arg()))) {
350  throw std::runtime_error("REGEXP not supported for unnested expressions");
351  }
352  char escape_char{'\\'};
353  if (expr->get_escape_expr()) {
354  auto escape_char_expr =
355  dynamic_cast<const Analyzer::Constant*>(expr->get_escape_expr());
356  CHECK(escape_char_expr);
357  CHECK(escape_char_expr->get_type_info().is_string());
358  CHECK_EQ(size_t(1), escape_char_expr->get_constval().stringval->size());
359  escape_char = (*escape_char_expr->get_constval().stringval)[0];
360  }
361  auto pattern = dynamic_cast<const Analyzer::Constant*>(expr->get_pattern_expr());
362  CHECK(pattern);
363  auto fast_dict_pattern_lv =
364  codegenDictRegexp(expr->get_own_arg(), pattern, escape_char, co);
365  if (fast_dict_pattern_lv) {
366  return fast_dict_pattern_lv;
367  }
368  const auto& ti = expr->get_arg()->get_type_info();
369  CHECK(ti.is_string());
370  if (g_enable_watchdog && ti.get_compression() != kENCODING_NONE) {
371  throw WatchdogException(
372  "Cannot do REGEXP_LIKE on this dictionary encoded column, its cardinality is too "
373  "high");
374  }
375  // Now we know we are working on NONE ENCODED column. So switch back to CPU
377  throw QueryMustRunOnCpu();
378  }
379  auto str_lv = codegen(expr->get_arg(), true, co);
380  if (str_lv.size() != 3) {
381  CHECK_EQ(size_t(1), str_lv.size());
382  str_lv.push_back(cgen_state_->emitCall("extract_str_ptr", {str_lv.front()}));
383  str_lv.push_back(cgen_state_->emitCall("extract_str_len", {str_lv.front()}));
384  }
385  auto regexp_expr_arg_lvs = codegen(expr->get_pattern_expr(), true, co);
386  CHECK_EQ(size_t(3), regexp_expr_arg_lvs.size());
387  const bool is_nullable{!expr->get_arg()->get_type_info().get_notnull()};
388  std::vector<llvm::Value*> regexp_args{
389  str_lv[1], str_lv[2], regexp_expr_arg_lvs[1], regexp_expr_arg_lvs[2]};
390  std::string fn_name("regexp_like");
391  regexp_args.push_back(cgen_state_->llInt(int8_t(escape_char)));
392  if (is_nullable) {
393  fn_name += "_nullable";
394  regexp_args.push_back(cgen_state_->inlineIntNull(expr->get_type_info()));
395  return cgen_state_->emitExternalCall(
396  fn_name, get_int_type(8, cgen_state_->context_), regexp_args);
397  }
398  return cgen_state_->emitExternalCall(
399  fn_name, get_int_type(1, cgen_state_->context_), regexp_args);
400 }
401 
403  const std::shared_ptr<Analyzer::Expr> pattern_arg,
404  const Analyzer::Constant* pattern,
405  const char escape_char,
406  const CompilationOptions& co) {
408  const auto cast_oper = std::dynamic_pointer_cast<Analyzer::UOper>(pattern_arg);
409  if (!cast_oper) {
410  return nullptr;
411  }
412  CHECK(cast_oper);
413  CHECK_EQ(kCAST, cast_oper->get_optype());
414  const auto dict_regexp_arg = cast_oper->get_own_operand();
415  const auto& dict_regexp_arg_ti = dict_regexp_arg->get_type_info();
416  CHECK(dict_regexp_arg_ti.is_string());
417  CHECK_EQ(kENCODING_DICT, dict_regexp_arg_ti.get_compression());
418  const auto comp_param = dict_regexp_arg_ti.get_comp_param();
419  const auto sdp = executor()->getStringDictionaryProxy(
420  comp_param, executor()->getRowSetMemoryOwner(), true);
421  if (sdp->storageEntryCount() > 15000000) {
422  return nullptr;
423  }
424  const auto& pattern_ti = pattern->get_type_info();
425  CHECK(pattern_ti.is_string());
426  CHECK_EQ(kENCODING_NONE, pattern_ti.get_compression());
427  const auto& pattern_datum = pattern->get_constval();
428  const auto& pattern_str = *pattern_datum.stringval;
429  const auto matching_ids = sdp->getRegexpLike(pattern_str, escape_char);
430  // InIntegerSet requires 64-bit values
431  std::vector<int64_t> matching_ids_64(matching_ids.size());
432  std::copy(matching_ids.begin(), matching_ids.end(), matching_ids_64.begin());
433  const auto in_values = std::make_shared<Analyzer::InIntegerSet>(
434  dict_regexp_arg, matching_ids_64, dict_regexp_arg_ti.get_notnull());
435  return codegen(in_values.get(), co);
436 }
std::string to_lower(const std::string &str)
#define CHECK_EQ(x, y)
Definition: Logger.h:217
std::pair< const char *, size_t > getStringBytes(int32_t string_id) const noexcept
const std::shared_ptr< Analyzer::Expr > get_own_arg() const
Definition: Analyzer.h:1012
bool g_enable_watchdog
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:942
CgenState * cgen_state_
bool is_null
Definition: sqltypes.h:153
const Expr * get_escape_expr() const
Definition: Analyzer.h:1014
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.h:228
SQLOps
Definition: sqldefs.h:29
Definition: sqldefs.h:35
Definition: sqldefs.h:36
Definition: sqldefs.h:49
Definition: sqldefs.h:30
const Expr * get_arg() const
Definition: Analyzer.h:1011
const Analyzer::Expr * extract_cast_arg(const Analyzer::Expr *expr)
Definition: Execute.h:199
std::string getString(int32_t string_id) const
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
DEVICE void ChunkIter_get_nth(ChunkIter *it, int n, bool uncompress, VarlenDatum *result, bool *is_end)
Definition: ChunkIter.cpp:181
const Expr * get_arg() const
Definition: Analyzer.h:939
int8_t * pointer
Definition: sqltypes.h:152
#define NULL_INT
NEVER_INLINE int8_t * extract_str_ptr_noinline(const uint64_t str_and_len)
std::vector< int32_t > getCompare(const std::string &pattern, const std::string &comp_operator) const
llvm::LLVMContext & context_
Definition: CgenState.h:338
Classes representing a parse tree.
DEVICE auto copy(ARGS &&...args)
Definition: gpu_enabled.h:51
bool get_is_simple() const
Definition: Analyzer.h:944
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)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:78
NEVER_INLINE int32_t extract_str_len_noinline(const uint64_t str_and_len)
llvm::Value * emitCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:175
std::string * stringval
Definition: sqltypes.h:220
ExecutorDeviceType device_type
#define RUNTIME_EXPORT
Definition: sqldefs.h:34
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:1013
const Expr * get_like_expr() const
Definition: Analyzer.h:941
Datum get_constval() const
Definition: Analyzer.h:335
Definition: sqldefs.h:32
const Expr * get_arg() const
Definition: Analyzer.h:690
RUNTIME_EXPORT int32_t string_compress(const int64_t ptr_and_len, const int64_t string_dict_handle)
Definition: StringOpsIR.cpp:50
Expression class for the LOWER (lowercase) string function. The &quot;arg&quot; constructor parameter must be a...
Definition: Analyzer.h:825
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:338
const Expr * get_arg() const
Definition: Analyzer.h:739
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:307
#define CHECK(condition)
Definition: Logger.h:209
Definition: sqldefs.h:31
int32_t getOrAddTransient(const std::string &str)
Definition: sqldefs.h:33
const std::shared_ptr< Analyzer::Expr > get_own_arg() const
Definition: Analyzer.h:940
bool is_unnest(const Analyzer::Expr *expr)
Definition: Execute.h:1217
RUNTIME_EXPORT int32_t lower_encoded(int32_t string_id, int64_t string_dict_proxy_address)
Definition: StringOpsIR.cpp:59
__device__ uint64_t string_decode(int8_t *chunk_iter_, int64_t pos)
int32_t getIdOfString(const std::string &str) const
RUNTIME_EXPORT uint64_t string_decompress(const int32_t string_id, const int64_t string_dict_handle)
Definition: StringOpsIR.cpp:37
const Expr * get_arg() const
Definition: Analyzer.h:829
bool get_is_ilike() const
Definition: Analyzer.h:943
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: sqltypes.h:151
Executor * executor() const