/** * @file main.cpp * @author Miguel Muniz * @brief main file for program, creates objects and calls functions. * Also reads in user input or inputed file and parses them. * @version 3.0 * @date 2023-04-24 */ //libraries #include "SQLManager.h" #include #include #include #include #include #include //namespaces using namespace std; namespace fs = std::filesystem; //namespace for file system //object declarations Database db; Table tb; DataManager dataM; //function prototypes void parser(string userInput); int main(int argc, char* argv[]){ //main function string userInput; if (argc == 2) { //checks if there are command line arguments string line, input; //size_t pos; ifstream myfile (argv[1]); if (!myfile) { std::cerr << "Error: could not open file " << argv[1] << std::endl; return 1; } else if (myfile.is_open()) { while ( getline (myfile,line) ){ //reads in file line by line // Replace any newline characters with spaces line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); if (line.empty()) { continue; } else if (line.find("--") != std::string::npos) { continue; } else if (line.find(';') != std::string::npos) { input += line; parser(input); // cout << "semi: " << input << endl; input.clear(); } else if (line.find('\n') == std::string::npos) { //input += line; line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); replace(line.begin(), line.end(), '\n', ' '); //cout << "newline: " << line << endl; input += line; continue; } //cout << input << endl; } //cout << input << endl; cout << "All Done." << endl; myfile.close(); } else { cout << "Invalid command line arguments" << endl; } } else if(argc == 1) { // is for manual input do{ getline(cin, userInput); if( userInput != ".EXIT"){ //prevents .EXIT from being parsed parser(userInput); } }while(userInput != ".EXIT"); } else { cout << "Invalid command line arguments" << endl; } return 0; } void parser(string userInput){ //parses the user input and calls the appropriate function from object // Remove non-printable characters from userInput // Remove all whitespace from userInput //userInput.erase(remove(userInput.begin(), userInput.end(), '\r'), userInput.end()); //userInput.erase(remove(userInput.begin(), userInput.end(), '\n'), userInput.end()); userInput.erase(remove(userInput.begin(), userInput.end(), '\t'), userInput.end()); //cout << "userInput: " << userInput << endl; vector tokens; stringstream ss(userInput); string token; while (getline(ss, token, ' ')) { // split string by spaces if (token.empty()) { // skip empty tokens continue; } token.erase(remove_if(token.begin(), token.end(), [](char c){ return !isprint(c); }), token.end()); // remove non-printable characters tokens.push_back(token); // add token to vector } if (tokens[0] == "CREATE" || tokens[0] == "create") { if(tokens.size() == 3 && tokens[1] == "DATABASE"){ string database_name = tokens[2]; database_name.erase(remove(database_name.begin(), database_name.end(), ';'), database_name.end()); //remove ; from string db.CreateDB(database_name); } else if (tokens[1] == "TABLE" || tokens[1] == "table"){ // Need to fix so that columns and datatypes are arrays. //string table_name = tokens[2]; string table_name = tokens[2].substr(0, tokens[2].find("(")); //grabs the id column if next to parentheses size_t start_pos = tokens[2].find_first_of("("); string sub_Fstr = tokens[2].substr(start_pos + 1); size_t end_pos = sub_str.find_first_of(" ,)"); string emp_id_str = sub_str.substr(0, end_pos); //cout << "Employee ID: " << emp_id_str << std::endl; //cout << "sub_str: " << sub_str << endl; string data_type; size_t pos, values_pos ,semi_pos; //cout << "meow" << endl data_type = emp_id_str + " "; //finds the position of the first ( and ) and removes them but not for var char for (unsigned int i = 3; i < tokens.size(); i++){ pos = tokens[i].find("varchar"); values_pos = tokens[i].find("("); semi_pos = tokens[i].find(")"); if (pos != string::npos) { //cout << "meow" << endl; tokens[i] = tokens[i].erase(token.size() - 2, 2); data_type += tokens[i] + " "; } else if (values_pos != string::npos){ //cout << "test: " << tokens[i] << endl; data_type += tokens[i] + " "; data_type.erase(remove(data_type.begin(), data_type.end(), '('), data_type.end()); } else if (semi_pos != string::npos){ //cout << "test: " << tokens[i] << endl; tokens[i].erase(remove(tokens[i].begin(), tokens[i].end(), ')'), tokens[i].end()); tokens[i].erase(remove(tokens[i].begin(), tokens[i].end(), ';'), tokens[i].end()); data_type += tokens[i] + " "; } else { data_type += tokens[i] + " "; } } //cout << "tb.CreateTB--data_type: " << data_type << endl; tb.CreateTB(table_name, data_type); } } else if (tokens.size() == 3 && tokens[0] == "DROP"){ //removes database or table if(tokens[1] == "DATABASE"){ string database_name = tokens[2]; database_name.erase(remove(database_name.begin(), database_name.end(), ';'), database_name.end()); db.DropDB(database_name); } else if (tokens[1] == "TABLE"){ string table_name = tokens[2]; table_name.erase(remove(table_name.begin(), table_name.end(), ';'), table_name.end()); tb.DropTB(table_name); } } else if (tokens.size() == 2 && tokens[0] == "USE"){ //Changes file path read by tables string database_name = tokens[1]; database_name.erase(remove(database_name.begin(), database_name.end(), ';'), database_name.end()); db.UseDB(database_name); } else if ((tokens[0] == "SELECT" || tokens[0] == "select")){ if (tokens[1] == "*"){ if (tokens[2] == "FROM" || tokens[2] == "from"){ if (tokens.size() > 3){ vector table_name; vector id; string target1, target2; size_t from, comma, join; bool inner_join = false, outer_join = false; //size_t pos = tokens.find(","); for(unsigned int i = 0; i < tokens.size(); i++){ //cout << "i: " << i << endl; from = tokens[i].find("from"); comma = tokens[i].find(","); join = tokens[i].find("join"); if(from != string::npos){ table_name.push_back(tokens[i+1]); //cout << "table_name: " << tokens[i+1] << endl; string comma_remove = tokens[i+2]; comma_remove.erase(remove(comma_remove.begin(), comma_remove.end(), ','), comma_remove.end()); id.push_back(comma_remove); //cout << "id: " << tokens[i+2] << endl; } else if (comma != string::npos){ table_name.push_back(tokens[i+1]); //cout << "table_name: " << tokens[i+1] << endl; id.push_back(tokens[i+2]); //cout << "id: " << tokens[i+2] << endl; } else if (join != string::npos){ table_name.push_back(tokens[i+1]); //cout << "table_name: " << tokens[i+1] << endl; id.push_back(tokens[i+2]); //cout << "id: " << tokens[i+2] << endl; } if (tokens[i] == "inner" && tokens[i+1] == "join"){ inner_join = true; //cout << "inner join" << endl; } else if (tokens[i] == "left" && tokens[i+1] == "outer" && tokens[i+2] == "join"){ outer_join = true; //cout << "outer join" << endl; } if (tokens[i] == "WHERE" || tokens[i] == "where" || tokens[i] == "ON" || tokens[i] == "on"){ target1 = tokens[i+1]; target2= tokens[i+3]; //cout << "target1: " << target1 << "; target2: " << target2 << endl; } } //cout << "inner_join: " << inner_join << endl; //cout << "outer_join: " << outer_join << endl; //boolean logic to determine which join to use if (inner_join == false && outer_join == false){//if no join is specified, then do a inner join inner_join = true; } if (inner_join == true){ dataM.innerJoin(table_name, id, target1, target2); //cout << "inner_join_true" << endl; } else if(outer_join == true){ dataM.outerJoin(table_name, id, target1, target2); //cout << "outer_join" << endl; } // //write a for loop that interates through the table_name vector and prints out all elements // for (unsigned int i = 0; i < table_name.size(); i++){ // cout << "table_name: " << table_name[i] << endl; // cout << "id: " << id[i] << endl; // } //dataM.innerJoin(table_name, id, target1, target2); } else if (tokens.size() < 4) { string table_name = tokens[3]; table_name.erase(remove(table_name.begin(), table_name.end(), ';'), table_name.end()); tb.SelectTB(table_name); } } else { //dataM.SelectAllData(); } } else { //selects specific columns string table_name; string column; string target_column; string opperator; string data_type; for(unsigned int i = 0; i < tokens.size(); i++){ if(tokens[i] == "SELECT" || tokens[i] == "select"){ for (/*unsigned int */ i = 1; i < tokens.size(); i++){ if(tokens[i] == "FROM" || tokens[i] == "from"){ // i = j; break; } else { column += tokens[i] + " "; //cout << "column: " << column << endl; } } //i++; column.erase(remove(column.begin(), column.end(), ','), column.end()); //cout << "i: " << i << endl; //i += 1; if(tokens[i] == "FROM" || tokens[i] == "from"){ table_name = tokens[i+1]; //cout << "table_name: " << table_name << endl; i += 2; //cout << "i: " << i << endl; if (tokens[i] == "WHERE" || tokens[i] == "where"){ target_column = tokens[i+1]; //cout << "target_column: " << target_column << endl; opperator = tokens[i+2]; //cout << "opperator: " << opperator << endl; data_type = tokens[i+3]; //cout << "data_type: " << data_type << endl; } } } } //cout << column << " " << table_name << " " << target_column << " "<< opperator << " " << data_type << endl; dataM.SelectData(table_name, column, target_column, opperator, data_type); } } else if (tokens.size() == 6 && tokens[0] == "ALTER"){ if(tokens[1] == "TABLE"){ //Alters table string table_name = tokens[2]; //grabs table name if(tokens[3] == "ADD"){ //Adds new column and new data type to table string column; string data_type; column = tokens[4]; data_type = tokens[5]; data_type.erase(remove(data_type.begin(), data_type.end(), ';'), data_type.end()); tb.AppendTB(table_name, column, data_type); } } } else if (tokens[0] == "insert"){ //inserts data into table string table_name = tokens[2]; string data_type; //size_t pos = data_type.find("values"); if (tokens.size() >= 3){ //if there are more than 3 tokens, then there are more than 1 column for (unsigned int i = 3; i < tokens.size(); i++){ data_type += tokens[i]; } } //remove characters from strings data_type.erase(remove(data_type.begin(), data_type.end(), '('), data_type.end()); //remove A from string size_t pos = data_type.find("values"); //finds the position of "values" in the string if (pos != string::npos) { // if "values" is found data_type.erase(pos, 6); // erase the 6 characters starting from "values" //cout << "meow" << endl; } //cout << "values-data_type: " << data_type << endl; //data_type.erase(remove(data_type.begin(), data_type.end(), ','), data_type.end()); data_type.erase(remove(data_type.begin(), data_type.end(), '('), data_type.end()); data_type.erase(remove(data_type.begin(), data_type.end(), ')'), data_type.end()); data_type.erase(remove(data_type.begin(), data_type.end(), ';'), data_type.end()); //data_type.erase(remove(data_type.begin(), data_type.end(), "'"), data_type.end()); // //filters out unwanted characters // pos = data_type.find("\'"); // size_t poscom = data_type.find(","); // //this is trying to find the row number // if (pos != std::string::npos) { // // Extract the substring before the colon // //data_type = data_type.substr(0, pos); // data_type.replace(pos, 1, " "); // } else if (poscom != std::string::npos){ // //data_type = data_type.substr(0, poscom); // data_type.replace(poscom, 1, ", "); // } //cout << "test-data_type: " << data_type << endl; dataM.InsertData(table_name, data_type); } else if (tokens[0] == "update"){ //updates data in table /* for (unsigned int i = 0; i < tokens.size(); i++){ cout << "update: " << tokens[i] << endl; } */ //cout << "update" << endl; string table_name = tokens[1]; table_name.erase(remove(table_name.begin(), table_name.end(), ';'), table_name.end()); if (tokens[2] == "set"){ string setColumn = tokens[3]; string opperator = tokens[4]; string value = tokens[5]; if (tokens[6] == "where"){ string targetColumn = tokens[7]; string columnName = tokens[9]; columnName.erase(remove(columnName.begin(), columnName.end(), ';'), columnName.end()); size_t start_pos = columnName.find("'"); size_t end_pos = columnName.find("'", start_pos + 1); if (start_pos != std::string::npos && end_pos != std::string::npos) { string columnNameStr = columnName.substr(start_pos + 1, end_pos - start_pos - 1); columnName = columnNameStr; //cout << "data_target: " << columnName << endl; } start_pos = value.find("'"); end_pos = value.find("'", start_pos + 1); if (start_pos != std::string::npos && end_pos != std::string::npos) { string valueStr = value.substr(start_pos + 1, end_pos - start_pos - 1); value = valueStr; //cout << "data_target: " << columnName << endl; } dataM.UpdateData(table_name, setColumn, value, targetColumn, columnName); } } } else if (tokens[0] == "delete"){ // deletes data from table if (tokens[1] == "from"){ string table_name = tokens[2]; table_name.erase(remove(table_name.begin(), table_name.end(), ';'), table_name.end()); if (tokens[3] == "where"){ string columnName = tokens[4]; string opperator = tokens[5]; string value = tokens[6]; size_t start_pos = value.find("'"); size_t end_pos = value.find("'", start_pos + 1); if (start_pos != std::string::npos && end_pos != std::string::npos) { string valueStr = value.substr(start_pos + 1, end_pos - start_pos - 1); value = valueStr; //cout << "data_target: " << columnName << endl; } value.erase(remove(value.begin(), value.end(), ';'), value.end()); dataM.DeleteData(table_name, opperator, columnName, value); } } } else if (tokens[0] == "--" || tokens[0].find("--") || tokens[0].substr(0, 2) == "--" ){ //checks for comments //do nothing } else if (tokens[0] == ".EXIT"){ exit(0); //exit program }else { cout << "Invalid input" << endl; //cout << "InvalidOut: " << tokens[0] << endl; } }