Skip to content

Commit 8712c5e

Browse files
committed
Modularizing constant test helpers
Pulling out all test helpers into a file called connectEngine, which is essentially just all functions that cannot be parallelized and will stay the same among the sequential, OpenMP, and MPI implementations. Additionally, added some total runtime statistics for the testing runners, making it pretty colors to look cool. This could additionally be pretty useful when doing benchmarks and runtime analysis.
1 parent 6213785 commit 8712c5e

File tree

5 files changed

+298
-245
lines changed

5 files changed

+298
-245
lines changed

QPESeq.c

Lines changed: 21 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -1,243 +1,17 @@
1-
/* Serial Implementation - uses the bplus serial engine and tokenizer to execute a provided SQL query */
1+
/* Serial Implementation - Runs commands from the query text file using connectEngine */
22

33
#define _POSIX_C_SOURCE 200809L // For strdup
44
#include <stdio.h>
55
#include <stdlib.h>
66
#include <string.h>
7-
#include <strings.h>
8-
#include <ctype.h>
9-
#include <assert.h>
10-
#include "../include/executeEngine-serial.h"
11-
#include "../include/sql.h"
12-
#include "../include/printHelper.h"
137
#include <time.h>
14-
15-
// Constants for the test environment
16-
#define DATA_FILE "data-generation/commands_50k.csv"
17-
#define TABLE_NAME "commands"
18-
#define MAX_TOKENS 100
19-
#define ROW_LIMIT 20 // Max rows to print in output
20-
21-
// Forward declarations B+ tree implementation
22-
typedef struct node node; // Pull node declaration from serial bplus
23-
typedef struct record record; // Pull record declaration from serial bplus
24-
25-
/* --- Helper functions --- */
26-
27-
// Helper to safely copy strings with truncation
28-
static inline void safe_copy(char *dst, size_t n, const char *src) {
29-
snprintf(dst, n, "%.*s", (int)n - 1, src);
30-
}
31-
32-
// Helper to trim whitespace from a string
33-
static inline char* trim(char *s) {
34-
while (*s && isspace((unsigned char)*s)) s++;
35-
return s;
36-
}
37-
38-
// Helper to map Parser OperatorType to string
39-
const char* get_operator_string(OperatorType op) {
40-
switch (op) {
41-
case OP_EQ: return "=";
42-
case OP_NEQ: return "!=";
43-
case OP_GT: return ">";
44-
case OP_LT: return "<";
45-
case OP_GTE: return ">=";
46-
case OP_LTE: return "<=";
47-
default: return "=";
48-
}
49-
}
50-
51-
// Helper to map Parser LogicOperator to string
52-
const char* get_logic_op_string(LogicOperator op) {
53-
switch (op) {
54-
case LOGIC_AND: return "AND";
55-
case LOGIC_OR: return "OR";
56-
default: return "AND";
57-
}
58-
}
59-
60-
// Optimal indexes constant
61-
const char* optimalIndexes[] = {
62-
"command_id",
63-
"user_id",
64-
"risk_level",
65-
"exit_code",
66-
"sudo_used"
67-
};
68-
const FieldType optimalIndexTypes[] = {
69-
FIELD_UINT64,
70-
FIELD_INT,
71-
FIELD_INT,
72-
FIELD_INT,
73-
FIELD_BOOL
74-
};
75-
const int numOptimalIndexes = 5;
76-
77-
// Helper to convert ParsedSQL conditions to engine's whereClauseS linked list
78-
struct whereClauseS* convert_conditions(ParsedSQL *parsed) {
79-
if (parsed->num_conditions == 0) return NULL;
80-
81-
struct whereClauseS *head = NULL;
82-
struct whereClauseS *current = NULL;
83-
84-
for (int i = 0; i < parsed->num_conditions; i++) {
85-
struct whereClauseS *node = malloc(sizeof(struct whereClauseS));
86-
node->attribute = parsed->conditions[i].column;
87-
node->operator = get_operator_string(parsed->conditions[i].op);
88-
node->value = parsed->conditions[i].value;
89-
90-
// Simple type inference for the test
91-
if (parsed->conditions[i].is_numeric) {
92-
node->value_type = 0; // Integer/Number
93-
} else {
94-
node->value_type = 1; // String
95-
}
96-
97-
// TODO - Handle sub-expressions and nested conditions
98-
// Note: Nested conditions are not currently supported by the test harness
99-
node->next = NULL;
100-
node->sub = NULL;
101-
102-
// Set logical operator for the *previous* node to connect to this one
103-
// The parser stores logic ops between conditions. logic_ops[0] is between cond[0] and cond[1]
104-
if (i < parsed->num_conditions - 1) {
105-
node->logical_op = get_logic_op_string(parsed->logic_ops[i]);
106-
} else {
107-
node->logical_op = NULL;
108-
}
109-
110-
if (head == NULL) {
111-
head = node;
112-
current = node;
113-
} else {
114-
current->next = node;
115-
current = node;
116-
}
117-
}
118-
return head;
119-
}
120-
121-
// Helper to free the manually constructed where clause
122-
void free_where_clause_list(struct whereClauseS *head) {
123-
while (head) {
124-
struct whereClauseS *temp = head;
125-
head = head->next;
126-
free(temp);
127-
}
128-
}
129-
130-
// Main test runner for a single query string
131-
void run_test_query(struct engineS *engine, const char *query, int max_rows) {
132-
133-
// Print query for testing
134-
printf("Executing Query: %s\n", query);
135-
136-
// Tokenize
137-
Token tokens[MAX_TOKENS];
138-
int num_tokens = tokenize(query, tokens, MAX_TOKENS);
139-
if (num_tokens <= 0) {
140-
printf("Tokenization failed.\n");
141-
return;
142-
}
143-
144-
// Parse - Determine which command is ran and extract components
145-
ParsedSQL parsed = parse_tokens(tokens);
146-
147-
// Convert to Engine Arguments
148-
const char *selectItems[parsed.num_columns > 0 ? parsed.num_columns : 1];
149-
int numSelectItems = 0;
150-
151-
if (!parsed.select_all) {
152-
numSelectItems = parsed.num_columns;
153-
for (int i = 0; i < numSelectItems; i++) {
154-
selectItems[i] = parsed.columns[i];
155-
}
156-
}
157-
158-
// Handle non-SELECT commands here and return early
159-
switch (parsed.command) {
160-
case CMD_INSERT: {
161-
if (parsed.num_values != 12) {
162-
printf("Error: INSERT requires exactly 12 values.\n");
163-
return;
164-
}
165-
record r;
166-
r.command_id = strtoull(parsed.insert_values[0], NULL, 10);
167-
safe_copy(r.raw_command, sizeof(r.raw_command), parsed.insert_values[1]);
168-
safe_copy(r.base_command, sizeof(r.base_command), parsed.insert_values[2]);
169-
safe_copy(r.shell_type, sizeof(r.shell_type), parsed.insert_values[3]);
170-
r.exit_code = atoi(parsed.insert_values[4]);
171-
safe_copy(r.timestamp, sizeof(r.timestamp), parsed.insert_values[5]);
172-
173-
// Handle boolean sudo_used
174-
r.sudo_used = (strcasecmp(parsed.insert_values[6], "true") == 0 || strcmp(parsed.insert_values[6], "1") == 0);
175-
176-
safe_copy(r.working_directory, sizeof(r.working_directory), parsed.insert_values[7]);
177-
r.user_id = atoi(parsed.insert_values[8]);
178-
safe_copy(r.user_name, sizeof(r.user_name), parsed.insert_values[9]);
179-
safe_copy(r.host_name, sizeof(r.host_name), parsed.insert_values[10]);
180-
r.risk_level = atoi(parsed.insert_values[11]);
181-
182-
if (executeQueryInsertSerial(engine, parsed.table, &r)) {
183-
printf("Insert successful.\n\n");
184-
} else {
185-
printf("Insert failed.\n\n");
186-
}
187-
return;
188-
}
189-
190-
case CMD_DELETE: {
191-
struct whereClauseS *whereClause = convert_conditions(&parsed);
192-
struct resultSetS *result = executeQueryDeleteSerial(engine, parsed.table, whereClause);
193-
if (result) {
194-
printf("Delete successful. Rows affected: %d\n", result->numRecords);
195-
freeResultSet(result);
196-
} else {
197-
printf("Delete failed.\n");
198-
}
199-
free_where_clause_list(whereClause);
200-
return;
201-
}
202-
203-
case CMD_SELECT: {
204-
// Handled below
205-
break;
206-
}
207-
208-
case CMD_NONE: {
209-
printf("No command detected.\n");
210-
return;
211-
}
212-
213-
default: {
214-
printf("Unsupported command.\n");
215-
return;
216-
}
217-
}
218-
219-
// Retreive the WHERE clause
220-
struct whereClauseS *whereClause = convert_conditions(&parsed);
221-
222-
// Execute
223-
struct resultSetS *result = executeQuerySelectSerial(
224-
engine,
225-
selectItems,
226-
numSelectItems,
227-
parsed.table,
228-
whereClause
229-
);
230-
231-
// Verify and Print
232-
printTable(NULL, result, max_rows);
233-
234-
// Cleanup
235-
if (result) freeResultSet(result); // Free the results object
236-
free_where_clause_list(whereClause); // Free where clause linked list
237-
printf("\n");
238-
}
239-
240-
/* --- Main Functionality - intake commands from text file and process */
8+
#include "../include/executeEngine-serial.h"
9+
#include "../include/connectEngine.h"
10+
// ANSI color codes for pretty printing
11+
#define CYAN "\x1b[36m"
12+
#define YELLOW "\x1b[33m"
13+
#define BOLD "\x1b[1m"
14+
#define RESET "\x1b[0m"
24115

24216
int main(int argc, char *argv[]) {
24317

@@ -256,6 +30,9 @@ int main(int argc, char *argv[]) {
25630
TABLE_NAME
25731
);
25832

33+
// End timer for engine initialization
34+
double initTimeTaken = ((double)clock() - totalStart) / CLOCKS_PER_SEC;
35+
25936
// Load the COMMANDS into memory (from COMMAND text file)
26037
const char *query_file = "sample-queries.txt";
26138
FILE *fp = fopen(query_file, "r");
@@ -287,6 +64,9 @@ int main(int argc, char *argv[]) {
28764
buffer[fsize] = 0;
28865
fclose(fp);
28966

67+
// End timer for loading queries
68+
double loadTimeTaken = ((double)clock() - totalStart) / CLOCKS_PER_SEC;
69+
29070
// Run each command from the command input file
29171
char *query = strtok(buffer, ";");
29272
while (query) {
@@ -301,8 +81,14 @@ int main(int argc, char *argv[]) {
30181
free(buffer);
30282
destroyEngineSerial(engine);
30383

84+
// Print total runtime statistics in pretty colors
30485
double totalTimeTaken = ((double)clock() - totalStart) / CLOCKS_PER_SEC;
305-
printf("Total Execution Time For All Queries: %.4f seconds\n", totalTimeTaken);
86+
printf(CYAN "======= Execution Summary =======" RESET "\n");
87+
printf(CYAN "Engine Initialization Time: " RESET YELLOW "%.4f seconds\n" RESET, initTimeTaken);
88+
printf(CYAN "Query Loading Time: " RESET YELLOW "%.4f seconds\n" RESET, loadTimeTaken - initTimeTaken);
89+
printf(CYAN "Query Execution Time: " RESET YELLOW "%.4f seconds\n" RESET, totalTimeTaken - loadTimeTaken);
90+
printf(BOLD CYAN "Total Execution Time: " RESET BOLD YELLOW "%.4f seconds" RESET "\n", totalTimeTaken);
91+
printf(CYAN "=================================" RESET "\n");
30692

30793
return EXIT_SUCCESS;
30894
}

0 commit comments

Comments
 (0)