Support MySQL-style syntax for DATE_ADD and similar functions

This commit is contained in:
Ivan Blinkov 2018-12-20 11:22:24 +03:00
parent 24a0b3a53e
commit f63aa0eb3b
3 changed files with 38 additions and 17 deletions

View File

@ -717,8 +717,8 @@ bool ParserExtractExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
bool ParserDateAddExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) bool ParserDateAddExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{ {
const char * function_name = nullptr; const char * function_name = nullptr;
ASTPtr left_node; ASTPtr timestamp_node;
ASTPtr right_node; ASTPtr offset_node;
if (ParserKeyword("DATEADD").ignore(pos, expected) || ParserKeyword("DATE_ADD").ignore(pos, expected) if (ParserKeyword("DATEADD").ignore(pos, expected) || ParserKeyword("DATE_ADD").ignore(pos, expected)
|| ParserKeyword("TIMESTAMPADD").ignore(pos, expected) || ParserKeyword("TIMESTAMP_ADD").ignore(pos, expected)) || ParserKeyword("TIMESTAMPADD").ignore(pos, expected) || ParserKeyword("TIMESTAMP_ADD").ignore(pos, expected))
@ -734,31 +734,50 @@ bool ParserDateAddExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
++pos; ++pos;
ParserInterval interval_parser; ParserInterval interval_parser;
if (!interval_parser.ignore(pos, expected)) if (interval_parser.ignore(pos, expected))
return false; {
/// function(unit, offset, timestamp)
if (pos->type != TokenType::Comma)
return false;
++pos;
const char * interval_function_name = interval_parser.getToIntervalKindFunctionName(); if (!ParserExpression().parse(pos, offset_node, expected))
return false;
if (pos->type != TokenType::Comma) if (pos->type != TokenType::Comma)
return false; return false;
++pos; ++pos;
if (!ParserExpression().parse(pos, left_node, expected)) if (!ParserExpression().parse(pos, timestamp_node, expected))
return false; return false;
}
else
{
/// function(timestamp, INTERVAL offset unit)
if (!ParserExpression().parse(pos, timestamp_node, expected))
return false;
if (pos->type != TokenType::Comma) if (pos->type != TokenType::Comma)
return false; return false;
++pos; ++pos;
if (!ParserExpression().parse(pos, right_node, expected)) if (!ParserKeyword("INTERVAL").ignore(pos, expected))
return false; return false;
if (!ParserExpression().parse(pos, offset_node, expected))
return false;
interval_parser.ignore(pos, expected);
}
if (pos->type != TokenType::ClosingRoundBracket) if (pos->type != TokenType::ClosingRoundBracket)
return false; return false;
++pos; ++pos;
const char * interval_function_name = interval_parser.getToIntervalKindFunctionName();
auto interval_expr_list_args = std::make_shared<ASTExpressionList>(); auto interval_expr_list_args = std::make_shared<ASTExpressionList>();
interval_expr_list_args->children = {left_node}; interval_expr_list_args->children = {offset_node};
auto interval_func_node = std::make_shared<ASTFunction>(); auto interval_func_node = std::make_shared<ASTFunction>();
interval_func_node->name = interval_function_name; interval_func_node->name = interval_function_name;
@ -766,7 +785,7 @@ bool ParserDateAddExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
interval_func_node->children.push_back(interval_func_node->arguments); interval_func_node->children.push_back(interval_func_node->arguments);
auto expr_list_args = std::make_shared<ASTExpressionList>(); auto expr_list_args = std::make_shared<ASTExpressionList>();
expr_list_args->children = {right_node, interval_func_node}; expr_list_args->children = {timestamp_node, interval_func_node};
auto func_node = std::make_shared<ASTFunction>(); auto func_node = std::make_shared<ASTFunction>();
func_node->name = function_name; func_node->name = function_name;

View File

@ -25,3 +25,4 @@ foo*
-3 -3
2021-01-01 2021-01-01
2018-07-18 01:02:03 2018-07-18 01:02:03
2018-04-01

View File

@ -27,3 +27,4 @@ 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_DIFF(QQ, toDate('2018-12-18'), toDate('2018-01-01'));
select DATE_ADD(YEAR, 3, 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')); select timestamp_sub(SQL_TSI_MONTH, 5, toDateTime('2018-12-18 01:02:03'));
select timestamp_ADD(toDate('2018-01-01'), INTERVAL 3 MONTH);