some TODOs removed..

This commit is contained in:
VaclavT 2021-08-14 11:33:02 +02:00
parent 6921421a65
commit 4665705c3d
10 changed files with 113 additions and 78 deletions

View File

@ -1,6 +1,5 @@
### TODO ### TODO
- better support for values in update and insert
- date functions - now, add_date... - date functions - now, add_date...
- string functions rtrim, ltrim, rpad, lpad - string functions rtrim, ltrim, rpad, lpad
- add pipe | concatenation - add pipe | concatenation
@ -9,7 +8,5 @@
- support for uniqueue indexes (primary key) - support for uniqueue indexes (primary key)
- support for btree indexes - support for btree indexes
- add count min and max functions, eg aggregate functions - add count min and max functions, eg aggregate functions
- support for parenthesis
- class members should have prefix m_
- add const wherever should be - add const wherever should be
- PERF in Row::Row(const Row &other), could be more efficient (memory and cpu) - PERF in Row::Row(const Row &other), could be more efficient (memory and cpu)

View File

@ -22,16 +22,15 @@ namespace usql {
} }
void Lexer::parse(const std::string &code) { void Lexer::parse(const std::string &code) {
// TODO handle empty code if (code.empty())
m_tokens.clear(); throw Exception("empty code");
m_tokens.clear();
m_tokens.reserve(64);
// PERF something like this to preallocate ??
if (code.size() > 100) {
m_tokens.reserve(code.size() / 10);
}
m_code_str = code; m_code_str = code;
if (!m_code_str.empty() && m_code_str.back() != '\n') { if (!m_code_str.empty() && m_code_str.back() != '\n') {
m_code_str.append("\n"); // TODO temp solution to prevent possible situation when last line is a comment m_code_str.append("\n"); // temp solution to prevent possible situation when last line is a comment
} }
auto words_begin = std::sregex_iterator(m_code_str.begin(), m_code_str.end(), k_words_regex); auto words_begin = std::sregex_iterator(m_code_str.begin(), m_code_str.end(), k_words_regex);
@ -116,7 +115,7 @@ namespace usql {
} }
TokenType Lexer::type(const std::string &token) { TokenType Lexer::type(const std::string &token) {
// TODO, FIXME 'one is evaluated as identifier // FIXME 'one is evaluated as identifier
if (token == ";") if (token == ";")
return TokenType::semicolon; return TokenType::semicolon;
if (token == "+") if (token == "+")

View File

@ -140,30 +140,31 @@ int main(int argc, char *argv[]) {
"create table a (i integer not null, s varchar(64), f float null, d date null, b boolean)", "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('one'), 'Y')",
"insert into a (i, s, b) values(1 + 10000, upper('one'), 'Y')", "insert into a (i, s, b) values(1 + 10000, upper('one'), 'Y')",
"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')", // "select to_string(i, '%d.%m.%Y %H:%M:%S'), i, s from a where i < to_date('20.12.2019', '%d.%m.%Y')",
"select i + 2, s, b from a where i >=1 order by 1 desc offset 0 limit 1", "select i + 2, i, s, b, f from a where i >=1 order by 1 desc offset 0 limit 1",
// "update table a set s = 'null string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'", // "update table a set s = 'null string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'",
"update table a set i = null", // "update table a set i = null",
"insert into a (i, s) values(2, 'two')", // "insert into a (i, s) values(2, 'two')",
"insert into a (i, s) values(3, 'two')", // "insert into a (i, s) values(3, 'two')",
"insert into a (i, s) values(4, lower('FOUR'))", // "insert into a (i, s) values(4, lower('FOUR'))",
"insert into a (i, s) values(5, 'five')", // "insert into a (i, s) values(5, 'five')",
"insert into a (i, s) values(to_date('20.12.1973', '%d.%m.%Y'), 'six')", // "insert into a (i, s) values(to_date('20.12.1973', '%d.%m.%Y'), 'six')",
// tohle zpusobi kresh "insert into a (i, d) values(6', '2006-10-04')", // tohle zpusobi kresh "insert into a (i, d) values(6', '2006-10-04')",
"insert into a (i, d) values(6, '2006-10-04')", // "insert into a (i, d) values(6, '2006-10-04')",
"save table a into '/tmp/a.csv'", // "save table a into '/tmp/a.csv'",
"select i, s from a where i > 2 order by 1 desc offset 1 limit 1", // "select i, s from a where i > 2 order by 1 desc offset 1 limit 1",
"select distinct s, d from a", // "select distinct s, d from a",
"select i, s from a where i = 1", // "select i, s from a where i = 1",
"select i, s from a where s = 'two'", // "select i, s from a where s = 'two'",
"select i, s from a where i <= 3 and s = 'one'", // "select i, s from a where i <= 3 and s = 'one'",
"select i, s from a where i > 0", // "select i, s from a where i > 0",
"delete from a where i = 4", // "delete from a where i = 4",
"select i, s from a where i > 0", // "select i, s from a where i > 0",
"update a set f = 9.99 where i = 3", // "update a set f = 9.99 where i = 3",
"select i, s, f from a where i = 3", // "select i, s, f from a where i = 3",
"update a set s = 'three', f = f + 0.01 where i = 3", // "update a set s = 'three', f = f + 0.01 where i = 3",
"select i, s, f from a where i = 3", // "select i, s, f from a where i = 3",
// "create table data (ticker varchar(8), price float null)", // "create table data (ticker varchar(8), price float null)",
// "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')", // "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')",
// "select ticker, price from data", // "select ticker, price from data",

View File

@ -47,7 +47,9 @@ namespace usql {
m_lexer.skipToken(TokenType::keyword_create); m_lexer.skipToken(TokenType::keyword_create);
m_lexer.skipToken(TokenType::keyword_table); m_lexer.skipToken(TokenType::keyword_table);
if (m_lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } if (m_lexer.tokenType() != TokenType::identifier)
throw Exception("syntax error, expecting identifier but found " + m_lexer.currentToken().token_string);
std::string table_name = m_lexer.consumeCurrentToken().token_string; std::string table_name = m_lexer.consumeCurrentToken().token_string;
// create as select // create as select
@ -111,7 +113,8 @@ namespace usql {
m_lexer.skipTokenOptional(TokenType::comma); m_lexer.skipTokenOptional(TokenType::comma);
// TODO in future constraints //constraints
//defaults
} while (m_lexer.tokenType() != TokenType::close_paren); } while (m_lexer.tokenType() != TokenType::close_paren);
return std::make_unique<CreateTableNode>(table_name, cols_def); return std::make_unique<CreateTableNode>(table_name, cols_def);
@ -155,9 +158,13 @@ namespace usql {
std::unique_ptr<Node> Parser::parse_set() { std::unique_ptr<Node> Parser::parse_set() {
m_lexer.skipToken(TokenType::keyword_set); m_lexer.skipToken(TokenType::keyword_set);
// TODO check these are string literals
if (m_lexer.currentToken().type!=TokenType::string_literal) throw Exception("Expecting literal in set name");
std::string name = m_lexer.consumeCurrentToken().token_string; std::string name = m_lexer.consumeCurrentToken().token_string;
m_lexer.skipTokenOptional(TokenType::equal); m_lexer.skipTokenOptional(TokenType::equal);
if (m_lexer.currentToken().type!=TokenType::string_literal) throw Exception("Expecting literal in set value");
std::string value = m_lexer.consumeCurrentToken().token_string; std::string value = m_lexer.consumeCurrentToken().token_string;
return std::make_unique<SetNode>(name, value); return std::make_unique<SetNode>(name, value);
@ -165,7 +172,8 @@ namespace usql {
std::unique_ptr<Node> Parser::parse_show() { std::unique_ptr<Node> Parser::parse_show() {
m_lexer.skipToken(TokenType::keyword_show); m_lexer.skipToken(TokenType::keyword_show);
// TODO check these are string literals
if (m_lexer.currentToken().type!=TokenType::string_literal) throw Exception("Expecting literal on show parameter name");
std::string name = m_lexer.consumeCurrentToken().token_string; std::string name = m_lexer.consumeCurrentToken().token_string;
return std::make_unique<ShowNode>(name); return std::make_unique<ShowNode>(name);
@ -179,13 +187,17 @@ namespace usql {
m_lexer.skipToken(TokenType::keyword_into); m_lexer.skipToken(TokenType::keyword_into);
// table name // table name
if (m_lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } if (m_lexer.tokenType() != TokenType::identifier)
throw Exception("syntax error, expecting identifier but found " + m_lexer.currentToken().token_string);
std::string table_name = m_lexer.consumeCurrentToken().token_string; std::string table_name = m_lexer.consumeCurrentToken().token_string;
// column names // column names
m_lexer.skipToken(TokenType::open_paren); m_lexer.skipToken(TokenType::open_paren);
do { do {
if (m_lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } if (m_lexer.tokenType() != TokenType::identifier)
throw Exception("syntax error, expecting identifier but found " + m_lexer.currentToken().token_string);
database_values.emplace_back(m_lexer.consumeCurrentToken().token_string); database_values.emplace_back(m_lexer.consumeCurrentToken().token_string);
m_lexer.skipTokenOptional(TokenType::comma); m_lexer.skipTokenOptional(TokenType::comma);

View File

@ -125,11 +125,11 @@ namespace usql {
bool isNull() override { return true; } bool isNull() override { return true; }
long getIntegerValue() override { throw Exception("not supported on null value"); }; long getIntegerValue() override { throw Exception("getIntegerValue not supported on NullValueNode"); };
double getDoubleValue() override { throw Exception("not supported on null value"); }; double getDoubleValue() override { throw Exception("getDoubleValue not supported on NullValueNode"); };
std::string getStringValue() override { throw Exception("not supported on null value"); }; std::string getStringValue() override { throw Exception("getStringValue not supported on NullValueNode"); };
long getDateValue() override { throw Exception("not supported on null value"); }; long getDateValue() override { throw Exception("getDateValue not supported on NullValueNode"); };
bool getBooleanValue() override { return false; }; bool getBooleanValue() override { throw Exception("getBooleanValue not supported on NullValueNode"); };
}; };
struct IntValueNode : ValueNode { struct IntValueNode : ValueNode {

49
row.cpp
View File

@ -8,7 +8,8 @@ namespace usql {
} }
int ColIntegerValue::compare(ColValue * other) { int ColIntegerValue::compare(ColValue * other) {
return other->isNull() ? 1 : m_integer - other->getIntValue(); // TODO implicit conversion from long to int long r = m_integer - other->getIntValue();
return other->isNull() ? 1 : r > 0 ? 1 : r == 0 ? 0 : -1;
} }
int ColDoubleValue::compare(ColValue * other) { int ColDoubleValue::compare(ColValue * other) {
@ -23,7 +24,8 @@ namespace usql {
} }
int ColDateValue::compare(ColValue * other) { int ColDateValue::compare(ColValue * other) {
return other->isNull() ? 1 : m_date - other->getIntValue(); // TODO implicit conversion from long to int long r = m_date - other->getIntValue();
return other->isNull() ? 1 : r > 0 ? 1 : r == 0 ? 0 : -1;
} }
int ColBooleanValue::compare(ColValue * other) { int ColBooleanValue::compare(ColValue * other) {
@ -41,27 +43,34 @@ namespace usql {
Row::Row(const Row &other) { Row::Row(const Row &other) {
m_columns.reserve(other.m_columns.size()); m_columns.reserve(other.m_columns.size());
// TODO fixme, here first set cols null and then immediately replace it // PERF here we first set cols null and then immediately replace it
for (int i = 0; i < other.m_columns.size(); i++) { for (int i = 0; i < other.m_columns.size(); i++) {
m_columns.push_back(std::make_unique<ColNullValue>()); m_columns.emplace_back(std::make_unique<ColNullValue>());
} }
// TODO get rid of dynamic_cast
for (int i = 0; i < other.m_columns.size(); i++) { for (int i = 0; i < other.m_columns.size(); i++) {
if (auto *other_v = dynamic_cast<ColIntegerValue *>(other.m_columns[i].get())) { if (other.m_columns[i]->isNull())
setIntColumnValue(i, other_v->getIntValue()); continue; // for null NOP
} else if (auto *other_v = dynamic_cast<ColDoubleValue *>(other.m_columns[i].get())) {
setFloatColumnValue(i, other_v->getDoubleValue()); ColumnType col_type = other.m_columns[i]->getColType();
} else if (auto *other_v = dynamic_cast<ColStringValue *>(other.m_columns[i].get())) { switch (col_type) {
setStringColumnValue(i, other_v->getStringValue()); case ColumnType::integer_type :
} else if (auto *other_v = dynamic_cast<ColDateValue *>(other.m_columns[i].get())) { setIntColumnValue(i, (static_cast<ColIntegerValue *>(other.m_columns[i].get())->getIntValue()));
setDateColumnValue(i, other_v->getDateValue()); break;
} else if (auto *other_v = dynamic_cast<ColBooleanValue *>(other.m_columns[i].get())) { case ColumnType::float_type :
setBoolColumnValue(i, other_v->getBoolValue()); setFloatColumnValue(i, (static_cast<ColDoubleValue *>(other.m_columns[i].get())->getDoubleValue()));
} else if (auto *other_v = dynamic_cast<ColNullValue *>(other.m_columns[i].get())) { break;
// NOP case ColumnType::varchar_type :
} else { setStringColumnValue(i, (static_cast<ColStringValue *>(other.m_columns[i].get())->getStringValue()));
throw Exception("unsupported data type"); break;
case ColumnType::date_type :
setDateColumnValue(i, (static_cast<ColDateValue *>(other.m_columns[i].get())->getDateValue()));
break;
case ColumnType::bool_type :
setBoolColumnValue(i, (static_cast<ColBooleanValue *>(other.m_columns[i].get())->getBoolValue()));
break;
default:
throw Exception("unsupported column type");
} }
} }
} }
@ -155,7 +164,7 @@ void Row::setColumnValue(ColDefNode *col_def, ValueNode *col_value) {
for (int ci = 0; ci < m_columns.size(); ci++) { for (int ci = 0; ci < m_columns.size(); ci++) {
auto value = m_columns[ci]->getStringValue(); auto value = m_columns[ci]->getStringValue();
// TODO use string functions handle len // TODO use rpad string function handle len
out.append(value + std::string(col_char_sizes[ci] - value.size(), ' ') + " | "); out.append(value + std::string(col_char_sizes[ci] - value.size(), ' ') + " | ");
} }

25
row.h
View File

@ -10,6 +10,7 @@ namespace usql {
struct ColValue { struct ColValue {
virtual bool isNull() { return false; }; virtual bool isNull() { return false; };
virtual ColumnType getColType() = 0;
virtual long getIntValue() = 0; virtual long getIntValue() = 0;
virtual double getDoubleValue() = 0; virtual double getDoubleValue() = 0;
virtual std::string getStringValue() = 0; virtual std::string getStringValue() = 0;
@ -25,11 +26,12 @@ namespace usql {
struct ColNullValue : ColValue { struct ColNullValue : ColValue {
bool isNull() override { return true; }; bool isNull() override { return true; };
long getIntValue() override { throw Exception("Not supported"); }; ColumnType getColType() override { throw Exception("getColType not supported on ColNullValue"); }
double getDoubleValue() override { throw Exception("Not supported"); }; long getIntValue() override { throw Exception("getIntValue not supported on ColNullValue"); };
double getDoubleValue() override { throw Exception("getDoubleValue not supported on ColNullValue"); };
std::string getStringValue() override { return "null"; }; std::string getStringValue() override { return "null"; };
long getDateValue() override { throw Exception("Not supported"); }; long getDateValue() override { throw Exception("getDateValue not supported on ColNullValue"); };
bool getBoolValue() override { throw Exception("Not supported"); }; bool getBoolValue() override { throw Exception("getDateValue not supported on ColNullValue"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
}; };
@ -39,11 +41,12 @@ namespace usql {
ColIntegerValue(long value) : m_integer(value) {}; ColIntegerValue(long value) : m_integer(value) {};
ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {}; ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {};
ColumnType getColType() override { return ColumnType::integer_type; };
long getIntValue() override { return m_integer; }; long getIntValue() override { return m_integer; };
double getDoubleValue() override { return (double) m_integer; }; double getDoubleValue() override { return (double) m_integer; };
std::string getStringValue() override { return std::to_string(m_integer); }; std::string getStringValue() override { return std::to_string(m_integer); };
long getDateValue() override { return m_integer; }; long getDateValue() override { return m_integer; };
bool getBoolValue() override { throw Exception("Not supported"); }; bool getBoolValue() override { throw Exception("Not supported on ColIntegerValue"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
@ -55,11 +58,12 @@ namespace usql {
ColDoubleValue(double value) : m_double(value) {}; ColDoubleValue(double value) : m_double(value) {};
ColDoubleValue(const ColDoubleValue &other) : m_double(other.m_double) {} ColDoubleValue(const ColDoubleValue &other) : m_double(other.m_double) {}
ColumnType getColType() override { return ColumnType::float_type; };
long getIntValue() override { return (long) m_double; }; long getIntValue() override { return (long) m_double; };
double getDoubleValue() override { return m_double; }; double getDoubleValue() override { return m_double; };
std::string getStringValue() override { return std::to_string(m_double); }; std::string getStringValue() override { return std::to_string(m_double); };
long getDateValue() override { return (long) m_double; }; long getDateValue() override { return (long) m_double; };
bool getBoolValue() override { throw Exception("Not supported"); }; bool getBoolValue() override { throw Exception("Not supported on ColDoubleValue"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
@ -71,11 +75,12 @@ namespace usql {
ColStringValue(const std::string &value) : m_string(value) {}; ColStringValue(const std::string &value) : m_string(value) {};
ColStringValue(const ColStringValue &other) : m_string(other.m_string) {}; ColStringValue(const ColStringValue &other) : m_string(other.m_string) {};
ColumnType getColType() override { return ColumnType::varchar_type; };
long getIntValue() override { return std::stoi(m_string); }; long getIntValue() override { return std::stoi(m_string); };
double getDoubleValue() override { return std::stod(m_string); }; double getDoubleValue() override { return std::stod(m_string); };
std::string getStringValue() override { return m_string; }; std::string getStringValue() override { return m_string; };
long getDateValue() override { return std::stoi(m_string); }; long getDateValue() override { return std::stoi(m_string); };
bool getBoolValue() override { throw Exception("Not supported"); }; bool getBoolValue() override { throw Exception("Not supported on ColStringValue"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
@ -86,11 +91,12 @@ namespace usql {
ColDateValue(long value) : m_date(value) {}; ColDateValue(long value) : m_date(value) {};
ColDateValue(const ColDateValue &other) : m_date(other.m_date) {}; ColDateValue(const ColDateValue &other) : m_date(other.m_date) {};
ColumnType getColType() override { return ColumnType::date_type; };
long getIntValue() override { return m_date; }; long getIntValue() override { return m_date; };
double getDoubleValue() override { return (double) m_date; }; double getDoubleValue() override { return (double) m_date; };
std::string getStringValue() override { return Settings::date_to_string(m_date); }; std::string getStringValue() override { return Settings::date_to_string(m_date); };
long getDateValue() override { return m_date; }; long getDateValue() override { return m_date; };
bool getBoolValue() override { throw Exception("Not supported"); }; bool getBoolValue() override { throw Exception("Not supported on ColDateValue"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
@ -101,10 +107,11 @@ namespace usql {
ColBooleanValue(bool value) : m_bool(value) {}; ColBooleanValue(bool value) : m_bool(value) {};
ColBooleanValue(const ColBooleanValue &other) : m_bool(other.m_bool) {}; ColBooleanValue(const ColBooleanValue &other) : m_bool(other.m_bool) {};
ColumnType getColType() override { return ColumnType::bool_type; };
long getIntValue() override { return (long) m_bool; }; long getIntValue() override { return (long) m_bool; };
double getDoubleValue() override { return (double) m_bool; }; double getDoubleValue() override { return (double) m_bool; };
std::string getStringValue() override { return m_bool ? "Y" : "N"; }; std::string getStringValue() override { return m_bool ? "Y" : "N"; };
long getDateValue() override { throw Exception("Not supported"); }; long getDateValue() override { throw Exception("Not supported on ColBooleanValue"); };
bool getBoolValue() override { return m_bool; }; bool getBoolValue() override { return m_bool; };
int compare(ColValue * other) override; int compare(ColValue * other) override;

View File

@ -236,7 +236,8 @@ void USql::execute_order_by(SelectFromTableNode &node, Table *table, Table *resu
auto compare_rows = [&node, &result](const Row &a, const Row &b) { auto compare_rows = [&node, &result](const Row &a, const Row &b) {
for(const auto& order_by_col_def : node.order_by) { for(const auto& order_by_col_def : node.order_by) {
ColDefNode col_def = result->get_column_def(order_by_col_def.col_index - 1); // TODO validate index // TODO validate index
ColDefNode col_def = result->get_column_def(order_by_col_def.col_index - 1);
ColValue *a_val = a.ith_column(col_def.order); ColValue *a_val = a.ith_column(col_def.order);
ColValue *b_val = b.ith_column(col_def.order); ColValue *b_val = b.ith_column(col_def.order);
@ -282,6 +283,7 @@ std::tuple<int, ColDefNode> USql::get_column_definition(Table *table, SelectColN
} else if (select_col_node->value->node_type == NodeType::arithmetical_operator) { } else if (select_col_node->value->node_type == NodeType::arithmetical_operator) {
// TODO return correct type // TODO return correct type
// hierarchicaly go throuhg and deduce right type
ColDefNode cdef = ColDefNode{new_col_name, ColumnType::float_type, col_order, 1, true}; ColDefNode cdef = ColDefNode{new_col_name, ColumnType::float_type, col_order, 1, true};
return std::make_tuple(-1, cdef); return std::make_tuple(-1, cdef);
} }
@ -289,6 +291,7 @@ std::tuple<int, ColDefNode> USql::get_column_definition(Table *table, SelectColN
} }
std::unique_ptr<Table> USql::execute_delete(DeleteFromTableNode &node) { std::unique_ptr<Table> USql::execute_delete(DeleteFromTableNode &node) {
// find source table // find source table
Table *table = find_table(node.table_name); Table *table = find_table(node.table_name);
@ -318,7 +321,8 @@ std::unique_ptr<Table> USql::execute_update(UpdateTableNode &node) {
if (eval_where(node.where.get(), table, *row)) { if (eval_where(node.where.get(), table, *row)) {
int i = 0; int i = 0;
for (const auto& col : node.cols_names) { for (const auto& col : node.cols_names) {
ColDefNode col_def = table->get_column_def(col.col_name); // TODO cache it like in select // TODO cache it like in select
ColDefNode col_def = table->get_column_def(col.col_name);
std::unique_ptr<ValueNode> new_val = eval_arithmetic_operator(col_def.type, std::unique_ptr<ValueNode> new_val = eval_arithmetic_operator(col_def.type,
static_cast<ArithmeticalOperatorNode &>(*node.values[i]), static_cast<ArithmeticalOperatorNode &>(*node.values[i]),
table, *row); table, *row);
@ -372,7 +376,7 @@ bool USql::eval_relational_operator(const RelationalOperatorNode &filter, Table
comparator = bl == br ? 0 : 1; // TODO define it comparator = bl == br ? 0 : 1; // TODO define it
// TODO handle dates // TODO handle dates
} else { } else {
// TODO throw exception throw Exception("Undefined combination of types");
} }
switch (filter.op) { switch (filter.op) {
@ -416,6 +420,9 @@ std::unique_ptr<ValueNode> USql::eval_database_value_node(Table *table, Row &row
ColDefNode col_def = table->get_column_def( dvl->col_name); // TODO optimize it to just get this def once ColDefNode col_def = table->get_column_def( dvl->col_name); // TODO optimize it to just get this def once
auto db_value = row.ith_column(col_def.order); auto db_value = row.ith_column(col_def.order);
if (db_value->isNull())
return std::make_unique<NullValueNode>();
if (col_def.type == ColumnType::integer_type) if (col_def.type == ColumnType::integer_type)
return std::make_unique<IntValueNode>(db_value->getIntValue()); return std::make_unique<IntValueNode>(db_value->getIntValue());
if (col_def.type == ColumnType::float_type) if (col_def.type == ColumnType::float_type)
@ -513,6 +520,9 @@ std::unique_ptr<ValueNode> USql::eval_arithmetic_operator(ColumnType outType, Ar
std::unique_ptr<ValueNode> left = eval_value_node(table, row, node.left.get()); std::unique_ptr<ValueNode> left = eval_value_node(table, row, node.left.get());
std::unique_ptr<ValueNode> right = eval_value_node(table, row, node.right.get()); std::unique_ptr<ValueNode> right = eval_value_node(table, row, node.right.get());
if (left->isNull() || right->isNull())
return std::make_unique<NullValueNode>();
if (outType == ColumnType::float_type) { if (outType == ColumnType::float_type) {
double l = ((ValueNode *) left.get())->getDoubleValue(); double l = ((ValueNode *) left.get())->getDoubleValue();
double r = ((ValueNode *) right.get())->getDoubleValue(); double r = ((ValueNode *) right.get())->getDoubleValue();