// Project Identifier: C0F4DFE8B340D81183C208F70F9D2D797908754D #include <queue> #include <stack> #include <deque> #include <list> #include <getopt.h> #include <sstream> #include <unistd.h> #include <iostream> #include <string> #include <vector> #include <stdio.h> #include <ctype.h> #include <algorithm> #include <map> #include <unordered_map> #include "functions.h" using namespace std; // COMMAND LINE //////////////////////////////////////////////////// void process_cmd_line(int argc, char** argv, Silly &silly){ //getopt int gotopt; int option_index = 0; static struct option long_opts[] = { {"help", no_argument, nullptr, 'h'}, {"quiet", no_argument, nullptr, 'q'}, {NULL, 0, NULL, 0} }; while((gotopt = getopt_long(argc, argv, "hq", long_opts, &option_index)) != -1){ switch(gotopt){ case 'h': std::cout << "You asked for help!\n"; exit(0); break; case 'q': silly.quiet = true; break; default: abort(); } } } // UTILITY //////////////////////////////////////////////////// // set command char set_command(string &cmd){ string junk; // COMMENT if(cmd[0] == '#'){ return 'y'; } // CREATE else if(cmd == "CREATE"){ return 'c'; } // QUIT else if(cmd == "QUIT"){ return 'q'; } // REMOVE else if(cmd == "REMOVE"){ return 'r'; } // INSERT else if(cmd == "INSERT"){ //get INTO cin >> junk; return 'i'; } // DELETE else if(cmd == "DELETE"){ //get FROM cin >> junk; return 'd'; } // PRINT else if(cmd == "PRINT"){ //get FROM cin >> junk; return 'p'; } // JOIN else if(cmd == "JOIN"){ return 'j'; } // GENERATE else if(cmd == "GENERATE"){ //get FOR cin >> junk; return 'g'; } return 'z'; } // create entry based on coltype TableEntry create_entry(Column &column){ // double if(column.coltype == 'd'){ double argument; cin >> argument; return TableEntry(argument); } // int else if(column.coltype == 'i'){ int argument; cin >> argument; return TableEntry(argument); } // bool else if(column.coltype == 'b'){ bool argument; cin >> argument; return TableEntry(argument); } // string else if(column.coltype == 's'){ string argument; cin >> argument; return TableEntry(argument); } else { return TableEntry(0); } } // if column in table, returns column index. else, returns -1 size_t get_col_index(string &colname, Table &table){ for(size_t i=0; i < table.cols.size(); i++){ // if column in table, return true if(table.cols[i].colname == colname){ return i; } } return static_cast<size_t>(-1); } // FUNCTIONS ////////////////////////////////////////////////////////////// // CREATE void create_table(string &argument, unordered_map<string, Table> &table_map){ std::cin >> argument; // ERROR CHECK: for if table already exists if(check_table_exists(argument, table_map)){ // print already exists print_table_exists(argument, "CREATE"); cin.clear(); return; } Table new_table(argument, 0); argument = ""; // in num columns cin >> argument; new_table.num_cols = stoi(argument); argument = ""; // in coltypes int name_count = new_table.num_cols; while(name_count > 0){ cin >> argument; Column column(argument[0]); new_table.cols.emplace_back(column); argument = ""; name_count--; } //in colnames for(size_t i=0; i< new_table.cols.size(); i++){ cin >> argument; new_table.cols[i].colname = argument; argument = ""; } // insert table into map std::pair<string, Table> insert_table (new_table.tablename, new_table); table_map.insert(insert_table); //ouput std::cout << "New table " << new_table.tablename << " with column(s) "; for(size_t i=0; i < new_table.cols.size(); i++){ std::cout << new_table.cols[i].colname << " "; } std::cout << "created\n"; } // INSERT void insert_into(string &argument, unordered_map<string, Table> &table_map){ // table_insert(tablename, table_map); // in tablename cin >> argument; string tablename = argument; argument = ""; // in num rows cin >> argument; int num_rows = stoi(argument); // in junk "ROWS" cin >> argument; argument = ""; // ERROR CHECK: if table does not exist if(!check_table_exists(tablename, table_map)){ // print does not exist print_table_n_exists(tablename, "INSERT"); cin.clear(); } else { auto it = table_map.find(tablename); // set start size_t start = it->second.cols[0].col.size(); // for each row for(int i=0; i < num_rows; i++){ // for each column for(size_t j=0; j < it->second.cols.size(); j++ ){ // check column type, create entry and push into column it->second.cols[j].col.emplace_back(create_entry(it->second.cols[j])); } } // set end size_t end = it->second.cols[0].col.size(); end--; std::cout << "Added " << num_rows << " rows to " << tablename << " from position " << start << " to " << end << "\n"; } } // takes coltype, operation and value, adjusts value based on coltype, and returns true if row should be deleted bool delete_check(char &coltype, TableEntry &col_entry, string &operation, string &value){ // if coltype is bool if(coltype == 'b'){ bool value_bool = false; if(value == "true"){ value_bool = true; } if(operation == "="){ return col_entry == value_bool; } else if(operation == ">"){ return col_entry > value_bool; } // less than else { return col_entry < value_bool; } } // if coltype is double else if(coltype == 'd'){ double value_double = stod(value); if(operation == "="){ return col_entry == value_double; } else if(operation == ">"){ return col_entry > value_double; } // less than else { return col_entry < value_double; } } // if coltype is int else if(coltype == 'i'){ int value_int = stoi(value); if(operation == "="){ return col_entry == value_int; } else if(operation == ">"){ return col_entry > value_int; } // less than else { return col_entry < value_int; } } // if coltype is string else{ if(operation == "="){ return col_entry == value; } else if(operation == ">"){ return col_entry > value; } // less than else{ return col_entry < value; } } return false; } // for each column in table, delete entry at col_index void execute_delete(Table &table, size_t col_index){ // vector<TableEntry>::iterator it; int delete_index= 0; for(size_t i=0; i < col_index; i++){ delete_index++; } // for each column in table, remove element at col index for(size_t i=0; i < table.cols.size(); i++){ // set it to item to be deleted auto it = table.cols[i].col.begin() + delete_index; vector<TableEntry> split; it++; // add to split after delete point while(it != table.cols[i].col.end()){ split.emplace_back(*it); it++; } // clear out original for(size_t j=0; j < split.size(); j++){ table.cols[i].col.pop_back(); } // delete table.cols[i].col.pop_back(); // add back to original // std::vector<TableEntry>::reverse_iterator iter = split.rbegin(); for(size_t k=0; k < split.size(); k++){ table.cols[i].col.emplace_back(split[k]); } while(!split.empty()){ split.pop_back(); } } } //delete rows void delete_rows(string &argument, unordered_map<std::string, Table> &table_map){ // get tablename string tablename; cin >> argument; tablename = argument; argument = ""; // cin WHERE cin >> argument; argument = ""; // get colname string colname; cin >> colname; // get operation string operation; cin >> operation; // get value cin >> argument; // ERROR CHECK: if table does not exist if(!check_table_exists(tablename, table_map)){ // print does not exist print_table_n_exists(tablename, "DELETE"); cin.clear(); return; } auto it = table_map.find(tablename); // ERROR CHECK: if column does not exist if(!check_column(colname, it->second)){ // print does not exist print_check_column(colname, "DELETE", it->second); cin.clear(); return; } // adjust value for(size_t i=0; i<it->second.cols.size(); i++){ if(it->second.cols[i].colname == colname){ string delete_coltype; delete_coltype = it->second.cols[i].coltype; } } // value will always be same type as coltype int delete_count = 0; //set search column to colname for(size_t i=0; i < it->second.cols.size(); i++){ if(it->second.cols[i].colname == colname){ //if column entry with op == true, delete row for(size_t j = 0; j < it->second.cols[i].col.size(); j++){ //if delete check returns true, delete entry index for each column in table if(delete_check(it->second.cols[i].coltype, it->second.cols[i].col[j], operation, argument) == true){ execute_delete(it->second, j); delete_count++; } } } } std::cout << "Deleted " << delete_count << " rows from " << tablename << "\n"; } // generate index void generate_index(string &colname, unordered_map<std::string, Table> &table_map){ string tablename; cin >> tablename; string indextype; cin >> indextype; // junk cin >> colname; cin >> colname; colname = ""; // get colname cin >> colname; // set table it // ERROR: table does not exist if(!check_table_exists(tablename, table_map)){ print_table_n_exists(tablename, "GENERATE"); cin.clear(); return; } auto it = table_map.find(tablename); // set column index // ERROR: colname not in table if(!check_column(colname, it->second)){ print_check_column(colname, "GENERATE", it->second); cin.clear(); return; } size_t index = get_col_index(colname, it->second); // clear if current index exists if(!it->second.cols[index].hash_map.empty()){ it->second.cols[index].hash_map.clear(); } if(!it->second.cols[index].bst_map.empty()){ it->second.cols[index].bst_map.clear(); } // HASH // keep track of insertion order into table // given column value in colname, row index is easy to find // key is column value, value is row index // iterate through column // create table entry, row index pair // insert to hash map if(indextype == "hash"){ // set booleans it->second.cols[index].hash_index = true; it->second.cols[index].bst_index = false; // iterate through given column for(size_t i=0; i < it->second.cols[index].col.size(); i++){ // i = row index // create + insert key (entry) value (row) pair it->second.cols[index].hash_map.insert(make_pair(it->second.cols[index].col[i], i)); } } // BST if(indextype == "bst"){ // set booleans it->second.cols[index].bst_index = true; it->second.cols[index].hash_index = false; // iterate through given column for(size_t i=0; i < it->second.cols[index].col.size(); i++){ // i = row index // create + insert key (entry) value (row) pair it->second.cols[index].bst_map.insert(make_pair(it->second.cols[index].col[i], i)); } } std::cout << "Created " << indextype << " index for table " << tablename << " on column " << colname << "\n"; } // takes coltype, operation and value, adjusts value based on coltype, and returns true if row should be printed bool print_check(Table &table_map, size_t &index, string &colname, string &operation, string &value){ // for each column in table for(size_t i=0; i < table_map.cols.size(); i++){ // find op column if(table_map.cols[i].colname == colname){ // if coltype is bool if(table_map.cols[i].coltype == 'b'){ bool value_bool = false; if(value == "true"){ value_bool = true; } if(operation == "="){ return table_map.cols[i].col[index] == value_bool; } else if(operation == ">"){ return table_map.cols[i].col[index] > value_bool; } // less than else { return table_map.cols[i].col[index] < value_bool; } } // if coltype is double else if(table_map.cols[i].coltype == 'd'){ double value_double = stod(value); if(operation == "="){ return table_map.cols[i].col[index] == value_double; } else if(operation == ">"){ return table_map.cols[i].col[index] > value_double; } // less than else { return table_map.cols[i].col[index] < value_double; } } // if coltype is int else if(table_map.cols[i].coltype == 'i'){ int value_int = stoi(value); if(operation == "="){ return table_map.cols[i].col[index] == value_int; } else if(operation == ">"){ return table_map.cols[i].col[index] > value_int; } // less than else { return table_map.cols[i].col[index] < value_int; } } // if coltype is string else{ if(operation == "="){ return table_map.cols[i].col[index] == value; } else if(operation == ">"){ return table_map.cols[i].col[index] > value; } // less than else{ return table_map.cols[i].col[index] < value; } } } } //colname not found return false; } // print void print_rows(string &argument, unordered_map<std::string, Table> &table_map, Silly &silly){ // get table name string tablename; cin >> argument; tablename = argument; argument = ""; // get col number int col_num; cin >> argument; col_num = stoi(argument); argument = ""; size_t row_count = 0; vector<string> cols_to_print; while(col_num > 0){ cin >> argument; cols_to_print.push_back(argument); col_num--; } // get argument argument = ""; cin >> argument; if(!silly.quiet){ // print column names for(size_t i=0; i<cols_to_print.size(); i++){ std::cout << cols_to_print[i] << " "; } std::cout << "\n"; } // ALL if(argument == "ALL"){ // set it to table auto it = table_map.find(tablename); // for length of column for(size_t i=0; i < it->second.cols[0].col.size(); i++){ // iterate through columns to print for(size_t k=0; k < cols_to_print.size(); k++){ // ERROR: col_to_print not in table if(!check_column(cols_to_print[k], it->second)){ print_check_column(cols_to_print[k], "PRINT", it->second); cin.clear(); return; } size_t print_index = get_col_index(cols_to_print[k], it->second); // !QUIET if(!silly.quiet){ // PRINTING std::cout << it->second.cols[print_index].col[i] << " "; } } row_count++; std::cout << "\n"; } } // WHERE if(argument == "WHERE"){ string colname = ""; string operation = ""; string condition; cin >> colname >> operation >> condition; auto it = table_map.find(tablename); // for column length for(size_t i=0; i < it->second.cols[0].col.size(); i++){ // check if row should be skipped if(print_check(it->second, i, colname, operation, condition)){ // iterate through cols to print for(size_t k=0; k < cols_to_print.size(); k++){ // ERROR: col_to_print not in table if(!check_column(cols_to_print[k], it->second)){ print_check_column(cols_to_print[k], "PRINT", it->second); cin.clear(); return; } // get column to print size_t print_index = get_col_index(cols_to_print[k], it->second); // !QUIET if(!silly.quiet){ // PRINTING // if BST /* if(it->second.cols[print_index].bst_index == true){ //variable i needs to be different // create map iterator map<TableEntry, size_t>::iterator bst_it; // set iterator to beginning of map bst_it = it->second.cols[print_index].bst_map.begin(); size_t increment = 0; while(increment != i){ ++increment; ++bst_it; std::cout << bst_it->first << " "; } } */ //else{ std::cout << it->second.cols[print_index].col[i] << " "; //} } } } else { continue; } row_count++; std::cout << "\n"; } } std::cout << "Printed " << row_count << " matching rows from " << tablename << "\n"; } // print join row // print each column in row void print_j_row(Table &table1, Table &table2, vector<string> &colnames, vector<int> &table_specs, size_t &index_one, size_t &index_two){ // for colnames container for(size_t i=0; i < colnames.size(); i++){ // if column is from table 1 if(table_specs[i] == 1){ // set col index in table 1 size_t col_index = get_col_index(colnames[i], table1); // print item in column at row index std::cout << table1.cols[col_index].col[index_one] << " "; } // table_specs[i] is 2 else { // set col index in table 2 size_t col_index = get_col_index(colnames[i], table2); // print item in column at row index std::cout << table2.cols[col_index].col[index_two] << " "; } } std::cout << "\n"; } // JOIN // print rows where col1 matches col2 void join_tables(string &argument, unordered_map<string, Table> &table_map, Silly &silly){ // join tables where values in selected columns match // INPUT string tablename_one; string tablename_two; string colname_one; string colname_two; string order; // order in printing vector<int> table_specs; vector<string> colnames; size_t count; string junk; // get t1 cin >> tablename_one; // AND cin >> junk; // get t2 cin >> tablename_two; // WHERE cin >> junk; cin >>colname_one; // = cin >> junk; // get colname two cin >> colname_two; // AND PRINT cin >> junk; cin >> junk; // get rowcount cin >> argument; count = static_cast<size_t>(stoi(argument)); argument = ""; // get output specs size_t cin_count = 0; while(cin_count != count){ // get column name cin >> argument; colnames.push_back(argument); argument = ""; // get table cin >> argument; table_specs.push_back(stoi(argument)); cin_count++; } if(!silly.quiet){ // output colnames for(size_t i=0; i < colnames.size(); i++){ std::cout << colnames[i] << " "; } std::cout << "\n"; } // OUTPUT TABLE INFO // error check tables // ERROR: tablename_one does not exist if(!check_table_exists(tablename_one, table_map)){ print_table_n_exists(tablename_one, "JOIN"); cin.clear(); return; } // ERROR: tablename_two does not exist if(!check_table_exists(tablename_two, table_map)){ print_table_n_exists(tablename_two, "JOIN"); cin.clear(); return; } // assign table its auto it1 = table_map.find(tablename_one); auto it2 = table_map.find(tablename_two); // GET COLUMNS // init column indexes size_t index_one = 0; size_t index_two = 0; // ERROR: colname_one not in table_one if(!check_column(colname_one, it1->second)){ print_check_column(colname_one, "JOIN", it1->second); cin.clear(); return; } // ERROR: colname_two not in table_two if(!check_column(colname_two, it2->second)){ print_check_column(colname_two, "JOIN", it2->second); cin.clear(); return; } index_one = get_col_index(colname_one, it1->second); index_two = get_col_index(colname_two, it2->second); // for the length of colname one for(size_t i=0; i < it1->second.cols[index_one].col.size(); i++){ // for the length of colname two for(size_t j=0; j < it2->second.cols[index_two].col.size(); j++){ // if value in col one is equal to value in col 2 if(it1->second.cols[index_one].col[i] == it2->second.cols[index_two].col[j]){ //std:: cout << it1->second.cols[index_one].col[j] << " and " << it2->second.cols[index_two].col[k] << " are equal.\n"; // print row if(!silly.quiet){ print_j_row(it1->second, it2->second, colnames, table_specs, i, j); } } } } std::cout << "Printed " << count << " rows from joining " << tablename_one << " to " << tablename_two << "\n"; } // REMOVE void remove_table(string &argument, unordered_map<string, Table> &table_map){ cin >> argument; // ERROR CHECK: if table doesn't exist if(!check_table_exists(argument, table_map)){ print_table_n_exists(argument, "REMOVE"); cin.clear(); } else { table_map.erase(argument); std::cout << "Table " << argument << " deleted\n"; } } // ERRORS // table already exists bool check_table_exists(string &tablename, unordered_map<string, Table> &table_map){ // if table already exists, return true if(table_map.find(tablename) == table_map.end()){ return false; } return true; } // print already exists void print_table_exists(string &tablename, string command){ std::cout << "Error during " << command << ": Cannot create already existing table " << tablename << ".\n"; } // print does not exist void print_table_n_exists(string &tablename, string command){ std::cout << "Error during " << command << ": Cannot create already existing table " << tablename << " does not name a table in the database\n"; } // returns true if column is in table bool check_column(string &colname, Table &table){ if(get_col_index(colname, table) == static_cast<size_t>(-1)){ return false; } return true; } // print column not in table void print_check_column(string &colname, string command, Table &table){ std::cout << "Error during " << command << ": " << colname << " does not name a column in " << table.tablename << "\n"; }