From 281f7d8700c194b1a06531bef5587c2983d227f6 Mon Sep 17 00:00:00 2001 From: VaclavT Date: Tue, 27 Jul 2021 18:07:20 +0200 Subject: [PATCH] usql update --- debug.lsp | 2 +- ml_usql.cpp | 2 +- usql/Readme.md | 12 ++-- usql/lexer.cpp | 6 ++ usql/lexer.h | 1 + usql/main.cpp | 9 ++- usql/parser.cpp | 86 +++++++++++++------------ usql/parser.h | 30 +++++++-- usql/row.cpp | 2 +- usql/row.h | 2 +- usql/table.cpp | 118 +++++++++++++++++++++++++++++----- usql/table.h | 16 +++-- usql/usql.cpp | 164 +++++++++++++++++++++--------------------------- usql/usql.h | 9 ++- 14 files changed, 290 insertions(+), 169 deletions(-) diff --git a/debug.lsp b/debug.lsp index c3a3cb1..f546a30 100644 --- a/debug.lsp +++ b/debug.lsp @@ -7,7 +7,7 @@ (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 "select to_string(datetime, '%d.%m.%Y %H:%M:%S'), symbol, prev_close, open, price, change, change_prct from prices")) diff --git a/ml_usql.cpp b/ml_usql.cpp index 0869ffd..d7825f3 100644 --- a/ml_usql.cpp +++ b/ml_usql.cpp @@ -16,7 +16,7 @@ MlValue uSQL::ivaluize(const usql::Table *table) { for (auto row : table->m_rows) { columns.clear(); for (int i = 0; i < table->columns_count(); i++) { - auto c = row.ithColumn(i); + auto c = row.ith_column(i); auto type = table->m_col_defs[i].type; if (type == ColumnType::integer_type) { columns.push_back(MlValue(c->getIntValue())); diff --git a/usql/Readme.md b/usql/Readme.md index 3da7ab6..16abf33 100644 --- a/usql/Readme.md +++ b/usql/Readme.md @@ -1,11 +1,11 @@ ### TODO -- save table command -- move csv generation from usql(save_table) to table class -- add exceptions +- drop table command +- add affecter rows and timing into result table +- add exceptions and rename it to UsqlException - class members should have prefix m_ +- maybe to create iterator on table - add pipe | token -- add to_date a to_string functions -- add min and max functions, eg aggregate functions +- add count min and max functions, eg aggregate functions - add logging -- add const wherever should be \ No newline at end of file +- add const wherever should be diff --git a/usql/lexer.cpp b/usql/lexer.cpp index e86787e..adac66c 100644 --- a/usql/lexer.cpp +++ b/usql/lexer.cpp @@ -162,6 +162,9 @@ namespace usql { if (token == "create") return TokenType::keyword_create; + if (token == "drop") + return TokenType::keyword_drop; + if (token == "where") return TokenType::keyword_where; @@ -338,6 +341,9 @@ namespace usql { case TokenType::keyword_create: txt = "create"; break; + case TokenType::keyword_drop: + txt = "drop"; + break; case TokenType::keyword_where: txt = "where"; break; diff --git a/usql/lexer.h b/usql/lexer.h index 30fdad9..2fbabb9 100644 --- a/usql/lexer.h +++ b/usql/lexer.h @@ -22,6 +22,7 @@ namespace usql { lesser_equal, keyword_as, keyword_create, + keyword_drop, keyword_table, keyword_where, keyword_delete, diff --git a/usql/main.cpp b/usql/main.cpp index 4f080f7..ef7655a 100644 --- a/usql/main.cpp +++ b/usql/main.cpp @@ -9,8 +9,11 @@ int main(int argc, char *argv[]) { std::vector sql_commands{ + "load prices from 'prices.csv'", "create table a (i integer not null, s varchar(64), f float null)", "insert into a (i, s) values(1, upper('one'))", + "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'))", @@ -34,8 +37,12 @@ int main(int argc, char *argv[]) { "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", + "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" + "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))", + "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 from prices" }; diff --git a/usql/parser.cpp b/usql/parser.cpp index 4541b4f..2f926dc 100644 --- a/usql/parser.cpp +++ b/usql/parser.cpp @@ -13,27 +13,22 @@ namespace usql { m_lexer.parse(code); // m_lexer.debugTokens(); - if (m_lexer.tokenType() == TokenType::keyword_create && m_lexer.nextTokenType() == TokenType::keyword_table) { + if (m_lexer.tokenType() == TokenType::keyword_create && m_lexer.nextTokenType() == TokenType::keyword_table) return parse_create_table(); - } - if (m_lexer.tokenType() == TokenType::keyword_insert) { + if (m_lexer.tokenType() == TokenType::keyword_insert) return parse_insert_into_table(); - } - if (m_lexer.tokenType() == TokenType::keyword_select) { + if (m_lexer.tokenType() == TokenType::keyword_select) return parse_select_from_table(); - } - if (m_lexer.tokenType() == TokenType::keyword_delete) { + if (m_lexer.tokenType() == TokenType::keyword_delete) return parse_delete_from_table(); - } - if (m_lexer.tokenType() == TokenType::keyword_update) { + if (m_lexer.tokenType() == TokenType::keyword_update) return parse_update_table(); - } - if (m_lexer.tokenType() == TokenType::keyword_load) { + if (m_lexer.tokenType() == TokenType::keyword_load) return parse_load_table(); - } - if (m_lexer.tokenType() == TokenType::keyword_save) { + if (m_lexer.tokenType() == TokenType::keyword_save) return parse_save_table(); - } + if (m_lexer.tokenType() == TokenType::keyword_drop) + return parse_drop_table(); std::cout << "ERROR, token:" << m_lexer.currentToken().token_string << std::endl; return std::make_unique(NodeType::error); @@ -110,7 +105,41 @@ namespace usql { } } + std::unique_ptr Parser::parse_load_table() { + m_lexer.skipToken(TokenType::keyword_load); + m_lexer.skipTokenOptional(TokenType::keyword_into); + std::string table_name = m_lexer.consumeCurrentToken().token_string; + + m_lexer.skipTokenOptional(TokenType::keyword_from); + + 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_drop_table() { + m_lexer.skipToken(TokenType::keyword_drop); + m_lexer.skipTokenOptional(TokenType::keyword_table); + + std::string table_name = m_lexer.consumeCurrentToken().token_string; + + return std::make_unique(table_name); + } + std::unique_ptr Parser::parse_insert_into_table() { std::vector column_names{}; std::vector> column_values{}; @@ -261,33 +290,6 @@ std::unique_ptr Parser::parse_select_from_table() { return std::make_unique(table_name, cols_names, std::move(values), std::move(where_node)); } - std::unique_ptr Parser::parse_load_table() { - m_lexer.skipToken(TokenType::keyword_load); - m_lexer.skipTokenOptional(TokenType::keyword_into); - - std::string table_name = m_lexer.consumeCurrentToken().token_string; - - m_lexer.skipTokenOptional(TokenType::keyword_from); - - 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 @@ -332,6 +334,8 @@ std::unique_ptr Parser::parse_select_from_table() { return std::make_unique(tokenString); case TokenType::identifier: return std::make_unique(tokenString); + case TokenType::keyword_null: + return std::make_unique(); default:; throw Exception("Unknown operand node"); } diff --git a/usql/parser.h b/usql/parser.h index 9a0e91c..ead5e65 100644 --- a/usql/parser.h +++ b/usql/parser.h @@ -1,7 +1,7 @@ #pragma once #include "lexer.h" -#include +#include "exception.h" #include #include @@ -16,6 +16,7 @@ namespace usql { enum class NodeType { true_node, + null_value, int_value, float_value, string_value, @@ -31,6 +32,7 @@ namespace usql { update_table, load_table, save_table, + drop_table, column_name, column_value, function, @@ -93,6 +95,17 @@ namespace usql { virtual ~ValueNode() {}; }; + struct NullValueNode : ValueNode { + + NullValueNode() : ValueNode(NodeType::null_value) {} + + bool isNull() override { return true; } + + long getIntValue() 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"); }; + }; + struct IntValueNode : ValueNode { long value; @@ -244,6 +257,12 @@ namespace usql { Node(NodeType::save_table), table_name(name), filename(file) {} }; + struct DropTableNode : Node { + std::string table_name; + + DropTableNode(const std::string& name) : Node(NodeType::drop_table), table_name(name) {} + }; + struct DeleteFromTableNode : Node { std::string table_name; std::unique_ptr where; @@ -263,15 +282,18 @@ namespace usql { private: std::unique_ptr parse_create_table(); + std::unique_ptr parse_load_table(); + std::unique_ptr parse_save_table(); + std::unique_ptr parse_drop_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(); + std::unique_ptr parse_value(); RelationalOperatorType parse_relational_operator(); LogicalOperatorType parse_logical_operator(); ArithmeticalOperatorType parse_arithmetical_operator(); diff --git a/usql/row.cpp b/usql/row.cpp index 61c9537..9e77b33 100644 --- a/usql/row.cpp +++ b/usql/row.cpp @@ -6,7 +6,7 @@ namespace usql { Row::Row(int cols_count) { m_columns.reserve(cols_count); for (int i = 0; i < cols_count; i++) { - m_columns.push_back(std::make_unique()); + m_columns.push_back(std::make_unique()); } } diff --git a/usql/row.h b/usql/row.h index be8d0ff..a94d797 100644 --- a/usql/row.h +++ b/usql/row.h @@ -82,7 +82,7 @@ namespace usql { return *m_columns[i]; } - ColValue * ithColumn(int i) const { + ColValue * ith_column(int i) const { return m_columns[i].get(); } diff --git a/usql/table.cpp b/usql/table.cpp index 9370bd1..db175d1 100644 --- a/usql/table.cpp +++ b/usql/table.cpp @@ -1,5 +1,7 @@ #include "table.h" +#include "csvreader.h" + namespace usql { @@ -20,10 +22,71 @@ ColDefNode Table::get_column_def(const std::string &col_name) { } -Row Table::createEmptyRow() { +Row Table::create_empty_row() { return Row(columns_count()); } +std::string Table::csv_string() { + // header + std::string out_string; + for(int i = 0; i < m_col_defs.size(); i++) { + if (i > 0) out_string += ","; + out_string += m_col_defs[i].name; + } + + // rows + for (auto it = m_rows.begin(); it != m_rows.end(); ++it) { + 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); + if (!col->isNull()) { + csv_line += col->getStringValue(); // TODO handle enclosing commas etc + } + } + out_string += csv_line; + } + + return out_string; +} + +int Table::load_csv_string(const std::string &content) { + int row_cnt = 0; + + CsvReader csvparser{}; + auto csv = csvparser.parseCSV(content); + + std::vector &colDefs = m_col_defs; + + for (auto it = csv.begin() + 1; it != csv.end(); ++it) { + std::vector csv_line = *it; + + // prepare empty new_row + Row new_row = create_empty_row(); + + // copy values + 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])); + } 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]); + } + } + + // append new_row + add_row(new_row); + + row_cnt++; + } + + return row_cnt; +} void Table::print() { std::cout << "** " << m_name << " **" << std::endl; @@ -36,38 +99,63 @@ 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); + add_copy_of_row(orig_row); } } -void Table::addRow(const Row &row) { - // TODO validate for not null values - // todo validate for length etc +void Table::add_row(const Row &row) { + validate_row(row); m_rows.push_back(row); } -void Table::addCopyOfRow(const Row &row) { - // TODO validate for not null values - // todo validate for length etc - - Row new_row = createEmptyRow(); +void Table::add_copy_of_row(const Row &row) { + Row new_row = create_empty_row(); for(int i = 0; i < m_col_defs.size(); i++) { - ColValue *ct = row.ithColumn(i); + ColValue *ct = row.ith_column(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()); + new_row.setColumnValue(i, row.ith_column(i)->getIntValue()); } else if (m_col_defs[i].type == ColumnType::float_type) { - new_row.setColumnValue(i, row.ithColumn(i)->getDoubleValue()); + new_row.setColumnValue(i, row.ith_column(i)->getDoubleValue()); } else if (m_col_defs[i].type == ColumnType::varchar_type) { - new_row.setColumnValue(i, row.ithColumn(i)->getStringValue()); + new_row.setColumnValue(i, row.ith_column(i)->getStringValue()); } } } - m_rows.push_back(row); + + validate_row(new_row); + m_rows.push_back(new_row); +} + +void Table::validate_column(const ColDefNode *col_def, ValueNode *col_val) { + if (col_def->null == false && 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) { + throw Exception("Column value of " + col_def->name + " is too long (" + col_val->getStringValue() + ")"); + } +} + +void Table::validate_column(const ColDefNode *col_def, ColValue *col_val) { + if (col_def->null == false && 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) { + throw Exception("Column value of " + col_def->name + " is too long (" + col_val->getStringValue() + ")"); + } +} + +void Table::validate_row(const Row &row) { + for(int i = 0; i < m_col_defs.size(); i++) { + ColDefNode col_def = m_col_defs[i]; + ColValue *col_val = row.ith_column(i); + + validate_column(&col_def, col_val); + } } } // namespace \ No newline at end of file diff --git a/usql/table.h b/usql/table.h index 2bfcb23..b7b20ff 100644 --- a/usql/table.h +++ b/usql/table.h @@ -4,6 +4,7 @@ #include "row.h" #include +#include namespace usql { @@ -16,15 +17,22 @@ namespace usql { int columns_count() const { return m_col_defs.size(); }; - Row createEmptyRow(); // TODO this means unnecessary copying - void addRow(const Row &row); - void addCopyOfRow(const Row &row); + Row create_empty_row(); // 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); + void validate_row(const Row &row); + + std::string csv_string(); + int load_csv_string(const std::string &content); void print(); std::string m_name; std::vector m_col_defs; - std::vector m_rows; + std::list m_rows; }; } \ No newline at end of file diff --git a/usql/usql.cpp b/usql/usql.cpp index 686be4a..7fbcaae 100644 --- a/usql/usql.cpp +++ b/usql/usql.cpp @@ -1,6 +1,5 @@ #include "usql.h" #include "exception.h" -#include "csvreader.h" #include "ml_date.h" #include @@ -38,6 +37,8 @@ std::unique_ptr USql::execute(Node &node) { return execute_load(static_cast(node)); case NodeType::save_table: return execute_save(static_cast(node)); + case NodeType::drop_table: + return execute_drop(static_cast(node)); default: return create_stmt_result_table(-1, "unknown statement"); } @@ -45,7 +46,8 @@ std::unique_ptr
USql::execute(Node &node) { std::unique_ptr
USql::execute_create_table(CreateTableNode &node) { - // TODO check table does not exists + check_table_not_exists(node.table_name); + Table table{node.table_name, node.cols_defs}; m_tables.push_back(table); @@ -54,7 +56,7 @@ 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 + check_table_not_exists(node.table_name); auto select = execute_select((SelectFromTableNode &) *node.select_table); @@ -66,7 +68,7 @@ std::unique_ptr
USql::execute_create_table_as_table(CreateTableAsSelectNo // 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); + table->add_copy_of_row(orig_row); } select.release(); // is it correct? hoping not to release select table here and then when releasing CreateTableAsSelectNode @@ -75,6 +77,50 @@ std::unique_ptr
USql::execute_create_table_as_table(CreateTableAsSelectNo } + +std::unique_ptr
USql::execute_load(LoadIntoTableNode &node) { + // find source table + Table *table_def = find_table(node.table_name); + + // read data + std::ifstream ifs(node.filename); + std::string content((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + + // load rows + auto rows_cnt = table_def->load_csv_string(content); + + return create_stmt_result_table(0, "load succeeded"); +} + + +std::unique_ptr
USql::execute_save(SaveTableNode &node) { + // find source table + Table *table_def = find_table(node.table_name); + + // make csv string + std::string csv_string = table_def->csv_string(); + + // save data + std::ofstream file(node.filename); + file << csv_string; + file.close(); + + return create_stmt_result_table(0, "save succeeded"); +} + +std::unique_ptr
USql::execute_drop(DropTableNode &node) { + auto name_cmp = [node](const Table& t) { return t.m_name == node.table_name; }; + + auto table_def = std::find_if(begin(m_tables), end(m_tables), name_cmp); + if (table_def != std::end(m_tables)) { + m_tables.erase(table_def); + return create_stmt_result_table(0, "drop succeeded"); + } + + throw Exception("table not found (" + node.table_name + ")"); +} + std::unique_ptr
USql::execute_insert_into_table(InsertIntoTableNode &node) { // TODO check column names.size = values.size @@ -82,7 +128,7 @@ std::unique_ptr
USql::execute_insert_into_table(InsertIntoTableNode &node Table *table_def = find_table(node.table_name); // prepare empty new_row - Row new_row = table_def->createEmptyRow(); + Row new_row = table_def->create_empty_row(); // copy values for (size_t i = 0; i < node.cols_names.size(); i++) { @@ -93,7 +139,7 @@ std::unique_ptr
USql::execute_insert_into_table(InsertIntoTableNode &node } // append new_row - table_def->addRow(new_row); + table_def->add_row(new_row); return create_stmt_result_table(0, "insert succeeded"); } @@ -109,7 +155,8 @@ std::unique_ptr
USql::execute_select(SelectFromTableNode &node) { std::vector source_table_col_index{}; 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); + auto [ src_tbl_col_index, rst_tbl_col_def ] = get_column_definition(table, + &node.cols_names->operator[](i), i); source_table_col_index.push_back(src_tbl_col_index); result_tbl_col_defs.push_back(rst_tbl_col_def); @@ -122,7 +169,7 @@ std::unique_ptr
USql::execute_select(SelectFromTableNode &node) { // eval where for row if (evalWhere(node.where.get(), table, *row)) { // prepare empty row - Row new_row = result->createEmptyRow(); + Row new_row = result->create_empty_row(); // copy column values for (auto idx = 0; idx < result->columns_count(); idx++) { @@ -134,7 +181,7 @@ std::unique_ptr
USql::execute_select(SelectFromTableNode &node) { new_row.setColumnValue(&result_tbl_col_defs[idx], col_value); } else { - ColValue *col_value = row->ithColumn(row_col_index); + ColValue *col_value = row->ith_column(row_col_index); new_row.setColumnValue(&result_tbl_col_defs[idx], col_value); } } @@ -147,7 +194,7 @@ 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::tuple USql::get_column_definition(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) { @@ -179,7 +226,6 @@ std::unique_ptr
USql::execute_delete(DeleteFromTableNode &node) { auto it = table->m_rows.begin(); for (; it != table->m_rows.end();) { if (evalWhere(node.where.get(), table, *it)) { - // TODO this can be really expensive operation it = table->m_rows.erase(it); } else { ++it; @@ -204,9 +250,11 @@ std::unique_ptr
USql::execute_update(UpdateTableNode &node) { std::unique_ptr new_val = evalArithmeticOperator(col_def.type, static_cast(*node.values[i]), table, *row); + table->validate_column(&col_def, new_val.get()); row->setColumnValue(&col_def, new_val.get()); i++; } + // TODO tady je problem, ze kdyz to zfajluje na jednom radku ostatni by se nemely provest } } @@ -214,83 +262,6 @@ std::unique_ptr
USql::execute_update(UpdateTableNode &node) { } -std::unique_ptr
USql::execute_load(LoadIntoTableNode &node) { - // find source table - Table *table_def = find_table(node.table_name); - - // read data - std::ifstream ifs(node.filename); - std::string content((std::istreambuf_iterator(ifs)), - (std::istreambuf_iterator())); - - CsvReader csvparser{}; - auto csv = csvparser.parseCSV(content); - - std::vector &colDefs = table_def->m_col_defs; - - for (auto it = csv.begin() + 1; it != csv.end(); ++it) { - std::vector csv_line = *it; - - // prepare empty new_row - Row new_row = table_def->createEmptyRow(); - - // copy values - for (size_t i = 0; i < table_def->columns_count(); i++) { - ColDefNode col_def = table_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])); - } 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]); - } - } - - // append new_row - table_def->addRow(new_row); - } - - return create_stmt_result_table(0, "load succeeded"); -} - - -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: @@ -353,6 +324,8 @@ std::unique_ptr USql::evalValueNode(Table *table, Row &row, Node *nod } else if (node->node_type == NodeType::function) { return evalFunctionValueNode(table, row, node); + } else if (node->node_type == NodeType::null_value) { + return std::make_unique(); } throw Exception("unsupported node type"); } @@ -361,7 +334,7 @@ std::unique_ptr USql::evalValueNode(Table *table, Row &row, Node *nod 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); + auto db_value = row.ith_column(col_def.order); if (col_def.type == ColumnType::integer_type) { return std::make_unique(db_value->getIntValue()); @@ -466,6 +439,7 @@ std::unique_ptr USql::evalArithmeticOperator(ColumnType outType, Arit default: throw Exception("implement me!!"); } + } else if (outType == ColumnType::integer_type) { long l = ((ValueNode *) left.get())->getIntValue(); long r = ((ValueNode *) right.get())->getIntValue(); @@ -504,10 +478,10 @@ std::unique_ptr
USql::create_stmt_result_table(long code, const std::stri auto table_def = std::make_unique
("result", result_tbl_col_defs); - Row new_row = table_def->createEmptyRow(); + Row new_row = table_def->create_empty_row(); new_row.setColumnValue(0, code); new_row.setColumnValue(1, text); - table_def->addRow(new_row); + table_def->add_row(new_row); return std::move(table_def); } @@ -524,4 +498,12 @@ Table *USql::find_table(const std::string &name) { } } +void USql::check_table_not_exists(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)) { + throw Exception("table already exists"); + } +} + } // namespace \ No newline at end of file diff --git a/usql/usql.h b/usql/usql.h index 50ffaf2..b3073d5 100644 --- a/usql/usql.h +++ b/usql/usql.h @@ -21,12 +21,14 @@ private: std::unique_ptr
execute_create_table(CreateTableNode &node); std::unique_ptr
execute_create_table_as_table(CreateTableAsSelectNode &node); + std::unique_ptr
execute_load(LoadIntoTableNode &node); + std::unique_ptr
execute_save(SaveTableNode &node); + std::unique_ptr
execute_drop(DropTableNode &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); - std::unique_ptr
execute_save(SaveTableNode &node); private: @@ -44,9 +46,10 @@ private: 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) ; + static std::tuple get_column_definition(Table *table, SelectColNode *select_col_node, int col_order) ; Table *find_table(const std::string &name); + void check_table_not_exists(const std::string &name); private: Parser m_parser;