Added support for LIMIT BY arbitary expressions [#CLICKHOUSE-3613] #1947

This commit is contained in:
Alexey Milovidov 2018-03-01 08:24:56 +03:00
parent e604be2799
commit f7e0912d81
6 changed files with 51 additions and 2 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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<UInt64>(typeid_cast<ASTLiteral &>(*query.limit_by_value).value);

View File

@ -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.

View File

@ -0,0 +1,13 @@
1
1
1
1
1
0
1
2
3
0
1
5
6

View File

@ -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);