44#include <stdio.h>
55#include <stdlib.h>
66#include <string.h>
7+ #include <strings.h> // For strcasecmp
78#include <time.h>
89#include <mpi.h>
910#include "../include/executeEngine-serial.h"
1011#include "../include/connectEngine.h"
12+ #include "../include/printHelper.h"
13+
14+ // Optimal indexes constant
15+ const char * optimalIndexes [] = {
16+ "command_id" ,
17+ "user_id" ,
18+ "risk_level" ,
19+ "exit_code" ,
20+ "sudo_used"
21+ };
22+ const FieldType optimalIndexTypes [] = {
23+ FIELD_UINT64 ,
24+ FIELD_INT ,
25+ FIELD_INT ,
26+ FIELD_INT ,
27+ FIELD_BOOL
28+ };
29+ const int numOptimalIndexes = 5 ;
30+
1131// ANSI color codes for pretty printing
1232#define CYAN "\x1b[36m"
1333#define YELLOW "\x1b[33m"
1434#define BOLD "\x1b[1m"
1535#define RESET "\x1b[0m"
1636
37+ // Helper to safely copy strings with truncation
38+ static inline void safe_copy (char * dst , size_t n , const char * src ) {
39+ snprintf (dst , n , "%.*s" , (int )n - 1 , src );
40+ }
41+
42+ // Helper to map Parser OperatorType to string
43+ const char * get_operator_string (OperatorType op ) {
44+ switch (op ) {
45+ case OP_EQ : return "=" ;
46+ case OP_NEQ : return "!=" ;
47+ case OP_GT : return ">" ;
48+ case OP_LT : return "<" ;
49+ case OP_GTE : return ">=" ;
50+ case OP_LTE : return "<=" ;
51+ default : return "=" ;
52+ }
53+ }
54+
55+ // Helper to map Parser LogicOperator to string
56+ const char * get_logic_op_string (LogicOperator op ) {
57+ switch (op ) {
58+ case LOGIC_AND : return "AND" ;
59+ case LOGIC_OR : return "OR" ;
60+ default : return "AND" ;
61+ }
62+ }
63+
64+ // Helper to convert ParsedSQL conditions to engine's whereClauseS linked list
65+ struct whereClauseS * convert_conditions (ParsedSQL * parsed ) {
66+ if (parsed -> num_conditions == 0 ) return NULL ;
67+
68+ struct whereClauseS * head = NULL ;
69+ struct whereClauseS * current = NULL ;
70+
71+ for (int i = 0 ; i < parsed -> num_conditions ; i ++ ) {
72+ struct whereClauseS * node = malloc (sizeof (struct whereClauseS ));
73+
74+ if (parsed -> conditions [i ].is_nested && parsed -> conditions [i ].nested_sql ) {
75+ node -> attribute = NULL ;
76+ node -> operator = NULL ;
77+ node -> value = NULL ;
78+ node -> value_type = 0 ;
79+ node -> sub = convert_conditions (parsed -> conditions [i ].nested_sql );
80+ } else {
81+ node -> attribute = parsed -> conditions [i ].column ;
82+ node -> operator = get_operator_string (parsed -> conditions [i ].op );
83+ node -> value = parsed -> conditions [i ].value ;
84+
85+ // Simple type inference for the test
86+ if (parsed -> conditions [i ].is_numeric ) {
87+ node -> value_type = 0 ; // Integer/Number
88+ } else {
89+ node -> value_type = 1 ; // String
90+ }
91+ node -> sub = NULL ;
92+ }
93+
94+ node -> next = NULL ;
95+
96+ if (i < parsed -> num_conditions - 1 ) {
97+ node -> logical_op = get_logic_op_string (parsed -> logic_ops [i ]);
98+ } else {
99+ node -> logical_op = NULL ;
100+ }
101+
102+ if (head == NULL ) {
103+ head = node ;
104+ current = node ;
105+ } else {
106+ current -> next = node ;
107+ current = node ;
108+ }
109+ }
110+ return head ;
111+ }
112+
113+ // Helper to free the manually constructed where clause
114+ void free_where_clause_list (struct whereClauseS * head ) {
115+ while (head ) {
116+ struct whereClauseS * temp = head ;
117+ head = head -> next ;
118+ free (temp );
119+ }
120+ }
121+
17122int main (int argc , char * argv []) {
18123
19- // NOTE: defaulting to sample queries file for ease of testing. Can implement CLI arg later.
20- (void )argc ; (void )argv ; // Unused for now. Prevent warnings.
124+ // Initialize MPI Environment
125+ MPI_Init (& argc , & argv );
126+ int rank , size ;
127+ MPI_Comm_rank (MPI_COMM_WORLD , & rank );
128+ MPI_Comm_size (MPI_COMM_WORLD , & size );
129+
130+ set_rank (rank );
21131
22132 // Start a timer for total runtime statistics
23- clock_t totalStart = clock ();
133+ double totalStart = MPI_Wtime ();
24134
25135 // Instantiate an engine object to handle the execution of the query
26136 struct engineS * engine = initializeEngineSerial (
@@ -32,14 +142,15 @@ int main(int argc, char *argv[]) {
32142 );
33143
34144 // End timer for engine initialization
35- double initTimeTaken = (( double ) clock () - totalStart ) / CLOCKS_PER_SEC ;
145+ double initTimeTaken = MPI_Wtime () - totalStart ;
36146
37147 // Load the COMMANDS into memory (from COMMAND text file)
38148 const char * query_file = "sample-queries.txt" ;
39149 FILE * fp = fopen (query_file , "r" );
40150 if (!fp ) {
41- perror ("Failed to open query file" );
151+ if ( rank == 0 ) perror ("Failed to open query file" );
42152 destroyEngineSerial (engine );
153+ MPI_Finalize ();
43154 return EXIT_FAILURE ;
44155 }
45156
@@ -49,47 +160,157 @@ int main(int argc, char *argv[]) {
49160
50161 char * buffer = malloc (fsize + 1 );
51162 if (!buffer ) {
52- perror ("Failed to allocate memory for query file" );
163+ if ( rank == 0 ) perror ("Failed to allocate memory for query file" );
53164 fclose (fp );
54165 destroyEngineSerial (engine );
166+ MPI_Finalize ();
55167 return EXIT_FAILURE ;
56168 }
57169 size_t read_size = fread (buffer , 1 , fsize , fp );
58170 if (read_size != (size_t )fsize ) {
59- perror ("Failed to read query file" );
171+ if ( rank == 0 ) perror ("Failed to read query file" );
60172 free (buffer );
61173 fclose (fp );
62174 destroyEngineSerial (engine );
175+ MPI_Finalize ();
63176 return EXIT_FAILURE ;
64177 }
65178 buffer [fsize ] = 0 ;
66179 fclose (fp );
67180
68181 // End timer for loading queries
69- double loadTimeTaken = ((double )clock () - totalStart ) / CLOCKS_PER_SEC ;
70-
71- // Run each command from the command input file
72- char * query = strtok (buffer , ";" );
73- while (query ) {
74- // Trim whitespace
75- query = trim (query );
76- if (* query ) {
77- run_test_query (engine , query , ROW_LIMIT ); // Limit output to 10 rows for testing
182+ double loadTimeTaken = MPI_Wtime () - totalStart ;
183+
184+ // Split queries into an array
185+ #define MAX_QUERIES 1000
186+ char * queries [MAX_QUERIES ];
187+ int query_count = 0 ;
188+
189+ char * token = strtok (buffer , ";" );
190+ while (token && query_count < MAX_QUERIES ) {
191+ queries [query_count ++ ] = token ;
192+ token = strtok (NULL , ";" );
193+ }
194+
195+ // Execute Queries
196+ for (int i = 0 ; i < query_count ; i ++ ) {
197+ char * query = trim (queries [i ]);
198+ if (!* query ) continue ;
199+
200+ // Tokenize
201+ Token tokens [MAX_TOKENS ];
202+ int num_tokens = tokenize (query , tokens , MAX_TOKENS );
203+
204+ ParsedSQL parsed ;
205+ struct resultSetS * result = NULL ;
206+ bool success = false;
207+ double execTime = 0 ;
208+ int rowsAffected = 0 ;
209+ bool parseFailed = false;
210+
211+ if (num_tokens > 0 ) {
212+ parsed = parse_tokens (tokens );
213+
214+ // Prepare Select Items
215+ const char * selectItems [parsed .num_columns > 0 ? parsed .num_columns : 1 ];
216+ int numSelectItems = 0 ;
217+ if (!parsed .select_all ) {
218+ numSelectItems = parsed .num_columns ;
219+ for (int k = 0 ; k < numSelectItems ; k ++ ) selectItems [k ] = parsed .columns [k ];
220+ }
221+
222+ double start = MPI_Wtime ();
223+
224+ // Execute based on command type
225+ if (parsed .command == CMD_INSERT ) {
226+ if (parsed .num_values == 12 ) {
227+ record r ;
228+ r .command_id = strtoull (parsed .insert_values [0 ], NULL , 10 );
229+ safe_copy (r .raw_command , sizeof (r .raw_command ), parsed .insert_values [1 ]);
230+ safe_copy (r .base_command , sizeof (r .base_command ), parsed .insert_values [2 ]);
231+ safe_copy (r .shell_type , sizeof (r .shell_type ), parsed .insert_values [3 ]);
232+ r .exit_code = atoi (parsed .insert_values [4 ]);
233+ safe_copy (r .timestamp , sizeof (r .timestamp ), parsed .insert_values [5 ]);
234+ r .sudo_used = (strcasecmp (parsed .insert_values [6 ], "true" ) == 0 || strcmp (parsed .insert_values [6 ], "1" ) == 0 );
235+ safe_copy (r .working_directory , sizeof (r .working_directory ), parsed .insert_values [7 ]);
236+ r .user_id = atoi (parsed .insert_values [8 ]);
237+ safe_copy (r .user_name , sizeof (r .user_name ), parsed .insert_values [9 ]);
238+ safe_copy (r .host_name , sizeof (r .host_name ), parsed .insert_values [10 ]);
239+ r .risk_level = atoi (parsed .insert_values [11 ]);
240+
241+ success = executeQueryInsertSerial (engine , parsed .table , & r );
242+ }
243+ }
244+ else if (parsed .command == CMD_DELETE ) {
245+ struct whereClauseS * whereClause = convert_conditions (& parsed );
246+ result = executeQueryDeleteSerial (engine , parsed .table , whereClause );
247+ if (result ) rowsAffected = result -> numRecords ;
248+ free_where_clause_list (whereClause );
249+ }
250+ else if (parsed .command == CMD_SELECT ) {
251+ struct whereClauseS * whereClause = convert_conditions (& parsed );
252+ result = executeQuerySelectSerial (engine , selectItems , numSelectItems , parsed .table , whereClause );
253+ free_where_clause_list (whereClause );
254+ }
255+
256+ execTime = MPI_Wtime () - start ;
257+ } else {
258+ parseFailed = true;
259+ }
260+
261+ // Print results (Rank 0 only)
262+ if (rank == 0 ) {
263+ printf ("Executing Query: %s\n" , query );
264+
265+ if (parseFailed ) {
266+ printf ("Tokenization failed.\n" );
267+ } else {
268+ if (parsed .command == CMD_INSERT ) {
269+ if (parsed .num_values != 12 ) {
270+ printf ("Error: INSERT requires exactly 12 values.\n" );
271+ } else if (success ) {
272+ printf ("Insert successful. Execution Time: %ld\n\n" , (long )execTime );
273+ } else {
274+ printf ("Insert failed. Execution Time: %ld\n\n" , (long )execTime );
275+ }
276+ } else if (parsed .command == CMD_DELETE ) {
277+ if (result ) {
278+ printf ("Delete successful. Rows affected: %d. Execution Time: %ld\n\n" , rowsAffected , (long )execTime );
279+ } else {
280+ printf ("Delete failed. Execution Time: %ld\n\n" , (long )execTime );
281+ }
282+ } else if (parsed .command == CMD_SELECT ) {
283+ printTable (NULL , result , ROW_LIMIT );
284+ printf ("\n" );
285+ } else if (parsed .command == CMD_NONE ) {
286+ printf ("No command detected.\n" );
287+ } else {
288+ fprintf (stderr , "Unsupported command.\n" );
289+ }
290+ }
78291 }
79- query = strtok (NULL , ";" );
292+
293+ // Cleanup
294+ if (result ) freeResultSet (result );
295+ }
296+
297+ // Print total runtime statistics in pretty colors (Rank 0 only)
298+ if (rank == 0 ) {
299+ double totalTimeTaken = MPI_Wtime () - totalStart ;
300+ printf (CYAN "======= Execution Summary =======" RESET "\n" );
301+ printf (CYAN "Engine Initialization Time: " RESET YELLOW "%.4f seconds\n" RESET , initTimeTaken );
302+ printf (CYAN "Query Loading Time: " RESET YELLOW "%.4f seconds\n" RESET , loadTimeTaken - initTimeTaken );
303+ printf (CYAN "Query Execution Time: " RESET YELLOW "%.4f seconds\n" RESET , totalTimeTaken - loadTimeTaken );
304+ printf (BOLD CYAN "Total Execution Time: " RESET BOLD YELLOW "%.4f seconds" RESET "\n" , totalTimeTaken );
305+ printf (CYAN "=================================" RESET "\n" );
80306 }
81307
308+ printf ("Rank %d: Freeing buffer...\n" , rank );
82309 free (buffer );
310+ printf ("Rank %d: Destroying engine...\n" , rank );
83311 destroyEngineSerial (engine );
312+ printf ("Rank %d: Finalizing MPI...\n" , rank );
84313
85- // Print total runtime statistics in pretty colors
86- double totalTimeTaken = ((double )clock () - totalStart ) / CLOCKS_PER_SEC ;
87- printf (CYAN "======= Execution Summary =======" RESET "\n" );
88- printf (CYAN "Engine Initialization Time: " RESET YELLOW "%.4f seconds\n" RESET , initTimeTaken );
89- printf (CYAN "Query Loading Time: " RESET YELLOW "%.4f seconds\n" RESET , loadTimeTaken - initTimeTaken );
90- printf (CYAN "Query Execution Time: " RESET YELLOW "%.4f seconds\n" RESET , totalTimeTaken - loadTimeTaken );
91- printf (BOLD CYAN "Total Execution Time: " RESET BOLD YELLOW "%.4f seconds" RESET "\n" , totalTimeTaken );
92- printf (CYAN "=================================" RESET "\n" );
93-
314+ MPI_Finalize ();
94315 return EXIT_SUCCESS ;
95316}
0 commit comments