OmniSciDB  fe05a0c208
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ExtensionFunctionsBinding.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 
18 #include <algorithm>
19 #include "ExternalExecutor.h"
20 
21 // A rather crude function binding logic based on the types of the arguments.
22 // We want it to be possible to write specialized versions of functions to be
23 // exposed as SQL extensions. This is important especially for performance
24 // reasons, since double operations can be significantly slower than float. We
25 // compute a score for each candidate signature based on conversions required to
26 // from the function arguments as specified in the SQL query to the versions in
27 // ExtensionFunctions.hpp.
28 
29 /*
30  New implementation for binding a SQL function operator to the
31  optimal candidate within in all available extension functions.
32  */
33 
34 namespace {
35 
37  switch (ext_arg_column_type) {
39  return ExtArgumentType::Int8;
51  return ExtArgumentType::Bool;
52  default:
53  UNREACHABLE();
54  }
55  return ExtArgumentType{};
56 }
57 
59  const ExtArgumentType ext_arg_column_list_type) {
60  switch (ext_arg_column_list_type) {
62  return ExtArgumentType::Int8;
74  return ExtArgumentType::Bool;
75  default:
76  UNREACHABLE();
77  }
78  return ExtArgumentType{};
79 }
80 
82  switch (ext_arg_array_type) {
84  return ExtArgumentType::Int8;
96  return ExtArgumentType::Bool;
97  default:
98  UNREACHABLE();
99  }
100  return ExtArgumentType{};
101 }
102 
103 static int match_arguments(const SQLTypeInfo& arg_type,
104  int sig_pos,
105  const std::vector<ExtArgumentType>& sig_types,
106  int& penalty_score) {
107  /*
108  Returns non-negative integer `offset` if `arg_type` and
109  `sig_types[sig_pos:sig_pos + offset]` match.
110 
111  The `offset` value can be interpreted as the number of extension
112  function arguments that is consumed by the given `arg_type`. For
113  instance, for scalar types the offset is always 1, for array
114  types the offset is 2: one argument for array pointer value and
115  one argument for the array size value, etc.
116 
117  Returns -1 when the types of an argument and the corresponding
118  extension function argument(s) mismatch, or when downcasting would
119  be effective.
120 
121  In case of non-negative `offset` result, the function updates
122  penalty_score argument as follows:
123 
124  add 1000 if arg_type is non-scalar, otherwise:
125  add 1000 * sizeof(sig_type) / sizeof(arg_type)
126  add 1000000 if type kinds differ (integer vs double, for instance)
127 
128  */
129  int max_pos = sig_types.size() - 1;
130  if (sig_pos > max_pos) {
131  return -1;
132  }
133  auto stype = sig_types[sig_pos];
134  switch (arg_type.get_type()) {
135  case kBOOLEAN:
136  if (stype == ExtArgumentType::Bool) {
137  penalty_score += 1000;
138  return 1;
139  }
140  break;
141  case kTINYINT:
142  switch (stype) {
144  penalty_score += 1000;
145  break;
147  penalty_score += 2000;
148  break;
150  penalty_score += 4000;
151  break;
153  penalty_score += 8000;
154  break;
156  penalty_score += 1008000;
157  break; // temporary: allow integers as double arguments
158  default:
159  return -1;
160  }
161  return 1;
162  case kSMALLINT:
163  switch (stype) {
165  penalty_score += 1000;
166  break;
168  penalty_score += 2000;
169  break;
171  penalty_score += 4000;
172  break;
174  penalty_score += 1004000;
175  break; // temporary: allow integers as double arguments
176  default:
177  return -1;
178  }
179  return 1;
180  case kINT:
181  switch (stype) {
183  penalty_score += 1000;
184  break;
186  penalty_score += 2000;
187  break;
189  penalty_score += 1002000;
190  break; // temporary: allow integers as double arguments
191  default:
192  return -1;
193  }
194  return 1;
195  case kBIGINT:
196  switch (stype) {
198  penalty_score += 1000;
199  break;
201  penalty_score += 1001000;
202  break; // temporary: allow integers as double arguments
203  default:
204  return -1;
205  }
206  return 1;
207  case kFLOAT:
208  switch (stype) {
210  penalty_score += 1000;
211  break;
213  penalty_score += 2000;
214  break; // is it ok to use floats as double arguments?
215  default:
216  return -1;
217  }
218  return 1;
219  case kDOUBLE:
220  if (stype == ExtArgumentType::Double) {
221  penalty_score += 1000;
222  return 1;
223  }
224  break;
225 
226  case kPOINT:
227  case kLINESTRING:
228  if ((stype == ExtArgumentType::PInt8 || stype == ExtArgumentType::PInt16 ||
229  stype == ExtArgumentType::PInt32 || stype == ExtArgumentType::PInt64 ||
230  stype == ExtArgumentType::PFloat || stype == ExtArgumentType::PDouble) &&
231  sig_pos < max_pos && sig_types[sig_pos + 1] == ExtArgumentType::Int64) {
232  penalty_score += 1000;
233  return 2;
234  } else if (stype == ExtArgumentType::GeoPoint ||
236  penalty_score += 1000;
237  return 1;
238  }
239  break;
240  case kARRAY:
241  if ((stype == ExtArgumentType::PInt8 || stype == ExtArgumentType::PInt16 ||
242  stype == ExtArgumentType::PInt32 || stype == ExtArgumentType::PInt64 ||
243  stype == ExtArgumentType::PFloat || stype == ExtArgumentType::PDouble ||
244  stype == ExtArgumentType::PBool) &&
245  sig_pos < max_pos && sig_types[sig_pos + 1] == ExtArgumentType::Int64) {
246  penalty_score += 1000;
247  return 2;
248  } else if (is_ext_arg_type_array(stype)) {
249  // array arguments must match exactly
250  CHECK(arg_type.is_array());
251  const auto stype_ti = ext_arg_type_to_type_info(get_array_arg_elem_type(stype));
252  if (arg_type.get_elem_type() == kBOOLEAN && stype_ti.get_type() == kTINYINT) {
253  /* Boolean array has the same low-level structure as Int8 array. */
254  penalty_score += 1000;
255  return 1;
256  } else if (arg_type.get_elem_type().get_type() == stype_ti.get_type()) {
257  penalty_score += 1000;
258  return 1;
259  } else {
260  return -1;
261  }
262  }
263  break;
264  case kPOLYGON:
265  if (stype == ExtArgumentType::PInt8 && sig_pos + 3 < max_pos &&
266  sig_types[sig_pos + 1] == ExtArgumentType::Int64 &&
267  sig_types[sig_pos + 2] == ExtArgumentType::PInt32 &&
268  sig_types[sig_pos + 3] == ExtArgumentType::Int64) {
269  penalty_score += 1000;
270  return 4;
271  } else if (stype == ExtArgumentType::GeoPolygon) {
272  penalty_score += 1000;
273  return 1;
274  }
275 
276  break;
277 
278  case kMULTIPOLYGON:
279  if (stype == ExtArgumentType::PInt8 && sig_pos + 5 < max_pos &&
280  sig_types[sig_pos + 1] == ExtArgumentType::Int64 &&
281  sig_types[sig_pos + 2] == ExtArgumentType::PInt32 &&
282  sig_types[sig_pos + 3] == ExtArgumentType::Int64 &&
283  sig_types[sig_pos + 4] == ExtArgumentType::PInt32 &&
284  sig_types[sig_pos + 5] == ExtArgumentType::Int64) {
285  penalty_score += 1000;
286  return 6;
287  } else if (stype == ExtArgumentType::GeoMultiPolygon) {
288  penalty_score += 1000;
289  return 1;
290  }
291  break;
292  case kDECIMAL:
293  case kNUMERIC:
294  if (stype == ExtArgumentType::Double && arg_type.get_logical_size() == 8) {
295  penalty_score += 1000;
296  return 1;
297  }
298  if (stype == ExtArgumentType::Float && arg_type.get_logical_size() == 4) {
299  penalty_score += 1000;
300  return 1;
301  }
302  break;
303  case kNULLT: // NULL maps to a pointer and size argument
304  if ((stype == ExtArgumentType::PInt8 || stype == ExtArgumentType::PInt16 ||
305  stype == ExtArgumentType::PInt32 || stype == ExtArgumentType::PInt64 ||
306  stype == ExtArgumentType::PFloat || stype == ExtArgumentType::PDouble ||
307  stype == ExtArgumentType::PBool) &&
308  sig_pos < max_pos && sig_types[sig_pos + 1] == ExtArgumentType::Int64) {
309  penalty_score += 1000;
310  return 2;
311  }
312  break;
313  case kCOLUMN:
314  if (is_ext_arg_type_column(stype)) {
315  // column arguments must match exactly
316  const auto stype_ti = ext_arg_type_to_type_info(get_column_arg_elem_type(stype));
317  if (arg_type.get_elem_type() == kBOOLEAN && stype_ti.get_type() == kTINYINT) {
318  /* Boolean column has the same low-level structure as Int8 column. */
319  penalty_score += 1000;
320  return 1;
321  } else if (arg_type.get_elem_type().get_type() == stype_ti.get_type()) {
322  penalty_score += 1000;
323  return 1;
324  } else {
325  return -1;
326  }
327  }
328  break;
329  case kCOLUMN_LIST:
330  if (is_ext_arg_type_column_list(stype)) {
331  // column_list arguments must match exactly
332  const auto stype_ti =
334  if (arg_type.get_elem_type() == kBOOLEAN && stype_ti.get_type() == kTINYINT) {
335  /* Boolean column_list has the same low-level structure as Int8 column_list. */
336  penalty_score += 10000;
337  return 1;
338  } else if (arg_type.get_elem_type().get_type() == stype_ti.get_type()) {
339  penalty_score += 10000;
340  return 1;
341  } else {
342  return -1;
343  }
344  }
345  break;
346  case kTEXT:
347  switch (arg_type.get_compression()) {
348  case kENCODING_NONE:
349  if (stype == ExtArgumentType::TextEncodingNone) {
350  penalty_score += 1000;
351  return 1;
352  }
353  return -1;
354  case kENCODING_DICT:
356  penalty_score += 1000;
357  return 1;
358  }
359  default:;
360  // todo: dict(8) and dict(16) encodings
361  }
362  /* Not implemented types:
363  kCHAR
364  kVARCHAR
365  kTIME
366  kTIMESTAMP
367  kDATE
368  kINTERVAL_DAY_TIME
369  kINTERVAL_YEAR_MONTH
370  kGEOMETRY
371  kGEOGRAPHY
372  kEVAL_CONTEXT_TYPE
373  kVOID
374  kCURSOR
375  */
376  default:
377  throw std::runtime_error(std::string(__FILE__) + "#" + std::to_string(__LINE__) +
378  ": support for " + arg_type.get_type_name() +
379  "(type=" + std::to_string(arg_type.get_type()) + ")" +
380  +" not implemented: \n pos=" + std::to_string(sig_pos) +
381  " max_pos=" + std::to_string(max_pos) + "\n sig_types=(" +
382  ExtensionFunctionsWhitelist::toString(sig_types) + ")");
383  }
384  return -1;
385 }
386 
387 bool is_valid_identifier(std::string str) {
388  if (!str.size()) {
389  return false;
390  }
391 
392  if (!(std::isalpha(str[0]) || str[0] == '_')) {
393  return false;
394  }
395 
396  for (size_t i = 1; i < str.size(); i++) {
397  if (!(std::isalnum(str[i]) || str[i] == '_')) {
398  return false;
399  }
400  }
401 
402  return true;
403 }
404 
405 } // namespace
406 
407 template <typename T>
408 std::tuple<T, std::vector<SQLTypeInfo>> bind_function(
409  std::string name,
410  Analyzer::ExpressionPtrVector func_args, // function args from sql query
411  const std::vector<T>& ext_funcs, // list of functions registered
412  const std::string processor) {
413  /* worker function
414 
415  Template type T must implement the following methods:
416 
417  std::vector<ExtArgumentType> getInputArgs()
418  */
419  /*
420  Return extension function/table function that has the following
421  properties
422 
423  1. each argument type in `arg_types` matches with extension
424  function argument types.
425 
426  For scalar types, the matching means that the types are either
427  equal or the argument type is smaller than the corresponding
428  the extension function argument type. This ensures that no
429  information is lost when casting of argument values is
430  required.
431 
432  For array and geo types, the matching means that the argument
433  type matches exactly with a group of extension function
434  argument types. See `match_arguments`.
435 
436  2. has minimal penalty score among all implementations of the
437  extension function with given `name`, see `get_penalty_score`
438  for the definition of penalty score.
439 
440  It is assumed that function_oper and extension functions in
441  ext_funcs have the same name.
442  */
443  if (!is_valid_identifier(name)) {
444  throw NativeExecutionError(
445  "Cannot bind function with invalid UDF/UDTF function name: " + name);
446  }
447 
448  int minimal_score = std::numeric_limits<int>::max();
449  int index = -1;
450  int optimal = -1;
451  int optimal_variant = -1;
452 
453  std::vector<SQLTypeInfo> type_infos_input;
454  for (auto atype : func_args) {
455  if constexpr (std::is_same_v<T, table_functions::TableFunction>) {
456  if (dynamic_cast<const Analyzer::ColumnVar*>(atype.get())) {
457  auto ti = generate_column_type(atype->get_type_info().get_type());
458  type_infos_input.push_back(ti);
459  continue;
460  }
461  }
462  type_infos_input.push_back(atype->get_type_info());
463  }
464 
465  // clang-format off
466  /*
467  Table functions may have arguments such as ColumnList that collect
468  neighboring columns with the same data type into a single object.
469  Here we compute all possible combinations of mapping a subset of
470  columns into columns sets. For example, if the types of function
471  arguments are (as given in func_args argument)
472 
473  (Column<int>, Column<int>, Column<int>, int)
474 
475  then the computed variants will be
476 
477  (Column<int>, Column<int>, Column<int>, int)
478  (Column<int>, Column<int>, ColumnList[1]<int>, int)
479  (Column<int>, ColumnList[1]<int>, Column<int>, int)
480  (Column<int>, ColumnList[2]<int>, int)
481  (ColumnList[1]<int>, Column<int>, Column<int>, int)
482  (ColumnList[1]<int>, Column<int>, ColumnList[1]<int>, int)
483  (ColumnList[2]<int>, Column<int>, int)
484  (ColumnList[3]<int>, int)
485 
486  where the integers in [..] indicate the number of collected
487  columns. In the SQLTypeInfo instance, this number is stored in the
488  SQLTypeInfo dimension attribute.
489 
490  As an example, let us consider a SQL query containing the
491  following expression calling a UDTF foo:
492 
493  table(foo(cursor(select a, b, c from tableofints), 1))
494 
495  Here follows a list of table functions and the corresponding
496  optimal argument type variants that are computed for the given
497  query expression:
498 
499  UDTF: foo(ColumnList<int>, RowMultiplier) -> Column<int>
500  (ColumnList[3]<int>, int) # a, b, c are all collected to column_list
501 
502  UDTF: foo(Column<int>, ColumnList<int>, RowMultiplier) -> Column<int>
503  (Column<int>, ColumnList[2]<int>, int) # b and c are collected to column_list
504 
505  UDTF: foo(Column<int>, Column<int>, Column<int>, RowMultiplier) -> Column<int>
506  (Column<int>, Column<int>, Column<int>, int)
507  */
508  // clang-format on
509  std::vector<std::vector<SQLTypeInfo>> type_infos_variants;
510  for (auto ti : type_infos_input) {
511  if (type_infos_variants.begin() == type_infos_variants.end()) {
512  type_infos_variants.push_back({ti});
513  if constexpr (std::is_same_v<T, table_functions::TableFunction>) {
514  if (ti.is_column()) {
515  auto mti = generate_column_list_type(ti.get_subtype());
516  mti.set_dimension(1);
517  type_infos_variants.push_back({mti});
518  }
519  }
520  continue;
521  }
522  std::vector<std::vector<SQLTypeInfo>> new_type_infos_variants;
523  for (auto& type_infos : type_infos_variants) {
524  if constexpr (std::is_same_v<T, table_functions::TableFunction>) {
525  if (ti.is_column()) {
526  auto new_type_infos = type_infos; // makes a copy
527  const auto& last = type_infos.back();
528  if (last.is_column_list() && last.get_subtype() == ti.get_subtype()) {
529  // last column_list consumes column argument if types match
530  new_type_infos.back().set_dimension(last.get_dimension() + 1);
531  } else {
532  // add column as column_list argument
533  auto mti = generate_column_list_type(ti.get_subtype());
534  mti.set_dimension(1);
535  new_type_infos.push_back(mti);
536  }
537  new_type_infos_variants.push_back(new_type_infos);
538  }
539  }
540  type_infos.push_back(ti);
541  }
542  type_infos_variants.insert(type_infos_variants.end(),
543  new_type_infos_variants.begin(),
544  new_type_infos_variants.end());
545  }
546 
547  // Find extension function that gives the best match on the set of
548  // argument type variants:
549  for (auto ext_func : ext_funcs) {
550  index++;
551 
552  auto ext_func_args = ext_func.getInputArgs();
553  int index_variant = -1;
554  for (const auto& type_infos : type_infos_variants) {
555  index_variant++;
556  int penalty_score = 0;
557  int pos = 0;
558  for (const auto& ti : type_infos) {
559  int offset = match_arguments(ti, pos, ext_func_args, penalty_score);
560  if (offset < 0) {
561  // atype does not match with ext_func argument
562  pos = -1;
563  break;
564  }
565  pos += offset;
566  }
567 
568  if ((size_t)pos == ext_func_args.size()) {
569  // prefer smaller return types
570  penalty_score += ext_arg_type_to_type_info(ext_func.getRet()).get_logical_size();
571  if (penalty_score < minimal_score) {
572  optimal = index;
573  minimal_score = penalty_score;
574  optimal_variant = index_variant;
575  }
576  }
577  }
578  }
579 
580  if (optimal == -1) {
581  /* no extension function found that argument types would match
582  with types in `arg_types` */
583  auto sarg_types = ExtensionFunctionsWhitelist::toString(type_infos_input);
584  std::string message;
585  if (!ext_funcs.size()) {
586  message = "Function " + name + "(" + sarg_types + ") not supported.";
587  throw ExtensionFunctionBindingError(message);
588  } else {
589  if constexpr (std::is_same_v<T, table_functions::TableFunction>) {
590  message = "Could not bind " + name + "(" + sarg_types + ") to any " + processor +
591  " UDTF implementation.";
592  } else if constexpr (std::is_same_v<T, ExtensionFunction>) {
593  message = "Could not bind " + name + "(" + sarg_types + ") to any " + processor +
594  " UDF implementation.";
595  } else {
596  LOG(FATAL) << "bind_function: unknown extension function type "
597  << typeid(T).name();
598  }
599  message += "\n Existing extension function implementations:";
600  for (const auto& ext_func : ext_funcs) {
601  // Do not show functions missing the sizer argument
602  if constexpr (std::is_same_v<T, table_functions::TableFunction>)
603  if (ext_func.useDefaultSizer())
604  continue;
605  message += "\n " + ext_func.toStringSQL();
606  }
607  }
608  throw ExtensionFunctionBindingError(message);
609  }
610 
611  // Functions with "_default_" suffix only exist for calcite
612  if constexpr (std::is_same_v<T, table_functions::TableFunction>) {
613  if (ext_funcs[optimal].hasUserSpecifiedOutputSizeMultiplier() &&
614  ext_funcs[optimal].useDefaultSizer()) {
615  std::string name = ext_funcs[optimal].getName();
616  name.erase(name.find(DEFAULT_ROW_MULTIPLIER_SUFFIX),
618  for (size_t i = 0; i < ext_funcs.size(); i++) {
619  if (ext_funcs[i].getName() == name) {
620  optimal = i;
621  std::vector<SQLTypeInfo> type_info = type_infos_variants[optimal_variant];
622  size_t sizer = ext_funcs[optimal].getOutputRowSizeParameter();
623  type_info.insert(type_info.begin() + sizer - 1, SQLTypeInfo(kINT, true));
624  return {ext_funcs[optimal], type_info};
625  }
626  }
627  UNREACHABLE();
628  }
629  }
630 
631  return {ext_funcs[optimal], type_infos_variants[optimal_variant]};
632 }
633 
634 const std::tuple<table_functions::TableFunction, std::vector<SQLTypeInfo>>
637  const std::vector<table_functions::TableFunction>& table_funcs,
638  const bool is_gpu) {
639  std::string processor = (is_gpu ? "GPU" : "CPU");
640  return bind_function<table_functions::TableFunction>(
641  name, input_args, table_funcs, processor);
642 }
643 
645  Analyzer::ExpressionPtrVector func_args) {
646  // used in RelAlgTranslator.cpp, first try GPU UDFs, then fall back
647  // to CPU UDFs.
648  bool is_gpu = true;
649  std::string processor = "GPU";
650  auto ext_funcs = ExtensionFunctionsWhitelist::get_ext_funcs(name, is_gpu);
651  if (!ext_funcs.size()) {
652  is_gpu = false;
653  processor = "CPU";
654  ext_funcs = ExtensionFunctionsWhitelist::get_ext_funcs(name, is_gpu);
655  }
656  try {
657  return std::get<0>(
658  bind_function<ExtensionFunction>(name, func_args, ext_funcs, processor));
659  } catch (ExtensionFunctionBindingError& e) {
660  if (is_gpu) {
661  is_gpu = false;
662  processor = "GPU|CPU";
663  ext_funcs = ExtensionFunctionsWhitelist::get_ext_funcs(name, is_gpu);
664  return std::get<0>(
665  bind_function<ExtensionFunction>(name, func_args, ext_funcs, processor));
666  } else {
667  throw;
668  }
669  }
670 }
671 
674  const bool is_gpu) {
675  // used below
676  std::vector<ExtensionFunction> ext_funcs =
678  std::string processor = (is_gpu ? "GPU" : "CPU");
679  return std::get<0>(
680  bind_function<ExtensionFunction>(name, func_args, ext_funcs, processor));
681 }
682 
684  const bool is_gpu) {
685  // used in ExtensionsIR.cpp
686  auto name = function_oper->getName();
687  Analyzer::ExpressionPtrVector func_args = {};
688  for (size_t i = 0; i < function_oper->getArity(); ++i) {
689  func_args.push_back(function_oper->getOwnArg(i));
690  }
691  return bind_function(name, func_args, is_gpu);
692 }
693 
694 const std::tuple<table_functions::TableFunction, std::vector<SQLTypeInfo>>
697  const bool is_gpu) {
698  // used in RelAlgExecutor.cpp
699  std::vector<table_functions::TableFunction> table_funcs =
701  return bind_table_function(name, input_args, table_funcs, is_gpu);
702 }
static std::vector< ExtensionFunction > get_ext_funcs(const std::string &name, const bool is_gpu)
ExtArgumentType get_array_arg_elem_type(const ExtArgumentType ext_arg_array_type)
size_t getArity() const
Definition: Analyzer.h:1360
bool is_ext_arg_type_column(const ExtArgumentType ext_arg_type)
#define LOG(tag)
Definition: Logger.h:194
auto generate_column_type(const SQLTypes subtype)
Definition: sqltypes.h:981
string name
Definition: setup.in.py:72
#define UNREACHABLE()
Definition: Logger.h:247
ExtArgumentType get_column_list_arg_elem_type(const ExtArgumentType ext_arg_column_list_type)
#define DEFAULT_ROW_MULTIPLIER_SUFFIX
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:314
std::string to_string(char const *&&v)
bool is_ext_arg_type_column_list(const ExtArgumentType ext_arg_type)
int get_logical_size() const
Definition: sqltypes.h:325
std::shared_ptr< Analyzer::Expr > getOwnArg(const size_t i) const
Definition: Analyzer.h:1367
bool is_ext_arg_type_array(const ExtArgumentType ext_arg_type)
auto generate_column_list_type(const SQLTypes subtype)
Definition: sqltypes.h:987
ExtArgumentType get_column_arg_elem_type(const ExtArgumentType ext_arg_column_type)
std::tuple< T, std::vector< SQLTypeInfo > > bind_function(std::string name, Analyzer::ExpressionPtrVector func_args, const std::vector< T > &ext_funcs, const std::string processor)
Definition: sqltypes.h:51
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:322
std::string get_type_name() const
Definition: sqltypes.h:417
const std::tuple< table_functions::TableFunction, std::vector< SQLTypeInfo > > bind_table_function(std::string name, Analyzer::ExpressionPtrVector input_args, const std::vector< table_functions::TableFunction > &table_funcs, const bool is_gpu)
static std::string toString(const std::vector< ExtensionFunction > &ext_funcs, std::string tab="")
#define CHECK(condition)
Definition: Logger.h:203
static std::vector< TableFunction > get_table_funcs(const std::string &name, const bool is_gpu)
std::vector< ExpressionPtr > ExpressionPtrVector
Definition: Analyzer.h:182
static int match_arguments(const SQLTypeInfo &arg_type, int sig_pos, const std::vector< ExtArgumentType > &sig_types, int &penalty_score)
Definition: sqltypes.h:44
std::string getName() const
Definition: Analyzer.h:1358
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:713
bool is_array() const
Definition: sqltypes.h:497
SQLTypeInfo ext_arg_type_to_type_info(const ExtArgumentType ext_arg_type)