From f346a9bf8b6e1cacaee538d376da668139b995e6 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov Date: Tue, 19 Jan 2021 04:00:39 +0300 Subject: [PATCH] frame grammar tmp --- src/Interpreters/AggregateDescription.h | 22 ++++++- src/Interpreters/ExpressionAnalyzer.cpp | 14 ++++ src/Parsers/ASTWindowDefinition.cpp | 21 ++++-- src/Parsers/ASTWindowDefinition.h | 4 ++ src/Parsers/ExpressionElementParsers.cpp | 65 +++++++++++++++++++ .../0_stateless/01591_window_functions.sql | 12 ++++ 6 files changed, 132 insertions(+), 6 deletions(-) diff --git a/src/Interpreters/AggregateDescription.h b/src/Interpreters/AggregateDescription.h index f1fc232d04d..89d1cdf4cb4 100644 --- a/src/Interpreters/AggregateDescription.h +++ b/src/Interpreters/AggregateDescription.h @@ -39,6 +39,26 @@ struct WindowFunctionDescription std::string dump() const; }; +struct WindowFrame +{ + enum class FrameType { Rows, Groups, Range }; + enum class OffsetType { Unbounded, Current, Offset }; + + // This flag signifies that the frame properties were not set explicitly by + // user, but the fields of this structure still have to contain proper values + // for the default frame of ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. + bool is_default = true; + + FrameType type = FrameType::Rows; + + /* + * We don't need these yet. + * OffsetType begin_offset = Unbounded; + + * OffsetType end_offset = Current; + */ +}; + struct WindowDescription { std::string window_name; @@ -54,7 +74,7 @@ struct WindowDescription // then by ORDER BY. This field holds this combined sort order. SortDescription full_sort_description; - // No frame info as of yet. + WindowFrame frame; // The window functions that are calculated for this window. std::vector window_functions; diff --git a/src/Interpreters/ExpressionAnalyzer.cpp b/src/Interpreters/ExpressionAnalyzer.cpp index 76fc0cf419f..97beff6b365 100644 --- a/src/Interpreters/ExpressionAnalyzer.cpp +++ b/src/Interpreters/ExpressionAnalyzer.cpp @@ -515,6 +515,20 @@ void makeWindowDescription(WindowDescription & desc, const IAST * ast) desc.full_sort_description = desc.partition_by; desc.full_sort_description.insert(desc.full_sort_description.end(), desc.order_by.begin(), desc.order_by.end()); + + if (definition.frame.type != WindowFrame::FrameType::Rows) + { + std::string name = definition.frame.type == WindowFrame::FrameType::Rows + ? "ROWS" + : definition.frame.type == WindowFrame::FrameType::Groups + ? "GROUPS" : "RANGE"; + + throw Exception(ErrorCodes::NOT_IMPLEMENTED, + "Window frame '{}' is not implemented (while processing '{}')", + name, ast->formatForErrorMessage()); + } + + desc.frame = definition.frame; } void ExpressionAnalyzer::makeWindowDescriptions(ActionsDAGPtr actions) diff --git a/src/Parsers/ASTWindowDefinition.cpp b/src/Parsers/ASTWindowDefinition.cpp index 79a4b4bf1c6..c726629d31b 100644 --- a/src/Parsers/ASTWindowDefinition.cpp +++ b/src/Parsers/ASTWindowDefinition.cpp @@ -22,6 +22,8 @@ ASTPtr ASTWindowDefinition::clone() const result->children.push_back(result->order_by); } + result->frame = frame; + return result; } @@ -31,12 +33,12 @@ String ASTWindowDefinition::getID(char) const } void ASTWindowDefinition::formatImpl(const FormatSettings & settings, - FormatState & state, FormatStateStacked frame) const + FormatState & state, FormatStateStacked format_frame) const { if (partition_by) { settings.ostr << "PARTITION BY "; - partition_by->formatImpl(settings, state, frame); + partition_by->formatImpl(settings, state, format_frame); } if (partition_by && order_by) @@ -47,7 +49,16 @@ void ASTWindowDefinition::formatImpl(const FormatSettings & settings, if (order_by) { settings.ostr << "ORDER BY "; - order_by->formatImpl(settings, state, frame); + order_by->formatImpl(settings, state, format_frame); + } + + if (!frame.is_default) + { + const auto name = frame.type == WindowFrame::FrameType::Rows + ? "ROWS" : frame.type == WindowFrame::FrameType::Groups + ? "GROUPS" : "RANGE"; + + settings.ostr << name << " BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"; } } @@ -56,8 +67,8 @@ std::string ASTWindowDefinition::getDefaultWindowName() const WriteBufferFromOwnString ostr; FormatSettings settings{ostr, true /* one_line */}; FormatState state; - FormatStateStacked frame; - formatImpl(settings, state, frame); + FormatStateStacked format_frame; + formatImpl(settings, state, format_frame); return ostr.str(); } diff --git a/src/Parsers/ASTWindowDefinition.h b/src/Parsers/ASTWindowDefinition.h index bf74cf809f9..fa20b74b0fc 100644 --- a/src/Parsers/ASTWindowDefinition.h +++ b/src/Parsers/ASTWindowDefinition.h @@ -1,5 +1,7 @@ #pragma once +#include + #include @@ -12,6 +14,8 @@ struct ASTWindowDefinition : public IAST ASTPtr order_by; + WindowFrame frame; + ASTPtr clone() const override; diff --git a/src/Parsers/ExpressionElementParsers.cpp b/src/Parsers/ExpressionElementParsers.cpp index 39f8a3c951c..a80f4561eb0 100644 --- a/src/Parsers/ExpressionElementParsers.cpp +++ b/src/Parsers/ExpressionElementParsers.cpp @@ -504,6 +504,65 @@ bool ParserWindowReference::parseImpl(Pos & pos, ASTPtr & node, Expected & expec return parser_definition.parse(pos, function->window_definition, expected); } +static bool tryParseFrameDefinition(ASTWindowDefinition * node, IParser::Pos & pos, + Expected & expected) +{ + ParserKeyword keyword_rows("ROWS"); + ParserKeyword keyword_groups("GROUPS"); + ParserKeyword keyword_range("RANGE"); + + if (keyword_rows.ignore(pos, expected)) + { + node->frame.type = WindowFrame::FrameType::Rows; + } + else if (keyword_groups.ignore(pos, expected)) + { + node->frame.type = WindowFrame::FrameType::Groups; + } + else if (keyword_range.ignore(pos, expected)) + { + node->frame.type = WindowFrame::FrameType::Range; + } + else + { + /* No frame clause. */ + return true; + } + + ParserKeyword keyword_between("BETWEEN"); + ParserKeyword keyword_unbounded("UNBOUNDED"); + ParserKeyword keyword_preceding("PRECEDING"); + ParserKeyword keyword_and("AND"); + ParserKeyword keyword_current_row("CURRENT ROW"); + + if (!keyword_between.ignore(pos, expected)) + { + return false; + } + + if (!keyword_unbounded.ignore(pos, expected)) + { + return false; + } + + if (!keyword_preceding.ignore(pos, expected)) + { + return false; + } + + if (!keyword_and.ignore(pos, expected)) + { + return false; + } + + if (!keyword_current_row.ignore(pos, expected)) + { + return false; + } + + return true; +} + bool ParserWindowDefinition::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) { auto result = std::make_shared(); @@ -548,6 +607,12 @@ bool ParserWindowDefinition::parseImpl(Pos & pos, ASTPtr & node, Expected & expe } } + if (!tryParseFrameDefinition(result.get(), pos, expected)) + { + /* Broken frame definition. */ + return false; + } + ParserToken parser_closing_bracket(TokenType::ClosingRoundBracket); if (!parser_closing_bracket.ignore(pos, expected)) { diff --git a/tests/queries/0_stateless/01591_window_functions.sql b/tests/queries/0_stateless/01591_window_functions.sql index 95afb9be408..e4858cd6dc6 100644 --- a/tests/queries/0_stateless/01591_window_functions.sql +++ b/tests/queries/0_stateless/01591_window_functions.sql @@ -92,3 +92,15 @@ from numbers(10) window w1 as (partition by intDiv(number, 3)) ; + +-- ROWS frame +select + sum(number) + over (order by number rows between unbounded preceding and current row) +from numbers(3); + + +select + sum(number) + over (order by number groups between unbounded preceding and current row) +from numbers(3);