diff --git a/debug.lsp b/debug.lsp index 7a6cfb8..c3a3cb1 100644 --- a/debug.lsp +++ b/debug.lsp @@ -1,6 +1,19 @@ -(usql "create table data (ticker varchar(8), price float null)") -(usql "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')") -(print (usql "select ticker, price from data")) +(define create_tbl_sql "create table prices (datetime integer, symbol varchar(8), prev_close float, open float, price float, change float, change_prct varchar(16))") +(define insert_sql "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 %')") +(define select_sql "select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct from prices") + + +(print (usql create_tbl_sql)) +(print (usql insert_sql)) +(print (usql select_sql)) + +(print (usql "select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct values from prices")) + + + +;; (print (usql "create table data (ticker varchar(8), price float null)")) +;; (usql "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')") +;; (print (usql "select ticker, price from data")) ;; (read-url "https://api.nasdaq.com/api/calendar/dividends/") diff --git a/ml.cpp b/ml.cpp index 1623fda..340172c 100644 --- a/ml.cpp +++ b/ml.cpp @@ -1926,14 +1926,12 @@ MlValue throw_exception(std::vector args, MlEnvironment &env) { } MlValue usql(std::vector args, MlEnvironment &env) { + eval_args(args, env); + if (args.size() != 1) throw MlError(MlValue("usql", throw_exception), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS); - try { - return uSQL::instance().execute(args[0].as_string()); - } catch (std::exception &e) { - return MlValue::nil(); - } + return uSQL::instance().execute(args[0].as_string()); } } // namespace builtin diff --git a/ml_usql.cpp b/ml_usql.cpp index 0b607ac..0869ffd 100644 --- a/ml_usql.cpp +++ b/ml_usql.cpp @@ -19,11 +19,11 @@ MlValue uSQL::ivaluize(const usql::Table *table) { auto c = row.ithColumn(i); auto type = table->m_col_defs[i].type; if (type == ColumnType::integer_type) { - columns.push_back(MlValue((long)c->integerValue())); + columns.push_back(MlValue(c->getIntValue())); } else if (type == ColumnType::float_type) { - columns.push_back(MlValue((double)c->floatValue())); + columns.push_back(MlValue(c->getDoubleValue())); } else { - columns.push_back(MlValue::string(c->stringValue())); + columns.push_back(MlValue::string(c->getStringValue())); } } rows.push_back(columns); diff --git a/usql/CMakeLists.txt b/usql/CMakeLists.txt new file mode 100644 index 0000000..745b7aa --- /dev/null +++ b/usql/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.0) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") + + +project(usql) + +set(PROJECT_NAME usql) + +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) + +add_executable(${PROJECT_NAME} ${SOURCE}) + +target_link_libraries(${PROJECT_NAME} stdc++ m) + +target_compile_options(usql PRIVATE -g) diff --git a/usql/Radme.md b/usql/Radme.md deleted file mode 100644 index 17d4fdd..0000000 --- a/usql/Radme.md +++ /dev/null @@ -1,11 +0,0 @@ - -### TODO -- unify using of float and double keywords to double -- use long data type for int -- add exceptions -- class members should have prefix m_ -- add pipe | token -- add to_date a to_number functions -- add min and max functions -- add logging -- add const wherever should be \ No newline at end of file diff --git a/usql/Readme.md b/usql/Readme.md new file mode 100644 index 0000000..3da7ab6 --- /dev/null +++ b/usql/Readme.md @@ -0,0 +1,11 @@ + +### TODO +- save table command +- move csv generation from usql(save_table) to table class +- add exceptions +- class members should have prefix m_ +- add pipe | token +- add to_date a to_string functions +- add min and max functions, eg aggregate functions +- add logging +- add const wherever should be \ No newline at end of file diff --git a/usql/clib/date.h b/usql/clib/date.h new file mode 120000 index 0000000..a6b3df1 --- /dev/null +++ b/usql/clib/date.h @@ -0,0 +1 @@ +../../clib/date.h \ No newline at end of file diff --git a/usql/data.csv b/usql/data.csv new file mode 100644 index 0000000..177e13f --- /dev/null +++ b/usql/data.csv @@ -0,0 +1,3 @@ +Ticker,Price +FDX,257.3 +C,59.85 \ No newline at end of file diff --git a/usql/exception.cpp b/usql/exception.cpp index 2f6f388..cee6b18 100644 --- a/usql/exception.cpp +++ b/usql/exception.cpp @@ -2,7 +2,7 @@ namespace usql { -Exception::Exception(const std::string &msg) { +Exception::Exception(const std::string &msg) : std::runtime_error(msg) { cause = msg; } diff --git a/usql/exception.h b/usql/exception.h index 312f8d3..aab3ec3 100644 --- a/usql/exception.h +++ b/usql/exception.h @@ -6,7 +6,7 @@ namespace usql { -class Exception : public std::exception { +class Exception : public std::runtime_error { private: std::string cause; diff --git a/usql/lexer.cpp b/usql/lexer.cpp index a9477ee..e86787e 100644 --- a/usql/lexer.cpp +++ b/usql/lexer.cpp @@ -13,12 +13,12 @@ namespace usql { Lexer::Lexer() { k_words_regex = - "[0-9]+\\.[0-9]+|[0-9][0-9_]+[0-9]|[0-9]+|[A-Za-z]+[A-Za-z0-9_#]*|[\\(\\)\\[\\]\\{\\}]|[-\\+\\*/" + "[-+]?[0-9]+\\.[0-9]+|[-+]?[0-9][0-9_]+[0-9]|[0-9]+|[A-Za-z]+[A-Za-z0-9_#]*|[\\(\\)\\[\\]\\{\\}]|[-\\+\\*/" ",;:\?]|==|>=|<=|~=|>|<|=|;|~|\\||or|and|\n|\r|\r\n|'([^']|'')*'|\".*?\"|%.*?\n"; - k_int_regex = "[0-9]+"; - k_int_underscored_regex = "[0-9][0-9_]+[0-9]"; - k_double_regex = "[0-9]+\\.[0-9]+"; - k_identifier_regex = "[A-Za-z]+[A-Za-z0-9_#]*"; + k_int_regex = "[-+]?[0-9]+"; + k_int_underscored_regex = "[-+]?[0-9][0-9_]+[0-9]"; + k_double_regex = "[-+]?[0-9]+\\.[0-9]+"; + k_identifier_regex = "[A-Za-z]+[A-Za-z0-9_#]*"; } void Lexer::parse(const std::string &code) { @@ -156,6 +156,9 @@ namespace usql { if (token == "<=") return TokenType::lesser_equal; + if (token == "as") + return TokenType::keyword_as; + if (token == "create") return TokenType::keyword_create; @@ -195,6 +198,9 @@ namespace usql { if (token == "load") return TokenType::keyword_load; + if (token == "save") + return TokenType::keyword_save; + if (token == "not") return TokenType::keyword_not; @@ -202,7 +208,7 @@ namespace usql { return TokenType::keyword_null; if (token == "integer") - return TokenType::keyword_int; + return TokenType::keyword_integer; if (token == "float") return TokenType::keyword_float; @@ -326,6 +332,9 @@ namespace usql { case TokenType::lesser_equal: txt = "<="; break; + case TokenType::keyword_as: + txt = "as"; + break; case TokenType::keyword_create: txt = "create"; break; @@ -356,13 +365,16 @@ namespace usql { case TokenType::keyword_load: txt = "load"; break; + case TokenType::keyword_save: + txt = "save"; + break; case TokenType::keyword_not: txt = "not"; break; case TokenType::keyword_null: txt = "null"; break; - case TokenType::keyword_int: + case TokenType::keyword_integer: txt = "integer"; break; case TokenType::keyword_float: diff --git a/usql/lexer.h b/usql/lexer.h index 7fba978..30fdad9 100644 --- a/usql/lexer.h +++ b/usql/lexer.h @@ -20,12 +20,14 @@ namespace usql { greater_equal, lesser, lesser_equal, + keyword_as, keyword_create, keyword_table, keyword_where, keyword_delete, keyword_update, keyword_load, + keyword_save, keyword_from, keyword_insert, keyword_into, @@ -35,7 +37,7 @@ namespace usql { keyword_copy, keyword_not, keyword_null, - keyword_int, + keyword_integer, keyword_float, keyword_varchar, int_number, diff --git a/usql/main.cpp b/usql/main.cpp new file mode 100644 index 0000000..4f080f7 --- /dev/null +++ b/usql/main.cpp @@ -0,0 +1,52 @@ +#include "parser.h" +#include "usql.h" + +// https://dev.to/joaoh82/what-would-sqlite-look-like-if-written-in-rust-part-1-2np4 + +// parser should get m_lexer as param and table executor to be able translate * or get types or so +// podporovat create as select +// drop table + +int main(int argc, char *argv[]) { + std::vector sql_commands{ + "create table a (i integer not null, s varchar(64), f float null)", + "insert into a (i, s) values(1, upper('one'))", + "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", + "select i, s from a where i = 1", + "select i, s from a where s = 'two'", + "select i, s from a where i <= 3 and s = 'one'", + "select i, s from a where i > 0", + "delete from a where i = 4", + "select i, s from a where i > 0", + "update a set f = 9.99 where i = 3", + "select i, s, f from a where i = 3", + "update a set s = 'three', f = f + 0.01 where i = 3", + "select i, s, f from a where i = 3", + "create table data (ticker varchar(8), price float null)", + "load data from '/Users/vaclavt/Library/Mobile Documents/com~apple~CloudDocs/Development/usql/data.csv')", + "select ticker, price from data", + "select i, s, f from a where i < 300", + "create table x as select i, s, f from a where i < 300", + "select i, s, f from x 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" + }; + + + usql::USql uSql{}; + + for (auto command : sql_commands) { + std::cout << command << std::endl; + auto result = uSql.execute(command); + + result->print(); + } + + return 0; +} diff --git a/usql/ml_date.cpp b/usql/ml_date.cpp new file mode 100644 index 0000000..e6ff561 --- /dev/null +++ b/usql/ml_date.cpp @@ -0,0 +1,59 @@ + +#include "ml_date.h" + +long now() { + // get-universal-time + time_t t = std::time(0); + long int now = static_cast(t); + + return now; +} + +std::string date_to_string(const long datetime, const std::string format) { + // std::locale::global(std::locale("en-US.UTF8")); + + time_t timestamp = datetime; + char mbstr[128]; + + if (std::strftime(mbstr, sizeof(mbstr), format.c_str(), std::localtime(×tamp))) { + std::string result = {mbstr}; + return result; + } + // TODO exception here + return "invalid argument"; +} + +long string_to_date(const std::string &datestr, const std::string &format) { + // format for example "%d.%m.%Y"; + + std::istringstream in{datestr.c_str()}; + date::sys_seconds tp; + in >> date::parse(format, tp); + return tp.time_since_epoch().count(); +} + +long add_to_date(const long datetime, const long quantity, const std::string &part) { + // part is one of 'year', 'month', 'day', 'hour', 'minute' or 'second' + + // very basic implementation, just for now - no timezones DST etc + time_t base = datetime; + struct tm *tm = localtime(&base); + + if (part == "year") { + tm->tm_year += quantity; + } else if (part == "month") { + tm->tm_mon += quantity; + } else if (part == "day") { + tm->tm_mday += quantity; + } else if (part == "hour") { + tm->tm_hour += quantity; + } else if (part == "minute") { + tm->tm_min += quantity; + } else if (part == "second") { + tm->tm_sec += quantity; + } else { + // TODO exception here + } + + return mktime(tm); +} diff --git a/usql/ml_date.h b/usql/ml_date.h new file mode 100644 index 0000000..5353d23 --- /dev/null +++ b/usql/ml_date.h @@ -0,0 +1,17 @@ + +#pragma once + +#include "clib/date.h" + +#include +#include + + +long now(); + +std::string date_to_string(const long datetime, const std::string format); + +long string_to_date(const std::string &datestr, const std::string &format); + +long add_to_date(const long datetime, const long quantity, const std::string &part); + diff --git a/usql/parser.cpp b/usql/parser.cpp index a22a233..4541b4f 100644 --- a/usql/parser.cpp +++ b/usql/parser.cpp @@ -6,158 +6,218 @@ namespace usql { // TOOD handle premature eof Parser::Parser() { - lexer = Lexer{}; + m_lexer = Lexer{}; } std::unique_ptr Parser::parse(const std::string &code) { - lexer.parse(code); - // lexer.debugTokens(); + m_lexer.parse(code); + // m_lexer.debugTokens(); - if (lexer.tokenType() == TokenType::keyword_create && lexer.nextTokenType() == TokenType::keyword_table) { + if (m_lexer.tokenType() == TokenType::keyword_create && m_lexer.nextTokenType() == TokenType::keyword_table) { return parse_create_table(); } - if (lexer.tokenType() == TokenType::keyword_insert) { + if (m_lexer.tokenType() == TokenType::keyword_insert) { return parse_insert_into_table(); } - if (lexer.tokenType() == TokenType::keyword_select) { + if (m_lexer.tokenType() == TokenType::keyword_select) { return parse_select_from_table(); } - if (lexer.tokenType() == TokenType::keyword_delete) { + if (m_lexer.tokenType() == TokenType::keyword_delete) { return parse_delete_from_table(); } - if (lexer.tokenType() == TokenType::keyword_update) { + if (m_lexer.tokenType() == TokenType::keyword_update) { return parse_update_table(); } - if (lexer.tokenType() == TokenType::keyword_load) { + if (m_lexer.tokenType() == TokenType::keyword_load) { return parse_load_table(); } + if (m_lexer.tokenType() == TokenType::keyword_save) { + return parse_save_table(); + } - std::cout << "ERROR, token:" << lexer.currentToken().token_string << std::endl; + std::cout << "ERROR, token:" << m_lexer.currentToken().token_string << std::endl; return std::make_unique(NodeType::error); } std::unique_ptr Parser::parse_create_table() { std::vector cols_def{}; - lexer.skipToken(TokenType::keyword_create); - lexer.skipToken(TokenType::keyword_table); + m_lexer.skipToken(TokenType::keyword_create); + m_lexer.skipToken(TokenType::keyword_table); - if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } - std::string table_name = lexer.consumeCurrentToken().token_string; + if (m_lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } + std::string table_name = m_lexer.consumeCurrentToken().token_string; - lexer.skipToken(TokenType::open_paren); - int column_order = 0; - do { - std::string column_name; - ColumnType column_type; - int column_len{1}; - bool column_nullable{true}; + // create as select + if (m_lexer.tokenType() == TokenType::keyword_as) { + m_lexer.skipToken(TokenType::keyword_as); - // column name - if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } - column_name = lexer.consumeCurrentToken().token_string; + std::unique_ptr select = parse_select_from_table(); - // column type and optionally len - if (lexer.tokenType() == TokenType::keyword_int) { - column_type = ColumnType::integer_type; - lexer.nextToken(); - } else if (lexer.tokenType() == TokenType::keyword_float) { - column_type = ColumnType::float_type; - lexer.nextToken(); - } else if (lexer.tokenType() == TokenType::keyword_varchar) { - column_type = ColumnType::varchar_type; - lexer.nextToken(); - lexer.skipToken(TokenType::open_paren); - if (lexer.tokenType() == TokenType::int_number) { - column_len = std::stoi(lexer.consumeCurrentToken().token_string); - } else { /* TODO handle error */ } - lexer.skipToken(TokenType::close_paren); - } else { /* TODO handle error */ } + return std::make_unique(table_name, std::move(select)); + } else { + m_lexer.skipToken(TokenType::open_paren); + int column_order = 0; + do { + std::string column_name; + ColumnType column_type; + int column_len{1}; + bool column_nullable{true}; - if (lexer.tokenType() == TokenType::keyword_not) { - lexer.nextToken(); - lexer.skipToken(TokenType::keyword_null); - column_nullable = false; - } else if (lexer.tokenType() == TokenType::keyword_null) { - lexer.nextToken(); - } + // column name + if (m_lexer.tokenType() != TokenType::identifier) { + throw Exception("syntax error, expected identifier"); + } + column_name = m_lexer.consumeCurrentToken().token_string; - cols_def.push_back( - ColDefNode(column_name, column_type, column_order++, column_len, column_nullable)); + // column type and optionally len + if (m_lexer.tokenType() == TokenType::keyword_integer) { + column_type = ColumnType::integer_type; + m_lexer.nextToken(); + } else if (m_lexer.tokenType() == TokenType::keyword_float) { + column_type = ColumnType::float_type; + m_lexer.nextToken(); + } else if (m_lexer.tokenType() == TokenType::keyword_varchar) { + column_type = ColumnType::varchar_type; + m_lexer.nextToken(); + m_lexer.skipToken(TokenType::open_paren); + if (m_lexer.tokenType() == TokenType::int_number) { + column_len = std::stoi(m_lexer.consumeCurrentToken().token_string); + } else { + throw Exception("syntax error, expected int number"); + } + m_lexer.skipToken(TokenType::close_paren); + } else { + throw Exception("syntax error, column type expected"); + } - lexer.skipTokenOptional(TokenType::comma); + if (m_lexer.tokenType() == TokenType::keyword_not) { + m_lexer.nextToken(); + m_lexer.skipToken(TokenType::keyword_null); + column_nullable = false; + } else if (m_lexer.tokenType() == TokenType::keyword_null) { + m_lexer.nextToken(); + } - // TODO in future constraints + cols_def.push_back( ColDefNode(column_name, column_type, column_order++, column_len, column_nullable)); - } while (lexer.tokenType() != TokenType::close_paren); + m_lexer.skipTokenOptional(TokenType::comma); + // TODO in future constraints + } while (m_lexer.tokenType() != TokenType::close_paren); - return std::make_unique(table_name, cols_def); + return std::make_unique(table_name, cols_def); + } } std::unique_ptr Parser::parse_insert_into_table() { - std::vector exec_code{}; - std::vector cols_names{}; - std::vector cols_values{}; + std::vector column_names{}; + std::vector> column_values{}; - lexer.skipToken(TokenType::keyword_insert); - lexer.skipToken(TokenType::keyword_into); + m_lexer.skipToken(TokenType::keyword_insert); + m_lexer.skipToken(TokenType::keyword_into); // table name - if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } - std::string table_name = lexer.consumeCurrentToken().token_string; + if (m_lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } + std::string table_name = m_lexer.consumeCurrentToken().token_string; // column names - lexer.skipToken(TokenType::open_paren); + m_lexer.skipToken(TokenType::open_paren); do { - if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } - cols_names.push_back(lexer.consumeCurrentToken().token_string); + if (m_lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ } + column_names.push_back(m_lexer.consumeCurrentToken().token_string); - lexer.skipTokenOptional(TokenType::comma); - } while (lexer.tokenType() != TokenType::close_paren); - lexer.skipToken(TokenType::close_paren); + m_lexer.skipTokenOptional(TokenType::comma); + } while (m_lexer.tokenType() != TokenType::close_paren); + m_lexer.skipToken(TokenType::close_paren); - lexer.skipToken(TokenType::keyword_values); + m_lexer.skipToken(TokenType::keyword_values); // column values - lexer.skipToken(TokenType::open_paren); + m_lexer.skipToken(TokenType::open_paren); do { - cols_values.push_back(lexer.consumeCurrentToken().token_string); + auto col_value = parse_value(); + column_values.push_back(std::move(col_value)); - lexer.skipTokenOptional(TokenType::comma); - } while (lexer.tokenType() != TokenType::close_paren); - lexer.skipToken(TokenType::close_paren); + m_lexer.skipTokenOptional(TokenType::comma); + } while (m_lexer.tokenType() != TokenType::close_paren); + m_lexer.skipToken(TokenType::close_paren); - return std::make_unique(table_name, cols_names, cols_values); + return std::make_unique(table_name, column_names, std::move(column_values)); } - std::unique_ptr Parser::parse_select_from_table() { - std::vector cols_names{}; +std::unique_ptr Parser::parse_value() { + if (m_lexer.tokenType() == TokenType::int_number) { + return std::make_unique(std::stoi(m_lexer.consumeCurrentToken().token_string)); + } + if (m_lexer.tokenType() == TokenType::double_number) { + return std::make_unique(std::stof(m_lexer.consumeCurrentToken().token_string)); + } + if (m_lexer.tokenType() == TokenType::string_literal) { + return std::make_unique(m_lexer.consumeCurrentToken().token_string); + } + if (m_lexer.tokenType() == TokenType::identifier && m_lexer.nextTokenType() == TokenType::open_paren) { + // function + std::string function_name = m_lexer.consumeCurrentToken().token_string; + std::vector> pars; - lexer.skipToken(TokenType::keyword_select); - while (lexer.tokenType() != TokenType::keyword_from) { - cols_names.push_back(lexer.consumeCurrentToken().token_string); - lexer.skipTokenOptional(TokenType::comma); - } + m_lexer.skipToken(TokenType::open_paren); + while (m_lexer.tokenType() != TokenType::close_paren) { // TODO handle errors + pars.push_back(parse_value()); + m_lexer.skipTokenOptional(TokenType::comma); + } + m_lexer.skipToken(TokenType::close_paren); + return std::make_unique(function_name, std::move(pars)); + } + if (m_lexer.tokenType() == TokenType::identifier) { + std::string name = m_lexer.consumeCurrentToken().token_string; + return std::make_unique(name); + } - lexer.skipToken(TokenType::keyword_from); - std::string table_name = lexer.consumeCurrentToken().token_string; + throw Exception("Syntax error, current token: " + m_lexer.currentToken().token_string); +} - std::unique_ptr where_node = parse_where_clause(); +std::unique_ptr Parser::parse_select_from_table() { + auto cols = std::make_unique>(); -// if (lexer.tokenType() == TokenType::keyword_order_by) {} -// if (lexer.tokenType() == TokenType::keyword_offset) {} -// if (lexer.tokenType() == TokenType::keyword_limit) {} + m_lexer.skipToken(TokenType::keyword_select); - return std::make_unique(table_name, cols_names, std::move(where_node)); - } + int i = 1; + while (m_lexer.tokenType() != TokenType::keyword_from) { + auto column_value = parse_value(); + std::string column_alias; + + if (column_value->node_type == NodeType::column_name) { + column_alias = ((ColNameNode*) column_value.get())->name; + } else { + column_alias = "c" + std::to_string(i); + i++; + } + + cols->push_back(SelectColNode{std::move(column_value), column_alias}); + + m_lexer.skipTokenOptional(TokenType::comma); + } + + m_lexer.skipToken(TokenType::keyword_from); + + std::string table_name = m_lexer.consumeCurrentToken().token_string; + + std::unique_ptr where_node = parse_where_clause(); + +// if (m_lexer.tokenType() == TokenType::keyword_order_by) {} +// if (m_lexer.tokenType() == TokenType::keyword_offset) {} +// if (m_lexer.tokenType() == TokenType::keyword_limit) {} + + return std::make_unique(table_name, std::move(cols), std::move(where_node)); +} std::unique_ptr Parser::parse_delete_from_table() { - lexer.skipToken(TokenType::keyword_delete); - lexer.skipToken(TokenType::keyword_from); + m_lexer.skipToken(TokenType::keyword_delete); + m_lexer.skipToken(TokenType::keyword_from); - std::string table_name = lexer.consumeCurrentToken().token_string; + std::string table_name = m_lexer.consumeCurrentToken().token_string; std::unique_ptr where_node = parse_where_clause(); @@ -165,22 +225,22 @@ namespace usql { } std::unique_ptr Parser::parse_update_table() { - lexer.skipToken(TokenType::keyword_update); - lexer.skipTokenOptional(TokenType::keyword_table); + m_lexer.skipToken(TokenType::keyword_update); + m_lexer.skipTokenOptional(TokenType::keyword_table); - std::string table_name = lexer.consumeCurrentToken().token_string; + std::string table_name = m_lexer.consumeCurrentToken().token_string; - lexer.skipToken(TokenType::keyword_set); + m_lexer.skipToken(TokenType::keyword_set); std::vector cols_names; std::vector> values; do { - cols_names.push_back(lexer.consumeCurrentToken().token_string); - lexer.skipToken(TokenType::equal); + cols_names.push_back(m_lexer.consumeCurrentToken().token_string); + m_lexer.skipToken(TokenType::equal); std::unique_ptr left = Parser::parse_operand_node(); - if (Lexer::isArithmeticalOperator(lexer.tokenType())) { + if (Lexer::isArithmeticalOperator(m_lexer.tokenType())) { ArithmeticalOperatorType op = parse_arithmetical_operator(); std::unique_ptr right = Parser::parse_operand_node(); @@ -192,9 +252,9 @@ namespace usql { std::make_unique(ArithmeticalOperatorType::copy_value, std::move(left), std::move(right))); } - lexer.skipTokenOptional(TokenType::comma); + m_lexer.skipTokenOptional(TokenType::comma); - } while (lexer.tokenType() != TokenType::keyword_where && lexer.tokenType() != TokenType::eof); + } while (m_lexer.tokenType() != TokenType::keyword_where && m_lexer.tokenType() != TokenType::eof); std::unique_ptr where_node = parse_where_clause(); @@ -202,37 +262,51 @@ namespace usql { } std::unique_ptr Parser::parse_load_table() { - lexer.skipToken(TokenType::keyword_load); - lexer.skipTokenOptional(TokenType::keyword_into); + m_lexer.skipToken(TokenType::keyword_load); + m_lexer.skipTokenOptional(TokenType::keyword_into); - std::string table_name = lexer.consumeCurrentToken().token_string; + std::string table_name = m_lexer.consumeCurrentToken().token_string; - lexer.skipTokenOptional(TokenType::keyword_from); + m_lexer.skipTokenOptional(TokenType::keyword_from); - std::string file_name = lexer.consumeCurrentToken().token_string; + std::string file_name = m_lexer.consumeCurrentToken().token_string; return std::make_unique(table_name, file_name); } + + std::unique_ptr Parser::parse_save_table() { + m_lexer.skipToken(TokenType::keyword_save); + m_lexer.skipTokenOptional(TokenType::keyword_table); + + std::string table_name = m_lexer.consumeCurrentToken().token_string; + + m_lexer.skipTokenOptional(TokenType::keyword_into); + + std::string file_name = m_lexer.consumeCurrentToken().token_string; + + return std::make_unique(table_name, file_name); + } + std::unique_ptr Parser::parse_where_clause() { // TODO add support for multiple filters // TODO add support for parenthesis - if (lexer.tokenType() != TokenType::keyword_where) { + if (m_lexer.tokenType() != TokenType::keyword_where) { return std::make_unique(); } std::unique_ptr node; - lexer.skipToken(TokenType::keyword_where); + m_lexer.skipToken(TokenType::keyword_where); do { node = parse_relational_expression(); - if (Lexer::isLogicalOperator(lexer.tokenType())) { + if (Lexer::isLogicalOperator(m_lexer.tokenType())) { auto operation = parse_logical_operator(); std::unique_ptr node2 = parse_relational_expression(); node = std::make_unique(operation, std::move(node), std::move(node2)); } - } while (lexer.tokenType() != TokenType::eof); // until whole where clause parsed + } while (m_lexer.tokenType() != TokenType::eof); // until whole where clause parsed return node; } @@ -247,13 +321,13 @@ namespace usql { std::unique_ptr Parser::parse_operand_node() { // while not end or order or limit - auto token_type = lexer.tokenType(); - std::string tokenString = lexer.consumeCurrentToken().token_string; + auto token_type = m_lexer.tokenType(); + std::string tokenString = m_lexer.consumeCurrentToken().token_string; switch (token_type) { case TokenType::int_number: return std::make_unique(std::stoi(tokenString)); case TokenType::double_number: - return std::make_unique(std::stod(tokenString)); + return std::make_unique(std::stod(tokenString)); case TokenType::string_literal: return std::make_unique(tokenString); case TokenType::identifier: @@ -264,7 +338,7 @@ namespace usql { } RelationalOperatorType Parser::parse_relational_operator() { - auto op = lexer.consumeCurrentToken(); + auto op = m_lexer.consumeCurrentToken(); switch (op.type) { case TokenType::equal: return RelationalOperatorType::equal; @@ -284,7 +358,7 @@ namespace usql { } LogicalOperatorType Parser::parse_logical_operator() { - auto op = lexer.consumeCurrentToken(); + auto op = m_lexer.consumeCurrentToken(); switch (op.type) { case TokenType::logical_and: return LogicalOperatorType::and_operator; @@ -296,7 +370,7 @@ namespace usql { } ArithmeticalOperatorType Parser::parse_arithmetical_operator() { - auto op = lexer.consumeCurrentToken(); + auto op = m_lexer.consumeCurrentToken(); switch (op.type) { case TokenType::plus: return ArithmeticalOperatorType::plus_operator; diff --git a/usql/parser.h b/usql/parser.h index 6fcba45..9a0e91c 100644 --- a/usql/parser.h +++ b/usql/parser.h @@ -8,7 +8,6 @@ namespace usql { - enum class ColumnType { integer_type, float_type, @@ -25,13 +24,16 @@ namespace usql { relational_operator, arithmetical_operator, create_table, + create_table_as_select, insert_into, select_from, delete_from, update_table, load_table, + save_table, column_name, column_value, + function, column_def, error }; @@ -45,18 +47,17 @@ namespace usql { struct ColNameNode : Node { std::string name; - ColNameNode(const std::string col_name) : - Node(NodeType::column_name), name(col_name) {} + ColNameNode(const std::string col_name) : Node(NodeType::column_name), name(col_name) {} }; - struct ColValueNode : Node { - std::string value; + struct SelectColNode : Node { + std::unique_ptr value; + std::string name; - ColValueNode(const std::string col_value) : - Node(NodeType::column_value), value(col_value) {} + SelectColNode(std::unique_ptr column, const std::string& alias) : + Node(NodeType::column_name), value(std::move(column)), name(alias) {} }; - // TODO add order in row struct ColDefNode : Node { std::string name; ColumnType type; @@ -64,11 +65,18 @@ namespace usql { int length; bool null; - ColDefNode(const std::string col_name, const ColumnType col_type, int col_order, int col_len, bool nullable) : + ColDefNode(const std::string col_name, ColumnType col_type, int col_order, int col_len, bool nullable) : Node(NodeType::column_def), name(col_name), type(col_type), order(col_order), length(col_len), null(nullable) {} }; + struct FunctionNode : Node { + std::string function; + std::vector> params; + + FunctionNode(const std::string func_name, std::vector> pars) : + Node(NodeType::function), function(func_name), params(std::move(pars)) {} + }; struct TrueNode : Node { TrueNode() : Node(NodeType::true_node) {} @@ -77,37 +85,32 @@ namespace usql { struct ValueNode : Node { ValueNode(NodeType type) : Node(type) {} - virtual int getIntValue() = 0; - + virtual bool isNull() { return false; } + virtual long getIntValue() = 0; virtual double getDoubleValue() = 0; - virtual std::string getStringValue() = 0; virtual ~ValueNode() {}; }; struct IntValueNode : ValueNode { - int value; + long value; - IntValueNode(int value) : ValueNode(NodeType::int_value), value(value) {} + IntValueNode(long value) : ValueNode(NodeType::int_value), value(value) {} - int getIntValue() { return value; }; - - double getDoubleValue() { return (double) value; }; - - std::string getStringValue() { return std::to_string(value); } + long getIntValue() override { return value; }; + double getDoubleValue() override { return (double) value; }; + std::string getStringValue() override { return std::to_string(value); } }; - struct FloatValueNode : ValueNode { + struct DoubleValueNode : ValueNode { double value; - FloatValueNode(double value) : ValueNode(NodeType::float_value), value(value) {} + DoubleValueNode(double value) : ValueNode(NodeType::float_value), value(value) {} - int getIntValue() { return (int) value; }; - - double getDoubleValue() { return value; }; - - std::string getStringValue() { return std::to_string(value); } + long getIntValue() override { return (long) value; }; + double getDoubleValue() override { return value; }; + std::string getStringValue() override { return std::to_string(value); } }; struct StringValueNode : ValueNode { @@ -115,11 +118,9 @@ namespace usql { StringValueNode(std::string value) : ValueNode(NodeType::string_value), value(value) {} - int getIntValue() { return std::stoi(value); }; - - double getDoubleValue() { return std::stod(value); }; - - std::string getStringValue() { return value; }; + long getIntValue() override { return std::stoi(value); }; + double getDoubleValue() override { return std::stod(value); }; + std::string getStringValue() override { return value; }; }; struct DatabaseValueNode : Node { @@ -181,31 +182,38 @@ namespace usql { Node(NodeType::arithmetical_operator), op(op), left(std::move(left)), right(std::move(right)) {}; }; - struct CreateTableNode : Node { std::string table_name; std::vector cols_defs; - CreateTableNode(const std::string name, std::vector defs) : + CreateTableNode(const std::string& name, std::vector defs) : Node(NodeType::create_table), table_name(name), cols_defs(defs) {} }; struct InsertIntoTableNode : Node { - std::string table_name; - std::vector cols_names; - std::vector cols_values; + std::string table_name; + std::vector cols_names; + std::vector> cols_values; - InsertIntoTableNode(const std::string name, std::vector names, std::vector values) : - Node(NodeType::insert_into), table_name(name), cols_names(names), cols_values(values) {} + InsertIntoTableNode(const std::string name, std::vector names, std::vector> values) : + Node(NodeType::insert_into), table_name(name), cols_names(names), cols_values(std::move(values)) {} }; struct SelectFromTableNode : Node { std::string table_name; - std::vector cols_names; + std::unique_ptr> cols_names; std::unique_ptr where; - SelectFromTableNode(std::string name, std::vector names, std::unique_ptr where_clause) : - Node(NodeType::select_from), table_name(name), cols_names(names), where(std::move(where_clause)) {} + SelectFromTableNode(std::string name, std::unique_ptr> names, std::unique_ptr where_clause) : + Node(NodeType::select_from), table_name(name), cols_names(std::move(names)), where(std::move(where_clause)) {} + }; + + struct CreateTableAsSelectNode : Node { + std::string table_name; + std::unique_ptr select_table; + + CreateTableAsSelectNode(const std::string name, std::unique_ptr table) : + Node(NodeType::create_table_as_select), table_name(name), select_table(std::move(table)) {} }; struct UpdateTableNode : Node { @@ -226,16 +234,22 @@ namespace usql { LoadIntoTableNode(const std::string name, std::string file) : Node(NodeType::load_table), table_name(name), filename(file) {} + }; + struct SaveTableNode : Node { + std::string table_name; + std::string filename; + + SaveTableNode(const std::string& name, std::string file) : + Node(NodeType::save_table), table_name(name), filename(file) {} }; struct DeleteFromTableNode : Node { std::string table_name; std::unique_ptr where; - DeleteFromTableNode(const std::string name, std::unique_ptr where_clause) : + DeleteFromTableNode(const std::string& name, std::unique_ptr where_clause) : Node(NodeType::delete_from), table_name(name), where(std::move(where_clause)) {} - }; @@ -249,32 +263,23 @@ namespace usql { private: std::unique_ptr parse_create_table(); - std::unique_ptr parse_insert_into_table(); - + std::unique_ptr parse_value(); std::unique_ptr parse_select_from_table(); - std::unique_ptr parse_delete_from_table(); - std::unique_ptr parse_update_table(); - std::unique_ptr parse_load_table(); - + std::unique_ptr parse_save_table(); std::unique_ptr parse_where_clause(); - std::unique_ptr parse_operand_node(); - RelationalOperatorType parse_relational_operator(); - LogicalOperatorType parse_logical_operator(); - ArithmeticalOperatorType parse_arithmetical_operator(); private: - Lexer lexer; + Lexer m_lexer; std::unique_ptr parse_relational_expression(); - }; } \ No newline at end of file diff --git a/usql/row.cpp b/usql/row.cpp index 27f5a04..61c9537 100644 --- a/usql/row.cpp +++ b/usql/row.cpp @@ -19,13 +19,13 @@ namespace usql { for (int i = 0; i < other.m_columns.size(); i++) { if (ColIntegerValue *other_v = dynamic_cast(other.m_columns[i].get())) { - setColumnValue(i, other_v->integerValue()); + setColumnValue(i, other_v->getIntValue()); } - if (ColFloatValue *other_v = dynamic_cast(other.m_columns[i].get())) { - setColumnValue(i, other_v->floatValue()); + if (ColDoubleValue *other_v = dynamic_cast(other.m_columns[i].get())) { + setColumnValue(i, other_v->getDoubleValue()); } if (ColStringValue *other_v = dynamic_cast(other.m_columns[i].get())) { - setColumnValue(i, other_v->stringValue()); + setColumnValue(i, other_v->getStringValue()); } } } @@ -35,22 +35,52 @@ namespace usql { return *this; } - void Row::setColumnValue(int col_index, int value) { + void Row::setColumnNull(int col_index) { + m_columns[col_index] = std::make_unique(); + } + + void Row::setColumnValue(int col_index, long value) { m_columns[col_index] = std::make_unique(value); } void Row::setColumnValue(int col_index, double value) { - m_columns[col_index] = std::make_unique(value); + m_columns[col_index] = std::make_unique(value); } void Row::setColumnValue(int col_index, const std::string &value) { m_columns[col_index] = std::make_unique(value); }; + 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); + } + } + + 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::print() { for (int ci = 0; ci < m_columns.size(); ci++) { if (ci > 0) std::cout << ","; - auto v = m_columns[ci]->stringValue(); + auto v = m_columns[ci]->getStringValue(); std::cout << v; } std::cout << std::endl; diff --git a/usql/row.h b/usql/row.h index 19596b2..be8d0ff 100644 --- a/usql/row.h +++ b/usql/row.h @@ -10,67 +10,54 @@ namespace usql { struct ColValue { - virtual bool isNull() { return false; };;;; - - virtual int integerValue() { throw Exception("Not supported"); }; - - virtual double floatValue() { throw Exception("Not supported"); }; - - virtual std::string stringValue() { throw Exception("Not supported"); }; + virtual bool isNull() { return false; }; + virtual long getIntValue() { throw Exception("Not supported"); }; + virtual double getDoubleValue() { throw Exception("Not supported"); }; + virtual std::string getStringValue() { throw Exception("Not supported"); }; }; struct ColNullValue : ColValue { virtual bool isNull() { return true; }; - - virtual std::string stringValue() { return "null"; }; + virtual std::string getStringValue() { return "null"; }; }; struct ColIntegerValue : ColValue { - ColIntegerValue(int value) : m_integer(value) {}; - + ColIntegerValue(long value) : m_integer(value) {}; ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {}; - virtual int integerValue() { return m_integer; }; - - virtual double floatValue() { return (double) m_integer; }; - - virtual std::string stringValue() { return std::to_string(m_integer); }; + virtual long getIntValue() { return m_integer; }; + virtual double getDoubleValue() { return (double) m_integer; }; + virtual std::string getStringValue() { return std::to_string(m_integer); }; int m_integer; }; - struct ColFloatValue : ColValue { + struct ColDoubleValue : ColValue { - ColFloatValue(double value) : m_float(value) {}; + ColDoubleValue(double value) : m_double(value) {}; + ColDoubleValue(const ColDoubleValue &other) : m_double(other.m_double) {} - ColFloatValue(const ColFloatValue &other) : m_float(other.m_float) {} + virtual long getIntValue() { return (long) m_double; }; + virtual double getDoubleValue() { return m_double; }; + virtual std::string getStringValue() { return std::to_string(m_double); }; - virtual int integerValue() { return (int) m_float; }; - - virtual double floatValue() { return m_float; }; - - virtual std::string stringValue() { return std::to_string(m_float); }; - - double m_float; + double m_double; }; struct ColStringValue : ColValue { ColStringValue(const std::string value) : m_string(value) {}; - ColStringValue(const ColStringValue &other) : m_string(other.m_string) {}; - virtual int integerValue() { return std::stoi(m_string); }; - - virtual double floatValue() { return std::stod(m_string); }; - - virtual std::string stringValue() { return m_string; }; + virtual long getIntValue() { return std::stoi(m_string); }; + virtual double getDoubleValue() { return std::stod(m_string); }; + virtual std::string getStringValue() { return m_string; }; std::string m_string; }; @@ -80,22 +67,22 @@ namespace usql { public: Row(int cols_count); - Row(const Row &other); Row &operator=(Row other); - void setColumnValue(int col_index, int value); - + 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 setColumnValue(ColDefNode *col_def, ColValue *col_value); + void setColumnValue(ColDefNode *col_def, ValueNode *col_value); ColValue &operator[](int i) { return *m_columns[i]; } - ColValue *ithColumn(int i) { + ColValue * ithColumn(int i) const { return m_columns[i].get(); } @@ -105,4 +92,4 @@ namespace usql { std::vector> m_columns; }; -} \ No newline at end of file +} // namespace \ No newline at end of file diff --git a/usql/table.cpp b/usql/table.cpp index 373abfc..9370bd1 100644 --- a/usql/table.cpp +++ b/usql/table.cpp @@ -3,45 +3,71 @@ namespace usql { - Table::Table(const std::string name, const std::vector columns) { - m_name = name; - m_col_defs = columns; - m_rows.clear(); - } +Table::Table(const std::string name, const std::vector columns) { + m_name = name; + m_col_defs = columns; + m_rows.clear(); +} - ColDefNode Table::get_column_def(const std::string &col_name) { - auto name_cmp = [col_name](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; - } else { - throw Exception("column not exists (" + 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 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; + } else { + throw Exception("column not exists (" + col_name + ")"); + } +} - Row Table::createEmptyRow() { - return Row(columns_count()); - } +Row Table::createEmptyRow() { + return Row(columns_count()); +} - void Table::print() { - std::cout << "** " << m_name << " **" << std::endl; - for (auto row : m_rows) { - row.print(); - } - } +void Table::print() { + std::cout << "** " << m_name << " **" << std::endl; + for (auto row : m_rows) { + row.print(); + } +} - Table::Table(const Table &other) { - m_name = other.m_name; - m_col_defs = other.m_col_defs; - m_rows.clear(); // row not copied now - } +Table::Table(const Table &other) { + m_name = other.m_name; + m_col_defs = other.m_col_defs; + for(const Row& orig_row : other.m_rows) { + addCopyOfRow(orig_row); + } +} - void Table::addRow(const Row &row) { - // TODO validate for not null values - // todo validate for length etc - m_rows.push_back(row); - } +void Table::addRow(const Row &row) { + // TODO validate for not null values + // todo validate for length etc + m_rows.push_back(row); +} -} \ No newline at end of file +void Table::addCopyOfRow(const Row &row) { + // TODO validate for not null values + // todo validate for length etc + + Row new_row = createEmptyRow(); + + for(int i = 0; i < m_col_defs.size(); i++) { + ColValue *ct = row.ithColumn(i); + + if (ct->isNull()) { + new_row.setColumnNull(i); + } else { + if (m_col_defs[i].type == ColumnType::integer_type) { + new_row.setColumnValue(i, row.ithColumn(i)->getIntValue()); + } else if (m_col_defs[i].type == ColumnType::float_type) { + new_row.setColumnValue(i, row.ithColumn(i)->getDoubleValue()); + } else if (m_col_defs[i].type == ColumnType::varchar_type) { + new_row.setColumnValue(i, row.ithColumn(i)->getStringValue()); + } + } + } + m_rows.push_back(row); +} + +} // namespace \ No newline at end of file diff --git a/usql/table.h b/usql/table.h index dda6a03..2bfcb23 100644 --- a/usql/table.h +++ b/usql/table.h @@ -10,7 +10,6 @@ namespace usql { struct Table { Table(const Table &other); - Table(const std::string name, const std::vector columns); ColDefNode get_column_def(const std::string &col_name); @@ -19,6 +18,7 @@ namespace usql { Row createEmptyRow(); // TODO this means unnecessary copying void addRow(const Row &row); + void addCopyOfRow(const Row &row); void print(); diff --git a/usql/table.h.gch b/usql/table.h.gch new file mode 100644 index 0000000..b42b654 Binary files /dev/null and b/usql/table.h.gch differ diff --git a/usql/usql.cpp b/usql/usql.cpp index b1eeefd..686be4a 100644 --- a/usql/usql.cpp +++ b/usql/usql.cpp @@ -1,6 +1,7 @@ #include "usql.h" #include "exception.h" #include "csvreader.h" +#include "ml_date.h" #include #include @@ -8,9 +9,14 @@ namespace usql { std::unique_ptr USql::execute(const std::string &command) { - auto node = m_parser.parse(command); + try { + std::unique_ptr node = m_parser.parse(command); + return execute(*node); + + } catch (std::exception &e) { + return create_stmt_result_table(-1, e.what()); + } - return execute(*node); } std::unique_ptr
USql::execute(Node &node) { @@ -18,18 +24,22 @@ std::unique_ptr
USql::execute(Node &node) { switch (node.node_type) { case NodeType::create_table: return execute_create_table(static_cast(node)); - case NodeType::insert_into: - return execute_insert_into_table(static_cast(node)); - case NodeType::select_from: - return execute_select(static_cast(node)); - case NodeType::delete_from: - return execute_delete(static_cast(node)); - case NodeType::update_table: - return execute_update(static_cast(node)); - case NodeType::load_table: - return execute_load(static_cast(node)); - default: - return create_stmt_result_table(-1, "unknown statement"); + case NodeType::create_table_as_select: + return execute_create_table_as_table(static_cast(node)); + case NodeType::insert_into: + return execute_insert_into_table(static_cast(node)); + case NodeType::select_from: + return execute_select(static_cast(node)); + case NodeType::delete_from: + return execute_delete(static_cast(node)); + case NodeType::update_table: + return execute_update(static_cast(node)); + case NodeType::load_table: + return execute_load(static_cast(node)); + case NodeType::save_table: + return execute_save(static_cast(node)); + default: + return create_stmt_result_table(-1, "unknown statement"); } } @@ -43,6 +53,28 @@ std::unique_ptr
USql::execute_create_table(CreateTableNode &node) { } +std::unique_ptr
USql::execute_create_table_as_table(CreateTableAsSelectNode &node) { + // TODO check table does not exists + + auto select = execute_select((SelectFromTableNode &) *node.select_table); + + // create table + Table new_table{node.table_name, select->m_col_defs}; + m_tables.push_back(new_table); + + // copy rows + // must be here, if rows are put into new_table, they are lost during m_tables.push_table + Table *table = find_table(node.table_name); + for( Row& orig_row : select->m_rows) { + table->addCopyOfRow(orig_row); + } + + select.release(); // is it correct? hoping not to release select table here and then when releasing CreateTableAsSelectNode + + return create_stmt_result_table(0, "table created"); +} + + std::unique_ptr
USql::execute_insert_into_table(InsertIntoTableNode &node) { // TODO check column names.size = values.size @@ -55,64 +87,56 @@ std::unique_ptr
USql::execute_insert_into_table(InsertIntoTableNode &node // copy values for (size_t i = 0; i < node.cols_names.size(); i++) { ColDefNode col_def = table_def->get_column_def(node.cols_names[i].name); + auto col_value = evalValueNode(table_def, new_row, node.cols_values[i].get()); - // TODO validate value - - if (col_def.type == ColumnType::integer_type) { - new_row.setColumnValue(col_def.order, std::stoi(node.cols_values[i].value)); - } else if (col_def.type == ColumnType::float_type) { - new_row.setColumnValue(col_def.order, std::stof(node.cols_values[i].value)); - } else { - new_row.setColumnValue(col_def.order, node.cols_values[i].value); - } + new_row.setColumnValue(&col_def, col_value.get()); } // append new_row table_def->addRow(new_row); - return create_stmt_result_table(0, "insert succeded"); + return create_stmt_result_table(0, "insert succeeded"); } std::unique_ptr
USql::execute_select(SelectFromTableNode &node) { - // TODO create plan for accessing rows - // find source table Table *table = find_table(node.table_name); + // create result table std::vector result_tbl_col_defs{}; std::vector source_table_col_index{}; - int i = 0; // new column order - for (auto rc : node.cols_names) { - ColDefNode cdef = table->get_column_def(rc.name); - source_table_col_index.push_back(cdef.order); - auto col = ColDefNode(rc.name, cdef.type, i, cdef.length, cdef.null); - result_tbl_col_defs.push_back(col); + for (int i = 0; i < node.cols_names->size(); i++) { + auto [ src_tbl_col_index, rst_tbl_col_def ] = getColumnDefinition(table, &node.cols_names->operator[](i), i); - i++; + source_table_col_index.push_back(src_tbl_col_index); + result_tbl_col_defs.push_back(rst_tbl_col_def); } auto result = std::make_unique
("result", result_tbl_col_defs); + // execute access plan for (auto row = begin(table->m_rows); row != end(table->m_rows); ++row) { // eval where for row - if (evalWhere(node.where.get(), table, row)) { + if (evalWhere(node.where.get(), table, *row)) { // prepare empty row Row new_row = result->createEmptyRow(); // copy column values for (auto idx = 0; idx < result->columns_count(); idx++) { auto row_col_index = source_table_col_index[idx]; - ColValue *col_value = row->ithColumn(row_col_index); - if (result_tbl_col_defs[idx].type == ColumnType::integer_type) - new_row.setColumnValue(idx, - ((ColIntegerValue *) col_value)->integerValue()); - if (result_tbl_col_defs[idx].type == ColumnType::float_type) - new_row.setColumnValue(idx, col_value->floatValue()); - if (result_tbl_col_defs[idx].type == ColumnType::varchar_type) - new_row.setColumnValue(idx, col_value->stringValue()); + + if (row_col_index == -1) { // TODO introduce constant here + auto evaluated_value = evalValueNode(table, *row, node.cols_names->operator[](idx).value.get()); + ValueNode *col_value = evaluated_value.get(); + + new_row.setColumnValue(&result_tbl_col_defs[idx], col_value); + } else { + ColValue *col_value = row->ithColumn(row_col_index); + new_row.setColumnValue(&result_tbl_col_defs[idx], col_value); + } } // add row to result @@ -123,17 +147,38 @@ std::unique_ptr
USql::execute_select(SelectFromTableNode &node) { return std::move(result); } +std::tuple USql::getColumnDefinition(Table *table, SelectColNode *select_col_node, int col_order ) { + std::string new_col_name = select_col_node->name; + + if (select_col_node->value->node_type == NodeType::column_name) { + ColDefNode src_cdef = table->get_column_def(new_col_name); + ColDefNode cdef = ColDefNode{new_col_name, src_cdef.type, col_order, src_cdef.length, src_cdef.null}; + return std::make_tuple(src_cdef.order, cdef); + + } else if (select_col_node->value->node_type == NodeType::function) { + auto node = static_cast(select_col_node->value.get()); + + if (node->function == "to_string") { + ColDefNode cdef = ColDefNode{new_col_name, ColumnType::varchar_type, col_order, 64, true}; + return std::make_tuple(-1, cdef); + } else if (node->function == "to_date") { + ColDefNode cdef = ColDefNode{new_col_name, ColumnType::integer_type, col_order, 1, true}; + return std::make_tuple(-1, cdef); + } + throw Exception("Unsupported function"); + } + throw Exception("Unsupported node type"); +} + std::unique_ptr
USql::execute_delete(DeleteFromTableNode &node) { - // TODO create plan for accessing rows - // find source table Table *table = find_table(node.table_name); // execute access plan auto it = table->m_rows.begin(); for (; it != table->m_rows.end();) { - if (evalWhere(node.where.get(), table, it)) { + if (evalWhere(node.where.get(), table, *it)) { // TODO this can be really expensive operation it = table->m_rows.erase(it); } else { @@ -141,38 +186,25 @@ std::unique_ptr
USql::execute_delete(DeleteFromTableNode &node) { } } - return create_stmt_result_table(0, "delete succeded"); + return create_stmt_result_table(0, "delete succeeded"); } std::unique_ptr
USql::execute_update(UpdateTableNode &node) { - // TODO create plan for accessing rows - // find source table Table *table = find_table(node.table_name); // execute access plan for (auto row = begin(table->m_rows); row != end(table->m_rows); ++row) { // eval where for row - if (evalWhere(node.where.get(), table, row)) { + if (evalWhere(node.where.get(), table, *row)) { int i = 0; - for (auto col : node.cols_names) { - // TODO cache it like in select - ColDefNode cdef = table->get_column_def(col.name); + for (const auto& col : node.cols_names) { + ColDefNode col_def = table->get_column_def(col.name); // TODO cache it like in select + std::unique_ptr new_val = evalArithmeticOperator(col_def.type, + static_cast(*node.values[i]), table, *row); - std::unique_ptr new_val = evalArithmetic(cdef.type, - static_cast(*node.values[i]), - table, row); - - if (cdef.type == ColumnType::integer_type) { - row->setColumnValue(cdef.order, new_val->getIntValue()); - } else if (cdef.type == ColumnType::float_type) { - row->setColumnValue(cdef.order, new_val->getDoubleValue()); - } else if (cdef.type == ColumnType::varchar_type) { - row->setColumnValue(cdef.order, new_val->getStringValue()); - } else { - throw Exception("Implement me!"); - } + row->setColumnValue(&col_def, new_val.get()); i++; } } @@ -208,7 +240,7 @@ std::unique_ptr
USql::execute_load(LoadIntoTableNode &node) { // TODO validate value if (col_def.type == ColumnType::integer_type) { - new_row.setColumnValue(col_def.order, std::stoi(csv_line[i])); + new_row.setColumnValue(col_def.order, std::stol(csv_line[i])); } else if (col_def.type == ColumnType::float_type) { new_row.setColumnValue(col_def.order, std::stof(csv_line[i])); } else { @@ -224,154 +256,230 @@ std::unique_ptr
USql::execute_load(LoadIntoTableNode &node) { } -bool USql::evalWhere(Node *where, Table *table, - std::vector>::iterator &row) const { +std::unique_ptr
USql::execute_save(SaveTableNode &node) { + // find source table + Table *table_def = find_table(node.table_name); + + // header + std::string out_string; + for(int i = 0; i < table_def->m_col_defs.size(); i++) { + if (i > 0) out_string += ","; + out_string += table_def->m_col_defs[i].name; + } + + // rows + for (auto it = table_def->m_rows.begin() + 1; it != table_def->m_rows.end(); ++it) { + std::string csv_line; + for(int i = 0; i < table_def->m_col_defs.size(); i++) { + if (i > 0) csv_line += ","; + + auto col = it->ithColumn(i); + if (!col->isNull()) { + csv_line += col->getStringValue(); // TODO handle enclosing commas etc + } + } + out_string += "\n"; + out_string += csv_line; + } + + // save data + std::ofstream file(node.filename); + file << out_string; + file.close(); + + return create_stmt_result_table(0, "save succeeded"); +} + + +bool USql::evalWhere(Node *where, Table *table, Row &row) const { switch (where->node_type) { // no where clause case NodeType::true_node: return true; - case NodeType::relational_operator: // just one condition + case NodeType::relational_operator: // just one condition return evalRelationalOperator(*((RelationalOperatorNode *) where), table, row); - case NodeType::logical_operator: - return evalLogicalOperator(*((LogicalOperatorNode *) where), table, row); - default: - throw Exception("Wrong node type"); + case NodeType::logical_operator: + return evalLogicalOperator(*((LogicalOperatorNode *) where), table, row); + default: + throw Exception("Wrong node type"); } return false; } -bool USql::evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, - std::vector>::iterator &row) const { - std::unique_ptr left_value = evalNode(table, row, filter.left.get()); - std::unique_ptr right_value = evalNode(table, row, filter.right.get()); +bool USql::evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, Row &row) const { + std::unique_ptr left_value = evalValueNode(table, row, filter.left.get()); + std::unique_ptr right_value = evalValueNode(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(); - } 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)) { + } 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) { + } 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 { // TODO throw exception } - switch (filter.op) { case RelationalOperatorType::equal: return comparator == 0.0; - case RelationalOperatorType::not_equal: - return comparator != 0.0; - case RelationalOperatorType::greater: - return comparator > 0.0; - case RelationalOperatorType::greater_equal: - return comparator >= 0.0; - case RelationalOperatorType::lesser: - return comparator < 0.0; - case RelationalOperatorType::lesser_equal: - return comparator <= 0.0; + case RelationalOperatorType::not_equal: + return comparator != 0.0; + case RelationalOperatorType::greater: + return comparator > 0.0; + case RelationalOperatorType::greater_equal: + return comparator >= 0.0; + case RelationalOperatorType::lesser: + return comparator < 0.0; + case RelationalOperatorType::lesser_equal: + return comparator <= 0.0; } throw Exception("invalid relational operator"); - } -std::unique_ptr -USql::evalNode(Table *table, std::vector>::iterator &row, Node *node) const { - if (node->node_type == NodeType::database_value) { - DatabaseValueNode *dvl = static_cast(node); - ColDefNode col_def = table->get_column_def( - dvl->col_name); // TODO optimize it to just get this def once - auto db_value = row->ithColumn(col_def.order); +std::unique_ptr USql::evalValueNode(Table *table, Row &row, Node *node) { + if (node->node_type == NodeType::database_value || node->node_type == NodeType::column_name) { // TODO sjednotit + return evalDatabaseValueNode(table, row, node); - if (col_def.type == ColumnType::integer_type) { - return std::make_unique(db_value->integerValue()); - } - if (col_def.type == ColumnType::float_type) { - return std::make_unique(db_value->floatValue()); - } - if (col_def.type == ColumnType::varchar_type) { - return std::make_unique(db_value->stringValue()); - } + } else if (node->node_type == NodeType::int_value || node->node_type == NodeType::float_value || node->node_type == NodeType::string_value) { + return evalLiteralValueNode(table, row, node); - } else if (node->node_type == NodeType::int_value) { - IntValueNode *ivl = static_cast(node); + } else if (node->node_type == NodeType::function) { + return evalFunctionValueNode(table, row, node); + } + throw Exception("unsupported node type"); +} + + +std::unique_ptr USql::evalDatabaseValueNode(Table *table, Row &row, Node *node) { + auto *dvl = static_cast(node); + ColDefNode col_def = table->get_column_def( dvl->col_name); // TODO optimize it to just get this def once + auto db_value = row.ithColumn(col_def.order); + + if (col_def.type == ColumnType::integer_type) { + return std::make_unique(db_value->getIntValue()); + } + if (col_def.type == ColumnType::float_type) { + return std::make_unique(db_value->getDoubleValue()); + } + if (col_def.type == ColumnType::varchar_type) { + return std::make_unique(db_value->getStringValue()); + } + throw Exception("unknown database value type"); +} + + +std::unique_ptr USql::evalLiteralValueNode(Table *table, Row &row, Node *node) { + if (node->node_type == NodeType::int_value) { + auto *ivl = static_cast(node); return std::make_unique(ivl->value); } else if (node->node_type == NodeType::float_value) { - FloatValueNode *ivl = static_cast(node); - return std::make_unique(ivl->value); + auto *ivl = static_cast(node); + return std::make_unique(ivl->value); } else if (node->node_type == NodeType::string_value) { - StringValueNode *ivl = static_cast(node); + auto *ivl = static_cast(node); return std::make_unique(ivl->value); + } throw Exception("invalid type"); } -bool USql::evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, - std::vector>::iterator &iter) const { - bool left = evalRelationalOperator(static_cast(*node.left), pTable, iter); +std::unique_ptr USql::evalFunctionValueNode(Table *table, Row &row, Node *node) { + auto *fnc = static_cast(node); - if ((node.op == LogicalOperatorType::and_operator && !left) || - (node.op == LogicalOperatorType::or_operator && left)) + std::vector> evaluatedPars; + for(auto & param : fnc->params) { + evaluatedPars.push_back(evalValueNode(table, row, param.get())); + } + + // TODO use some enum + if (fnc->function == "lower") { + std::string str = evaluatedPars[0]->getStringValue(); + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); }); + return std::make_unique(str); + } + if (fnc->function == "upper") { + std::string str = evaluatedPars[0]->getStringValue(); + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) -> unsigned char { return std::toupper(c); }); + return std::make_unique(str); + } + + if (fnc->function == "to_date") { + std::string date = evaluatedPars[0]->getStringValue(); + std::string format = evaluatedPars[1]->getStringValue(); + long epoch_time = string_to_date(date, format); + return std::make_unique(epoch_time); + } + if (fnc->function == "to_string") { + long date = evaluatedPars[0]->getIntValue(); + std::string format = evaluatedPars[1]->getStringValue(); + std::string formated_date = date_to_string(date, format); + return std::make_unique(formated_date); + } + + throw Exception("invalid function"); +} + + +bool USql::evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, Row &row) const { + bool left = evalRelationalOperator(static_cast(*node.left), pTable, row); + + if ((node.op == LogicalOperatorType::and_operator && !left) || (node.op == LogicalOperatorType::or_operator && left)) return left; - bool right = evalRelationalOperator(static_cast(*node.right), pTable, iter); + bool right = evalRelationalOperator(static_cast(*node.right), pTable, row); return right; } -std::unique_ptr -USql::evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, - std::vector>::iterator &row) const { +std::unique_ptr USql::evalArithmeticOperator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) const { if (node.op == ArithmeticalOperatorType::copy_value) { - return evalNode(table, row, node.left.get()); + return evalValueNode(table, row, node.left.get()); } - std::unique_ptr left = evalNode(table, row, node.left.get()); - std::unique_ptr right = evalNode(table, row, node.right.get()); + std::unique_ptr left = evalValueNode(table, row, node.left.get()); + std::unique_ptr right = evalValueNode(table, row, node.right.get()); if (outType == ColumnType::float_type) { double l = ((ValueNode *) left.get())->getDoubleValue(); double r = ((ValueNode *) right.get())->getDoubleValue(); switch (node.op) { case ArithmeticalOperatorType::plus_operator: - return std::make_unique(l + r); - case ArithmeticalOperatorType::minus_operator: - return std::make_unique(l - r); - case ArithmeticalOperatorType::multiply_operator: - return std::make_unique(l * r); - case ArithmeticalOperatorType::divide_operator: - return std::make_unique(l / r); - default: - throw Exception("implement me!!"); + return std::make_unique(l + r); + case ArithmeticalOperatorType::minus_operator: + return std::make_unique(l - r); + case ArithmeticalOperatorType::multiply_operator: + return std::make_unique(l * r); + case ArithmeticalOperatorType::divide_operator: + return std::make_unique(l / r); + default: + throw Exception("implement me!!"); } } else if (outType == ColumnType::integer_type) { - int l = ((ValueNode *) left.get())->getIntValue(); - int r = ((ValueNode *) right.get())->getIntValue(); + long l = ((ValueNode *) left.get())->getIntValue(); + long r = ((ValueNode *) right.get())->getIntValue(); switch (node.op) { case ArithmeticalOperatorType::plus_operator: return std::make_unique(l + r); - case ArithmeticalOperatorType::minus_operator: - return std::make_unique(l - r); - case ArithmeticalOperatorType::multiply_operator: - return std::make_unique(l * r); - case ArithmeticalOperatorType::divide_operator: - return std::make_unique(l / r); - default: - throw Exception("implement me!!"); + case ArithmeticalOperatorType::minus_operator: + return std::make_unique(l - r); + case ArithmeticalOperatorType::multiply_operator: + return std::make_unique(l * r); + case ArithmeticalOperatorType::divide_operator: + return std::make_unique(l / r); + default: + throw Exception("implement me!!"); } } else if (outType == ColumnType::varchar_type) { @@ -380,9 +488,8 @@ USql::evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table * switch (node.op) { case ArithmeticalOperatorType::plus_operator: return std::make_unique(l + r); - - default: - throw Exception("implement me!!"); + default: + throw Exception("implement me!!"); } } @@ -390,19 +497,7 @@ USql::evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table * } - -Table *USql::find_table(const std::string name) { - auto name_cmp = [name](const Table& t) { return t.m_name == name; }; - auto table_def = std::find_if(begin(m_tables), end(m_tables), name_cmp); - if (table_def != std::end(m_tables)) { - return table_def.operator->(); - } else { - throw Exception("table not found (" + name + ")"); - } -} - - -std::unique_ptr
USql::create_stmt_result_table(int code, std::string text) { +std::unique_ptr
USql::create_stmt_result_table(long code, const std::string& text) { std::vector 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, 255, false)); @@ -417,4 +512,16 @@ std::unique_ptr
USql::create_stmt_result_table(int code, std::string text return std::move(table_def); } -} \ No newline at end of file + + +Table *USql::find_table(const std::string &name) { + auto name_cmp = [name](const Table& t) { return t.m_name == name; }; + auto table_def = std::find_if(begin(m_tables), end(m_tables), name_cmp); + if (table_def != std::end(m_tables)) { + return table_def.operator->(); + } else { + throw Exception("table not found (" + name + ")"); + } +} + +} // namespace \ No newline at end of file diff --git a/usql/usql.h b/usql/usql.h index 9173b50..50ffaf2 100644 --- a/usql/usql.h +++ b/usql/usql.h @@ -4,13 +4,15 @@ #include "table.h" #include +#include namespace usql { class USql { public: - USql() {}; + USql() = default; + std::unique_ptr
execute(const std::string &command); @@ -18,41 +20,37 @@ private: std::unique_ptr
execute(Node &node); std::unique_ptr
execute_create_table(CreateTableNode &node); - + std::unique_ptr
execute_create_table_as_table(CreateTableAsSelectNode &node); std::unique_ptr
execute_insert_into_table(InsertIntoTableNode &node); - std::unique_ptr
execute_select(SelectFromTableNode &node); - std::unique_ptr
execute_delete(DeleteFromTableNode &node); - std::unique_ptr
execute_update(UpdateTableNode &node); - std::unique_ptr
execute_load(LoadIntoTableNode &node); - - Table *find_table(const std::string name); - - std::unique_ptr
create_stmt_result_table(int code, std::string text); + std::unique_ptr
execute_save(SaveTableNode &node); private: - bool evalWhere(Node *where, Table *table, - std::vector>::iterator &row) const; + bool evalWhere(Node *where, Table *table, Row &row) const; - std::unique_ptr evalNode(Table *table, std::vector>::iterator &row, - Node *node) const; + static std::unique_ptr evalValueNode(Table *table, Row &row, Node *node); + static std::unique_ptr evalDatabaseValueNode(Table *table, Row &row, Node *node); + static std::unique_ptr evalLiteralValueNode(Table *table, Row &row, Node *node); + static std::unique_ptr evalFunctionValueNode(Table *table, Row &row, Node *node); - bool evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, - std::vector>::iterator &row) const; - bool evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, - std::vector>::iterator &iter) const; + bool evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, Row &row) const; + bool evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, Row &row) const; + std::unique_ptr evalArithmeticOperator(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, Row &row) const; + + + static std::unique_ptr
create_stmt_result_table(long code, const std::string& text); + static std::tuple getColumnDefinition(Table *table, SelectColNode *select_col_node, int col_order) ; + Table *find_table(const std::string &name); - std::unique_ptr evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, - std::vector>::iterator &row) const; private: Parser m_parser; - std::vector
m_tables; + std::list
m_tables; }; -} \ No newline at end of file +} // namespace \ No newline at end of file diff --git a/utils/local_install.sh b/utils/local_install.sh index b0e7f19..cc911fc 100755 --- a/utils/local_install.sh +++ b/utils/local_install.sh @@ -1,7 +1,7 @@ #!/bin/sh gcc -std=c99 -c -O2 -o linenoise.o clib/linenoise.c -c++ -c -O2 -I/usr/local/opt/openssl/include -Iclib --std=c++17 ml.cpp ml_io.cpp ml_date.cpp ml_string.cpp ml_util.cpp ml_profiler.cpp clib/json11.cpp clib/csvparser.cpp clib/sslclient.cpp clib/printf.cpp +c++ -c -O2 -I/usr/local/opt/openssl/include -Iclib --std=c++17 ml.cpp ml_io.cpp ml_date.cpp ml_string.cpp ml_util.cpp ml_profiler.cpp ml_usql.cpp clib/json11.cpp clib/csvparser.cpp clib/sslclient.cpp clib/printf.cpp usql/exception.cpp usql/lexer.cpp usql/parser.cpp usql/usql.cpp usql/table.cpp usql/table.h usql/row.cpp usql/csvreader.cpp usql/usql.cpp c++ -o ml -O2 -L/usr/local/lib -L/usr/local/opt/openssl/lib -lm -lstdc++ -lcrypto -lssl *.o cp stdlib/*.lsp /usr/local/var/mlisp/ diff --git a/utils/remote_install.sh b/utils/remote_install.sh index eebef65..3b40fc0 100755 --- a/utils/remote_install.sh +++ b/utils/remote_install.sh @@ -24,7 +24,7 @@ fi echo "Building ml" ssh -p 5333 root@46.28.109.184 "cd /tmp/mlisp; gcc -std=c99 -c -O2 -o linenoise.o clib/linenoise.c" -ssh -p 5333 root@46.28.109.184 "cd /tmp/mlisp; c++ -c -O2 -I/usr/local/opt/openssl/include -Iclib --std=c++17 ml.cpp ml_io.cpp ml_date.cpp ml_string.cpp ml_util.cpp ml_profiler.cpp clib/json11.cpp clib/csvparser.cpp clib/sslclient.cpp clib/printf.cpp" +ssh -p 5333 root@46.28.109.184 "cd /tmp/mlisp; c++ -c -O2 -I/usr/local/opt/openssl/include -Iclib --std=c++17 ml.cpp ml_io.cpp ml_date.cpp ml_string.cpp ml_util.cpp ml_profiler.cpp ml_usql.cpp clib/json11.cpp clib/csvparser.cpp clib/sslclient.cpp clib/printf.cpp usql/exception.cpp usql/lexer.cpp usql/parser.cpp usql/usql.cpp usql/table.cpp usql/table.h usql/row.cpp usql/csvreader.cpp usql/usql.cpp" ssh -p 5333 root@46.28.109.184 "cd /tmp/mlisp; c++ -o ml -O2 -L/usr/local/lib -L/usr/local/opt/openssl/lib -lm -lstdc++ -lcrypto -lssl *.o"