Skip to main content

reifydb_sql/
parser.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use crate::{
5	Error,
6	ast::*,
7	token::{Keyword, Token},
8};
9
10pub struct Parser {
11	tokens: Vec<Token>,
12	pos: usize,
13}
14
15impl Parser {
16	pub fn new(tokens: Vec<Token>) -> Self {
17		Self {
18			tokens,
19			pos: 0,
20		}
21	}
22
23	pub fn parse(&mut self) -> Result<Statement, Error> {
24		let stmt = match self.peek()? {
25			Token::Keyword(Keyword::With) => self.parse_select()?,
26			Token::Keyword(Keyword::Select) => self.parse_select()?,
27			Token::Keyword(Keyword::Insert) => self.parse_insert()?,
28			Token::Keyword(Keyword::Update) => self.parse_update()?,
29			Token::Keyword(Keyword::Delete) => self.parse_delete()?,
30			Token::Keyword(Keyword::Create) => self.parse_create()?,
31			Token::Keyword(Keyword::Drop) => self.parse_drop()?,
32			other => return Err(Error(format!("unexpected token: {other:?}"))),
33		};
34		// Skip optional trailing semicolon
35		if self.pos < self.tokens.len() && self.tokens[self.pos] == Token::Semicolon {
36			self.pos += 1;
37		}
38		Ok(stmt)
39	}
40
41	fn peek(&self) -> Result<&Token, Error> {
42		self.tokens.get(self.pos).ok_or_else(|| Error("unexpected end of input".into()))
43	}
44
45	fn advance(&mut self) -> Result<Token, Error> {
46		if self.pos < self.tokens.len() {
47			let tok = self.tokens[self.pos].clone();
48			self.pos += 1;
49			Ok(tok)
50		} else {
51			Err(Error("unexpected end of input".into()))
52		}
53	}
54
55	fn expect_keyword(&mut self, kw: Keyword) -> Result<(), Error> {
56		let tok = self.advance()?;
57		if tok == Token::Keyword(kw.clone()) {
58			Ok(())
59		} else {
60			Err(Error(format!("expected {kw:?}, got {tok:?}")))
61		}
62	}
63
64	fn expect_token(&mut self, expected: Token) -> Result<(), Error> {
65		let tok = self.advance()?;
66		if tok == expected {
67			Ok(())
68		} else {
69			Err(Error(format!("expected {expected:?}, got {tok:?}")))
70		}
71	}
72
73	fn at_keyword(&self, kw: &Keyword) -> bool {
74		matches!(self.tokens.get(self.pos), Some(Token::Keyword(k)) if k == kw)
75	}
76
77	fn at_token(&self, t: &Token) -> bool {
78		matches!(self.tokens.get(self.pos), Some(tok) if tok == t)
79	}
80
81	fn is_eof(&self) -> bool {
82		self.pos >= self.tokens.len()
83	}
84
85	fn expect_ident(&mut self) -> Result<String, Error> {
86		let tok = self.advance()?;
87		match tok {
88			Token::Ident(name) => Ok(name),
89			// Allow certain keywords to be used as identifiers (common in SQL)
90			Token::Keyword(kw) => Ok(keyword_to_string(&kw)),
91			_ => Err(Error(format!("expected identifier, got {tok:?}"))),
92		}
93	}
94
95	/// Check if next token is an identifier-like token (not a structural keyword).
96	/// Used for optional alias detection.
97	fn is_ident_like(&self) -> bool {
98		match self.tokens.get(self.pos) {
99			Some(Token::Ident(_)) => true,
100			Some(Token::Keyword(kw)) => !is_structural_keyword(kw),
101			_ => false,
102		}
103	}
104
105	fn parse_select(&mut self) -> Result<Statement, Error> {
106		let sel = self.parse_select_statement()?;
107		Ok(Statement::Select(Box::new(sel)))
108	}
109
110	fn parse_select_statement(&mut self) -> Result<SelectStatement, Error> {
111		let ctes = if self.at_keyword(&Keyword::With) {
112			self.parse_cte_list()?
113		} else {
114			vec![]
115		};
116
117		self.expect_keyword(Keyword::Select)?;
118
119		let distinct = if self.at_keyword(&Keyword::Distinct) {
120			self.advance()?;
121			true
122		} else {
123			false
124		};
125
126		let columns = self.parse_select_columns()?;
127
128		let mut from = None;
129		let mut joins = Vec::new();
130
131		if self.at_keyword(&Keyword::From) {
132			self.advance()?;
133			let (first_from, _first_alias) = self.parse_from_item()?;
134			from = Some(first_from);
135
136			// Handle comma-separated tables (implicit cross join)
137			while self.at_token(&Token::Comma) {
138				self.advance()?;
139				let (extra_from, extra_alias) = self.parse_from_item()?;
140				let alias = extra_alias.or_else(|| match &extra_from {
141					FromClause::Table {
142						name,
143						..
144					} => Some(name.clone()),
145					_ => None,
146				});
147				joins.push(JoinClause {
148					join_type: JoinType::Cross,
149					table: extra_from,
150					table_alias: alias,
151					on: Expr::BoolLiteral(true),
152				});
153			}
154		}
155		while self.parse_join_if_present()? {
156			let join = self.finish_parse_join()?;
157			joins.push(join);
158		}
159
160		let where_clause = if self.at_keyword(&Keyword::Where) {
161			self.advance()?;
162			Some(self.parse_expr()?)
163		} else {
164			None
165		};
166
167		let group_by = if self.at_keyword(&Keyword::Group) {
168			self.advance()?;
169			self.expect_keyword(Keyword::By)?;
170			self.parse_expr_list()?
171		} else {
172			vec![]
173		};
174
175		let having = if self.at_keyword(&Keyword::Having) {
176			self.advance()?;
177			Some(self.parse_expr()?)
178		} else {
179			None
180		};
181
182		let order_by = if self.at_keyword(&Keyword::Order) {
183			self.advance()?;
184			self.expect_keyword(Keyword::By)?;
185			self.parse_order_by_list()?
186		} else {
187			vec![]
188		};
189
190		let limit = if self.at_keyword(&Keyword::Limit) {
191			self.advance()?;
192			Some(self.parse_u64()?)
193		} else {
194			None
195		};
196
197		let offset = if self.at_keyword(&Keyword::Offset) {
198			self.advance()?;
199			Some(self.parse_u64()?)
200		} else {
201			None
202		};
203
204		// Set operations: UNION [ALL] / INTERSECT / EXCEPT
205		let set_op = if self.at_keyword(&Keyword::Union) {
206			self.advance()?;
207			let op = if self.at_keyword(&Keyword::All) {
208				self.advance()?;
209				SetOp::UnionAll
210			} else {
211				SetOp::Union
212			};
213			let right = self.parse_select_statement()?;
214			Some((op, Box::new(right)))
215		} else if self.at_keyword(&Keyword::Intersect) {
216			self.advance()?;
217			let right = self.parse_select_statement()?;
218			Some((SetOp::Intersect, Box::new(right)))
219		} else if self.at_keyword(&Keyword::Except) {
220			self.advance()?;
221			let right = self.parse_select_statement()?;
222			Some((SetOp::Except, Box::new(right)))
223		} else {
224			None
225		};
226
227		Ok(SelectStatement {
228			ctes,
229			distinct,
230			columns,
231			from,
232			joins,
233			where_clause,
234			group_by,
235			having,
236			order_by,
237			limit,
238			offset,
239			set_op,
240		})
241	}
242
243	/// Parse a single FROM item (table or subquery) with optional alias.
244	/// Returns (FromClause, Option<alias>).
245	fn parse_from_item(&mut self) -> Result<(FromClause, Option<String>), Error> {
246		let from = if self.at_token(&Token::OpenParen) {
247			// Could be a subquery
248			self.advance()?;
249			if self.at_keyword(&Keyword::Select) {
250				let sel = self.parse_select_statement()?;
251				self.expect_token(Token::CloseParen)?;
252				FromClause::Subquery(Box::new(sel))
253			} else {
254				return Err(Error("expected subquery after '('".into()));
255			}
256		} else {
257			let name = self.expect_ident()?;
258			if self.at_token(&Token::Dot) {
259				self.advance()?;
260				let table = self.expect_ident()?;
261				FromClause::Table {
262					shape: Some(name),
263					name: table,
264					alias: None,
265				}
266			} else {
267				FromClause::Table {
268					name,
269					shape: None,
270					alias: None,
271				}
272			}
273		};
274
275		// Optional alias: AS alias or bare alias
276		let alias = if self.at_keyword(&Keyword::As) {
277			self.advance()?;
278			Some(self.expect_ident()?)
279		} else if !self.is_eof() && self.is_ident_like() {
280			Some(self.expect_ident()?)
281		} else {
282			None
283		};
284
285		// Embed alias into FromClause::Table if possible
286		if let Some(alias) = alias {
287			match from {
288				FromClause::Table {
289					name,
290					shape,
291					..
292				} => Ok((
293					FromClause::Table {
294						name,
295						shape,
296						alias: Some(alias),
297					},
298					None,
299				)),
300				other => Ok((other, Some(alias))),
301			}
302		} else {
303			Ok((from, None))
304		}
305	}
306
307	fn parse_cte_list(&mut self) -> Result<Vec<CteDefinition>, Error> {
308		self.expect_keyword(Keyword::With)?;
309		if self.at_keyword(&Keyword::Recursive) {
310			return Err(Error("recursive CTEs are not supported".into()));
311		}
312		let mut ctes = Vec::new();
313		loop {
314			let name = self.expect_ident()?;
315			self.expect_keyword(Keyword::As)?;
316			self.expect_token(Token::OpenParen)?;
317			let query = self.parse_select_statement()?;
318			self.expect_token(Token::CloseParen)?;
319			ctes.push(CteDefinition {
320				name,
321				query,
322			});
323			if self.at_token(&Token::Comma) {
324				self.advance()?;
325			} else {
326				break;
327			}
328		}
329		Ok(ctes)
330	}
331
332	fn parse_select_columns(&mut self) -> Result<Vec<SelectColumn>, Error> {
333		let mut cols = Vec::new();
334		loop {
335			if self.at_token(&Token::Asterisk) {
336				self.advance()?;
337				cols.push(SelectColumn::AllColumns);
338			} else if self.is_eof()
339				|| self.at_keyword(&Keyword::From)
340				|| self.at_keyword(&Keyword::Where)
341				|| self.at_keyword(&Keyword::Order)
342				|| self.at_keyword(&Keyword::Limit)
343				|| self.at_keyword(&Keyword::Group)
344				|| self.at_keyword(&Keyword::Having)
345				|| self.at_keyword(&Keyword::Union)
346				|| self.at_keyword(&Keyword::Intersect)
347				|| self.at_keyword(&Keyword::Except)
348				|| self.at_token(&Token::Semicolon)
349				|| self.at_token(&Token::CloseParen)
350			{
351				break;
352			} else {
353				let expr = self.parse_expr()?;
354				let alias = if self.at_keyword(&Keyword::As) {
355					self.advance()?;
356					Some(self.expect_ident()?)
357				} else {
358					None
359				};
360				cols.push(SelectColumn::Expr {
361					expr,
362					alias,
363				});
364			}
365
366			if self.at_token(&Token::Comma) {
367				self.advance()?;
368			} else {
369				break;
370			}
371		}
372		Ok(cols)
373	}
374
375	fn parse_from_clause(&mut self) -> Result<FromClause, Error> {
376		let (from, _alias) = self.parse_from_item()?;
377		Ok(from)
378	}
379
380	/// Check if the next tokens form a JOIN clause.  Returns true and
381	/// consumes the join-type keywords (INNER/LEFT/CROSS and JOIN) if present.
382	fn parse_join_if_present(&mut self) -> Result<bool, Error> {
383		if self.is_eof() {
384			return Ok(false);
385		}
386		// Bare JOIN
387		if self.at_keyword(&Keyword::Join) {
388			return Ok(true);
389		}
390		// INNER JOIN / LEFT JOIN / LEFT OUTER JOIN / CROSS JOIN / NATURAL JOIN / RIGHT JOIN / FULL JOIN / FULL
391		// OUTER JOIN
392		if self.at_keyword(&Keyword::Inner)
393			|| self.at_keyword(&Keyword::Left)
394			|| self.at_keyword(&Keyword::Right)
395			|| self.at_keyword(&Keyword::Cross)
396			|| self.at_keyword(&Keyword::Natural)
397			|| self.at_keyword(&Keyword::Full)
398		{
399			// Look ahead for JOIN (possibly with OUTER in between)
400			let mut look = self.pos + 1;
401			if look < self.tokens.len() && self.tokens[look] == Token::Keyword(Keyword::Outer) {
402				look += 1;
403			}
404			if look < self.tokens.len() && self.tokens[look] == Token::Keyword(Keyword::Join) {
405				return Ok(true);
406			}
407		}
408		Ok(false)
409	}
410
411	fn finish_parse_join(&mut self) -> Result<JoinClause, Error> {
412		let join_type = if self.at_keyword(&Keyword::Left) {
413			self.advance()?;
414			if self.at_keyword(&Keyword::Outer) {
415				self.advance()?;
416			}
417			self.expect_keyword(Keyword::Join)?;
418			JoinType::Left
419		} else if self.at_keyword(&Keyword::Inner) {
420			self.advance()?;
421			self.expect_keyword(Keyword::Join)?;
422			JoinType::Inner
423		} else if self.at_keyword(&Keyword::Cross) {
424			self.advance()?;
425			self.expect_keyword(Keyword::Join)?;
426			JoinType::Cross
427		} else if self.at_keyword(&Keyword::Natural) {
428			self.advance()?;
429			self.expect_keyword(Keyword::Join)?;
430			JoinType::Inner
431		} else if self.at_keyword(&Keyword::Right) || self.at_keyword(&Keyword::Full) {
432			self.advance()?;
433			if self.at_keyword(&Keyword::Outer) {
434				self.advance()?;
435			}
436			self.expect_keyword(Keyword::Join)?;
437			JoinType::Inner // best-effort: treat as inner
438		} else {
439			self.expect_keyword(Keyword::Join)?;
440			JoinType::Inner
441		};
442
443		let table = self.parse_from_clause()?;
444		let table_alias = if self.at_keyword(&Keyword::As) {
445			self.advance()?;
446			Some(self.expect_ident()?)
447		} else if !self.is_eof() && self.is_ident_like() && !self.at_keyword(&Keyword::On) {
448			Some(self.expect_ident()?)
449		} else {
450			// Check if alias was embedded in FromClause::Table
451			match &table {
452				FromClause::Table {
453					alias,
454					..
455				} => alias.clone(),
456				_ => None,
457			}
458		};
459
460		let on = if self.at_keyword(&Keyword::On) {
461			self.advance()?;
462			self.parse_expr()?
463		} else {
464			// CROSS JOIN or NATURAL JOIN might not have ON
465			Expr::BoolLiteral(true)
466		};
467
468		Ok(JoinClause {
469			join_type,
470			table,
471			table_alias,
472			on,
473		})
474	}
475
476	fn parse_insert(&mut self) -> Result<Statement, Error> {
477		self.expect_keyword(Keyword::Insert)?;
478		self.expect_keyword(Keyword::Into)?;
479
480		let (shape, table) = self.parse_table_name()?;
481
482		let columns = if self.at_token(&Token::OpenParen) {
483			self.advance()?;
484			let cols = self.parse_ident_list()?;
485			self.expect_token(Token::CloseParen)?;
486			cols
487		} else {
488			vec![]
489		};
490
491		// INSERT INTO ... SELECT or INSERT INTO ... VALUES
492		if self.at_keyword(&Keyword::Select) || self.at_keyword(&Keyword::With) {
493			let sel = self.parse_select_statement()?;
494			return Ok(Statement::Insert(InsertStatement {
495				table,
496				shape,
497				columns,
498				source: InsertSource::Select(Box::new(sel)),
499			}));
500		}
501
502		self.expect_keyword(Keyword::Values)?;
503
504		let mut values = Vec::new();
505		loop {
506			self.expect_token(Token::OpenParen)?;
507			let row = self.parse_expr_list()?;
508			self.expect_token(Token::CloseParen)?;
509			values.push(row);
510			if self.at_token(&Token::Comma) {
511				self.advance()?;
512			} else {
513				break;
514			}
515		}
516
517		Ok(Statement::Insert(InsertStatement {
518			table,
519			shape,
520			columns,
521			source: InsertSource::Values(values),
522		}))
523	}
524
525	fn parse_update(&mut self) -> Result<Statement, Error> {
526		self.expect_keyword(Keyword::Update)?;
527		let (shape, table) = self.parse_table_name()?;
528		self.expect_keyword(Keyword::Set)?;
529
530		let mut assignments = Vec::new();
531		loop {
532			let col = self.expect_ident()?;
533			self.expect_token(Token::Eq)?;
534			let val = self.parse_expr()?;
535			assignments.push((col, val));
536			if self.at_token(&Token::Comma) {
537				self.advance()?;
538			} else {
539				break;
540			}
541		}
542
543		let where_clause = if self.at_keyword(&Keyword::Where) {
544			self.advance()?;
545			Some(self.parse_expr()?)
546		} else {
547			None
548		};
549
550		Ok(Statement::Update(UpdateStatement {
551			table,
552			shape,
553			assignments,
554			where_clause,
555		}))
556	}
557
558	fn parse_delete(&mut self) -> Result<Statement, Error> {
559		self.expect_keyword(Keyword::Delete)?;
560		self.expect_keyword(Keyword::From)?;
561		let (shape, table) = self.parse_table_name()?;
562
563		let where_clause = if self.at_keyword(&Keyword::Where) {
564			self.advance()?;
565			Some(self.parse_expr()?)
566		} else {
567			None
568		};
569
570		Ok(Statement::Delete(DeleteStatement {
571			table,
572			shape,
573			where_clause,
574		}))
575	}
576
577	fn parse_create(&mut self) -> Result<Statement, Error> {
578		self.expect_keyword(Keyword::Create)?;
579
580		// CREATE UNIQUE INDEX ...
581		if self.at_keyword(&Keyword::Unique) {
582			self.advance()?;
583			self.expect_keyword(Keyword::Index)?;
584			return self.parse_create_index(true);
585		}
586
587		// CREATE INDEX ...
588		if self.at_keyword(&Keyword::Index) {
589			self.advance()?;
590			return self.parse_create_index(false);
591		}
592
593		// CREATE TABLE ...
594		self.expect_keyword(Keyword::Table)?;
595
596		// IF NOT EXISTS
597		let if_not_exists = if self.at_keyword(&Keyword::If) {
598			self.advance()?;
599			self.expect_keyword(Keyword::Not)?;
600			self.expect_keyword(Keyword::Exists)?;
601			true
602		} else {
603			false
604		};
605
606		let (shape, table) = self.parse_table_name()?;
607
608		self.expect_token(Token::OpenParen)?;
609		let mut columns = Vec::new();
610		let mut primary_key = Vec::new();
611		loop {
612			if self.at_token(&Token::CloseParen) {
613				break;
614			}
615			// Check for PRIMARY KEY(...) table constraint
616			if self.at_keyword(&Keyword::Primary) {
617				self.advance()?;
618				self.expect_keyword(Keyword::Key)?;
619				self.expect_token(Token::OpenParen)?;
620				primary_key = self.parse_ident_list()?;
621				self.expect_token(Token::CloseParen)?;
622				if self.at_token(&Token::Comma) {
623					self.advance()?;
624				}
625				continue;
626			}
627			// Check for UNIQUE(...) table constraint (skip it)
628			if self.at_keyword(&Keyword::Unique) {
629				self.advance()?;
630				self.expect_token(Token::OpenParen)?;
631				let _cols = self.parse_ident_list()?;
632				self.expect_token(Token::CloseParen)?;
633				if self.at_token(&Token::Comma) {
634					self.advance()?;
635				}
636				continue;
637			}
638			let name = self.expect_ident()?;
639			let data_type = self.parse_sql_type()?;
640			let mut nullable = true;
641			if self.at_keyword(&Keyword::Not) {
642				self.advance()?;
643				self.expect_keyword(Keyword::Null)?;
644				nullable = false;
645			} else if self.at_keyword(&Keyword::Null) {
646				self.advance()?;
647				nullable = true;
648			}
649			// Column-level PRIMARY KEY
650			if self.at_keyword(&Keyword::Primary) {
651				self.advance()?;
652				self.expect_keyword(Keyword::Key)?;
653				primary_key.push(name.clone());
654				nullable = false; // PRIMARY KEY implies NOT NULL
655			}
656			// Column-level UNIQUE (skip)
657			if self.at_keyword(&Keyword::Unique) {
658				self.advance()?;
659			}
660			// DEFAULT clause (skip the expression)
661			if !self.is_eof() && matches!(self.tokens.get(self.pos), Some(Token::Keyword(Keyword::Set))) {
662				// "DEFAULT" would be an ident, not a keyword - skip
663			}
664			columns.push(Column {
665				name,
666				data_type,
667				nullable,
668			});
669			if self.at_token(&Token::Comma) {
670				self.advance()?;
671			} else {
672				break;
673			}
674		}
675		self.expect_token(Token::CloseParen)?;
676
677		Ok(Statement::CreateTable(CreateTableStatement {
678			table,
679			shape,
680			columns,
681			primary_key,
682			if_not_exists,
683		}))
684	}
685
686	fn parse_create_index(&mut self, unique: bool) -> Result<Statement, Error> {
687		// CREATE [UNIQUE] INDEX [IF NOT EXISTS] name ON table (columns...)
688		// Handle IF NOT EXISTS
689		if self.at_keyword(&Keyword::If) {
690			self.advance()?;
691			self.expect_keyword(Keyword::Not)?;
692			self.expect_keyword(Keyword::Exists)?;
693		}
694
695		let index_name = self.expect_ident()?;
696		self.expect_keyword(Keyword::On)?;
697		let (shape, table) = self.parse_table_name()?;
698
699		self.expect_token(Token::OpenParen)?;
700		let mut columns = Vec::new();
701		loop {
702			let name = self.expect_ident()?;
703			let direction = if self.at_keyword(&Keyword::Asc) {
704				self.advance()?;
705				Some(OrderDirection::Asc)
706			} else if self.at_keyword(&Keyword::Desc) {
707				self.advance()?;
708				Some(OrderDirection::Desc)
709			} else {
710				None
711			};
712			columns.push(IndexColumn {
713				name,
714				direction,
715			});
716			if self.at_token(&Token::Comma) {
717				self.advance()?;
718			} else {
719				break;
720			}
721		}
722		self.expect_token(Token::CloseParen)?;
723
724		// Skip optional WHERE clause for partial indexes
725		if self.at_keyword(&Keyword::Where) {
726			self.advance()?;
727			let _ = self.parse_expr()?;
728		}
729
730		Ok(Statement::CreateIndex(CreateIndexStatement {
731			unique,
732			index_name,
733			table,
734			shape,
735			columns,
736		}))
737	}
738
739	fn parse_drop(&mut self) -> Result<Statement, Error> {
740		self.expect_keyword(Keyword::Drop)?;
741
742		// DROP INDEX (skip entirely)
743		if self.at_keyword(&Keyword::Index) {
744			self.advance()?;
745			// IF EXISTS
746			let _if_exists = if self.at_keyword(&Keyword::If) {
747				self.advance()?;
748				self.expect_keyword(Keyword::Exists)?;
749				true
750			} else {
751				false
752			};
753			let index_name = self.expect_ident()?;
754			// DROP INDEX just emits as-is
755			return Ok(Statement::DropTable(DropTableStatement {
756				table: index_name,
757				shape: None,
758				if_exists: _if_exists,
759			}));
760		}
761
762		self.expect_keyword(Keyword::Table)?;
763
764		let if_exists = if self.at_keyword(&Keyword::If) {
765			self.advance()?;
766			self.expect_keyword(Keyword::Exists)?;
767			true
768		} else {
769			false
770		};
771
772		let (shape, table) = self.parse_table_name()?;
773
774		Ok(Statement::DropTable(DropTableStatement {
775			table,
776			shape,
777			if_exists,
778		}))
779	}
780
781	fn parse_sql_type(&mut self) -> Result<SqlType, Error> {
782		let tok = self.advance()?;
783		match tok {
784			Token::Keyword(Keyword::Int) => Ok(SqlType::Int),
785			Token::Keyword(Keyword::Int2) => Ok(SqlType::Int2),
786			Token::Keyword(Keyword::Int4) => Ok(SqlType::Int4),
787			Token::Keyword(Keyword::Int8) => Ok(SqlType::Int8),
788			Token::Keyword(Keyword::Smallint) => Ok(SqlType::Smallint),
789			Token::Keyword(Keyword::Integer) => Ok(SqlType::Integer),
790			Token::Keyword(Keyword::Bigint) => Ok(SqlType::Bigint),
791			Token::Keyword(Keyword::Float4) => Ok(SqlType::Float4),
792			Token::Keyword(Keyword::Float8) => Ok(SqlType::Float8),
793			Token::Keyword(Keyword::FloatKw) => Ok(SqlType::FloatType),
794			Token::Keyword(Keyword::Numeric) => Ok(SqlType::Numeric),
795			Token::Keyword(Keyword::Real) => Ok(SqlType::Real),
796			Token::Keyword(Keyword::Double) => {
797				// DOUBLE PRECISION
798				if self.at_keyword(&Keyword::Precision) {
799					self.advance()?;
800				}
801				Ok(SqlType::Double)
802			}
803			Token::Keyword(Keyword::Boolean) => Ok(SqlType::Boolean),
804			Token::Keyword(Keyword::Bool) => Ok(SqlType::Bool),
805			Token::Keyword(Keyword::Text) => Ok(SqlType::Text),
806			Token::Keyword(Keyword::Utf8) => Ok(SqlType::Utf8),
807			Token::Keyword(Keyword::Blob) => Ok(SqlType::Blob),
808			Token::Keyword(Keyword::Varchar) => {
809				let len = if self.at_token(&Token::OpenParen) {
810					self.advance()?;
811					let n = self.parse_u64()?;
812					self.expect_token(Token::CloseParen)?;
813					Some(n)
814				} else {
815					None
816				};
817				Ok(SqlType::Varchar(len))
818			}
819			Token::Keyword(Keyword::Char) => {
820				let len = if self.at_token(&Token::OpenParen) {
821					self.advance()?;
822					let n = self.parse_u64()?;
823					self.expect_token(Token::CloseParen)?;
824					Some(n)
825				} else {
826					None
827				};
828				Ok(SqlType::Char(len))
829			}
830			_ => Err(Error(format!("expected SQL type, got {tok:?}"))),
831		}
832	}
833
834	fn parse_expr(&mut self) -> Result<Expr, Error> {
835		self.parse_or()
836	}
837
838	fn parse_or(&mut self) -> Result<Expr, Error> {
839		let mut left = self.parse_and()?;
840		while self.at_keyword(&Keyword::Or) {
841			self.advance()?;
842			let right = self.parse_and()?;
843			left = Expr::BinaryOp {
844				left: Box::new(left),
845				op: BinaryOp::Or,
846				right: Box::new(right),
847			};
848		}
849		Ok(left)
850	}
851
852	fn parse_and(&mut self) -> Result<Expr, Error> {
853		let mut left = self.parse_not()?;
854		while self.at_keyword(&Keyword::And) {
855			self.advance()?;
856			let right = self.parse_not()?;
857			left = Expr::BinaryOp {
858				left: Box::new(left),
859				op: BinaryOp::And,
860				right: Box::new(right),
861			};
862		}
863		Ok(left)
864	}
865
866	fn parse_not(&mut self) -> Result<Expr, Error> {
867		if self.at_keyword(&Keyword::Not) {
868			// Check for NOT EXISTS
869			if matches!(self.tokens.get(self.pos + 1), Some(Token::Keyword(Keyword::Exists))) {
870				self.advance()?; // NOT
871				self.advance()?; // EXISTS
872				self.expect_token(Token::OpenParen)?;
873				let sel = self.parse_select_statement()?;
874				self.expect_token(Token::CloseParen)?;
875				return Ok(Expr::UnaryOp {
876					op: UnaryOp::Not,
877					expr: Box::new(Expr::Exists(Box::new(sel))),
878				});
879			}
880			self.advance()?;
881			let expr = self.parse_not()?;
882			Ok(Expr::UnaryOp {
883				op: UnaryOp::Not,
884				expr: Box::new(expr),
885			})
886		} else {
887			self.parse_comparison()
888		}
889	}
890
891	fn parse_comparison(&mut self) -> Result<Expr, Error> {
892		let mut left = self.parse_addition()?;
893
894		// IS NULL / IS NOT NULL
895		if self.at_keyword(&Keyword::Is) {
896			self.advance()?;
897			if self.at_keyword(&Keyword::Not) {
898				self.advance()?;
899				self.expect_keyword(Keyword::Null)?;
900				return Ok(Expr::IsNull {
901					expr: Box::new(left),
902					negated: true,
903				});
904			} else {
905				self.expect_keyword(Keyword::Null)?;
906				return Ok(Expr::IsNull {
907					expr: Box::new(left),
908					negated: false,
909				});
910			}
911		}
912
913		// NOT BETWEEN / BETWEEN ... AND ...
914		if self.at_keyword(&Keyword::Not)
915			&& matches!(self.tokens.get(self.pos + 1), Some(Token::Keyword(Keyword::Between)))
916		{
917			self.advance()?; // NOT
918			self.advance()?; // BETWEEN
919			let low = self.parse_addition()?;
920			self.expect_keyword(Keyword::And)?;
921			let high = self.parse_addition()?;
922			return Ok(Expr::Between {
923				expr: Box::new(left),
924				low: Box::new(low),
925				high: Box::new(high),
926				negated: true,
927			});
928		}
929
930		if self.at_keyword(&Keyword::Between) {
931			self.advance()?;
932			let low = self.parse_addition()?;
933			self.expect_keyword(Keyword::And)?;
934			let high = self.parse_addition()?;
935			return Ok(Expr::Between {
936				expr: Box::new(left),
937				low: Box::new(low),
938				high: Box::new(high),
939				negated: false,
940			});
941		}
942
943		// NOT LIKE / LIKE
944		if self.at_keyword(&Keyword::Not)
945			&& matches!(self.tokens.get(self.pos + 1), Some(Token::Keyword(Keyword::Like)))
946		{
947			self.advance()?; // NOT
948			self.advance()?; // LIKE
949			let pattern = self.parse_addition()?;
950			return Ok(Expr::Like {
951				expr: Box::new(left),
952				pattern: Box::new(pattern),
953				negated: true,
954			});
955		}
956
957		if self.at_keyword(&Keyword::Like) {
958			self.advance()?;
959			let pattern = self.parse_addition()?;
960			return Ok(Expr::Like {
961				expr: Box::new(left),
962				pattern: Box::new(pattern),
963				negated: false,
964			});
965		}
966
967		// NOT GLOB / GLOB (treat like LIKE for now)
968		if self.at_keyword(&Keyword::Not)
969			&& matches!(self.tokens.get(self.pos + 1), Some(Token::Keyword(Keyword::Glob)))
970		{
971			self.advance()?; // NOT
972			self.advance()?; // GLOB
973			let pattern = self.parse_addition()?;
974			return Ok(Expr::Like {
975				expr: Box::new(left),
976				pattern: Box::new(pattern),
977				negated: true,
978			});
979		}
980
981		if self.at_keyword(&Keyword::Glob) {
982			self.advance()?;
983			let pattern = self.parse_addition()?;
984			return Ok(Expr::Like {
985				expr: Box::new(left),
986				pattern: Box::new(pattern),
987				negated: false,
988			});
989		}
990
991		// NOT IN / IN (...)
992		if self.at_keyword(&Keyword::Not)
993			&& matches!(self.tokens.get(self.pos + 1), Some(Token::Keyword(Keyword::In)))
994		{
995			self.advance()?; // NOT
996			self.advance()?; // IN
997			self.expect_token(Token::OpenParen)?;
998			// Check for subquery
999			if self.at_keyword(&Keyword::Select) || self.at_keyword(&Keyword::With) {
1000				let sel = self.parse_select_statement()?;
1001				self.expect_token(Token::CloseParen)?;
1002				return Ok(Expr::InSelect {
1003					expr: Box::new(left),
1004					subquery: Box::new(sel),
1005					negated: true,
1006				});
1007			}
1008			let list = self.parse_expr_list()?;
1009			self.expect_token(Token::CloseParen)?;
1010			return Ok(Expr::InList {
1011				expr: Box::new(left),
1012				list,
1013				negated: true,
1014			});
1015		}
1016
1017		if self.at_keyword(&Keyword::In) {
1018			self.advance()?;
1019			self.expect_token(Token::OpenParen)?;
1020			// Check for subquery
1021			if self.at_keyword(&Keyword::Select) || self.at_keyword(&Keyword::With) {
1022				let sel = self.parse_select_statement()?;
1023				self.expect_token(Token::CloseParen)?;
1024				return Ok(Expr::InSelect {
1025					expr: Box::new(left),
1026					subquery: Box::new(sel),
1027					negated: false,
1028				});
1029			}
1030			let list = self.parse_expr_list()?;
1031			self.expect_token(Token::CloseParen)?;
1032			return Ok(Expr::InList {
1033				expr: Box::new(left),
1034				list,
1035				negated: false,
1036			});
1037		}
1038
1039		// Comparison operators
1040		let op = match self.tokens.get(self.pos) {
1041			Some(Token::Eq) => Some(BinaryOp::Eq),
1042			Some(Token::NotEq) => Some(BinaryOp::NotEq),
1043			Some(Token::Lt) => Some(BinaryOp::Lt),
1044			Some(Token::Gt) => Some(BinaryOp::Gt),
1045			Some(Token::LtEq) => Some(BinaryOp::LtEq),
1046			Some(Token::GtEq) => Some(BinaryOp::GtEq),
1047			_ => None,
1048		};
1049		if let Some(op) = op {
1050			self.advance()?;
1051			let right = self.parse_addition()?;
1052			left = Expr::BinaryOp {
1053				left: Box::new(left),
1054				op,
1055				right: Box::new(right),
1056			};
1057		}
1058
1059		Ok(left)
1060	}
1061
1062	fn parse_addition(&mut self) -> Result<Expr, Error> {
1063		let mut left = self.parse_multiplication()?;
1064		loop {
1065			let op = match self.tokens.get(self.pos) {
1066				Some(Token::Plus) => Some(BinaryOp::Add),
1067				Some(Token::Minus) => Some(BinaryOp::Sub),
1068				Some(Token::Concat) => Some(BinaryOp::Concat),
1069				_ => None,
1070			};
1071			if let Some(op) = op {
1072				self.advance()?;
1073				let right = self.parse_multiplication()?;
1074				left = Expr::BinaryOp {
1075					left: Box::new(left),
1076					op,
1077					right: Box::new(right),
1078				};
1079			} else {
1080				break;
1081			}
1082		}
1083		Ok(left)
1084	}
1085
1086	fn parse_multiplication(&mut self) -> Result<Expr, Error> {
1087		let mut left = self.parse_unary()?;
1088		loop {
1089			let op = match self.tokens.get(self.pos) {
1090				Some(Token::Asterisk) => Some(BinaryOp::Mul),
1091				Some(Token::Slash) => Some(BinaryOp::Div),
1092				Some(Token::Percent) => Some(BinaryOp::Mod),
1093				_ => None,
1094			};
1095			if let Some(op) = op {
1096				self.advance()?;
1097				let right = self.parse_unary()?;
1098				left = Expr::BinaryOp {
1099					left: Box::new(left),
1100					op,
1101					right: Box::new(right),
1102				};
1103			} else {
1104				break;
1105			}
1106		}
1107		Ok(left)
1108	}
1109
1110	fn parse_unary(&mut self) -> Result<Expr, Error> {
1111		if self.at_token(&Token::Minus) {
1112			self.advance()?;
1113			let expr = self.parse_unary()?;
1114			return Ok(Expr::UnaryOp {
1115				op: UnaryOp::Neg,
1116				expr: Box::new(expr),
1117			});
1118		}
1119		// Unary + (identity)
1120		if self.at_token(&Token::Plus) {
1121			self.advance()?;
1122			return self.parse_unary();
1123		}
1124		self.parse_primary()
1125	}
1126
1127	fn parse_primary(&mut self) -> Result<Expr, Error> {
1128		let tok = self.peek()?.clone();
1129		match tok {
1130			Token::Integer(n) => {
1131				self.advance()?;
1132				Ok(Expr::IntegerLiteral(n))
1133			}
1134			Token::Float(f) => {
1135				self.advance()?;
1136				Ok(Expr::FloatLiteral(f))
1137			}
1138			Token::StringLit(s) => {
1139				self.advance()?;
1140				Ok(Expr::StringLiteral(s))
1141			}
1142			Token::Keyword(Keyword::True) => {
1143				self.advance()?;
1144				Ok(Expr::BoolLiteral(true))
1145			}
1146			Token::Keyword(Keyword::False) => {
1147				self.advance()?;
1148				Ok(Expr::BoolLiteral(false))
1149			}
1150			Token::Keyword(Keyword::Null) => {
1151				self.advance()?;
1152				Ok(Expr::Null)
1153			}
1154			Token::Keyword(Keyword::Cast) => self.parse_cast_expr(),
1155			Token::Keyword(Keyword::Case) => self.parse_case_expr(),
1156			Token::Keyword(Keyword::Exists) => {
1157				self.advance()?;
1158				self.expect_token(Token::OpenParen)?;
1159				let sel = self.parse_select_statement()?;
1160				self.expect_token(Token::CloseParen)?;
1161				Ok(Expr::Exists(Box::new(sel)))
1162			}
1163			Token::Keyword(Keyword::Not) => {
1164				// NOT EXISTS handled at parse_not level, but if we get here via parse_primary...
1165				if matches!(self.tokens.get(self.pos + 1), Some(Token::Keyword(Keyword::Exists))) {
1166					self.advance()?; // NOT
1167					self.advance()?; // EXISTS
1168					self.expect_token(Token::OpenParen)?;
1169					let sel = self.parse_select_statement()?;
1170					self.expect_token(Token::CloseParen)?;
1171					Ok(Expr::UnaryOp {
1172						op: UnaryOp::Not,
1173						expr: Box::new(Expr::Exists(Box::new(sel))),
1174					})
1175				} else {
1176					Err(Error(format!("unexpected token in expression: {tok:?}")))
1177				}
1178			}
1179			// Aggregate function keywords
1180			Token::Keyword(Keyword::Count)
1181			| Token::Keyword(Keyword::Sum)
1182			| Token::Keyword(Keyword::Avg)
1183			| Token::Keyword(Keyword::Min)
1184			| Token::Keyword(Keyword::Max) => {
1185				let name = keyword_to_string(match &self.advance()? {
1186					Token::Keyword(kw) => kw,
1187					_ => unreachable!(),
1188				});
1189				self.expect_token(Token::OpenParen)?;
1190				// Handle DISTINCT inside aggregate: COUNT(DISTINCT x)
1191				let distinct_prefix = if self.at_keyword(&Keyword::Distinct) {
1192					self.advance()?;
1193					true
1194				} else {
1195					false
1196				};
1197				let args = if self.at_token(&Token::Asterisk) {
1198					self.advance()?;
1199					vec![Expr::Identifier("*".into())]
1200				} else {
1201					self.parse_expr_list()?
1202				};
1203				self.expect_token(Token::CloseParen)?;
1204				if distinct_prefix {
1205					// Wrap as DISTINCT_name function
1206					Ok(Expr::FunctionCall {
1207						name: format!("{name}_DISTINCT"),
1208						args,
1209					})
1210				} else {
1211					Ok(Expr::FunctionCall {
1212						name,
1213						args,
1214					})
1215				}
1216			}
1217			Token::OpenParen => {
1218				self.advance()?;
1219				// Check for subquery
1220				if self.at_keyword(&Keyword::Select) || self.at_keyword(&Keyword::With) {
1221					let sel = self.parse_select_statement()?;
1222					self.expect_token(Token::CloseParen)?;
1223					return Ok(Expr::Subquery(Box::new(sel)));
1224				}
1225				let expr = self.parse_expr()?;
1226				self.expect_token(Token::CloseParen)?;
1227				Ok(Expr::Nested(Box::new(expr)))
1228			}
1229			Token::Ident(_) => {
1230				let name = self.expect_ident()?;
1231				// Check for qualified identifier (table.column)
1232				if self.at_token(&Token::Dot) {
1233					self.advance()?;
1234					let col = self.expect_ident()?;
1235					// Check for function call on qualified name
1236					if self.at_token(&Token::OpenParen) {
1237						self.advance()?;
1238						let args = if self.at_token(&Token::CloseParen) {
1239							vec![]
1240						} else if self.at_token(&Token::Asterisk) {
1241							self.advance()?;
1242							vec![Expr::Identifier("*".into())]
1243						} else {
1244							self.parse_expr_list()?
1245						};
1246						self.expect_token(Token::CloseParen)?;
1247						Ok(Expr::FunctionCall {
1248							name: format!("{name}.{col}"),
1249							args,
1250						})
1251					} else {
1252						Ok(Expr::QualifiedIdentifier(name, col))
1253					}
1254				}
1255				// Check for function call
1256				else if self.at_token(&Token::OpenParen) {
1257					self.advance()?;
1258					let args = if self.at_token(&Token::CloseParen) {
1259						vec![]
1260					} else if self.at_token(&Token::Asterisk) {
1261						self.advance()?;
1262						vec![Expr::Identifier("*".into())]
1263					} else {
1264						self.parse_expr_list()?
1265					};
1266					self.expect_token(Token::CloseParen)?;
1267					Ok(Expr::FunctionCall {
1268						name,
1269						args,
1270					})
1271				} else {
1272					Ok(Expr::Identifier(name))
1273				}
1274			}
1275			_ => Err(Error(format!("unexpected token in expression: {tok:?}"))),
1276		}
1277	}
1278
1279	fn parse_cast_expr(&mut self) -> Result<Expr, Error> {
1280		self.expect_keyword(Keyword::Cast)?;
1281		self.expect_token(Token::OpenParen)?;
1282		let expr = self.parse_expr()?;
1283		self.expect_keyword(Keyword::As)?;
1284		let data_type = self.parse_sql_type()?;
1285		self.expect_token(Token::CloseParen)?;
1286		Ok(Expr::Cast {
1287			expr: Box::new(expr),
1288			data_type,
1289		})
1290	}
1291
1292	fn parse_case_expr(&mut self) -> Result<Expr, Error> {
1293		self.expect_keyword(Keyword::Case)?;
1294
1295		// Simple CASE (CASE expr WHEN ...) vs Searched CASE (CASE WHEN ...)
1296		let operand = if !self.at_keyword(&Keyword::When) {
1297			Some(Box::new(self.parse_expr()?))
1298		} else {
1299			None
1300		};
1301
1302		let mut when_clauses = Vec::new();
1303		while self.at_keyword(&Keyword::When) {
1304			self.advance()?;
1305			let condition = self.parse_expr()?;
1306			self.expect_keyword(Keyword::Then)?;
1307			let result = self.parse_expr()?;
1308			when_clauses.push((condition, result));
1309		}
1310
1311		let else_clause = if self.at_keyword(&Keyword::Else) {
1312			self.advance()?;
1313			Some(Box::new(self.parse_expr()?))
1314		} else {
1315			None
1316		};
1317
1318		self.expect_keyword(Keyword::End)?;
1319
1320		Ok(Expr::Case {
1321			operand,
1322			when_clauses,
1323			else_clause,
1324		})
1325	}
1326
1327	fn parse_expr_list(&mut self) -> Result<Vec<Expr>, Error> {
1328		let mut exprs = Vec::new();
1329		exprs.push(self.parse_expr()?);
1330		while self.at_token(&Token::Comma) {
1331			self.advance()?;
1332			exprs.push(self.parse_expr()?);
1333		}
1334		Ok(exprs)
1335	}
1336
1337	fn parse_ident_list(&mut self) -> Result<Vec<String>, Error> {
1338		let mut names = Vec::new();
1339		names.push(self.expect_ident()?);
1340		while self.at_token(&Token::Comma) {
1341			self.advance()?;
1342			names.push(self.expect_ident()?);
1343		}
1344		Ok(names)
1345	}
1346
1347	fn parse_order_by_list(&mut self) -> Result<Vec<OrderByItem>, Error> {
1348		let mut items = Vec::new();
1349		loop {
1350			let expr = self.parse_expr()?;
1351			let direction = if self.at_keyword(&Keyword::Desc) {
1352				self.advance()?;
1353				OrderDirection::Desc
1354			} else {
1355				if self.at_keyword(&Keyword::Asc) {
1356					self.advance()?;
1357				}
1358				OrderDirection::Asc
1359			};
1360			items.push(OrderByItem {
1361				expr,
1362				direction,
1363			});
1364			if self.at_token(&Token::Comma) {
1365				self.advance()?;
1366			} else {
1367				break;
1368			}
1369		}
1370		Ok(items)
1371	}
1372
1373	fn parse_u64(&mut self) -> Result<u64, Error> {
1374		let tok = self.advance()?;
1375		match tok {
1376			Token::Integer(n) if n >= 0 => Ok(n as u64),
1377			_ => Err(Error(format!("expected positive integer, got {tok:?}"))),
1378		}
1379	}
1380
1381	fn parse_table_name(&mut self) -> Result<(Option<String>, String), Error> {
1382		let name = self.expect_ident()?;
1383		if self.at_token(&Token::Dot) {
1384			self.advance()?;
1385			let table = self.expect_ident()?;
1386			Ok((Some(name), table))
1387		} else {
1388			Ok((None, name))
1389		}
1390	}
1391}
1392
1393/// Keywords that are structural (end a FROM/SELECT clause, etc.)
1394/// and should NOT be treated as bare aliases.
1395fn is_structural_keyword(kw: &Keyword) -> bool {
1396	matches!(
1397		kw,
1398		Keyword::Where
1399			| Keyword::Order | Keyword::Group
1400			| Keyword::Having | Keyword::Limit
1401			| Keyword::Offset | Keyword::Join
1402			| Keyword::Inner | Keyword::Left
1403			| Keyword::Right | Keyword::Cross
1404			| Keyword::Outer | Keyword::Full
1405			| Keyword::Natural | Keyword::On
1406			| Keyword::Set | Keyword::Values
1407			| Keyword::Select | Keyword::From
1408			| Keyword::Union | Keyword::Intersect
1409			| Keyword::Except | Keyword::When
1410			| Keyword::Then | Keyword::Else
1411			| Keyword::End | Keyword::And
1412			| Keyword::Or | Keyword::Not
1413	)
1414}
1415
1416fn keyword_to_string(kw: &Keyword) -> String {
1417	match kw {
1418		Keyword::Select => "SELECT",
1419		Keyword::From => "FROM",
1420		Keyword::Where => "WHERE",
1421		Keyword::And => "AND",
1422		Keyword::Or => "OR",
1423		Keyword::Not => "NOT",
1424		Keyword::As => "AS",
1425		Keyword::Order => "ORDER",
1426		Keyword::By => "BY",
1427		Keyword::Asc => "ASC",
1428		Keyword::Desc => "DESC",
1429		Keyword::Limit => "LIMIT",
1430		Keyword::Offset => "OFFSET",
1431		Keyword::Group => "GROUP",
1432		Keyword::Having => "HAVING",
1433		Keyword::Distinct => "DISTINCT",
1434		Keyword::Insert => "INSERT",
1435		Keyword::Into => "INTO",
1436		Keyword::Values => "VALUES",
1437		Keyword::Update => "UPDATE",
1438		Keyword::Set => "SET",
1439		Keyword::Delete => "DELETE",
1440		Keyword::Create => "CREATE",
1441		Keyword::Table => "TABLE",
1442		Keyword::Join => "JOIN",
1443		Keyword::Inner => "INNER",
1444		Keyword::Left => "LEFT",
1445		Keyword::Right => "RIGHT",
1446		Keyword::On => "ON",
1447		Keyword::Null => "NULL",
1448		Keyword::True => "true",
1449		Keyword::False => "false",
1450		Keyword::Is => "IS",
1451		Keyword::In => "IN",
1452		Keyword::Between => "BETWEEN",
1453		Keyword::Cast => "CAST",
1454		Keyword::Count => "COUNT",
1455		Keyword::Sum => "SUM",
1456		Keyword::Avg => "AVG",
1457		Keyword::Min => "MIN",
1458		Keyword::Max => "MAX",
1459		Keyword::Int => "INT",
1460		Keyword::Int2 => "INT2",
1461		Keyword::Int4 => "INT4",
1462		Keyword::Int8 => "INT8",
1463		Keyword::Smallint => "SMALLINT",
1464		Keyword::Integer => "INTEGER",
1465		Keyword::Bigint => "BIGINT",
1466		Keyword::Float4 => "FLOAT4",
1467		Keyword::Float8 => "FLOAT8",
1468		Keyword::Real => "REAL",
1469		Keyword::Double => "DOUBLE",
1470		Keyword::Precision => "PRECISION",
1471		Keyword::Boolean => "BOOLEAN",
1472		Keyword::Bool => "BOOL",
1473		Keyword::Varchar => "VARCHAR",
1474		Keyword::Text => "TEXT",
1475		Keyword::Char => "CHAR",
1476		Keyword::Utf8 => "UTF8",
1477		Keyword::Blob => "BLOB",
1478		Keyword::Primary => "PRIMARY",
1479		Keyword::Key => "KEY",
1480		Keyword::With => "WITH",
1481		Keyword::Recursive => "RECURSIVE",
1482		Keyword::Case => "CASE",
1483		Keyword::When => "WHEN",
1484		Keyword::Then => "THEN",
1485		Keyword::Else => "ELSE",
1486		Keyword::End => "END",
1487		Keyword::Exists => "EXISTS",
1488		Keyword::Union => "UNION",
1489		Keyword::All => "ALL",
1490		Keyword::Intersect => "INTERSECT",
1491		Keyword::Except => "EXCEPT",
1492		Keyword::Like => "LIKE",
1493		Keyword::Glob => "GLOB",
1494		Keyword::If => "IF",
1495		Keyword::FloatKw => "FLOAT",
1496		Keyword::Index => "INDEX",
1497		Keyword::Unique => "UNIQUE",
1498		Keyword::Drop => "DROP",
1499		Keyword::Cross => "CROSS",
1500		Keyword::Outer => "OUTER",
1501		Keyword::Full => "FULL",
1502		Keyword::Natural => "NATURAL",
1503		Keyword::Numeric => "NUMERIC",
1504	}
1505	.into()
1506}
1507
1508#[cfg(test)]
1509mod tests {
1510	use super::*;
1511	use crate::token::tokenize;
1512
1513	#[test]
1514	fn test_parse_simple_select() {
1515		let tokens = tokenize("SELECT id, name FROM users").unwrap();
1516		let stmt = Parser::new(tokens).parse().unwrap();
1517		match stmt {
1518			Statement::Select(sel) => {
1519				assert_eq!(sel.columns.len(), 2);
1520				assert!(sel.from.is_some());
1521			}
1522			_ => panic!("expected select"),
1523		}
1524	}
1525
1526	#[test]
1527	fn test_parse_select_star() {
1528		let tokens = tokenize("SELECT * FROM users").unwrap();
1529		let stmt = Parser::new(tokens).parse().unwrap();
1530		match stmt {
1531			Statement::Select(sel) => {
1532				assert!(matches!(sel.columns[0], SelectColumn::AllColumns));
1533			}
1534			_ => panic!("expected select"),
1535		}
1536	}
1537
1538	#[test]
1539	fn test_parse_where() {
1540		let tokens = tokenize("SELECT * FROM users WHERE age > 18").unwrap();
1541		let stmt = Parser::new(tokens).parse().unwrap();
1542		match stmt {
1543			Statement::Select(sel) => {
1544				assert!(sel.where_clause.is_some());
1545			}
1546			_ => panic!("expected select"),
1547		}
1548	}
1549
1550	#[test]
1551	fn test_parse_insert() {
1552		let tokens = tokenize("INSERT INTO users (id, name) VALUES (1, 'Alice')").unwrap();
1553		let stmt = Parser::new(tokens).parse().unwrap();
1554		match stmt {
1555			Statement::Insert(ins) => {
1556				assert_eq!(ins.table, "users");
1557				assert_eq!(ins.columns.len(), 2);
1558				match &ins.source {
1559					InsertSource::Values(v) => assert_eq!(v.len(), 1),
1560					_ => panic!("expected values"),
1561				}
1562			}
1563			_ => panic!("expected insert"),
1564		}
1565	}
1566}