| 563 | } |
| 564 | |
| 565 | static void SubstituteTemplateType(LogicalType &type, case_insensitive_map_t<vector<LogicalType>> &bindings, |
| 566 | const string &function_name) { |
| 567 | // Replace all template types in with their bound concrete types. |
| 568 | type = TypeVisitor::VisitReplace(type, [&](const LogicalType &t) -> LogicalType { |
| 569 | if (t.id() == LogicalTypeId::TEMPLATE) { |
| 570 | const auto index = TemplateType::GetName(t); |
| 571 | auto it = bindings.find(index); |
| 572 | if (it != bindings.end()) { |
| 573 | // found a binding, return the concrete type |
| 574 | return LogicalType::NormalizeType(it->second.back()); |
| 575 | } |
| 576 | |
| 577 | // If we reach here, the template type was not bound to any concrete type. |
| 578 | // We dont throw an error here, but give users a chance to handle unresolved template type later in the |
| 579 | // "bind_scalar_function_t" callback. We then throw an error if the template type is still not bound |
| 580 | // in the "CheckTemplateTypesResolved" method afterwards. |
| 581 | } |
| 582 | return t; |
| 583 | }); |
| 584 | } |
| 585 | |
| 586 | void FunctionBinder::ResolveTemplateTypes(BaseScalarFunction &bound_function, |
| 587 | const vector<unique_ptr<Expression>> &children) { |