#pragma once #include #include #include #include #include namespace DB::Analyzer { class CNF { public: struct AtomicFormula { bool negative = false; QueryTreeNodePtrWithHash node_with_hash; bool operator==(const AtomicFormula & rhs) const; bool operator<(const AtomicFormula & rhs) const; }; // Different hash is generated for different order, so we use std::set using OrGroup = std::set; using AndGroup = std::set; std::string dump() const; static constexpr size_t DEFAULT_MAX_GROWTH_MULTIPLIER = 20; static constexpr size_t MAX_ATOMS_WITHOUT_CHECK = 200; CNF & transformAtoms(std::function fn); CNF & transformGroups(std::function fn); CNF & filterAlwaysTrueGroups(std::function predicate); CNF & filterAlwaysFalseAtoms(std::function predicate); CNF & reduce(); void appendGroup(const AndGroup & and_group); /// Convert "NOT fn" to a single node representing inverse of "fn" CNF & pushNotIntoFunctions(const ContextPtr & context); CNF & pullNotOutFunctions(const ContextPtr & context); static AtomicFormula pushNotIntoFunction(const AtomicFormula & atom, const ContextPtr & context); explicit CNF(AndGroup statements_); static std::optional tryBuildCNF(const QueryTreeNodePtr & node, ContextPtr context, size_t max_growth_multiplier = DEFAULT_MAX_GROWTH_MULTIPLIER); static CNF toCNF(const QueryTreeNodePtr & node, ContextPtr context, size_t max_growth_multiplier = DEFAULT_MAX_GROWTH_MULTIPLIER); QueryTreeNodePtr toQueryTree() const; const auto & getStatements() const { return statements; } private: AndGroup statements; }; }