#pragma once #include #include #include #include #include namespace DB { class ASTIdentifier; class TableJoin; namespace ASOF { enum class Inequality; } enum class JoinIdentifierPos { /// Position can't be established, identifier not resolved Unknown, /// Left side of JOIN Left, /// Right side of JOIN Right, /// Expression not valid, e.g. doesn't contain identifiers NotApplicable, }; using JoinIdentifierPosPair = std::pair; class CollectJoinOnKeysMatcher { public: using Visitor = ConstInDepthNodeVisitor; struct Data { TableJoin & analyzed_join; const TableWithColumnNamesAndTypes & left_table; const TableWithColumnNamesAndTypes & right_table; const Aliases & aliases; const bool is_asof{false}; ASTPtr asof_left_key{}; ASTPtr asof_right_key{}; void addJoinKeys(const ASTPtr & left_ast, const ASTPtr & right_ast, JoinIdentifierPosPair table_pos); void addAsofJoinKeys(const ASTPtr & left_ast, const ASTPtr & right_ast, JoinIdentifierPosPair table_pos, const ASOFJoinInequality & asof_inequality); void asofToJoinKeys(); }; static void visit(const ASTPtr & ast, Data & data) { if (auto * func = ast->as()) { visit(*func, ast, data); } else if (auto * ident = ast->as()) { visit(*ident, ast, data); } else { /// visit children } } static bool needChildVisit(const ASTPtr & node, const ASTPtr &) { if (auto * func = node->as()) return func->name == "and"; return true; } private: static void visit(const ASTFunction & func, const ASTPtr & ast, Data & data); static void visit(const ASTIdentifier & ident, const ASTPtr & ast, Data & data); static void getIdentifiers(const ASTPtr & ast, std::vector & out); static JoinIdentifierPosPair getTableNumbers(const ASTPtr & left_ast, const ASTPtr & right_ast, Data & data); static const ASTIdentifier * unrollAliases(const ASTIdentifier * identifier, const Aliases & aliases); static JoinIdentifierPos getTableForIdentifiers(const ASTPtr & ast, bool throw_on_table_mix, const Data & data); }; /// Parse JOIN ON expression and collect ASTs for joined columns. using CollectJoinOnKeysVisitor = CollectJoinOnKeysMatcher::Visitor; }