From 0fb9f9ffe6018558cbbc26818b272dc191901d00 Mon Sep 17 00:00:00 2001 From: Antonio Andelic Date: Fri, 17 Mar 2023 13:38:01 +0000 Subject: [PATCH] Add support for substitute column --- src/Analyzer/Passes/ConvertQueryToCNFPass.cpp | 307 +++++++++++++++++- .../AddIndexConstraintsOptimizer.cpp | 2 +- src/Interpreters/ComparisonGraph.h | 2 +- .../SubstituteColumnOptimizer.cpp | 6 +- .../WhereConstraintsOptimizer.cpp | 12 +- .../tests/gtest_comparison_graph.cpp | 4 +- src/Storages/ConstraintsDescription.cpp | 8 +- src/Storages/ConstraintsDescription.h | 6 +- ...ergeTreeIndexHypothesisMergedCondition.cpp | 12 +- .../MergeTreeIndexHypothesisMergedCondition.h | 6 +- .../01623_constraints_column_swap.reference | 236 ++++++++++++++ .../01623_constraints_column_swap.sql | 16 +- 12 files changed, 580 insertions(+), 37 deletions(-) diff --git a/src/Analyzer/Passes/ConvertQueryToCNFPass.cpp b/src/Analyzer/Passes/ConvertQueryToCNFPass.cpp index f807b096a78..591f2a1557c 100644 --- a/src/Analyzer/Passes/ConvertQueryToCNFPass.cpp +++ b/src/Analyzer/Passes/ConvertQueryToCNFPass.cpp @@ -9,7 +9,13 @@ #include #include +#include + #include +#include "Analyzer/HashUtils.h" +#include "Analyzer/IQueryTreeNode.h" +#include "Interpreters/ComparisonGraph.h" +#include "base/types.h" namespace DB { @@ -344,6 +350,286 @@ void addIndexConstraint(Analyzer::CNF & cnf, const QueryTreeNodes & table_expres } } +struct ColumnPrice +{ + Int64 compressed_size{0}; + Int64 uncompressed_size{0}; + + ColumnPrice(const Int64 compressed_size_, const Int64 uncompressed_size_) + : compressed_size(compressed_size_) + , uncompressed_size(uncompressed_size_) + { + } + + bool operator<(const ColumnPrice & that) const + { + return std::tie(compressed_size, uncompressed_size) < std::tie(that.compressed_size, that.uncompressed_size); + } + + ColumnPrice & operator+=(const ColumnPrice & that) + { + compressed_size += that.compressed_size; + uncompressed_size += that.uncompressed_size; + return *this; + } + + ColumnPrice & operator-=(const ColumnPrice & that) + { + compressed_size -= that.compressed_size; + uncompressed_size -= that.uncompressed_size; + return *this; + } +}; + +using ColumnPriceByName = std::unordered_map; +using ColumnPriceByQueryNode = QueryTreeNodePtrWithHashMap; + +class ComponentCollectorVisitor : public ConstInDepthQueryTreeVisitor +{ +public: + ComponentCollectorVisitor( + std::set & components_, + QueryTreeNodePtrWithHashMap & query_node_to_component_, + const ComparisonGraph & graph_) + : components(components_), query_node_to_component(query_node_to_component_), graph(graph_) + {} + + void visitImpl(const QueryTreeNodePtr & node) + { + if (auto id = graph.getComponentId(node)) + { + query_node_to_component.emplace(node, *id); + components.insert(*id); + } + } + +private: + std::set & components; + QueryTreeNodePtrWithHashMap & query_node_to_component; + + const ComparisonGraph & graph; +}; + +class ColumnNameCollectorVisitor : public ConstInDepthQueryTreeVisitor +{ +public: + ColumnNameCollectorVisitor( + std::unordered_set & column_names_, + const QueryTreeNodePtrWithHashMap & query_node_to_component_) + : column_names(column_names_), query_node_to_component(query_node_to_component_) + {} + + bool needChildVisit(const VisitQueryTreeNodeType & parent, const VisitQueryTreeNodeType &) + { + return !query_node_to_component.contains(parent); + } + + void visitImpl(const QueryTreeNodePtr & node) + { + if (query_node_to_component.contains(node)) + return; + + if (const auto * column_node = node->as()) + column_names.insert(column_node->getColumnName()); + } + +private: + std::unordered_set & column_names; + const QueryTreeNodePtrWithHashMap & query_node_to_component; +}; + +class SubstituteColumnVisitor : public InDepthQueryTreeVisitor +{ +public: + SubstituteColumnVisitor( + const QueryTreeNodePtrWithHashMap & query_node_to_component_, + const std::unordered_map & id_to_query_node_map_, + ContextPtr context_) + : query_node_to_component(query_node_to_component_), id_to_query_node_map(id_to_query_node_map_), context(std::move(context_)) + {} + + void visitImpl(QueryTreeNodePtr & node) + { + auto component_id_it = query_node_to_component.find(node); + if (component_id_it == query_node_to_component.end()) + return; + + const auto component_id = component_id_it->second; + auto new_node = id_to_query_node_map.at(component_id)->clone(); + + if (!node->getResultType()->equals(*new_node->getResultType())) + { + node = buildCastFunction(new_node, node->getResultType(), context); + return; + } + + node = std::move(new_node); + } + +private: + const QueryTreeNodePtrWithHashMap & query_node_to_component; + const std::unordered_map & id_to_query_node_map; + ContextPtr context; +}; + +ColumnPrice calculatePrice( + const ColumnPriceByName & column_prices, + const std::unordered_set & column_names) +{ + ColumnPrice result(0, 0); + + for (const auto & column : column_names) + { + if (auto it = column_prices.find(column); it != column_prices.end()) + result += it->second; + } + + return result; +} + + +void bruteForce( + const ComparisonGraph & graph, + const std::vector & components, + size_t current_component, + const ColumnPriceByName & column_prices, + ColumnPrice current_price, + std::vector & expressions_stack, + ColumnPrice & min_price, + std::vector & min_expressions) +{ + if (current_component == components.size()) + { + if (current_price < min_price) + { + min_price = current_price; + min_expressions = expressions_stack; + } + return; + } + + for (const auto & node : graph.getComponent(components[current_component])) + { + std::unordered_set column_names; + ColumnNameCollectorVisitor column_name_collector{column_names, {}}; + column_name_collector.visit(node); + + ColumnPrice expression_price = calculatePrice(column_prices, column_names); + + expressions_stack.push_back(node); + current_price += expression_price; + + ColumnPriceByName new_prices(column_prices); + for (const auto & column : column_names) + new_prices.insert_or_assign(column, ColumnPrice(0, 0)); + + bruteForce(graph, + components, + current_component + 1, + new_prices, + current_price, + expressions_stack, + min_price, + min_expressions); + + current_price -= expression_price; + expressions_stack.pop_back(); + } +} + +void substituteColumns(QueryNode & query_node, const QueryTreeNodes & table_expressions, const ContextPtr & context) +{ + static constexpr UInt64 COLUMN_PENALTY = 10 * 1024 * 1024; + static constexpr Int64 INDEX_PRICE = -1'000'000'000'000'000'000; + + for (const auto & table_expression : table_expressions) + { + auto snapshot = getStorageSnapshot(table_expression); + if (!snapshot || !snapshot->metadata) + continue; + + const auto column_sizes = snapshot->storage.getColumnSizes(); + if (column_sizes.empty()) + return; + + auto query_tree_constraint = snapshot->metadata->getConstraints().getQueryTreeData(context, table_expression); + const auto & graph = query_tree_constraint.getGraph(); + + auto run_for_all = [&](const auto function) + { + function(query_node.getProjectionNode()); + + if (query_node.hasWhere()) + function(query_node.getWhere()); + + if (query_node.hasPrewhere()) + function(query_node.getPrewhere()); + + if (query_node.hasHaving()) + function(query_node.getHaving()); + }; + + std::set components; + QueryTreeNodePtrWithHashMap query_node_to_component; + std::unordered_set column_names; + + run_for_all([&](QueryTreeNodePtr & node) + { + ComponentCollectorVisitor component_collector{components, query_node_to_component, graph}; + component_collector.visit(node); + ColumnNameCollectorVisitor column_name_collector{column_names, query_node_to_component}; + column_name_collector.visit(node); + }); + + ColumnPriceByName column_prices; + const auto primary_key = snapshot->metadata->getColumnsRequiredForPrimaryKey(); + + for (const auto & [column_name, column_size] : column_sizes) + column_prices.insert_or_assign(column_name, ColumnPrice(column_size.data_compressed + COLUMN_PENALTY, column_size.data_uncompressed)); + + for (const auto & column_name : primary_key) + column_prices.insert_or_assign(column_name, ColumnPrice(INDEX_PRICE, INDEX_PRICE)); + + for (const auto & column_name : column_names) + column_prices.insert_or_assign(column_name, ColumnPrice(0, 0)); + + std::unordered_map id_to_query_node_map; + std::vector components_list; + + for (const auto component_id : components) + { + auto component = graph.getComponent(component_id); + if (component.size() == 1) + id_to_query_node_map[component_id] = component.front(); + else + components_list.push_back(component_id); + } + + std::vector expressions_stack; + ColumnPrice min_price(std::numeric_limits::max(), std::numeric_limits::max()); + std::vector min_expressions; + + bruteForce(graph, + components_list, + 0, + column_prices, + ColumnPrice(0, 0), + expressions_stack, + min_price, + min_expressions); + + for (size_t i = 0; i < components_list.size(); ++i) + id_to_query_node_map[components_list[i]] = min_expressions[i]; + + SubstituteColumnVisitor substitute_column{query_node_to_component, id_to_query_node_map, context}; + + run_for_all([&](QueryTreeNodePtr & node) + { + substitute_column.visit(node); + }); + } +} + void optimizeWithConstraints(Analyzer::CNF & cnf, const QueryTreeNodes & table_expressions, const ContextPtr & context) { cnf.pullNotOutFunctions(context); @@ -410,11 +696,24 @@ public: auto table_expressions = extractTableExpressions(query_node->getJoinTree()); - if (query_node->hasWhere()) - optimizeNode(query_node->getWhere(), table_expressions, getContext()); + const auto & context = getContext(); + const auto & settings = context->getSettingsRef(); - if (query_node->hasPrewhere()) - optimizeNode(query_node->getPrewhere(), table_expressions, getContext()); + bool has_filter = false; + const auto optimize_filter = [&](QueryTreeNodePtr & filter_node) + { + if (filter_node == nullptr) + return; + + optimizeNode(query_node->getWhere(), table_expressions, context); + has_filter = true; + }; + + optimize_filter(query_node->getWhere()); + optimize_filter(query_node->getPrewhere()); + + if (has_filter && settings.optimize_substitute_columns) + substituteColumns(*query_node, table_expressions, context); } }; diff --git a/src/Interpreters/AddIndexConstraintsOptimizer.cpp b/src/Interpreters/AddIndexConstraintsOptimizer.cpp index 15adc737f6f..b9d56ec2ff8 100644 --- a/src/Interpreters/AddIndexConstraintsOptimizer.cpp +++ b/src/Interpreters/AddIndexConstraintsOptimizer.cpp @@ -104,7 +104,7 @@ namespace /// we can add to expression 'indexHint(I < A)' condition. CNFQuery::OrGroup createIndexHintGroup( const CNFQuery::OrGroup & group, - const ComparisonGraph<> & graph, + const ComparisonGraph & graph, const ASTs & primary_key_only_asts) { CNFQuery::OrGroup result; diff --git a/src/Interpreters/ComparisonGraph.h b/src/Interpreters/ComparisonGraph.h index 19b23917917..ecfc617ac8a 100644 --- a/src/Interpreters/ComparisonGraph.h +++ b/src/Interpreters/ComparisonGraph.h @@ -33,7 +33,7 @@ concept ComparisonGraphNodeType = std::same_as || std::same_as +template class ComparisonGraph { public: diff --git a/src/Interpreters/SubstituteColumnOptimizer.cpp b/src/Interpreters/SubstituteColumnOptimizer.cpp index 4cc9572749f..c4aef89fed2 100644 --- a/src/Interpreters/SubstituteColumnOptimizer.cpp +++ b/src/Interpreters/SubstituteColumnOptimizer.cpp @@ -32,13 +32,13 @@ public: struct Data { - const ComparisonGraph<> & graph; + const ComparisonGraph & graph; std::set & components; std::unordered_map & old_name; std::unordered_map & component; UInt64 & current_id; - Data(const ComparisonGraph<> & graph_, + Data(const ComparisonGraph & graph_, std::set & components_, std::unordered_map & old_name_, std::unordered_map & component_, @@ -165,7 +165,7 @@ ColumnPrice calculatePrice( /// price of all columns on which ast depends. /// TODO: branch-and-bound void bruteforce( - const ComparisonGraph<> & graph, + const ComparisonGraph & graph, const std::vector & components, size_t current_component, const ColumnPriceByName & column_prices, diff --git a/src/Interpreters/WhereConstraintsOptimizer.cpp b/src/Interpreters/WhereConstraintsOptimizer.cpp index e3934e8ea7f..91c19fa264e 100644 --- a/src/Interpreters/WhereConstraintsOptimizer.cpp +++ b/src/Interpreters/WhereConstraintsOptimizer.cpp @@ -74,7 +74,7 @@ bool checkIfGroupAlwaysTrueFullMatch(const CNFQuery::OrGroup & group, const Cons return false; } -bool checkIfGroupAlwaysTrueGraph(const CNFQuery::OrGroup & group, const ComparisonGraph<> & graph) +bool checkIfGroupAlwaysTrueGraph(const CNFQuery::OrGroup & group, const ComparisonGraph & graph) { /// We try to find at least one atom that is always true by using comparison graph. for (const auto & atom : group) @@ -82,7 +82,7 @@ bool checkIfGroupAlwaysTrueGraph(const CNFQuery::OrGroup & group, const Comparis const auto * func = atom.ast->as(); if (func && func->arguments->children.size() == 2) { - const auto expected = ComparisonGraph<>::atomToCompareResult(atom); + const auto expected = ComparisonGraph::atomToCompareResult(atom); if (graph.isAlwaysCompare(expected, func->arguments->children[0], func->arguments->children[1])) return true; } @@ -108,20 +108,20 @@ bool checkIfAtomAlwaysFalseFullMatch(const CNFQuery::AtomicFormula & atom, const return false; } -bool checkIfAtomAlwaysFalseGraph(const CNFQuery::AtomicFormula & atom, const ComparisonGraph<> & graph) +bool checkIfAtomAlwaysFalseGraph(const CNFQuery::AtomicFormula & atom, const ComparisonGraph & graph) { const auto * func = atom.ast->as(); if (func && func->arguments->children.size() == 2) { /// TODO: special support for != - const auto expected = ComparisonGraph<>::atomToCompareResult(atom); + const auto expected = ComparisonGraph::atomToCompareResult(atom); return !graph.isPossibleCompare(expected, func->arguments->children[0], func->arguments->children[1]); } return false; } -void replaceToConstants(ASTPtr & term, const ComparisonGraph<> & graph) +void replaceToConstants(ASTPtr & term, const ComparisonGraph & graph) { const auto equal_constant = graph.getEqualConst(term); if (equal_constant) @@ -135,7 +135,7 @@ void replaceToConstants(ASTPtr & term, const ComparisonGraph<> & graph) } } -CNFQuery::AtomicFormula replaceTermsToConstants(const CNFQuery::AtomicFormula & atom, const ComparisonGraph<> & graph) +CNFQuery::AtomicFormula replaceTermsToConstants(const CNFQuery::AtomicFormula & atom, const ComparisonGraph & graph) { CNFQuery::AtomicFormula result; result.negative = atom.negative; diff --git a/src/Interpreters/tests/gtest_comparison_graph.cpp b/src/Interpreters/tests/gtest_comparison_graph.cpp index 32dcb3de6b3..96a78241c8e 100644 --- a/src/Interpreters/tests/gtest_comparison_graph.cpp +++ b/src/Interpreters/tests/gtest_comparison_graph.cpp @@ -9,11 +9,11 @@ using namespace DB; -static ComparisonGraph<> getGraph(const String & query) +static ComparisonGraph getGraph(const String & query) { ParserExpressionList parser(false); ASTPtr ast = parseQuery(parser, query, 0, 0); - return ComparisonGraph<>(ast->children); + return ComparisonGraph(ast->children); } TEST(ComparisonGraph, Bounds) diff --git a/src/Storages/ConstraintsDescription.cpp b/src/Storages/ConstraintsDescription.cpp index 3f4d264b4a1..db37ac7c4c3 100644 --- a/src/Storages/ConstraintsDescription.cpp +++ b/src/Storages/ConstraintsDescription.cpp @@ -110,7 +110,7 @@ std::vector ConstraintsDescription::getAtomicConstraint return constraint_data; } -std::unique_ptr> ConstraintsDescription::buildGraph() const +std::unique_ptr> ConstraintsDescription::buildGraph() const { static const NameSet relations = { "equals", "less", "lessOrEquals", "greaterOrEquals", "greater" }; @@ -128,7 +128,7 @@ std::unique_ptr> ConstraintsDescription::buildGraph() const } } - return std::make_unique>(constraints_for_graph); + return std::make_unique>(constraints_for_graph); } ConstraintsExpressions ConstraintsDescription::getExpressions(const DB::ContextPtr context, @@ -150,7 +150,7 @@ ConstraintsExpressions ConstraintsDescription::getExpressions(const DB::ContextP return res; } -const ComparisonGraph<> & ConstraintsDescription::getGraph() const +const ComparisonGraph & ConstraintsDescription::getGraph() const { return *graph; } @@ -313,7 +313,7 @@ void ConstraintsDescription::update() { cnf_constraints.clear(); ast_to_atom_ids.clear(); - graph = std::make_unique>(ASTs()); + graph = std::make_unique>(ASTs()); return; } diff --git a/src/Storages/ConstraintsDescription.h b/src/Storages/ConstraintsDescription.h index 2c34ef1ef37..33bd8e1abf9 100644 --- a/src/Storages/ConstraintsDescription.h +++ b/src/Storages/ConstraintsDescription.h @@ -43,7 +43,7 @@ public: const std::vector> & getConstraintData() const; std::vector getAtomicConstraintData() const; - const ComparisonGraph<> & getGraph() const; + const ComparisonGraph & getGraph() const; ConstraintsExpressions getExpressions(ContextPtr context, const NamesAndTypesList & source_columns_) const; @@ -79,7 +79,7 @@ public: private: std::vector> buildConstraintData() const; - std::unique_ptr> buildGraph() const; + std::unique_ptr> buildGraph() const; void update(); ASTs constraints; @@ -87,7 +87,7 @@ private: std::vector> cnf_constraints; std::map ast_to_atom_ids; - std::unique_ptr> graph; + std::unique_ptr> graph; }; } diff --git a/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.cpp b/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.cpp index 2bb6857a855..4227ffc6873 100644 --- a/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.cpp +++ b/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.cpp @@ -108,7 +108,7 @@ bool MergeTreeIndexhypothesisMergedCondition::alwaysUnknownOrTrue() const func->name = "greaterOrEquals"; } - const auto weak_graph = std::make_unique>(active_atomic_formulas); + const auto weak_graph = std::make_unique>(active_atomic_formulas); bool useless = true; expression_cnf->iterateGroups( @@ -146,7 +146,7 @@ bool MergeTreeIndexhypothesisMergedCondition::mayBeTrueOnGranule(const MergeTree values.push_back(granule->met); } - const ComparisonGraph<> * graph = nullptr; + const ComparisonGraph * graph = nullptr; { std::lock_guard lock(cache_mutex); @@ -170,7 +170,7 @@ bool MergeTreeIndexhypothesisMergedCondition::mayBeTrueOnGranule(const MergeTree const auto * func = atom.ast->as(); if (func && func->arguments->children.size() == 2) { - const auto expected = ComparisonGraph<>::atomToCompareResult(atom); + const auto expected = ComparisonGraph::atomToCompareResult(atom); if (graph->isPossibleCompare(expected, func->arguments->children[0], func->arguments->children[1])) { /// If graph failed use matching. @@ -188,7 +188,7 @@ bool MergeTreeIndexhypothesisMergedCondition::mayBeTrueOnGranule(const MergeTree return !always_false; } -std::unique_ptr> MergeTreeIndexhypothesisMergedCondition::buildGraph(const std::vector & values) const +std::unique_ptr> MergeTreeIndexhypothesisMergedCondition::buildGraph(const std::vector & values) const { ASTs active_atomic_formulas(atomic_constraints); for (size_t i = 0; i < values.size(); ++i) @@ -199,10 +199,10 @@ std::unique_ptr> MergeTreeIndexhypothesisMergedCondition::buil std::begin(index_to_compare_atomic_hypotheses[i]), std::end(index_to_compare_atomic_hypotheses[i])); } - return std::make_unique>(active_atomic_formulas); + return std::make_unique>(active_atomic_formulas); } -const ComparisonGraph<> * MergeTreeIndexhypothesisMergedCondition::getGraph(const std::vector & values) const +const ComparisonGraph * MergeTreeIndexhypothesisMergedCondition::getGraph(const std::vector & values) const { auto [it, inserted] = graph_cache.try_emplace(values); if (inserted) diff --git a/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.h b/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.h index f08cfba6ca0..3ab82f4d3ee 100644 --- a/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.h +++ b/src/Storages/MergeTree/MergeTreeIndexHypothesisMergedCondition.h @@ -20,8 +20,8 @@ public: private: void addConstraints(const ConstraintsDescription & constraints_description); - std::unique_ptr> buildGraph(const std::vector & values) const; - const ComparisonGraph<> * getGraph(const std::vector & values) const; + std::unique_ptr> buildGraph(const std::vector & values) const; + const ComparisonGraph * getGraph(const std::vector & values) const; ASTPtr expression_ast; std::unique_ptr expression_cnf; @@ -29,7 +29,7 @@ private: /// Part analysis can be done in parallel. /// So, we have shared answer and graph cache. mutable std::mutex cache_mutex; - mutable std::unordered_map, std::unique_ptr>> graph_cache; + mutable std::unordered_map, std::unique_ptr>> graph_cache; mutable std::unordered_map, bool> answer_cache; std::vector> index_to_compare_atomic_hypotheses; diff --git a/tests/queries/0_stateless/01623_constraints_column_swap.reference b/tests/queries/0_stateless/01623_constraints_column_swap.reference index 7ae4516fe9e..520bd16ae25 100644 --- a/tests/queries/0_stateless/01623_constraints_column_swap.reference +++ b/tests/queries/0_stateless/01623_constraints_column_swap.reference @@ -3,51 +3,287 @@ SELECT (b AS b) + 3 AS `plus(b, 3)` FROM column_swap_test_test WHERE b = 1 +QUERY id: 0 + PROJECTION COLUMNS + plus(cityHash64(a), 10) UInt64 + plus(b, 3) UInt64 + PROJECTION + LIST id: 1, nodes: 2 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + COLUMN id: 4, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 6, constant_value: UInt64_10, constant_value_type: UInt8 + FUNCTION id: 7, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 8, nodes: 2 + COLUMN id: 9, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 10, constant_value: UInt64_3, constant_value_type: UInt8 + JOIN TREE + TABLE id: 5, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 11, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 12, nodes: 2 + COLUMN id: 13, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 14, constant_value: UInt64_1, constant_value_type: UInt8 SELECT (b AS `cityHash64(a)`) + 10 AS `plus(cityHash64(a), 10)`, (b AS b) + 3 AS `plus(b, 3)` FROM column_swap_test_test WHERE b = 0 +QUERY id: 0 + PROJECTION COLUMNS + plus(cityHash64(a), 10) UInt64 + plus(b, 3) UInt64 + PROJECTION + LIST id: 1, nodes: 2 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + COLUMN id: 4, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 6, constant_value: UInt64_10, constant_value_type: UInt8 + FUNCTION id: 7, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 8, nodes: 2 + COLUMN id: 9, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 10, constant_value: UInt64_3, constant_value_type: UInt8 + JOIN TREE + TABLE id: 5, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 11, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 12, nodes: 2 + COLUMN id: 13, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 14, constant_value: UInt64_0, constant_value_type: UInt8 SELECT (b AS `cityHash64(a)`) + 10 AS `plus(cityHash64(a), 10)`, (b AS b) + 3 AS `plus(b, 3)` FROM column_swap_test_test WHERE b = 0 +QUERY id: 0 + PROJECTION COLUMNS + plus(cityHash64(a), 10) UInt64 + plus(b, 3) UInt64 + PROJECTION + LIST id: 1, nodes: 2 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + COLUMN id: 4, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 6, constant_value: UInt64_10, constant_value_type: UInt8 + FUNCTION id: 7, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 8, nodes: 2 + COLUMN id: 9, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 10, constant_value: UInt64_3, constant_value_type: UInt8 + JOIN TREE + TABLE id: 5, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 11, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 12, nodes: 2 + COLUMN id: 13, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 14, constant_value: UInt64_0, constant_value_type: UInt8 SELECT (b AS `cityHash64(a)`) + 10 AS `plus(cityHash64(a), 10)`, (b AS b) + 3 AS `plus(b, 3)` FROM column_swap_test_test WHERE b = 1 +QUERY id: 0 + PROJECTION COLUMNS + plus(cityHash64(a), 10) UInt64 + plus(b, 3) UInt64 + PROJECTION + LIST id: 1, nodes: 2 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + COLUMN id: 4, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 6, constant_value: UInt64_10, constant_value_type: UInt8 + FUNCTION id: 7, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 8, nodes: 2 + COLUMN id: 9, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 10, constant_value: UInt64_3, constant_value_type: UInt8 + JOIN TREE + TABLE id: 5, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 11, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 12, nodes: 2 + COLUMN id: 13, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 14, constant_value: UInt64_1, constant_value_type: UInt8 SELECT (b AS `cityHash64(a)`) + 10 AS `plus(cityHash64(a), 10)` FROM column_swap_test_test WHERE b = 0 +QUERY id: 0 + PROJECTION COLUMNS + plus(cityHash64(a), 10) UInt64 + PROJECTION + LIST id: 1, nodes: 1 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + COLUMN id: 4, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 6, constant_value: UInt64_10, constant_value_type: UInt8 + JOIN TREE + TABLE id: 5, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 7, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 8, nodes: 2 + COLUMN id: 9, column_name: b, result_type: UInt64, source_id: 5 + CONSTANT id: 10, constant_value: UInt64_0, constant_value_type: UInt8 SELECT (cityHash64(a) AS `cityHash64(a)`) + 10 AS `plus(cityHash64(a), 10)`, a AS a FROM column_swap_test_test WHERE cityHash64(a) = 0 +QUERY id: 0 + PROJECTION COLUMNS + plus(cityHash64(a), 10) UInt64 + a String + PROJECTION + LIST id: 1, nodes: 2 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + FUNCTION id: 4, function_name: cityHash64, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 5, nodes: 1 + COLUMN id: 6, column_name: a, result_type: String, source_id: 7 + CONSTANT id: 8, constant_value: UInt64_10, constant_value_type: UInt8 + COLUMN id: 9, column_name: a, result_type: String, source_id: 7 + JOIN TREE + TABLE id: 7, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 10, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 11, nodes: 2 + FUNCTION id: 12, function_name: cityHash64, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 13, nodes: 1 + COLUMN id: 14, column_name: a, result_type: String, source_id: 7 + CONSTANT id: 15, constant_value: UInt64_0, constant_value_type: UInt8 SELECT (cityHash64(a) AS b) + 10 AS `plus(b, 10)`, a AS a FROM column_swap_test_test WHERE cityHash64(a) = 0 +QUERY id: 0 + PROJECTION COLUMNS + plus(b, 10) UInt64 + a String + PROJECTION + LIST id: 1, nodes: 2 + FUNCTION id: 2, function_name: plus, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 3, nodes: 2 + FUNCTION id: 4, function_name: cityHash64, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 5, nodes: 1 + COLUMN id: 6, column_name: a, result_type: String, source_id: 7 + CONSTANT id: 8, constant_value: UInt64_10, constant_value_type: UInt8 + COLUMN id: 9, column_name: a, result_type: String, source_id: 7 + JOIN TREE + TABLE id: 7, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 10, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 11, nodes: 2 + FUNCTION id: 12, function_name: cityHash64, function_type: ordinary, result_type: UInt64 + ARGUMENTS + LIST id: 13, nodes: 1 + COLUMN id: 14, column_name: a, result_type: String, source_id: 7 + CONSTANT id: 15, constant_value: UInt64_0, constant_value_type: UInt8 SELECT a AS `substring(reverse(b), 1, 1)`, a AS a FROM column_swap_test_test WHERE a = \'c\' +QUERY id: 0 + PROJECTION COLUMNS + substring(reverse(b), 1, 1) String + a String + PROJECTION + LIST id: 1, nodes: 2 + COLUMN id: 2, column_name: a, result_type: String, source_id: 3 + COLUMN id: 4, column_name: a, result_type: String, source_id: 3 + JOIN TREE + TABLE id: 3, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 5, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 6, nodes: 2 + COLUMN id: 7, column_name: a, result_type: String, source_id: 3 + CONSTANT id: 8, constant_value: \'c\', constant_value_type: String SELECT a AS `substring(reverse(b), 1, 1)`, a AS a FROM column_swap_test_test WHERE a = \'c\' +QUERY id: 0 + PROJECTION COLUMNS + substring(reverse(b), 1, 1) String + a String + PROJECTION + LIST id: 1, nodes: 2 + COLUMN id: 2, column_name: a, result_type: String, source_id: 3 + COLUMN id: 4, column_name: a, result_type: String, source_id: 3 + JOIN TREE + TABLE id: 3, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 5, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 6, nodes: 2 + COLUMN id: 7, column_name: a, result_type: String, source_id: 3 + CONSTANT id: 8, constant_value: \'c\', constant_value_type: String SELECT a AS t1, a AS t2 FROM column_swap_test_test WHERE a = \'c\' +QUERY id: 0 + PROJECTION COLUMNS + t1 String + t2 String + PROJECTION + LIST id: 1, nodes: 2 + COLUMN id: 2, column_name: a, result_type: String, source_id: 3 + COLUMN id: 4, column_name: a, result_type: String, source_id: 3 + JOIN TREE + TABLE id: 3, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 5, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 6, nodes: 2 + COLUMN id: 7, column_name: a, result_type: String, source_id: 3 + CONSTANT id: 8, constant_value: \'c\', constant_value_type: String SELECT a AS `substring(reverse(b), 1, 1)` FROM column_swap_test_test WHERE a = \'c\' +QUERY id: 0 + PROJECTION COLUMNS + substring(reverse(b), 1, 1) String + PROJECTION + LIST id: 1, nodes: 1 + COLUMN id: 2, column_name: a, result_type: String, source_id: 3 + JOIN TREE + TABLE id: 3, table_name: default.column_swap_test_test + WHERE + FUNCTION id: 4, function_name: equals, function_type: ordinary, result_type: UInt8 + ARGUMENTS + LIST id: 5, nodes: 2 + COLUMN id: 6, column_name: a, result_type: String, source_id: 3 + CONSTANT id: 7, constant_value: \'c\', constant_value_type: String SELECT a FROM t_bad_constraint +QUERY id: 0 + PROJECTION COLUMNS + a UInt32 + PROJECTION + LIST id: 1, nodes: 1 + COLUMN id: 2, column_name: a, result_type: UInt32, source_id: 3 + JOIN TREE + TABLE id: 3, table_name: default.t_bad_constraint diff --git a/tests/queries/0_stateless/01623_constraints_column_swap.sql b/tests/queries/0_stateless/01623_constraints_column_swap.sql index 873ebbed729..97e014d9c25 100644 --- a/tests/queries/0_stateless/01623_constraints_column_swap.sql +++ b/tests/queries/0_stateless/01623_constraints_column_swap.sql @@ -13,17 +13,20 @@ INSERT INTO column_swap_test_test VALUES (1, 'cat', 1), (2, 'dog', 2); INSERT INTO column_swap_test_test SELECT number AS i, format('test {} kek {}', toString(number), toString(number + 10)) AS a, 1 AS b FROM system.numbers LIMIT 1000000; EXPLAIN SYNTAX SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE cityHash64(a) = 1; ---EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE cityHash64(a) = 1; +EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE cityHash64(a) = 1; EXPLAIN SYNTAX SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE cityHash64(a) = 0; ---EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE cityHash64(a) = 0; +EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE cityHash64(a) = 0; EXPLAIN SYNTAX SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE b = 0; ---EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE b = 0; +EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE b = 0; EXPLAIN SYNTAX SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE b = 1; ---EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE b = 1; +EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, b + 3 FROM column_swap_test_test WHERE b = 1; EXPLAIN SYNTAX SELECT cityHash64(a) + 10 FROM column_swap_test_test WHERE cityHash64(a) = 0; +EXPLAIN QUERY TREE SELECT cityHash64(a) + 10 FROM column_swap_test_test WHERE cityHash64(a) = 0; EXPLAIN SYNTAX SELECT cityHash64(a) + 10, a FROM column_swap_test_test WHERE cityHash64(a) = 0; +EXPLAIN QUERY TREE SELECT cityHash64(a) + 10, a FROM column_swap_test_test WHERE cityHash64(a) = 0; EXPLAIN SYNTAX SELECT b + 10, a FROM column_swap_test_test WHERE b = 0; +EXPLAIN QUERY TREE SELECT b + 10, a FROM column_swap_test_test WHERE b = 0; DROP TABLE column_swap_test_test; @@ -31,9 +34,13 @@ CREATE TABLE column_swap_test_test (i Int64, a String, b String, CONSTRAINT c1 A INSERT INTO column_swap_test_test SELECT number AS i, toString(number) AS a, format('test {} kek {}', toString(number), toString(number + 10)) b FROM system.numbers LIMIT 1000000; EXPLAIN SYNTAX SELECT substring(reverse(b), 1, 1), a FROM column_swap_test_test WHERE a = 'c'; +EXPLAIN QUERY TREE SELECT substring(reverse(b), 1, 1), a FROM column_swap_test_test WHERE a = 'c'; EXPLAIN SYNTAX SELECT substring(reverse(b), 1, 1), a FROM column_swap_test_test WHERE substring(reverse(b), 1, 1) = 'c'; +EXPLAIN QUERY TREE SELECT substring(reverse(b), 1, 1), a FROM column_swap_test_test WHERE substring(reverse(b), 1, 1) = 'c'; EXPLAIN SYNTAX SELECT substring(reverse(b), 1, 1) AS t1, a AS t2 FROM column_swap_test_test WHERE substring(reverse(b), 1, 1) = 'c'; +EXPLAIN QUERY TREE SELECT substring(reverse(b), 1, 1) AS t1, a AS t2 FROM column_swap_test_test WHERE substring(reverse(b), 1, 1) = 'c'; EXPLAIN SYNTAX SELECT substring(reverse(b), 1, 1) FROM column_swap_test_test WHERE substring(reverse(b), 1, 1) = 'c'; +EXPLAIN QUERY TREE SELECT substring(reverse(b), 1, 1) FROM column_swap_test_test WHERE substring(reverse(b), 1, 1) = 'c'; DROP TABLE column_swap_test_test; @@ -44,5 +51,6 @@ CREATE TABLE t_bad_constraint(a UInt32, s String, CONSTRAINT c1 ASSUME a = toUIn INSERT INTO t_bad_constraint SELECT number, randomPrintableASCII(100) FROM numbers(10000); EXPLAIN SYNTAX SELECT a FROM t_bad_constraint; +EXPLAIN QUERY TREE SELECT a FROM t_bad_constraint; DROP TABLE t_bad_constraint;