usql update

This commit is contained in:
2021-08-23 18:14:05 +02:00
parent 8d220356f2
commit 0e90d6047c
28 changed files with 1623 additions and 3774 deletions

View File

@@ -1,29 +1,49 @@
#include "table.h"
#include "csvreader.h"
#include "ml_string.h"
#include <fstream>
#include <algorithm>
namespace usql {
Table::Table(const std::string name, const std::vector<ColDefNode> columns) {
Table::Table(const std::string& name, const std::vector<ColDefNode>& columns) {
m_name = name;
m_col_defs = columns;
m_rows.clear();
m_rows.reserve(256);
}
Table::Table(const Table &other) {
m_name = other.m_name;
m_col_defs = other.m_col_defs;
m_rows.reserve(other.m_rows.size());
for(const Row& orig_row : other.m_rows) {
commit_copy_of_row(orig_row);
}
}
ColDefNode Table::get_column_def(const std::string &col_name) {
auto name_cmp = [col_name](ColDefNode cd) { return cd.name == col_name; };
auto name_cmp = [col_name](const ColDefNode& cd) { return cd.name == col_name; };
auto col_def = std::find_if(begin(m_col_defs), end(m_col_defs), name_cmp);
if (col_def != std::end(m_col_defs)) {
return *col_def;
} else {
throw Exception("column not exists (" + col_name + ")");
throw Exception("column does not exist (" + col_name + ")");
}
}
ColDefNode Table::get_column_def(int col_index) {
if (col_index >= 0 && col_index < columns_count()) {
return m_col_defs[col_index];
} else {
throw Exception("column with this index does not exists (" + std::to_string(col_index) + ")");
}
}
Row Table::create_empty_row() {
return Row(columns_count());
Row& Table::create_empty_row() {
m_rows.emplace_back(columns_count());
return m_rows.back();
}
std::string Table::csv_string() {
@@ -35,14 +55,14 @@ std::string Table::csv_string() {
}
// rows
for (auto it = m_rows.begin(); it != m_rows.end(); ++it) {
for (auto & m_row : m_rows) {
std::string csv_line{"\n"};
for(int i = 0; i < m_col_defs.size(); i++) {
if (i > 0) csv_line += ",";
auto col = it->ith_column(i);
if (!col->isNull()) {
csv_line += col->getStringValue(); // TODO handle enclosing commas etc
auto & col = m_row[i];
if (!col.isNull()) {
csv_line += col.getStringValue(); // TODO handle enclosing commas etc
}
}
out_string += csv_line;
@@ -52,87 +72,150 @@ std::string Table::csv_string() {
}
int Table::load_csv_string(const std::string &content) {
int row_cnt = 0;
CsvReader csvparser{};
auto csv = csvparser.parseCSV(content);
std::vector<ColDefNode> &colDefs = m_col_defs;
for (auto it = csv.begin() + 1; it != csv.end(); ++it) {
std::vector<std::string> 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++;
}
CsvReader csvparser{};
int row_cnt = csvparser.parseCSV2(content, colDefs, *this);
return row_cnt;
}
int Table::load_csv_file(const std::string &filename) {
std::vector<ColDefNode> &colDefs = m_col_defs;
// allocate enough space
int line_size = 128;
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
auto file_size = in.tellg();
std::ifstream infile(filename);
if (infile.good()) {
std::string sLine;
std::getline(infile, sLine);
line_size = (int)sLine.size();
}
infile.close();
if (file_size > 0) {
auto new_size = m_rows.size() + int(file_size / line_size * 1.20);
m_rows.reserve(new_size);
}
// load rows
CsvReader csvparser{};
int row_cnt = csvparser.parseCSV(filename, colDefs, *this);
return row_cnt;
}
void Table::create_row_from_vector(const std::vector<ColDefNode> &colDefs, const std::vector<std::string> &csv_line) {
// prepare empty new_row
Row& new_row = create_empty_row();
// copy values
for (int i = 0; i < std::min<int>(columns_count(), csv_line.size()); i++) {
const ColDefNode & col_def = colDefs[i];
if (csv_line[i].empty()) {
new_row.setColumnNull(col_def.order);
} else if (col_def.type == ColumnType::integer_type) {
new_row.setIntColumnValue(col_def.order, string_to_long(csv_line[i]));
} else if (col_def.type == ColumnType::float_type) {
new_row.setFloatColumnValue(col_def.order, string_to_double(csv_line[i]));
} else if (col_def.type == ColumnType::varchar_type) {
new_row.setStringColumnValue(col_def.order, csv_line[i]);
} else if (col_def.type == ColumnType::date_type) {
new_row.setDateColumnValue(col_def.order, csv_line[i]);
} else if (col_def.type == ColumnType::bool_type) {
new_row.setBoolColumnValue(col_def.order, csv_line[i]);
} else
throw Exception("unsupported column type");
}
// append new_row
commit_row(new_row);
}
double Table::string_to_double(const std::string &s) {
try {
return std::stod(s);
} catch (std::invalid_argument &e) {
throw Exception("error parsing as double: " + s);
}
}
long Table::string_to_long(const std::string &s) {
try {
return std::stol(s);
} catch (std::invalid_argument &e) {
throw Exception("error parsing as integer: " + s);
}
}
void Table::print() {
std::cout << "** " << m_name << " **" << std::endl;
for (auto row : m_rows) {
row.print();
std::string out{"| "};
std::string out2{"+-"};
for(const auto& col_def : m_col_defs) {
int col_size = Row::print_get_column_size(col_def);
if (col_def.type==ColumnType::integer_type || col_def.type==ColumnType::float_type || col_def.type==ColumnType::bool_type)
out.append(string_padd(col_def.name, col_size, ' ', false) + " | ");
else
out.append(string_padd(col_def.name, col_size, ' ', true) + " | ");
out2.append(string_padd("-", col_size, '-', true) + "-+ ");
}
// std::cout << "** " << m_name << " **" << std::endl;
std::cout << out << std::endl;
std::cout << out2 << std::endl;
for(auto& row : m_rows) {
row.print(m_col_defs);
}
std::cout << std::endl;
}
void Table::commit_row(const Row &row) {
try {
validate_row(row);
} catch (Exception &e) {
m_rows.erase(m_rows.end() - 1);
throw e;
}
}
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) {
add_copy_of_row(orig_row);
}
}
void Table::add_row(const Row &row) {
validate_row(row);
m_rows.push_back(row);
}
void Table::add_copy_of_row(const Row &row) {
Row new_row = create_empty_row();
void Table::commit_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.ith_column(i);
ColValue &ct = row[i];
if (ct->isNull()) {
if (ct.isNull()) {
new_row.setColumnNull(i);
} else {
if (m_col_defs[i].type == ColumnType::integer_type) {
new_row.setColumnValue(i, row.ith_column(i)->getIntValue());
new_row.setIntColumnValue(i, row[i].getIntValue());
} else if (m_col_defs[i].type == ColumnType::float_type) {
new_row.setColumnValue(i, row.ith_column(i)->getDoubleValue());
new_row.setFloatColumnValue(i, row[i].getDoubleValue());
} else if (m_col_defs[i].type == ColumnType::varchar_type) {
new_row.setColumnValue(i, row.ith_column(i)->getStringValue());
}
new_row.setStringColumnValue(i, row[i].getStringValue());
} else if (m_col_defs[i].type == ColumnType::date_type) {
new_row.setDateColumnValue(i, row[i].getDateValue());
} else if (m_col_defs[i].type == ColumnType::bool_type) {
new_row.setBoolColumnValue(i, row[i].getBoolValue());
} else
throw Exception("unsupported column type");
}
}
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()) {
if (!col_def->null && col_val->isNull()) {
throw Exception("Column " + col_def->name + " cannot be null");
}
if (col_def->type == ColumnType::varchar_type && !col_val->isNull() && col_val->getStringValue().size() > col_def->length) {
@@ -140,22 +223,22 @@ void Table::validate_column(const ColDefNode *col_def, ValueNode *col_val) {
}
}
void Table::validate_column(const ColDefNode *col_def, ColValue *col_val) {
if (col_def->null == false && col_val->isNull()) {
void Table::validate_column(const ColDefNode *col_def, ColValue &col_val) {
if (!col_def->null && col_val.isNull()) {
throw Exception("Column " + col_def->name + " cannot be null");
}
if (col_def->type == ColumnType::varchar_type && !col_val->isNull() && col_val->getStringValue().size() > col_def->length) {
throw Exception("Column value of " + col_def->name + " is too long (" + col_val->getStringValue() + ")");
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);
ColValue &col_val = row[i];
validate_column(&col_def, col_val);
}
}
} // namespace
} // namespace