diff --git a/dbms/include/DB/Parsers/ExpressionListParsers.h b/dbms/include/DB/Parsers/ExpressionListParsers.h index 39181884726..2e0684f4615 100644 --- a/dbms/include/DB/Parsers/ExpressionListParsers.h +++ b/dbms/include/DB/Parsers/ExpressionListParsers.h @@ -180,11 +180,23 @@ protected: }; +class ParserBetweenExpression : public IParserBase +{ +private: + ParserAdditiveExpression elem_parser; + +protected: + const char * getName() const { return "BETWEEN expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected); +}; + + class ParserComparisonExpression : public IParserBase { private: static const char * operators[]; - ParserLeftAssociativeBinaryOperatorList operator_parser {operators, ParserPtr(new ParserAdditiveExpression)}; + ParserLeftAssociativeBinaryOperatorList operator_parser {operators, ParserPtr(new ParserBetweenExpression)}; protected: const char * getName() const { return "comparison expression"; } diff --git a/dbms/src/Parsers/ExpressionListParsers.cpp b/dbms/src/Parsers/ExpressionListParsers.cpp index 1abac6a6ccf..00c1f603b15 100644 --- a/dbms/src/Parsers/ExpressionListParsers.cpp +++ b/dbms/src/Parsers/ExpressionListParsers.cpp @@ -233,6 +233,90 @@ bool ParserVariableArityOperatorList::parseImpl(Pos & pos, Pos end, ASTPtr & nod return true; } +bool ParserBetweenExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected) +{ + /// Для выражения (subject BETWEEN left AND right) + /// создаём AST такое же, как для (subject >= left AND subject <= right). + + ParserWhiteSpaceOrComments ws; + ParserString s_between("BETWEEN", true, true); + ParserString s_and("AND", true, true); + + ASTPtr subject; + ASTPtr left; + ASTPtr right; + + Pos begin = pos; + + if (!elem_parser.parse(pos, end, subject, max_parsed_pos, expected)) + return false; + + ws.ignore(pos, end); + + if (!s_between.ignore(pos, end, max_parsed_pos, expected)) + node = subject; + else + { + ws.ignore(pos, end); + + if (!elem_parser.parse(pos, end, left, max_parsed_pos, expected)) + return false; + + ws.ignore(pos, end); + + if (!s_and.ignore(pos, end, max_parsed_pos, expected)) + return false; + + ws.ignore(pos, end); + + if (!elem_parser.parse(pos, end, right, max_parsed_pos, expected)) + return false; + + /// функция AND + std::unique_ptr f_and = std::make_unique(); + std::unique_ptr args_and = std::make_unique(); + + /// >= + std::unique_ptr f_ge = std::make_unique(); + std::unique_ptr args_ge = std::make_unique(); + + /// <= + std::unique_ptr f_le = std::make_unique(); + std::unique_ptr args_le = std::make_unique(); + + args_ge->children.emplace_back(subject); + args_ge->children.emplace_back(left); + + args_le->children.emplace_back(subject); + args_le->children.emplace_back(right); + + f_ge->range.first = begin; + f_ge->range.second = pos; + f_ge->name = "greaterOrEquals"; + f_ge->arguments = args_ge.release(); + f_ge->children.emplace_back(f_ge->arguments); + + f_le->range.first = begin; + f_le->range.second = pos; + f_le->name = "lessOrEquals"; + f_le->arguments = args_le.release(); + f_le->children.emplace_back(f_le->arguments); + + args_and->children.emplace_back(f_ge.release()); + args_and->children.emplace_back(f_le.release()); + + f_and->range.first = begin; + f_and->range.second = pos; + f_and->name = "and"; + f_and->arguments = args_and.release(); + f_and->children.emplace_back(f_and->arguments); + + node = f_and.release(); + } + + return true; +} + bool ParserTernaryOperatorExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected) { ParserWhiteSpaceOrComments ws; diff --git a/dbms/tests/queries/0_stateless/00320_between.reference b/dbms/tests/queries/0_stateless/00320_between.reference new file mode 100644 index 00000000000..d00491fd7e5 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00320_between.reference @@ -0,0 +1 @@ +1 diff --git a/dbms/tests/queries/0_stateless/00320_between.sql b/dbms/tests/queries/0_stateless/00320_between.sql new file mode 100644 index 00000000000..af403bdcc12 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00320_between.sql @@ -0,0 +1 @@ +SELECT 2 BETWEEN 1 + 1 AND 3 - 1;