MCPcopy Create free account
hub / github.com/duckdb/duckdb / InferTemplateType

Function InferTemplateType

src/function/function_binder.cpp:437–563  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

435}
436
437static void InferTemplateType(ClientContext &context, const LogicalType &source, const LogicalType &target,
438 case_insensitive_map_t<vector<LogicalType>> &bindings, const Expression &current_expr,
439 const BaseScalarFunction &function) {
440 if (target.id() == LogicalTypeId::UNKNOWN || target.id() == LogicalTypeId::SQLNULL) {
441 // If the actual type is unknown, we cannot infer anything more.
442 // Therefore, we map all remaining templates in the source to UNKNOWN or SQLNULL, if not already inferred to
443 // something else
444
445 // This might seem a bit strange, why not just not set the binding and error out later when we try to substitute
446 // all templates? Well, this is how bindings for most nested functions already work, they simply propagate the
447 // UNKNOWN/SQLNULL. The binder will later check for UNKNOWN/SQLNULL in return types and if it finds one, insert
448 // a dummy cast to INT32 so that the function can be executed without errors (and just return NULLs).
449
450 TypeVisitor::Contains(source, [&](const LogicalType &child) {
451 if (child.id() == LogicalTypeId::TEMPLATE) {
452 const auto index = TemplateType::GetName(child);
453 if (bindings.find(index) == bindings.end()) {
454 // not found, add the binding
455 bindings[index] = {target.id()};
456 }
457 }
458 return false; // continue visiting
459 });
460 return;
461 }
462
463 // If the source is a template type, we bind it, or try to unify its existing binding with the target type.
464 if (source.id() == LogicalTypeId::TEMPLATE) {
465 const auto &index = TemplateType::GetName(source);
466 auto it = bindings.find(index);
467 if (it == bindings.end()) {
468 // not found, add the binding
469 bindings[index] = {target};
470 return;
471 }
472 if (it->second.back() == target) {
473 // already bound to the same type
474 return;
475 }
476
477 // Try to unify (promote) the type candidates
478 LogicalType result;
479 if (LogicalType::TryGetMaxLogicalType(context, it->second.back(), target, result)) {
480 // Type unification was successful
481 if (it->second.back() != result) {
482 // update the binding
483 it->second.push_back(target);
484 it->second.push_back(std::move(result)); // Push the new promoted type
485 }
486 return;
487 }
488
489 // If we reach here, it means the types are incompatible
490 string msg =
491 StringUtil::Format("Cannot deduce template type '%s' in function: '%s'\nType '%s' was inferred to be:\n",
492 TemplateType::GetName(source), function.ToString(), TemplateType::GetName(source));
493 const auto &steps = it->second;
494

Callers 1

ResolveTemplateTypesMethod · 0.85

Calls 15

ContainsFunction · 0.85
GetNameFunction · 0.85
BinderExceptionClass · 0.85
MinValueFunction · 0.85
idMethod · 0.80
GetQueryLocationMethod · 0.80
IsNestedMethod · 0.80
AuxInfoMethod · 0.80
findMethod · 0.45
endMethod · 0.45
backMethod · 0.45

Tested by

no test coverage detected