some TODOs removed..
This commit is contained in:
parent
6921421a65
commit
4665705c3d
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
### TODO
|
||||
- better support for values in update and insert
|
||||
- date functions - now, add_date...
|
||||
- string functions rtrim, ltrim, rpad, lpad
|
||||
- add pipe | concatenation
|
||||
|
|
@ -9,7 +8,5 @@
|
|||
- support for uniqueue indexes (primary key)
|
||||
- support for btree indexes
|
||||
- add count min and max functions, eg aggregate functions
|
||||
- support for parenthesis
|
||||
- class members should have prefix m_
|
||||
- add const wherever should be
|
||||
- PERF in Row::Row(const Row &other), could be more efficient (memory and cpu)
|
||||
|
|
|
|||
15
lexer.cpp
15
lexer.cpp
|
|
@ -22,16 +22,15 @@ namespace usql {
|
|||
}
|
||||
|
||||
void Lexer::parse(const std::string &code) {
|
||||
// TODO handle empty code
|
||||
m_tokens.clear();
|
||||
if (code.empty())
|
||||
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;
|
||||
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);
|
||||
|
|
@ -116,7 +115,7 @@ namespace usql {
|
|||
}
|
||||
|
||||
TokenType Lexer::type(const std::string &token) {
|
||||
// TODO, FIXME 'one is evaluated as identifier
|
||||
// FIXME 'one is evaluated as identifier
|
||||
if (token == ";")
|
||||
return TokenType::semicolon;
|
||||
if (token == "+")
|
||||
|
|
|
|||
43
main.cpp
43
main.cpp
|
|
@ -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)",
|
||||
"insert into a (i, s, b) values(1, 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 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 i = null",
|
||||
"insert into a (i, s) values(2, 'two')",
|
||||
"insert into a (i, s) values(3, 'two')",
|
||||
"insert into a (i, s) values(4, lower('FOUR'))",
|
||||
"insert into a (i, s) values(5, 'five')",
|
||||
"insert into a (i, s) values(to_date('20.12.1973', '%d.%m.%Y'), 'six')",
|
||||
// "update table a set i = null",
|
||||
// "insert into a (i, s) values(2, 'two')",
|
||||
// "insert into a (i, s) values(3, 'two')",
|
||||
// "insert into a (i, s) values(4, lower('FOUR'))",
|
||||
// "insert into a (i, s) values(5, 'five')",
|
||||
// "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')",
|
||||
"insert into a (i, d) values(6, '2006-10-04')",
|
||||
"save table a into '/tmp/a.csv'",
|
||||
"select i, s from a where i > 2 order by 1 desc offset 1 limit 1",
|
||||
"select distinct s, d from a",
|
||||
"select i, s from a where i = 1",
|
||||
"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 > 0",
|
||||
"delete from a where i = 4",
|
||||
"select i, s from a where i > 0",
|
||||
"update a set f = 9.99 where i = 3",
|
||||
"select i, s, f from a where i = 3",
|
||||
"update a set s = 'three', f = f + 0.01 where i = 3",
|
||||
"select i, s, f from a where i = 3",
|
||||
// "insert into a (i, d) values(6, '2006-10-04')",
|
||||
// "save table a into '/tmp/a.csv'",
|
||||
// "select i, s from a where i > 2 order by 1 desc offset 1 limit 1",
|
||||
// "select distinct s, d from a",
|
||||
// "select i, s from a where i = 1",
|
||||
// "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 > 0",
|
||||
// "delete from a where i = 4",
|
||||
// "select i, s from a where i > 0",
|
||||
// "update a set f = 9.99 where i = 3",
|
||||
// "select i, s, f from a where i = 3",
|
||||
// "update a set s = 'three', f = f + 0.01 where i = 3",
|
||||
// "select i, s, f from a where i = 3",
|
||||
// "create table data (ticker varchar(8), price float null)",
|
||||
// "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')",
|
||||
// "select ticker, price from data",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ std::string date_to_string(const long datetime, const std::string format) {
|
|||
return result;
|
||||
}
|
||||
// TODO exception here
|
||||
return "invalid argument";
|
||||
return "invalid argument";
|
||||
}
|
||||
|
||||
long string_to_date(const std::string &datestr, const std::string &format) {
|
||||
|
|
|
|||
24
parser.cpp
24
parser.cpp
|
|
@ -47,7 +47,9 @@ namespace usql {
|
|||
m_lexer.skipToken(TokenType::keyword_create);
|
||||
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;
|
||||
|
||||
// create as select
|
||||
|
|
@ -111,7 +113,8 @@ namespace usql {
|
|||
|
||||
m_lexer.skipTokenOptional(TokenType::comma);
|
||||
|
||||
// TODO in future constraints
|
||||
//constraints
|
||||
//defaults
|
||||
} while (m_lexer.tokenType() != TokenType::close_paren);
|
||||
|
||||
return std::make_unique<CreateTableNode>(table_name, cols_def);
|
||||
|
|
@ -155,9 +158,13 @@ namespace usql {
|
|||
|
||||
std::unique_ptr<Node> Parser::parse_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;
|
||||
|
||||
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;
|
||||
|
||||
return std::make_unique<SetNode>(name, value);
|
||||
|
|
@ -165,7 +172,8 @@ namespace usql {
|
|||
|
||||
std::unique_ptr<Node> Parser::parse_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;
|
||||
|
||||
return std::make_unique<ShowNode>(name);
|
||||
|
|
@ -179,13 +187,17 @@ namespace usql {
|
|||
m_lexer.skipToken(TokenType::keyword_into);
|
||||
|
||||
// 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;
|
||||
|
||||
// column names
|
||||
m_lexer.skipToken(TokenType::open_paren);
|
||||
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);
|
||||
|
||||
m_lexer.skipTokenOptional(TokenType::comma);
|
||||
|
|
|
|||
10
parser.h
10
parser.h
|
|
@ -125,11 +125,11 @@ namespace usql {
|
|||
|
||||
bool isNull() override { return true; }
|
||||
|
||||
long getIntegerValue() override { throw Exception("not supported on null value"); };
|
||||
double getDoubleValue() override { throw Exception("not supported on null value"); };
|
||||
std::string getStringValue() override { throw Exception("not supported on null value"); };
|
||||
long getDateValue() override { throw Exception("not supported on null value"); };
|
||||
bool getBooleanValue() override { return false; };
|
||||
long getIntegerValue() override { throw Exception("getIntegerValue not supported on NullValueNode"); };
|
||||
double getDoubleValue() override { throw Exception("getDoubleValue not supported on NullValueNode"); };
|
||||
std::string getStringValue() override { throw Exception("getStringValue not supported on NullValueNode"); };
|
||||
long getDateValue() override { throw Exception("getDateValue not supported on NullValueNode"); };
|
||||
bool getBooleanValue() override { throw Exception("getBooleanValue not supported on NullValueNode"); };
|
||||
};
|
||||
|
||||
struct IntValueNode : ValueNode {
|
||||
|
|
|
|||
51
row.cpp
51
row.cpp
|
|
@ -8,7 +8,8 @@ namespace usql {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -23,7 +24,8 @@ namespace usql {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -41,28 +43,35 @@ namespace usql {
|
|||
|
||||
Row::Row(const Row &other) {
|
||||
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++) {
|
||||
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++) {
|
||||
if (auto *other_v = dynamic_cast<ColIntegerValue *>(other.m_columns[i].get())) {
|
||||
setIntColumnValue(i, other_v->getIntValue());
|
||||
} else if (auto *other_v = dynamic_cast<ColDoubleValue *>(other.m_columns[i].get())) {
|
||||
setFloatColumnValue(i, other_v->getDoubleValue());
|
||||
} else if (auto *other_v = dynamic_cast<ColStringValue *>(other.m_columns[i].get())) {
|
||||
setStringColumnValue(i, other_v->getStringValue());
|
||||
} else if (auto *other_v = dynamic_cast<ColDateValue *>(other.m_columns[i].get())) {
|
||||
setDateColumnValue(i, other_v->getDateValue());
|
||||
} else if (auto *other_v = dynamic_cast<ColBooleanValue *>(other.m_columns[i].get())) {
|
||||
setBoolColumnValue(i, other_v->getBoolValue());
|
||||
} else if (auto *other_v = dynamic_cast<ColNullValue *>(other.m_columns[i].get())) {
|
||||
// NOP
|
||||
} else {
|
||||
throw Exception("unsupported data type");
|
||||
}
|
||||
if (other.m_columns[i]->isNull())
|
||||
continue; // for null NOP
|
||||
|
||||
ColumnType col_type = other.m_columns[i]->getColType();
|
||||
switch (col_type) {
|
||||
case ColumnType::integer_type :
|
||||
setIntColumnValue(i, (static_cast<ColIntegerValue *>(other.m_columns[i].get())->getIntValue()));
|
||||
break;
|
||||
case ColumnType::float_type :
|
||||
setFloatColumnValue(i, (static_cast<ColDoubleValue *>(other.m_columns[i].get())->getDoubleValue()));
|
||||
break;
|
||||
case ColumnType::varchar_type :
|
||||
setStringColumnValue(i, (static_cast<ColStringValue *>(other.m_columns[i].get())->getStringValue()));
|
||||
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++) {
|
||||
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(), ' ') + " | ");
|
||||
}
|
||||
|
||||
|
|
|
|||
25
row.h
25
row.h
|
|
@ -10,6 +10,7 @@ namespace usql {
|
|||
|
||||
struct ColValue {
|
||||
virtual bool isNull() { return false; };
|
||||
virtual ColumnType getColType() = 0;
|
||||
virtual long getIntValue() = 0;
|
||||
virtual double getDoubleValue() = 0;
|
||||
virtual std::string getStringValue() = 0;
|
||||
|
|
@ -25,11 +26,12 @@ namespace usql {
|
|||
|
||||
struct ColNullValue : ColValue {
|
||||
bool isNull() override { return true; };
|
||||
long getIntValue() override { throw Exception("Not supported"); };
|
||||
double getDoubleValue() override { throw Exception("Not supported"); };
|
||||
ColumnType getColType() override { throw Exception("getColType not supported on ColNullValue"); }
|
||||
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"; };
|
||||
long getDateValue() override { throw Exception("Not supported"); };
|
||||
bool getBoolValue() override { throw Exception("Not supported"); };
|
||||
long getDateValue() override { throw Exception("getDateValue not supported on ColNullValue"); };
|
||||
bool getBoolValue() override { throw Exception("getDateValue not supported on ColNullValue"); };
|
||||
|
||||
int compare(ColValue * other) override;
|
||||
};
|
||||
|
|
@ -39,11 +41,12 @@ namespace usql {
|
|||
ColIntegerValue(long value) : m_integer(value) {};
|
||||
ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {};
|
||||
|
||||
ColumnType getColType() override { return ColumnType::integer_type; };
|
||||
long getIntValue() override { return m_integer; };
|
||||
double getDoubleValue() override { return (double) m_integer; };
|
||||
std::string getStringValue() override { return std::to_string(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;
|
||||
|
||||
|
|
@ -55,11 +58,12 @@ namespace usql {
|
|||
ColDoubleValue(double value) : m_double(value) {};
|
||||
ColDoubleValue(const ColDoubleValue &other) : m_double(other.m_double) {}
|
||||
|
||||
ColumnType getColType() override { return ColumnType::float_type; };
|
||||
long getIntValue() override { return (long) m_double; };
|
||||
double getDoubleValue() override { return m_double; };
|
||||
std::string getStringValue() override { return std::to_string(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;
|
||||
|
||||
|
|
@ -71,11 +75,12 @@ namespace usql {
|
|||
ColStringValue(const std::string &value) : m_string(value) {};
|
||||
ColStringValue(const ColStringValue &other) : m_string(other.m_string) {};
|
||||
|
||||
ColumnType getColType() override { return ColumnType::varchar_type; };
|
||||
long getIntValue() override { return std::stoi(m_string); };
|
||||
double getDoubleValue() override { return std::stod(m_string); };
|
||||
std::string getStringValue() override { return 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;
|
||||
|
||||
|
|
@ -86,11 +91,12 @@ namespace usql {
|
|||
ColDateValue(long value) : m_date(value) {};
|
||||
ColDateValue(const ColDateValue &other) : m_date(other.m_date) {};
|
||||
|
||||
ColumnType getColType() override { return ColumnType::date_type; };
|
||||
long getIntValue() override { return m_date; };
|
||||
double getDoubleValue() override { return (double) m_date; };
|
||||
std::string getStringValue() override { return Settings::date_to_string(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;
|
||||
|
||||
|
|
@ -101,10 +107,11 @@ namespace usql {
|
|||
ColBooleanValue(bool value) : m_bool(value) {};
|
||||
ColBooleanValue(const ColBooleanValue &other) : m_bool(other.m_bool) {};
|
||||
|
||||
ColumnType getColType() override { return ColumnType::bool_type; };
|
||||
long getIntValue() override { return (long) m_bool; };
|
||||
double getDoubleValue() override { return (double) m_bool; };
|
||||
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; };
|
||||
|
||||
int compare(ColValue * other) override;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ std::string Table::csv_string() {
|
|||
|
||||
auto col = m_row.ith_column(i);
|
||||
if (!col->isNull()) {
|
||||
csv_line += col->getStringValue(); // TODO handle enclosing commas etc
|
||||
csv_line += col->getStringValue(); // TODO handle enclosing commas etc
|
||||
}
|
||||
}
|
||||
out_string += csv_line;
|
||||
|
|
|
|||
16
usql.cpp
16
usql.cpp
|
|
@ -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) {
|
||||
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 *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) {
|
||||
// TODO return correct type
|
||||
// hierarchicaly go throuhg and deduce right type
|
||||
ColDefNode cdef = ColDefNode{new_col_name, ColumnType::float_type, col_order, 1, true};
|
||||
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) {
|
||||
// find source table
|
||||
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)) {
|
||||
int i = 0;
|
||||
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,
|
||||
static_cast<ArithmeticalOperatorNode &>(*node.values[i]),
|
||||
table, *row);
|
||||
|
|
@ -372,7 +376,7 @@ bool USql::eval_relational_operator(const RelationalOperatorNode &filter, Table
|
|||
comparator = bl == br ? 0 : 1; // TODO define it
|
||||
// TODO handle dates
|
||||
} else {
|
||||
// TODO throw exception
|
||||
throw Exception("Undefined combination of types");
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
return std::make_unique<IntValueNode>(db_value->getIntValue());
|
||||
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> right = eval_value_node(table, row, node.right.get());
|
||||
|
||||
if (left->isNull() || right->isNull())
|
||||
return std::make_unique<NullValueNode>();
|
||||
|
||||
if (outType == ColumnType::float_type) {
|
||||
double l = ((ValueNode *) left.get())->getDoubleValue();
|
||||
double r = ((ValueNode *) right.get())->getDoubleValue();
|
||||
|
|
|
|||
Loading…
Reference in New Issue