**Use case**

Please look at the next request:
```
SELECT * FROM numbers(1000000) WHERE number % 10000 == 0 and extremely_heavy_udf(number) == 'ok'
```
Now as far as all the functions are "eager" the heavy UDF will drastically reduce performance of the request. 

**Describe the solution you'd like**

As far as I understood after a conversation with @alexey-milovidov you have a "Short Circuit Processing" optimization for simple logical predicates (like conjunctive normal form) doing "lazy calculate" for heavy functions.

So it would be nice to assume all UDF functions as heavy-to-process (which is very close to the truth).

{
    const auto & loader = context->getExternalUserDefinedExecutableFunctionsLoader();
    auto load_result = loader.getLoadResult(function_name);
    if (load_result.object)
    {
        auto executable_function = std::static_pointer_cast<const UserDefinedExecutableFunction>(load_result.object);
        auto function = std::make_shared<UserDefinedFunction>(std::move(executable_function), std::move(context));
        return std::make_unique<FunctionToOverloadResolverAdaptor>(std::move(function));
    }
    return nullptr;
}
bool UserDefinedExecutableFunctionFactory::has(const String & function_name, ContextPtr context)
{
    const auto & loader = context->getExternalUserDefinedExecutableFunctionsLoader();
    auto load_result = loader.getLoadResult(function_name);
    bool result = load_result.object != nullptr;
    return result;
}
std::vector<String> UserDefinedExecutableFunctionFactory::getRegisteredNames(ContextPtr context)
{
    const auto & loader = context->getExternalUserDefinedExecutableFunctionsLoader();
    auto loaded_objects = loader.getLoadedObjects();
    std::vector<std::string> registered_names;
    registered_names.reserve(loaded_objects.size());
    for (auto & loaded_object : loaded_objects)
        registered_names.emplace_back(loaded_object->getLoadableName());
    return registered_names;
}
}