From 0352c5a57c8a3124f60dad8506b03fa3b41bd3e0 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 19 Dec 2018 14:37:14 +0300 Subject: [PATCH] Introduce DATE_ADD/DATE_SUB/TIMESTAMP_ADD/TIMESTAMP_SUB #3705 --- dbms/src/Parsers/CommonParsers.h | 25 +++++++ dbms/src/Parsers/ExpressionElementParsers.cpp | 68 ++++++++++++++++++- dbms/src/Parsers/ExpressionElementParsers.h | 7 ++ dbms/src/Parsers/ExpressionListParsers.cpp | 32 +-------- .../00765_sql_compatibility_aliases.reference | 2 + .../00765_sql_compatibility_aliases.sql | 2 + 6 files changed, 105 insertions(+), 31 deletions(-) diff --git a/dbms/src/Parsers/CommonParsers.h b/dbms/src/Parsers/CommonParsers.h index 01944b6d21e..44c8ab17fb7 100644 --- a/dbms/src/Parsers/CommonParsers.h +++ b/dbms/src/Parsers/CommonParsers.h @@ -66,6 +66,31 @@ public: ParserInterval() : interval_kind(IntervalKind::Incorrect) {} + const char * getToIntervalKindFunctionName() + { + switch (interval_kind) + { + case ParserInterval::IntervalKind::Second: + return "toIntervalSecond"; + case ParserInterval::IntervalKind::Minute: + return "toIntervalMinute"; + case ParserInterval::IntervalKind::Hour: + return "toIntervalHour"; + case ParserInterval::IntervalKind::Day: + return "toIntervalDay"; + case ParserInterval::IntervalKind::Week: + return "toIntervalWeek"; + case ParserInterval::IntervalKind::Month: + return "toIntervalMonth"; + case ParserInterval::IntervalKind::Quarter: + return "toIntervalQuarter"; + case ParserInterval::IntervalKind::Year: + return "toIntervalYear"; + default: + return nullptr; + } + } + protected: const char * getName() const override { return "interval"; } diff --git a/dbms/src/Parsers/ExpressionElementParsers.cpp b/dbms/src/Parsers/ExpressionElementParsers.cpp index ba7c7dbf108..35e66da5141 100644 --- a/dbms/src/Parsers/ExpressionElementParsers.cpp +++ b/dbms/src/Parsers/ExpressionElementParsers.cpp @@ -714,13 +714,78 @@ bool ParserExtractExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & exp return true; } +bool ParserDateAddExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) +{ + const char * function_name = nullptr; + ASTPtr left_node; + ASTPtr right_node; + + if (ParserKeyword("DATEADD").ignore(pos, expected) || ParserKeyword("DATE_ADD").ignore(pos, expected) + || ParserKeyword("TIMESTAMPADD").ignore(pos, expected) || ParserKeyword("TIMESTAMP_ADD").ignore(pos, expected)) + function_name = "plus"; + else if (ParserKeyword("DATESUB").ignore(pos, expected) || ParserKeyword("DATE_SUB").ignore(pos, expected) + || ParserKeyword("TIMESTAMPSUB").ignore(pos, expected) || ParserKeyword("TIMESTAMP_SUB").ignore(pos, expected)) + function_name = "minus"; + else + return false; + + if (pos->type != TokenType::OpeningRoundBracket) + return false; + ++pos; + + ParserInterval interval_parser; + if (!interval_parser.ignore(pos, expected)) + return false; + + const char * interval_function_name = interval_parser.getToIntervalKindFunctionName(); + + if (pos->type != TokenType::Comma) + return false; + ++pos; + + if (!ParserExpression().parse(pos, left_node, expected)) + return false; + + if (pos->type != TokenType::Comma) + return false; + ++pos; + + if (!ParserExpression().parse(pos, right_node, expected)) + return false; + + if (pos->type != TokenType::ClosingRoundBracket) + return false; + ++pos; + + auto interval_expr_list_args = std::make_shared(); + interval_expr_list_args->children = {left_node}; + + auto interval_func_node = std::make_shared(); + interval_func_node->name = interval_function_name; + interval_func_node->arguments = std::move(interval_expr_list_args); + interval_func_node->children.push_back(interval_func_node->arguments); + + auto expr_list_args = std::make_shared(); + expr_list_args->children = {right_node, interval_func_node}; + + auto func_node = std::make_shared(); + func_node->name = function_name; + func_node->arguments = std::move(expr_list_args); + func_node->children.push_back(func_node->arguments); + + node = std::move(func_node); + + return true; +} + bool ParserDateDiffExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) { const char * interval_name = nullptr; ASTPtr left_node; ASTPtr right_node; - if (!(ParserKeyword("DATEDIFF").ignore(pos, expected) || ParserKeyword("DATE_DIFF").ignore(pos, expected))) + if (!(ParserKeyword("DATEDIFF").ignore(pos, expected) || ParserKeyword("DATE_DIFF").ignore(pos, expected) + || ParserKeyword("TIMESTAMPDIFF").ignore(pos, expected) || ParserKeyword("TIMESTAMP_DIFF").ignore(pos, expected))) return false; if (pos->type != TokenType::OpeningRoundBracket) @@ -1093,6 +1158,7 @@ bool ParserExpressionElement::parseImpl(Pos & pos, ASTPtr & node, Expected & exp || ParserLiteral().parse(pos, node, expected) || ParserCastExpression().parse(pos, node, expected) || ParserExtractExpression().parse(pos, node, expected) + || ParserDateAddExpression().parse(pos, node, expected) || ParserDateDiffExpression().parse(pos, node, expected) || ParserSubstringExpression().parse(pos, node, expected) || ParserTrimExpression().parse(pos, node, expected) diff --git a/dbms/src/Parsers/ExpressionElementParsers.h b/dbms/src/Parsers/ExpressionElementParsers.h index c35a6613155..c6afbd171e4 100644 --- a/dbms/src/Parsers/ExpressionElementParsers.h +++ b/dbms/src/Parsers/ExpressionElementParsers.h @@ -131,6 +131,13 @@ protected: bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; }; +class ParserDateAddExpression : public IParserBase +{ +protected: + const char * getName() const override { return "DATE_ADD expression"; } + bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; +}; + class ParserDateDiffExpression : public IParserBase { protected: diff --git a/dbms/src/Parsers/ExpressionListParsers.cpp b/dbms/src/Parsers/ExpressionListParsers.cpp index 75b20226fb6..de6fc2dc129 100644 --- a/dbms/src/Parsers/ExpressionListParsers.cpp +++ b/dbms/src/Parsers/ExpressionListParsers.cpp @@ -607,41 +607,13 @@ bool ParserIntervalOperatorExpression::parseImpl(Pos & pos, ASTPtr & node, Expec if (!ParserExpressionWithOptionalAlias(false).parse(pos, expr, expected)) return false; - const char * function_name = nullptr; ParserInterval interval_parser; if (!interval_parser.ignore(pos, expected)) return false; - switch (interval_parser.interval_kind) - { - case ParserInterval::IntervalKind::Second: - function_name = "toIntervalSecond"; - break; - case ParserInterval::IntervalKind::Minute: - function_name = "toIntervalMinute"; - break; - case ParserInterval::IntervalKind::Hour: - function_name = "toIntervalHour"; - break; - case ParserInterval::IntervalKind::Day: - function_name = "toIntervalDay"; - break; - case ParserInterval::IntervalKind::Week: - function_name = "toIntervalWeek"; - break; - case ParserInterval::IntervalKind::Month: - function_name = "toIntervalMonth"; - break; - case ParserInterval::IntervalKind::Quarter: - function_name = "toIntervalQuarter"; - break; - case ParserInterval::IntervalKind::Year: - function_name = "toIntervalYear"; - break; - default: - return false; - } + const char * function_name = interval_parser.getToIntervalKindFunctionName(); + /// the function corresponding to the operator auto function = std::make_shared(); diff --git a/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.reference b/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.reference index 4e05015901b..43e7758e0f1 100644 --- a/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.reference +++ b/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.reference @@ -23,3 +23,5 @@ fooabbafoo foo* -11 -3 +2021-01-01 +2018-07-18 01:02:03 diff --git a/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.sql b/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.sql index 6fea2dafe1c..6373d579f39 100644 --- a/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.sql +++ b/dbms/tests/queries/0_stateless/00765_sql_compatibility_aliases.sql @@ -25,3 +25,5 @@ select TRIM(both 'ab' FROM 'abbafooabbafooabba'); select trim(LEADING '*[]{}|\\' FROM '\\|[[[}}}*foo*'); select DATE_DIFF(MONTH, toDate('2018-12-18'), toDate('2018-01-01')); select DATE_DIFF(QQ, toDate('2018-12-18'), toDate('2018-01-01')); +select DATE_ADD(YEAR, 3, toDate('2018-01-01')); +select timestamp_sub(SQL_TSI_MONTH, 5, toDateTime('2018-12-18 01:02:03'));