| 14 | namespace binder { |
| 15 | |
| 16 | BoundTableScanInfo Binder::bindTableFunc(const std::string& tableFuncName, |
| 17 | const parser::ParsedExpression& expr, std::vector<parser::YieldVariable> yieldVariables) { |
| 18 | auto catalog = catalog::Catalog::Get(*clientContext); |
| 19 | auto transaction = transaction::Transaction::Get(*clientContext); |
| 20 | auto entry = catalog->getFunctionEntry(transaction, tableFuncName, |
| 21 | clientContext->useInternalCatalogEntry()); |
| 22 | expression_vector positionalParams; |
| 23 | std::vector<LogicalType> positionalParamTypes; |
| 24 | optional_params_t optionalParams; |
| 25 | expression_vector optionalParamsLegacy; |
| 26 | for (auto i = 0u; i < expr.getNumChildren(); i++) { |
| 27 | auto& childExpr = *expr.getChild(i); |
| 28 | auto param = expressionBinder.bindExpression(childExpr); |
| 29 | ExpressionUtil::validateExpressionType(*param, |
| 30 | {ExpressionType::LITERAL, ExpressionType::PARAMETER, ExpressionType::PATTERN}); |
| 31 | if (!childExpr.hasAlias()) { |
| 32 | positionalParams.push_back(param); |
| 33 | positionalParamTypes.push_back(param->getDataType().copy()); |
| 34 | } else { |
| 35 | if (param->expressionType == ExpressionType::LITERAL) { |
| 36 | auto literalExpr = param->constPtrCast<LiteralExpression>(); |
| 37 | optionalParams.emplace(childExpr.getAlias(), literalExpr->getValue()); |
| 38 | } |
| 39 | param->setAlias(expr.getChild(i)->getAlias()); |
| 40 | optionalParamsLegacy.push_back(param); |
| 41 | } |
| 42 | } |
| 43 | auto func = BuiltInFunctionsUtils::matchFunction(tableFuncName, positionalParamTypes, |
| 44 | entry->ptrCast<catalog::FunctionCatalogEntry>()); |
| 45 | auto tableFunc = func->constPtrCast<TableFunction>(); |
| 46 | std::vector<LogicalType> inputTypes; |
| 47 | if (tableFunc->inferInputTypes) { |
| 48 | // For functions which take in nested data types, we have to use the input parameters to |
| 49 | // detect the input types. (E.g. query_hnsw_index takes in an ARRAY which needs the user |
| 50 | // input parameters to decide the array dimension). |
| 51 | inputTypes = tableFunc->inferInputTypes(positionalParams); |
| 52 | } else { |
| 53 | // For functions which don't have nested type parameters, we can simply use the types |
| 54 | // declared in the function signature. |
| 55 | for (auto i = 0u; i < tableFunc->parameterTypeIDs.size(); i++) { |
| 56 | inputTypes.push_back(LogicalType(tableFunc->parameterTypeIDs[i])); |
| 57 | } |
| 58 | } |
| 59 | for (auto i = 0u; i < positionalParams.size(); ++i) { |
| 60 | auto parameterTypeID = tableFunc->parameterTypeIDs[i]; |
| 61 | if (positionalParams[i]->expressionType == ExpressionType::LITERAL && |
| 62 | parameterTypeID != LogicalTypeID::ANY) { |
| 63 | positionalParams[i] = expressionBinder.foldExpression( |
| 64 | expressionBinder.implicitCastIfNecessary(positionalParams[i], inputTypes[i])); |
| 65 | } |
| 66 | } |
| 67 | auto bindInput = TableFuncBindInput(); |
| 68 | bindInput.params = std::move(positionalParams); |
| 69 | bindInput.optionalParams = std::move(optionalParams); |
| 70 | bindInput.optionalParamsLegacy = std::move(optionalParamsLegacy); |
| 71 | bindInput.binder = this; |
| 72 | bindInput.yieldVariables = std::move(yieldVariables); |
| 73 | return BoundTableScanInfo{*tableFunc, tableFunc->bindFunc(clientContext, &bindInput)}; |
nothing calls this directly
no test coverage detected