From 61f3af90af6b7265a2b58299a723241afb06579e Mon Sep 17 00:00:00 2001 From: VaclavT Date: Wed, 8 Sep 2021 18:34:11 +0200 Subject: [PATCH] initial support for is null and is not null will nedd some work, but just for now --- lexer.cpp | 8 +++++++- lexer.h | 1 + main.cpp | 6 ++++-- parser.cpp | 6 ++++++ parser.h | 4 +++- usql.cpp | 10 +++++++++- 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lexer.cpp b/lexer.cpp index 7fd0f42..4015bcf 100644 --- a/lexer.cpp +++ b/lexer.cpp @@ -104,7 +104,8 @@ namespace usql { bool Lexer::isRelationalOperator(TokenType token_type) { return (token_type == TokenType::equal || token_type == TokenType::not_equal || token_type == TokenType::greater || token_type == TokenType::greater_equal || - token_type == TokenType::lesser || token_type == TokenType::lesser_equal); + token_type == TokenType::lesser || token_type == TokenType::lesser_equal || + token_type == TokenType::is); } bool Lexer::isLogicalOperator(TokenType token_type) { @@ -145,6 +146,8 @@ namespace usql { return TokenType::lesser; if (token == "<=") return TokenType::lesser_equal; + if (token == "is") + return TokenType::is; if (token == "as") return TokenType::keyword_as; if (token == "create") @@ -321,6 +324,9 @@ namespace usql { case TokenType::lesser_equal: txt = "<="; break; + case TokenType::is: + txt = "is"; + break; case TokenType::keyword_as: txt = "as"; break; diff --git a/lexer.h b/lexer.h index 68fdacf..09399b9 100644 --- a/lexer.h +++ b/lexer.h @@ -20,6 +20,7 @@ namespace usql { greater_equal, lesser, lesser_equal, + is, keyword_as, keyword_create, keyword_drop, diff --git a/main.cpp b/main.cpp index 9fe7fe3..efc63d7 100644 --- a/main.cpp +++ b/main.cpp @@ -145,9 +145,11 @@ void debug() { // "select ticker, dimension, calendar_date, eps, dps, roa*100 as roa, roe*100 as roe, pp(revenue), netinc from sf1 where (ticker = 'AIG' or ticker = 'WFC') and dimension = 'MRY' and calendar_date > to_date('2019-01-01', '%Y-%m-%d') order by 3 desc // "select ticker, dimension, calendar_date, eps, dps, roa*100 as roa, roe*100 as roe, pp(revenue) as revenue, pp(netinc) as netinc from sf1 where (ticker = 'AIG' or ticker = 'WFC') and dimension = 'MRY' and calendar_date > to_date('2019-01-01', '%Y-%m-%d') order by 3 desc", "create table a (i integer not null, s varchar(64), f float null, d date null, b boolean)", - "insert into a (i, s, b) values(1, upper('one'), 'Y')", + "insert into a (i, s, b) values(1, upper('zero'), 'Y')", "insert into a (i, s, b, f) values(1 + 10000, upper('one'), 'N', 3.1415)", - "select * from a where d is null", + "insert into a (i, s, f) values(2 + 10000, upper('two'), 3.1415)", + "select * from a where b is null", + "select * from a where b is not null", // "select * from a where b='N'", // "update a set i = i * 100, f = f + 0.01 where i > 1", // "select to_string(i, '%d.%m.%Y %H:%M:%S'), i, s from a where i < to_date('20.12.2019', '%d.%m.%Y')", diff --git a/parser.cpp b/parser.cpp index 7453008..8bc7fdc 100644 --- a/parser.cpp +++ b/parser.cpp @@ -472,6 +472,12 @@ namespace usql { return RelationalOperatorType::lesser; case TokenType::lesser_equal: return RelationalOperatorType::lesser_equal; + case TokenType::is: + if (m_lexer.tokenType() == TokenType::keyword_not) { + m_lexer.skipToken(TokenType::keyword_not); + return RelationalOperatorType::is_not; + } + return RelationalOperatorType::is; default: throw Exception("Unknown relational operator " + op.token_string); } diff --git a/parser.h b/parser.h index 4ab3390..e64096e 100644 --- a/parser.h +++ b/parser.h @@ -210,7 +210,9 @@ namespace usql { greater_equal, lesser, lesser_equal, - not_equal + not_equal, + is, + is_not // like }; diff --git a/usql.cpp b/usql.cpp index 058c269..ca05bf1 100644 --- a/usql.cpp +++ b/usql.cpp @@ -398,7 +398,15 @@ bool USql::eval_relational_operator(const RelationalOperatorNode &filter, Table double comparator; - if (left_value->node_type == NodeType::int_value && right_value->node_type == NodeType::int_value) { + if (left_value->node_type == NodeType::null_value || right_value->node_type == NodeType::null_value) { + bool all_null = left_value->isNull() && right_value->node_type == NodeType::null_value || + right_value->isNull() && left_value->node_type == NodeType::null_value; + if (filter.op == RelationalOperatorType::is) + return all_null; + if (filter.op == RelationalOperatorType::is_not) + return !all_null; + return false; + } else if (left_value->node_type == NodeType::int_value && right_value->node_type == NodeType::int_value) { comparator = left_value->getIntegerValue() - right_value->getIntegerValue(); } else if ((left_value->node_type == NodeType::int_value && right_value->node_type == NodeType::float_value) || (left_value->node_type == NodeType::float_value && right_value->node_type == NodeType::int_value) ||