#include <string> #include <getopt.h> #include <iostream> #include "relData.h" #include <algorithm> using namespace std; class Primary { private: bool quiet; unordered_map<string, Table> tables; public: void set_defaults() { quiet = false; } void help_option() { cout << "This program is intended to emulate a relational database." << endl; cout << "For more information, read README.txt file." << endl; exit(0); } void option_management(int argc, char *argv[]) { string mode; opterr = false; int choice; int option_index = 0; // For information on getOpts and these statements below, read into the documentation of getOpts.h option longOpts[] = { { "quiet", no_argument, nullptr, 'q' }, { "help", no_argument, nullptr, 'h'}, { nullptr, 0, nullptr, '\0' }}; // Required closing bit while ((choice = getopt_long(argc, argv, "qh", longOpts, &option_index)) != -1) { switch (choice) { case 'q': { quiet = true; break; } // end case q case 'h': { help_option(); break; } // end case h default: cerr << "Unknown command line option" << endl; exit(1); } // End of Switch } // End of While } // end of option_management() void SQL() { string cmd; do { cout << "% "; cin >> cmd; char first = cmd.at(0); switch (first) { case '#': { string junk; getline(cin, junk); break; } // end case '#' case 'C': { string name; int number; cin >> name >> number; create_input_management(name, number); break; } // end case 'C' case 'I': { string inputName, junk; int inputNumber; cin >> junk >> inputName >> inputNumber >> junk; input_input_management(inputName, inputNumber); break; } // end case 'I' case 'D': { string inputName, junk; cin >> junk >> inputName >> junk; string command = "DELETE"; bool tableLegit = table_exist_check(command, inputName); if(!tableLegit) { break; } delete_input_management(inputName); break; } // end case 'D' case 'G': { string junk, inputName, type, colName; cin >> junk >> inputName >> type >> junk >> junk >> colName; string command = "GENERATE"; bool validTable = table_exist_check(command, inputName); if(!validTable) { break; } bool validCol = column_exist_check(command, colName, inputName); if(!validCol) { break; } generate_index_management(inputName, type, colName); break; } // end case 'G' case 'P': { string junk, inputname; int numCols; cin >> junk >> inputname >> numCols; string command = "PRINT"; bool tableValid = table_exist_check(command, inputname); if(!tableValid) { break; } print_input_management(inputname, numCols); break; } // end case 'P' case 'J': { join_input_management(); break; } // end case 'J' case 'R': { string inputname; cin >> inputname; string command = "REMOVE"; bool tableExist = table_exist_check(command, inputname); if(!tableExist) { break; } remove_input_management(inputname); break; } // end case 'R' default: { if(first == 'Q') { break; } else { cout << "Error: unrecognized command" << endl; break; } } // end default case } } while (cmd != "QUIT"); } void create_input_management(string &name, int &number) { string coltype; string colname; string temp = ""; // Checking to make sure a table with the same name doesn't already exist auto iter = tables.find(name); string junk2; if(iter != tables.end()) { getline(cin, junk2); cout << "Error during CREATE: "; cout << "Cannot create already existing table " << name << endl; return; } // If not, create the table tables[name]; for(size_t i = 0; i < static_cast <size_t> (number); i++) { cin >> coltype; if(coltype == "int") { pair<string, Metadata> insertionPair; insertionPair.second.datatype = Metadata::Datatype::Int; tables[name].columns.push_back(insertionPair); } // end case "int" else if(coltype == "string") { pair<string, Metadata> insertionPair; insertionPair.second.datatype = Metadata::Datatype::String; tables[name].columns.push_back(insertionPair); } // end case "string" else if(coltype == "bool") { pair<string, Metadata> insertionPair; insertionPair.second.datatype = Metadata::Datatype::Bool; tables[name].columns.push_back(insertionPair); } // end case "bool" else if(coltype == "double") { pair<string, Metadata> insertionPair; insertionPair.second.datatype = Metadata::Datatype::Double; tables[name].columns.push_back(insertionPair); } // end case "double" } tables[name].bstIndex = false; tables[name].hashIndex = false; tables[name].orderedMapIndexColNum = -1; tables[name].unorderedMapIndexColNum = -1; cout << "New table " << name << " with column(s) "; for(size_t i = 0; i < static_cast <size_t> (number); i++) { cin >> colname; tables[name].columns[i].first = colname; cout << tables[name].columns[i].first << " "; } cout << "created" << endl; } void input_input_management(string &inputname, int &inputnumber) { // Checking to make sure a table with the name provided exists auto iter = tables.find(inputname); string junk2; if(iter == tables.end()) { cout << "Error during INSERT: "; cout << inputname << " does not name a table in the database" << endl; return; } // If it does, insert the requested data auto it = tables.find(inputname); // Preventing excess memory using reserve size_t currentSize = it->second.data.size(); it->second.data.reserve(currentSize + static_cast<size_t>(inputnumber)); // Reading in proper datatype size_t horizontalSize = it->second.columns.size(); for(size_t i = currentSize; i < currentSize + static_cast<size_t>(inputnumber); i++) { vector<TableEntry> tempVec; tempVec.clear(); for(size_t j = 0; j < horizontalSize; j++) { if(it->second.columns[j].second.datatype == Metadata::Datatype::Int) { int num; cin >> num; tempVec.emplace_back(num); } else if(it->second.columns[j].second.datatype == Metadata::Datatype::String) { string sentence; cin >> sentence; tempVec.emplace_back(sentence); } else if(it->second.columns[j].second.datatype == Metadata::Datatype::Bool) { string tf; bool tf2; cin >> tf; if(tf == "true") { tf2 = true; } else if(tf == "false") { tf2 = false; } else { return; } tempVec.emplace_back(tf2); } else if(it->second.columns[j].second.datatype == Metadata::Datatype::Double) { double dec; cin >> dec; tempVec.emplace_back(dec); } } it->second.data.emplace_back(tempVec); } size_t col = 0; if(it->second.bstIndex == true) { col = static_cast<size_t>(it->second.orderedMapIndexColNum); for(size_t i = currentSize; i < it->second.data.size(); i++) { TableEntry te = it->second.data[i][col]; it->second.orderedMapIndex[te].push_back(static_cast<int>(i)); } } else if(it->second.hashIndex == true) { col = static_cast<size_t>(it->second.unorderedMapIndexColNum); for(size_t i = currentSize; i < it->second.data.size(); i++) { TableEntry te = it->second.data[i][col]; it->second.unorderedMapIndex[te].push_back(static_cast<int>(i)); } } cout << "Added " << inputnumber << " rows to " << inputname; cout << " from position " << currentSize << " to "; cout << it->second.data.size() - 1 << endl; } void print_input_management(string &inputname, int &colNums) { // Make space in vector for all column names requested to be printed, vector<string> colNames; colNames.reserve(static_cast<size_t>(colNums)); vector<int> indicies; indicies.reserve(static_cast<size_t>(colNums)); auto it = tables.find(inputname); // Take in those names and store them into the vector + checking if they exist bool colLegit; for(size_t i = 0; i < static_cast<size_t>(colNums); i++) { string colName; cin >> colName; string newC = "PRINT"; colLegit = column_exist_check(newC, colName, inputname); if(!colLegit) { return; } colNames.push_back(colName); } // Get rid of the 'where', unless its 'all', then do all: string whereOrAll; cin >> whereOrAll; if(whereOrAll == "ALL") { print_all(colNames, indicies, inputname); return; } // If it's 'where', then find all the indicies of the columns that were requested // But first, deal with the cin of column name, operation, and value string primaryName; char operation; cin >> primaryName >> operation; // Making sure primaryName is a real column in the table bool primaryLegit; string print = "PRINT"; primaryLegit = column_exist_check(print, primaryName, inputname); if(!primaryLegit) { return; } // Get indicies of columns in the colNames vector for(size_t i = 0; i < colNames.size(); i++) { for(size_t j = 0; j < it->second.columns.size(); j++) { if(colNames[i] == it->second.columns[j].first) { indicies.push_back(static_cast<int>(j)); } } } // I don't know what datatype to take in // We have helpers for that // First I have to find the index of that column // Finding index of the primary column (one with the operation on it) int temp = 0; for(size_t i = 0; i < it->second.columns.size(); i++) { if(it->second.columns[i].first == primaryName) { temp = static_cast<int>(i); } } // Now to do the 4-way split for datatypes if(it->second.columns[static_cast<size_t>(temp)].second.datatype == Metadata::Datatype::Int) { TableEntry intTE = int_helper(); print_comparisons(indicies, inputname, temp, intTE, operation); return; } else if(it->second.columns[static_cast<size_t>(temp)].second.datatype == Metadata::Datatype::Double) { TableEntry doubles = double_helper(); print_comparisons(indicies, inputname, temp, doubles, operation); return; } else if(it->second.columns[static_cast<size_t>(temp)].second.datatype == Metadata::Datatype::Bool) { TableEntry tOrF = bool_helper(); print_comparisons(indicies, inputname, temp, tOrF, operation); return; } else { TableEntry strings = string_helper(); print_comparisons(indicies, inputname, temp, strings, operation); return; } } void print_all(vector<string>& colNames, vector<int> indicies, string &inputname) { auto it = tables.find(inputname); for(size_t i = 0; i < colNames.size(); i++) { if(!quiet) { cout << colNames[i] << " "; } } if(!quiet) { cout << endl; } for(size_t i = 0; i < colNames.size(); i++) { for(size_t j = 0; j < it->second.columns.size(); j++) { if(colNames[i] == it->second.columns[j].first) { indicies.push_back(static_cast<int>(j)); } } } int numRows = 0; bool flag = false; for(size_t i = 0; i < it->second.data.size(); i++) { flag = false; for(size_t j = 0; j < indicies.size(); j++) { if(it->second.columns[static_cast<size_t>(indicies[j])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[i][static_cast<size_t>(indicies[j])] == false) { if(!quiet) { cout << "false "; } flag = true; } else { if(!quiet) { cout << "true "; } flag = true; } } else { if(!quiet) { cout << it->second.data[i][static_cast<size_t>(indicies[j])] << " "; } flag = true; } } if(flag) { if(!quiet) { cout << endl; } numRows++; } } cout << "Printed " << numRows << " matching rows from " << inputname << endl; return; } void print_comparisons(vector<int>& indicies, string &inputname, int &temp, TableEntry te, char &op) { // Okay, so now we have a TableEntry object to compare with... // Now, utilize the functors // Making comparisons between TableEntry object and every value of // the specified column and printing from our vector of indicies auto it = tables.find(inputname); // Printing column names bool temp2; for(size_t i = 0; i < indicies.size(); i++) { if(!quiet) { cout << it->second.columns[static_cast<size_t>(indicies[i])].first << " "; } } if(!quiet) { cout << endl; } int numRows = 0; // If generate index was done with type hash (only needs to be done with equals) if(it->second.unorderedMapIndexColNum == temp) { bool flag = false; if(op == '=') {; for(size_t i = 0; i < it->second.unorderedMapIndex[te].size(); i++) { flag = false; for(size_t j = 0; j < indicies.size(); j++) { if(it->second.columns[static_cast<size_t>(indicies[j])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[static_cast<size_t>(it->second.unorderedMapIndex[te][i])][static_cast<size_t>(indicies[j])] == false) { if(!quiet) { cout << "false "; } flag = true; } else { if(!quiet) { cout << "true "; } flag = true; } } else { if(!quiet) { cout << it->second.data[static_cast<size_t>(it->second.unorderedMapIndex[te][i])][static_cast<size_t>(indicies[j])] << " "; } flag = true; } } if(flag) { numRows++; if(!quiet) { cout << endl; } } } cout << "Printed " << numRows << " matching rows from " << inputname << endl; return; } } // If generate index was done with type bst (all operations) if(it->second.orderedMapIndexColNum == temp) { if(op == '=') { bool flag = false; for(size_t i = 0; i < it->second.orderedMapIndex[te].size(); i++) { flag = false; for(size_t j = 0; j < indicies.size(); j++) { if(it->second.columns[static_cast<size_t>(indicies[j])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[static_cast<size_t>(it->second.orderedMapIndex[te][i])][static_cast<size_t>(indicies[j])] == false) { if(!quiet) { cout << "false "; } flag = true; } else { if(!quiet) { cout << "true "; } flag = true; } } else { if(!quiet) { cout << it->second.data[static_cast<size_t>(it->second.orderedMapIndex[te][i])][static_cast<size_t>(indicies[j])] << " "; } flag = true; } } if(flag) { numRows++; if(!quiet) { cout << endl; } } } cout << "Printed " << numRows << " matching rows from " << inputname << endl; return; } else if(op == '>') { bool flag = false; auto lowerIt = it->second.orderedMapIndex.upper_bound(te); auto maxIt = it->second.orderedMapIndex.end(); for(auto i = lowerIt; i != maxIt; i++) { for(size_t j = 0; j < i->second.size(); j++) { flag = false; for(size_t c = 0; c < indicies.size(); c++) { if(it->second.columns[static_cast<size_t>(indicies[c])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[static_cast<size_t>(i->second[j])][static_cast<size_t>(indicies[c])] == false) { if(!quiet) { cout << "false "; } flag = true; } else { if(!quiet) { cout << "true "; } flag = true; } } else { if(!quiet) { cout << it->second.data[static_cast<size_t>(i->second[j])][static_cast<size_t>(indicies[c])] << " "; } flag = true; } } if(flag) { numRows++; if(!quiet) { cout << endl; } } } } cout << "Printed " << numRows << " matching rows from " << inputname << endl; return; } else if(op == '<') { bool flag = false; auto lowerIt = it->second.orderedMapIndex.begin(); auto maxIt = it->second.orderedMapIndex.lower_bound(te); for(auto i = lowerIt; i != maxIt; i++) { for(size_t j = 0; j < i->second.size(); j++) { flag = false; for(size_t c = 0; c < indicies.size(); c++) { if(it->second.columns[static_cast<size_t>(indicies[c])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[static_cast<size_t>(i->second[j])][static_cast<size_t>(indicies[c])] == false) { flag = true; if(!quiet) { cout << "false "; } } else { flag = true; if(!quiet) { cout << "true "; } } } else { flag = true; if(!quiet) { cout << it->second.data[static_cast<size_t>(i->second[j])][static_cast<size_t>(indicies[c])] << " "; } } } if(flag) { numRows++; if(!quiet) { cout << endl; } } } } cout << "Printed " << numRows << " matching rows from " << inputname << endl; return; } } // Printing without a generated index bool flag = false; for(size_t i = 0; i < it->second.data.size(); i++) { flag = false; for(size_t j = 0; j < indicies.size(); j++) { if(op == '=') { temp2 = equals_helper(te, it->second.data[i][static_cast<size_t>(temp)]); if(temp2 == true) { if(it->second.columns[static_cast<size_t>(indicies[j])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[i][static_cast<size_t>(indicies[j])] == false) { flag = true; if(!quiet) { cout << "false "; } } else { flag = true; if(!quiet) { cout << "true "; } } } else { flag = true; if(!quiet) { cout << it->second.data[i][static_cast<size_t>(indicies[j])] << " "; } } } } if(op == '>') { temp2 = less_helper(te, it->second.data[i][static_cast<size_t>(temp)]); if(temp2 == true) { if(it->second.columns[static_cast<size_t>(indicies[j])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[i][static_cast<size_t>(indicies[j])] == false) { if(!quiet) { cout << "false "; } flag = true; } else { if(!quiet) { cout << "true "; } flag = true; } } else { flag = true; if(!quiet) { cout << it->second.data[i][static_cast<size_t>(indicies[j])] << " "; } } } } if(op == '<') { temp2 = greater_helper(te, it->second.data[i][static_cast<size_t>(temp)]); if(temp2 == true) { if(it->second.columns[static_cast<size_t>(indicies[j])].second.datatype == Metadata::Datatype::Bool) { if(it->second.data[i][static_cast<size_t>(indicies[j])] == false) { if(!quiet) { cout << "false "; } flag = true; } else { if(!quiet) { cout << "true "; } flag = true; } } else { if(!quiet) { cout << it->second.data[i][static_cast<size_t>(indicies[j])] << " "; } flag = true; } } } } if(flag) { if(!quiet) { cout << endl; } numRows++; } } cout << "Printed " << numRows << " matching rows from " << inputname << endl; return; } void delete_input_management(string &inputname) { // Take in the column name and operation string primaryName; char operation; cin >> primaryName >> operation; // Checking if primaryName is in the table string strDel = "DELETE"; bool colExist = column_exist_check(strDel, primaryName, inputname); if(!colExist) { return; } auto it = tables.find(inputname); // Get the index of the column, could this be avoided by an index member variable? int temp = 0; for(size_t i = 0; i < it->second.columns.size(); i++) { if(it->second.columns[i].first == primaryName) { temp = static_cast<int>(i); } } // Okay, now to do the 4-way split for datatypes if(it->second.columns[static_cast<size_t>(temp)].second.datatype == Metadata::Datatype::Int) { TableEntry intTE = int_helper(); delete_if(inputname, temp, intTE, operation); return; } else if(it->second.columns[static_cast<size_t>(temp)].second.datatype == Metadata::Datatype::Double) { TableEntry doubles = double_helper(); delete_if(inputname, temp, doubles, operation); return; } else if(it->second.columns[static_cast<size_t>(temp)].second.datatype == Metadata::Datatype::Bool) { TableEntry tOrF = bool_helper(); delete_if(inputname, temp, tOrF, operation); return; } else { TableEntry strings = string_helper(); delete_if(inputname, temp, strings, operation); return; } } void delete_if(string &inputname, int &temp, TableEntry &te, char &operation) { auto iter = tables.find(inputname); // For purpose of the final print size_t dataSize = iter->second.data.size(); if(operation == '=') { auto it = iter->second.data.begin(); auto it2 = iter->second.data.end(); equalFunctor equal(temp, te); iter->second.data.erase(remove_if(it, it2, equal), it2); } if(operation == '>') { auto it = iter->second.data.begin(); auto it2 = iter->second.data.end(); lessFunctor le(temp, te); iter->second.data.erase(remove_if(it, it2, le), it2); } if(operation == '<') { auto it = iter->second.data.begin(); auto it2 = iter->second.data.end(); greaterFunctor gr(temp, te); iter->second.data.erase(remove_if(it, it2, gr), it2); } size_t newDataSize = iter->second.data.size(); cout << "Deleted " << dataSize - newDataSize << " rows from " << inputname << endl; if(iter->second.hashIndex || iter->second.bstIndex) { generate_index_post_delete(inputname); } } void remove_input_management(string &inputname) { tables.erase(inputname); cout << "Table " << inputname << " deleted" << endl; return; } void generate_index_management(string &inputname, string &type, string &colName) { auto it = tables.find(inputname); it->second.orderedMapIndex.clear(); it->second.unorderedMapIndex.clear(); it->second.orderedMapIndexColNum = -1; it->second.unorderedMapIndexColNum = -1; it->second.hashIndex = false; it->second.bstIndex = false; if(type == "hash") { it->second.hashIndex = true; size_t temp = 0; for(size_t i = 0; i < it->second.columns.size(); i++) { if(it->second.columns[i].first == colName) { temp = i; } } it->second.unorderedMapIndexColNum = static_cast<int>(temp); for(size_t i = 0; i < it->second.data.size(); i++) { it->second.unorderedMapIndex[it->second.data[i][temp]].push_back(static_cast<int>(i)); } cout << "Created hash index for table " << inputname << " on column " << colName << endl; return; } if(type == "bst") { it->second.bstIndex = true; size_t temp2 = 0; for(size_t i = 0; i < it->second.columns.size(); i++) { if(it->second.columns[i].first == colName) { temp2 = i; } } for(size_t i = 0; i < it->second.data.size(); i++) { it->second.orderedMapIndex[it->second.data[i][temp2]].push_back(static_cast<int>(i)); } it->second.orderedMapIndexColNum = static_cast<int>(temp2); cout << "Created bst index for table " << inputname << " on column " << colName << endl; return; } } void generate_index_post_delete(string &inputname) { auto it = tables.find(inputname); if(it->second.hashIndex) { it->second.unorderedMapIndex.clear(); size_t temp = static_cast<size_t>(it->second.unorderedMapIndexColNum); for(size_t i = 0; i < it->second.data.size(); i++) { it->second.unorderedMapIndex[it->second.data[i][temp]].push_back(static_cast<int>(i)); } return; } else if(it->second.bstIndex) { it->second.orderedMapIndex.clear(); size_t temp2 = static_cast<size_t>(it->second.orderedMapIndexColNum); for(size_t i = 0; i < it->second.data.size(); i++) { it->second.orderedMapIndex[it->second.data[i][temp2]].push_back(static_cast<int>(i)); } return; } } void join_input_management() { // All input management and error checking string junk, tablename1, tablename2, colname1, colname2; int n; char otherjunk; string command = "JOIN"; cin >> tablename1; if(!table_exist_check(command, tablename1)) { return; } cin >> junk >> tablename2; if(!table_exist_check(command, tablename2)) { return; } cin >> junk >> colname1; if(!column_exist_check(command, colname1, tablename1)) { return; } cin >> otherjunk >> colname2; if(!column_exist_check(command, colname2, tablename2)) { return; } cin >> junk >> junk >> n; // Storing print_colnameN and their respective '1's or '2's into pairs vector<pair<int, int>> printColNamePairs; string printcolname; int whichTable; printColNamePairs.reserve(static_cast<size_t>(n)); for(size_t i = 0; i < static_cast<size_t>(n); i++) { cin >> printcolname >> whichTable; if(whichTable == 1) { if(!column_exist_check(command, printcolname, tablename1)) { return; } for(size_t j = 0; j < tables[tablename1].columns.size(); j++) { if(tables[tablename1].columns[j].first == printcolname) { pair<int, int> tempPair; tempPair.first = static_cast<int>(j); tempPair.second = whichTable; printColNamePairs.push_back(tempPair); break; } } } else if(whichTable == 2) { if(!column_exist_check(command, printcolname, tablename2)) { return; } for(size_t k = 0; k < tables[tablename2].columns.size(); k++) { if(tables[tablename2].columns[k].first == printcolname) { pair<int, int> tempPair; tempPair.first = static_cast<int>(k); tempPair.second = whichTable; printColNamePairs.push_back(tempPair); break; } } } } // Find index of column int colTab1 = 0; int colTab2 = 0; for(size_t i = 0; i < tables[tablename1].columns.size(); i++) { if(tables[tablename1].columns[i].first == colname1) { colTab1 = static_cast<int>(i); } } for(size_t i = 0; i < tables[tablename2].columns.size(); i++) { if(tables[tablename2].columns[i].first == colname2) { colTab2 = static_cast<int>(i); } } // Doing generate index on the new column unordered_map<TableEntry, vector<int>> h; for(size_t i = 0; i < tables[tablename2].data.size(); i++) { h[tables[tablename2].data[i][static_cast<size_t>(colTab2)]].push_back(static_cast<int>(i)); } for(size_t i = 0; i < printColNamePairs.size(); i++) { if(printColNamePairs[i].second == 1) { if(!quiet) { cout << tables[tablename1].columns[static_cast<size_t>(printColNamePairs[i].first)].first << " "; } } else if(printColNamePairs[i].second == 2) { if(!quiet) { cout << tables[tablename2].columns[static_cast<size_t>(printColNamePairs[i].first)].first << " "; } } } if(!quiet) { cout << endl; } int numRowsPrint = 0; for(size_t i = 0; i < tables[tablename1].data.size(); i++) { if(h.find(tables[tablename1].data[i][static_cast<size_t>(colTab1)]) != h.end()) { for(size_t j = 0; j < h[tables[tablename1].data[i][static_cast<size_t>(colTab1)]].size(); j++) { for(size_t k = 0; k < printColNamePairs.size(); k++) { if(printColNamePairs[k].second == 1) { if(tables[tablename1].columns[static_cast<size_t>(printColNamePairs[k].first)].second.datatype == Metadata::Datatype::Bool) { if(tables[tablename1].data[i][static_cast<size_t>(printColNamePairs[k].first)] == false) { if(!quiet) { cout << "false "; } } else { if(!quiet) { cout << "true "; } } } else { if(!quiet) { cout << tables[tablename1].data[i][static_cast<size_t>(printColNamePairs[k].first)]<< " "; } } } else if(printColNamePairs[k].second == 2) { int row = h[tables[tablename1].data[i][static_cast<size_t>(colTab1)]][j]; if(tables[tablename2].columns[static_cast<size_t>(printColNamePairs[k].first)].second.datatype == Metadata::Datatype::Bool) { if(tables[tablename2].data[static_cast<size_t>(row)][static_cast<size_t>(printColNamePairs[k].first)] == false) { if(!quiet) { cout << "false "; } } else { if(!quiet) { cout << "true "; } } } else { if(!quiet) { cout << tables[tablename2].data[static_cast<size_t>(row)][static_cast<size_t>(printColNamePairs[k].first)] << " "; } } } } if(!quiet) { cout << endl; } numRowsPrint++; } } else { continue; } } cout << "Printed " << numRowsPrint << " rows from joining " << tablename1 << " to " << tablename2 << endl; return; } TableEntry string_helper() { string a; cin >> a; TableEntry c = TableEntry(a); return c; } TableEntry bool_helper() { string a; bool b; cin >> a; if(a == "true") { b = true; } else { b = false; } TableEntry c = TableEntry(b); return c; } TableEntry int_helper() { int a; cin >> a; TableEntry c = TableEntry(a); return c; } TableEntry double_helper() { double a; cin >> a; TableEntry c = TableEntry(a); return c; } bool equals_helper (const TableEntry &te1, const TableEntry &te2) const { return te1 == te2; } bool greater_helper (const TableEntry &te1, const TableEntry &te2) const { return te1 > te2; } bool less_helper (const TableEntry &te1, const TableEntry &te2) const { return te1 < te2; } bool table_exist_check(string &command, string &tablename) { auto iter = tables.find(tablename); string junk2; if(iter == tables.end()) { getline(cin, junk2); cout << "Error during " << command << ": " << tablename; cout << " does not name a table in the database" << endl; return false; } return true; } bool column_exist_check(string &command, string &colName, string &tablename) { for(size_t i = 0; i < tables[tablename].columns.size(); i++) { if(tables[tablename].columns[i].first == colName) { return true; } } string junk; getline(cin, junk); cout << "Error during " << command << ": " << colName; cout << " does not name a column in " << tablename << endl; return false; } }; int main(int argc, char *argv[]) { // I/O Speedup ios_base::sync_with_stdio(false); // Declaring and initializing an instance of the primary class Primary p1; p1.set_defaults(); p1.option_management(argc, argv); p1.SQL(); cout << "Thanks for using the relational database!" << endl; return 0; }