OmniSciDB  c0231cc57d
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ConstantIR.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 std::vector<llvm::Value*> CodeGenerator::codegen(const Analyzer::Constant* constant,
21  const EncodingType enc_type,
22  const int dict_id,
23  const CompilationOptions& co) {
25  if (co.hoist_literals) {
26  if (const auto geo_constant = dynamic_cast<const Analyzer::GeoConstant*>(constant)) {
27  return codegenGeoConstant(geo_constant, co);
28  } else {
29  std::vector<const Analyzer::Constant*> constants(
30  executor()->deviceCount(co.device_type), constant);
31  return codegenHoistedConstants(constants, enc_type, dict_id);
32  }
33  }
34  const auto& type_info = constant->get_type_info();
35  const auto type =
36  type_info.is_decimal() ? decimal_to_int_type(type_info) : type_info.get_type();
37  switch (type) {
38  case kBOOLEAN:
39  return {llvm::ConstantInt::get(get_int_type(8, cgen_state_->context_),
40  constant->get_constval().boolval)};
41  case kTINYINT:
42  case kSMALLINT:
43  case kINT:
44  case kBIGINT:
45  case kTIME:
46  case kTIMESTAMP:
47  case kDATE:
48  case kINTERVAL_DAY_TIME:
50  return {CodeGenerator::codegenIntConst(constant, cgen_state_)};
51  case kFLOAT:
52  return {llvm::ConstantFP::get(llvm::Type::getFloatTy(cgen_state_->context_),
53  constant->get_constval().floatval)};
54  case kDOUBLE:
55  return {llvm::ConstantFP::get(llvm::Type::getDoubleTy(cgen_state_->context_),
56  constant->get_constval().doubleval)};
57  case kVARCHAR:
58  case kCHAR:
59  case kTEXT: {
60  CHECK(constant->get_constval().stringval || constant->get_is_null());
61  if (constant->get_is_null()) {
62  if (enc_type == kENCODING_DICT) {
63  return {
64  cgen_state_->llInt(static_cast<int32_t>(inline_int_null_val(type_info)))};
65  }
66  return {cgen_state_->llInt(int64_t(0)),
67  llvm::Constant::getNullValue(
68  llvm::PointerType::get(get_int_type(8, cgen_state_->context_), 0)),
69  cgen_state_->llInt(int32_t(0))};
70  }
71  const auto& str_const = *constant->get_constval().stringval;
72  if (enc_type == kENCODING_DICT) {
73  return {
75  ->getStringDictionaryProxy(
76  dict_id, executor()->getRowSetMemoryOwner(), true)
77  ->getIdOfString(str_const))};
78  }
79  return {cgen_state_->llInt(int64_t(0)),
80  cgen_state_->addStringConstant(str_const),
81  cgen_state_->llInt(static_cast<int32_t>(str_const.size()))};
82  }
83  default:
84  CHECK(false);
85  }
86  abort();
87 }
88 
89 llvm::ConstantInt* CodeGenerator::codegenIntConst(const Analyzer::Constant* constant,
90  CgenState* cgen_state) {
91  const auto& type_info = constant->get_type_info();
92  if (constant->get_is_null()) {
93  return cgen_state->inlineIntNull(type_info);
94  }
95  const auto type =
96  type_info.is_decimal() ? decimal_to_int_type(type_info) : type_info.get_type();
97  switch (type) {
98  case kTINYINT:
99  return cgen_state->llInt(constant->get_constval().tinyintval);
100  case kSMALLINT:
101  return cgen_state->llInt(constant->get_constval().smallintval);
102  case kINT:
103  return cgen_state->llInt(constant->get_constval().intval);
104  case kBIGINT:
105  return cgen_state->llInt(constant->get_constval().bigintval);
106  case kTIME:
107  case kTIMESTAMP:
108  case kDATE:
109  case kINTERVAL_DAY_TIME:
111  return cgen_state->llInt(constant->get_constval().bigintval);
112  default:
113  UNREACHABLE();
114  }
115  UNREACHABLE();
116  return nullptr;
117 }
118 
119 namespace {
120 
121 SQLTypes get_phys_int_type(const size_t byte_sz) {
122  switch (byte_sz) {
123  case 1:
124  return kTINYINT;
125  case 2:
126  return kSMALLINT;
127  case 4:
128  return kINT;
129  case 8:
130  return kBIGINT;
131  default:
132  CHECK(false);
133  }
134  return kNULLT;
135 }
136 
137 } // namespace
138 
139 // Below, the val_bits_in used to always equal the val_bits_out so we're being cautious.
141 
143  const SQLTypeInfo& type_info,
144  const EncodingType enc_type,
145  const int dict_id,
146  const int16_t lit_off,
147  const size_t lit_bytes) {
149  std::string literal_name = "literal_" + std::to_string(lit_off);
150  auto lit_buff_query_func_lv = get_arg_by_name(cgen_state_->query_func_, "literals");
151  const auto lit_buf_start = cgen_state_->query_func_entry_ir_builder_.CreateGEP(
152  lit_buff_query_func_lv->getType()->getScalarType()->getPointerElementType(),
153  lit_buff_query_func_lv,
154  cgen_state_->llInt(lit_off));
155  CHECK(!type_info.is_geometry());
156  if (type_info.is_string() && enc_type != kENCODING_DICT) {
158  CHECK_EQ(size_t(4),
160  auto off_and_len_ptr = cgen_state_->query_func_entry_ir_builder_.CreateBitCast(
161  lit_buf_start,
162  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0));
163  // packed offset + length, 16 bits each
164  auto off_and_len = cgen_state_->query_func_entry_ir_builder_.CreateLoad(
165  off_and_len_ptr->getType()->getPointerElementType(), off_and_len_ptr);
166  auto off_lv = cgen_state_->query_func_entry_ir_builder_.CreateLShr(
168  off_and_len, cgen_state_->llInt(int32_t(0xffff0000))),
169  cgen_state_->llInt(int32_t(16)));
170  auto len_lv = cgen_state_->query_func_entry_ir_builder_.CreateAnd(
171  off_and_len, cgen_state_->llInt(int32_t(0x0000ffff)));
172 
173  auto var_start = cgen_state_->llInt(int64_t(0));
174  auto var_start_address = cgen_state_->query_func_entry_ir_builder_.CreateGEP(
175  lit_buff_query_func_lv->getType()->getScalarType()->getPointerElementType(),
176  lit_buff_query_func_lv,
177  off_lv);
178  auto var_length = len_lv;
179 
180  var_start->setName(literal_name + "_start");
181  var_start_address->setName(literal_name + "_start_address");
182  var_length->setName(literal_name + "_length");
183 
184  return {var_start, var_start_address, var_length};
185  } else if (type_info.is_array() &&
186  (enc_type == kENCODING_NONE || enc_type == kENCODING_GEOINT)) {
187  if (enc_type == kENCODING_NONE) {
189  } else if (enc_type == kENCODING_GEOINT) {
191  CHECK_EQ(kTINYINT, type_info.get_subtype());
192  }
193 
194  auto off_and_len_ptr = cgen_state_->query_func_entry_ir_builder_.CreateBitCast(
195  lit_buf_start,
196  llvm::PointerType::get(get_int_type(32, cgen_state_->context_), 0));
197  // packed offset + length, 16 bits each
198  auto off_and_len = cgen_state_->query_func_entry_ir_builder_.CreateLoad(
199  off_and_len_ptr->getType()->getPointerElementType(), off_and_len_ptr);
200  auto off_lv = cgen_state_->query_func_entry_ir_builder_.CreateLShr(
202  off_and_len, cgen_state_->llInt(int32_t(0xffff0000))),
203  cgen_state_->llInt(int32_t(16)));
204  auto len_lv = cgen_state_->query_func_entry_ir_builder_.CreateAnd(
205  off_and_len, cgen_state_->llInt(int32_t(0x0000ffff)));
206 
207  auto var_start_address = cgen_state_->query_func_entry_ir_builder_.CreateGEP(
208  lit_buff_query_func_lv->getType()->getScalarType()->getPointerElementType(),
209  lit_buff_query_func_lv,
210  off_lv);
211  auto var_length = len_lv;
212 
213  var_start_address->setName(literal_name + "_start_address");
214  var_length->setName(literal_name + "_length");
215 
216  return {var_start_address, var_length};
217  }
218 
219  // Load a literal from the literal buffer. See also getOrAddLiteral().
220  llvm::Type* val_ptr_type{nullptr};
221  // NOTE(sy): If val_bits_in is ever different from val_bits_out, that means we need to
222  // generate casting below for the type that has this happen. Currently only the decimal
223  // type is known to ever have this happen.
224  const size_t lit_bits = lit_bytes * 8;
225  const size_t val_bits_out = get_bit_width(type_info);
226  const size_t val_bits_in = type_info.is_decimal() ? lit_bits : val_bits_out;
227  if (val_bits_in != lit_bits && !g_allow_invalid_literal_buffer_reads) {
228  // Refuse to read the wrong number of bytes from the literal buffer.
229  std::stringstream ss;
230  ss << "Invalid literal buffer read size " << val_bits_in << " (expected " << lit_bits
231  << ") for type " << toString(type_info.get_type())
232  << ". See also: --allow-invalid-literal-buffer-reads";
233  LOG(ERROR) << "ERROR: " << ss.str();
234  LOG(ERROR) << type_info.to_string();
235  throw std::runtime_error(ss.str());
236  }
237  CHECK_EQ(size_t(0), val_bits_in % 8);
238  CHECK_EQ(size_t(0), val_bits_out % 8);
239  if (type_info.is_integer() || type_info.is_decimal() || type_info.is_time() ||
240  type_info.is_timeinterval() || type_info.is_string() || type_info.is_boolean()) {
241  val_ptr_type = llvm::PointerType::get(
242  llvm::IntegerType::get(cgen_state_->context_, val_bits_in), 0);
243  } else {
244  CHECK(type_info.get_type() == kFLOAT || type_info.get_type() == kDOUBLE);
245  val_ptr_type = (type_info.get_type() == kFLOAT)
246  ? llvm::Type::getFloatPtrTy(cgen_state_->context_)
247  : llvm::Type::getDoublePtrTy(cgen_state_->context_);
248  }
249  auto* bit_cast = cgen_state_->query_func_entry_ir_builder_.CreateBitCast(lit_buf_start,
250  val_ptr_type);
251  llvm::Value* lit_lv = cgen_state_->query_func_entry_ir_builder_.CreateLoad(
252  bit_cast->getType()->getPointerElementType(), bit_cast);
253  if (type_info.is_decimal() && val_bits_in != val_bits_out) {
254  // Generate casting.
255  SQLTypeInfo type_info_in(get_phys_int_type(val_bits_in / 8),
256  type_info.get_dimension(),
257  type_info.get_scale(),
258  false,
260  0,
261  type_info.get_subtype());
262  SQLTypeInfo type_info_out(get_phys_int_type(val_bits_out / 8),
263  type_info.get_dimension(),
264  type_info.get_scale(),
265  false,
267  0,
268  type_info.get_subtype());
269  lit_lv = cgen_state_->emitEntryCall("cast_int" + std::to_string(val_bits_in) +
270  "_t_to_int" + std::to_string(val_bits_out) +
271  "_t_nullable",
272  {lit_lv,
273  cgen_state_->inlineIntNull(type_info_in),
274  cgen_state_->inlineIntNull(type_info_out)});
275  }
276  lit_lv->setName(literal_name);
277  return {lit_lv};
278 }
279 
281  const SQLTypeInfo& type_info,
282  const EncodingType enc_type,
283  const int16_t lit_off,
284  const std::vector<llvm::Value*>& literal_loads) {
286  std::string literal_name = "literal_" + std::to_string(lit_off);
287  CHECK(!type_info.is_geometry());
288 
289  if (type_info.is_string() && enc_type != kENCODING_DICT) {
290  CHECK_EQ(literal_loads.size(), 3u);
291 
292  llvm::Value* var_start = literal_loads[0];
293  llvm::Value* var_start_address = literal_loads[1];
294  llvm::Value* var_length = literal_loads[2];
295 
296  llvm::PointerType* placeholder0_type =
297  llvm::PointerType::get(var_start->getType(), 0);
298  auto* int_to_ptr0 =
299  cgen_state_->ir_builder_.CreateIntToPtr(cgen_state_->llInt(0), placeholder0_type);
300  auto placeholder0 = cgen_state_->ir_builder_.CreateLoad(
301  int_to_ptr0->getType()->getPointerElementType(),
302  int_to_ptr0,
303  "__placeholder__" + literal_name + "_start");
304  llvm::PointerType* placeholder1_type =
305  llvm::PointerType::get(var_start_address->getType(), 0);
306  auto* int_to_ptr1 =
307  cgen_state_->ir_builder_.CreateIntToPtr(cgen_state_->llInt(0), placeholder1_type);
308  auto placeholder1 = cgen_state_->ir_builder_.CreateLoad(
309  int_to_ptr1->getType()->getPointerElementType(),
310  int_to_ptr1,
311  "__placeholder__" + literal_name + "_start_address");
312  llvm::PointerType* placeholder2_type =
313  llvm::PointerType::get(var_length->getType(), 0);
314  auto* int_to_ptr2 =
315  cgen_state_->ir_builder_.CreateIntToPtr(cgen_state_->llInt(0), placeholder2_type);
316  auto placeholder2 = cgen_state_->ir_builder_.CreateLoad(
317  int_to_ptr2->getType()->getPointerElementType(),
318  int_to_ptr2,
319  "__placeholder__" + literal_name + "_length");
320 
321  cgen_state_->row_func_hoisted_literals_[placeholder0] = {lit_off, 0};
322  cgen_state_->row_func_hoisted_literals_[placeholder1] = {lit_off, 1};
323  cgen_state_->row_func_hoisted_literals_[placeholder2] = {lit_off, 2};
324 
325  return {placeholder0, placeholder1, placeholder2};
326  }
327 
328  if (type_info.is_array() &&
329  (enc_type == kENCODING_NONE || enc_type == kENCODING_GEOINT)) {
330  CHECK_EQ(literal_loads.size(), 2u);
331 
332  llvm::Value* var_start_address = literal_loads[0];
333  llvm::Value* var_length = literal_loads[1];
334 
335  llvm::PointerType* placeholder0_type =
336  llvm::PointerType::get(var_start_address->getType(), 0);
337  auto* int_to_ptr0 =
338  cgen_state_->ir_builder_.CreateIntToPtr(cgen_state_->llInt(0), placeholder0_type);
339  auto placeholder0 = cgen_state_->ir_builder_.CreateLoad(
340  int_to_ptr0->getType()->getPointerElementType(),
341  int_to_ptr0,
342  "__placeholder__" + literal_name + "_start_address");
343  llvm::PointerType* placeholder1_type =
344  llvm::PointerType::get(var_length->getType(), 0);
345  auto* int_to_ptr1 =
346  cgen_state_->ir_builder_.CreateIntToPtr(cgen_state_->llInt(0), placeholder1_type);
347  auto placeholder1 = cgen_state_->ir_builder_.CreateLoad(
348  int_to_ptr1->getType()->getPointerElementType(),
349  int_to_ptr1,
350  "__placeholder__" + literal_name + "_length");
351 
352  cgen_state_->row_func_hoisted_literals_[placeholder0] = {lit_off, 0};
353  cgen_state_->row_func_hoisted_literals_[placeholder1] = {lit_off, 1};
354 
355  return {placeholder0, placeholder1};
356  }
357 
358  CHECK_EQ(literal_loads.size(), 1u);
359  llvm::Value* to_return_lv = literal_loads[0];
360 
361  auto* int_to_ptr = cgen_state_->ir_builder_.CreateIntToPtr(
362  cgen_state_->llInt(0), llvm::PointerType::get(to_return_lv->getType(), 0));
363  auto placeholder0 =
364  cgen_state_->ir_builder_.CreateLoad(int_to_ptr->getType()->getPointerElementType(),
365  int_to_ptr,
366  "__placeholder__" + literal_name);
367 
368  cgen_state_->row_func_hoisted_literals_[placeholder0] = {lit_off, 0};
369 
370  return {placeholder0};
371 }
372 
373 std::vector<llvm::Value*> CodeGenerator::codegenHoistedConstants(
374  const std::vector<const Analyzer::Constant*>& constants,
375  const EncodingType enc_type,
376  const int dict_id) {
378  CHECK(!constants.empty());
379  const auto& type_info = constants.front()->get_type_info();
380  checked_int16_t checked_lit_off{0};
381  size_t next_lit_bytes{0};
382  int16_t lit_off{-1};
383  size_t lit_bytes;
384  try {
385  for (size_t device_id = 0; device_id < constants.size(); ++device_id) {
386  const auto constant = constants[device_id];
387  const auto& crt_type_info = constant->get_type_info();
388  CHECK(type_info == crt_type_info);
389  std::tie(checked_lit_off, next_lit_bytes) =
390  cgen_state_->getOrAddLiteral(constant, enc_type, dict_id, device_id);
391  if (device_id) {
392  CHECK_EQ(lit_off, checked_lit_off);
393  CHECK_EQ(lit_bytes, next_lit_bytes);
394  } else {
395  lit_off = static_cast<int16_t>(checked_lit_off);
396  lit_bytes = next_lit_bytes;
397  }
398  }
399  } catch (const std::range_error& e) {
400  // detect literal buffer overflow when trying to
401  // assign literal buf offset which is not in a valid range
402  // to checked_type variable
403  throw TooManyLiterals();
404  }
405  CHECK_GE(lit_off, 0);
406  std::vector<llvm::Value*> hoisted_literal_loads;
407  auto entry = cgen_state_->query_func_literal_loads_.find(lit_off);
408 
409  if (entry == cgen_state_->query_func_literal_loads_.end()) {
410  hoisted_literal_loads =
411  codegenHoistedConstantsLoads(type_info, enc_type, dict_id, lit_off, lit_bytes);
412  cgen_state_->query_func_literal_loads_[lit_off] = hoisted_literal_loads;
413  } else {
414  hoisted_literal_loads = entry->second;
415  }
416 
417  std::vector<llvm::Value*> literal_placeholders = codegenHoistedConstantsPlaceholders(
418  type_info, enc_type, lit_off, hoisted_literal_loads);
419  return literal_placeholders;
420 }
int8_t tinyintval
Definition: sqltypes.h:232
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:405
#define CHECK_EQ(x, y)
Definition: Logger.h:230
llvm::Value * emitEntryCall(const std::string &fname, const std::vector< llvm::Value * > &args)
Definition: CgenState.cpp:231
Definition: sqltypes.h:63
SQLTypes
Definition: sqltypes.h:52
CgenState * cgen_state_
#define LOG(tag)
Definition: Logger.h:216
llvm::Value * addStringConstant(const std::string &str)
Definition: CgenState.h:187
HOST DEVICE int get_scale() const
Definition: sqltypes.h:409
llvm::Function * query_func_
Definition: CgenState.h:464
std::unordered_map< llvm::Value *, HoistedLiteralLoadLocator > row_func_hoisted_literals_
Definition: CgenState.h:472
llvm::IRBuilder ir_builder_
Definition: CgenState.h:441
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 15, 15, boost::multiprecision::signed_magnitude, boost::multiprecision::checked, void >> checked_int16_t
int8_t boolval
Definition: sqltypes.h:231
bool get_is_null() const
Definition: Analyzer.h:342
#define UNREACHABLE()
Definition: Logger.h:266
#define CHECK_GE(x, y)
Definition: Logger.h:235
std::unordered_map< int, std::vector< llvm::Value * > > query_func_literal_loads_
Definition: CgenState.h:466
std::string toString(const QueryDescriptionType &type)
Definition: Types.h:64
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:404
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
int32_t intval
Definition: sqltypes.h:234
bool is_time() const
Definition: sqltypes.h:606
std::string to_string(char const *&&v)
static size_t literalBytes(const CgenState::LiteralValue &lit)
Definition: CgenState.h:474
float floatval
Definition: sqltypes.h:236
boost::variant< int8_t, int16_t, int32_t, int64_t, float, double, std::pair< std::string, int >, std::string, std::vector< double >, std::vector< int32_t >, std::vector< int8_t >, std::pair< std::vector< int8_t >, int >> LiteralValue
Definition: CgenState.h:182
std::string to_string() const
Definition: sqltypes.h:568
EncodingType
Definition: sqltypes.h:253
size_t get_bit_width(const SQLTypeInfo &ti)
llvm::LLVMContext & context_
Definition: CgenState.h:439
llvm::Value * get_arg_by_name(llvm::Function *func, const std::string &name)
Definition: Execute.h:166
std::vector< llvm::Value * > codegenHoistedConstants(const std::vector< const Analyzer::Constant * > &constants, const EncodingType enc_type, const int dict_id)
Definition: ConstantIR.cpp:373
bool is_integer() const
Definition: sqltypes.h:602
llvm::ConstantInt * inlineIntNull(const SQLTypeInfo &)
Definition: CgenState.cpp:64
int64_t bigintval
Definition: sqltypes.h:235
std::vector< llvm::Value * > codegenHoistedConstantsPlaceholders(const SQLTypeInfo &type_info, const EncodingType enc_type, const int16_t lit_off, const std::vector< llvm::Value * > &literal_loads)
Definition: ConstantIR.cpp:280
bool is_timeinterval() const
Definition: sqltypes.h:611
int16_t smallintval
Definition: sqltypes.h:233
bool is_boolean() const
Definition: sqltypes.h:607
llvm::IRBuilder query_func_entry_ir_builder_
Definition: CgenState.h:465
#define AUTOMATIC_IR_METADATA(CGENSTATE)
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:82
std::string * stringval
Definition: sqltypes.h:240
SQLTypes decimal_to_int_type(const SQLTypeInfo &ti)
Definition: Datum.cpp:499
ExecutorDeviceType device_type
std::vector< llvm::Value * > codegen(const Analyzer::Expr *, const bool fetch_columns, const CompilationOptions &)
Definition: IRCodegen.cpp:30
Definition: sqltypes.h:66
Definition: sqltypes.h:67
static llvm::ConstantInt * codegenIntConst(const Analyzer::Constant *constant, CgenState *cgen_state)
Definition: ConstantIR.cpp:89
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:412
Datum get_constval() const
Definition: Analyzer.h:343
HOST DEVICE int get_dimension() const
Definition: sqltypes.h:406
Definition: sqltypes.h:55
bool g_allow_invalid_literal_buffer_reads
Definition: ConstantIR.cpp:140
llvm::ConstantInt * llInt(const T v) const
Definition: CgenState.h:306
#define CHECK(condition)
Definition: Logger.h:222
bool is_geometry() const
Definition: sqltypes.h:612
std::vector< llvm::Value * > codegenHoistedConstantsLoads(const SQLTypeInfo &type_info, const EncodingType enc_type, const int dict_id, const int16_t lit_off, const size_t lit_bytes)
Definition: ConstantIR.cpp:142
int64_t inline_int_null_val(const SQL_TYPE_INFO &ti)
std::vector< llvm::Value * > codegenGeoConstant(const Analyzer::GeoConstant *, const CompilationOptions &)
Definition: GeoIR.cpp:111
Definition: sqltypes.h:59
bool is_string() const
Definition: sqltypes.h:600
std::tuple< size_t, size_t > getOrAddLiteral(const Analyzer::Constant *constant, const EncodingType enc_type, const int dict_id, const int device_id)
Definition: CgenState.h:46
bool is_decimal() const
Definition: sqltypes.h:603
SQLTypes get_phys_int_type(const size_t byte_sz)
Definition: ColumnIR.cpp:377
bool is_array() const
Definition: sqltypes.h:608
double doubleval
Definition: sqltypes.h:237
Executor * executor() const