```
SELECT * FROM t0 ASOF LEFT JOIN t1 ON (t1.x = t0.x) AND greater(('\0llall\0ll\0ll\0llall\0llall\0llall\0llall\0llall\0llall\0llall\0llall\0llall\0llall\0ll\0ll\0llall\0llall\0llall', x, x, y), t0.y, t1.y)
```

{
        if (auto * func = ast->as<ASTFunction>())
            visit(*func, ast, data);
    }
    static bool needChildVisit(const ASTPtr & node, const ASTPtr &)
    {
        if (auto * func = node->as<ASTFunction>())
            if (func->name == "equals")
                return false;
        return true;
    }
private:
    static void visit(const ASTFunction & func, const ASTPtr & ast, Data & data);
    static void getIdentifiers(const ASTPtr & ast, std::vector<const ASTIdentifier *> & out);
    static std::pair<size_t, size_t> getTableNumbers(const ASTPtr & expr, const ASTPtr & left_ast, const ASTPtr & right_ast, Data & data);
    static const ASTIdentifier * unrollAliases(const ASTIdentifier * identifier, const Aliases & aliases);
    static size_t getTableForIdentifiers(std::vector<const ASTIdentifier *> & identifiers, const Data & data);
    [[noreturn]] static void throwSyntaxException(const String & msg);
};
using CollectJoinOnKeysVisitor = CollectJoinOnKeysMatcher::Visitor;
}