Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement NOT BETWEEN operator (cleanups). #4328

Merged
merged 13 commits into from Feb 10, 2019
3 changes: 3 additions & 0 deletions dbms/src/Parsers/ExpressionElementParsers.cpp
Expand Up @@ -1130,6 +1130,9 @@ const char * ParserAlias::restricted_keywords[] =
"FORMAT",
"UNION",
"INTO",
"NOT",
"BETWEEN",
"LIKE",
nullptr
};

Expand Down
71 changes: 45 additions & 26 deletions dbms/src/Parsers/ExpressionListParsers.cpp
Expand Up @@ -228,9 +228,10 @@ bool ParserVariableArityOperatorList::parseImpl(Pos & pos, ASTPtr & node, Expect

bool ParserBetweenExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
/// For the expression (subject BETWEEN left AND right)
/// For the expression (subject [NOT] BETWEEN left AND right)
/// create an AST the same as for (subject> = left AND subject <= right).

ParserKeyword s_not("NOT");
ParserKeyword s_between("BETWEEN");
ParserKeyword s_and("AND");

Expand All @@ -241,8 +242,16 @@ bool ParserBetweenExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
if (!elem_parser.parse(pos, subject, expected))
return false;

bool negative = s_not.ignore(pos, expected);

if (!s_between.ignore(pos, expected))
{
if (negative)
--pos;

/// No operator was parsed, just return element.
node = subject;
}
else
{
if (!elem_parser.parse(pos, left, expected))
Expand All @@ -254,40 +263,50 @@ bool ParserBetweenExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
if (!elem_parser.parse(pos, right, expected))
return false;

/// AND function
auto f_and = std::make_shared<ASTFunction>();
auto args_and = std::make_shared<ASTExpressionList>();
auto f_combined_expression = std::make_shared<ASTFunction>();
auto args_combined_expression = std::make_shared<ASTExpressionList>();

/// [NOT] BETWEEN left AND right
auto f_left_expr = std::make_shared<ASTFunction>();
auto args_left_expr = std::make_shared<ASTExpressionList>();

/// >=
auto f_ge = std::make_shared<ASTFunction>();
auto args_ge = std::make_shared<ASTExpressionList>();
auto f_right_expr = std::make_shared<ASTFunction>();
auto args_right_expr = std::make_shared<ASTExpressionList>();

/// <=
auto f_le = std::make_shared<ASTFunction>();
auto args_le = std::make_shared<ASTExpressionList>();
args_left_expr->children.emplace_back(subject);
args_left_expr->children.emplace_back(left);

args_ge->children.emplace_back(subject);
args_ge->children.emplace_back(left);
args_right_expr->children.emplace_back(subject);
args_right_expr->children.emplace_back(right);

args_le->children.emplace_back(subject);
args_le->children.emplace_back(right);
if (negative)
{
/// NOT BETWEEN
f_left_expr->name = "less";
f_right_expr->name = "greater";
f_combined_expression->name = "or";
}
else
{
/// BETWEEN
f_left_expr->name = "greaterOrEquals";
f_right_expr->name = "lessOrEquals";
f_combined_expression->name = "and";
}

f_ge->name = "greaterOrEquals";
f_ge->arguments = args_ge;
f_ge->children.emplace_back(f_ge->arguments);
f_left_expr->arguments = args_left_expr;
f_left_expr->children.emplace_back(f_left_expr->arguments);

f_le->name = "lessOrEquals";
f_le->arguments = args_le;
f_le->children.emplace_back(f_le->arguments);
f_right_expr->arguments = args_right_expr;
f_right_expr->children.emplace_back(f_right_expr->arguments);

args_and->children.emplace_back(f_ge);
args_and->children.emplace_back(f_le);
args_combined_expression->children.emplace_back(f_left_expr);
args_combined_expression->children.emplace_back(f_right_expr);

f_and->name = "and";
f_and->arguments = args_and;
f_and->children.emplace_back(f_and->arguments);
f_combined_expression->arguments = args_combined_expression;
f_combined_expression->children.emplace_back(f_combined_expression->arguments);

node = f_and;
node = f_combined_expression;
}

return true;
Expand Down
18 changes: 18 additions & 0 deletions dbms/tests/queries/0_stateless/00834_not_between.reference
@@ -0,0 +1,18 @@
1
0
1
5
6
7
8
9
0 0
0 0
0 0
0 0
1 1
1 1
1 1
0 0
0 0
0 0
4 changes: 4 additions & 0 deletions dbms/tests/queries/0_stateless/00834_not_between.sql
@@ -0,0 +1,4 @@
SELECT 2 NOT BETWEEN 2 + 1 AND 4 - 1;
SELECT number FROM ( SELECT number FROM system.numbers LIMIT 10 ) WHERE number NOT BETWEEN 2 AND 4;

SELECT number BETWEEN 4 AND 6, NOT number NOT BETWEEN 4 AND 6 AND 1 FROM numbers(10);