**Describe what's wrong**

UDF functions are global objects. Creating or dropping them requires global level privilege.

- https://clickhouse.com/docs/en/sql-reference/statements/create/function/
- https://github.com/ClickHouse/ClickHouse/blob/14811a357e2136ff2940d791f2dbe59c65e87601/tests/integration/test_access_for_functions/test.py#L22

But "system.privileges" table reports DATABASE level for these privileges.

```
SELECT
    privilege,
    level
FROM system.privileges
WHERE CAST(privilege, 'text') LIKE '%FUNCTION%'

┌─privilege──────────────┬─level────┐
│ CREATE FUNCTION        │ DATABASE │
│ DROP FUNCTION          │ DATABASE │
│ SYSTEM RELOAD FUNCTION │ GLOBAL   │
└────────────────────────┴──────────┘
```

**Does it reproduce on recent release?**

Actual for the latest versions and master. In particular, for 21.12.4.1.

if (flags & precalc.introspection_flags)
            return access_denied("Introspection functions are disabled, because setting 'allow_introspection_functions' is set to 0", ErrorCodes::FUNCTION_NOT_ALLOWED);
    }
    return access_granted();
}
template <bool throw_if_denied, bool grant_option>
bool ContextAccess::checkAccessImpl(const AccessFlags & flags) const
{
    return checkAccessImplHelper<throw_if_denied, grant_option>(flags);
}
template <bool throw_if_denied, bool grant_option, typename... Args>
bool ContextAccess::checkAccessImpl(const AccessFlags & flags, const std::string_view & database, const Args &... args) const
{
    return checkAccessImplHelper<throw_if_denied, grant_option>(flags, database.empty() ? params.current_database : database, args...);
}
template <bool throw_if_denied, bool grant_option>
bool ContextAccess::checkAccessImplHelper(const AccessRightsElement & element) const
{
    assert(!element.grant_option || grant_option);
    if (element.any_database)
        return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags);
    else if (element.any_table)
        return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags, element.database);
    else if (element.any_column)
        return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags, element.database, element.table);
    else
        return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags, element.database, element.table, element.columns);
}
template <bool throw_if_denied, bool grant_option>
bool ContextAccess::checkAccessImpl(const AccessRightsElement & element) const