#include "table.h" #include "csvreader.h" #include "ml_string.h" #include #include #include namespace usql { Table::Table(const std::string& name, const std::vector& columns) { m_name = name; m_col_defs = columns; 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) if (orig_row.is_visible()) commit_copy_of_row((Row&)orig_row); } ColDefNode Table::get_column_def(const std::string &col_name) { auto name_cmp = [col_name](const ColDefNode& cd) { return cd.name == col_name; }; auto col_def = std::find_if(std::begin(m_col_defs), std::end(m_col_defs), name_cmp); if (col_def != std::end(m_col_defs)) { return *col_def; } else { 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 m_index does not exists (" + std::to_string(col_index) + ")"); } } Row& Table::create_empty_row() { std::unique_lock guard(m_insert_guard); m_rows.emplace_back(columns_count(), false); return m_rows.back(); } void Table::create_row_from_vector(const std::vector &colDefs, const std::vector &csv_line) { // prepare empty new_row Row& new_row = create_empty_row(); // copy values for (size_t i = 0; i < std::min(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, Settings::string_to_long(csv_line[i])); } else if (col_def.type == ColumnType::float_type) { new_row.setFloatColumnValue(col_def.order, Settings::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); } std::string Table::csv_string() { const size_t k_row_size_est = m_col_defs.size() * 16; std::string out_string; out_string.reserve(m_rows.size() * k_row_size_est); // header for(size_t i = 0; i < m_col_defs.size(); i++) { if (i > 0) out_string += ','; out_string += m_col_defs[i].name; } // rows for (auto & row : m_rows) { if (row.is_visible()) { std::string csv_line{"\n"}; csv_line.reserve(k_row_size_est); for (size_t i = 0; i < m_col_defs.size(); i++) { if (i > 0) csv_line += ','; auto &col = row[i]; if (!col.isNull()) { csv_line += col.getCsvStringValue(); } } out_string += csv_line; } } return out_string; } size_t Table::load_csv_string(const std::string &content) { std::vector &colDefs = m_col_defs; CsvReader csvparser{}; auto row_cnt = csvparser.parseCSVString(content, colDefs, *this); return row_cnt; } size_t Table::load_csv_file(const std::string &filename) { std::vector &colDefs = m_col_defs; // allocate enough space int line_size = 256; 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() + 1; } 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{}; auto row_cnt = csvparser.parseCSVFile(filename, colDefs, *this); return row_cnt; } void Table::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; } size_t Table::get_rowid(const Row &row) const { const Row* row_addr = (Row*)&row; const Row* begin_addr = &(*m_rows.begin()); return row_addr - begin_addr; } void Table::commit_row(Row &row) { try { validate_row(row); index_row(row); } catch (const Exception &e) { throw e; } } void Table::commit_copy_of_row(Row &row) { Row& new_row = create_empty_row(); for(size_t i = 0; i < m_col_defs.size(); i++) { ColValue &ct = row[i]; if (ct.isNull()) { new_row.setColumnNull(i); } else { if (m_col_defs[i].type == ColumnType::integer_type) { new_row.setIntColumnValue(i, row[i].getIntegerValue()); } else if (m_col_defs[i].type == ColumnType::float_type) { new_row.setFloatColumnValue(i, row[i].getDoubleValue()); } else if (m_col_defs[i].type == ColumnType::varchar_type) { 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); index_row(row); } void Table::validate_column(const ColDefNode *col_def, ValueNode *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() + ")"); } } 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() + ")"); } void Table::validate_row(Row &row) { for(size_t i = 0; i < m_col_defs.size(); i++) { ColDefNode col_def = m_col_defs[i]; ColValue &col_val = row[i]; validate_column(&col_def, col_val); } row.set_visible(); } void Table::create_index(const Index& index) { m_indexes.push_back(index); } bool Table::drop_index(const std::string &index_name) { auto it = std::find_if(m_indexes.begin(), m_indexes.end(), [&index_name](const Index &idx) { return idx.get_index_name() == index_name; }); if (it != m_indexes.end()) { m_indexes.erase(it); return true; } return false; } void Table::index_row(Index &index, const ColDefNode &col_def, const Row &row, const size_t rowid) { index.insert(reinterpret_cast(&row[col_def.order]), rowid); } void Table::unindex_row(Index &index, const ColDefNode &col_def, const Row &row, const size_t rowid) { index.remove(reinterpret_cast(&row[col_def.order]), rowid); } void Table::reindex_row(Index &index, const ColDefNode &col_def, const Row &old_row, const Row &new_row, size_t rowid) { unindex_row(index, col_def, old_row, rowid); index_row(index, col_def, new_row, rowid); } void Table::index_row(const Row &row) { if (!m_indexes.empty()) { const size_t rowid = get_rowid(row); std::unique_lock guard(m_insert_guard); for (auto &idx : m_indexes) { ColDefNode cDef = get_column_def(idx.get_column_name()); index_row(idx, cDef, row, rowid); } } } void Table::unindex_row(const Row &row) { if (!m_indexes.empty()) { const size_t rowid = get_rowid(row); for (auto &idx : m_indexes) { ColDefNode cDef = get_column_def(idx.get_column_name()); unindex_row(idx, cDef, row, rowid); } } } void Table::reindex_row(const Row &old_row, const Row &new_row) { if (!m_indexes.empty()) { const size_t rowid = get_rowid(new_row); for (auto &idx : m_indexes) { ColDefNode cDef = get_column_def(idx.get_column_name()); reindex_row(idx, cDef, old_row, new_row, rowid); } } } void Table::index_rows(const std::string &index_name) { auto index = get_index(index_name); ColDefNode cDef = get_column_def(index->get_column_name()); size_t rowid = 0; for(const Row& r : m_rows) { index_row(*index, cDef, r, rowid); rowid++; } } Index * Table::get_index(const std::string &index_name) { auto it = std::find_if(m_indexes.begin(), m_indexes.end(), [&index_name](const Index &idx) { return idx.get_index_name() == index_name; }); return (it != m_indexes.end()) ? &(*it) : nullptr; } Index * Table::get_index_for_column(const std::string &col_name) { auto it = std::find_if(m_indexes.begin(), m_indexes.end(), [&col_name](const Index &idx) { return idx.get_column_name() == col_name; }); return (it != m_indexes.end()) ? &(*it) : nullptr; } bool Table::empty() const { if (m_rows.empty()) return true; for (const auto & r : m_rows) if (r.is_visible()) return false; return true; } Row *Table::rows_scanner::next() { if (m_use_rowids) { while (m_rowids_idx < m_rowids.size()) { auto row_ptr = &m_table->m_rows[m_rowids[m_rowids_idx]]; if (row_ptr->is_visible()) { m_rowids_idx++; return row_ptr; } m_rowids_idx++; } } else { while (m_fscan_itr != m_table->m_rows.end()) { if (m_fscan_itr->is_visible()) { auto i = m_fscan_itr; m_fscan_itr++; return &(*i); } m_fscan_itr++; } } return nullptr; } } // namespace