From f7e0912d81fea09326996a3aaee951ea4148ca30 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 1 Mar 2018 08:24:56 +0300 Subject: [PATCH] Added support for LIMIT BY arbitary expressions [#CLICKHOUSE-3613] #1947 --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 18 ++++++++++++++++++ dbms/src/Interpreters/ExpressionAnalyzer.h | 1 + .../Interpreters/InterpreterSelectQuery.cpp | 13 +++++++++++-- dbms/src/Interpreters/InterpreterSelectQuery.h | 1 + .../00583_limit_by_expressions.reference | 13 +++++++++++++ .../0_stateless/00583_limit_by_expressions.sql | 7 +++++++ 6 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00583_limit_by_expressions.reference create mode 100644 dbms/tests/queries/0_stateless/00583_limit_by_expressions.sql diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 10362fc54f6..e0b78a30b0d 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -2529,6 +2529,24 @@ bool ExpressionAnalyzer::appendOrderBy(ExpressionActionsChain & chain, bool only return true; } +bool ExpressionAnalyzer::appendLimitBy(ExpressionActionsChain & chain, bool only_types) +{ + assertSelect(); + + if (!select_query->limit_by_expression_list) + return false; + + initChain(chain, aggregated_columns); + ExpressionActionsChain::Step & step = chain.steps.back(); + + getRootActions(select_query->limit_by_expression_list, only_types, false, step.actions); + + for (const auto & child : select_query->limit_by_expression_list->children) + step.required_output.push_back(child->getColumnName()); + + return true; +} + void ExpressionAnalyzer::appendProjectResult(ExpressionActionsChain & chain) const { assertSelect(); diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.h b/dbms/src/Interpreters/ExpressionAnalyzer.h index bdddb169271..ccad4b13740 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.h +++ b/dbms/src/Interpreters/ExpressionAnalyzer.h @@ -111,6 +111,7 @@ public: bool appendHaving(ExpressionActionsChain & chain, bool only_types); void appendSelect(ExpressionActionsChain & chain, bool only_types); bool appendOrderBy(ExpressionActionsChain & chain, bool only_types); + bool appendLimitBy(ExpressionActionsChain & chain, bool only_types); /// Deletes all columns except mentioned by SELECT, arranges the remaining columns and renames them to aliases. void appendProjectResult(ExpressionActionsChain & chain) const; diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 05f3c856206..3fe7896ff58 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -286,6 +286,10 @@ InterpreterSelectQuery::AnalysisResult InterpreterSelectQuery::analyzeExpression res.before_order_and_select = chain.getLastActions(); chain.addStep(); + query_analyzer->appendLimitBy(chain, !res.second_stage); + res.before_limit_by = chain.getLastActions(); + chain.addStep(); + query_analyzer->appendProjectResult(chain); res.final_projection = chain.getLastActions(); @@ -456,9 +460,14 @@ void InterpreterSelectQuery::executeImpl(Pipeline & pipeline, const BlockInputSt if (need_second_distinct_pass) executeDistinct(pipeline, false, Names()); + if (query.limit_by_expression_list) + { + executeExpression(pipeline, expressions.before_limit_by); + executeLimitBy(pipeline); + } + /** We must do projection after DISTINCT because projection may remove some columns. */ - executeLimitBy(pipeline); executeProjection(pipeline, expressions.final_projection); /** Extremes are calculated before LIMIT, but after LIMIT BY. This is Ok. @@ -1029,7 +1038,7 @@ void InterpreterSelectQuery::executeLimitBy(Pipeline & pipeline) Names columns; for (const auto & elem : query.limit_by_expression_list->children) - columns.emplace_back(elem->getAliasOrColumnName()); + columns.emplace_back(elem->getColumnName()); size_t value = safeGet(typeid_cast(*query.limit_by_value).value); diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.h b/dbms/src/Interpreters/InterpreterSelectQuery.h index 2150672e2c7..19e312189d8 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.h +++ b/dbms/src/Interpreters/InterpreterSelectQuery.h @@ -124,6 +124,7 @@ private: ExpressionActionsPtr before_aggregation; ExpressionActionsPtr before_having; ExpressionActionsPtr before_order_and_select; + ExpressionActionsPtr before_limit_by; ExpressionActionsPtr final_projection; /// Columns from the SELECT list, before renaming them to aliases. diff --git a/dbms/tests/queries/0_stateless/00583_limit_by_expressions.reference b/dbms/tests/queries/0_stateless/00583_limit_by_expressions.reference new file mode 100644 index 00000000000..c9ce7e7c8aa --- /dev/null +++ b/dbms/tests/queries/0_stateless/00583_limit_by_expressions.reference @@ -0,0 +1,13 @@ +1 +1 +1 +1 +1 +0 +1 +2 +3 +0 +1 +5 +6 diff --git a/dbms/tests/queries/0_stateless/00583_limit_by_expressions.sql b/dbms/tests/queries/0_stateless/00583_limit_by_expressions.sql new file mode 100644 index 00000000000..0163a36f5f0 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00583_limit_by_expressions.sql @@ -0,0 +1,7 @@ +SELECT 1 FROM system.one LIMIT 1 BY 1; +SELECT 1 FROM system.one LIMIT 1 BY 1 AS one; +SELECT 1 as one FROM system.one LIMIT 1 BY 1; +SELECT 1 as one FROM system.one LIMIT 1 BY one; +SELECT 1 as one FROM system.one LIMIT 1 BY rand(); +SELECT number FROM numbers(10) LIMIT 2 BY number % 2; +SELECT number FROM numbers(10) LIMIT 2 BY intDiv(number, 5);