date and boolean data types added
This commit is contained in:
parent
4b95be1e31
commit
15a065c2aa
|
|
@ -14,7 +14,7 @@ set(PROJECT_NAME usql)
|
|||
include_directories(${CMAKE_SOURCE_DIR}/clib ${CMAKE_SOURCE_DIR})
|
||||
|
||||
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})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
|
||||
### TODO
|
||||
- support for *
|
||||
- add support for set setting value
|
||||
- command line interface
|
||||
- date functions - now, add_date...
|
||||
- support for order by, offset, limit (allow column name in order by, validate)
|
||||
- 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 parenthesis
|
||||
- functions rtrim, ltrim, rpad, lpad
|
||||
- support for *
|
||||
- add pipe | token
|
||||
- maybe to create iterator on table
|
||||
- add exceptions and rename it to UsqlException
|
||||
- class members should have prefix m_
|
||||
- add const wherever should be
|
||||
|
|
|
|||
1483
clib/linenoise.c
1483
clib/linenoise.c
File diff suppressed because it is too large
Load Diff
|
|
@ -20,7 +20,7 @@ namespace usql {
|
|||
std::string field;
|
||||
|
||||
std::vector<std::vector<std::string>> parsed_data;
|
||||
parsed_data.reserve(128);
|
||||
parsed_data.reserve(256);
|
||||
|
||||
std::vector<std::string> line;
|
||||
line.reserve(32);
|
||||
|
|
|
|||
18
lexer.cpp
18
lexer.cpp
|
|
@ -45,7 +45,7 @@ namespace usql {
|
|||
match_str = stringLiteral(match_str);
|
||||
|
||||
if (token_type != TokenType::newline)
|
||||
m_tokens.push_back(Token{match_str, token_type});
|
||||
m_tokens.emplace_back(match_str, token_type);
|
||||
}
|
||||
|
||||
// DEBUG IT
|
||||
|
|
@ -56,8 +56,8 @@ namespace usql {
|
|||
|
||||
void Lexer::debugTokens() {
|
||||
int i = 0;
|
||||
for (std::vector<Token>::iterator it = m_tokens.begin(); it != m_tokens.end(); ++it) {
|
||||
std::cerr << i << "\t" << it->token_string << std::endl;
|
||||
for (auto & m_token : m_tokens) {
|
||||
std::cerr << i << "\t" << m_token.token_string << std::endl;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -197,6 +197,10 @@ namespace usql {
|
|||
return TokenType::keyword_float;
|
||||
if (token == "varchar")
|
||||
return TokenType::keyword_varchar;
|
||||
if (token == "date")
|
||||
return TokenType::keyword_date;
|
||||
if (token == "boolean")
|
||||
return TokenType::keyword_bool;
|
||||
if (token == "distinct")
|
||||
return TokenType::keyword_distinct;
|
||||
if (token == "or")
|
||||
|
|
@ -244,7 +248,7 @@ namespace usql {
|
|||
if (!replace) {
|
||||
return str;
|
||||
}
|
||||
std::string out = "";
|
||||
std::string out;
|
||||
out.reserve(str.size());
|
||||
|
||||
|
||||
|
|
@ -384,6 +388,12 @@ namespace usql {
|
|||
case TokenType::keyword_varchar:
|
||||
txt = "varchar";
|
||||
break;
|
||||
case TokenType::keyword_date:
|
||||
txt = "date";
|
||||
break;
|
||||
case TokenType::keyword_bool:
|
||||
txt = "boolean";
|
||||
break;
|
||||
case TokenType::keyword_distinct:
|
||||
txt = "distinct";
|
||||
break;
|
||||
|
|
|
|||
4
lexer.h
4
lexer.h
|
|
@ -47,6 +47,8 @@ namespace usql {
|
|||
keyword_integer,
|
||||
keyword_float,
|
||||
keyword_varchar,
|
||||
keyword_date,
|
||||
keyword_bool,
|
||||
keyword_distinct,
|
||||
int_number,
|
||||
double_number,
|
||||
|
|
@ -103,7 +105,7 @@ namespace usql {
|
|||
private:
|
||||
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);
|
||||
|
||||
|
|
|
|||
36
main.cpp
36
main.cpp
|
|
@ -126,23 +126,31 @@ void repl() {
|
|||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<std::string> sql_commands{
|
||||
"create table a (i integer not null, s varchar(64), f float null)",
|
||||
"insert into a (i, s) values(1, upper('one'))",
|
||||
// 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))"
|
||||
"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 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')",
|
||||
"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 from a",
|
||||
// "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",
|
||||
// "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",
|
||||
|
|
@ -157,10 +165,10 @@ int main(int argc, char *argv[]) {
|
|||
// "drop table x",
|
||||
// "select i, 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))",
|
||||
"load prices from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/prices.csv'",
|
||||
// "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'",
|
||||
// "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"
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
26
parser.cpp
26
parser.cpp
|
|
@ -56,8 +56,8 @@ namespace usql {
|
|||
do {
|
||||
std::string column_name;
|
||||
ColumnType column_type;
|
||||
int column_len{1};
|
||||
bool column_nullable{true};
|
||||
int column_len = 1;
|
||||
bool column_nullable = true;
|
||||
|
||||
// column name
|
||||
if (m_lexer.tokenType() != TokenType::identifier) {
|
||||
|
|
@ -82,8 +82,14 @@ namespace usql {
|
|||
throw Exception("syntax error, expected int number");
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
|
|
@ -94,7 +100,7 @@ namespace usql {
|
|||
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);
|
||||
|
||||
|
|
@ -155,7 +161,7 @@ namespace usql {
|
|||
m_lexer.skipToken(TokenType::open_paren);
|
||||
do {
|
||||
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);
|
||||
} while (m_lexer.tokenType() != TokenType::close_paren);
|
||||
|
|
@ -272,7 +278,7 @@ namespace usql {
|
|||
std::vector<std::unique_ptr<Node>> values;
|
||||
|
||||
do {
|
||||
cols_names.push_back(m_lexer.consumeCurrentToken().token_string);
|
||||
cols_names.emplace_back(m_lexer.consumeCurrentToken().token_string);
|
||||
m_lexer.skipToken(TokenType::equal);
|
||||
|
||||
std::unique_ptr<Node> left = Parser::parse_operand_node();
|
||||
|
|
@ -332,9 +338,9 @@ namespace usql {
|
|||
auto token_type = m_lexer.tokenType();
|
||||
std::string tokenString = m_lexer.consumeCurrentToken().token_string;
|
||||
switch (token_type) {
|
||||
case TokenType::int_number:
|
||||
col_index = std::stoi(tokenString);
|
||||
break;
|
||||
case TokenType::int_number:
|
||||
col_index = std::stoi(tokenString);
|
||||
break;
|
||||
default:
|
||||
throw Exception("column index allowed in order by clause at this moment");
|
||||
}
|
||||
|
|
@ -346,7 +352,7 @@ namespace usql {
|
|||
asc = false;
|
||||
}
|
||||
|
||||
order_cols.push_back(ColOrderNode{col_index, asc});
|
||||
order_cols.emplace_back(col_index, asc);
|
||||
|
||||
m_lexer.skipTokenOptional(TokenType::comma);
|
||||
|
||||
|
|
|
|||
44
parser.h
44
parser.h
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
#include "lexer.h"
|
||||
#include "exception.h"
|
||||
#include <string>
|
||||
#include "ml_date.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace usql {
|
||||
|
|
@ -11,7 +13,9 @@ namespace usql {
|
|||
enum class ColumnType {
|
||||
integer_type,
|
||||
float_type,
|
||||
varchar_type
|
||||
varchar_type,
|
||||
date_type,
|
||||
bool_type
|
||||
};
|
||||
|
||||
enum class NodeType {
|
||||
|
|
@ -20,6 +24,7 @@ namespace usql {
|
|||
int_value,
|
||||
float_value,
|
||||
string_value,
|
||||
bool_value,
|
||||
database_value,
|
||||
logical_operator,
|
||||
relational_operator,
|
||||
|
|
@ -109,11 +114,13 @@ namespace usql {
|
|||
ValueNode(NodeType type) : Node(type) {}
|
||||
|
||||
virtual bool isNull() { return false; }
|
||||
virtual long getIntValue() = 0;
|
||||
virtual long getIntegerValue() = 0;
|
||||
virtual double getDoubleValue() = 0;
|
||||
virtual std::string getStringValue() = 0;
|
||||
virtual long getDateValue() = 0;
|
||||
virtual bool getBooleanValue() = 0;
|
||||
|
||||
virtual ~ValueNode() {};
|
||||
virtual ~ValueNode() = default;
|
||||
};
|
||||
|
||||
struct NullValueNode : ValueNode {
|
||||
|
|
@ -122,9 +129,11 @@ namespace usql {
|
|||
|
||||
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"); };
|
||||
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 {
|
||||
|
|
@ -132,9 +141,11 @@ namespace usql {
|
|||
|
||||
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; };
|
||||
std::string getStringValue() override { return std::to_string(value); }
|
||||
long getDateValue() override { return value; };
|
||||
bool getBooleanValue() override { return value != 0; };
|
||||
};
|
||||
|
||||
struct DoubleValueNode : ValueNode {
|
||||
|
|
@ -142,9 +153,11 @@ namespace usql {
|
|||
|
||||
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; };
|
||||
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 {
|
||||
|
|
@ -152,11 +165,26 @@ namespace usql {
|
|||
|
||||
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); };
|
||||
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 {
|
||||
std::string col_name;
|
||||
|
||||
|
|
|
|||
121
row.cpp
121
row.cpp
|
|
@ -8,13 +8,12 @@ namespace usql {
|
|||
}
|
||||
|
||||
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) {
|
||||
if (other->isNull()) { // null goes to end
|
||||
return 1;
|
||||
}
|
||||
if (other->isNull()) return 1; // null goes to end
|
||||
|
||||
double c = m_double - other->getDoubleValue();
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
m_columns.reserve(cols_count);
|
||||
for (int i = 0; i < cols_count; i++) {
|
||||
|
|
@ -32,20 +41,27 @@ namespace usql {
|
|||
|
||||
Row::Row(const Row &other) {
|
||||
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++) {
|
||||
m_columns.push_back(std::make_unique<ColNullValue>());
|
||||
}
|
||||
|
||||
// TODO get rid of dynamic_cast
|
||||
for (int i = 0; i < other.m_columns.size(); i++) {
|
||||
if (ColIntegerValue *other_v = dynamic_cast<ColIntegerValue *>(other.m_columns[i].get())) {
|
||||
setColumnValue(i, other_v->getIntValue());
|
||||
}
|
||||
if (ColDoubleValue *other_v = dynamic_cast<ColDoubleValue *>(other.m_columns[i].get())) {
|
||||
setColumnValue(i, other_v->getDoubleValue());
|
||||
}
|
||||
if (ColStringValue *other_v = dynamic_cast<ColStringValue *>(other.m_columns[i].get())) {
|
||||
setColumnValue(i, other_v->getStringValue());
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,43 +75,70 @@ namespace usql {
|
|||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!col_value->isNull()) {
|
||||
if (col_def->type == ColumnType::integer_type)
|
||||
setColumnValue(col_def->order, col_value->getIntValue());
|
||||
else if (col_def->type == ColumnType::float_type)
|
||||
setColumnValue(col_def->order, col_value->getDoubleValue());
|
||||
else if (col_def->type == ColumnType::varchar_type)
|
||||
setColumnValue(col_def->order, col_value->getStringValue());
|
||||
} else {
|
||||
setColumnNull(col_def->order);
|
||||
}
|
||||
if (!col_value->isNull()) {
|
||||
if (col_def->type == ColumnType::integer_type)
|
||||
setIntColumnValue(col_def->order, col_value->getIntValue());
|
||||
else if (col_def->type == ColumnType::float_type)
|
||||
setFloatColumnValue(col_def->order, col_value->getDoubleValue());
|
||||
else if (col_def->type == ColumnType::varchar_type)
|
||||
setStringColumnValue(col_def->order, col_value->getStringValue());
|
||||
else if (col_def->type == ColumnType::date_type)
|
||||
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) {
|
||||
if (!col_value->isNull()) {
|
||||
if (col_def->type == ColumnType::integer_type)
|
||||
setColumnValue(col_def->order, col_value->getIntValue());
|
||||
else if (col_def->type == ColumnType::float_type)
|
||||
setColumnValue(col_def->order, col_value->getDoubleValue());
|
||||
else if (col_def->type == ColumnType::varchar_type)
|
||||
setColumnValue(col_def->order, col_value->getStringValue());
|
||||
} else {
|
||||
setColumnNull(col_def->order);
|
||||
}
|
||||
}
|
||||
void Row::setColumnValue(ColDefNode *col_def, ValueNode *col_value) {
|
||||
if (!col_value->isNull()) {
|
||||
if (col_def->type == ColumnType::integer_type)
|
||||
setIntColumnValue(col_def->order, col_value->getIntegerValue());
|
||||
else if (col_def->type == ColumnType::float_type)
|
||||
setFloatColumnValue(col_def->order, col_value->getDoubleValue());
|
||||
else if (col_def->type == ColumnType::varchar_type)
|
||||
setStringColumnValue(col_def->order, col_value->getStringValue());
|
||||
else if (col_def->type == ColumnType::date_type)
|
||||
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 {
|
||||
for (int ci = 0; ci < m_columns.size(); ci++) {
|
||||
|
|
|
|||
57
row.h
57
row.h
|
|
@ -2,44 +2,48 @@
|
|||
|
||||
#include "exception.h"
|
||||
#include "parser.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace usql {
|
||||
|
||||
|
||||
struct ColValue {
|
||||
|
||||
virtual bool isNull() { return false; };
|
||||
virtual long getIntValue() = 0;
|
||||
virtual double getDoubleValue() = 0;
|
||||
virtual std::string getStringValue() = 0;
|
||||
virtual long getDateValue() = 0;
|
||||
virtual bool getBoolValue() = 0;
|
||||
|
||||
virtual int compare(ColValue * other) = 0;
|
||||
|
||||
virtual ~ColValue() = default;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct ColNullValue : ColValue {
|
||||
|
||||
bool isNull() override { return true; };
|
||||
long getIntValue() override { throw Exception("Not supported"); };
|
||||
double getDoubleValue() override { throw Exception("Not supported"); };
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
struct ColIntegerValue : ColValue {
|
||||
|
||||
ColIntegerValue(long value) : m_integer(value) {};
|
||||
ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {};
|
||||
|
||||
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"); };
|
||||
|
||||
int compare(ColValue * other) override;
|
||||
|
||||
|
|
@ -48,13 +52,14 @@ namespace usql {
|
|||
|
||||
|
||||
struct ColDoubleValue : ColValue {
|
||||
|
||||
ColDoubleValue(double value) : m_double(value) {};
|
||||
ColDoubleValue(const ColDoubleValue &other) : m_double(other.m_double) {}
|
||||
|
||||
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"); };
|
||||
|
||||
int compare(ColValue * other) override;
|
||||
|
||||
|
|
@ -63,19 +68,49 @@ namespace usql {
|
|||
|
||||
|
||||
struct ColStringValue : ColValue {
|
||||
|
||||
ColStringValue(const std::string &value) : m_string(value) {};
|
||||
ColStringValue(const ColStringValue &other) : m_string(other.m_string) {};
|
||||
|
||||
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"); };
|
||||
|
||||
int compare(ColValue * other) override;
|
||||
|
||||
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 {
|
||||
|
||||
|
|
@ -87,9 +122,13 @@ namespace usql {
|
|||
bool operator==(const Row &other) const {return this->compare(other) == 0; };
|
||||
|
||||
void setColumnNull(int col_index);
|
||||
void setColumnValue(int col_index, long value);
|
||||
void setColumnValue(int col_index, double value);
|
||||
void setColumnValue(int col_index, const std::string &value);
|
||||
void setIntColumnValue(int col_index, long value);
|
||||
void setFloatColumnValue(int col_index, double 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, ValueNode *col_value);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
73
table.cpp
73
table.cpp
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
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_col_defs = columns;
|
||||
m_rows.reserve(16);
|
||||
m_rows.reserve(256);
|
||||
}
|
||||
|
||||
Table::Table(const Table &other) {
|
||||
|
|
@ -22,7 +22,7 @@ Table::Table(const Table &other) {
|
|||
}
|
||||
|
||||
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);
|
||||
if (col_def != std::end(m_col_defs)) {
|
||||
return *col_def;
|
||||
|
|
@ -39,8 +39,8 @@ ColDefNode Table::get_column_def(int col_index) {
|
|||
}
|
||||
}
|
||||
|
||||
Row Table::create_empty_row() {
|
||||
return Row(columns_count());
|
||||
Row Table::create_empty_row() const {
|
||||
return {columns_count()};
|
||||
}
|
||||
|
||||
std::string Table::csv_string() {
|
||||
|
|
@ -52,12 +52,12 @@ std::string Table::csv_string() {
|
|||
}
|
||||
|
||||
// rows
|
||||
for (auto it = m_rows.begin(); it != m_rows.end(); ++it) {
|
||||
for (auto & m_row : m_rows) {
|
||||
std::string csv_line{"\n"};
|
||||
for(int i = 0; i < m_col_defs.size(); i++) {
|
||||
if (i > 0) csv_line += ",";
|
||||
|
||||
auto col = it->ith_column(i);
|
||||
auto col = m_row.ith_column(i);
|
||||
if (!col->isNull()) {
|
||||
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++) {
|
||||
ColDefNode col_def = get_column_def(colDefs[i].name);
|
||||
|
||||
// TODO validate value
|
||||
if (col_def.type == ColumnType::integer_type) {
|
||||
new_row.setColumnValue(col_def.order, std::stol(csv_line[i]));
|
||||
if (csv_line[i].empty()) {
|
||||
new_row.setColumnNull(col_def.order);
|
||||
} 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) {
|
||||
new_row.setColumnValue(col_def.order, std::stof(csv_line[i]));
|
||||
} else {
|
||||
new_row.setColumnValue(col_def.order, csv_line[i]);
|
||||
}
|
||||
new_row.setFloatColumnValue(col_def.order, string_to_double(csv_line[i]));
|
||||
} else if (col_def.type == ColumnType::varchar_type) {
|
||||
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
|
||||
|
|
@ -105,12 +111,28 @@ int Table::load_csv_string(const std::string &content) {
|
|||
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() {
|
||||
std::string out{"| "};
|
||||
std::string out2{"+-"};
|
||||
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;
|
||||
col_char_sizes.push_back(col_size);
|
||||
|
||||
|
|
@ -129,6 +151,10 @@ void Table::print() {
|
|||
}
|
||||
|
||||
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);
|
||||
m_rows.push_back(row);
|
||||
}
|
||||
|
|
@ -143,12 +169,17 @@ void Table::add_copy_of_row(const Row &row) {
|
|||
new_row.setColumnNull(i);
|
||||
} else {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
if (col_def->null == false && col_val->isNull()) {
|
||||
if (!col_def->null && col_val->isNull()) {
|
||||
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) {
|
||||
|
|
@ -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) {
|
||||
if (col_def->null == false && col_val->isNull()) {
|
||||
if (!col_def->null && col_val->isNull()) {
|
||||
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) {
|
||||
|
|
|
|||
11
table.h
11
table.h
|
|
@ -10,7 +10,7 @@ namespace usql {
|
|||
struct Table {
|
||||
|
||||
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(int col_index);
|
||||
|
|
@ -18,12 +18,12 @@ namespace usql {
|
|||
int columns_count() const { return m_col_defs.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_copy_of_row(const Row &row);
|
||||
|
||||
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, ValueNode *col_val);
|
||||
static void validate_column(const ColDefNode *col_def, ColValue *col_val);
|
||||
void validate_row(const Row &row);
|
||||
|
||||
std::string csv_string();
|
||||
|
|
@ -34,6 +34,9 @@ namespace usql {
|
|||
std::string m_name;
|
||||
std::vector<ColDefNode> m_col_defs;
|
||||
std::vector<Row> m_rows;
|
||||
|
||||
static long string_to_long(const std::string &s) ;
|
||||
static double string_to_double(const std::string &s) ;
|
||||
};
|
||||
|
||||
}
|
||||
80
usql.cpp
80
usql.cpp
|
|
@ -199,7 +199,7 @@ std::unique_ptr<Table> USql::execute_select(SelectFromTableNode &node) {
|
|||
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;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void USql::execute_order_by(SelectFromTableNode &node, Table *table, Table *result) const {
|
||||
if (node.order_by.size() == 0) return;
|
||||
void USql::execute_order_by(SelectFromTableNode &node, Table *table, Table *result) {
|
||||
if (node.order_by.empty()) return;
|
||||
|
||||
auto compare_rows = [&node, &result, this](const Row &a, const Row &b) {
|
||||
for(auto order_by_col_def : node.order_by) {
|
||||
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
|
||||
ColValue *a_val = a.ith_column(col_def.order);
|
||||
ColValue *b_val = b.ith_column(col_def.order);
|
||||
|
||||
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 ? false : true;
|
||||
if (compare < 0) return order_by_col_def.ascending;
|
||||
if (compare > 0) return !order_by_col_def.ascending;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void USql::execute_offset_limit(OffsetLimitNode &node, Table *result) const {
|
||||
void USql::execute_offset_limit(OffsetLimitNode &node, Table *result) {
|
||||
if (node.offset > 0)
|
||||
result->m_rows.erase(result->m_rows.begin(),
|
||||
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(
|
||||
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());
|
||||
|
||||
affected_rows -= table->rows_count();
|
||||
|
|
@ -295,7 +295,7 @@ std::unique_ptr<Table> USql::execute_update(UpdateTableNode &node) {
|
|||
static_cast<ArithmeticalOperatorNode &>(*node.values[i]),
|
||||
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());
|
||||
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
|
||||
case NodeType::true_node:
|
||||
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> right_value = eval_value_node(table, row, filter.right.get());
|
||||
|
||||
double comparator;
|
||||
|
||||
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) ||
|
||||
(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)) {
|
||||
comparator = left_value->getDoubleValue() - right_value->getDoubleValue();
|
||||
} else if (left_value->node_type == NodeType::string_value || right_value->node_type == NodeType::string_value) {
|
||||
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 {
|
||||
// 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) {
|
||||
if (node->node_type == NodeType::database_value || node->node_type == NodeType::column_name) { // TODO sjednotit
|
||||
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) {
|
||||
} 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) {
|
||||
return eval_literal_value_node(table, row, node);
|
||||
|
||||
} else if (node->node_type == NodeType::function) {
|
||||
return eval_function_value_node(table, row, node);
|
||||
} 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
|
||||
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());
|
||||
}
|
||||
if (col_def.type == ColumnType::float_type) {
|
||||
if (col_def.type == ColumnType::float_type)
|
||||
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());
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
@ -408,7 +414,11 @@ std::unique_ptr<ValueNode> USql::eval_literal_value_node(Table *table, Row &row,
|
|||
auto *ivl = static_cast<StringValueNode *>(node);
|
||||
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");
|
||||
}
|
||||
|
|
@ -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 format = evaluatedPars[1]->getStringValue();
|
||||
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") {
|
||||
long date = evaluatedPars[0]->getIntValue();
|
||||
long date = evaluatedPars[0]->getDateValue();
|
||||
std::string format = evaluatedPars[1]->getStringValue();
|
||||
std::string formated_date = date_to_string(date, format);
|
||||
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);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
long l = ((ValueNode *) left.get())->getIntValue();
|
||||
long r = ((ValueNode *) right.get())->getIntValue();
|
||||
long l = ((ValueNode *) left.get())->getIntegerValue();
|
||||
long r = ((ValueNode *) right.get())->getIntegerValue();
|
||||
switch (node.op) {
|
||||
case ArithmeticalOperatorType::plus_operator:
|
||||
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!!");
|
||||
}
|
||||
}
|
||||
// TODO date node should support addition and substraction
|
||||
|
||||
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::vector<ColDefNode> result_tbl_col_defs{};
|
||||
result_tbl_col_defs.push_back(ColDefNode("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.push_back(ColDefNode("affected_rows", ColumnType::integer_type, 0, 1, true));
|
||||
result_tbl_col_defs.emplace_back("code", ColumnType::integer_type, 0, 1, false);
|
||||
result_tbl_col_defs.emplace_back("desc", ColumnType::varchar_type, 1, 48, false);
|
||||
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);
|
||||
|
||||
Row new_row = table_def->create_empty_row();
|
||||
new_row.setColumnValue(0, code);
|
||||
new_row.setColumnValue(1, text);
|
||||
new_row.setColumnValue(2, affected_rows);
|
||||
new_row.setIntColumnValue(0, code);
|
||||
new_row.setStringColumnValue(1, text);
|
||||
new_row.setIntColumnValue(2, affected_rows);
|
||||
table_def->add_row(new_row);
|
||||
|
||||
return std::move(table_def);
|
||||
|
|
@ -554,4 +565,5 @@ void USql::check_table_not_exists(const std::string &name) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
15
usql.h
15
usql.h
|
|
@ -13,7 +13,6 @@ class USql {
|
|||
public:
|
||||
USql() = default;
|
||||
|
||||
|
||||
std::unique_ptr<Table> execute(const std::string &command);
|
||||
|
||||
private:
|
||||
|
|
@ -32,7 +31,7 @@ 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_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);
|
||||
|
||||
|
||||
bool eval_relational_operator(const RelationalOperatorNode &filter, Table *table, Row &row) const;
|
||||
bool eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &row) const;
|
||||
std::unique_ptr<ValueNode> eval_arithmetic_operator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) const;
|
||||
static bool eval_relational_operator(const RelationalOperatorNode &filter, Table *table, Row &row) ;
|
||||
static bool eval_logical_operator(LogicalOperatorNode &node, Table *pTable, Row &row) ;
|
||||
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);
|
||||
|
|
@ -55,9 +54,9 @@ private:
|
|||
Parser m_parser;
|
||||
std::list<Table> m_tables;
|
||||
|
||||
void execute_distinct(SelectFromTableNode &node, Table *result) const;
|
||||
void execute_order_by(SelectFromTableNode &node, Table *table, Table *result) const;
|
||||
void execute_offset_limit(OffsetLimitNode &node, Table *result) const;
|
||||
static void execute_distinct(SelectFromTableNode &node, Table *result) ;
|
||||
static void execute_order_by(SelectFromTableNode &node, Table *table, Table *result) ;
|
||||
static void execute_offset_limit(OffsetLimitNode &node, Table *result) ;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
Loading…
Reference in New Issue