mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-18 13:42:02 +00:00
impl
This commit is contained in:
parent
99929981ab
commit
36aaabfd3a
@ -3,10 +3,10 @@
|
||||
|
||||
#include <Poco/String.h>
|
||||
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/ReadBufferFromMemory.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <Parsers/DumpASTNode.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
#include <Parsers/ASTAsterisk.h>
|
||||
#include <Parsers/ASTColumnsTransformers.h>
|
||||
@ -49,6 +49,7 @@ namespace ErrorCodes
|
||||
extern const int BAD_ARGUMENTS;
|
||||
extern const int SYNTAX_ERROR;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int ILLEGAL_AGGREGATION;
|
||||
}
|
||||
|
||||
|
||||
@ -268,7 +269,6 @@ bool ParserCompoundIdentifier::parseImpl(Pos & pos, ASTPtr & node, Expected & ex
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
ParserIdentifier id_parser;
|
||||
@ -276,6 +276,7 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
ParserKeyword all("ALL");
|
||||
ParserExpressionList contents(false, is_table_function);
|
||||
ParserSelectWithUnionQuery select;
|
||||
ParserKeyword filter("FILTER");
|
||||
ParserKeyword over("OVER");
|
||||
|
||||
bool has_all = false;
|
||||
@ -440,16 +441,27 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
function_node->children.push_back(function_node->parameters);
|
||||
}
|
||||
|
||||
if (over.ignore(pos, expected))
|
||||
if (filter.ignore(pos, expected))
|
||||
{
|
||||
function_node->is_window_function = true;
|
||||
|
||||
// We are slightly breaking the parser interface by parsing the window
|
||||
// definition into an existing ASTFunction. Normally it would take a
|
||||
// reference to ASTPtr and assign it the new node. We only have a pointer
|
||||
// of a different type, hence this workaround with a temporary pointer.
|
||||
ASTPtr function_node_as_iast = function_node;
|
||||
|
||||
ParserFilterClause filter_parser;
|
||||
if (!filter_parser.parse(pos, function_node_as_iast, expected))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (over.ignore(pos, expected))
|
||||
{
|
||||
function_node->is_window_function = true;
|
||||
|
||||
ASTPtr function_node_as_iast = function_node;
|
||||
|
||||
ParserWindowReference window_reference;
|
||||
if (!window_reference.parse(pos, function_node_as_iast, expected))
|
||||
{
|
||||
@ -504,6 +516,51 @@ bool ParserTableFunctionView::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserFilterClause::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
assert(node);
|
||||
ASTFunction & function = dynamic_cast<ASTFunction &>(*node);
|
||||
|
||||
ParserToken parser_openging_bracket(TokenType::OpeningRoundBracket);
|
||||
if (!parser_openging_bracket.ignore(pos, expected))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ParserKeyword parser_where("WHERE");
|
||||
if (!parser_where.ignore(pos, expected))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ParserExpressionList parser_condition(false);
|
||||
ASTPtr condition;
|
||||
if (!parser_condition.parse(pos, condition, expected))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ParserToken parser_closing_bracket(TokenType::ClosingRoundBracket);
|
||||
if (!parser_closing_bracket.ignore(pos, expected))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (function.name.find("If") != String::npos)
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_AGGREGATION,
|
||||
"Filter clause provided for an aggregating function (" + function.name + ") already containing If suffix");
|
||||
}
|
||||
if (condition->children.empty())
|
||||
{
|
||||
throw Exception(ErrorCodes::SYNTAX_ERROR, "Empty condition for WHERE");
|
||||
}
|
||||
|
||||
function.name += "If";
|
||||
function.arguments->children.push_back(condition->children[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserWindowReference::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
assert(node);
|
||||
|
@ -171,6 +171,13 @@ protected:
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
|
||||
// Allows to make queries like SELECT SUM(<expr>) FILTER(WHERE <cond>) FROM ...
|
||||
class ParserFilterClause : public IParserBase
|
||||
{
|
||||
const char * getName() const override { return "filter"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
|
||||
// Window reference (the thing that goes after OVER) for window function.
|
||||
// Can be either window name or window definition.
|
||||
class ParserWindowReference : public IParserBase
|
||||
|
@ -0,0 +1,2 @@
|
||||
98
|
||||
2450
|
4
tests/queries/0_stateless/02000_select_with_filter.sql
Normal file
4
tests/queries/0_stateless/02000_select_with_filter.sql
Normal file
@ -0,0 +1,4 @@
|
||||
SELECT argMax(number, number + 1) FILTER(WHERE number != 99) FROM numbers(100) ;
|
||||
SELECT sum(number) FILTER(WHERE number % 2 == 0) FROM numbers(100);
|
||||
SELECT sumIfOrNull(number, number % 2 == 1) FILTER(WHERE number % 2 == 0) FROM numbers(100); -- { clientError 184 }
|
||||
SELECT sum(number) FILTER(WHERE) FROM numbers(100); -- { clientError 62 }
|
Loading…
Reference in New Issue
Block a user