· 5 years ago · Mar 28, 2020, 11:00 PM
1// Project identifier: C0F4DFE8B340D81183C208F70F9D2D797908754D
2#include <getopt.h>
3#include <algorithm>
4#include <iostream>
5#include <map>
6#include <queue>
7#include <unordered_map>
8#include "tableObj.h"
9struct funcGreater {
10 bool operator()(const vector<TableEntry> &rows) const {
11 return rows[columnIndex] > valueCompared;
12 }
13 funcGreater(int columnIndex1, const TableEntry &valueCompared1)
14 : columnIndex(columnIndex1), valueCompared(valueCompared1) {}
15
16 int columnIndex;
17 TableEntry valueCompared;
18};
19
20struct funcLess {
21 bool operator()(const vector<TableEntry> &rows) const {
22 return rows[columnIndex] < valueCompared;
23 }
24 funcLess(int columnIndex1, const TableEntry &valueCompared1)
25 : columnIndex(columnIndex1), valueCompared(valueCompared1) {}
26
27 int columnIndex;
28 TableEntry valueCompared;
29};
30
31struct funcEqual {
32 bool operator()(const vector<TableEntry> &rows) const {
33 return rows[columnIndex] == valueCompared;
34 }
35 funcEqual(int columnIndex1, const TableEntry &valueCompared1)
36 : columnIndex(columnIndex1), valueCompared(valueCompared1) {}
37
38 int columnIndex;
39 TableEntry valueCompared;
40};
41
42// use remove_if, create an instance of the comparator
43// done in reading of the file
44// funcGreater comp(columnIndex, valueCompared);
45// remove_if(
46
47// creates a new tableentry of the type that was read in from the left hand
48// side, then we read in the thing after the operator
49template <typename F>
50void four_split(EntryType type, F &&f) {
51 switch (type) {
52 case EntryType::Bool: {
53 bool val;
54 cin >> val;
55 forward<F>(f)(val);
56 break;
57 }
58 case EntryType::Int: {
59 int val;
60 cin >> val;
61 forward<F>(f)(val);
62 break;
63 }
64 case EntryType::Double: {
65 double val;
66 cin >> val;
67 forward<F>(f)(val);
68 break;
69 }
70 case EntryType::String: {
71 string val;
72 cin >> val;
73 forward<F>(f)(val);
74 break;
75 }
76 }
77}
78
79class silly {
80 public:
81 // read in command inputs
82 void get_options(int argc, char **argv);
83 void run();
84 void createCommand();
85 void removeCommand();
86 void insertCommand();
87 void printCommand();
88 void deleteCommand();
89 void generateCommand();
90 void joinCommand();
91 void joinCommandFunc(int columnIndex1, int numberColumns, string &tableName1,
92 string &tableName2, vector<string> &columnStrings,
93 vector<int> &tableNumbers,
94 unordered_map<TableEntry, vector<int>> &genHashTemp);
95 void joinCommandFuncBST(int columnIndex1, int numberColumns,
96 string &tableName1, string &tableName2,
97 vector<string> &columnStrings,
98 vector<int> &tableNumbers,
99 map<TableEntry, vector<int>> &genBST);
100 void printAll(vector<string> &colNames, vector<int> &colIndex,
101 string &tableName);
102 void printWhere(vector<string> &colNames, vector<int> &colIndex,
103 string &tableName);
104 void insertCommandHelperPush(string &tableName, size_t i, size_t j);
105 void insertGenBST(string &tableName, size_t i, size_t j);
106 void insertGenHash(string &tableName, size_t i, size_t j);
107 void multipleCommandError(bool &columnError, string &tableName,
108 string &dummy);
109
110 // void deleteCommandGenFunc(string &tableName, int columnIndex);
111 unordered_map<string, tableObj> allTable;
112
113 private:
114 bool quiet = false;
115};
116
117// ----------------------------------------------------------------------------
118// Driver
119// ----------------------------------------------------------------------------
120
121int main(int argc, char **argv) {
122 // speed up code
123 ios_base::sync_with_stdio(false);
124 std::cout << std::boolalpha;
125 std::cin >> std::boolalpha;
126
127 // Instantiate a game
128 silly *data = new silly();
129
130 // Read and process the command line options.
131 data->get_options(argc, argv);
132
133 // Read in the provided file through stdin.
134 data->run();
135
136 delete data;
137
138 return 0;
139}
140
141// ----------------------------------------------------------------------------
142// stock Definitions
143// ----------------------------------------------------------------------------
144
145// Read and process command line options.
146void silly::get_options(int argc, char **argv) {
147 int option_index = 0, option = 0;
148 opterr = false;
149 // use getopt to find command line options
150 struct option longOpts[] = {{"quiet", no_argument, nullptr, 'q'},
151 {"help", no_argument, nullptr, 'h'},
152 {nullptr, 0, nullptr, '\0'}};
153
154 while ((option = getopt_long(argc, argv, "qh", longOpts, &option_index)) !=
155 -1) {
156 switch (option) {
157 case 'q':
158 quiet = true;
159 break;
160 case 'h':
161 cerr << "Help, error.\n";
162 exit(0);
163 default:
164 cerr << "Wrong Output, error.\n";
165 exit(0);
166 }
167 }
168}
169
170// strat: reads in the string of the corresponding type, and converts that
171// into an enum which we push back into a deque of EntryType
172void colReadCaes(string &dummy, deque<EntryType> &colTypes) {
173 EntryType colType;
174 if (dummy == "double") {
175 colType = EntryType::Double;
176 } else if (dummy == "int") {
177 colType = EntryType::Int;
178 } else if (dummy == "bool") {
179 colType = EntryType::Bool;
180 } else {
181 colType = EntryType::String;
182 }
183 colTypes.push_back(colType);
184}
185
186void silly::createCommand() {
187 string tableName;
188 int columnAmount = 0;
189 string dummy;
190
191 // purpose: reads in up to the columnAmount, becuz after it's dependent on
192 // how many columnAmount there are
193 cin >> tableName >> columnAmount;
194 // purose: error checking if tableName exists, if not we insert into the
195 // map, tableName we table object with the table Name (Error 1)
196
197 auto it = allTable.find(tableName);
198 if (it != allTable.end()) {
199 cout << "Error: Cannot create already existing table " << tableName << "\n";
200
201 getline(cin, dummy);
202 } else {
203 tableObj defaultTableObj(tableName);
204 allTable.insert({tableName, defaultTableObj});
205
206 // strat: use an entryTypes container which is a enum class to hold the
207 // types, then create column objects when is start reading the names with
208 // his enum class
209 deque<EntryType> colTypes;
210 for (int i = 0; i < columnAmount; ++i) {
211 cin >> dummy;
212 // purpose: function that creates the column type, and pushes it into the
213 // vector of col Types
214 colReadCaes(dummy, colTypes);
215 }
216 // purpose: reads the col name, and uses the deque of col Types to associate
217 // name to type, then we create a col object, and push the object into the
218 // deque of col Objects in our tableEntry class
219 for (int i = 0; i < columnAmount; ++i) {
220 cin >> dummy;
221 columnObj colObj(dummy, colTypes[i]);
222 allTable[tableName].colContainer.push_back(colObj);
223 }
224
225 cout << "New table " << tableName << " with column(s) ";
226 for (int i = 0; i < columnAmount; ++i) {
227 cout << allTable[tableName].colContainer[i].colName << " ";
228 }
229 cout << "created\n";
230 }
231}
232
233void silly::removeCommand() {
234 string dummy;
235 cin >> dummy;
236 auto it = allTable.find(dummy);
237 if (it == allTable.end()) {
238 cout << "Error: " << dummy << " does not name a table in the database\n";
239 getline(cin, dummy);
240 } else {
241 allTable.erase(dummy);
242 cout << "Table " << dummy << " deleted\n";
243 }
244}
245
246void silly::insertGenBST(string &tableName, size_t i, size_t j) {
247 size_t columnLocation = -1;
248
249 tableObj ¤tTable = allTable[tableName];
250 // purpose: convert it to the correct column index
251 for (size_t k = 0; k < currentTable.colContainer.size(); ++k) {
252 // purpose: we only insert if it's genBst is not empty and we're in the
253 // correct column
254 if (!currentTable.genBST.empty() &&
255 currentTable.generateColumnBST ==
256 currentTable.colContainer[k].colName) {
257 columnLocation = k;
258 }
259 }
260
261 // purpose: we insert into the bst if the columnLocation, and column matches
262 if (columnLocation == j) {
263 currentTable.genBST[currentTable.matrix[i][j]].emplace_back(i);
264 }
265}
266
267void silly::insertGenHash(string &tableName, size_t i, size_t j) {
268 size_t columnLocation = -1;
269 // purpose: convert it to the correct column index
270 tableObj ¤tTable = allTable[tableName];
271 for (size_t k = 0; k < currentTable.colContainer.size(); ++k) {
272 if (!currentTable.genHash.empty() &&
273 currentTable.generateColumnHash ==
274 currentTable.colContainer[k].colName) {
275 columnLocation = k;
276 }
277 }
278
279 // purpose: we insert into the bst if the columnLocation, and column matches
280 if (columnLocation == j) {
281 currentTable.genHash[currentTable.matrix[i][j]].emplace_back(i);
282 }
283}
284
285void silly::insertCommandHelperPush(string &tableName, size_t i, size_t j) {
286 // purpose: the 4 cases when we push back into the 2d matrix in each
287 // table object
288 tableObj ¤tTable = allTable[tableName];
289 if (currentTable.colContainer[j].colType == EntryType::String) {
290 string entryType;
291 cin >> entryType;
292 currentTable.matrix[i].emplace_back(entryType);
293
294 // purpose: if it genBST is on, and we insert a new entry, update the map
295 insertGenBST(tableName, i, j);
296 insertGenHash(tableName, i, j);
297 }
298 if (currentTable.colContainer[j].colType == EntryType::Bool) {
299 bool entryType;
300 cin >> entryType;
301 currentTable.matrix[i].emplace_back(entryType);
302 // purpose: if it genBST is on, and we insert a new entry, update the map
303 insertGenBST(tableName, i, j);
304 insertGenHash(tableName, i, j);
305 }
306 if (currentTable.colContainer[j].colType == EntryType::Int) {
307 int entryType;
308 cin >> entryType;
309 currentTable.matrix[i].emplace_back(entryType);
310 // purpose: if it genBST is on, and we insert a new entry, update the map
311 insertGenBST(tableName, i, j);
312 insertGenHash(tableName, i, j);
313 }
314 if (currentTable.colContainer[j].colType == EntryType::Double) {
315 double entryType;
316 cin >> entryType;
317 currentTable.matrix[i].emplace_back(entryType);
318 // purpose: if it genBST is on, and we insert a new entry, update the map
319 insertGenBST(tableName, i, j);
320 insertGenHash(tableName, i, j);
321 }
322}
323
324void silly::insertCommand() {
325 string dummy;
326 string tableName;
327
328 int rowsAdded = 0;
329 cin >> dummy >> tableName;
330 auto it = allTable.find(tableName);
331 if (it == allTable.end()) {
332 cout << "Error: " << tableName
333 << " does not name a table in the database\n";
334
335 cin >> rowsAdded;
336 // remove all the insert rows after
337 for (int i = 0; i < rowsAdded + 1; i++) {
338 getline(cin, dummy);
339 }
340 }
341 // strat: add the number of rows to the existing amount, by reserving
342 // current
343 // + added amount,iterate through and insert items into 2d vector
344 else {
345 cin >> rowsAdded >> dummy;
346
347 tableObj ¤tTable = allTable[tableName];
348 size_t oldRowSize = currentTable.matrix.size();
349 currentTable.matrix.resize(currentTable.matrix.size() + rowsAdded);
350 // iterate from oldRowSize - 1, till the new capacity
351 for (size_t i = oldRowSize; i < currentTable.matrix.size(); ++i) {
352 // iterate through the # of columns
353 currentTable.matrix[i].reserve(currentTable.colContainer.size());
354 // we iterate through each column, and emplace back into the [i][j]
355 // position
356 for (size_t j = 0; j < currentTable.colContainer.size(); ++j) {
357 // purpose: pushes into the specific tablename at row i, and column j
358 insertCommandHelperPush(tableName, i, j);
359 }
360 }
361
362 cout << "Added " << rowsAdded << " rows to " << tableName
363 << " from position " << oldRowSize << " to "
364 << allTable[tableName].matrix.size() - 1 << "\n";
365 }
366}
367
368// purpose: we iterate through and turn it to true if we do find the column
369// name
370void silly::multipleCommandError(bool &columnPresent, string &tableName,
371 string &dummy) {
372 tableObj ¤tTable = allTable[tableName];
373 for (unsigned int i = 0; i < currentTable.colContainer.size(); ++i) {
374 if (dummy == currentTable.colContainer[i].colName) {
375 columnPresent = true;
376 }
377 }
378}
379
380void silly::printAll(vector<string> &colNames, vector<int> &colIndex,
381 string &tableName) {
382 // purpose: we print out each value in this deque
383 if (!quiet) {
384 for (unsigned int i = 0; i < colNames.size(); ++i) {
385 cout << colNames[i] << " ";
386 }
387 cout << "\n";
388 }
389
390 if (quiet) {
391 cout << "Printed " << allTable[tableName].matrix.size()
392 << " matching rows from " << tableName << "\n";
393 return;
394 }
395 tableObj ¤tTable = allTable[tableName];
396 // purpose counter for couting how many matching rows we found
397 int rowsMatch = 0;
398 // purpose: i loop is iterating through the rows
399 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
400 // purpose: j loop is for iterating through col index
401 for (unsigned int j = 0; j < colIndex.size(); ++j) {
402 cout << currentTable.matrix[i][colIndex[j]] << " ";
403 }
404 cout << "\n";
405 rowsMatch++;
406 }
407 cout << "Printed " << currentTable.matrix.size() << " matching rows from "
408 << tableName << "\n";
409}
410
411void silly::printWhere(vector<string> &colNames, vector<int> &colIndex,
412 string &tableName) {
413 // purpose: we read in the column name, and iterate through the column
414 // container to also store the type
415 string columnName;
416 string dummy;
417 cin >> columnName;
418 int columnIndex = 0;
419
420 bool found = false;
421 tableObj ¤tTable = allTable[tableName];
422 for (unsigned int i = 0; i < currentTable.colContainer.size(); ++i) {
423 if (columnName == currentTable.colContainer[i].colName) {
424 // stating that it's been found, and we mark the index
425 columnIndex = i;
426 found = true;
427 }
428 }
429
430 // purpose: for error checking, we didn't find the column name in the
431 // table
432 if (found == false) {
433 cout << "Error: " << columnName << " value does not name a column in "
434 << tableName << "\n";
435 getline(cin, dummy);
436 }
437 // purpose: valid column in the table, therefore we now traverse through
438 // each row and compare that the condition is true
439 else {
440 if (!quiet)
441 // purpose: we print out each value in this deque
442 {
443 for (unsigned int i = 0; i < colNames.size(); ++i) {
444 cout << colNames[i] << " ";
445 }
446 cout << "\n";
447 }
448
449 char condition;
450 cin >> condition;
451 int rowsMatch = 0;
452 tableObj ¤tTable = allTable[tableName];
453
454 // takes ColTypee, and makes val into the correct type(string, bool, int
455 // double)
456 four_split(
457 currentTable.colContainer[columnIndex].colType, [&](const auto &val) {
458 // creates a tableEntry of the val after we decide what the type
459 // should be
460 TableEntry newValue(val);
461 // condition: must be >, column #'s match, and genBst is not empty for
462 // this table
463
464 if (condition == '>' &&
465 columnName == currentTable.generateColumnBST &&
466 !currentTable.genBST.empty()) {
467 if (quiet) {
468 auto start = currentTable.genBST.upper_bound(newValue);
469 auto end = currentTable.genBST.end();
470 while (start != end) {
471 rowsMatch += int(start->second.size());
472 start++;
473 }
474 cout << "Printed " << rowsMatch << " matching rows from "
475 << tableName << "\n";
476 } else {
477 auto start = currentTable.genBST.upper_bound(newValue);
478 auto end = currentTable.genBST.end();
479 while (start != end) {
480 for (auto row_number : start->second) {
481 for (unsigned int j = 0; j < colIndex.size(); ++j) {
482 cout << currentTable.matrix[row_number][colIndex[j]] << " ";
483 }
484 cout << "\n";
485 rowsMatch++;
486 }
487
488 start++;
489 }
490 cout << "Printed " << rowsMatch << " matching rows from "
491 << tableName << "\n";
492 }
493 } else if (condition == '<' &&
494 columnName == currentTable.generateColumnBST &&
495 !currentTable.genBST.empty()) {
496 if (quiet) {
497 auto start = currentTable.genBST.begin();
498 auto end = currentTable.genBST.lower_bound(newValue);
499 while (start != end) {
500 rowsMatch += int(start->second.size());
501 start++;
502 }
503 cout << "Printed " << rowsMatch << " matching rows from "
504 << tableName << "\n";
505 } else {
506 auto start = currentTable.genBST.begin();
507 auto end = currentTable.genBST.lower_bound(newValue);
508 while (start != end) {
509 for (auto row_number : start->second) {
510 for (unsigned int j = 0; j < colIndex.size(); ++j) {
511 cout << currentTable.matrix[row_number][colIndex[j]] << " ";
512 }
513 cout << "\n";
514
515 rowsMatch++;
516 }
517 start++;
518 }
519 cout << "Printed " << rowsMatch << " matching rows from "
520 << tableName << "\n";
521 }
522 } else if (condition == '=' &&
523 columnName == currentTable.generateColumnHash &&
524 !currentTable.genHash.empty()) {
525 if (quiet) {
526 int addRows = 0;
527 auto it = currentTable.genHash.find(newValue);
528 if (it != currentTable.genHash.end()) {
529 addRows = addRows + (int)it->second.size();
530 }
531 rowsMatch = rowsMatch + addRows;
532 cout << "Printed " << rowsMatch << " matching rows from "
533 << tableName << "\n";
534 } else {
535 vector<int> rowsPrint = currentTable.genHash[newValue];
536 for (auto row_number : rowsPrint) {
537 for (unsigned int j = 0; j < colIndex.size(); ++j) {
538 cout << currentTable.matrix[row_number][colIndex[j]] << " ";
539 }
540 cout << "\n";
541 }
542
543 cout << "Printed " << rowsPrint.size() << " matching rows from "
544 << tableName << "\n";
545 }
546 } else if (condition == '=') {
547 if (quiet) {
548 auto functor1 = funcEqual(columnIndex, newValue);
549 for (size_t i = 0; i < currentTable.matrix.size(); i++) {
550 if (functor1(currentTable.matrix[i])) {
551 rowsMatch++;
552 }
553 }
554 cout << "Printed " << rowsMatch << " matching rows from "
555 << tableName << "\n";
556 } else {
557 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
558 // purpose: now we compare val, and specific [i][columnIndex
559 // entry], if it meets conditions, we print the wanted columns
560 // based on the columnIndex vector we made that stores wanted
561 // columns
562 if (newValue == currentTable.matrix[i][columnIndex]) {
563 for (unsigned int j = 0; j < colIndex.size(); ++j) {
564 cout << currentTable.matrix[i][colIndex[j]] << " ";
565 }
566 cout << "\n";
567
568 rowsMatch++;
569 }
570 }
571 cout << "Printed " << rowsMatch << " matching rows from "
572 << tableName << "\n";
573 }
574 } else if (condition == '<') {
575 if (quiet) {
576 auto functor1 = funcLess(columnIndex, newValue);
577 for (size_t i = 0; i < currentTable.matrix.size(); i++) {
578 if (functor1(currentTable.matrix[i])) {
579 rowsMatch++;
580 }
581 }
582 cout << "Printed " << rowsMatch << " matching rows from "
583 << tableName << "\n";
584 } else {
585 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
586 // purpose: now we compare val, and specific [i][columnIndex
587 // entry], if it meets conditions, we print the wanted columns
588 // based on the columnIndex vector we made that stores wanted
589 // columns
590 if (currentTable.matrix[i][columnIndex] < newValue) {
591 for (unsigned int j = 0; j < colIndex.size(); ++j) {
592 cout << currentTable.matrix[i][colIndex[j]] << " ";
593 }
594 cout << "\n";
595
596 rowsMatch++;
597 }
598 }
599 cout << "Printed " << rowsMatch << " matching rows from "
600 << tableName << "\n";
601 }
602 } else if (condition == '>') {
603 if (quiet) {
604 auto functor1 = funcGreater(columnIndex, newValue);
605 for (size_t i = 0; i < currentTable.matrix.size(); i++) {
606 if (functor1(currentTable.matrix[i])) {
607 rowsMatch++;
608 }
609 }
610 cout << "Printed " << rowsMatch << " matching rows from "
611 << tableName << "\n";
612 } else {
613 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
614 // purpose: now we compare val, and specific [i][columnIndex
615 // entry], if it meets conditions, we print the wanted columns
616 // based on the columnIndex vector we made that stores wanted
617 // columns
618 if (currentTable.matrix[i][columnIndex] > newValue) {
619 for (unsigned int j = 0; j < colIndex.size(); ++j) {
620 cout << currentTable.matrix[i][colIndex[j]] << " ";
621 }
622 cout << "\n";
623
624 rowsMatch++;
625 }
626 }
627 cout << "Printed " << rowsMatch << " matching rows from "
628 << tableName << "\n";
629 }
630 }
631 });
632 }
633}
634
635// 4 way split between string, bool, int double}
636
637void silly::printCommand() {
638 string dummy;
639 string tableName;
640 int columnAmount = 0;
641 cin >> dummy >> tableName;
642
643 // error check #1
644 auto it = allTable.find(tableName);
645 if (it == allTable.end()) {
646 cout << "Error: " << tableName
647 << " does not name a table in the database\n";
648 getline(cin, dummy);
649 } else {
650 cin >> columnAmount;
651
652 vector<string> colNames;
653 colNames.reserve(columnAmount);
654 // purpose: we iterate through the wanted colNames and put them into a
655 // deque
656 bool columnPresent = false;
657 for (int i = 0; i < columnAmount; ++i) {
658 cin >> dummy;
659
660 // checks if dummy is the tableName column container, if it is we
661 // return(breaks out)
662 multipleCommandError(columnPresent, tableName, dummy);
663 if (columnPresent == false) {
664 cout << "Error: " << dummy << " does not name a column in " << tableName
665 << "\n";
666 getline(cin, dummy);
667 return;
668 }
669 colNames.push_back(dummy);
670 }
671 // reads in the all/where part
672 cin >> dummy;
673
674 // purpose: we convert the strings to indics by traversing colName
675 // vector, and see if can find a match within the col Container, if so
676 // push_back the index to the index container might be sped up*
677 vector<int> colIndex;
678 colIndex.reserve(columnAmount);
679
680 tableObj ¤tTable = allTable[tableName];
681 for (unsigned int j = 0; j < colNames.size(); ++j) {
682 for (unsigned int i = 0; i < currentTable.colContainer.size(); ++i) {
683 if (colNames[j] == currentTable.colContainer[i].colName) {
684 colIndex.push_back(i);
685 }
686 }
687 }
688 if (dummy == "ALL") {
689 printAll(colNames, colIndex, tableName);
690 }
691 // printWhere case
692 else {
693 printWhere(colNames, colIndex, tableName);
694 }
695 }
696}
697
698void silly::deleteCommand() {
699 string dummy;
700 string columnName;
701 string tableName;
702 char operateor;
703 EntryType colTypee;
704 int columnIndex = 0;
705 cin >> dummy >> tableName;
706 auto it = allTable.find(tableName);
707 // error check for column name
708 bool found = false;
709
710 // purpose: checks
711 if (it == allTable.end()) {
712 cout << "Error: " << tableName
713 << " does not name a table in the database\n";
714 getline(cin, dummy);
715 } else {
716 cin >> dummy >> columnName;
717 // error check #2
718 tableObj ¤tTable = allTable[tableName];
719 for (unsigned int i = 0; i < currentTable.colContainer.size(); ++i) {
720 if (columnName == currentTable.colContainer[i].colName) {
721 colTypee = currentTable.colContainer[i].colType;
722 // stating that it's been found, and we mark the index
723 columnIndex = i;
724 found = true;
725 }
726 }
727
728 if (found == false) {
729 cout << "Error: " << columnName << " does not name a column in "
730 << tableName << "\n";
731 getline(cin, dummy);
732 }
733 // we do delete function here
734 else {
735 cin >> operateor;
736 // takes ColTypee, and makes val into the correct type(string, bool, int
737 // double)
738 tableObj ¤tTable = allTable[tableName];
739 long unsigned int numberRows = currentTable.matrix.size();
740 four_split(colTypee, [&](const auto &val) {
741 // creates a tableEntry of the val after we decide what the type
742 // should be
743 TableEntry newValue(val);
744 switch (operateor) {
745 case '=': {
746 funcEqual functor1(columnIndex, newValue);
747 currentTable.matrix.erase(
748 remove_if(currentTable.matrix.begin(),
749 currentTable.matrix.end(), functor1),
750 currentTable.matrix.end());
751
752 if (!currentTable.genBST.empty()) {
753 currentTable.genBST.clear();
754 // purpose we find the index of where the gen is on
755 tableObj ¤tTable = allTable[tableName];
756 int genColumnIndex = 0;
757 for (unsigned int i = 0; i < currentTable.colContainer.size();
758 ++i) {
759 if (currentTable.generateColumnBST ==
760 currentTable.colContainer[i].colName) {
761 genColumnIndex = i;
762 }
763 }
764 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
765 currentTable.genBST[currentTable.matrix[i][genColumnIndex]]
766 .emplace_back(i);
767 }
768 } else if (!currentTable.genHash.empty()) {
769 currentTable.genHash.clear();
770 tableObj ¤tTable = allTable[tableName];
771 int genColumnIndex = 0;
772 for (unsigned int i = 0; i < currentTable.colContainer.size();
773 ++i) {
774 if (currentTable.generateColumnBST ==
775 currentTable.colContainer[i].colName) {
776 genColumnIndex = i;
777 }
778 }
779 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
780 currentTable.genBST[currentTable.matrix[i][genColumnIndex]]
781 .emplace_back(i);
782 }
783 }
784 break;
785 }
786 case '<': {
787 funcLess functor1(columnIndex, newValue);
788 allTable[tableName].matrix.erase(
789 remove_if(allTable[tableName].matrix.begin(),
790 allTable[tableName].matrix.end(), functor1),
791 allTable[tableName].matrix.end());
792
793 if (!currentTable.genBST.empty()) {
794 currentTable.genBST.clear();
795 // purpose we find the index of where the gen is on
796 tableObj ¤tTable = allTable[tableName];
797 int genColumnIndex = 0;
798 for (unsigned int i = 0; i < currentTable.colContainer.size();
799 ++i) {
800 if (currentTable.generateColumnBST ==
801 currentTable.colContainer[i].colName) {
802 genColumnIndex = i;
803 }
804 }
805 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
806 currentTable.genBST[currentTable.matrix[i][genColumnIndex]]
807 .emplace_back(i);
808 }
809 } else if (!currentTable.genHash.empty()) {
810 currentTable.genHash.clear();
811 tableObj ¤tTable = allTable[tableName];
812 int genColumnIndex = 0;
813 for (unsigned int i = 0; i < currentTable.colContainer.size();
814 ++i) {
815 if (currentTable.generateColumnBST ==
816 currentTable.colContainer[i].colName) {
817 genColumnIndex = i;
818 }
819 }
820 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
821 currentTable.genBST[currentTable.matrix[i][genColumnIndex]]
822 .emplace_back(i);
823 }
824 }
825 break;
826 }
827 case '>': {
828 funcGreater functor1(columnIndex, newValue);
829 allTable[tableName].matrix.erase(
830 remove_if(allTable[tableName].matrix.begin(),
831 allTable[tableName].matrix.end(), functor1),
832 allTable[tableName].matrix.end());
833
834 if (!currentTable.genBST.empty()) {
835 currentTable.genBST.clear();
836 // purpose we find the index of where the gen is on
837 tableObj ¤tTable = allTable[tableName];
838 int genColumnIndex = 0;
839 for (unsigned int i = 0; i < currentTable.colContainer.size();
840 ++i) {
841 if (currentTable.generateColumnBST ==
842 currentTable.colContainer[i].colName) {
843 genColumnIndex = i;
844 }
845 }
846 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
847 currentTable.genBST[currentTable.matrix[i][genColumnIndex]]
848 .emplace_back(i);
849 }
850 } else if (!currentTable.genHash.empty()) {
851 currentTable.genHash.clear();
852 tableObj ¤tTable = allTable[tableName];
853 int genColumnIndex = 0;
854 for (unsigned int i = 0; i < currentTable.colContainer.size();
855 ++i) {
856 if (currentTable.generateColumnBST ==
857 currentTable.colContainer[i].colName) {
858 genColumnIndex = i;
859 }
860 }
861 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
862 currentTable.genBST[currentTable.matrix[i][genColumnIndex]]
863 .emplace_back(i);
864 }
865 }
866 break;
867 }
868 }
869 });
870 numberRows = numberRows - allTable[tableName].matrix.size();
871 cout << "Deleted " << numberRows << " rows from " << tableName << "\n";
872 }
873 }
874}
875
876void silly::generateCommand() {
877 string dummy;
878 string tableName;
879 string columnName;
880 string indexType;
881 int columnIndex = 0;
882 cin >> dummy >> tableName;
883 auto it = allTable.find(tableName);
884 // error check for column name
885
886 // purpose: checks
887 if (it == allTable.end()) {
888 cout << "Error: " << tableName
889 << " does not name a table in the database\n";
890 getline(cin, dummy);
891 } else {
892 cin >> indexType >> dummy >> dummy >> columnName;
893 bool found = false;
894 // error check #2
895 tableObj ¤tTable = allTable[tableName];
896 for (unsigned int i = 0; i < currentTable.colContainer.size(); ++i) {
897 if (columnName == currentTable.colContainer[i].colName) {
898 columnIndex = i;
899 found = true;
900 }
901 }
902
903 if (found == false) {
904 cout << "Error: " << columnName << " does not name a column in "
905 << tableName << "\n";
906 getline(cin, dummy);
907 } else if (indexType == "hash") {
908 tableObj ¤tTable = allTable[tableName];
909 currentTable.genHash.clear();
910 currentTable.genBST.clear();
911 currentTable.generateColumnHash = columnName;
912
913 // strat: we iterate through each row and column, and check if it's in
914 // the hasher map, if it is push_back index in the vector, else we
915 // insert the key, and the vector with the new entry
916 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
917 currentTable.genHash[currentTable.matrix[i][columnIndex]].emplace_back(
918 i);
919 }
920 cout << "Created " << indexType << " index for table " << tableName
921 << " on column " << columnName << "\n";
922 // purpose: what if they the want to do another generate
923 } else if (indexType == "bst") {
924 tableObj ¤tTable = allTable[tableName];
925 currentTable.genHash.clear();
926 currentTable.genBST.clear();
927 currentTable.generateColumnBST = columnName;
928
929 // strat: we iterate through each row and column, and check if it's in
930 // the hasher map, if it is push_back index in the vector, else we
931 // insert the key, and the vector with the new entry
932 for (unsigned int i = 0; i < currentTable.matrix.size(); ++i) {
933 currentTable.genBST[currentTable.matrix[i][columnIndex]].emplace_back(
934 i);
935 }
936 cout << "Created " << indexType << " index for table " << tableName
937 << " on column " << columnName << "\n";
938 }
939 }
940}
941
942int convertColumnToIndex(deque<columnObj> colContainer, string columnName) {
943 for (unsigned int i = 0; i < colContainer.size(); ++i) {
944 if (columnName == colContainer[i].colName) {
945 return i;
946 }
947 }
948 return 0;
949}
950
951void silly::joinCommandFunc(
952 int columnIndex1, int numberColumns, string &tableName1, string &tableName2,
953 vector<string> &columnStrings, vector<int> &tableNumbers,
954 unordered_map<TableEntry, vector<int>> &genHashTemp) {
955 // loop through all the rows of tableName1 w/
956 // the index of columnIndex1,
957 // and compare with if it's inside tableName2
958 int size = 0;
959
960 tableObj ¤tTable1 = allTable[tableName1];
961
962 for (unsigned int i = 0; i < currentTable1.matrix.size(); ++i) {
963 // Note: genhash temp is key pairs to stuff in table 2, so we insert a
964 // key from table 1, and see if it's also in table 2, then we want that
965 // vector
966 vector<int> rowVecTable2 =
967 genHashTemp[currentTable1.matrix[i][columnIndex1]];
968 // strat: there are multiple rows in table 2 that sync with the table 1
969 // key, therefore we go 1 by 1
970 for (unsigned int k = 0; k < rowVecTable2.size(); ++k) {
971 for (int j = 0; j < numberColumns; ++j) {
972 // each iteration check if 0 or 1 in the int vector, so we know
973 // which tableName to search through
974 string correctName;
975 if (tableNumbers[j] == 1) {
976 correctName = tableName1;
977 } else {
978 correctName = tableName2;
979 }
980 tableObj &correctTable = allTable[correctName];
981 // converts the string value in columnStrings vector in the wanted
982 // table
983 int columnNumber =
984 convertColumnToIndex(correctTable.colContainer, columnStrings[j]);
985
986 // strat: the row changes if we're printing from table 1 or table 2,
987 // row is based on i if we're in table1, if we're in table 2, row is
988 // based on the the vector of rows we got from our temp hash
989 if (tableNumbers[j] == 1) {
990 cout << correctTable.matrix[i][columnNumber] << " ";
991 } else {
992 cout << correctTable.matrix[rowVecTable2[k]][columnNumber] << " ";
993 }
994 }
995 cout << "\n";
996
997 size++;
998 }
999 }
1000 cout << "Printed " << size << " rows from joining " << tableName1 << " to "
1001 << tableName2 << "\n";
1002}
1003
1004void silly::joinCommandFuncBST(int columnIndex1, int numberColumns,
1005 string &tableName1, string &tableName2,
1006 vector<string> &columnStrings,
1007 vector<int> &tableNumbers,
1008 map<TableEntry, vector<int>> &genBSTFunc) {
1009 int size = 0;
1010 // loop through all the rows of tableName1 w/
1011 // the index of columnIndex1,
1012 // and compare with if it's inside tableName2
1013
1014 tableObj ¤tTable1 = allTable[tableName1];
1015 for (unsigned int i = 0; i < currentTable1.matrix.size(); ++i) {
1016 // Note: genhash temp is key pairs to stuff in table 2, so we insert a
1017 // key from table 1, and see if it's also in table 2, then we want that
1018 // vector
1019 vector<int> rowVecTable2 =
1020 genBSTFunc[currentTable1.matrix[i][columnIndex1]];
1021 // strat: there are multiple rows in table 2 that sync with the table 1
1022 // key, therefore we go 1 by 1
1023 for (unsigned int k = 0; k < rowVecTable2.size(); ++k) {
1024 for (int j = 0; j < numberColumns; ++j) {
1025 // each iteration check if 0 or 1 in the int vector, so we know
1026 // which tableName to search through
1027 string correctName;
1028 if (tableNumbers[j] == 1) {
1029 correctName = tableName1;
1030 } else {
1031 correctName = tableName2;
1032 }
1033
1034 tableObj &correctTable = allTable[correctName];
1035 // converts the string value in columnStrings vector in the wanted
1036 // table
1037 int columnNumber =
1038 convertColumnToIndex(correctTable.colContainer, columnStrings[j]);
1039
1040 // strat: the row changes if we're printing from table 1 or table 2,
1041 // row is based on i if we're in table1, if we're in table 2, row is
1042 // based on the the vector of rows we got from our temp hash
1043 if (tableNumbers[j] == 1) {
1044 cout << correctTable.matrix[i][columnNumber] << " ";
1045 } else {
1046 cout << correctTable.matrix[rowVecTable2[k]][columnNumber] << " ";
1047 }
1048 }
1049
1050 cout << "\n";
1051
1052 size++;
1053 }
1054 }
1055 cout << "Printed " << size << " rows from joining " << tableName1 << " to "
1056 << tableName2 << "\n";
1057}
1058
1059void silly::joinCommand() {
1060 string tableName1;
1061 string tableName2;
1062 string dummy;
1063 string columnName1;
1064 string columnName2;
1065 int numberColumns;
1066 int columnIndex1 = 0;
1067 int columnIndex2 = 0;
1068
1069 cin >> tableName1 >> dummy >> tableName2;
1070
1071 // error checks for tableNames
1072 auto it1 = allTable.find(tableName1);
1073 auto it2 = allTable.find(tableName2);
1074 // purpose: checks
1075 if (it1 == allTable.end()) {
1076 cout << "Error: " << tableName1
1077 << " does not name a table in the database\n";
1078 getline(cin, dummy);
1079 } else if (it2 == allTable.end()) {
1080 cout << "Error: " << tableName2
1081 << " does not name a table in the database\n";
1082 getline(cin, dummy);
1083 } else { // error check for column name
1084 cin >> dummy >> columnName1 >> dummy >> columnName2 >> dummy >> dummy >>
1085 numberColumns;
1086
1087 bool found1 = false;
1088 bool found2 = false;
1089
1090 tableObj ¤tTable1 = allTable[tableName1];
1091 tableObj ¤tTable2 = allTable[tableName2];
1092 // error check #2
1093 for (unsigned int i = 0; i < currentTable1.colContainer.size(); ++i) {
1094 if (columnName1 == currentTable1.colContainer[i].colName) {
1095 columnIndex1 = i;
1096 found1 = true;
1097 }
1098 }
1099 for (unsigned int i = 0; i < currentTable2.colContainer.size(); ++i) {
1100 if (columnName2 == currentTable2.colContainer[i].colName) {
1101 columnIndex2 = i;
1102 found2 = true;
1103 }
1104 }
1105
1106 if (found1 == false) {
1107 cout << columnName1
1108 << " is not the name of a column in the table specified by "
1109 << tableName1 << "\n";
1110 getline(cin, dummy);
1111 } else if (found2 == false) {
1112 cout << columnName2
1113 << " is not the name of a column in the table specified by "
1114 << tableName2 << "\n";
1115 getline(cin, dummy);
1116 } else {
1117 // purpose: make a vector of join objects, hold their string name and
1118 // which table it's in
1119 vector<string> columnStrings;
1120 vector<int> tableNumbers;
1121 columnStrings.reserve(numberColumns);
1122 tableNumbers.reserve(numberColumns);
1123 int dummyValue;
1124 bool columnPresent = false;
1125 bool breakout = false;
1126 for (int i = 0; i < numberColumns; ++i) {
1127 cin >> dummy >> dummyValue;
1128 columnStrings.push_back(dummy);
1129
1130 tableNumbers.push_back(dummyValue);
1131 if (dummyValue == 1) {
1132 // checks string dummy is a possible column
1133 multipleCommandError(columnPresent, tableName1, dummy);
1134 } else {
1135 multipleCommandError(columnPresent, tableName2, dummy);
1136 }
1137 // if a column we were gonna print, we didn't find the respective
1138 // container, we break out of loop
1139 if (columnPresent == false && dummyValue == 1) {
1140 cout << "Error: " << dummy << " does not name a column in "
1141 << tableName1 << "\n";
1142 getline(cin, dummy);
1143 breakout = true;
1144 break;
1145 }
1146 if (columnPresent == false && dummyValue == 2) {
1147 cout << "Error: " << dummy << " does not name a column in "
1148 << tableName2 << "\n";
1149 getline(cin, dummy);
1150 breakout = true;
1151 break;
1152 }
1153 // we reset columnPresent back to false
1154 columnPresent = false;
1155 }
1156 // purpose: if column was not present in what we were looking at, we
1157 // getline and finish running the function
1158 if (breakout == false) {
1159 if (!quiet) {
1160 for (unsigned int i = 0; i < columnStrings.size(); ++i) {
1161 cout << columnStrings[i] << " ";
1162 }
1163 cout << "\n";
1164 }
1165
1166 tableObj ¤tTable2 = allTable[tableName2];
1167 int rowsMatch = 0;
1168 if (quiet) {
1169 for (size_t i = 0; i < currentTable1.matrix.size(); i++) {
1170 TableEntry &newVal = currentTable1.matrix[i][columnIndex1];
1171
1172 if (currentTable2.generateColumnBST == columnName2 &&
1173 !currentTable2.genBST.empty()) {
1174 auto it = currentTable2.genBST.find(newVal);
1175 if (it != currentTable2.genBST.end()) {
1176 rowsMatch += int(it->second.size());
1177 }
1178 } else if (currentTable2.generateColumnHash == columnName2 &&
1179 !currentTable2.genHash.empty()) {
1180 auto it = currentTable2.genHash.find(newVal);
1181 if (it != currentTable2.genHash.end()) {
1182 rowsMatch += int(it->second.size());
1183 }
1184 } else {
1185 vector<size_t> addingRows;
1186 for (size_t k = 0; k < currentTable2.matrix.size(); k++) {
1187 if (currentTable2.matrix[k][columnIndex2] == newVal) {
1188 addingRows.emplace_back(k);
1189 }
1190 }
1191 rowsMatch = rowsMatch + (int)addingRows.size();
1192 }
1193 }
1194 cout << "Printed " << rowsMatch << " rows from joining " << tableName1
1195 << " to " << tableName2 << "\n";
1196 return;
1197 }
1198
1199 // purpose: 2 seperate funcs where we dont need to create a map, and
1200 // the corresponding column has a hash table for it to the rows alrdy
1201 // by generate func
1202 if (!currentTable2.genBST.empty() &&
1203 currentTable2.generateColumnBST == columnName2) {
1204 joinCommandFuncBST(columnIndex1, numberColumns, tableName1,
1205 tableName2, columnStrings, tableNumbers,
1206 currentTable2.genBST);
1207 }
1208 // strat: it must have a bst, and the column indics must be the same
1209 else if (!currentTable2.genHash.empty() &&
1210 currentTable2.generateColumnHash == columnName2) {
1211 joinCommandFunc(columnIndex1, numberColumns, tableName1, tableName2,
1212 columnStrings, tableNumbers, currentTable2.genHash);
1213 }
1214 // strat: it must have not bst and no hash OR it is not empty but column
1215 // numbers dont match
1216 else {
1217 // strat: check if columnName2 has a hash or bst index, if not we
1218 // make a temp, hash index used for fast check
1219 unordered_map<TableEntry, vector<int>> genHashTemp;
1220 for (unsigned int i = 0; i < currentTable2.matrix.size(); ++i) {
1221 genHashTemp[currentTable2.matrix[i][columnIndex2]].emplace_back(i);
1222 }
1223 joinCommandFunc(columnIndex1, numberColumns, tableName1, tableName2,
1224 columnStrings, tableNumbers, genHashTemp);
1225 }
1226 }
1227 }
1228 }
1229}
1230
1231void quitCommand() { cout << "Thanks for being silly!\n"; }
1232
1233void silly::run() {
1234 void quitCommand();
1235 string cmd;
1236 do {
1237 cout << "% ";
1238 cin >> cmd;
1239 // purpose: error for when they add a comment such as '#'
1240 if (cmd[0] == '#') {
1241 getline(cin, cmd);
1242 } else if (cmd[0] == 'C') {
1243 createCommand();
1244 } else if (cmd[0] == 'R') {
1245 removeCommand();
1246 } else if (cmd[0] == 'I') {
1247 insertCommand();
1248 } else if (cmd[0] == 'P') {
1249 printCommand();
1250 } else if (cmd[0] == 'Q') {
1251 quitCommand();
1252 } else if (cmd[0] == 'D') {
1253 deleteCommand();
1254 } else if (cmd[0] == 'G') {
1255 generateCommand();
1256 } else if (cmd[0] == 'J') {
1257 joinCommand();
1258 } else {
1259 cout << "Error: unrecognized command\n";
1260 getline(cin, cmd);
1261 }
1262 } while (cmd != "QUIT");
1263
1264 // purpose: program returns 0 from main(handled in main), and prints a
1265 // goodbye message
1266}