1use crate::config::{Table, TableCatalog};
3use crate::engine::{evaluator::Evaluator, row::Row};
4use crate::error::{DdbError, Result};
5use crate::file_io::{CsvReader, FileLock};
6use crate::functions::Value;
7use crate::parser::{DeleteStatement, InsertStatement, JoinClause, JoinType, OrderDirection, SelectColumn, SelectStatement, UpdateStatement, UpsertStatement};
8use std::fs::{File, OpenOptions};
9use std::io::{BufRead, BufReader, BufWriter, Write};
10
11pub struct QueryExecutor {
12 evaluator: Evaluator,
13}
14
15impl QueryExecutor {
16 pub fn new() -> Self {
17 QueryExecutor {
18 evaluator: Evaluator::new(),
19 }
20 }
21
22 pub fn execute_select(&self, stmt: &SelectStatement, table: &Table) -> Result<Vec<Row>> {
24 self.execute_select_with_catalog(stmt, table, None)
25 }
26
27 pub fn execute_select_with_catalog(
29 &self,
30 stmt: &SelectStatement,
31 table: &Table,
32 catalog: Option<&TableCatalog>,
33 ) -> Result<Vec<Row>> {
34 let has_aggregates = self.has_aggregate_functions(&stmt.columns);
36 let has_group_by = !stmt.group_by.is_empty();
37
38 if has_aggregates || has_group_by {
39 return self.execute_aggregate_select_with_catalog(stmt, table, catalog);
40 }
41
42 let mut reader = CsvReader::new(&table.data_file, table.field_delimiter, true)?;
44 let mut rows = Vec::new();
45 while let Some(row) = reader.next_row()? {
46 rows.push(row);
47 }
48
49 if !stmt.joins.is_empty() {
51 rows = self.execute_joins(rows, &stmt.joins, catalog)?;
52 }
53
54 rows.retain(|row| {
56 if let Some(where_expr) = &stmt.where_clause {
57 if let Ok(result) = self.evaluator.evaluate(where_expr, row) {
58 if let Ok(matches) = self.to_boolean(&result) {
59 return matches;
60 }
61 }
62 }
63 stmt.where_clause.is_none()
64 });
65
66 rows = rows
68 .into_iter()
69 .filter_map(|row| self.project_row(&row, &stmt.columns).ok())
70 .collect();
71
72 if stmt.distinct {
74 rows = self.deduplicate_rows(rows);
75 }
76
77 if !stmt.order_by.is_empty() {
79 if let Some(limit) = &stmt.limit {
81 if limit.offset.is_none() || limit.offset == Some(0) {
82 rows = self.sort_rows_with_limit(rows, &stmt.order_by, limit.count)?;
84 } else {
85 rows = self.sort_rows(rows, &stmt.order_by)?;
87 let start = limit.offset.unwrap_or(0);
88 rows = rows.into_iter().skip(start).take(limit.count).collect();
89 }
90 } else {
91 rows = self.sort_rows(rows, &stmt.order_by)?;
93 }
94 } else if let Some(limit) = &stmt.limit {
95 let start = limit.offset.unwrap_or(0);
97 rows = rows.into_iter().skip(start).take(limit.count).collect();
98 }
99
100 Ok(rows)
101 }
102
103 fn has_aggregate_functions(&self, columns: &[SelectColumn]) -> bool {
105 columns.iter().any(|col| match col {
106 SelectColumn::Function { name, .. } => {
107 matches!(
108 name.to_uppercase().as_str(),
109 "COUNT" | "SUM" | "AVG" | "MIN" | "MAX" | "STDDEV" | "VARIANCE" | "GROUP_CONCAT"
110 )
111 }
112 _ => false,
113 })
114 }
115
116 fn execute_joins(
118 &self,
119 left_rows: Vec<Row>,
120 joins: &[JoinClause],
121 catalog: Option<&TableCatalog>,
122 ) -> Result<Vec<Row>> {
123 let mut result = left_rows;
124
125 for join in joins {
126 let catalog = catalog.ok_or_else(|| {
128 DdbError::ExecutionError(
129 "JOIN requires table catalog. Use execute_select_with_catalog.".to_string(),
130 )
131 })?;
132
133 let right_table = catalog.get_table(&join.table).ok_or_else(|| {
134 DdbError::ExecutionError(format!("Table '{}' not found for JOIN", join.table))
135 })?;
136
137 let mut right_reader =
139 CsvReader::new(&right_table.data_file, right_table.field_delimiter, true)?;
140 let mut right_rows = Vec::new();
141 while let Some(row) = right_reader.next_row()? {
142 right_rows.push(row);
143 }
144
145 result = self.perform_join_indexed(result, right_rows, join)?;
147 }
148
149 Ok(result)
150 }
151
152 fn perform_join(
154 &self,
155 left_rows: Vec<Row>,
156 right_rows: Vec<Row>,
157 join: &JoinClause,
158 ) -> Result<Vec<Row>> {
159 let mut joined_rows = Vec::new();
160
161 match join.join_type {
162 JoinType::Inner => {
163 for left_row in &left_rows {
165 for right_row in &right_rows {
166 let combined = self.merge_rows(left_row, right_row);
167 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
168 if self.to_boolean(&result)? {
169 joined_rows.push(combined);
170 }
171 }
172 }
173 }
174 JoinType::Left => {
175 for left_row in &left_rows {
177 let mut matched = false;
178 for right_row in &right_rows {
179 let combined = self.merge_rows(left_row, right_row);
180 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
181 if self.to_boolean(&result)? {
182 joined_rows.push(combined);
183 matched = true;
184 }
185 }
186 if !matched {
187 let row_with_nulls = left_row.clone();
189 joined_rows.push(row_with_nulls);
192 }
193 }
194 }
195 JoinType::Right => {
196 for right_row in &right_rows {
198 let mut matched = false;
199 for left_row in &left_rows {
200 let combined = self.merge_rows(left_row, right_row);
201 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
202 if self.to_boolean(&result)? {
203 joined_rows.push(combined);
204 matched = true;
205 }
206 }
207 if !matched {
208 joined_rows.push(right_row.clone());
210 }
211 }
212 }
213 JoinType::Full => {
214 let mut matched_left = vec![false; left_rows.len()];
216 let mut matched_right = vec![false; right_rows.len()];
217
218 for (left_idx, left_row) in left_rows.iter().enumerate() {
219 for (right_idx, right_row) in right_rows.iter().enumerate() {
220 let combined = self.merge_rows(left_row, right_row);
221 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
222 if self.to_boolean(&result)? {
223 joined_rows.push(combined);
224 matched_left[left_idx] = true;
225 matched_right[right_idx] = true;
226 }
227 }
228 }
229
230 for (idx, left_row) in left_rows.iter().enumerate() {
232 if !matched_left[idx] {
233 joined_rows.push(left_row.clone());
234 }
235 }
236
237 for (idx, right_row) in right_rows.iter().enumerate() {
239 if !matched_right[idx] {
240 joined_rows.push(right_row.clone());
241 }
242 }
243 }
244 }
245
246 Ok(joined_rows)
247 }
248
249 fn perform_join_indexed(
252 &self,
253 left_rows: Vec<Row>,
254 right_rows: Vec<Row>,
255 join: &JoinClause,
256 ) -> Result<Vec<Row>> {
257 use crate::engine::index::HashIndex;
258
259 let index_info = self.try_extract_equality_join(&join.on_condition);
262
263 if let Some((left_col, right_col)) = index_info {
264 let right_index = HashIndex::build(&right_col, &right_rows);
267
268 let mut joined_rows = Vec::new();
269
270 match join.join_type {
271 JoinType::Inner => {
272 for left_row in &left_rows {
274 if let Some(left_value) = left_row.get(&left_col) {
275 if let Some(matching_indices) = right_index.lookup(left_value) {
276 for &right_idx in matching_indices {
277 let right_row = &right_rows[right_idx];
278 let combined = self.merge_rows(left_row, right_row);
279
280 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
282 if self.to_boolean(&result)? {
283 joined_rows.push(combined);
284 }
285 }
286 }
287 }
288 }
289 }
290 JoinType::Left => {
291 for left_row in &left_rows {
293 let mut matched = false;
294 if let Some(left_value) = left_row.get(&left_col) {
295 if let Some(matching_indices) = right_index.lookup(left_value) {
296 for &right_idx in matching_indices {
297 let right_row = &right_rows[right_idx];
298 let combined = self.merge_rows(left_row, right_row);
299
300 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
301 if self.to_boolean(&result)? {
302 joined_rows.push(combined);
303 matched = true;
304 }
305 }
306 }
307 }
308 if !matched {
309 joined_rows.push(left_row.clone());
310 }
311 }
312 }
313 JoinType::Right => {
314 let left_index = HashIndex::build(&left_col, &left_rows);
316 let mut matched_right = vec![false; right_rows.len()];
317
318 for (right_idx, right_row) in right_rows.iter().enumerate() {
319 if let Some(right_value) = right_row.get(&right_col) {
320 if let Some(matching_indices) = left_index.lookup(right_value) {
321 for &left_idx in matching_indices {
322 let left_row = &left_rows[left_idx];
323 let combined = self.merge_rows(left_row, right_row);
324
325 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
326 if self.to_boolean(&result)? {
327 joined_rows.push(combined);
328 matched_right[right_idx] = true;
329 }
330 }
331 }
332 }
333 }
334
335 for (idx, right_row) in right_rows.iter().enumerate() {
337 if !matched_right[idx] {
338 joined_rows.push(right_row.clone());
339 }
340 }
341 }
342 JoinType::Full => {
343 let mut matched_left = vec![false; left_rows.len()];
345 let mut matched_right = vec![false; right_rows.len()];
346
347 for (left_idx, left_row) in left_rows.iter().enumerate() {
349 if let Some(left_value) = left_row.get(&left_col) {
350 if let Some(matching_indices) = right_index.lookup(left_value) {
351 for &right_idx in matching_indices {
352 let right_row = &right_rows[right_idx];
353 let combined = self.merge_rows(left_row, right_row);
354
355 let result = self.evaluator.evaluate(&join.on_condition, &combined)?;
356 if self.to_boolean(&result)? {
357 joined_rows.push(combined);
358 matched_left[left_idx] = true;
359 matched_right[right_idx] = true;
360 }
361 }
362 }
363 }
364 }
365
366 for (idx, left_row) in left_rows.iter().enumerate() {
368 if !matched_left[idx] {
369 joined_rows.push(left_row.clone());
370 }
371 }
372
373 for (idx, right_row) in right_rows.iter().enumerate() {
375 if !matched_right[idx] {
376 joined_rows.push(right_row.clone());
377 }
378 }
379 }
380 }
381
382 Ok(joined_rows)
383 } else {
384 self.perform_join(left_rows, right_rows, join)
386 }
387 }
388
389 fn try_extract_equality_join(&self, expr: &crate::parser::Expression) -> Option<(String, String)> {
392 use crate::parser::{BinaryOperator, Expression};
393
394 if let Expression::BinaryOp { left, op, right } = expr {
395 if matches!(op, BinaryOperator::Equal) {
397 if let (Expression::Column(left_col), Expression::Column(right_col)) = (left.as_ref(), right.as_ref()) {
399 return Some((left_col.clone(), right_col.clone()));
400 }
401 }
402 }
403
404 None
405 }
406
407 fn merge_rows(&self, left: &Row, right: &Row) -> Row {
409 let mut merged = left.clone();
410 for (name, value) in right.as_map() {
411 merged.set(name, value.clone());
412 }
413 merged
414 }
415
416 #[allow(dead_code)]
418 fn execute_aggregate_select(&self, stmt: &SelectStatement, table: &Table) -> Result<Vec<Row>> {
419 self.execute_aggregate_select_with_catalog(stmt, table, None)
420 }
421
422 fn execute_aggregate_select_with_catalog(
424 &self,
425 stmt: &SelectStatement,
426 table: &Table,
427 catalog: Option<&TableCatalog>,
428 ) -> Result<Vec<Row>> {
429 let mut reader = CsvReader::new(&table.data_file, table.field_delimiter, true)?;
431 let mut all_rows = Vec::new();
432 while let Some(row) = reader.next_row()? {
433 all_rows.push(row);
434 }
435
436 if !stmt.joins.is_empty() {
438 all_rows = self.execute_joins(all_rows, &stmt.joins, catalog)?;
439 }
440
441 all_rows.retain(|row| {
443 if let Some(where_expr) = &stmt.where_clause {
444 if let Ok(result) = self.evaluator.evaluate(where_expr, row) {
445 if let Ok(matches) = self.to_boolean(&result) {
446 return matches;
447 }
448 }
449 return false;
450 }
451 true
452 });
453
454 if !stmt.group_by.is_empty() {
456 return self.execute_group_by_aggregation(all_rows, stmt);
457 }
458
459 let mut result_row = Row::new();
461
462 for col_spec in &stmt.columns {
463 match col_spec {
464 SelectColumn::Function { name, args, alias } => {
465 let aggregate_result = if self.is_count_star(name, args) {
467 Value::Integer(all_rows.len() as i64)
469 } else {
470 let values: Result<Vec<Value>> = all_rows
472 .iter()
473 .map(|row| {
474 if args.len() == 1 {
475 self.evaluator.evaluate(&args[0], row)
476 } else {
477 Err(DdbError::ExecutionError(
478 "Aggregate functions require exactly one argument".to_string(),
479 ))
480 }
481 })
482 .collect();
483
484 let values = values?;
485
486 match name.to_uppercase().as_str() {
488 "COUNT" => crate::functions::aggregate::count(&values, true)?,
489 "SUM" => crate::functions::aggregate::sum(&values)?,
490 "AVG" => crate::functions::aggregate::avg(&values)?,
491 "MIN" => crate::functions::aggregate::min(&values)?,
492 "MAX" => crate::functions::aggregate::max(&values)?,
493 "STDDEV" | "STDDEV_POP" => crate::functions::aggregate::stddev_pop(&values)?,
494 "VARIANCE" | "VAR_POP" => crate::functions::aggregate::var_pop(&values)?,
495 _ => {
496 return Err(DdbError::ExecutionError(format!(
497 "Unknown aggregate function: {}",
498 name
499 )))
500 }
501 }
502 };
503
504 let default_name = format!("{}(...)", name);
505 let output_name = alias.as_ref().unwrap_or(&default_name);
506 result_row.set(output_name, aggregate_result);
507 }
508 SelectColumn::Column { name, alias } => {
509 let value = all_rows
512 .first()
513 .and_then(|row| row.get(name).cloned())
514 .unwrap_or(Value::Null);
515 let output_name = alias.as_ref().unwrap_or(name);
516 result_row.set(output_name, value);
517 }
518 SelectColumn::Wildcard => {
519 return Err(DdbError::ExecutionError(
520 "Cannot use * with aggregate functions (use COUNT(*) instead)".to_string(),
521 ));
522 }
523 }
524 }
525
526 Ok(vec![result_row])
527 }
528
529 fn execute_group_by_aggregation(
531 &self,
532 all_rows: Vec<Row>,
533 stmt: &SelectStatement,
534 ) -> Result<Vec<Row>> {
535 use std::collections::HashMap;
536
537 let mut groups: HashMap<Vec<String>, Vec<Row>> = HashMap::new();
539
540 for row in all_rows {
541 let mut group_key = Vec::new();
543 for col_name in &stmt.group_by {
544 let value = row.get(col_name)
545 .map(|v| v.to_string())
546 .unwrap_or_else(|| "NULL".to_string());
547 group_key.push(value);
548 }
549
550 groups.entry(group_key).or_insert_with(Vec::new).push(row);
551 }
552
553 let mut result_rows = Vec::new();
555
556 for (_group_key, group_rows) in groups {
557 let mut result_row = Row::new();
558
559 for (_idx, col_name) in stmt.group_by.iter().enumerate() {
561 if let Some(value) = group_rows.first().and_then(|row| row.get(col_name)) {
562 result_row.set(col_name, value.clone());
563 }
564 }
565
566 for col_spec in &stmt.columns {
568 match col_spec {
569 SelectColumn::Function { name, args, alias } => {
570 let aggregate_result = if self.is_count_star(name, args) {
571 Value::Integer(group_rows.len() as i64)
572 } else {
573 let values: Result<Vec<Value>> = group_rows
575 .iter()
576 .map(|row| {
577 if args.len() == 1 {
578 self.evaluator.evaluate(&args[0], row)
579 } else {
580 Err(DdbError::ExecutionError(
581 "Aggregate functions require exactly one argument".to_string(),
582 ))
583 }
584 })
585 .collect();
586
587 let values = values?;
588
589 match name.to_uppercase().as_str() {
591 "COUNT" => crate::functions::aggregate::count(&values, true)?,
592 "SUM" => crate::functions::aggregate::sum(&values)?,
593 "AVG" => crate::functions::aggregate::avg(&values)?,
594 "MIN" => crate::functions::aggregate::min(&values)?,
595 "MAX" => crate::functions::aggregate::max(&values)?,
596 "STDDEV" | "STDDEV_POP" => crate::functions::aggregate::stddev_pop(&values)?,
597 "VARIANCE" | "VAR_POP" => crate::functions::aggregate::var_pop(&values)?,
598 _ => {
599 return Err(DdbError::ExecutionError(format!(
600 "Unknown aggregate function: {}",
601 name
602 )))
603 }
604 }
605 };
606
607 let default_name = format!("{}(...)", name);
608 let output_name = alias.as_ref().unwrap_or(&default_name);
609 result_row.set(output_name, aggregate_result);
610 }
611 SelectColumn::Column { name, alias } => {
612 if !stmt.group_by.contains(name) {
614 return Err(DdbError::ExecutionError(format!(
615 "Column '{}' must appear in GROUP BY clause or be used in an aggregate function",
616 name
617 )));
618 }
619 if let Some(alias_name) = alias {
621 if let Some(value) = result_row.get(name) {
622 result_row.set(alias_name, value.clone());
623 }
624 }
625 }
626 SelectColumn::Wildcard => {
627 return Err(DdbError::ExecutionError(
628 "Cannot use * with GROUP BY (select specific columns)".to_string(),
629 ));
630 }
631 }
632 }
633
634 if let Some(having_expr) = &stmt.having {
636 let result = self.evaluator.evaluate(having_expr, &result_row)?;
637 let matches = self.to_boolean(&result)?;
638 if !matches {
639 continue; }
641 }
642
643 result_rows.push(result_row);
644 }
645
646 Ok(result_rows)
647 }
648
649 fn is_count_star(&self, name: &str, args: &[crate::parser::Expression]) -> bool {
651 name.to_uppercase() == "COUNT"
652 && args.len() == 1
653 && matches!(&args[0], crate::parser::Expression::Column(col) if col == "*")
654 }
655
656 fn project_row(&self, row: &Row, columns: &[SelectColumn]) -> Result<Row> {
658 let mut new_row = Row::new();
659
660 for col_spec in columns {
661 match col_spec {
662 SelectColumn::Wildcard => {
663 for (name, value) in row.as_map() {
665 new_row.set(name, value.clone());
666 }
667 }
668 SelectColumn::Column { name, alias } => {
669 let value = if name.starts_with("@@") {
671 let var_name = &name[2..];
672 let var_expr = crate::parser::Expression::SystemVariable(var_name.to_string());
673 self.evaluator.evaluate(&var_expr, row)?
674 } else {
675 row.get(name)
676 .cloned()
677 .ok_or_else(|| DdbError::ColumnNotFound(name.clone()))?
678 };
679 let output_name = alias.as_ref().unwrap_or(name);
680 new_row.set(output_name, value);
681 }
682 SelectColumn::Function { name, args, alias } => {
683 let func_expr = crate::parser::Expression::Function {
685 name: name.clone(),
686 args: args.clone(),
687 };
688 let result = self.evaluator.evaluate(&func_expr, row)?;
689
690 let default_name = format!("{}(...)", name);
691 let output_name = alias.as_ref().unwrap_or(&default_name);
692 new_row.set(output_name, result);
693 }
694 }
695 }
696
697 Ok(new_row)
698 }
699
700 fn deduplicate_rows(&self, mut rows: Vec<Row>) -> Vec<Row> {
702 let mut seen = std::collections::HashSet::new();
703 rows.retain(|row| {
704 let key = self.row_to_key(row);
705 seen.insert(key)
706 });
707 rows
708 }
709
710 fn row_to_key(&self, row: &Row) -> Vec<String> {
712 let mut keys: Vec<_> = row.column_names();
713 keys.sort();
714 keys.iter()
715 .map(|name| {
716 row.get(name)
717 .map(|v| v.to_string())
718 .unwrap_or_else(|| "NULL".to_string())
719 })
720 .collect()
721 }
722
723 fn sort_rows(
725 &self,
726 mut rows: Vec<Row>,
727 order_by: &[crate::parser::OrderByColumn],
728 ) -> Result<Vec<Row>> {
729 rows.sort_by(|a, b| {
730 for order_col in order_by {
731 let a_val = a.get(&order_col.column).cloned().unwrap_or(Value::Null);
732 let b_val = b.get(&order_col.column).cloned().unwrap_or(Value::Null);
733
734 let cmp = self.compare_values(&a_val, &b_val);
735
736 let cmp = match order_col.direction {
737 OrderDirection::Asc => cmp,
738 OrderDirection::Desc => cmp.reverse(),
739 };
740
741 if cmp != std::cmp::Ordering::Equal {
742 return cmp;
743 }
744 }
745 std::cmp::Ordering::Equal
746 });
747
748 Ok(rows)
749 }
750
751 fn sort_rows_with_limit(
754 &self,
755 mut rows: Vec<Row>,
756 order_by: &[crate::parser::OrderByColumn],
757 limit: usize,
758 ) -> Result<Vec<Row>> {
759 use std::cmp::Ordering;
760
761 if limit == 0 {
763 return Ok(Vec::new());
764 }
765
766 if rows.len() <= limit {
768 return self.sort_rows(rows, order_by);
769 }
770
771 if limit * 2 > rows.len() {
773 return self.sort_rows(rows, order_by);
774 }
775
776 let cmp_fn = |a: &Row, b: &Row| -> Ordering {
778 for order_col in order_by {
779 let a_val = a.get(&order_col.column).cloned().unwrap_or(Value::Null);
780 let b_val = b.get(&order_col.column).cloned().unwrap_or(Value::Null);
781
782 let cmp = self.compare_values(&a_val, &b_val);
783
784 let cmp = match order_col.direction {
785 OrderDirection::Asc => cmp,
786 OrderDirection::Desc => cmp.reverse(),
787 };
788
789 if cmp != Ordering::Equal {
790 return cmp;
791 }
792 }
793 Ordering::Equal
794 };
795
796 rows.select_nth_unstable_by(limit, |a, b| cmp_fn(a, b));
799
800 rows.truncate(limit);
802 rows.sort_by(|a, b| cmp_fn(a, b));
803
804 Ok(rows)
805 }
806
807 fn compare_values(&self, left: &Value, right: &Value) -> std::cmp::Ordering {
809 use std::cmp::Ordering;
810
811 match (left, right) {
812 (Value::Null, Value::Null) => Ordering::Equal,
813 (Value::Null, _) => Ordering::Less,
814 (_, Value::Null) => Ordering::Greater,
815 (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
816 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
817 (Value::Integer(a), Value::Float(b)) => {
818 (*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
819 }
820 (Value::Float(a), Value::Integer(b)) => {
821 a.partial_cmp(&(*b as f64)).unwrap_or(Ordering::Equal)
822 }
823 (Value::String(a), Value::String(b)) => a.cmp(b),
824 (Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
825 (Value::Date(a), Value::Date(b)) => a.cmp(b),
826 (Value::DateTime(a), Value::DateTime(b)) => a.cmp(b),
827 (Value::Time(a), Value::Time(b)) => a.cmp(b),
828 _ => Ordering::Equal,
829 }
830 }
831
832 fn to_boolean(&self, value: &Value) -> Result<bool> {
834 match value {
835 Value::Boolean(b) => Ok(*b),
836 Value::Integer(i) => Ok(*i != 0),
837 Value::Float(f) => Ok(*f != 0.0),
838 Value::String(s) => Ok(!s.is_empty()),
839 Value::Null => Ok(false),
840 _ => Ok(true),
841 }
842 }
843
844 pub fn execute_insert(&self, stmt: &InsertStatement, table: &Table) -> Result<usize> {
846 let lock = FileLock::new(&table.data_file)?;
848 lock.lock_exclusive()?;
849
850 let file = OpenOptions::new()
852 .append(true)
853 .open(&table.data_file)?;
854
855 let mut writer = BufWriter::new(file);
856 let mut rows_inserted = 0;
857
858 let _column_names = if stmt.columns.is_empty() {
860 table.columns.iter().map(|c| c.name.clone()).collect::<Vec<_>>()
862 } else {
863 stmt.columns.clone()
864 };
865
866 for value_row in &stmt.values {
868 if !stmt.columns.is_empty() && value_row.len() != stmt.columns.len() {
869 return Err(DdbError::ExecutionError(format!(
870 "Column count ({}) doesn't match value count ({})",
871 stmt.columns.len(),
872 value_row.len()
873 )));
874 }
875
876 let mut csv_row = Vec::new();
878 for expr in value_row {
879 let empty_row = Row::new();
881 let value = self.evaluator.evaluate(expr, &empty_row)?;
882 csv_row.push(self.value_to_csv_string(&value));
883 }
884
885 writeln!(writer, "{}", csv_row.join(&table.field_delimiter.to_string()))?;
887
888 rows_inserted += 1;
889 }
890
891 writer.flush()?;
892
893 Ok(rows_inserted)
895 }
896
897 pub fn execute_upsert(&self, stmt: &UpsertStatement, table: &Table) -> Result<(usize, usize)> {
900 let lock = FileLock::new(&table.data_file)?;
902 lock.lock_exclusive()?;
903
904 let file = File::open(&table.data_file)?;
906 let reader = BufReader::new(file);
907 let mut lines: Vec<String> = reader.lines().collect::<std::result::Result<Vec<_>, _>>()?;
908
909 if lines.is_empty() {
910 return Err(DdbError::ExecutionError("Cannot UPSERT into empty file".to_string()));
911 }
912
913 let header = lines[0].clone();
915 let column_names: Vec<String> = header
916 .split(table.field_delimiter)
917 .map(|s| s.trim().to_string())
918 .collect();
919
920 let key_col_idx = column_names
922 .iter()
923 .position(|c| c == &stmt.key_column)
924 .ok_or_else(|| {
925 DdbError::ExecutionError(format!(
926 "Key column '{}' not found in table",
927 stmt.key_column
928 ))
929 })?;
930
931 if stmt.columns.len() != column_names.len() {
933 return Err(DdbError::ExecutionError(format!(
934 "Column count mismatch: UPSERT specifies {} columns, table has {}",
935 stmt.columns.len(),
936 column_names.len()
937 )));
938 }
939
940 let mut rows_inserted = 0;
941 let mut rows_updated = 0;
942
943 for value_row in &stmt.values {
945 if value_row.len() != stmt.columns.len() {
946 return Err(DdbError::ExecutionError(format!(
947 "Value count ({}) doesn't match column count ({})",
948 value_row.len(),
949 stmt.columns.len()
950 )));
951 }
952
953 let empty_row = Row::new();
955 let mut values = Vec::new();
956 for expr in value_row {
957 let value = self.evaluator.evaluate(expr, &empty_row)?;
958 values.push(value);
959 }
960
961 let key_col_pos = stmt
963 .columns
964 .iter()
965 .position(|c| c == &stmt.key_column)
966 .ok_or_else(|| {
967 DdbError::ExecutionError(format!(
968 "Key column '{}' not found in UPSERT columns",
969 stmt.key_column
970 ))
971 })?;
972 let key_value_str = self.value_to_csv_string(&values[key_col_pos]);
973
974 let mut found_row_idx = None;
976 for i in (table.data_starts_on as usize + 1)..lines.len() {
977 let line = &lines[i];
978 if line.trim().is_empty() {
979 continue;
980 }
981
982 let row_values: Vec<String> = line
983 .split(table.field_delimiter)
984 .map(|s| s.trim().to_string())
985 .collect();
986
987 if key_col_idx < row_values.len() && row_values[key_col_idx] == key_value_str {
988 found_row_idx = Some(i);
989 break;
990 }
991 }
992
993 let csv_row: Vec<String> = values.iter().map(|v| self.value_to_csv_string(v)).collect();
995 let csv_line = csv_row.join(&table.field_delimiter.to_string());
996
997 if let Some(idx) = found_row_idx {
998 lines[idx] = csv_line;
1000 rows_updated += 1;
1001 } else {
1002 lines.push(csv_line);
1004 rows_inserted += 1;
1005 }
1006 }
1007
1008 let file = OpenOptions::new()
1010 .write(true)
1011 .truncate(true)
1012 .open(&table.data_file)?;
1013
1014 let mut writer = BufWriter::new(file);
1015 for line in &lines {
1016 writeln!(writer, "{}", line)?;
1017 }
1018 writer.flush()?;
1019
1020 Ok((rows_inserted, rows_updated))
1021 }
1022
1023 pub fn execute_update(&self, stmt: &UpdateStatement, table: &Table) -> Result<usize> {
1025 let lock = FileLock::new(&table.data_file)?;
1027 lock.lock_exclusive()?;
1028
1029 let file = File::open(&table.data_file)?;
1031 let reader = BufReader::new(file);
1032 let mut lines: Vec<String> = reader.lines().collect::<std::result::Result<Vec<_>, _>>()?;
1033
1034 if lines.is_empty() {
1035 return Ok(0);
1036 }
1037
1038 let header = lines[0].clone();
1040 let column_names: Vec<String> = header
1041 .split(table.field_delimiter)
1042 .map(|s| s.trim().to_string())
1043 .collect();
1044
1045 let mut rows_updated = 0;
1046
1047 for i in (table.data_starts_on as usize + 1)..lines.len() {
1049 let line = &lines[i];
1050
1051 if line.trim().is_empty() {
1053 continue;
1054 }
1055
1056 let values: Vec<String> = line
1058 .split(table.field_delimiter)
1059 .map(|s| s.trim().to_string())
1060 .collect();
1061
1062 let mut row = Row::new();
1063 for (idx, col_name) in column_names.iter().enumerate() {
1064 if idx < values.len() {
1065 row.set(col_name, self.parse_value(&values[idx]));
1066 }
1067 }
1068
1069 let matches = if let Some(where_expr) = &stmt.where_clause {
1071 let result = self.evaluator.evaluate(where_expr, &row)?;
1072 self.to_boolean(&result)?
1073 } else {
1074 true };
1076
1077 if matches {
1078 for (column, value_expr) in &stmt.assignments {
1080 let new_value = self.evaluator.evaluate(value_expr, &row)?;
1081 row.set(column, new_value);
1082 }
1083
1084 let mut csv_values = Vec::new();
1086 for col_name in &column_names {
1087 if let Some(value) = row.get(col_name) {
1088 csv_values.push(self.value_to_csv_string(value));
1089 } else {
1090 csv_values.push(String::new());
1091 }
1092 }
1093
1094 lines[i] = csv_values.join(&table.field_delimiter.to_string());
1095 rows_updated += 1;
1096 }
1097 }
1098
1099 let file = OpenOptions::new()
1101 .write(true)
1102 .truncate(true)
1103 .open(&table.data_file)?;
1104
1105 let mut writer = BufWriter::new(file);
1106 for line in &lines {
1107 writeln!(writer, "{}", line)?;
1108 }
1109 writer.flush()?;
1110
1111 Ok(rows_updated)
1112 }
1113
1114 pub fn execute_delete(&self, stmt: &DeleteStatement, table: &Table) -> Result<usize> {
1116 let lock = FileLock::new(&table.data_file)?;
1118 lock.lock_exclusive()?;
1119
1120 let file = File::open(&table.data_file)?;
1122 let reader = BufReader::new(file);
1123 let lines: Vec<String> = reader.lines().collect::<std::result::Result<Vec<_>, _>>()?;
1124
1125 if lines.is_empty() {
1126 return Ok(0);
1127 }
1128
1129 let header = lines[0].clone();
1131 let column_names: Vec<String> = header
1132 .split(table.field_delimiter)
1133 .map(|s| s.trim().to_string())
1134 .collect();
1135
1136 let mut kept_lines = vec![header]; let mut rows_deleted = 0;
1138
1139 for i in (table.data_starts_on as usize + 1)..lines.len() {
1141 let line = &lines[i];
1142
1143 if line.trim().is_empty() {
1145 continue;
1146 }
1147
1148 let values: Vec<String> = line
1150 .split(table.field_delimiter)
1151 .map(|s| s.trim().to_string())
1152 .collect();
1153
1154 let mut row = Row::new();
1155 for (idx, col_name) in column_names.iter().enumerate() {
1156 if idx < values.len() {
1157 row.set(col_name, self.parse_value(&values[idx]));
1158 }
1159 }
1160
1161 let should_delete = if let Some(where_expr) = &stmt.where_clause {
1163 let result = self.evaluator.evaluate(where_expr, &row)?;
1164 self.to_boolean(&result)?
1165 } else {
1166 true };
1168
1169 if should_delete {
1170 rows_deleted += 1;
1171 } else {
1172 kept_lines.push(line.clone());
1173 }
1174 }
1175
1176 let file = OpenOptions::new()
1178 .write(true)
1179 .truncate(true)
1180 .open(&table.data_file)?;
1181
1182 let mut writer = BufWriter::new(file);
1183 for line in &kept_lines {
1184 writeln!(writer, "{}", line)?;
1185 }
1186 writer.flush()?;
1187
1188 Ok(rows_deleted)
1189 }
1190
1191 fn value_to_csv_string(&self, value: &Value) -> String {
1193 match value {
1194 Value::String(s) => {
1195 if s.contains(',') || s.contains('"') || s.contains('\n') {
1197 format!("\"{}\"", s.replace('"', "\"\""))
1198 } else {
1199 s.clone()
1200 }
1201 }
1202 Value::Integer(i) => i.to_string(),
1203 Value::Float(f) => f.to_string(),
1204 Value::Boolean(b) => b.to_string(),
1205 Value::Null => String::new(),
1206 Value::Date(d) => d.format("%Y-%m-%d").to_string(),
1207 Value::DateTime(dt) => dt.format("%Y-%m-%d %H:%M:%S").to_string(),
1208 Value::Time(t) => t.format("%H:%M:%S").to_string(),
1209 }
1210 }
1211
1212 fn parse_value(&self, s: &str) -> Value {
1214 if s.is_empty() {
1215 return Value::Null;
1216 }
1217
1218 if let Ok(i) = s.parse::<i64>() {
1220 return Value::Integer(i);
1221 }
1222
1223 if let Ok(f) = s.parse::<f64>() {
1225 return Value::Float(f);
1226 }
1227
1228 match s.to_lowercase().as_str() {
1230 "true" | "t" | "yes" | "y" | "1" => return Value::Boolean(true),
1231 "false" | "f" | "no" | "n" | "0" => return Value::Boolean(false),
1232 _ => {}
1233 }
1234
1235 Value::String(s.to_string())
1237 }
1238}
1239
1240impl Default for QueryExecutor {
1241 fn default() -> Self {
1242 Self::new()
1243 }
1244}
1245
1246#[cfg(test)]
1247mod tests {
1248 use super::*;
1249 use crate::parser::{BinaryOperator, Expression, Literal};
1250 use std::io::Write;
1251 use tempfile::NamedTempFile;
1252
1253 fn create_test_table() -> (Table, NamedTempFile) {
1254 let mut file = NamedTempFile::new().unwrap();
1255 writeln!(file, "id,name,age").unwrap();
1256 writeln!(file, "1,Alice,30").unwrap();
1257 writeln!(file, "2,Bob,25").unwrap();
1258 writeln!(file, "3,Charlie,35").unwrap();
1259 file.flush().unwrap();
1260
1261 let table = Table {
1262 name: "users".to_string(),
1263 database: "test".to_string(),
1264 data_file: file.path().to_string_lossy().to_string(),
1265 columns: vec![],
1266 field_delimiter: ',',
1267 data_starts_on: 0,
1268 comment_char: None,
1269 };
1270
1271 (table, file)
1272 }
1273
1274 #[test]
1275 fn test_execute_select_all() {
1276 let (table, _file) = create_test_table();
1277 let executor = QueryExecutor::new();
1278
1279 let stmt = SelectStatement {
1280 distinct: false,
1281 columns: vec![SelectColumn::Wildcard],
1282 from: Some("users".to_string()),
1283 joins: vec![],
1284 where_clause: None,
1285 group_by: vec![],
1286 having: None,
1287 order_by: vec![],
1288 limit: None,
1289 };
1290
1291 let results = executor.execute_select(&stmt, &table).unwrap();
1292 assert_eq!(results.len(), 3);
1293 }
1294
1295 #[test]
1296 fn test_execute_select_with_where() {
1297 let (table, _file) = create_test_table();
1298 let executor = QueryExecutor::new();
1299
1300 let where_expr = Expression::BinaryOp {
1302 left: Box::new(Expression::Column("age".to_string())),
1303 op: BinaryOperator::GreaterThan,
1304 right: Box::new(Expression::Literal(Literal::Integer(25))),
1305 };
1306
1307 let stmt = SelectStatement {
1308 distinct: false,
1309 columns: vec![SelectColumn::Wildcard],
1310 from: Some("users".to_string()),
1311 joins: vec![],
1312 where_clause: Some(where_expr),
1313 group_by: vec![],
1314 having: None,
1315 order_by: vec![],
1316 limit: None,
1317 };
1318
1319 let results = executor.execute_select(&stmt, &table).unwrap();
1320 assert_eq!(results.len(), 2); }
1322
1323 #[test]
1324 fn test_execute_select_with_columns() {
1325 let (table, _file) = create_test_table();
1326 let executor = QueryExecutor::new();
1327
1328 let stmt = SelectStatement {
1329 distinct: false,
1330 columns: vec![
1331 SelectColumn::Column {
1332 name: "name".to_string(),
1333 alias: None,
1334 },
1335 SelectColumn::Column {
1336 name: "age".to_string(),
1337 alias: None,
1338 },
1339 ],
1340 from: Some("users".to_string()),
1341 joins: vec![],
1342 where_clause: None,
1343 group_by: vec![],
1344 having: None,
1345 order_by: vec![],
1346 limit: None,
1347 };
1348
1349 let results = executor.execute_select(&stmt, &table).unwrap();
1350 assert_eq!(results.len(), 3);
1351
1352 let row = &results[0];
1354 assert!(row.get("name").is_some());
1355 assert!(row.get("age").is_some());
1356 assert!(row.get("id").is_none());
1358 }
1359
1360 #[test]
1361 fn test_execute_select_with_limit() {
1362 let (table, _file) = create_test_table();
1363 let executor = QueryExecutor::new();
1364
1365 let stmt = SelectStatement {
1366 distinct: false,
1367 columns: vec![SelectColumn::Wildcard],
1368 from: Some("users".to_string()),
1369 joins: vec![],
1370 where_clause: None,
1371 group_by: vec![],
1372 having: None,
1373 order_by: vec![],
1374 limit: Some(crate::parser::Limit {
1375 offset: None,
1376 count: 2,
1377 }),
1378 };
1379
1380 let results = executor.execute_select(&stmt, &table).unwrap();
1381 assert_eq!(results.len(), 2);
1382 }
1383
1384 #[test]
1385 fn test_execute_select_with_order_by() {
1386 let (table, _file) = create_test_table();
1387 let executor = QueryExecutor::new();
1388
1389 let stmt = SelectStatement {
1390 distinct: false,
1391 columns: vec![SelectColumn::Wildcard],
1392 from: Some("users".to_string()),
1393 joins: vec![],
1394 where_clause: None,
1395 group_by: vec![],
1396 having: None,
1397 order_by: vec![crate::parser::OrderByColumn {
1398 column: "age".to_string(),
1399 direction: OrderDirection::Desc,
1400 }],
1401 limit: None,
1402 };
1403
1404 let results = executor.execute_select(&stmt, &table).unwrap();
1405 assert_eq!(results.len(), 3);
1406
1407 assert_eq!(
1409 results[0].get("name"),
1410 Some(&Value::String("Charlie".to_string()))
1411 );
1412 assert_eq!(
1413 results[2].get("name"),
1414 Some(&Value::String("Bob".to_string()))
1415 );
1416 }
1417
1418 #[test]
1419 fn test_indexed_join() {
1420 use crate::file_io::CsvReader;
1421
1422 let mut users_file = NamedTempFile::new().unwrap();
1424 writeln!(users_file, "id,name").unwrap();
1425 writeln!(users_file, "1,Alice").unwrap();
1426 writeln!(users_file, "2,Bob").unwrap();
1427 writeln!(users_file, "3,Charlie").unwrap();
1428 users_file.flush().unwrap();
1429
1430 let users_table = Table {
1431 name: "users".to_string(),
1432 database: "test".to_string(),
1433 data_file: users_file.path().to_string_lossy().to_string(),
1434 columns: vec![],
1435 field_delimiter: ',',
1436 data_starts_on: 0,
1437 comment_char: None,
1438 };
1439
1440 let mut orders_file = NamedTempFile::new().unwrap();
1442 writeln!(orders_file, "order_id,user_id,amount").unwrap();
1443 writeln!(orders_file, "101,1,50").unwrap();
1444 writeln!(orders_file, "102,2,75").unwrap();
1445 writeln!(orders_file, "103,1,100").unwrap();
1446 orders_file.flush().unwrap();
1447
1448 let mut users_reader = CsvReader::new(&users_table.data_file, ',', true).unwrap();
1450 let mut left_rows = Vec::new();
1451 while let Some(row) = users_reader.next_row().unwrap() {
1452 left_rows.push(row);
1453 }
1454
1455 let orders_path = orders_file.path().to_string_lossy().to_string();
1457 let mut orders_reader = CsvReader::new(&orders_path, ',', true).unwrap();
1458 let mut right_rows = Vec::new();
1459 while let Some(row) = orders_reader.next_row().unwrap() {
1460 right_rows.push(row);
1461 }
1462
1463 let join_condition = Expression::BinaryOp {
1465 left: Box::new(Expression::Column("id".to_string())),
1466 op: BinaryOperator::Equal,
1467 right: Box::new(Expression::Column("user_id".to_string())),
1468 };
1469
1470 let join_clause = JoinClause {
1471 join_type: JoinType::Inner,
1472 table: "orders".to_string(),
1473 on_condition: join_condition,
1474 };
1475
1476 let executor = QueryExecutor::new();
1478 let results = executor
1479 .perform_join_indexed(left_rows, right_rows, &join_clause)
1480 .unwrap();
1481
1482 assert_eq!(results.len(), 3);
1484
1485 let alice_orders: Vec<_> = results
1487 .iter()
1488 .filter(|r| r.get("name") == Some(&Value::String("Alice".to_string())))
1489 .collect();
1490 assert_eq!(alice_orders.len(), 2);
1491
1492 let bob_orders: Vec<_> = results
1493 .iter()
1494 .filter(|r| r.get("name") == Some(&Value::String("Bob".to_string())))
1495 .collect();
1496 assert_eq!(bob_orders.len(), 1);
1497
1498 let charlie_orders: Vec<_> = results
1500 .iter()
1501 .filter(|r| r.get("name") == Some(&Value::String("Charlie".to_string())))
1502 .collect();
1503 assert_eq!(charlie_orders.len(), 0);
1504 }
1505}