From af4c37ea9208f87a2ba4ba7cdd65abf20c4f224c Mon Sep 17 00:00:00 2001 From: Andrey Mironov Date: Mon, 4 Aug 2014 19:25:38 +0400 Subject: [PATCH] dbms: support WITH TOTALS without GROUP BY --- .../DB/Interpreters/ExpressionAnalyzer.h | 4 +-- .../DB/Parsers/ExpressionElementParsers.h | 2 +- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 31 +++++++++++++++++-- .../Interpreters/InterpreterSelectQuery.cpp | 4 +++ dbms/src/Parsers/ExpressionElementParsers.cpp | 2 +- dbms/src/Parsers/ParserSelectQuery.cpp | 18 +++++------ dbms/src/Parsers/formatAST.cpp | 6 ++-- dbms/src/Server/TCPHandler.cpp | 4 ++- 8 files changed, 51 insertions(+), 20 deletions(-) diff --git a/dbms/include/DB/Interpreters/ExpressionAnalyzer.h b/dbms/include/DB/Interpreters/ExpressionAnalyzer.h index 4d058e69b8d..0fec5ffdea2 100644 --- a/dbms/include/DB/Interpreters/ExpressionAnalyzer.h +++ b/dbms/include/DB/Interpreters/ExpressionAnalyzer.h @@ -220,8 +220,8 @@ private: void normalizeTree(); void normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias); - /// Eliminates injective function calls from group by statement - void eliminateInjectives(); + /// Eliminates injective function calls and constant expressions from group by statement + void optimizeGroupBy(); /// Превратить перечисление значений или подзапрос в ASTSet. node - функция in или notIn. void makeSet(ASTFunction * node, const Block & sample_block); diff --git a/dbms/include/DB/Parsers/ExpressionElementParsers.h b/dbms/include/DB/Parsers/ExpressionElementParsers.h index 65b7ec53b0e..ccbd68bbd75 100644 --- a/dbms/include/DB/Parsers/ExpressionElementParsers.h +++ b/dbms/include/DB/Parsers/ExpressionElementParsers.h @@ -22,7 +22,7 @@ protected: class ParserParenthesisExpression : public IParserBase { protected: - const char * getName() const { return "expression in parenthesis"; } + const char * getName() const { return "parenthesized expression"; } bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Expected & expected); }; diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 364d7b7e884..9aad597d3b0 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -69,7 +69,7 @@ void ExpressionAnalyzer::init() normalizeTree(); /// GROUP BY injective function elimination - eliminateInjectives(); + optimizeGroupBy(); /// array_join_alias_to_name, array_join_result_to_source. getArrayJoinedColumns(); @@ -122,7 +122,7 @@ void ExpressionAnalyzer::analyzeAggregation() if (select_query->group_expression_list) { NameSet unique_keys; - const ASTs & group_asts = select_query->group_expression_list->children; + auto & group_asts = select_query->group_expression_list->children; for (size_t i = 0; i < group_asts.size(); ++i) { getRootActions(group_asts[i], true, false, temp_actions); @@ -135,6 +135,17 @@ void ExpressionAnalyzer::analyzeAggregation() const auto & col = block.getByName(column_name); + /// constant expressions have non-null column pointer at this stage + if (const auto is_constexpr = col.column) + { + if (i < group_asts.size() - 1) + group_asts[i] = std::move(group_asts.back()); + + group_asts.pop_back(); + i -= 1; + continue; + } + NameAndTypePair key{column_name, col.type}; aggregation_keys.push_back(key); @@ -145,6 +156,12 @@ void ExpressionAnalyzer::analyzeAggregation() aggregated_columns.push_back(std::move(key)); } } + + if (group_asts.empty()) + { + select_query->group_expression_list = nullptr; + has_aggregation = select_query->having_expression || aggregate_descriptions.size(); + } } for (size_t i = 0; i < aggregate_descriptions.size(); ++i) @@ -426,7 +443,7 @@ void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_as } -void ExpressionAnalyzer::eliminateInjectives() +void ExpressionAnalyzer::optimizeGroupBy() { if (!(select_query && select_query->group_expression_list)) return; @@ -469,7 +486,15 @@ void ExpressionAnalyzer::eliminateInjectives() std::back_inserter(group_exprs), is_literal ); } + else if (is_literal(group_exprs[i])) + { + remove_expr_at_index(i); + i -= 1; + } } + + if (group_exprs.empty()) + select_query->group_expression_list = nullptr; } diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 359b2fa050e..c63ca92f7ae 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -346,6 +346,10 @@ BlockInputStreamPtr InterpreterSelectQuery::execute() need_second_distinct_pass = streams.size() > 1; } + else if (query.group_by_with_totals && !aggregate_final) + { + executeTotalsAndHaving(streams, false, nullptr, aggregate_overflow_row); + } if (has_order_by) executeOrder(streams); diff --git a/dbms/src/Parsers/ExpressionElementParsers.cpp b/dbms/src/Parsers/ExpressionElementParsers.cpp index 8c5932c773a..9ac5019d12e 100644 --- a/dbms/src/Parsers/ExpressionElementParsers.cpp +++ b/dbms/src/Parsers/ExpressionElementParsers.cpp @@ -77,7 +77,7 @@ bool ParserParenthesisExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, E /// пустое выражение в скобках недопустимо if (expr_list.children.empty()) { - expected = "not empty list of expressions in parenthesis"; + expected = "non-empty parenthesized list of expressions"; return false; } diff --git a/dbms/src/Parsers/ParserSelectQuery.cpp b/dbms/src/Parsers/ParserSelectQuery.cpp index 9c2bf4ea4a8..a997628372f 100644 --- a/dbms/src/Parsers/ParserSelectQuery.cpp +++ b/dbms/src/Parsers/ParserSelectQuery.cpp @@ -198,18 +198,18 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Expected & return false; ws.ignore(pos, end); + } - /// WITH TOTALS - if (s_with.ignore(pos, end, expected)) - { - ws.ignore(pos, end); - if (!s_totals.ignore(pos, end, expected)) - return false; + /// WITH TOTALS + if (s_with.ignore(pos, end, expected)) + { + ws.ignore(pos, end); + if (!s_totals.ignore(pos, end, expected)) + return false; - select_query->group_by_with_totals = true; + select_query->group_by_with_totals = true; - ws.ignore(pos, end); - } + ws.ignore(pos, end); } /// HAVING expr diff --git a/dbms/src/Parsers/formatAST.cpp b/dbms/src/Parsers/formatAST.cpp index 6b5bf8fba75..31c8a903eb5 100644 --- a/dbms/src/Parsers/formatAST.cpp +++ b/dbms/src/Parsers/formatAST.cpp @@ -194,11 +194,11 @@ void formatAST(const ASTSelectQuery & ast, std::ostream & s, size_t indent, bo one_line ? formatAST(*ast.group_expression_list, s, indent, hilite, one_line) : formatExpressionListMultiline(typeid_cast(*ast.group_expression_list), s, indent, hilite); - - if (ast.group_by_with_totals) - s << (hilite ? hilite_keyword : "") << nl_or_ws << indent_str << (one_line ? "" : " ") << "WITH TOTALS" << (hilite ? hilite_none : ""); } + if (ast.group_by_with_totals) + s << (hilite ? hilite_keyword : "") << nl_or_ws << indent_str << (one_line ? "" : " ") << "WITH TOTALS" << (hilite ? hilite_none : ""); + if (ast.having_expression) { s << (hilite ? hilite_keyword : "") << nl_or_ws << indent_str << "HAVING " << (hilite ? hilite_none : ""); diff --git a/dbms/src/Server/TCPHandler.cpp b/dbms/src/Server/TCPHandler.cpp index c111853da8e..596a69d8e38 100644 --- a/dbms/src/Server/TCPHandler.cpp +++ b/dbms/src/Server/TCPHandler.cpp @@ -85,7 +85,9 @@ void TCPHandler::runImpl() sendHello(); - connection_context.setProgressCallback(boost::bind(&TCPHandler::updateProgress, this, _1, _2)); + connection_context.setProgressCallback([this] (const size_t rows, const size_t bytes) { + return this->updateProgress(rows, bytes); + }); while (1) {