1use crate::{SqlRsError, Result, Value};
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum AggregateFunction {
5 Count,
6 Sum,
7 Avg,
8 Min,
9 Max,
10}
11
12#[derive(Debug, Clone)]
13pub enum SelectColumn {
14 Star,
15 Column(String),
16 Aggregate {
17 function: AggregateFunction,
18 column: String,
19 },
20}
21
22#[derive(Debug, Clone)]
23pub enum Statement {
24 CreateTable {
25 name: String,
26 columns: Vec<(String, String)>,
27 },
28 Insert {
29 table: String,
30 columns: Vec<String>,
31 values: Vec<Value>,
32 },
33 Select {
34 table: String,
35 columns: Vec<SelectColumn>,
36 joins: Vec<Join>,
37 where_clause: Option<WhereClause>,
38 group_by: Option<Vec<String>>,
39 order_by: Option<OrderBy>,
40 limit: Option<usize>,
41 offset: Option<usize>,
42 },
43 Update {
44 table: String,
45 sets: Vec<(String, Value)>,
46 where_clause: Option<WhereClause>,
47 },
48 Delete {
49 table: String,
50 where_clause: Option<WhereClause>,
51 },
52 DropTable {
53 name: String,
54 },
55 CreateIndex {
56 index_name: String,
57 table: String,
58 column: String,
59 },
60 DropIndex {
61 index_name: String,
62 },
63}
64
65#[derive(Debug, Clone)]
66pub enum WhereExpression {
67 Condition {
68 column: String,
69 operator: String,
70 value: Value,
71 },
72 And {
73 left: Box<WhereExpression>,
74 right: Box<WhereExpression>,
75 },
76 Or {
77 left: Box<WhereExpression>,
78 right: Box<WhereExpression>,
79 },
80}
81
82pub type WhereClause = WhereExpression;
84
85#[derive(Debug, Clone)]
86pub struct OrderBy {
87 pub column: String,
88 pub ascending: bool,
89}
90
91#[derive(Debug, Clone, PartialEq)]
92pub enum JoinType {
93 Inner,
94 Left,
95 Right,
96}
97
98#[derive(Debug, Clone)]
99pub struct Join {
100 pub join_type: JoinType,
101 pub table: String,
102 pub on_left: String,
103 pub on_right: String,
104}
105
106pub fn parse_sql(sql: &str) -> Result<Statement> {
107 let sql = sql.trim();
108 let upper = sql.to_uppercase();
109
110 let words: Vec<&str> = upper.split_whitespace().collect();
112
113 if words.len() >= 2 && words[0] == "CREATE" && words[1] == "TABLE" {
114 parse_create_table(sql)
115 } else if words.len() >= 2 && words[0] == "CREATE" && words[1] == "INDEX" {
116 parse_create_index(sql)
117 } else if words.len() >= 2 && words[0] == "INSERT" && words[1] == "INTO" {
118 parse_insert(sql)
119 } else if words.len() >= 1 && words[0] == "SELECT" {
120 parse_select(sql)
121 } else if words.len() >= 1 && words[0] == "UPDATE" {
122 parse_update(sql)
123 } else if words.len() >= 2 && words[0] == "DELETE" && words[1] == "FROM" {
124 parse_delete(sql)
125 } else if words.len() >= 2 && words[0] == "DROP" && words[1] == "TABLE" {
126 parse_drop_table(sql)
127 } else if words.len() >= 2 && words[0] == "DROP" && words[1] == "INDEX" {
128 parse_drop_index(sql)
129 } else {
130 Err(SqlRsError::Query(format!(
131 "Unsupported SQL statement: {}",
132 sql
133 )))
134 }
135}
136
137fn parse_create_table(sql: &str) -> Result<Statement> {
138 let parts: Vec<&str> = sql.split_whitespace().collect();
139
140 if parts.len() < 4 {
141 return Err(SqlRsError::Query(
142 "Invalid CREATE TABLE syntax".to_string(),
143 ));
144 }
145
146 let name = parts[2].to_string();
147
148 let columns_start = sql
149 .find('(')
150 .ok_or_else(|| SqlRsError::Query("Missing column definitions".to_string()))?;
151 let columns_end = sql
152 .rfind(')')
153 .ok_or_else(|| SqlRsError::Query("Missing closing parenthesis".to_string()))?;
154
155 let columns_str = &sql[columns_start + 1..columns_end];
156 let column_defs: Vec<&str> = columns_str.split(',').map(|s| s.trim()).collect();
157
158 let mut columns = Vec::new();
159 for def in column_defs {
160 let parts: Vec<&str> = def.split_whitespace().collect();
161 if parts.len() >= 2 {
162 columns.push((parts[0].to_string(), parts[1].to_uppercase()));
163 }
164 }
165
166 if columns.is_empty() {
167 return Err(SqlRsError::Query("No valid column definitions found".to_string()));
168 }
169
170 Ok(Statement::CreateTable { name, columns })
171}
172
173fn parse_insert(sql: &str) -> Result<Statement> {
174 let upper = sql.to_uppercase();
175
176 let table_start = upper
177 .find("INTO")
178 .ok_or_else(|| SqlRsError::Query("Missing INTO".to_string()))?
179 + 4;
180 let values_start = upper
181 .find("VALUES")
182 .ok_or_else(|| SqlRsError::Query("Missing VALUES".to_string()))?;
183
184 let table_part = sql[table_start..values_start].trim();
185
186 let (table, columns) = if let Some(paren_start) = table_part.find('(') {
187 let table = table_part[..paren_start].trim().to_string();
188 let paren_end = table_part
189 .rfind(')')
190 .ok_or_else(|| SqlRsError::Query("Missing closing parenthesis".to_string()))?;
191 let cols_str = &table_part[paren_start + 1..paren_end];
192 let columns: Vec<String> = cols_str.split(',').map(|s| s.trim().to_string()).collect();
193 (table, columns)
194 } else {
195 (table_part.to_string(), Vec::new())
196 };
197
198 let values_part = &sql[values_start + 6..].trim();
199 let values_start = values_part
200 .find('(')
201 .ok_or_else(|| SqlRsError::Query("Missing values parenthesis".to_string()))?;
202 let values_end = values_part
203 .rfind(')')
204 .ok_or_else(|| SqlRsError::Query("Missing closing parenthesis".to_string()))?;
205
206 let values_str = &values_part[values_start + 1..values_end];
207 let value_strs: Vec<&str> = values_str.split(',').map(|s| s.trim()).collect();
208
209 let mut values = Vec::new();
210 for val_str in value_strs {
211 values.push(parse_value(val_str)?);
212 }
213
214 Ok(Statement::Insert {
215 table,
216 columns,
217 values,
218 })
219}
220
221fn parse_select(sql: &str) -> Result<Statement> {
222 let upper = sql.to_uppercase();
223
224 let from_pos = upper
225 .find("FROM")
226 .ok_or_else(|| SqlRsError::Query("Missing FROM".to_string()))?;
227
228 let cols_str = sql[6..from_pos].trim();
229 let columns = parse_select_columns(cols_str)?;
230
231 let after_from = &sql[from_pos + 4..];
232 let upper_after_from = after_from.to_uppercase();
233
234 let inner_join_pos = upper_after_from.find("INNER JOIN");
236 let left_join_pos = upper_after_from.find("LEFT JOIN");
237 let right_join_pos = upper_after_from.find("RIGHT JOIN");
238 let join_pos = upper_after_from.find("JOIN");
239 let where_pos = upper_after_from.find("WHERE");
240 let group_pos = upper_after_from.find("GROUP BY");
241 let order_pos = upper_after_from.find("ORDER BY");
242 let limit_pos = upper_after_from.find("LIMIT");
243 let offset_pos = upper_after_from.find("OFFSET");
244
245 let first_join_pos = [inner_join_pos, left_join_pos, right_join_pos, join_pos]
247 .iter()
248 .filter_map(|&p| p)
249 .min();
250
251 let table_end = [first_join_pos, where_pos, group_pos, order_pos, limit_pos, offset_pos]
253 .iter()
254 .filter_map(|&p| p)
255 .min()
256 .unwrap_or(after_from.len());
257
258 let table = after_from[..table_end].trim().to_string();
259
260 let joins = if first_join_pos.is_some() {
262 parse_joins(after_from, first_join_pos.unwrap())?
263 } else {
264 Vec::new()
265 };
266
267 let where_clause = if let Some(pos) = where_pos {
269 let where_end = [group_pos, order_pos, limit_pos, offset_pos]
270 .iter()
271 .filter_map(|&p| p)
272 .filter(|&p| p > pos)
273 .min()
274 .unwrap_or(after_from.len());
275 let where_str = after_from[pos + 5..where_end].trim();
276 Some(parse_where(where_str)?)
277 } else {
278 None
279 };
280
281 let group_by = if let Some(pos) = group_pos {
283 let group_end = [order_pos, limit_pos, offset_pos]
284 .iter()
285 .filter_map(|&p| p)
286 .filter(|&p| p > pos)
287 .min()
288 .unwrap_or(after_from.len());
289 let group_str = after_from[pos + 8..group_end].trim();
290 let columns: Vec<String> = group_str.split(',').map(|s| s.trim().to_string()).collect();
291 Some(columns)
292 } else {
293 None
294 };
295
296 let order_by = if let Some(pos) = order_pos {
298 let order_end = [limit_pos, offset_pos]
299 .iter()
300 .filter_map(|&p| p)
301 .filter(|&p| p > pos)
302 .min()
303 .unwrap_or(after_from.len());
304 let order_str = after_from[pos + 8..order_end].trim();
305 Some(parse_order_by(order_str)?)
306 } else {
307 None
308 };
309
310 let limit = if let Some(pos) = limit_pos {
312 let limit_end = offset_pos
313 .filter(|&p| p > pos)
314 .unwrap_or(after_from.len());
315 let limit_str = after_from[pos + 5..limit_end].trim();
316 Some(limit_str.parse::<usize>().map_err(|_| {
317 SqlRsError::Query("Invalid LIMIT value".to_string())
318 })?)
319 } else {
320 None
321 };
322
323 let offset = if let Some(pos) = offset_pos {
325 let offset_str = after_from[pos + 6..].trim();
326 Some(offset_str.parse::<usize>().map_err(|_| {
327 SqlRsError::Query("Invalid OFFSET value".to_string())
328 })?)
329 } else {
330 None
331 };
332
333 Ok(Statement::Select {
334 table,
335 columns,
336 joins,
337 where_clause,
338 group_by,
339 order_by,
340 limit,
341 offset,
342 })
343}
344
345fn parse_joins(after_from: &str, start_pos: usize) -> Result<Vec<Join>> {
346 let upper = after_from.to_uppercase();
347 let mut joins = Vec::new();
348 let mut current_pos = start_pos;
349
350 let where_pos = upper.find("WHERE");
352 let group_pos = upper.find("GROUP BY");
353 let order_pos = upper.find("ORDER BY");
354 let limit_pos = upper.find("LIMIT");
355 let offset_pos = upper.find("OFFSET");
356
357 let joins_end = [where_pos, group_pos, order_pos, limit_pos, offset_pos]
358 .iter()
359 .filter_map(|&p| p)
360 .min()
361 .unwrap_or(after_from.len());
362
363 while current_pos < joins_end {
364 let remaining = &after_from[current_pos..joins_end];
365 let remaining_upper = remaining.to_uppercase();
366
367 let (join_type, keyword_len) = if remaining_upper.starts_with("INNER JOIN") {
369 (JoinType::Inner, 10)
370 } else if remaining_upper.starts_with("LEFT JOIN") {
371 (JoinType::Left, 9)
372 } else if remaining_upper.starts_with("RIGHT JOIN") {
373 (JoinType::Right, 10)
374 } else if remaining_upper.starts_with("JOIN") {
375 (JoinType::Inner, 4) } else {
377 break;
378 };
379
380 let after_join = &remaining[keyword_len..].trim_start();
382 let after_join_upper = after_join.to_uppercase();
383
384 let on_pos = after_join_upper.find(" ON ")
386 .ok_or_else(|| SqlRsError::Query("Missing ON clause in JOIN".to_string()))?;
387
388 let table_name = after_join[..on_pos].trim().to_string();
389
390 let after_on = &after_join[on_pos + 4..];
392
393 let next_inner_join = after_on.to_uppercase().find("INNER JOIN");
395 let next_left_join = after_on.to_uppercase().find("LEFT JOIN");
396 let next_right_join = after_on.to_uppercase().find("RIGHT JOIN");
397 let next_join = after_on.to_uppercase().find(" JOIN");
398
399 let on_end = [next_inner_join, next_left_join, next_right_join, next_join]
400 .iter()
401 .filter_map(|&p| p)
402 .min()
403 .unwrap_or(after_on.len());
404
405 let on_clause = after_on[..on_end].trim();
406
407 let parts: Vec<&str> = on_clause.split('=').map(|s| s.trim()).collect();
409 if parts.len() != 2 {
410 return Err(SqlRsError::Query("Invalid ON clause format".to_string()));
411 }
412
413 let on_left = parts[0].to_string();
414 let on_right = parts[1].to_string();
415
416 joins.push(Join {
417 join_type,
418 table: table_name,
419 on_left,
420 on_right,
421 });
422
423 let consumed = keyword_len + on_pos + 4 + on_end;
426 current_pos = current_pos + consumed;
427
428 while current_pos < joins_end && after_from.as_bytes().get(current_pos).map_or(false, |&b| b.is_ascii_whitespace()) {
430 current_pos += 1;
431 }
432 }
433
434 Ok(joins)
435}
436
437fn parse_select_columns(cols_str: &str) -> Result<Vec<SelectColumn>> {
438 let cols_str = cols_str.trim();
439
440 if cols_str.is_empty() {
441 return Err(SqlRsError::Query("Empty column list in SELECT".to_string()));
442 }
443
444 if cols_str == "*" {
445 return Ok(vec![SelectColumn::Star]);
446 }
447
448 let mut columns = Vec::new();
449 for col_str in cols_str.split(',') {
450 let col_str = col_str.trim();
451 let col_upper = col_str.to_uppercase();
452
453 if col_upper.starts_with("COUNT(") {
455 let inner = &col_str[6..col_str.len().saturating_sub(1)].trim();
456 columns.push(SelectColumn::Aggregate {
457 function: AggregateFunction::Count,
458 column: inner.to_string(),
459 });
460 } else if col_upper.starts_with("SUM(") {
461 let inner = &col_str[4..col_str.len().saturating_sub(1)].trim();
462 columns.push(SelectColumn::Aggregate {
463 function: AggregateFunction::Sum,
464 column: inner.to_string(),
465 });
466 } else if col_upper.starts_with("AVG(") {
467 let inner = &col_str[4..col_str.len().saturating_sub(1)].trim();
468 columns.push(SelectColumn::Aggregate {
469 function: AggregateFunction::Avg,
470 column: inner.to_string(),
471 });
472 } else if col_upper.starts_with("MIN(") {
473 let inner = &col_str[4..col_str.len().saturating_sub(1)].trim();
474 columns.push(SelectColumn::Aggregate {
475 function: AggregateFunction::Min,
476 column: inner.to_string(),
477 });
478 } else if col_upper.starts_with("MAX(") {
479 let inner = &col_str[4..col_str.len().saturating_sub(1)].trim();
480 columns.push(SelectColumn::Aggregate {
481 function: AggregateFunction::Max,
482 column: inner.to_string(),
483 });
484 } else {
485 columns.push(SelectColumn::Column(col_str.to_string()));
487 }
488 }
489
490 Ok(columns)
491}
492
493fn parse_update(sql: &str) -> Result<Statement> {
494 let upper = sql.to_uppercase();
495
496 let update_pos = 0;
498 let set_pos = upper
499 .find("SET")
500 .ok_or_else(|| SqlRsError::Query("Missing SET in UPDATE".to_string()))?;
501
502 let table = sql[update_pos + 6..set_pos].trim().to_string();
503
504 let after_set = &sql[set_pos + 3..].trim();
506
507 let (set_where_str, where_clause) =
508 if let Some(where_pos) = after_set.to_uppercase().find("WHERE") {
509 let set_str = &after_set[..where_pos];
510 let where_str = &after_set[where_pos + 5..];
511 (set_str.to_string(), Some(parse_where(where_str.trim())?))
512 } else {
513 (after_set.to_string(), None)
514 };
515
516 let mut sets = Vec::new();
518 for set_clause in set_where_str.split(',') {
519 let set_clause = set_clause.trim();
520 if let Some(eq_pos) = set_clause.find('=') {
521 let column = set_clause[..eq_pos].trim().to_string();
522 let value_str = set_clause[eq_pos + 1..].trim();
523 let value = parse_value(value_str)?;
524 sets.push((column, value));
525 } else {
526 return Err(SqlRsError::Query(format!(
527 "Invalid SET clause: {}",
528 set_clause
529 )));
530 }
531 }
532
533 if sets.is_empty() {
534 return Err(SqlRsError::Query("No SET clauses provided".to_string()));
535 }
536
537 Ok(Statement::Update {
538 table,
539 sets,
540 where_clause,
541 })
542}
543
544fn parse_where(where_str: &str) -> Result<WhereExpression> {
545 parse_or_expression(where_str)
547}
548
549fn parse_or_expression(where_str: &str) -> Result<WhereExpression> {
550 let upper = where_str.to_uppercase();
551
552 let or_positions = find_logical_operator_positions(&upper, "OR");
554
555 if !or_positions.is_empty() {
557 let or_pos = or_positions[0];
559 let left_str = &where_str[..or_pos];
560 let right_str = &where_str[or_pos + 3..]; return Ok(WhereExpression::Or {
563 left: Box::new(parse_and_expression(left_str.trim())?),
564 right: Box::new(parse_or_expression(right_str.trim())?),
565 });
566 }
567
568 parse_and_expression(where_str)
570}
571
572fn parse_and_expression(where_str: &str) -> Result<WhereExpression> {
573 let upper = where_str.to_uppercase();
574
575 let and_positions = find_logical_operator_positions(&upper, "AND");
577
578 if !and_positions.is_empty() {
580 let and_pos = and_positions[0];
582 let left_str = &where_str[..and_pos];
583 let right_str = &where_str[and_pos + 4..]; return Ok(WhereExpression::And {
586 left: Box::new(parse_and_expression(left_str.trim())?),
587 right: Box::new(parse_and_expression(right_str.trim())?),
588 });
589 }
590
591 parse_condition(where_str)
593}
594
595fn find_logical_operator_positions(upper: &str, operator: &str) -> Vec<usize> {
596 let mut positions = Vec::new();
597 let mut depth = 0;
598 let bytes = upper.as_bytes();
599 let op_bytes = operator.as_bytes();
600 let op_len = op_bytes.len();
601
602 for i in 0..bytes.len() {
603 match bytes[i] {
604 b'(' => depth += 1,
605 b')' => depth -= 1,
606 _ if depth == 0 => {
607 if i + op_len <= bytes.len() && &bytes[i..i + op_len] == op_bytes {
609 let before_ok = i == 0 || bytes[i - 1].is_ascii_whitespace();
611 let after_ok = i + op_len >= bytes.len() || bytes[i + op_len].is_ascii_whitespace();
612
613 if before_ok && after_ok {
614 positions.push(i);
615 }
616 }
617 }
618 _ => {}
619 }
620 }
621
622 positions
623}
624
625fn parse_condition(where_str: &str) -> Result<WhereExpression> {
626 let trimmed = where_str.trim();
627
628 if trimmed.starts_with('(') {
630 let mut depth = 0;
632 let mut close_pos = 0;
633 let mut chars = trimmed.chars().enumerate();
634
635 while let Some((pos, c)) = chars.next() {
636 match c {
637 '(' => depth += 1,
638 ')' => {
639 depth -= 1;
640 if depth == 0 {
641 close_pos = pos;
642 break;
643 }
644 }
645 _ => {}
646 }
647 }
648
649 if close_pos > 0 {
650 let inner = &trimmed[1..close_pos];
651 let remaining = &trimmed[close_pos + 1..].trim();
652
653 if remaining.is_empty() {
655 return parse_or_expression(inner);
656 } else {
657 let left_expr = parse_or_expression(inner)?;
660
661 let remaining_upper = remaining.to_uppercase();
663 if remaining_upper.starts_with("AND ") {
664 let right_str = remaining[4..].trim();
665 let right_expr = parse_or_expression(right_str)?;
666 return Ok(WhereExpression::And {
667 left: Box::new(left_expr),
668 right: Box::new(right_expr),
669 });
670 } else if remaining_upper.starts_with("OR ") {
671 let right_str = remaining[3..].trim();
672 let right_expr = parse_or_expression(right_str)?;
673 return Ok(WhereExpression::Or {
674 left: Box::new(left_expr),
675 right: Box::new(right_expr),
676 });
677 }
678 }
679 }
680 }
681
682 let operators = [">=", "<=", "!=", "=", ">", "<"];
684
685 for op in &operators {
686 if let Some(pos) = trimmed.find(op) {
687 let column = trimmed[..pos].trim().to_string();
688 let value_str = trimmed[pos + op.len()..].trim();
689 let value = parse_value(value_str)?;
690
691 return Ok(WhereExpression::Condition {
692 column,
693 operator: op.to_string(),
694 value,
695 });
696 }
697 }
698
699 Err(SqlRsError::Query("Invalid WHERE clause".to_string()))
700}
701
702fn parse_delete(sql: &str) -> Result<Statement> {
703 let upper = sql.to_uppercase();
704
705 let from_pos = upper
706 .find("FROM")
707 .ok_or_else(|| SqlRsError::Query("Missing FROM in DELETE".to_string()))?;
708
709 let after_from = &sql[from_pos + 4..].trim();
710
711 let (table, where_clause) = if let Some(where_pos) = after_from.to_uppercase().find("WHERE") {
712 let table = after_from[..where_pos].trim().to_string();
713 let where_str = after_from[where_pos + 5..].trim();
714 (table, Some(parse_where(where_str)?))
715 } else {
716 (after_from.to_string(), None)
717 };
718
719 if table.is_empty() {
720 return Err(SqlRsError::Query("Missing table name in DELETE".to_string()));
721 }
722
723 Ok(Statement::Delete {
724 table,
725 where_clause,
726 })
727}
728
729fn parse_drop_table(sql: &str) -> Result<Statement> {
730 let parts: Vec<&str> = sql.split_whitespace().collect();
731
732 if parts.len() < 3 {
733 return Err(SqlRsError::Query(
734 "Invalid DROP TABLE syntax".to_string(),
735 ));
736 }
737
738 let name = parts[2].to_string();
739
740 Ok(Statement::DropTable { name })
741}
742
743fn parse_order_by(order_str: &str) -> Result<OrderBy> {
744 let upper = order_str.to_uppercase();
745 let ascending = !upper.ends_with("DESC");
746
747 let column = if upper.ends_with("ASC") {
748 order_str[..order_str.len() - 3].trim().to_string()
749 } else if upper.ends_with("DESC") {
750 order_str[..order_str.len() - 4].trim().to_string()
751 } else {
752 order_str.trim().to_string()
753 };
754
755 Ok(OrderBy { column, ascending })
756}
757
758fn parse_value(s: &str) -> Result<Value> {
759 let s = s.trim();
760
761 if s.eq_ignore_ascii_case("NULL") {
762 return Ok(Value::Null);
763 }
764
765 if s.eq_ignore_ascii_case("TRUE") {
766 return Ok(Value::Boolean(true));
767 }
768
769 if s.eq_ignore_ascii_case("FALSE") {
770 return Ok(Value::Boolean(false));
771 }
772
773 if (s.starts_with('\'') && s.ends_with('\'')) || (s.starts_with('"') && s.ends_with('"')) {
774 return Ok(Value::Text(s[1..s.len() - 1].to_string()));
775 }
776
777 if let Ok(i) = s.parse::<i64>() {
778 return Ok(Value::Integer(i));
779 }
780
781 if let Ok(f) = s.parse::<f64>() {
782 return Ok(Value::Float(f));
783 }
784
785 Ok(Value::Text(s.to_string()))
786}
787
788fn parse_create_index(sql: &str) -> Result<Statement> {
789 let upper = sql.to_uppercase();
791
792 let on_pos = upper
793 .find(" ON ")
794 .ok_or_else(|| SqlRsError::Query("Missing ON in CREATE INDEX".to_string()))?;
795
796 let index_part = &sql[12..on_pos].trim(); let index_name = index_part.to_string();
798
799 if index_name.is_empty() {
800 return Err(SqlRsError::Query("Missing index name in CREATE INDEX".to_string()));
801 }
802
803 let after_on = &sql[on_pos + 4..].trim();
804
805 let paren_start = after_on
807 .find('(')
808 .ok_or_else(|| SqlRsError::Query("Missing column specification in CREATE INDEX".to_string()))?;
809
810 let table = after_on[..paren_start].trim().to_string();
811
812 if table.is_empty() {
813 return Err(SqlRsError::Query("Missing table name in CREATE INDEX".to_string()));
814 }
815
816 let paren_end = after_on
817 .rfind(')')
818 .ok_or_else(|| SqlRsError::Query("Missing closing parenthesis in CREATE INDEX".to_string()))?;
819
820 let column = after_on[paren_start + 1..paren_end].trim().to_string();
821
822 if column.is_empty() {
823 return Err(SqlRsError::Query("Missing column name in CREATE INDEX".to_string()));
824 }
825
826 Ok(Statement::CreateIndex {
827 index_name,
828 table,
829 column,
830 })
831}
832
833fn parse_drop_index(sql: &str) -> Result<Statement> {
834 let parts: Vec<&str> = sql.split_whitespace().collect();
836
837 if parts.len() < 3 {
838 return Err(SqlRsError::Query("Invalid DROP INDEX syntax".to_string()));
839 }
840
841 let index_name = parts[2].to_string();
842
843 if index_name.is_empty() {
844 return Err(SqlRsError::Query("Missing index name in DROP INDEX".to_string()));
845 }
846
847 Ok(Statement::DropIndex { index_name })
848}