#pragma once #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; } using PredicateExpressions = std::vector; using ProjectionWithAlias = std::pair; using ProjectionsWithAliases = std::vector; using SubqueriesProjectionColumns = std::map; using IdentifierWithQualifiedName = std::pair; using IdentifiersWithQualifiedNameSet = std::vector; /** This class provides functions for Push-Down predicate expressions * * The Example: * - Query before optimization : * SELECT id_1, name_1 FROM (SELECT id_1, name_1 FROM table_a UNION ALL SELECT id_2, name_2 FROM table_b) * WHERE id_1 = 1 * - Query after optimization : * SELECT id_1, name_1 FROM (SELECT id_1, name_1 FROM table_a WHERE id_1 = 1 UNION ALL SELECT id_2, name_2 FROM table_b WHERE id_2 = 1) * WHERE id_1 = 1 * For more details : https://github.com/yandex/ClickHouse/pull/2015#issuecomment-374283452 */ class PredicateExpressionsOptimizer { /// Extracts settings, mostly to show which are used and which are not. struct ExtractedSettings { const bool enable_optimize_predicate_expression; /// QueryNormalizer settings const UInt64 max_ast_depth; const UInt64 max_expanded_ast_elements; const String count_distinct_implementation; template ExtractedSettings(const T & settings) : enable_optimize_predicate_expression(settings.enable_optimize_predicate_expression), max_ast_depth(settings.max_ast_depth), max_expanded_ast_elements(settings.max_expanded_ast_elements), count_distinct_implementation(settings.count_distinct_implementation) {} }; public: PredicateExpressionsOptimizer(ASTSelectQuery * ast_select_, ExtractedSettings && settings_, const Context & context_); bool optimize(); private: ASTSelectQuery * ast_select; const ExtractedSettings settings; const Context & context; enum OptimizeKind { NONE, PUSH_TO_PREWHERE, PUSH_TO_WHERE, PUSH_TO_HAVING, }; bool isAggregateFunction(ASTPtr & node); bool isArrayJoinFunction(const ASTPtr & node); PredicateExpressions splitConjunctionPredicate(ASTPtr & predicate_expression); void getDependenciesAndQualifiedOfExpression(const ASTPtr & expression, IdentifiersWithQualifiedNameSet & dependencies_and_qualified, std::vector & tables_with_aliases); bool optimizeExpression(const ASTPtr & outer_expression, ASTPtr & subquery_expression, ASTSelectQuery * subquery); bool optimizeImpl(ASTPtr & outer_expression, SubqueriesProjectionColumns & subqueries_projection_columns, bool is_prewhere); bool cannotPushDownOuterPredicate(const ProjectionsWithAliases & subquery_projection_columns, ASTSelectQuery * subquery, IdentifiersWithQualifiedNameSet & outer_predicate_dependencies, bool & is_prewhere, OptimizeKind & optimize_kind); void cloneOuterPredicateForInnerPredicate(const ASTPtr & outer_predicate, const ProjectionsWithAliases & projection_columns, std::vector & tables, ASTPtr & inner_predicate); void getAllSubqueryProjectionColumns(SubqueriesProjectionColumns & all_subquery_projection_columns); void getSubqueryProjectionColumns(SubqueriesProjectionColumns & all_subquery_projection_columns, String & qualified_name_prefix, const ASTPtr & subquery); ASTs getSelectQueryProjectionColumns(ASTPtr & ast); std::vector getSelectTablesExpression(ASTSelectQuery * select_query); ASTs evaluateAsterisk(ASTSelectQuery * select_query, const ASTPtr & asterisk); void cleanExpressionAlias(ASTPtr & expression); }; }