From 24d4fb2567720aaacc6a9439ff4df5552d0e1213 Mon Sep 17 00:00:00 2001 From: VaclavT Date: Wed, 14 Jul 2021 23:18:54 +0200 Subject: [PATCH] preparing for functions --- Radme.md | 12 + exception.cpp | 11 +- exception.h | 14 +- main.cpp | 2 +- parser.cpp | 38 ++- parser.h | 30 +- table.h | 2 +- usql.cpp | 827 +++++++++++++++++++++++++------------------------- usql.h | 66 ++-- 9 files changed, 535 insertions(+), 467 deletions(-) create mode 100644 Radme.md diff --git a/Radme.md b/Radme.md new file mode 100644 index 0000000..8887230 --- /dev/null +++ b/Radme.md @@ -0,0 +1,12 @@ + +### TODO +- unify using of float and double keywords to double +- use long data type for int +- stoi -> stol, stof -> stod +- 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/exception.cpp b/exception.cpp index 894cc3d..2f6f388 100644 --- a/exception.cpp +++ b/exception.cpp @@ -2,10 +2,11 @@ namespace usql { - Exception::Exception(const std::string &msg) { - cause = msg; - } +Exception::Exception(const std::string &msg) { + cause = msg; +} - const char *Exception::what() const noexcept { return cause.c_str(); } -} \ No newline at end of file +const char *Exception::what() const noexcept { return cause.c_str(); } + +} diff --git a/exception.h b/exception.h index 12cd6fc..312f8d3 100644 --- a/exception.h +++ b/exception.h @@ -6,14 +6,14 @@ namespace usql { - class Exception : public std::exception { - private: - std::string cause; +class Exception : public std::exception { +private: + std::string cause; - public: - Exception(const std::string &msg); +public: + Exception(const std::string &msg); - const char *what() const noexcept; - }; + const char *what() const noexcept; +}; } \ No newline at end of file diff --git a/main.cpp b/main.cpp index d66d9dd..42e3cf5 100644 --- a/main.cpp +++ b/main.cpp @@ -32,7 +32,7 @@ int main(int argc, char *argv[]) { }; - usql::uSQL uSql{}; + usql::USql uSql{}; for (auto command : sql_commands) { std::cout << command << std::endl; diff --git a/parser.cpp b/parser.cpp index a22a233..d7ff0db 100644 --- a/parser.cpp +++ b/parser.cpp @@ -82,8 +82,7 @@ namespace usql { lexer.nextToken(); } - cols_def.push_back( - ColDefNode(column_name, column_type, column_order++, column_len, column_nullable)); + cols_def.push_back( ColDefNode(column_name, column_type, column_order++, column_len, column_nullable)); lexer.skipTokenOptional(TokenType::comma); @@ -99,7 +98,7 @@ namespace usql { std::unique_ptr Parser::parse_insert_into_table() { std::vector exec_code{}; std::vector cols_names{}; - std::vector cols_values{}; + std::vector> cols_values{}; lexer.skipToken(TokenType::keyword_insert); lexer.skipToken(TokenType::keyword_into); @@ -123,15 +122,44 @@ namespace usql { // column values lexer.skipToken(TokenType::open_paren); do { - cols_values.push_back(lexer.consumeCurrentToken().token_string); + // cols_values.push_back(lexer.consumeCurrentToken().token_string); + auto col_value = parse_value(); + cols_values.push_back(std::move(col_value)); lexer.skipTokenOptional(TokenType::comma); } while (lexer.tokenType() != TokenType::close_paren); lexer.skipToken(TokenType::close_paren); - return std::make_unique(table_name, cols_names, cols_values); + return std::make_unique(table_name, cols_names, std::move(cols_values)); } +std::unique_ptr Parser::parse_value() { + if (lexer.tokenType() == TokenType::int_number) { + return std::make_unique(std::stoi(lexer.consumeCurrentToken().token_string)); + } + if (lexer.tokenType() == TokenType::double_number) { + return std::make_unique(std::stof(lexer.consumeCurrentToken().token_string)); + } + if (lexer.tokenType() == TokenType::string_literal) { + if (lexer.nextTokenType() != TokenType::open_paren) { + return std::make_unique(lexer.consumeCurrentToken().token_string); + } else { + // function + std::string func_name = lexer.consumeCurrentToken().token_string; + std::vector> pars; + + lexer.skipToken(TokenType::open_paren); + while (lexer.tokenType() != TokenType::close_paren) { // TODO handle errors + auto par = parse_value(); + lexer.skipTokenOptional(TokenType::comma); + } + lexer.skipToken(TokenType::close_paren); + return std::make_unique(func_name, std::move(pars)); + } + } + throw Exception("Syntax error"); +} + std::unique_ptr Parser::parse_select_from_table() { std::vector cols_names{}; diff --git a/parser.h b/parser.h index 6fcba45..ff29726 100644 --- a/parser.h +++ b/parser.h @@ -32,6 +32,7 @@ namespace usql { load_table, column_name, column_value, + function, column_def, error }; @@ -49,13 +50,6 @@ namespace usql { Node(NodeType::column_name), name(col_name) {} }; - struct ColValueNode : Node { - std::string value; - - ColValueNode(const std::string col_value) : - Node(NodeType::column_value), value(col_value) {} - }; - // TODO add order in row struct ColDefNode : Node { std::string name; @@ -69,6 +63,20 @@ namespace usql { null(nullable) {} }; + struct ColValueNode : Node { + std::string value; + + ColValueNode(const std::string col_value) : + Node(NodeType::column_value), value(col_value) {} + }; + + 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) {} @@ -193,10 +201,10 @@ namespace usql { struct InsertIntoTableNode : Node { std::string table_name; std::vector cols_names; - std::vector cols_values; + 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 { @@ -252,6 +260,8 @@ namespace usql { 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(); diff --git a/table.h b/table.h index 428606b..dda6a03 100644 --- a/table.h +++ b/table.h @@ -15,7 +15,7 @@ namespace usql { ColDefNode get_column_def(const std::string &col_name); - int columns_count() { return m_col_defs.size(); }; + int columns_count() const { return m_col_defs.size(); }; Row createEmptyRow(); // TODO this means unnecessary copying void addRow(const Row &row); diff --git a/usql.cpp b/usql.cpp index 7e0e15c..5c6f139 100644 --- a/usql.cpp +++ b/usql.cpp @@ -7,415 +7,422 @@ namespace usql { - std::unique_ptr uSQL::execute(const std::string &command) { - auto node = m_parser.parse(command); - - return execute(*node); - } - - - std::unique_ptr
uSQL::execute(Node &node) { - // TODO optimize execution nodes here - 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"); - } - } - - - std::unique_ptr
uSQL::execute_create_table(CreateTableNode &node) { - // TODO check table does not exists - Table table{node.table_name, node.cols_defs}; - m_tables.push_back(table); - - 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 - - // find table - Table *table_def = find_table(node.table_name); - - // prepare empty new_row - Row new_row = table_def->createEmptyRow(); - - // 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); - - // 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); - } - } - - // append new_row - table_def->addRow(new_row); - - return create_stmt_result_table(0, "insert succeded"); - } - - - 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); - - i++; - } - 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)) { - // 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()); - } - - // add row to result - result->m_rows.push_back(new_row); - } - } - - return std::move(result); - } - - - 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)) { - // TODO this can be really expensive operation - it = table->m_rows.erase(it); - } else { - ++it; - } - } - - return create_stmt_result_table(0, "delete succeded"); - } - - - 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)) { - int i = 0; - for (auto col : node.cols_names) { - // TODO cache it like in select - ColDefNode cdef = table->get_column_def(col.name); - - 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!"); - } - i++; - } - } - } - - return create_stmt_result_table(0, "delete succeeded"); - } - - - 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::stoi(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"); - } - - - bool uSQL::evalWhere(Node *where, Table *table, - std::vector>::iterator &row) const { - switch (where->node_type) { // no where clause - case NodeType::true_node: - return true; - 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"); - } - - 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()); - - 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)) { - comparator = left_value->getDoubleValue() - right_value->getDoubleValue(); - } else if (left_value->node_type == NodeType::string_value || - right_value->node_type == NodeType::string_value) { - comparator = left_value->getStringValue().compare(right_value->getStringValue()); - } else { - // 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; - } - - 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); - - 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) { - IntValueNode *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); - - } else if (node->node_type == NodeType::string_value) { - StringValueNode *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); - - if ((node.op == LogicalOperatorType::and_operator && !left) || - (node.op == LogicalOperatorType::or_operator && left)) - return left; - - bool right = evalRelationalOperator(static_cast(*node.right), pTable, iter); - return right; - } - - - std::unique_ptr - uSQL::evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, - std::vector>::iterator &row) const { - if (node.op == ArithmeticalOperatorType::copy_value) { - return evalNode(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()); - - 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!!"); - } - } else if (outType == ColumnType::integer_type) { - int l = ((ValueNode *) left.get())->getIntValue(); - int 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!!"); - } - - } else if (outType == ColumnType::varchar_type) { - std::string l = ((ValueNode *) left.get())->getStringValue(); - std::string r = ((ValueNode *) right.get())->getStringValue(); - switch (node.op) { - case ArithmeticalOperatorType::plus_operator: - return std::make_unique(l + r); - - default: - throw Exception("implement me!!"); - } - } - - throw Exception("implement me!!"); - } - - - - 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::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)); - - auto table_def = std::make_unique
("result", result_tbl_col_defs); - - Row new_row = table_def->createEmptyRow(); - new_row.setColumnValue(0, code); - new_row.setColumnValue(1, text); - table_def->addRow(new_row); - - return std::move(table_def); - } +std::unique_ptr
USql::execute(const std::string &command) { + auto node = m_parser.parse(command); + + return execute(*node); +} + +std::unique_ptr
USql::execute(Node &node) { + // TODO optimize execution nodes here + 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"); + } +} + + +std::unique_ptr
USql::execute_create_table(CreateTableNode &node) { + // TODO check table does not exists + Table table{node.table_name, node.cols_defs}; + m_tables.push_back(table); + + 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 + + // find table + Table *table_def = find_table(node.table_name); + + // prepare empty new_row + Row new_row = table_def->createEmptyRow(); + + // 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); + + // TODO validate value + auto value = evalValueNode(node.cols_values[i].get()); + + if (col_def.type == ColumnType::integer_type) { + new_row.setColumnValue(col_def.order, value->getIntValue()); + } else if (col_def.type == ColumnType::float_type) { + new_row.setColumnValue(col_def.order, value->getDoubleValue()); + } else { + new_row.setColumnValue(col_def.order, value->getStringValue()); + } + } + + // append new_row + table_def->addRow(new_row); + + return create_stmt_result_table(0, "insert succeded"); +} + + +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); + + i++; + } + 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)) { + // 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()); + } + + // add row to result + result->m_rows.push_back(new_row); + } + } + + return std::move(result); +} + + +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)) { + // TODO this can be really expensive operation + it = table->m_rows.erase(it); + } else { + ++it; + } + } + + return create_stmt_result_table(0, "delete succeded"); +} + + +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)) { + int i = 0; + for (auto col : node.cols_names) { + // TODO cache it like in select + ColDefNode cdef = table->get_column_def(col.name); + + 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!"); + } + i++; + } + } + } + + return create_stmt_result_table(0, "delete succeeded"); +} + + +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::stoi(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"); +} + + +bool USql::evalWhere(Node *where, Table *table, + std::vector>::iterator &row) const { + switch (where->node_type) { // no where clause + case NodeType::true_node: + return true; + 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"); + } + + 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()); + + 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)) { + comparator = left_value->getDoubleValue() - right_value->getDoubleValue(); + } else if (left_value->node_type == NodeType::string_value || + right_value->node_type == NodeType::string_value) { + comparator = left_value->getStringValue().compare(right_value->getStringValue()); + } else { + // 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; + } + + 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); + + 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 { + return evalValueNode(node); + } +} + + +std::unique_ptr USql::evalValueNode(Node *node) const { + if (node->node_type == NodeType::int_value) { + IntValueNode *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); + + } else if (node->node_type == NodeType::string_value) { + StringValueNode *ivl = static_cast(node); + return std::make_unique(ivl->value); + } else if ("function eval" == "xxx") { + + } + + 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); + + if ((node.op == LogicalOperatorType::and_operator && !left) || + (node.op == LogicalOperatorType::or_operator && left)) + return left; + + bool right = evalRelationalOperator(static_cast(*node.right), pTable, iter); + return right; +} + + +std::unique_ptr +USql::evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, + std::vector>::iterator &row) const { + if (node.op == ArithmeticalOperatorType::copy_value) { + return evalNode(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()); + + 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!!"); + } + } else if (outType == ColumnType::integer_type) { + int l = ((ValueNode *) left.get())->getIntValue(); + int 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!!"); + } + + } else if (outType == ColumnType::varchar_type) { + std::string l = ((ValueNode *) left.get())->getStringValue(); + std::string r = ((ValueNode *) right.get())->getStringValue(); + switch (node.op) { + case ArithmeticalOperatorType::plus_operator: + return std::make_unique(l + r); + + default: + throw Exception("implement me!!"); + } + } + + throw Exception("implement me!!"); +} + + + +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::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)); + + auto table_def = std::make_unique
("result", result_tbl_col_defs); + + Row new_row = table_def->createEmptyRow(); + new_row.setColumnValue(0, code); + new_row.setColumnValue(1, text); + table_def->addRow(new_row); + + return std::move(table_def); +} } \ No newline at end of file diff --git a/usql.h b/usql.h index 5a35c09..9be3bd9 100644 --- a/usql.h +++ b/usql.h @@ -7,44 +7,54 @@ namespace usql { - class uSQL { +class USql { - public: - std::unique_ptr
execute(const std::string &command); +public: + USql() {}; - private: - std::unique_ptr
execute(Node &node); + std::unique_ptr
execute(const std::string &command); - std::unique_ptr
execute_create_table(CreateTableNode &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); +private: + std::unique_ptr
execute(Node &node); - Table *find_table(const std::string name); - std::unique_ptr
create_stmt_result_table(int code, std::string text); + std::unique_ptr
execute_create_table(CreateTableNode &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); - private: - bool evalWhere(Node *where, Table *table, - std::vector>::iterator &row) const; +private: + bool evalWhere(Node *where, Table *table, + std::vector>::iterator &row) const; - std::unique_ptr evalNode(Table *table, std::vector>::iterator &row, - Node *node) const; + std::unique_ptr evalNode(Table *table, std::vector>::iterator &row, + Node *node) const; - bool evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, - std::vector>::iterator &row) const; + std::unique_ptr evalValueNode(Node *node) const; - bool evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, - std::vector>::iterator &iter) const; + bool evalRelationalOperator(const RelationalOperatorNode &filter, Table *table, + std::vector>::iterator &row) const; - std::unique_ptr evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, - std::vector>::iterator &row) const; + bool evalLogicalOperator(LogicalOperatorNode &node, Table *pTable, + std::vector>::iterator &iter) const; - private: - Parser m_parser; - std::vector
m_tables; - }; + std::unique_ptr evalArithmetic(ColumnType outType, ArithmeticalOperatorNode &node, Table *table, + std::vector>::iterator &row) const; + +private: + Parser m_parser; + std::vector
m_tables; +}; } \ No newline at end of file