another ugly basic implementation
This commit is contained in:
parent
b55115f7c3
commit
b4711985b3
|
|
@ -12,7 +12,7 @@ project(msql)
|
|||
set(PROJECT_NAME msql)
|
||||
|
||||
set(SOURCE
|
||||
exception.cpp lexer.cpp parser.cpp executor.cpp main.cpp table.cpp table.h)
|
||||
exception.cpp lexer.cpp parser.cpp executor.cpp main.cpp table.cpp table.h row.cpp row.h)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCE})
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
### TODO
|
||||
- rename it to usql
|
||||
- rename Exception to UException, Table to UTable, Row to URow etc
|
||||
- unify using of float and double keywords
|
||||
- add constructors
|
||||
- add exceptions
|
||||
- class members should have prefix m_O
|
||||
- add pipe | token
|
||||
- add logging
|
||||
79
executor.cpp
79
executor.cpp
|
|
@ -14,7 +14,7 @@ Table* Executor::find_table(const std::string name) {
|
|||
if (table_def != std::end(m_tables)) {
|
||||
return table_def.operator->();
|
||||
} else {
|
||||
// TODO throw exception
|
||||
throw Exception("table not found (" + name + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,25 +50,28 @@ bool Executor::execute_insert_into_table(InsertIntoTableNode& node) {
|
|||
Table* table_def = find_table(node.table_name);
|
||||
|
||||
// prepare empty new_row
|
||||
std::vector<std::string> new_row;
|
||||
new_row.reserve(table_def->columns_count());
|
||||
for(size_t i=0; i<table_def->columns_count(); i++) {
|
||||
new_row.push_back(std::string {""});
|
||||
}
|
||||
Row new_row = table_def->createEmptyRow();
|
||||
|
||||
// copy values
|
||||
for(size_t i=0; i<node.cols_names.size(); i++) {
|
||||
auto colNameNode = node.cols_names[i];
|
||||
ColDefNode col_def = table_def->get_column_def(colNameNode.name);
|
||||
|
||||
// TODO validate
|
||||
new_row[col_def.order] = node.cols_values[i].value;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check not null columns
|
||||
|
||||
// append new_row
|
||||
table_def->m_rows.push_back(new_row);
|
||||
table_def->addRow(new_row);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -99,18 +102,56 @@ bool Executor::execute_select(SelectFromTableNode& node) {
|
|||
|
||||
|
||||
for (auto row = begin (table->m_rows); row != end (table->m_rows); ++row) {
|
||||
// eval there for row
|
||||
bool where_true = true;
|
||||
|
||||
if (where_true) {
|
||||
// prepare empty row
|
||||
std::vector<std::string> new_row;
|
||||
new_row.reserve(result.columns_count());
|
||||
for(auto i=0; i<result.columns_count(); i++) {
|
||||
new_row.push_back(row->at(source_table_col_index[i]));
|
||||
// eval where for row
|
||||
bool where_true = true;
|
||||
if (node.where->node_type == NodeType::true_node) { // no where clause
|
||||
where_true = true;
|
||||
} else { // evaluate where
|
||||
RelationalOperatorNode& filter = static_cast<RelationalOperatorNode &>(*node.where);
|
||||
if (filter.op == RelationalOperatorType::greater) {
|
||||
std::unique_ptr<Node> left_value;
|
||||
if ((*filter.left).node_type == NodeType::database_value) {
|
||||
DatabaseValueNode *dvl = static_cast<DatabaseValueNode*>(filter.left.get());
|
||||
ColDefNode col_def = table->get_column_def(dvl->col_name); // TODO optimize it to just get this def once
|
||||
auto db_value = row->ithColum(col_def.order);
|
||||
if (col_def.type == ColumnType::integer_type) {
|
||||
left_value = std::make_unique<IntValueNode>(db_value->integerValue());
|
||||
}
|
||||
// TODO other cases
|
||||
}
|
||||
result.m_rows.push_back(new_row);
|
||||
|
||||
std::unique_ptr<Node> right_value;
|
||||
if ((*filter.right).node_type == NodeType::int_value) {
|
||||
IntValueNode *ivl = static_cast<IntValueNode*>(filter.right.get());
|
||||
right_value = std::make_unique<IntValueNode>(ivl->value);
|
||||
}
|
||||
|
||||
IntValueNode* left_int_value = static_cast<IntValueNode *>(left_value.get());
|
||||
IntValueNode* right_int_value = static_cast<IntValueNode *>(right_value.get());
|
||||
|
||||
where_true = left_int_value->value > right_int_value->value;
|
||||
}
|
||||
}
|
||||
|
||||
if (where_true) {
|
||||
// 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->ithColum(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);
|
||||
}
|
||||
}
|
||||
|
||||
result.print();
|
||||
|
|
|
|||
14
lexer.cpp
14
lexer.cpp
|
|
@ -24,7 +24,7 @@ void Lexer::parse(const std::string &code) {
|
|||
|
||||
// TODO make it constant
|
||||
std::regex words_regex("[0-9]+\\.[0-9]+|[0-9][0-9_]+[0-9]|[0-9]+|[A-Za-z]+[A-Za-z0-9_#]*|[\\(\\)\\[\\]\\{\\}]|[-\\+\\*/"
|
||||
",;:\?]|==|>=|<=|~=|>|<|=|;|~|\\|\\||&&|\n|\r|\r\n|'([^']|'')*'|\".*?\"|%.*?\n");
|
||||
",;:\?]|==|>=|<=|~=|>|<|=|;|~|\\||or|and|\n|\r|\r\n|'([^']|'')*'|\".*?\"|%.*?\n");
|
||||
|
||||
auto words_begin = std::sregex_iterator(m_code_str.begin(), m_code_str.end(), words_regex);
|
||||
auto words_end = std::sregex_iterator();
|
||||
|
|
@ -55,6 +55,12 @@ void Lexer::debugTokens() {
|
|||
|
||||
Token Lexer::currentToken() { return m_tokens[m_index]; }
|
||||
|
||||
Token Lexer::consumeCurrentToken() {
|
||||
int i = m_index;
|
||||
nextToken();
|
||||
return m_tokens[i];
|
||||
}
|
||||
|
||||
void Lexer::nextToken() {
|
||||
if (m_index < m_tokens.size()) {
|
||||
m_index++;
|
||||
|
|
@ -65,7 +71,7 @@ void Lexer::skipToken(TokenType type) {
|
|||
if (tokenType() == type) {
|
||||
nextToken();
|
||||
} else {
|
||||
throw Exception("ERROR unexpected token " + currentToken().token_string + ", instead of " + typeToString(type));
|
||||
throw Exception("ERROR unexpected token " + consumeCurrentToken().token_string + ", instead of " + typeToString(type));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,10 +183,10 @@ TokenType Lexer::type(const std::string &token) {
|
|||
if (token == "varchar")
|
||||
return TokenType::keyword_varchar;
|
||||
|
||||
if (token == "||")
|
||||
if (token == "or")
|
||||
return TokenType::logical_or;
|
||||
|
||||
if (token == "&&")
|
||||
if (token == "and")
|
||||
return TokenType::logical_and;
|
||||
|
||||
if (token == ",")
|
||||
|
|
|
|||
7
lexer.h
7
lexer.h
|
|
@ -40,6 +40,7 @@ enum class TokenType {
|
|||
close_paren,
|
||||
logical_and,
|
||||
logical_or,
|
||||
pipe,
|
||||
semicolon,
|
||||
comma,
|
||||
newline,
|
||||
|
|
@ -61,7 +62,8 @@ public:
|
|||
|
||||
void debugTokens();
|
||||
|
||||
Token currentToken();
|
||||
Token currentToken();
|
||||
Token consumeCurrentToken();
|
||||
|
||||
void nextToken();
|
||||
|
||||
|
|
@ -72,7 +74,8 @@ public:
|
|||
TokenType nextTokenType();
|
||||
TokenType prevTokenType();
|
||||
|
||||
static bool isRelationalOperator(TokenType token_type);
|
||||
static bool isRelationalOperator(TokenType token_type);
|
||||
static bool isLogicalOperator(TokenType token_type);
|
||||
|
||||
private:
|
||||
TokenType type(const std::string &token);
|
||||
|
|
|
|||
5
main.cpp
5
main.cpp
|
|
@ -16,7 +16,8 @@ int main(int argc, char *argv[]) {
|
|||
"insert into a (i, s) values(1, 'one')",
|
||||
"insert into a (i, s) values(2, 'two')",
|
||||
"insert into a (i, s) values(3, 'two')",
|
||||
"select i, s from a where i > 0"
|
||||
"insert into a (i, s) values(4, 'four')",
|
||||
"select i, s from a where i > 2"
|
||||
// "update a set s = 'three' where i = 3"
|
||||
// "delete from a where i = 3"
|
||||
// "select i, s from a where i > 0"
|
||||
|
|
@ -25,7 +26,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
for(auto command : sql_commands) {
|
||||
auto node = parser.parse(command);
|
||||
executor.execute(*node.get());
|
||||
executor.execute(*node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
77
parser.cpp
77
parser.cpp
|
|
@ -19,6 +19,7 @@ std::unique_ptr<Node> Parser::parse(const std::string &code) {
|
|||
return parse_select_from_table();
|
||||
}
|
||||
|
||||
std::cout << "ERROR, token:" << lexer.currentToken().token_string << std::endl;
|
||||
return std::make_unique<Node>(NodeType::error);
|
||||
}
|
||||
|
||||
|
|
@ -29,8 +30,7 @@ std::unique_ptr<Node> Parser::parse_create_table() {
|
|||
lexer.skipToken(TokenType::keyword_table);
|
||||
|
||||
if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ }
|
||||
std::string table_name = lexer.currentToken().token_string;
|
||||
lexer.nextToken();
|
||||
std::string table_name = lexer.consumeCurrentToken().token_string;
|
||||
|
||||
lexer.skipToken(TokenType::open_paren);
|
||||
int column_order = 0;
|
||||
|
|
@ -42,8 +42,7 @@ std::unique_ptr<Node> Parser::parse_create_table() {
|
|||
|
||||
// column name
|
||||
if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ }
|
||||
column_name = lexer.currentToken().token_string;
|
||||
lexer.nextToken();
|
||||
column_name = lexer.consumeCurrentToken().token_string;
|
||||
|
||||
// column type and optionaly len
|
||||
if (lexer.tokenType() == TokenType::keyword_int) {
|
||||
|
|
@ -57,8 +56,7 @@ std::unique_ptr<Node> Parser::parse_create_table() {
|
|||
lexer.nextToken();
|
||||
lexer.skipToken(TokenType::open_paren);
|
||||
if (lexer.tokenType() == TokenType::int_number) {
|
||||
column_len = std::stoi(lexer.currentToken().token_string);
|
||||
lexer.nextToken();
|
||||
column_len = std::stoi(lexer.consumeCurrentToken().token_string);
|
||||
} else { /* TODO handle error */ }
|
||||
lexer.skipToken(TokenType::close_paren);
|
||||
} else { /* TODO handle error */ }
|
||||
|
|
@ -94,15 +92,13 @@ std::unique_ptr<Node> Parser::parse_insert_into_table() {
|
|||
|
||||
// table name
|
||||
if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ }
|
||||
std::string table_name = lexer.currentToken().token_string;
|
||||
lexer.nextToken();
|
||||
std::string table_name = lexer.consumeCurrentToken().token_string;
|
||||
|
||||
// column names
|
||||
lexer.skipToken(TokenType::open_paren);
|
||||
do {
|
||||
if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ }
|
||||
cols_names.push_back(lexer.currentToken().token_string);
|
||||
lexer.nextToken();
|
||||
cols_names.push_back(lexer.consumeCurrentToken().token_string);
|
||||
|
||||
lexer.skipTokenOptional(TokenType::comma);
|
||||
} while (lexer.tokenType() != TokenType::close_paren);
|
||||
|
|
@ -113,8 +109,7 @@ std::unique_ptr<Node> Parser::parse_insert_into_table() {
|
|||
// column values
|
||||
lexer.skipToken(TokenType::open_paren);
|
||||
do {
|
||||
cols_values.push_back(lexer.currentToken().token_string);
|
||||
lexer.nextToken();
|
||||
cols_values.push_back(lexer.consumeCurrentToken().token_string);
|
||||
|
||||
lexer.skipTokenOptional(TokenType::comma);
|
||||
} while (lexer.tokenType() != TokenType::close_paren);
|
||||
|
|
@ -124,25 +119,69 @@ std::unique_ptr<Node> Parser::parse_insert_into_table() {
|
|||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::parse_select_from_table() {
|
||||
std::vector<Node> where {};
|
||||
std::vector<ColNameNode> cols_names {};
|
||||
std::unique_ptr<Node> where_node;
|
||||
|
||||
lexer.skipToken(TokenType::keyword_select);
|
||||
// TODO support also numbers and expressions
|
||||
while (lexer.tokenType() != TokenType::keyword_from) {
|
||||
// TODO add consumeToken() which returns token and advances to next token
|
||||
cols_names.push_back(lexer.currentToken().token_string);
|
||||
lexer.nextToken();
|
||||
cols_names.push_back(lexer.consumeCurrentToken().token_string);
|
||||
lexer.skipTokenOptional(TokenType::comma);
|
||||
}
|
||||
lexer.skipToken(TokenType::keyword_from);
|
||||
std::string table_name = lexer.currentToken().token_string;
|
||||
lexer.nextToken();
|
||||
std::string table_name = lexer.consumeCurrentToken().token_string;
|
||||
|
||||
if (lexer.tokenType() == TokenType::keyword_where) {}
|
||||
if (lexer.tokenType() == TokenType::keyword_where) {
|
||||
lexer.skipToken(TokenType::keyword_where);
|
||||
where_node = parse_where_clause();
|
||||
} else {
|
||||
where_node = std::make_unique<TrueNode>();
|
||||
}
|
||||
// if (lexer.tokenType() == TokenType::keyword_order_by) {}
|
||||
// if (lexer.tokenType() == TokenType::keyword_offset) {}
|
||||
// if (lexer.tokenType() == TokenType::keyword_limit) {}
|
||||
|
||||
return std::make_unique<SelectFromTableNode>(table_name, cols_names, where);
|
||||
return std::make_unique<SelectFromTableNode>(table_name, cols_names, std::move(where_node));
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::parse_where_clause() {
|
||||
// TODO add support for multiple filters
|
||||
// TODO add support for parenthises
|
||||
|
||||
auto left = parse_operand_node();
|
||||
auto operation = parse_operator();
|
||||
auto right = parse_operand_node();
|
||||
|
||||
return std::make_unique<RelationalOperatorNode>(operation, std::move(left), std::move(right));
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::parse_operand_node() {
|
||||
// while not end or order or limit
|
||||
auto token_type = lexer.tokenType();
|
||||
std::string tokenString = lexer.consumeCurrentToken().token_string;
|
||||
switch (token_type) {
|
||||
case TokenType::int_number:
|
||||
return std::make_unique<IntValueNode>(std::stoi(tokenString));
|
||||
case TokenType::double_number:
|
||||
return std::make_unique<FloatValueNode>(std::stod(tokenString));
|
||||
case TokenType::string_literal:
|
||||
return std::make_unique<StringValueNode>(tokenString);
|
||||
case TokenType::identifier:
|
||||
return std::make_unique<DatabaseValueNode>(tokenString);
|
||||
default: ;
|
||||
// Throw exception
|
||||
}
|
||||
}
|
||||
|
||||
RelationalOperatorType Parser::parse_operator() {
|
||||
auto op = lexer.consumeCurrentToken();
|
||||
switch (op.type) {
|
||||
case TokenType::equal:
|
||||
return RelationalOperatorType::equal;
|
||||
case TokenType::greater:
|
||||
return RelationalOperatorType::greater;
|
||||
default: ;
|
||||
// Throw exception
|
||||
}
|
||||
}
|
||||
70
parser.h
70
parser.h
|
|
@ -14,6 +14,13 @@ enum class ColumnType {
|
|||
};
|
||||
|
||||
enum class NodeType {
|
||||
true_node,
|
||||
int_value,
|
||||
float_value,
|
||||
string_value,
|
||||
database_value,
|
||||
logical_operator,
|
||||
relational_operator,
|
||||
create_table,
|
||||
insert_into,
|
||||
select_from,
|
||||
|
|
@ -56,6 +63,59 @@ struct ColDefNode : Node {
|
|||
Node(NodeType::column_def), name(col_name), type(col_type), order(col_order), length(col_len), null(nullable) {}
|
||||
};
|
||||
|
||||
struct TrueNode : Node {
|
||||
TrueNode() : Node(NodeType::true_node) {}
|
||||
};
|
||||
|
||||
struct IntValueNode : Node {
|
||||
int value;
|
||||
|
||||
IntValueNode(int value) : Node(NodeType::int_value), value(value) {}
|
||||
};
|
||||
|
||||
struct FloatValueNode : Node {
|
||||
double value;
|
||||
|
||||
FloatValueNode(double value) : Node(NodeType::float_value), value(value) {}
|
||||
};
|
||||
|
||||
struct StringValueNode : Node {
|
||||
std::string value;
|
||||
|
||||
StringValueNode(std::string value) : Node(NodeType::string_value), value(value) {}
|
||||
};
|
||||
|
||||
struct DatabaseValueNode : Node {
|
||||
std::string col_name;
|
||||
|
||||
DatabaseValueNode(std::string name) : Node(NodeType::database_value), col_name(name) {}
|
||||
};
|
||||
|
||||
struct LogicalOperatorNode : Node {
|
||||
// and_operator,
|
||||
// or_operator,
|
||||
// not_operator,
|
||||
// and / or / not
|
||||
std::unique_ptr<Node> left;
|
||||
std::unique_ptr<Node> right;
|
||||
};
|
||||
|
||||
enum class RelationalOperatorType {
|
||||
equal,
|
||||
greater
|
||||
// =, !=, >, >=, <, <=, like
|
||||
};
|
||||
|
||||
struct RelationalOperatorNode : Node {
|
||||
RelationalOperatorType op;
|
||||
|
||||
std::unique_ptr<Node> left;
|
||||
std::unique_ptr<Node> right;
|
||||
|
||||
RelationalOperatorNode(RelationalOperatorType op, std::unique_ptr<Node> left, std::unique_ptr<Node> right) :
|
||||
Node(NodeType::relational_operator), op(op), left(std::move(left)), right(std::move(right)) {};
|
||||
};
|
||||
|
||||
struct CreateTableNode : Node {
|
||||
std::string table_name;
|
||||
std::vector<ColDefNode> cols_defs;
|
||||
|
|
@ -76,10 +136,10 @@ struct InsertIntoTableNode : Node {
|
|||
struct SelectFromTableNode : Node {
|
||||
std::string table_name;
|
||||
std::vector<ColNameNode> cols_names;
|
||||
std::vector<Node> where;
|
||||
std::unique_ptr<Node> where;
|
||||
|
||||
SelectFromTableNode(const std::string name, std::vector<ColNameNode> names, std::vector<Node> where_clause) :
|
||||
Node(NodeType::select_from), table_name(name), cols_names(names), where(where_clause) {}
|
||||
SelectFromTableNode(const std::string name, std::vector<ColNameNode> names, std::unique_ptr<Node> where_clause) :
|
||||
Node(NodeType::select_from), table_name(name), cols_names(names), where(std::move(where_clause)) {}
|
||||
};
|
||||
|
||||
struct UpdateTableNode : Node { };
|
||||
|
|
@ -101,6 +161,10 @@ private:
|
|||
std::unique_ptr<Node> parse_insert_into_table();
|
||||
std::unique_ptr<Node> parse_select_from_table();
|
||||
|
||||
std::unique_ptr<Node> parse_where_clause();
|
||||
std::unique_ptr<Node> parse_operand_node();
|
||||
RelationalOperatorType parse_operator();
|
||||
|
||||
private:
|
||||
Lexer lexer;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
#include "row.h"
|
||||
|
||||
|
||||
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<ColValue>());
|
||||
}
|
||||
}
|
||||
|
||||
Row::Row(const Row &other) {
|
||||
m_columns.reserve(other.m_columns.size());
|
||||
// TODO fixme this is nonsense
|
||||
for (int i = 0; i < other.m_columns.size(); i++) {
|
||||
m_columns.push_back(std::make_unique<ColNullValue>());
|
||||
}
|
||||
|
||||
for (int i = 0; i < other.m_columns.size(); i++) {
|
||||
if (ColIntegerValue* other_v = dynamic_cast<ColIntegerValue*>(other.m_columns[i].get())) {
|
||||
setColumnValue(i, other_v->integerValue());
|
||||
}
|
||||
if (ColFloatValue* other_v = dynamic_cast<ColFloatValue*>(other.m_columns[i].get())) {
|
||||
setColumnValue(i, other_v->floatValue());
|
||||
}
|
||||
if (ColStringValue* other_v = dynamic_cast<ColStringValue*>(other.m_columns[i].get())) {
|
||||
setColumnValue(i, other_v->stringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Row::setColumnValue(int col_index, int value) {
|
||||
m_columns[col_index] = std::make_unique<ColIntegerValue>(value);
|
||||
}
|
||||
|
||||
void Row::setColumnValue(int col_index, double value) {
|
||||
m_columns[col_index] = std::make_unique<ColFloatValue>(value);
|
||||
}
|
||||
|
||||
void Row::setColumnValue(int col_index, std::string value) {
|
||||
m_columns[col_index] = std::make_unique<ColStringValue>(value);
|
||||
};
|
||||
|
||||
void Row::print() {
|
||||
for(int i=0; i<m_columns.size(); i++) {
|
||||
m_columns[i].get()->print();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
#pragma once
|
||||
|
||||
#include "exception.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ColumnValue {
|
||||
|
||||
|
||||
private:
|
||||
ColumnType m_type;
|
||||
union {
|
||||
int int_value;
|
||||
double float_value;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct ColValue {
|
||||
|
||||
virtual bool isNull() { return false; };
|
||||
virtual bool isInteger() { return false; };
|
||||
virtual bool isFloat() { return false; };
|
||||
virtual bool isString() { 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 void print() {std::cout << "ColValue:" << std::endl; };
|
||||
};
|
||||
|
||||
|
||||
struct ColNullValue : ColValue {
|
||||
|
||||
virtual bool isNull() { return true; };
|
||||
|
||||
virtual void print() {std::cout << "ColNullValue:" << std::endl; };
|
||||
};
|
||||
|
||||
|
||||
struct ColIntegerValue : ColValue {
|
||||
|
||||
ColIntegerValue(int value) : m_integer(value) {};
|
||||
ColIntegerValue(const ColIntegerValue &other) : m_integer(other.m_integer) {}
|
||||
|
||||
virtual bool isInteger() { return true; };
|
||||
|
||||
virtual int integerValue() { return m_integer; };
|
||||
virtual double floatValue() { return (double) m_integer; };
|
||||
virtual std::string stringValue() { return std::to_string(m_integer); };
|
||||
|
||||
virtual void print() {std::cout << "ColIntegerValue: " << m_integer <<std::endl; };
|
||||
|
||||
int m_integer;
|
||||
};
|
||||
|
||||
|
||||
struct ColFloatValue : ColValue {
|
||||
|
||||
ColFloatValue(double value) : m_float(value) {};
|
||||
ColFloatValue(const ColFloatValue &other) : m_float(other.m_float) {}
|
||||
|
||||
virtual bool isFloat() { return true; }
|
||||
|
||||
virtual int integerValue() { return (int) m_float; };
|
||||
virtual double floatValue() { return m_float; };
|
||||
virtual std::string stringValue() { return std::to_string(m_float); };
|
||||
|
||||
virtual void print() {std::cout << "ColFloatValue: " << m_float <<std::endl; };
|
||||
|
||||
double m_float;
|
||||
};
|
||||
|
||||
|
||||
struct ColStringValue : ColValue {
|
||||
|
||||
ColStringValue(const std::string value) : m_string(value) {};
|
||||
ColStringValue(const ColStringValue &other) : m_string(other.m_string) {};
|
||||
|
||||
virtual bool isString() { return true; }
|
||||
|
||||
virtual int integerValue() { return std::stoi(m_string); };
|
||||
virtual double floatValue() { return std::stod(m_string); };
|
||||
virtual std::string stringValue() { return m_string; };
|
||||
|
||||
virtual void print() {std::cout << "ColStringValue: " << m_string <<std::endl; };
|
||||
|
||||
std::string m_string;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Row {
|
||||
|
||||
public:
|
||||
Row(int cols_count);
|
||||
Row(const Row &other);
|
||||
|
||||
void setColumnValue(int col_index, int value);
|
||||
void setColumnValue(int col_index, double value);
|
||||
void setColumnValue(int col_index, std::string value);
|
||||
|
||||
ColValue& operator[](int i) {
|
||||
return *m_columns[i];
|
||||
}
|
||||
|
||||
ColValue* ithColum(int i) {
|
||||
return m_columns[i].get();
|
||||
}
|
||||
|
||||
void print();
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<ColValue>> m_columns;
|
||||
};
|
||||
26
table.cpp
26
table.cpp
|
|
@ -7,22 +7,40 @@ Table::Table(const std::string name, const std::vector<ColDefNode> columns) {
|
|||
m_rows.clear();
|
||||
}
|
||||
|
||||
ColDefNode Table::get_column_def(const std::string col_name) {
|
||||
ColDefNode Table::get_column_def(const std::string& col_name) {
|
||||
auto name_cmp = [col_name](ColDefNode cd){ return cd.name == col_name; };
|
||||
auto 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 {
|
||||
// TODO throw exception
|
||||
throw Exception("column not exists (" + col_name + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row Table::createEmptyRow() {
|
||||
return Row(columns_count());
|
||||
}
|
||||
|
||||
|
||||
void Table::print() {
|
||||
std::cout << "** " << m_name << " **" << std::endl;
|
||||
for(auto row : m_rows) {
|
||||
for( auto col : row) {
|
||||
std::cout << col << ",";
|
||||
for(int ci = 0; ci < columns_count(); ci++) {
|
||||
auto v = row[ci].stringValue();
|
||||
std::cout << v << ",";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Table::Table(const Table& other) {
|
||||
m_name = other.m_name;
|
||||
m_col_defs = other.m_col_defs;
|
||||
m_rows.clear(); // row not copied now
|
||||
}
|
||||
|
||||
void Table::addRow(const Row &row) {
|
||||
m_rows.push_back(row);
|
||||
}
|
||||
|
||||
|
|
|
|||
16
table.h
16
table.h
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "parser.h"
|
||||
#include "row.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -8,14 +9,21 @@
|
|||
struct Table {
|
||||
|
||||
// public:
|
||||
Table(const Table& other);
|
||||
|
||||
Table(const std::string name, const std::vector<ColDefNode> columns);
|
||||
|
||||
ColDefNode get_column_def(const std::string col_name);
|
||||
ColDefNode get_column_def(const std::string& col_name);
|
||||
int columns_count() { return m_col_defs.size(); };
|
||||
|
||||
Row createEmptyRow(); // TODO this means unnecessary copying
|
||||
void addRow(const Row &row);
|
||||
|
||||
void print();
|
||||
|
||||
|
||||
// private:
|
||||
std::string m_name;
|
||||
std::vector<ColDefNode> m_col_defs;
|
||||
std::vector<std::vector<std::string>> m_rows;
|
||||
std::string m_name;
|
||||
std::vector<ColDefNode> m_col_defs;
|
||||
std::vector<Row> m_rows;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue