| 24 | }; |
| 25 | |
| 26 | static std::unique_ptr<FunctionBindData> bindFunc(const ScalarBindFuncInput& input) { |
| 27 | auto scalarFunction = input.definition->ptrCast<ScalarFunction>(); |
| 28 | // for list_contains(list, input), we expect input and list child have the same type, if list |
| 29 | // is empty, we use in the input type. Otherwise, we use list child type because casting list |
| 30 | // is more expensive. |
| 31 | std::vector<LogicalType> paramTypes; |
| 32 | LogicalType childType; |
| 33 | auto listExpr = input.arguments[0]; |
| 34 | auto elementExpr = input.arguments[1]; |
| 35 | if (ExpressionUtil::isEmptyList(*listExpr)) { |
| 36 | childType = elementExpr->getDataType().copy(); |
| 37 | } else { |
| 38 | auto& listChildType = ListType::getChildType(listExpr->getDataType()); |
| 39 | auto& elementType = elementExpr->getDataType(); |
| 40 | if (!LogicalTypeUtils::tryGetMaxLogicalType(listChildType, elementType, childType)) { |
| 41 | throw BinderException(std::format("Cannot compare {} and {} in list_contains function.", |
| 42 | listChildType.toString(), elementType.toString())); |
| 43 | } |
| 44 | } |
| 45 | if (childType.getLogicalTypeID() == LogicalTypeID::ANY) { |
| 46 | childType = LogicalType::STRING(); |
| 47 | } |
| 48 | auto listType = LogicalType::LIST(childType.copy()); |
| 49 | paramTypes.push_back(listType.copy()); |
| 50 | paramTypes.push_back(childType.copy()); |
| 51 | TypeUtils::visit(childType.getPhysicalType(), [&scalarFunction]<typename T>(T) { |
| 52 | scalarFunction->execFunc = |
| 53 | ScalarFunction::BinaryExecListStructFunction<list_entry_t, T, uint8_t, ListContains>; |
| 54 | }); |
| 55 | return std::make_unique<FunctionBindData>(std::move(paramTypes), LogicalType::BOOL()); |
| 56 | } |
| 57 | |
| 58 | function_set ListContainsFunction::getFunctionSet() { |
| 59 | function_set result; |
nothing calls this directly
no test coverage detected