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
- 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)

View File

@ -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 == "+")

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)",
"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",

View File

@ -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) {

View File

@ -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);

View File

@ -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
View File

@ -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
View File

@ -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;

View File

@ -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;

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) {
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();