date and boolean data types added

This commit is contained in:
VaclavT 2021-08-06 22:46:48 +02:00
parent 4b95be1e31
commit 15a065c2aa
17 changed files with 1123 additions and 907 deletions

View File

@ -14,7 +14,7 @@ set(PROJECT_NAME usql)
include_directories(${CMAKE_SOURCE_DIR}/clib ${CMAKE_SOURCE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/clib ${CMAKE_SOURCE_DIR})
set(SOURCE set(SOURCE
exception.cpp lexer.cpp parser.cpp usql.cpp main.cpp table.cpp table.h row.cpp row.h csvreader.cpp csvreader.h ml_date.cpp clib/ml_string.cpp clib/linenoise.c) exception.cpp lexer.cpp parser.cpp usql.cpp main.cpp table.cpp table.h row.cpp row.h csvreader.cpp csvreader.h ml_date.cpp settings.cpp clib/ml_string.cpp clib/linenoise.c)
add_executable(${PROJECT_NAME} ${SOURCE}) add_executable(${PROJECT_NAME} ${SOURCE})

View File

@ -1,15 +1,16 @@
### TODO ### TODO
- support for *
- add support for set setting value
- command line interface - command line interface
- date functions - now, add_date...
- support for order by, offset, limit (allow column name in order by, validate) - support for order by, offset, limit (allow column name in order by, validate)
- add count min and max functions, eg aggregate functions - add count min and max functions, eg aggregate functions
- support for uniqueue indexes - support for uniqueue indexes (primary key)
- support for btree indexes - support for btree indexes
- support for parenthesis - support for parenthesis
- functions rtrim, ltrim, rpad, lpad - functions rtrim, ltrim, rpad, lpad
- support for *
- add pipe | token - add pipe | token
- maybe to create iterator on table - maybe to create iterator on table
- add exceptions and rename it to UsqlException
- class members should have prefix m_ - class members should have prefix m_
- add const wherever should be - add const wherever should be

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ namespace usql {
std::string field; std::string field;
std::vector<std::vector<std::string>> parsed_data; std::vector<std::vector<std::string>> parsed_data;
parsed_data.reserve(128); parsed_data.reserve(256);
std::vector<std::string> line; std::vector<std::string> line;
line.reserve(32); line.reserve(32);

View File

@ -45,7 +45,7 @@ namespace usql {
match_str = stringLiteral(match_str); match_str = stringLiteral(match_str);
if (token_type != TokenType::newline) if (token_type != TokenType::newline)
m_tokens.push_back(Token{match_str, token_type}); m_tokens.emplace_back(match_str, token_type);
} }
// DEBUG IT // DEBUG IT
@ -56,8 +56,8 @@ namespace usql {
void Lexer::debugTokens() { void Lexer::debugTokens() {
int i = 0; int i = 0;
for (std::vector<Token>::iterator it = m_tokens.begin(); it != m_tokens.end(); ++it) { for (auto & m_token : m_tokens) {
std::cerr << i << "\t" << it->token_string << std::endl; std::cerr << i << "\t" << m_token.token_string << std::endl;
i++; i++;
} }
} }
@ -197,6 +197,10 @@ namespace usql {
return TokenType::keyword_float; return TokenType::keyword_float;
if (token == "varchar") if (token == "varchar")
return TokenType::keyword_varchar; return TokenType::keyword_varchar;
if (token == "date")
return TokenType::keyword_date;
if (token == "boolean")
return TokenType::keyword_bool;
if (token == "distinct") if (token == "distinct")
return TokenType::keyword_distinct; return TokenType::keyword_distinct;
if (token == "or") if (token == "or")
@ -244,7 +248,7 @@ namespace usql {
if (!replace) { if (!replace) {
return str; return str;
} }
std::string out = ""; std::string out;
out.reserve(str.size()); out.reserve(str.size());
@ -384,6 +388,12 @@ namespace usql {
case TokenType::keyword_varchar: case TokenType::keyword_varchar:
txt = "varchar"; txt = "varchar";
break; break;
case TokenType::keyword_date:
txt = "date";
break;
case TokenType::keyword_bool:
txt = "boolean";
break;
case TokenType::keyword_distinct: case TokenType::keyword_distinct:
txt = "distinct"; txt = "distinct";
break; break;

View File

@ -47,6 +47,8 @@ namespace usql {
keyword_integer, keyword_integer,
keyword_float, keyword_float,
keyword_varchar, keyword_varchar,
keyword_date,
keyword_bool,
keyword_distinct, keyword_distinct,
int_number, int_number,
double_number, double_number,
@ -103,7 +105,7 @@ namespace usql {
private: private:
TokenType type(const std::string &token); TokenType type(const std::string &token);
std::string stringLiteral(std::string token); static std::string stringLiteral(std::string token);
static std::string typeToString(TokenType token_type); static std::string typeToString(TokenType token_type);

View File

@ -126,23 +126,31 @@ void repl() {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::vector<std::string> sql_commands{ std::vector<std::string> sql_commands{
"create table a (i integer not null, s varchar(64), f float null)", // boolean datatype "create table ticker ( tablee varchar(3) not null, permaticker integer, ticker varchar(8) not null, name varchar(256) not null, exchange varchar(32), isdelisted boolean, category varchar(32), cusips varchar(256), siccode integer, sicsector varchar(256), sicindustry varchar(256), famasector varchar(256), famaindustry varchar(256), sector varchar(128), industry varchar(128), scalemarketcap varchar(64), scalerevenue varchar(64), relatedtickers varchar(128), currency varchar(3), location varchar(64), lastupdated date, firstadded date, firstpricedate date, lastpricedate date, firstquarter date, lastquarter date, secfilings varchar(256), companysite varchar(256))"
"insert into a (i, s) values(1, upper('one'))", "create table ticker ( tablee varchar(5) not null, permaticker integer, ticker varchar(10) not null, name varchar(256) not null, exchange varchar(32), isdelisted boolean, category varchar(32), cusips varchar(256), siccode integer, sicsector varchar(256), sicindustry varchar(256), famasector varchar(256), famaindustry varchar(256), sector varchar(128), industry varchar(128), scalemarketcap varchar(64), scalerevenue varchar(64), relatedtickers varchar(128), currency varchar(3), location varchar(64), lastupdated date, firstadded date, firstpricedate date, lastpricedate date, firstquarter date, lastquarter date, secfilings varchar(256), companysite varchar(256))",
"load ticker from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/tickers.csv')",
"select permaticker, ticker, name from ticker where ticker = 'WFC'"
// "select * from ticker limit 5"
// "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')",
// "select i, s, b 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')",
"save table a into '/tmp/a.csv'", // tohle zpusobi kresh "insert into a (i, d) values(6', '2006-10-04')",
"select i, s from a where i > 2 order by 1 desc offset 1 limit 1", // "insert into a (i, d) values(6, '2006-10-04')",
"select distinct s from a", // "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 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",
@ -157,10 +165,10 @@ int main(int argc, char *argv[]) {
// "drop table x", // "drop table x",
// "select i, s, f from a where i > 300", // "select i, s, f from a where i > 300",
// "select i, to_string(i, '%d.%m.%Y'), s, f from a where i > 300", // "select i, to_string(i, '%d.%m.%Y'), s, f from a where i > 300",
"create table prices (datetime integer, symbol varchar(8), prev_close float, open float, price float, change float, change_prct varchar(16))", // "create table prices (datetime integer, symbol varchar(8), prev_close float, open float, price float, change float, change_prct varchar(16))",
"load prices from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/prices.csv'", // "load prices from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/prices.csv'",
// "insert into prices (datetime, symbol, prev_close, open, price, change, change_prct) values (1626979443, 'MPC', 54.08, 53.82, 53.63, -0.832101, '-0.83 %')", // "insert into prices (datetime, symbol, prev_close, open, price, change, change_prct) values (1626979443, 'MPC', 54.08, 53.82, 53.63, -0.832101, '-0.83 %')",
"select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct, datetime from prices where symbol = 'SYF' order by 8 desc limit 10" // "select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct, datetime from prices where symbol = 'SYF' order by 8 desc limit 10"
}; };

View File

@ -56,8 +56,8 @@ namespace usql {
do { do {
std::string column_name; std::string column_name;
ColumnType column_type; ColumnType column_type;
int column_len{1}; int column_len = 1;
bool column_nullable{true}; bool column_nullable = true;
// column name // column name
if (m_lexer.tokenType() != TokenType::identifier) { if (m_lexer.tokenType() != TokenType::identifier) {
@ -82,8 +82,14 @@ namespace usql {
throw Exception("syntax error, expected int number"); throw Exception("syntax error, expected int number");
} }
m_lexer.skipToken(TokenType::close_paren); m_lexer.skipToken(TokenType::close_paren);
} else if (m_lexer.tokenType() == TokenType::keyword_date) {
column_type = ColumnType::date_type;
m_lexer.nextToken();
} else if (m_lexer.tokenType() == TokenType::keyword_bool) {
column_type = ColumnType::bool_type;
m_lexer.nextToken();
} else { } else {
throw Exception("syntax error, column type expected"); throw Exception("syntax error, column type expected, found " + m_lexer.currentToken().token_string);
} }
if (m_lexer.tokenType() == TokenType::keyword_not) { if (m_lexer.tokenType() == TokenType::keyword_not) {
@ -94,7 +100,7 @@ namespace usql {
m_lexer.nextToken(); m_lexer.nextToken();
} }
cols_def.push_back( ColDefNode(column_name, column_type, column_order++, column_len, column_nullable)); cols_def.emplace_back(column_name, column_type, column_order++, column_len, column_nullable);
m_lexer.skipTokenOptional(TokenType::comma); m_lexer.skipTokenOptional(TokenType::comma);
@ -155,7 +161,7 @@ namespace usql {
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) { /* TODO handle error */ }
column_names.push_back(m_lexer.consumeCurrentToken().token_string); column_names.emplace_back(m_lexer.consumeCurrentToken().token_string);
m_lexer.skipTokenOptional(TokenType::comma); m_lexer.skipTokenOptional(TokenType::comma);
} while (m_lexer.tokenType() != TokenType::close_paren); } while (m_lexer.tokenType() != TokenType::close_paren);
@ -272,7 +278,7 @@ namespace usql {
std::vector<std::unique_ptr<Node>> values; std::vector<std::unique_ptr<Node>> values;
do { do {
cols_names.push_back(m_lexer.consumeCurrentToken().token_string); cols_names.emplace_back(m_lexer.consumeCurrentToken().token_string);
m_lexer.skipToken(TokenType::equal); m_lexer.skipToken(TokenType::equal);
std::unique_ptr<Node> left = Parser::parse_operand_node(); std::unique_ptr<Node> left = Parser::parse_operand_node();
@ -332,9 +338,9 @@ namespace usql {
auto token_type = m_lexer.tokenType(); auto token_type = m_lexer.tokenType();
std::string tokenString = m_lexer.consumeCurrentToken().token_string; std::string tokenString = m_lexer.consumeCurrentToken().token_string;
switch (token_type) { switch (token_type) {
case TokenType::int_number: case TokenType::int_number:
col_index = std::stoi(tokenString); col_index = std::stoi(tokenString);
break; break;
default: default:
throw Exception("column index allowed in order by clause at this moment"); throw Exception("column index allowed in order by clause at this moment");
} }
@ -346,7 +352,7 @@ namespace usql {
asc = false; asc = false;
} }
order_cols.push_back(ColOrderNode{col_index, asc}); order_cols.emplace_back(col_index, asc);
m_lexer.skipTokenOptional(TokenType::comma); m_lexer.skipTokenOptional(TokenType::comma);

View File

@ -2,8 +2,10 @@
#include "lexer.h" #include "lexer.h"
#include "exception.h" #include "exception.h"
#include <string> #include "ml_date.h"
#include "settings.h"
#include <string>
#include <vector> #include <vector>
namespace usql { namespace usql {
@ -11,7 +13,9 @@ namespace usql {
enum class ColumnType { enum class ColumnType {
integer_type, integer_type,
float_type, float_type,
varchar_type varchar_type,
date_type,
bool_type
}; };
enum class NodeType { enum class NodeType {
@ -20,6 +24,7 @@ namespace usql {
int_value, int_value,
float_value, float_value,
string_value, string_value,
bool_value,
database_value, database_value,
logical_operator, logical_operator,
relational_operator, relational_operator,
@ -109,11 +114,13 @@ namespace usql {
ValueNode(NodeType type) : Node(type) {} ValueNode(NodeType type) : Node(type) {}
virtual bool isNull() { return false; } virtual bool isNull() { return false; }
virtual long getIntValue() = 0; virtual long getIntegerValue() = 0;
virtual double getDoubleValue() = 0; virtual double getDoubleValue() = 0;
virtual std::string getStringValue() = 0; virtual std::string getStringValue() = 0;
virtual long getDateValue() = 0;
virtual bool getBooleanValue() = 0;
virtual ~ValueNode() {}; virtual ~ValueNode() = default;
}; };
struct NullValueNode : ValueNode { struct NullValueNode : ValueNode {
@ -122,9 +129,11 @@ namespace usql {
bool isNull() override { return true; } bool isNull() override { return true; }
long getIntValue() override { throw Exception("not supported on null value"); }; long getIntegerValue() override { throw Exception("not supported on null value"); };
double getDoubleValue() 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"); }; 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; };
}; };
struct IntValueNode : ValueNode { struct IntValueNode : ValueNode {
@ -132,9 +141,11 @@ namespace usql {
IntValueNode(long value) : ValueNode(NodeType::int_value), value(value) {} IntValueNode(long value) : ValueNode(NodeType::int_value), value(value) {}
long getIntValue() override { return value; }; long getIntegerValue() override { return value; };
double getDoubleValue() override { return (double) value; }; double getDoubleValue() override { return (double) value; };
std::string getStringValue() override { return std::to_string(value); } std::string getStringValue() override { return std::to_string(value); }
long getDateValue() override { return value; };
bool getBooleanValue() override { return value != 0; };
}; };
struct DoubleValueNode : ValueNode { struct DoubleValueNode : ValueNode {
@ -142,9 +153,11 @@ namespace usql {
DoubleValueNode(double value) : ValueNode(NodeType::float_value), value(value) {} DoubleValueNode(double value) : ValueNode(NodeType::float_value), value(value) {}
long getIntValue() override { return (long) value; }; long getIntegerValue() override { return (long) value; };
double getDoubleValue() override { return value; }; double getDoubleValue() override { return value; };
std::string getStringValue() override { return std::to_string(value); } std::string getStringValue() override { return std::to_string(value); }
long getDateValue() override { return (long) value; };
bool getBooleanValue() override { return value != 0.0; };
}; };
struct StringValueNode : ValueNode { struct StringValueNode : ValueNode {
@ -152,11 +165,26 @@ namespace usql {
StringValueNode(std::string value) : ValueNode(NodeType::string_value), value(value) {} StringValueNode(std::string value) : ValueNode(NodeType::string_value), value(value) {}
long getIntValue() override { return std::stoi(value); }; long getIntegerValue() override { return std::stoi(value); };
double getDoubleValue() override { return std::stod(value); }; double getDoubleValue() override { return std::stod(value); };
std::string getStringValue() override { return value; }; std::string getStringValue() override { return value; };
long getDateValue() override { return Settings::string_to_date(value); };
bool getBooleanValue() override { return value == "true"; };
}; };
struct BooleanValueNode : ValueNode {
bool value;
BooleanValueNode(bool value) : ValueNode(NodeType::bool_value), value(value) {}
long getIntegerValue() override { return (long) value; };
double getDoubleValue() override { return (double) value; };
std::string getStringValue() override { return value ? "true" : "false"; }
long getDateValue() override { return (long) value; };
bool getBooleanValue() override { return value; };
};
struct DatabaseValueNode : Node { struct DatabaseValueNode : Node {
std::string col_name; std::string col_name;

121
row.cpp
View File

@ -8,13 +8,12 @@ namespace usql {
} }
int ColIntegerValue::compare(ColValue * other) { int ColIntegerValue::compare(ColValue * other) {
return other->isNull() ? 1 : m_integer - other->getIntValue(); // null goes to end return other->isNull() ? 1 : m_integer - other->getIntValue(); // TODO implicit conversion from long to int
} }
int ColDoubleValue::compare(ColValue * other) { int ColDoubleValue::compare(ColValue * other) {
if (other->isNull()) { // null goes to end if (other->isNull()) return 1; // null goes to end
return 1;
}
double c = m_double - other->getDoubleValue(); double c = m_double - other->getDoubleValue();
return c < 0 ? -1 : c == 0.0 ? 0 : 1; return c < 0 ? -1 : c == 0.0 ? 0 : 1;
} }
@ -23,6 +22,16 @@ namespace usql {
return other->isNull() ? 1 : m_string.compare(other->getStringValue()); // null goes to end return other->isNull() ? 1 : m_string.compare(other->getStringValue()); // null goes to end
} }
int ColDateValue::compare(ColValue * other) {
return other->isNull() ? 1 : m_date - other->getIntValue(); // TODO implicit conversion from long to int
}
int ColBooleanValue::compare(ColValue * other) {
if (other->isNull()) return 1; // null goes to end
return m_bool==other->getBoolValue() ? 0 : m_bool && !other->getBoolValue() ? -1 : 1; // true first
}
Row::Row(int cols_count) { Row::Row(int cols_count) {
m_columns.reserve(cols_count); m_columns.reserve(cols_count);
for (int i = 0; i < cols_count; i++) { for (int i = 0; i < cols_count; i++) {
@ -32,20 +41,27 @@ 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 this is nonsense // TODO fixme, here 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.push_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 (ColIntegerValue *other_v = dynamic_cast<ColIntegerValue *>(other.m_columns[i].get())) { if (auto *other_v = dynamic_cast<ColIntegerValue *>(other.m_columns[i].get())) {
setColumnValue(i, other_v->getIntValue()); setIntColumnValue(i, other_v->getIntValue());
} } else if (auto *other_v = dynamic_cast<ColDoubleValue *>(other.m_columns[i].get())) {
if (ColDoubleValue *other_v = dynamic_cast<ColDoubleValue *>(other.m_columns[i].get())) { setFloatColumnValue(i, other_v->getDoubleValue());
setColumnValue(i, other_v->getDoubleValue()); } else if (auto *other_v = dynamic_cast<ColStringValue *>(other.m_columns[i].get())) {
} setStringColumnValue(i, other_v->getStringValue());
if (ColStringValue *other_v = dynamic_cast<ColStringValue *>(other.m_columns[i].get())) { } else if (auto *other_v = dynamic_cast<ColDateValue *>(other.m_columns[i].get())) {
setColumnValue(i, other_v->getStringValue()); 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");
} }
} }
} }
@ -59,43 +75,70 @@ namespace usql {
m_columns[col_index] = std::make_unique<ColNullValue>(); m_columns[col_index] = std::make_unique<ColNullValue>();
} }
void Row::setColumnValue(int col_index, long value) { void Row::setIntColumnValue(int col_index, long value) {
m_columns[col_index] = std::make_unique<ColIntegerValue>(value); m_columns[col_index] = std::make_unique<ColIntegerValue>(value);
} }
void Row::setColumnValue(int col_index, double value) { void Row::setFloatColumnValue(int col_index, double value) {
m_columns[col_index] = std::make_unique<ColDoubleValue>(value); m_columns[col_index] = std::make_unique<ColDoubleValue>(value);
} }
void Row::setColumnValue(int col_index, const std::string &value) { void Row::setStringColumnValue(int col_index, const std::string &value) {
m_columns[col_index] = std::make_unique<ColStringValue>(value); m_columns[col_index] = std::make_unique<ColStringValue>(value);
}; }
void Row::setDateColumnValue(int col_index, long value) {
m_columns[col_index] = std::make_unique<ColDateValue>(value);
}
void Row::setDateColumnValue(int col_index, const std::string &value) {
m_columns[col_index] = std::make_unique<ColDateValue>(Settings::string_to_date(value));
}
void Row::setBoolColumnValue(int col_index, bool value) {
m_columns[col_index] = std::make_unique<ColBooleanValue>(value);
}
void Row::setBoolColumnValue(int col_index, const std::string &value) {
bool v = (value=="Y" || value=="1");
m_columns[col_index] = std::make_unique<ColBooleanValue>(v);
}
void Row::setColumnValue(ColDefNode *col_def, ColValue *col_value) { void Row::setColumnValue(ColDefNode *col_def, ColValue *col_value) {
if (!col_value->isNull()) { if (!col_value->isNull()) {
if (col_def->type == ColumnType::integer_type) if (col_def->type == ColumnType::integer_type)
setColumnValue(col_def->order, col_value->getIntValue()); setIntColumnValue(col_def->order, col_value->getIntValue());
else if (col_def->type == ColumnType::float_type) else if (col_def->type == ColumnType::float_type)
setColumnValue(col_def->order, col_value->getDoubleValue()); setFloatColumnValue(col_def->order, col_value->getDoubleValue());
else if (col_def->type == ColumnType::varchar_type) else if (col_def->type == ColumnType::varchar_type)
setColumnValue(col_def->order, col_value->getStringValue()); setStringColumnValue(col_def->order, col_value->getStringValue());
} else { else if (col_def->type == ColumnType::date_type)
setColumnNull(col_def->order); setDateColumnValue(col_def->order, col_value->getDateValue());
} else if (col_def->type == ColumnType::bool_type)
setBoolColumnValue(col_def->order, col_value->getBoolValue());
} else {
setColumnNull(col_def->order);
}
} }
void Row::setColumnValue(ColDefNode *col_def, ValueNode *col_value) { void Row::setColumnValue(ColDefNode *col_def, ValueNode *col_value) {
if (!col_value->isNull()) { if (!col_value->isNull()) {
if (col_def->type == ColumnType::integer_type) if (col_def->type == ColumnType::integer_type)
setColumnValue(col_def->order, col_value->getIntValue()); setIntColumnValue(col_def->order, col_value->getIntegerValue());
else if (col_def->type == ColumnType::float_type) else if (col_def->type == ColumnType::float_type)
setColumnValue(col_def->order, col_value->getDoubleValue()); setFloatColumnValue(col_def->order, col_value->getDoubleValue());
else if (col_def->type == ColumnType::varchar_type) else if (col_def->type == ColumnType::varchar_type)
setColumnValue(col_def->order, col_value->getStringValue()); setStringColumnValue(col_def->order, col_value->getStringValue());
} else { else if (col_def->type == ColumnType::date_type)
setColumnNull(col_def->order); setIntColumnValue(col_def->order, col_value->getDateValue());
} else if (col_def->type == ColumnType::bool_type)
} setBoolColumnValue(col_def->order, col_value->getBooleanValue());
else
throw Exception("unsupported data type");
} else {
setColumnNull(col_def->order);
}
}
int Row::compare(const Row & other) const { int Row::compare(const Row & other) const {
for (int ci = 0; ci < m_columns.size(); ci++) { for (int ci = 0; ci < m_columns.size(); ci++) {

57
row.h
View File

@ -2,44 +2,48 @@
#include "exception.h" #include "exception.h"
#include "parser.h" #include "parser.h"
#include "settings.h"
#include <vector> #include <vector>
namespace usql { namespace usql {
struct ColValue { struct ColValue {
virtual bool isNull() { return false; }; virtual bool isNull() { return false; };
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;
virtual long getDateValue() = 0;
virtual bool getBoolValue() = 0;
virtual int compare(ColValue * other) = 0; virtual int compare(ColValue * other) = 0;
virtual ~ColValue() = default; virtual ~ColValue() = default;
}; };
struct ColNullValue : ColValue { struct ColNullValue : ColValue {
bool isNull() override { return true; }; bool isNull() override { return true; };
long getIntValue() override { throw Exception("Not supported"); }; long getIntValue() override { throw Exception("Not supported"); };
double getDoubleValue() override { throw Exception("Not supported"); }; double getDoubleValue() override { throw Exception("Not supported"); };
std::string getStringValue() override { return "null"; }; std::string getStringValue() override { return "null"; };
long getDateValue() override { throw Exception("Not supported"); };
bool getBoolValue() override { throw Exception("Not supported"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
}; };
struct ColIntegerValue : ColValue { struct ColIntegerValue : ColValue {
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) {};
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; };
bool getBoolValue() override { throw Exception("Not supported"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
@ -48,13 +52,14 @@ namespace usql {
struct ColDoubleValue : ColValue { struct ColDoubleValue : ColValue {
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) {}
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; };
bool getBoolValue() override { throw Exception("Not supported"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
@ -63,19 +68,49 @@ namespace usql {
struct ColStringValue : ColValue { struct ColStringValue : ColValue {
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) {};
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); };
bool getBoolValue() override { throw Exception("Not supported"); };
int compare(ColValue * other) override; int compare(ColValue * other) override;
std::string m_string; std::string m_string;
}; };
struct ColDateValue : ColValue {
ColDateValue(long value) : m_date(value) {};
ColDateValue(const ColDateValue &other) : m_date(other.m_date) {};
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"); };
int compare(ColValue * other) override;
long m_date; // seconds since epoch for now
};
struct ColBooleanValue : ColValue {
ColBooleanValue(bool value) : m_bool(value) {};
ColBooleanValue(const ColBooleanValue &other) : m_bool(other.m_bool) {};
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"); };
bool getBoolValue() override { return m_bool; };
int compare(ColValue * other) override;
bool m_bool;
};
class Row { class Row {
@ -87,9 +122,13 @@ namespace usql {
bool operator==(const Row &other) const {return this->compare(other) == 0; }; bool operator==(const Row &other) const {return this->compare(other) == 0; };
void setColumnNull(int col_index); void setColumnNull(int col_index);
void setColumnValue(int col_index, long value); void setIntColumnValue(int col_index, long value);
void setColumnValue(int col_index, double value); void setFloatColumnValue(int col_index, double value);
void setColumnValue(int col_index, const std::string &value); void setStringColumnValue(int col_index, const std::string &value);
void setDateColumnValue(int col_index, long value);
void setDateColumnValue(int col_index, const std::string &value);
void setBoolColumnValue(int col_index, bool value);
void setBoolColumnValue(int col_index, const std::string &value);
void setColumnValue(ColDefNode *col_def, ColValue *col_value); void setColumnValue(ColDefNode *col_def, ColValue *col_value);
void setColumnValue(ColDefNode *col_def, ValueNode *col_value); void setColumnValue(ColDefNode *col_def, ValueNode *col_value);

30
settings.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "settings.h"
#include "ml_date.h"
namespace usql {
std::vector<std::pair<std::string, std::string>> Settings::m_settings =
{ std::make_pair("DATE_FORMAT", "%Y-%m-%d"),
std::make_pair("BOOL_TRUE_LITERAL", "Y"),
std::make_pair("BOOL_FALSE_LITERAL", "N") };
long Settings::string_to_date(const std::string &datestr) {
return ::string_to_date(datestr, get_setting("DATE_FORMAT"));
}
std::string Settings::date_to_string(long date) {
return ::date_to_string(date, get_setting("DATE_FORMAT"));
}
std::basic_string<char> Settings::get_setting(const std::string &name) {
for(const auto& pair : m_settings) {
if (pair.first == name) return pair.second;
}
// TODO exception
}
} // namespace

21
settings.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <string>
#include <map>
namespace usql {
class Settings {
public:
static long string_to_date(const std::string &datestr);
static std::string date_to_string(long date);
private:
static std::basic_string<char> get_setting(const std::string &name);
private:
static std::vector<std::pair<std::string, std::string>> m_settings;
};
} // namespace

View File

@ -6,10 +6,10 @@
namespace usql { namespace usql {
Table::Table(const std::string name, const std::vector<ColDefNode> columns) { Table::Table(const std::string& name, const std::vector<ColDefNode>& columns) {
m_name = name; m_name = name;
m_col_defs = columns; m_col_defs = columns;
m_rows.reserve(16); m_rows.reserve(256);
} }
Table::Table(const Table &other) { Table::Table(const Table &other) {
@ -22,7 +22,7 @@ Table::Table(const Table &other) {
} }
ColDefNode Table::get_column_def(const std::string &col_name) { ColDefNode Table::get_column_def(const std::string &col_name) {
auto name_cmp = [col_name](ColDefNode cd) { return cd.name == col_name; }; auto name_cmp = [col_name](const ColDefNode& cd) { return cd.name == col_name; };
auto col_def = std::find_if(begin(m_col_defs), end(m_col_defs), name_cmp); auto col_def = std::find_if(begin(m_col_defs), end(m_col_defs), name_cmp);
if (col_def != std::end(m_col_defs)) { if (col_def != std::end(m_col_defs)) {
return *col_def; return *col_def;
@ -39,8 +39,8 @@ ColDefNode Table::get_column_def(int col_index) {
} }
} }
Row Table::create_empty_row() { Row Table::create_empty_row() const {
return Row(columns_count()); return {columns_count()};
} }
std::string Table::csv_string() { std::string Table::csv_string() {
@ -52,12 +52,12 @@ std::string Table::csv_string() {
} }
// rows // rows
for (auto it = m_rows.begin(); it != m_rows.end(); ++it) { for (auto & m_row : m_rows) {
std::string csv_line{"\n"}; std::string csv_line{"\n"};
for(int i = 0; i < m_col_defs.size(); i++) { for(int i = 0; i < m_col_defs.size(); i++) {
if (i > 0) csv_line += ","; if (i > 0) csv_line += ",";
auto col = it->ith_column(i); auto col = m_row.ith_column(i);
if (!col->isNull()) { if (!col->isNull()) {
csv_line += col->getStringValue(); // TODO handle enclosing commas etc csv_line += col->getStringValue(); // TODO handle enclosing commas etc
} }
@ -86,14 +86,20 @@ int Table::load_csv_string(const std::string &content) {
for (size_t i = 0; i < columns_count(); i++) { for (size_t i = 0; i < columns_count(); i++) {
ColDefNode col_def = get_column_def(colDefs[i].name); ColDefNode col_def = get_column_def(colDefs[i].name);
// TODO validate value if (csv_line[i].empty()) {
if (col_def.type == ColumnType::integer_type) { new_row.setColumnNull(col_def.order);
new_row.setColumnValue(col_def.order, std::stol(csv_line[i])); } else if (col_def.type == ColumnType::integer_type) {
new_row.setIntColumnValue(col_def.order, string_to_long(csv_line[i]));
} else if (col_def.type == ColumnType::float_type) { } else if (col_def.type == ColumnType::float_type) {
new_row.setColumnValue(col_def.order, std::stof(csv_line[i])); new_row.setFloatColumnValue(col_def.order, string_to_double(csv_line[i]));
} else { } else if (col_def.type == ColumnType::varchar_type) {
new_row.setColumnValue(col_def.order, csv_line[i]); new_row.setStringColumnValue(col_def.order, csv_line[i]);
} } else if (col_def.type == ColumnType::date_type) {
new_row.setDateColumnValue(col_def.order, csv_line[i]);
} else if (col_def.type == ColumnType::bool_type) {
new_row.setBoolColumnValue(col_def.order, csv_line[i]);
} else
throw Exception("unsupported column type");
} }
// append new_row // append new_row
@ -105,12 +111,28 @@ int Table::load_csv_string(const std::string &content) {
return row_cnt; return row_cnt;
} }
double Table::string_to_double(const std::string &s) {
try {
return std::stod(s);
} catch (std::invalid_argument &e) {
throw Exception("error parsing as double: " + s);
}
}
long Table::string_to_long(const std::string &s) {
try {
return std::stol(s);
} catch (std::invalid_argument &e) {
throw Exception("error parsing as integer: " + s);
}
}
void Table::print() { void Table::print() {
std::string out{"| "}; std::string out{"| "};
std::string out2{"+-"}; std::string out2{"+-"};
std::vector<int> col_char_sizes{}; std::vector<int> col_char_sizes{};
for(auto col_def : m_col_defs) { for(const auto& col_def : m_col_defs) {
int col_size = col_def.type == ColumnType::varchar_type ? col_def.length : 10; int col_size = col_def.type == ColumnType::varchar_type ? col_def.length : 10;
col_char_sizes.push_back(col_size); col_char_sizes.push_back(col_size);
@ -129,6 +151,10 @@ void Table::print() {
} }
void Table::add_row(const Row &row) { void Table::add_row(const Row &row) {
// PERF, here it is performance botleneck, because
// m_rows.push_back(row) calls Row::Row(const Row &other) constructor
// it would be much more performant to add row directly to m_rows in create_new_row
// and here in case of failed validation only remove it
validate_row(row); validate_row(row);
m_rows.push_back(row); m_rows.push_back(row);
} }
@ -143,12 +169,17 @@ void Table::add_copy_of_row(const Row &row) {
new_row.setColumnNull(i); new_row.setColumnNull(i);
} else { } else {
if (m_col_defs[i].type == ColumnType::integer_type) { if (m_col_defs[i].type == ColumnType::integer_type) {
new_row.setColumnValue(i, row.ith_column(i)->getIntValue()); new_row.setIntColumnValue(i, row.ith_column(i)->getIntValue());
} else if (m_col_defs[i].type == ColumnType::float_type) { } else if (m_col_defs[i].type == ColumnType::float_type) {
new_row.setColumnValue(i, row.ith_column(i)->getDoubleValue()); new_row.setFloatColumnValue(i, row.ith_column(i)->getDoubleValue());
} else if (m_col_defs[i].type == ColumnType::varchar_type) { } else if (m_col_defs[i].type == ColumnType::varchar_type) {
new_row.setColumnValue(i, row.ith_column(i)->getStringValue()); new_row.setStringColumnValue(i, row.ith_column(i)->getStringValue());
} } else if (m_col_defs[i].type == ColumnType::date_type) {
new_row.setDateColumnValue(i, row.ith_column(i)->getDateValue());
} else if (m_col_defs[i].type == ColumnType::bool_type) {
new_row.setBoolColumnValue(i, row.ith_column(i)->getBoolValue());
} else
throw Exception("unsupported column type");
} }
} }
@ -157,7 +188,7 @@ void Table::add_copy_of_row(const Row &row) {
} }
void Table::validate_column(const ColDefNode *col_def, ValueNode *col_val) { void Table::validate_column(const ColDefNode *col_def, ValueNode *col_val) {
if (col_def->null == false && col_val->isNull()) { if (!col_def->null && col_val->isNull()) {
throw Exception("Column " + col_def->name + " cannot be null"); throw Exception("Column " + col_def->name + " cannot be null");
} }
if (col_def->type == ColumnType::varchar_type && !col_val->isNull() && col_val->getStringValue().size() > col_def->length) { if (col_def->type == ColumnType::varchar_type && !col_val->isNull() && col_val->getStringValue().size() > col_def->length) {
@ -166,7 +197,7 @@ void Table::validate_column(const ColDefNode *col_def, ValueNode *col_val) {
} }
void Table::validate_column(const ColDefNode *col_def, ColValue *col_val) { void Table::validate_column(const ColDefNode *col_def, ColValue *col_val) {
if (col_def->null == false && col_val->isNull()) { if (!col_def->null && col_val->isNull()) {
throw Exception("Column " + col_def->name + " cannot be null"); throw Exception("Column " + col_def->name + " cannot be null");
} }
if (col_def->type == ColumnType::varchar_type && !col_val->isNull() && col_val->getStringValue().size() > col_def->length) { if (col_def->type == ColumnType::varchar_type && !col_val->isNull() && col_val->getStringValue().size() > col_def->length) {

11
table.h
View File

@ -10,7 +10,7 @@ namespace usql {
struct Table { struct Table {
Table(const Table &other); Table(const Table &other);
Table(const std::string name, const std::vector<ColDefNode> columns); Table(const std::string& name, const std::vector<ColDefNode>& columns);
ColDefNode get_column_def(const std::string &col_name); ColDefNode get_column_def(const std::string &col_name);
ColDefNode get_column_def(int col_index); ColDefNode get_column_def(int col_index);
@ -18,12 +18,12 @@ namespace usql {
int columns_count() const { return m_col_defs.size(); }; int columns_count() const { return m_col_defs.size(); };
int rows_count() const { return m_rows.size(); }; int rows_count() const { return m_rows.size(); };
Row create_empty_row(); // TODO this means unnecessary copying Row create_empty_row() const; // TODO this means unnecessary copying
void add_row(const Row &row); void add_row(const Row &row);
void add_copy_of_row(const Row &row); void add_copy_of_row(const Row &row);
void validate_column(const ColDefNode *col_def, ValueNode *col_val); static void validate_column(const ColDefNode *col_def, ValueNode *col_val);
void validate_column(const ColDefNode *col_def, ColValue *col_val); static void validate_column(const ColDefNode *col_def, ColValue *col_val);
void validate_row(const Row &row); void validate_row(const Row &row);
std::string csv_string(); std::string csv_string();
@ -34,6 +34,9 @@ namespace usql {
std::string m_name; std::string m_name;
std::vector<ColDefNode> m_col_defs; std::vector<ColDefNode> m_col_defs;
std::vector<Row> m_rows; std::vector<Row> m_rows;
static long string_to_long(const std::string &s) ;
static double string_to_double(const std::string &s) ;
}; };
} }

View File

@ -199,7 +199,7 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
return std::move(result); return std::move(result);
} }
void USql::execute_distinct(SelectFromTableNode &node, Table *result) const { void USql::execute_distinct(SelectFromTableNode &node, Table *result) {
if (!node.distinct) return; if (!node.distinct) return;
auto compare_rows = [](const Row &a, const Row &b) { return a.compare(b) >= 0; }; auto compare_rows = [](const Row &a, const Row &b) { return a.compare(b) >= 0; };
@ -208,19 +208,19 @@ void USql::execute_distinct(SelectFromTableNode &node, Table *result) const {
result->m_rows.erase(std::unique(result->m_rows.begin(), result->m_rows.end()), result->m_rows.end()); result->m_rows.erase(std::unique(result->m_rows.begin(), result->m_rows.end()), result->m_rows.end());
} }
void USql::execute_order_by(SelectFromTableNode &node, Table *table, Table *result) const { void USql::execute_order_by(SelectFromTableNode &node, Table *table, Table *result) {
if (node.order_by.size() == 0) return; if (node.order_by.empty()) return;
auto compare_rows = [&node, &result, this](const Row &a, const Row &b) { auto compare_rows = [&node, &result](const Row &a, const Row &b) {
for(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 ColDefNode col_def = result->get_column_def(order_by_col_def.col_index - 1); // TODO validate index
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);
int compare = a_val->compare(b_val); int compare = a_val->compare(b_val);
if (compare < 0) return order_by_col_def.ascending ? true : false; if (compare < 0) return order_by_col_def.ascending;
if (compare > 0) return order_by_col_def.ascending ? false : true; if (compare > 0) return !order_by_col_def.ascending;
} }
return false; return false;
}; };
@ -228,7 +228,7 @@ void USql::execute_order_by(SelectFromTableNode &node, Table *table, Table *resu
std::sort(result->m_rows.begin(), result->m_rows.end(), compare_rows); std::sort(result->m_rows.begin(), result->m_rows.end(), compare_rows);
} }
void USql::execute_offset_limit(OffsetLimitNode &node, Table *result) const { void USql::execute_offset_limit(OffsetLimitNode &node, Table *result) {
if (node.offset > 0) if (node.offset > 0)
result->m_rows.erase(result->m_rows.begin(), result->m_rows.erase(result->m_rows.begin(),
result->rows_count() > node.offset ? result->m_rows.begin() + node.offset : result->m_rows.end()); result->rows_count() > node.offset ? result->m_rows.begin() + node.offset : result->m_rows.end());
@ -270,7 +270,7 @@ std::unique_ptr<Table> USql::execute_delete(DeleteFromTableNode &node) {
table->m_rows.erase( table->m_rows.erase(
std::remove_if(table->m_rows.begin(), table->m_rows.end(), std::remove_if(table->m_rows.begin(), table->m_rows.end(),
[&node, table, this](Row &row){return eval_where(node.where.get(), table, row);}), [&node, table](Row &row){return eval_where(node.where.get(), table, row);}),
table->m_rows.end()); table->m_rows.end());
affected_rows -= table->rows_count(); affected_rows -= table->rows_count();
@ -295,7 +295,7 @@ std::unique_ptr<Table> USql::execute_update(UpdateTableNode &node) {
static_cast<ArithmeticalOperatorNode &>(*node.values[i]), static_cast<ArithmeticalOperatorNode &>(*node.values[i]),
table, *row); table, *row);
table->validate_column(&col_def, new_val.get()); usql::Table::validate_column(&col_def, new_val.get());
row->setColumnValue(&col_def, new_val.get()); row->setColumnValue(&col_def, new_val.get());
i++; i++;
} }
@ -308,7 +308,7 @@ std::unique_ptr<Table> USql::execute_update(UpdateTableNode &node) {
} }
bool USql::eval_where(Node *where, Table *table, Row &row) const { bool USql::eval_where(Node *where, Table *table, Row &row) {
switch (where->node_type) { // no where clause switch (where->node_type) { // no where clause
case NodeType::true_node: case NodeType::true_node:
return true; return true;
@ -324,20 +324,25 @@ bool USql::eval_where(Node *where, Table *table, Row &row) const {
} }
bool USql::eval_relational_operator(const RelationalOperatorNode &filter, Table *table, Row &row) const { bool USql::eval_relational_operator(const RelationalOperatorNode &filter, Table *table, Row &row) {
std::unique_ptr<ValueNode> left_value = eval_value_node(table, row, filter.left.get()); std::unique_ptr<ValueNode> left_value = eval_value_node(table, row, filter.left.get());
std::unique_ptr<ValueNode> right_value = eval_value_node(table, row, filter.right.get()); std::unique_ptr<ValueNode> right_value = eval_value_node(table, row, filter.right.get());
double comparator; double comparator;
if (left_value->node_type == NodeType::int_value && right_value->node_type == NodeType::int_value) { if (left_value->node_type == NodeType::int_value && right_value->node_type == NodeType::int_value) {
comparator = left_value->getIntValue() - right_value->getIntValue(); comparator = left_value->getIntegerValue() - right_value->getIntegerValue();
} else if ((left_value->node_type == NodeType::int_value && right_value->node_type == NodeType::float_value) || } 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) || (left_value->node_type == NodeType::float_value && right_value->node_type == NodeType::int_value) ||
(left_value->node_type == NodeType::float_value && right_value->node_type == NodeType::float_value)) { (left_value->node_type == NodeType::float_value && right_value->node_type == NodeType::float_value)) {
comparator = left_value->getDoubleValue() - right_value->getDoubleValue(); comparator = left_value->getDoubleValue() - right_value->getDoubleValue();
} else if (left_value->node_type == NodeType::string_value || right_value->node_type == NodeType::string_value) { } else if (left_value->node_type == NodeType::string_value || right_value->node_type == NodeType::string_value) {
comparator = left_value->getStringValue().compare(right_value->getStringValue()); comparator = left_value->getStringValue().compare(right_value->getStringValue());
} else if (left_value->node_type == NodeType::bool_value && right_value->node_type == NodeType::bool_value) {
bool bl = left_value->getBooleanValue();
bool br = right_value->getBooleanValue();
comparator = bl == br ? 0 : 1; // TODO define it
// TODO handle dates
} else { } else {
// TODO throw exception // TODO throw exception
} }
@ -364,10 +369,8 @@ bool USql::eval_relational_operator(const RelationalOperatorNode &filter, Table
std::unique_ptr<ValueNode> USql::eval_value_node(Table *table, Row &row, Node *node) { std::unique_ptr<ValueNode> USql::eval_value_node(Table *table, Row &row, Node *node) {
if (node->node_type == NodeType::database_value || node->node_type == NodeType::column_name) { // TODO sjednotit if (node->node_type == NodeType::database_value || node->node_type == NodeType::column_name) { // TODO sjednotit
return eval_database_value_node(table, row, node); return eval_database_value_node(table, row, node);
} else if (node->node_type == NodeType::int_value || node->node_type == NodeType::float_value || node->node_type == NodeType::string_value || node->node_type == NodeType::bool_value) {
} else if (node->node_type == NodeType::int_value || node->node_type == NodeType::float_value || node->node_type == NodeType::string_value) {
return eval_literal_value_node(table, row, node); return eval_literal_value_node(table, row, node);
} else if (node->node_type == NodeType::function) { } else if (node->node_type == NodeType::function) {
return eval_function_value_node(table, row, node); return eval_function_value_node(table, row, node);
} else if (node->node_type == NodeType::null_value) { } else if (node->node_type == NodeType::null_value) {
@ -382,15 +385,18 @@ 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 (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) {
return std::make_unique<DoubleValueNode>(db_value->getDoubleValue()); return std::make_unique<DoubleValueNode>(db_value->getDoubleValue());
} if (col_def.type == ColumnType::varchar_type)
if (col_def.type == ColumnType::varchar_type) {
return std::make_unique<StringValueNode>(db_value->getStringValue()); return std::make_unique<StringValueNode>(db_value->getStringValue());
} if (col_def.type == ColumnType::bool_type)
return std::make_unique<BooleanValueNode>(db_value->getBoolValue());
// Date has no it's own value node (it is passed around as string)
if (col_def.type == ColumnType::date_type)
return std::make_unique<StringValueNode>(db_value->getStringValue());
throw Exception("unknown database value type"); throw Exception("unknown database value type");
} }
@ -408,7 +414,11 @@ std::unique_ptr<ValueNode> USql::eval_literal_value_node(Table *table, Row &row,
auto *ivl = static_cast<StringValueNode *>(node); auto *ivl = static_cast<StringValueNode *>(node);
return std::make_unique<StringValueNode>(ivl->value); return std::make_unique<StringValueNode>(ivl->value);
} else if (node->node_type == NodeType::bool_value) {
auto *ivl = static_cast<BooleanValueNode *>(node);
return std::make_unique<BooleanValueNode>(ivl->value);
} }
// Date has no it's own value node (it is passed around as string)
throw Exception("invalid type"); throw Exception("invalid type");
} }
@ -438,10 +448,10 @@ std::unique_ptr<ValueNode> USql::eval_function_value_node(Table *table, Row &row
std::string date = evaluatedPars[0]->getStringValue(); std::string date = evaluatedPars[0]->getStringValue();
std::string format = evaluatedPars[1]->getStringValue(); std::string format = evaluatedPars[1]->getStringValue();
long epoch_time = string_to_date(date, format); long epoch_time = string_to_date(date, format);
return std::make_unique<IntValueNode>(epoch_time); return std::make_unique<IntValueNode>(epoch_time); // No DateValueNode for now
} }
if (fnc->function == "to_string") { if (fnc->function == "to_string") {
long date = evaluatedPars[0]->getIntValue(); long date = evaluatedPars[0]->getDateValue();
std::string format = evaluatedPars[1]->getStringValue(); std::string format = evaluatedPars[1]->getStringValue();
std::string formated_date = date_to_string(date, format); std::string formated_date = date_to_string(date, format);
return std::make_unique<StringValueNode>(formated_date); return std::make_unique<StringValueNode>(formated_date);
@ -451,7 +461,7 @@ std::unique_ptr<ValueNode> USql::eval_function_value_node(Table *table, Row &row
} }
bool USql::eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &row) const { bool USql::eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &row) {
bool left = eval_relational_operator(static_cast<const RelationalOperatorNode &>(*node.left), pTable, row); bool left = eval_relational_operator(static_cast<const RelationalOperatorNode &>(*node.left), pTable, row);
if ((node.op == LogicalOperatorType::and_operator && !left) || (node.op == LogicalOperatorType::or_operator && left)) if ((node.op == LogicalOperatorType::and_operator && !left) || (node.op == LogicalOperatorType::or_operator && left))
@ -462,7 +472,7 @@ bool USql::eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &
} }
std::unique_ptr<ValueNode> USql::eval_arithmetic_operator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) const { std::unique_ptr<ValueNode> USql::eval_arithmetic_operator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) {
if (node.op == ArithmeticalOperatorType::copy_value) { if (node.op == ArithmeticalOperatorType::copy_value) {
return eval_value_node(table, row, node.left.get()); return eval_value_node(table, row, node.left.get());
} }
@ -487,8 +497,8 @@ std::unique_ptr<ValueNode> USql::eval_arithmetic_operator(ColumnType outType, Ar
} }
} else if (outType == ColumnType::integer_type) { } else if (outType == ColumnType::integer_type) {
long l = ((ValueNode *) left.get())->getIntValue(); long l = ((ValueNode *) left.get())->getIntegerValue();
long r = ((ValueNode *) right.get())->getIntValue(); long r = ((ValueNode *) right.get())->getIntegerValue();
switch (node.op) { switch (node.op) {
case ArithmeticalOperatorType::plus_operator: case ArithmeticalOperatorType::plus_operator:
return std::make_unique<IntValueNode>(l + r); return std::make_unique<IntValueNode>(l + r);
@ -512,6 +522,7 @@ std::unique_ptr<ValueNode> USql::eval_arithmetic_operator(ColumnType outType, Ar
throw Exception("implement me!!"); throw Exception("implement me!!");
} }
} }
// TODO date node should support addition and substraction
throw Exception("implement me!!"); throw Exception("implement me!!");
} }
@ -519,16 +530,16 @@ std::unique_ptr<ValueNode> USql::eval_arithmetic_operator(ColumnType outType, Ar
std::unique_ptr<Table> USql::create_stmt_result_table(long code, const std::string &text, long affected_rows) { std::unique_ptr<Table> USql::create_stmt_result_table(long code, const std::string &text, long affected_rows) {
std::vector<ColDefNode> result_tbl_col_defs{}; std::vector<ColDefNode> result_tbl_col_defs{};
result_tbl_col_defs.push_back(ColDefNode("code", ColumnType::integer_type, 0, 1, false)); result_tbl_col_defs.emplace_back("code", ColumnType::integer_type, 0, 1, false);
result_tbl_col_defs.push_back(ColDefNode("desc", ColumnType::varchar_type, 1, 48, false)); result_tbl_col_defs.emplace_back("desc", ColumnType::varchar_type, 1, 48, false);
result_tbl_col_defs.push_back(ColDefNode("affected_rows", ColumnType::integer_type, 0, 1, true)); result_tbl_col_defs.emplace_back("affected_rows", ColumnType::integer_type, 0, 1, true);
auto table_def = std::make_unique<Table>("result", result_tbl_col_defs); auto table_def = std::make_unique<Table>("result", result_tbl_col_defs);
Row new_row = table_def->create_empty_row(); Row new_row = table_def->create_empty_row();
new_row.setColumnValue(0, code); new_row.setIntColumnValue(0, code);
new_row.setColumnValue(1, text); new_row.setStringColumnValue(1, text);
new_row.setColumnValue(2, affected_rows); new_row.setIntColumnValue(2, affected_rows);
table_def->add_row(new_row); table_def->add_row(new_row);
return std::move(table_def); return std::move(table_def);
@ -554,4 +565,5 @@ void USql::check_table_not_exists(const std::string &name) {
} }
} }
} // namespace } // namespace

15
usql.h
View File

@ -13,7 +13,6 @@ class USql {
public: public:
USql() = default; USql() = default;
std::unique_ptr<Table> execute(const std::string &command); std::unique_ptr<Table> execute(const std::string &command);
private: private:
@ -32,7 +31,7 @@ private:
private: private:
bool eval_where(Node *where, Table *table, Row &row) const; static bool eval_where(Node *where, Table *table, Row &row) ;
static std::unique_ptr<ValueNode> eval_value_node(Table *table, Row &row, Node *node); static std::unique_ptr<ValueNode> eval_value_node(Table *table, Row &row, Node *node);
static std::unique_ptr<ValueNode> eval_database_value_node(Table *table, Row &row, Node *node); static std::unique_ptr<ValueNode> eval_database_value_node(Table *table, Row &row, Node *node);
@ -40,9 +39,9 @@ private:
static std::unique_ptr<ValueNode> eval_function_value_node(Table *table, Row &row, Node *node); static std::unique_ptr<ValueNode> eval_function_value_node(Table *table, Row &row, Node *node);
bool eval_relational_operator(const RelationalOperatorNode &filter, Table *table, Row &row) const; static bool eval_relational_operator(const RelationalOperatorNode &filter, Table *table, Row &row) ;
bool eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &row) const; static bool eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &row) ;
std::unique_ptr<ValueNode> eval_arithmetic_operator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) const; static std::unique_ptr<ValueNode> eval_arithmetic_operator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) ;
static std::unique_ptr<Table> create_stmt_result_table(long code, const std::string &text, long affected_rows); static std::unique_ptr<Table> create_stmt_result_table(long code, const std::string &text, long affected_rows);
@ -55,9 +54,9 @@ private:
Parser m_parser; Parser m_parser;
std::list<Table> m_tables; std::list<Table> m_tables;
void execute_distinct(SelectFromTableNode &node, Table *result) const; static void execute_distinct(SelectFromTableNode &node, Table *result) ;
void execute_order_by(SelectFromTableNode &node, Table *table, Table *result) const; static void execute_order_by(SelectFromTableNode &node, Table *table, Table *result) ;
void execute_offset_limit(OffsetLimitNode &node, Table *result) const; static void execute_offset_limit(OffsetLimitNode &node, Table *result) ;
}; };
} // namespace } // namespace