OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TableFunctionsFactory.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <boost/algorithm/string.hpp>
20 
21 #include <algorithm>
22 #include <string_view>
23 #include <unordered_map>
24 #include <utility>
25 
26 extern bool g_enable_table_functions;
27 extern bool g_enable_ml_functions;
29 
30 namespace table_functions {
31 
32 namespace {
33 
35  switch (ext_arg_type) {
37  return SQLTypeInfo(kTINYINT, false);
39  return SQLTypeInfo(kSMALLINT, false);
41  return SQLTypeInfo(kINT, false);
43  return SQLTypeInfo(kBIGINT, false);
45  return SQLTypeInfo(kFLOAT, false);
47  return SQLTypeInfo(kDOUBLE, false);
49  return SQLTypeInfo(kBOOLEAN, false);
50  default:
51  return ext_arg_type_to_type_info(ext_arg_type);
52  }
53  UNREACHABLE();
54  return SQLTypeInfo(kNULLT, false);
55 }
56 
58  switch (ext_arg_type) {
60  return SQLTypeInfo(kTINYINT, false);
62  return SQLTypeInfo(kSMALLINT, false);
64  return SQLTypeInfo(kINT, false);
66  return SQLTypeInfo(kBIGINT, false);
68  return SQLTypeInfo(kFLOAT, false);
70  return SQLTypeInfo(kDOUBLE, false);
72  return SQLTypeInfo(kBOOLEAN, false);
73  default:
74  return ext_arg_type_to_type_info(ext_arg_type).get_elem_type();
75  }
76  UNREACHABLE();
77  return SQLTypeInfo(kNULLT, false);
78 }
79 
80 } // namespace
81 
83  CHECK_LT(idx, input_args_.size());
85 }
86 
88  CHECK_LT(idx, output_args_.size());
89  // TODO(adb): conditionally handle nulls
91 }
92 
93 // TODO(pearu): rename to countLiteralArgs as the relevant argument
94 // types include TextEncodingNone, Array, etc literals that are not
95 // scalars.
97  int32_t scalar_args = 0;
98  for (const auto& ext_arg : input_args_) {
99  if (is_ext_arg_type_scalar(ext_arg)) {
100  scalar_args += 1;
101  }
102  }
103  return scalar_args;
104 }
105 
107  if (hasPreFlightOutputSizer()) {
108  return true;
109  }
110  // workaround for default args
111  for (size_t idx = 0; idx < std::min(input_args_.size(), annotations_.size()); idx++) {
112  const auto& ann = getInputAnnotations(idx);
113  if (ann.find("require") != ann.end()) {
114  return true;
115  }
116  }
117  return false;
118 }
119 
120 const std::map<std::string, std::string> TableFunction::getAnnotations(
121  const size_t idx) const {
122  CHECK_LE(idx, sql_args_.size() + output_args_.size());
123  if (annotations_.empty() || idx >= annotations_.size()) {
124  static const std::map<std::string, std::string> empty = {};
125  return empty;
126  }
127  return annotations_[idx];
128 }
129 
130 const std::map<std::string, std::string> TableFunction::getInputAnnotations(
131  const size_t input_arg_idx) const {
132  CHECK_LT(input_arg_idx, input_args_.size());
133  return getAnnotations(input_arg_idx);
134 }
135 
136 const std::string TableFunction::getInputAnnotation(const size_t input_arg_idx,
137  const std::string& key,
138  const std::string& default_) const {
139  const std::map<std::string, std::string> ann = getInputAnnotations(input_arg_idx);
140  const auto& it = ann.find(key);
141  if (it != ann.end()) {
142  return it->second;
143  }
144  return default_;
145 }
146 
147 const std::map<std::string, std::string> TableFunction::getOutputAnnotations(
148  const size_t output_arg_idx) const {
149  CHECK_LT(output_arg_idx, output_args_.size());
150  return getAnnotations(output_arg_idx + sql_args_.size());
151 }
152 
153 const std::string TableFunction::getOutputAnnotation(const size_t output_arg_idx,
154  const std::string& key,
155  const std::string& default_) const {
156  const std::map<std::string, std::string> ann = getOutputAnnotations(output_arg_idx);
157  const auto& it = ann.find(key);
158  if (it != ann.end()) {
159  return it->second;
160  }
161  return default_;
162 }
163 
164 const std::map<std::string, std::string> TableFunction::getFunctionAnnotations() const {
165  return getAnnotations(sql_args_.size() + output_args_.size());
166 }
167 
169  const std::string& key,
170  const std::string& default_) const {
171  const std::map<std::string, std::string> ann = getFunctionAnnotations();
172  const auto& it = ann.find(key);
173  if (it != ann.end()) {
174  return it->second;
175  }
176  return default_;
177 }
178 
179 const std::vector<std::string> TableFunction::getCursorFields(
180  const size_t sql_idx) const {
181  std::vector<std::string> fields;
182  const std::string& line = getInputAnnotation(sql_idx, "fields", "");
183  if (line.empty()) {
184  static const std::vector<std::string> empty = {};
185  return empty;
186  }
187  std::string substr = line.substr(1, line.size() - 2);
188  boost::split(fields, substr, boost::is_any_of(", "), boost::token_compress_on);
189  return fields;
190 }
191 
192 const std::string TableFunction::getArgTypes(bool use_input_args) const {
193  if (use_input_args) {
194  std::vector<std::string> arg_types;
195  size_t arg_idx = 0;
196  for (size_t sql_idx = 0; sql_idx < sql_args_.size(); sql_idx++) {
197  const std::vector<std::string> cursor_fields = getCursorFields(sql_idx);
198  if (cursor_fields.empty()) {
199  // fields => {}
200  arg_types.emplace_back(
202  } else {
203  std::vector<std::string> vec;
204  for (size_t i = 0; i < cursor_fields.size(); i++) {
205  vec.emplace_back(ExtensionFunctionsWhitelist::toString(input_args_[arg_idx++]));
206  }
207  arg_types.emplace_back("Cursor<" + boost::algorithm::join(vec, ", ") + ">");
208  }
209  }
210  return "[" + boost::algorithm::join(arg_types, ", ") + "]";
211  } else {
213  }
214 }
215 
216 const std::string TableFunction::getArgNames(bool use_input_args) const {
217  std::vector<std::string> names;
218  if (use_input_args) {
219  for (size_t idx = 0; idx < sql_args_.size(); idx++) {
220  const std::vector<std::string> cursor_fields = getCursorFields(idx);
221  if (cursor_fields.empty()) {
222  const std::string& name = getInputAnnotation(idx, "name", "''");
223  names.emplace_back(name);
224  } else {
225  names.emplace_back("Cursor<" + boost::algorithm::join(cursor_fields, ", ") + ">");
226  }
227  }
228  } else {
229  for (size_t idx = 0; idx < output_args_.size(); idx++) {
230  const std::string& name = getOutputAnnotation(idx, "name", "''");
231  names.emplace_back(name);
232  }
233  }
234 
235  return "[" + boost::algorithm::join(names, ", ") + "]";
236 }
237 
238 const std::string TableFunction::getInputArgsDefaultValues() const {
239  std::vector<std::string> default_values;
240  default_values.reserve(sql_args_.size());
241  for (size_t idx = 0; idx < sql_args_.size(); idx++) {
242  const std::string& name = getInputAnnotation(idx, "default", "UNSPECIFIED");
243  default_values.emplace_back(name);
244  }
245 
246  return "[" + boost::algorithm::join(default_values, ",") + "]";
247 }
248 
249 std::pair<int32_t, int32_t> TableFunction::getInputID(const size_t idx) const {
250  // if the annotation is of the form args<INT,INT>, it is refering to a column list
251 #define PREFIX_LENGTH 5
252  const auto& annotation = getOutputAnnotations(idx);
253  auto annot = annotation.find("input_id");
254  if (annot == annotation.end()) {
255  size_t lo = 0;
256  for (const auto& ext_arg : input_args_) {
257  switch (ext_arg) {
279  return std::make_pair(lo, 0);
280  default:
281  lo++;
282  }
283  }
284  return {-1, -1}; // indicates unspecified
285  }
286 
287  const std::string& input_id = annot->second;
288 
289  if (input_id == "args<-1>") {
290  // empty input id! -1 seems to be the magic number used in RelAlgExecutor.cpp
291  return {-1, -1};
292  }
293 
294  size_t comma = input_id.find(",");
295  int32_t gt = input_id.size() - 1;
296  int32_t lo = std::stoi(input_id.substr(PREFIX_LENGTH, comma - 1));
297 
298  if (comma == std::string::npos) {
299  return std::make_pair(lo, 0);
300  }
301  int32_t hi = std::stoi(input_id.substr(comma + 1, gt - comma - 1));
302  return std::make_pair(lo, hi);
303 }
304 
306  /*
307  This function differs from getOutputRowSizeParameter() since it returns the correct
308  index for the sizer in the sql_args list. For instance, consider the example below:
309 
310  RowMultiplier=4
311  input_args=[{i32*, i64}, {i32*, i64}, {i32*, i64}, i32, {i32*, i64}, {i32*, i64},
312  i32] sql_args=[cursor, i32, cursor, i32]
313 
314  Non-scalar args are aggregated in a cursor inside the sql_args list and the new
315  sizer index is 2 rather than 4 originally specified.
316  */
317 
319  size_t sizer = getOutputRowSizeParameter(); // lookup until reach the sizer arg
320  int32_t ext_arg_index = 0, sql_arg_index = 0;
321 
322  auto same_kind = [&](const ExtArgumentType& ext_arg, const ExtArgumentType& sql_arg) {
323  return ((is_ext_arg_type_scalar(ext_arg) && is_ext_arg_type_scalar(sql_arg)) ||
325  };
326 
327  while ((size_t)ext_arg_index < sizer) {
328  if ((size_t)ext_arg_index == sizer - 1) {
329  return sql_arg_index;
330  }
331 
332  const auto& ext_arg = input_args_[ext_arg_index];
333  const auto& sql_arg = sql_args_[sql_arg_index];
334 
335  if (same_kind(ext_arg, sql_arg)) {
336  ++ext_arg_index;
337  ++sql_arg_index;
338  } else {
339  CHECK(same_kind(ext_arg, sql_args_[sql_arg_index - 1]));
340  ext_arg_index += 1;
341  }
342  }
343 
344  CHECK(false);
345  }
346 
347  return getOutputRowSizeParameter();
348 }
349 
350 namespace {
351 
352 template <size_t... I>
353 constexpr bool string_view_array_sorted_and_distinct(std::string_view const* list,
354  std::index_sequence<I...>) {
355  return ((list[I] < list[I + 1]) && ...);
356 }
357 
358 bool is_table_function_whitelisted(std::string_view const function_name) {
359  // All table functions that will be on by default (and not just for testing)
360  // must be added to the whitelisted_table_functions list below.
361  // These lists must be in alphabetical order (enforced at compile-time)
362  constexpr std::string_view whitelisted_table_functions[]{
363  "dbscan",
364  "decision_tree_reg_fit",
365  "gbt_reg_fit",
366  "generate_random_strings",
367  "generate_series",
368  "get_decision_trees",
369  "kmeans",
370  "linear_reg_coefs",
371  "linear_reg_fit",
372  "ml_reg_predict",
373  "pca_fit",
374  "r2_score",
375  "random_forest_reg_fit",
376  "random_forest_reg_var_importance",
377  "supported_ml_frameworks",
378  "tf_compute_dwell_times",
379  "tf_cross_section_1d",
380  "tf_cross_section_2d",
381  "tf_feature_self_similarity",
382  "tf_feature_similarity",
383  "tf_geo_multi_rasterize",
384  "tf_geo_rasterize",
385  "tf_geo_rasterize_slope",
386  "tf_graph_shortest_path",
387  "tf_graph_shortest_paths_distances",
388  "tf_load_point_cloud",
389  "tf_mandelbrot",
390  "tf_mandelbrot_cuda",
391  "tf_mandelbrot_cuda_float",
392  "tf_mandelbrot_float",
393  "tf_point_cloud_metadata",
394  "tf_raster_contour_lines",
395  "tf_raster_contour_polygons",
396  "tf_raster_graph_shortest_slope_weighted_path"
397  };
398  constexpr auto whitelisted_table_functions_len =
399  sizeof(whitelisted_table_functions) / sizeof(*whitelisted_table_functions);
400 
401 
402  // Must be sorted.
403  constexpr std::string_view ml_table_functions[]{"dbscan",
404  "decision_tree_reg_fit",
405  "gbt_reg_fit",
406  "get_decision_trees",
407  "kmeans",
408  "linear_reg_coefs",
409  "linear_reg_fit",
410  "ml_reg_predict",
411  "pca_fit"
412  "r2_score",
413  "random_forest_reg_fit",
414  "random_forest_reg_var_importance",
415  "supported_ml_frameworks"};
416  constexpr auto ml_table_functions_len =
417  sizeof(ml_table_functions) / sizeof(*ml_table_functions);
418 
419  // compile-time validation that above lists are sorted and distinct
421  whitelisted_table_functions,
422  std::make_index_sequence<whitelisted_table_functions_len - 1>{}));
424  ml_table_functions, std::make_index_sequence<ml_table_functions_len - 1>{}));
425 
426  if (!std::binary_search(whitelisted_table_functions,
427  whitelisted_table_functions + whitelisted_table_functions_len,
428  function_name)) {
429  return false;
430  }
431  return g_enable_ml_functions ||
432  !std::binary_search(ml_table_functions,
433  ml_table_functions + ml_table_functions_len,
434  function_name);
435 }
436 
437 
438 } // namespace
439 
441  const std::string& name,
442  const TableFunctionOutputRowSizer sizer,
443  const std::vector<ExtArgumentType>& input_args,
444  const std::vector<ExtArgumentType>& output_args,
445  const std::vector<ExtArgumentType>& sql_args,
446  const std::vector<std::map<std::string, std::string>>& annotations,
447  bool is_runtime) {
448  static const std::map<std::string, std::string> empty = {};
449 
450  auto func_annotations =
451  (annotations.size() == sql_args.size() + output_args.size() + 1 ? annotations.back()
452  : empty);
453  auto mgr_annotation = func_annotations.find("uses_manager");
454  bool uses_manager = mgr_annotation != func_annotations.end() &&
455  boost::algorithm::to_lower_copy(mgr_annotation->second) == "true";
456 
457  auto tf = TableFunction(name,
458  sizer,
459  input_args,
460  output_args,
461  sql_args,
462  annotations,
463  is_runtime,
464  uses_manager);
465  const auto tf_name = tf.getName(true /* drop_suffix */, true /* lower */);
466  if (!g_enable_dev_table_functions && !is_runtime &&
467  !is_table_function_whitelisted(tf_name)) {
468  return;
469  }
470  auto sig = tf.getSignature(/* include_name */ true, /* include_output */ false);
471  for (auto it = functions_.begin(); it != functions_.end();) {
472  if (it->second.getName() == name) {
473  if (it->second.isRuntime()) {
474  LOG(WARNING)
475  << "Overriding existing run-time table function (reset not called?): "
476  << name;
477  it = functions_.erase(it);
478  } else {
479  throw std::runtime_error("Will not override existing load-time table function: " +
480  name);
481  }
482  } else {
483  if (sig == it->second.getSignature(/* include_name */ true,
484  /* include_output */ false) &&
485  ((tf.isCPU() && it->second.isCPU()) || (tf.isGPU() && it->second.isGPU()))) {
486  LOG(WARNING)
487  << "The existing (1) and added (2) table functions have the same signature `"
488  << sig << "`:\n"
489  << " 1: " << it->second.toString() << "\n 2: " << tf.toString() << "\n";
490  }
491  ++it;
492  }
493  }
494 
495  functions_.emplace(name, tf);
497  auto input_args2 = input_args;
498  input_args2.erase(input_args2.begin() + sizer.val - 1);
499 
500  auto sql_args2 = sql_args;
501  auto sql_sizer_pos = tf.getSqlOutputRowSizeParameter();
502  sql_args2.erase(sql_args2.begin() + sql_sizer_pos);
503 
504  auto annotations2 = annotations;
505  annotations2.erase(annotations2.begin() + sql_sizer_pos);
506 
508  sizer,
509  input_args2,
510  output_args,
511  sql_args2,
512  annotations2,
513  is_runtime,
514  uses_manager);
515  auto sig = tf2.getSignature(/* include_name */ true, /* include_output */ false);
516  for (auto it = functions_.begin(); it != functions_.end();) {
517  if (sig == it->second.getSignature(/* include_name */ true,
518  /* include_output */ false) &&
519  ((tf2.isCPU() && it->second.isCPU()) || (tf2.isGPU() && it->second.isGPU()))) {
520  LOG(WARNING)
521  << "The existing (1) and added (2) table functions have the same signature `"
522  << sig << "`:\n"
523  << " 1: " << it->second.toString() << "\n 2: " << tf2.toString() << "\n";
524  }
525  ++it;
526  }
527  functions_.emplace(name + DEFAULT_ROW_MULTIPLIER_SUFFIX, tf2);
528  }
529 }
530 
531 /*
532  The implementation for `void TableFunctionsFactory::init()` is
533  generated by QueryEngine/scripts/generate_TableFunctionsFactory_init.py
534 */
535 
536 // removes existing runtime table functions
539  return;
540  }
541  for (auto it = functions_.begin(); it != functions_.end();) {
542  if (it->second.isRuntime()) {
543  it = functions_.erase(it);
544  } else {
545  ++it;
546  }
547  }
548 }
549 
550 namespace {
551 
552 std::string drop_suffix_impl(const std::string& str) {
553  const auto idx = str.find("__");
554  if (idx == std::string::npos) {
555  return str;
556  }
557  CHECK_GT(idx, std::string::size_type(0));
558  return str.substr(0, idx);
559 }
560 
561 } // namespace
562 
563 std::string TableFunction::getName(const bool drop_suffix, const bool lower) const {
564  std::string result = name_;
565  if (drop_suffix) {
566  result = drop_suffix_impl(result);
567  }
568  if (lower) {
570  }
571  return result;
572 }
573 
574 std::string TableFunction::getSignature(const bool include_name,
575  const bool include_output) const {
576  std::string sig;
577  if (include_name) {
578  sig += getName(/*drop_suffix=*/true, /*lower=*/true);
579  }
580 
581  size_t arg_idx = 0;
582  std::vector<std::string> args;
583  for (size_t sql_idx = 0; sql_idx < sql_args_.size(); sql_idx++) {
584  const std::vector<std::string> cursor_fields = getCursorFields(sql_idx);
585  if (cursor_fields.empty()) {
586  const auto& type = ExtensionFunctionsWhitelist::toString(input_args_[arg_idx++]);
587  const auto& name = getInputAnnotation(sql_idx, "name", "");
588  args.emplace_back(name.empty() ? type : (type + " " + name));
589  } else {
590  std::vector<std::string> vec;
591  for (size_t i = 0; i < cursor_fields.size(); i++) {
592  const auto& type = ExtensionFunctionsWhitelist::toString(input_args_[arg_idx++]);
593  const auto& name = cursor_fields[i];
594  vec.emplace_back((name.empty() ? type : type + " " + name));
595  }
596  args.emplace_back("Cursor<" + boost::algorithm::join(vec, ", ") + ">");
597  }
598  }
599  sig += "(" + boost::algorithm::join(args, ", ") + ")";
600  if (include_output) {
602  }
603  return sig;
604 }
605 
607  // gets the name of the pre flight function associated with this table function
608  return getName(false, true) + PREFLIGHT_SUFFIX;
609 }
610 
611 std::vector<TableFunction> TableFunctionsFactory::get_table_funcs(const std::string& name,
612  const bool is_gpu) {
613  std::vector<TableFunction> table_funcs;
614  for (const auto& tf : get_table_funcs(name)) {
615  if (is_gpu ? tf.isGPU() : tf.isCPU()) {
616  table_funcs.emplace_back(tf);
617  }
618  }
619  return table_funcs;
620 }
621 
622 std::vector<TableFunction> TableFunctionsFactory::get_table_funcs(
623  const std::string& name) {
624  std::vector<TableFunction> table_funcs;
625  auto table_func_name = name;
626  boost::algorithm::to_lower(table_func_name);
627  for (const auto& pair : functions_) {
628  auto fname = drop_suffix_impl(pair.first);
629  if (fname == table_func_name) {
630  table_funcs.push_back(pair.second);
631  }
632  }
633  return table_funcs;
634 }
635 
636 std::vector<TableFunction> TableFunctionsFactory::get_table_funcs(const bool is_runtime) {
637  std::vector<TableFunction> table_funcs;
638  for (const auto& pair : functions_) {
639  if (pair.second.isRuntime() == is_runtime) {
640  table_funcs.push_back(pair.second);
641  }
642  }
643  return table_funcs;
644 }
645 
646 std::vector<TableFunction> TableFunctionsFactory::get_table_funcs() {
647  std::vector<TableFunction> table_funcs;
648  for (const auto& pair : functions_) {
649  table_funcs.push_back(pair.second);
650  }
651  return table_funcs;
652 }
653 
654 std::unordered_map<std::string, TableFunction> TableFunctionsFactory::functions_;
655 
656 } // namespace table_functions
SQLTypeInfo getOutputSQLType(const size_t idx) const
std::string to_lower(const std::string &str)
const std::string getOutputAnnotation(const size_t output_arg_idx, const std::string &key, const std::string &default_) const
static std::vector< TableFunction > get_table_funcs()
bool is_ext_arg_type_scalar(const ExtArgumentType ext_arg_type)
#define PREFIX_LENGTH
static void add(const std::string &name, const TableFunctionOutputRowSizer sizer, const std::vector< ExtArgumentType > &input_args, const std::vector< ExtArgumentType > &output_args, const std::vector< ExtArgumentType > &sql_args, const std::vector< std::map< std::string, std::string >> &annotations, bool is_runtime=false)
#define LOG(tag)
Definition: Logger.h:285
std::string join(T const &container, std::string const &delim)
SQLTypeInfo ext_arg_pointer_type_to_type_info(const ExtArgumentType ext_arg_type)
#define UNREACHABLE()
Definition: Logger.h:338
#define PREFLIGHT_SUFFIX
SQLTypeInfo ext_arg_type_to_type_info_output(const ExtArgumentType ext_arg_type)
const std::map< std::string, std::string > getFunctionAnnotations() const
const std::vector< std::map< std::string, std::string > > annotations_
const std::vector< ExtArgumentType > output_args_
#define DEFAULT_ROW_MULTIPLIER_SUFFIX
std::pair< int32_t, int32_t > getInputID(const size_t idx) const
const std::string getFunctionAnnotation(const std::string &key, const std::string &default_) const
#define CHECK_GT(x, y)
Definition: Logger.h:305
std::vector< std::string > split(std::string_view str, std::string_view delim, std::optional< size_t > maxsplit)
split apart a string into a vector of substrings
bool is_table_function_whitelisted(std::string_view const function_name)
TableFunction
Definition: enums.h:58
std::string getSignature(const bool include_name, const bool include_output) const
bool is_ext_arg_type_nonscalar(const ExtArgumentType ext_arg_type)
const std::vector< ExtArgumentType > sql_args_
SQLTypeInfo getInputSQLType(const size_t idx) const
const std::string getArgNames(const bool use_input_args) const
std::string drop_suffix_impl(const std::string &str)
const std::map< std::string, std::string > getOutputAnnotations(const size_t output_arg_idx) const
const std::string getInputAnnotation(const size_t input_arg_idx, const std::string &key, const std::string &default_) const
bool g_enable_dev_table_functions
Definition: Execute.cpp:124
std::string getName(const bool drop_suffix=false, const bool lower=false) const
#define CHECK_LT(x, y)
Definition: Logger.h:303
const std::string getArgTypes(const bool use_input_args) const
#define CHECK_LE(x, y)
Definition: Logger.h:304
const std::string getInputArgsDefaultValues() const
tuple line
Definition: parse_ast.py:10
constexpr bool string_view_array_sorted_and_distinct(std::string_view const *list, std::index_sequence< I...>)
const std::vector< std::string > getCursorFields(const size_t sql_idx) const
bool g_enable_ml_functions
Definition: Execute.cpp:122
const std::map< std::string, std::string > getInputAnnotations(const size_t input_arg_idx) const
static std::string toString(const std::vector< ExtensionFunction > &ext_funcs, std::string tab="")
#define CHECK(condition)
Definition: Logger.h:291
static std::unordered_map< std::string, TableFunction > functions_
Definition: sqltypes.h:72
const std::vector< ExtArgumentType > input_args_
string name
Definition: setup.in.py:72
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:977
SQLTypeInfo ext_arg_type_to_type_info(const ExtArgumentType ext_arg_type)
bool g_enable_table_functions
Definition: Execute.cpp:121
const std::vector< std::map< std::string, std::string > > & getAnnotations() const