vibesql_parser/parser/
mod.rs

1use std::fmt;
2
3use crate::{keywords::Keyword, lexer::Lexer, token::Token};
4
5/// Maximum number of terms allowed in an ORDER BY clause.
6/// This matches SQLite's SQLITE_MAX_COLUMN default of 2000.
7/// See: https://www.sqlite.org/limits.html
8pub const MAX_ORDER_BY_TERMS: usize = 2000;
9
10mod advanced_objects;
11mod alter;
12mod create;
13mod cursor;
14mod delete;
15mod domain;
16mod drop;
17mod expressions;
18mod grant;
19mod helpers;
20mod index;
21mod insert;
22mod introspection;
23mod prepared;
24mod revoke;
25mod role;
26mod schema;
27mod select;
28mod table_options;
29mod transaction;
30mod trigger;
31mod truncate;
32mod update;
33mod view;
34
35/// Parser error
36#[derive(Debug, Clone, PartialEq)]
37pub struct ParseError {
38    pub message: String,
39}
40
41impl fmt::Display for ParseError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "Parse error: {}", self.message)
44    }
45}
46
47/// SQL Parser - converts tokens into AST
48pub struct Parser {
49    tokens: Vec<Token>,
50    position: usize,
51    /// Counter for placeholder parameters (?)
52    /// Incremented each time a placeholder is parsed, providing 0-indexed parameter positions
53    placeholder_count: usize,
54}
55
56impl Parser {
57    /// Create a new parser from tokens
58    pub fn new(tokens: Vec<Token>) -> Self {
59        Parser { tokens, position: 0, placeholder_count: 0 }
60    }
61
62    /// Parse a comma-separated list of items using a provided parser function
63    ///
64    /// This is a generic helper that consolidates the common pattern of parsing
65    /// comma-separated lists throughout the parser (e.g., GROUP BY expressions,
66    /// ORDER BY items, identifier lists, etc.)
67    ///
68    /// # Arguments
69    /// * `parse_item` - Closure that parses a single item of type T
70    ///
71    /// # Returns
72    /// * `Ok(Vec<T>)` - Successfully parsed list of items
73    /// * `Err(ParseError)` - Error parsing an item
74    ///
75    /// # Example
76    /// ```text
77    /// // Parse comma-separated expressions (for GROUP BY)
78    /// let exprs = self.parse_comma_separated_list(|p| p.parse_expression())?;
79    ///
80    /// // Parse comma-separated identifiers
81    /// let ids = self.parse_comma_separated_list(|p| p.parse_identifier())?;
82    /// ```
83    pub fn parse_comma_separated_list<T, F>(&mut self, parse_item: F) -> Result<Vec<T>, ParseError>
84    where
85        F: Fn(&mut Self) -> Result<T, ParseError>,
86    {
87        let mut items = Vec::new();
88
89        // Parse first item
90        items.push(parse_item(self)?);
91
92        // Parse remaining items (preceded by commas)
93        while matches!(self.peek(), Token::Comma) {
94            self.advance(); // consume comma
95            items.push(parse_item(self)?);
96        }
97
98        Ok(items)
99    }
100
101    /// Parse SQL input string into a Statement
102    pub fn parse_sql(input: &str) -> Result<vibesql_ast::Statement, ParseError> {
103        let mut lexer = Lexer::new(input);
104        let tokens =
105            lexer.tokenize().map_err(|e| ParseError { message: format!("Lexer error: {}", e) })?;
106
107        let mut parser = Parser::new(tokens);
108        parser.parse_statement()
109    }
110
111    /// Parse a statement
112    pub fn parse_statement(&mut self) -> Result<vibesql_ast::Statement, ParseError> {
113        match self.peek() {
114            Token::Keyword { keyword: Keyword::Select, .. } => {
115                let select_stmt = self.parse_select_statement()?;
116                Ok(vibesql_ast::Statement::Select(Box::new(select_stmt)))
117            }
118            Token::Keyword { keyword: Keyword::With, .. } => {
119                // WITH can precede SELECT, INSERT, UPDATE, or DELETE
120                // Parse the CTE list first, then check what statement follows
121                self.parse_with_statement()
122            }
123            Token::Keyword { keyword: Keyword::Values, .. } => {
124                let select_stmt = self.parse_values_statement()?;
125                Ok(vibesql_ast::Statement::Select(Box::new(select_stmt)))
126            }
127            Token::Keyword { keyword: Keyword::Insert, .. } => {
128                let insert_stmt = self.parse_insert_statement()?;
129                Ok(vibesql_ast::Statement::Insert(insert_stmt))
130            }
131            Token::Keyword { keyword: Keyword::Replace, .. } => {
132                let insert_stmt = self.parse_replace_statement()?;
133                Ok(vibesql_ast::Statement::Insert(insert_stmt))
134            }
135            Token::Keyword { keyword: Keyword::Update, .. } => {
136                let update_stmt = self.parse_update_statement()?;
137                Ok(vibesql_ast::Statement::Update(update_stmt))
138            }
139            Token::Keyword { keyword: Keyword::Delete, .. } => {
140                let delete_stmt = self.parse_delete_statement()?;
141                Ok(vibesql_ast::Statement::Delete(delete_stmt))
142            }
143            Token::Keyword { keyword: Keyword::Create, .. } => {
144                // Check for CREATE OR REPLACE VIEW and CREATE OR REPLACE TEMP/TEMPORARY VIEW
145                if self.peek_next_keyword(Keyword::Or)
146                    && matches!(
147                        self.peek_at_offset(2),
148                        Token::Keyword { keyword: Keyword::Replace, .. }
149                    )
150                {
151                    // Could be CREATE OR REPLACE VIEW or CREATE OR REPLACE TEMP/TEMPORARY VIEW
152                    if matches!(
153                        self.peek_at_offset(3),
154                        Token::Keyword { keyword: Keyword::View, .. }
155                    ) || matches!(
156                        self.peek_at_offset(3),
157                        Token::Keyword { keyword: Keyword::Temp, .. }
158                    ) || matches!(
159                        self.peek_at_offset(3),
160                        Token::Keyword { keyword: Keyword::Temporary, .. }
161                    ) {
162                        return Ok(vibesql_ast::Statement::CreateView(
163                            self.parse_create_view_statement()?,
164                        ));
165                    }
166                }
167                if self.peek_next_keyword(Keyword::Table) {
168                    Ok(vibesql_ast::Statement::CreateTable(self.parse_create_table_statement()?))
169                } else if self.peek_next_keyword(Keyword::Schema) {
170                    Ok(vibesql_ast::Statement::CreateSchema(self.parse_create_schema_statement()?))
171                } else if self.peek_next_keyword(Keyword::Role) {
172                    Ok(vibesql_ast::Statement::CreateRole(self.parse_create_role_statement()?))
173                } else if self.peek_next_keyword(Keyword::Domain) {
174                    Ok(vibesql_ast::Statement::CreateDomain(self.parse_create_domain_statement()?))
175                } else if self.peek_next_keyword(Keyword::Sequence) {
176                    Ok(vibesql_ast::Statement::CreateSequence(
177                        self.parse_create_sequence_statement()?,
178                    ))
179                } else if self.peek_next_keyword(Keyword::Type) {
180                    Ok(vibesql_ast::Statement::CreateType(self.parse_create_type_statement()?))
181                } else if self.peek_next_keyword(Keyword::Collation) {
182                    Ok(vibesql_ast::Statement::CreateCollation(
183                        self.parse_create_collation_statement()?,
184                    ))
185                } else if self.peek_next_keyword(Keyword::Character) {
186                    Ok(vibesql_ast::Statement::CreateCharacterSet(
187                        self.parse_create_character_set_statement()?,
188                    ))
189                } else if self.peek_next_keyword(Keyword::Translation) {
190                    Ok(vibesql_ast::Statement::CreateTranslation(
191                        self.parse_create_translation_statement()?,
192                    ))
193                } else if self.peek_next_keyword(Keyword::View) {
194                    Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?))
195                } else if self.peek_next_keyword(Keyword::Temp)
196                    || self.peek_next_keyword(Keyword::Temporary)
197                {
198                    // CREATE TEMP TABLE or CREATE TEMP VIEW / CREATE TEMPORARY TABLE or VIEW
199                    // Check offset 2 to determine if it's TABLE or VIEW
200                    if matches!(
201                        self.peek_at_offset(2),
202                        Token::Keyword { keyword: Keyword::Table, .. }
203                    ) {
204                        Ok(vibesql_ast::Statement::CreateTable(
205                            self.parse_create_table_statement()?,
206                        ))
207                    } else {
208                        Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?))
209                    }
210                } else if self.peek_next_keyword(Keyword::Trigger) {
211                    Ok(vibesql_ast::Statement::CreateTrigger(
212                        self.parse_create_trigger_statement()?,
213                    ))
214                } else if self.peek_next_keyword(Keyword::Index)
215                    || self.peek_next_keyword(Keyword::Unique)
216                    || self.peek_next_keyword(Keyword::Fulltext)
217                    || self.peek_next_keyword(Keyword::Spatial)
218                {
219                    Ok(vibesql_ast::Statement::CreateIndex(self.parse_create_index_statement()?))
220                } else if self.peek_next_keyword(Keyword::Assertion) {
221                    Ok(vibesql_ast::Statement::CreateAssertion(
222                        self.parse_create_assertion_statement()?,
223                    ))
224                } else if self.peek_next_keyword(Keyword::Procedure) {
225                    Ok(vibesql_ast::Statement::CreateProcedure(
226                        self.parse_create_procedure_statement()?,
227                    ))
228                } else if self.peek_next_keyword(Keyword::Function) {
229                    Ok(vibesql_ast::Statement::CreateFunction(
230                        self.parse_create_function_statement()?,
231                    ))
232                } else {
233                    Err(ParseError {
234                        message:
235                            "Expected TABLE, SCHEMA, ROLE, DOMAIN, SEQUENCE, TYPE, COLLATION, CHARACTER, TRANSLATION, VIEW, TRIGGER, INDEX, ASSERTION, PROCEDURE, or FUNCTION after CREATE"
236                                .to_string(),
237                    })
238                }
239            }
240            Token::Keyword { keyword: Keyword::Drop, .. } => {
241                if self.peek_next_keyword(Keyword::Table) {
242                    Ok(vibesql_ast::Statement::DropTable(self.parse_drop_table_statement()?))
243                } else if self.peek_next_keyword(Keyword::Schema) {
244                    Ok(vibesql_ast::Statement::DropSchema(self.parse_drop_schema_statement()?))
245                } else if self.peek_next_keyword(Keyword::Role) {
246                    Ok(vibesql_ast::Statement::DropRole(self.parse_drop_role_statement()?))
247                } else if self.peek_next_keyword(Keyword::Domain) {
248                    Ok(vibesql_ast::Statement::DropDomain(self.parse_drop_domain_statement()?))
249                } else if self.peek_next_keyword(Keyword::Sequence) {
250                    Ok(vibesql_ast::Statement::DropSequence(self.parse_drop_sequence_statement()?))
251                } else if self.peek_next_keyword(Keyword::Type) {
252                    Ok(vibesql_ast::Statement::DropType(self.parse_drop_type_statement()?))
253                } else if self.peek_next_keyword(Keyword::Collation) {
254                    Ok(vibesql_ast::Statement::DropCollation(
255                        self.parse_drop_collation_statement()?,
256                    ))
257                } else if self.peek_next_keyword(Keyword::Character) {
258                    Ok(vibesql_ast::Statement::DropCharacterSet(
259                        self.parse_drop_character_set_statement()?,
260                    ))
261                } else if self.peek_next_keyword(Keyword::Translation) {
262                    Ok(vibesql_ast::Statement::DropTranslation(
263                        self.parse_drop_translation_statement()?,
264                    ))
265                } else if self.peek_next_keyword(Keyword::View) {
266                    Ok(vibesql_ast::Statement::DropView(self.parse_drop_view_statement()?))
267                } else if self.peek_next_keyword(Keyword::Trigger) {
268                    Ok(vibesql_ast::Statement::DropTrigger(self.parse_drop_trigger_statement()?))
269                } else if self.peek_next_keyword(Keyword::Index) {
270                    Ok(vibesql_ast::Statement::DropIndex(self.parse_drop_index_statement()?))
271                } else if self.peek_next_keyword(Keyword::Assertion) {
272                    Ok(vibesql_ast::Statement::DropAssertion(
273                        self.parse_drop_assertion_statement()?,
274                    ))
275                } else if self.peek_next_keyword(Keyword::Procedure) {
276                    Ok(vibesql_ast::Statement::DropProcedure(
277                        self.parse_drop_procedure_statement()?,
278                    ))
279                } else if self.peek_next_keyword(Keyword::Function) {
280                    Ok(vibesql_ast::Statement::DropFunction(self.parse_drop_function_statement()?))
281                } else {
282                    Err(ParseError {
283                        message:
284                            "Expected TABLE, SCHEMA, ROLE, DOMAIN, SEQUENCE, TYPE, COLLATION, CHARACTER, TRANSLATION, VIEW, TRIGGER, INDEX, ASSERTION, PROCEDURE, or FUNCTION after DROP"
285                                .to_string(),
286                    })
287                }
288            }
289            Token::Keyword { keyword: Keyword::Truncate, .. } => {
290                let truncate_stmt = self.parse_truncate_table_statement()?;
291                Ok(vibesql_ast::Statement::TruncateTable(truncate_stmt))
292            }
293            Token::Keyword { keyword: Keyword::Alter, .. } => {
294                if self.peek_next_keyword(Keyword::Table) {
295                    let alter_stmt = self.parse_alter_table_statement()?;
296                    Ok(vibesql_ast::Statement::AlterTable(alter_stmt))
297                } else if self.peek_next_keyword(Keyword::Sequence) {
298                    let alter_stmt = self.parse_alter_sequence_statement()?;
299                    Ok(vibesql_ast::Statement::AlterSequence(alter_stmt))
300                } else if self.peek_next_keyword(Keyword::Trigger) {
301                    let alter_stmt = self.parse_alter_trigger_statement()?;
302                    Ok(vibesql_ast::Statement::AlterTrigger(alter_stmt))
303                } else {
304                    Err(ParseError {
305                        message: "Expected TABLE, SEQUENCE, or TRIGGER after ALTER".to_string(),
306                    })
307                }
308            }
309            Token::Keyword { keyword: Keyword::Reindex, .. } => {
310                let reindex_stmt = self.parse_reindex_statement()?;
311                Ok(vibesql_ast::Statement::Reindex(reindex_stmt))
312            }
313            Token::Keyword { keyword: Keyword::Analyze, .. } => {
314                let analyze_stmt = self.parse_analyze_statement()?;
315                Ok(vibesql_ast::Statement::Analyze(analyze_stmt))
316            }
317            Token::Keyword { keyword: Keyword::Explain, .. } => {
318                let explain_stmt = self.parse_explain_statement()?;
319                Ok(vibesql_ast::Statement::Explain(explain_stmt))
320            }
321            Token::Keyword { keyword: Keyword::Begin, .. }
322            | Token::Keyword { keyword: Keyword::Start, .. } => {
323                let begin_stmt = self.parse_begin_statement()?;
324                Ok(vibesql_ast::Statement::BeginTransaction(begin_stmt))
325            }
326            Token::Keyword { keyword: Keyword::Commit, .. }
327            | Token::Keyword { keyword: Keyword::End, .. } => {
328                // END is a SQLite alias for COMMIT in transaction context
329                let commit_stmt = self.parse_commit_statement()?;
330                Ok(vibesql_ast::Statement::Commit(commit_stmt))
331            }
332            Token::Keyword { keyword: Keyword::Rollback, .. } => {
333                // Check if this is ROLLBACK TO SAVEPOINT by looking ahead
334                let saved_position = self.position;
335                self.advance(); // consume ROLLBACK
336                if self.peek_keyword(Keyword::To) {
337                    // Reset and parse as ROLLBACK TO SAVEPOINT
338                    self.position = saved_position;
339                    let rollback_to_stmt = self.parse_rollback_to_savepoint_statement()?;
340                    Ok(vibesql_ast::Statement::RollbackToSavepoint(rollback_to_stmt))
341                } else {
342                    // Reset and parse as regular ROLLBACK
343                    self.position = saved_position;
344                    let rollback_stmt = self.parse_rollback_statement()?;
345                    Ok(vibesql_ast::Statement::Rollback(rollback_stmt))
346                }
347            }
348            Token::Keyword { keyword: Keyword::Savepoint, .. } => {
349                let savepoint_stmt = self.parse_savepoint_statement()?;
350                Ok(vibesql_ast::Statement::Savepoint(savepoint_stmt))
351            }
352            Token::Keyword { keyword: Keyword::Release, .. } => {
353                let release_stmt = self.parse_release_savepoint_statement()?;
354                Ok(vibesql_ast::Statement::ReleaseSavepoint(release_stmt))
355            }
356            Token::Keyword { keyword: Keyword::Set, .. } => {
357                // Look ahead to determine which SET statement this is
358                if self.peek_next_keyword(Keyword::Schema) {
359                    let set_stmt = self.parse_set_schema_statement()?;
360                    Ok(vibesql_ast::Statement::SetSchema(set_stmt))
361                } else if self.peek_next_keyword(Keyword::Catalog) {
362                    let set_stmt = schema::parse_set_catalog(self)?;
363                    Ok(vibesql_ast::Statement::SetCatalog(set_stmt))
364                } else if self.peek_next_keyword(Keyword::Names) {
365                    let set_stmt = schema::parse_set_names(self)?;
366                    Ok(vibesql_ast::Statement::SetNames(set_stmt))
367                } else if self.peek_next_keyword(Keyword::Time) {
368                    let set_stmt = schema::parse_set_time_zone(self)?;
369                    Ok(vibesql_ast::Statement::SetTimeZone(set_stmt))
370                } else if self.peek_next_keyword(Keyword::Transaction) {
371                    let set_stmt = self.parse_set_transaction_statement()?;
372                    Ok(vibesql_ast::Statement::SetTransaction(set_stmt))
373                } else if self.peek_next_keyword(Keyword::Local) {
374                    // SET LOCAL TRANSACTION
375                    let set_stmt = self.parse_set_transaction_statement()?;
376                    Ok(vibesql_ast::Statement::SetTransaction(set_stmt))
377                } else {
378                    // Try to parse as SET variable statement (SESSION/GLOBAL or direct variable)
379                    let set_stmt = schema::parse_set_variable(self)?;
380                    Ok(vibesql_ast::Statement::SetVariable(set_stmt))
381                }
382            }
383            Token::Keyword { keyword: Keyword::Grant, .. } => {
384                let grant_stmt = self.parse_grant_statement()?;
385                Ok(vibesql_ast::Statement::Grant(grant_stmt))
386            }
387            Token::Keyword { keyword: Keyword::Revoke, .. } => {
388                let revoke_stmt = self.parse_revoke_statement()?;
389                Ok(vibesql_ast::Statement::Revoke(revoke_stmt))
390            }
391            Token::Keyword { keyword: Keyword::Declare, .. } => {
392                let declare_cursor_stmt = self.parse_declare_cursor_statement()?;
393                Ok(vibesql_ast::Statement::DeclareCursor(declare_cursor_stmt))
394            }
395            Token::Keyword { keyword: Keyword::Open, .. } => {
396                let open_cursor_stmt = self.parse_open_cursor_statement()?;
397                Ok(vibesql_ast::Statement::OpenCursor(open_cursor_stmt))
398            }
399            Token::Keyword { keyword: Keyword::Fetch, .. } => {
400                let fetch_stmt = self.parse_fetch_statement()?;
401                Ok(vibesql_ast::Statement::Fetch(fetch_stmt))
402            }
403            Token::Keyword { keyword: Keyword::Close, .. } => {
404                let close_cursor_stmt = self.parse_close_cursor_statement()?;
405                Ok(vibesql_ast::Statement::CloseCursor(close_cursor_stmt))
406            }
407            Token::Keyword { keyword: Keyword::Call, .. } => {
408                let call_stmt = self.parse_call_statement()?;
409                Ok(vibesql_ast::Statement::Call(call_stmt))
410            }
411            Token::Keyword { keyword: Keyword::Show, .. } => self.parse_show_statement(),
412            Token::Keyword { keyword: Keyword::Describe, .. } => {
413                let describe_stmt = self.parse_describe_statement()?;
414                Ok(vibesql_ast::Statement::Describe(describe_stmt))
415            }
416            Token::Keyword { keyword: Keyword::Prepare, .. } => {
417                let prepare_stmt = self.parse_prepare_statement()?;
418                Ok(vibesql_ast::Statement::Prepare(prepare_stmt))
419            }
420            Token::Keyword { keyword: Keyword::Execute, .. } => {
421                let execute_stmt = self.parse_execute_statement()?;
422                Ok(vibesql_ast::Statement::Execute(execute_stmt))
423            }
424            Token::Keyword { keyword: Keyword::Deallocate, .. } => {
425                let deallocate_stmt = self.parse_deallocate_statement()?;
426                Ok(vibesql_ast::Statement::Deallocate(deallocate_stmt))
427            }
428            Token::Keyword { keyword: Keyword::Pragma, .. } => {
429                let pragma_stmt = self.parse_pragma_statement()?;
430                Ok(vibesql_ast::Statement::Pragma(pragma_stmt))
431            }
432            _ => Err(ParseError { message: self.peek().syntax_error() }),
433        }
434    }
435
436    /// Parse BEGIN [TRANSACTION] statement
437    pub fn parse_begin_statement(&mut self) -> Result<vibesql_ast::BeginStmt, ParseError> {
438        transaction::parse_begin_statement(self)
439    }
440
441    /// Parse COMMIT statement
442    pub fn parse_commit_statement(&mut self) -> Result<vibesql_ast::CommitStmt, ParseError> {
443        transaction::parse_commit_statement(self)
444    }
445
446    /// Parse ROLLBACK statement
447    pub fn parse_rollback_statement(&mut self) -> Result<vibesql_ast::RollbackStmt, ParseError> {
448        transaction::parse_rollback_statement(self)
449    }
450
451    /// Parse ALTER TABLE statement
452    pub fn parse_alter_table_statement(
453        &mut self,
454    ) -> Result<vibesql_ast::AlterTableStmt, ParseError> {
455        alter::parse_alter_table(self)
456    }
457
458    /// Parse SAVEPOINT statement
459    pub fn parse_savepoint_statement(&mut self) -> Result<vibesql_ast::SavepointStmt, ParseError> {
460        transaction::parse_savepoint_statement(self)
461    }
462
463    /// Parse ROLLBACK TO SAVEPOINT statement
464    pub fn parse_rollback_to_savepoint_statement(
465        &mut self,
466    ) -> Result<vibesql_ast::RollbackToSavepointStmt, ParseError> {
467        transaction::parse_rollback_to_savepoint_statement(self)
468    }
469
470    /// Parse RELEASE SAVEPOINT statement
471    pub fn parse_release_savepoint_statement(
472        &mut self,
473    ) -> Result<vibesql_ast::ReleaseSavepointStmt, ParseError> {
474        transaction::parse_release_savepoint_statement(self)
475    }
476
477    /// Parse CREATE SCHEMA statement
478    pub fn parse_create_schema_statement(
479        &mut self,
480    ) -> Result<vibesql_ast::CreateSchemaStmt, ParseError> {
481        schema::parse_create_schema(self)
482    }
483
484    /// Parse DROP SCHEMA statement
485    pub fn parse_drop_schema_statement(
486        &mut self,
487    ) -> Result<vibesql_ast::DropSchemaStmt, ParseError> {
488        schema::parse_drop_schema(self)
489    }
490
491    /// Parse SET SCHEMA statement
492    pub fn parse_set_schema_statement(&mut self) -> Result<vibesql_ast::SetSchemaStmt, ParseError> {
493        schema::parse_set_schema(self)
494    }
495
496    /// Parse GRANT statement
497    pub fn parse_grant_statement(&mut self) -> Result<vibesql_ast::GrantStmt, ParseError> {
498        grant::parse_grant(self)
499    }
500
501    /// Parse REVOKE statement
502    pub fn parse_revoke_statement(&mut self) -> Result<vibesql_ast::RevokeStmt, ParseError> {
503        revoke::parse_revoke(self)
504    }
505
506    /// Parse CREATE ROLE statement
507    pub fn parse_create_role_statement(
508        &mut self,
509    ) -> Result<vibesql_ast::CreateRoleStmt, ParseError> {
510        role::parse_create_role(self)
511    }
512
513    /// Parse DROP ROLE statement
514    pub fn parse_drop_role_statement(&mut self) -> Result<vibesql_ast::DropRoleStmt, ParseError> {
515        role::parse_drop_role(self)
516    }
517
518    // ========================================================================
519    // Advanced SQL Object Parsers (SQL:1999)
520    // ========================================================================
521
522    /// Parse CREATE DOMAIN statement (uses full implementation from domain module)
523    pub fn parse_create_domain_statement(
524        &mut self,
525    ) -> Result<vibesql_ast::CreateDomainStmt, ParseError> {
526        domain::parse_create_domain(self)
527    }
528
529    /// Parse DROP DOMAIN statement (uses full implementation from domain module)
530    pub fn parse_drop_domain_statement(
531        &mut self,
532    ) -> Result<vibesql_ast::DropDomainStmt, ParseError> {
533        domain::parse_drop_domain(self)
534    }
535
536    /// Parse CREATE SEQUENCE statement
537    pub fn parse_create_sequence_statement(
538        &mut self,
539    ) -> Result<vibesql_ast::CreateSequenceStmt, ParseError> {
540        advanced_objects::parse_create_sequence(self)
541    }
542
543    /// Parse DROP SEQUENCE statement
544    pub fn parse_drop_sequence_statement(
545        &mut self,
546    ) -> Result<vibesql_ast::DropSequenceStmt, ParseError> {
547        advanced_objects::parse_drop_sequence(self)
548    }
549
550    /// Parse ALTER SEQUENCE statement
551    pub fn parse_alter_sequence_statement(
552        &mut self,
553    ) -> Result<vibesql_ast::AlterSequenceStmt, ParseError> {
554        advanced_objects::parse_alter_sequence(self)
555    }
556
557    /// Parse CREATE TYPE statement
558    pub fn parse_create_type_statement(
559        &mut self,
560    ) -> Result<vibesql_ast::CreateTypeStmt, ParseError> {
561        advanced_objects::parse_create_type(self)
562    }
563
564    /// Parse SET TRANSACTION statement
565    pub fn parse_set_transaction_statement(
566        &mut self,
567    ) -> Result<vibesql_ast::SetTransactionStmt, ParseError> {
568        // SET keyword
569        self.expect_keyword(Keyword::Set)?;
570
571        // Optional LOCAL keyword
572        let local = self.try_consume_keyword(Keyword::Local);
573
574        // TRANSACTION keyword
575        self.expect_keyword(Keyword::Transaction)?;
576
577        // Parse optional characteristics
578        let mut isolation_level = None;
579        let mut access_mode = None;
580
581        loop {
582            if self.try_consume_keyword(Keyword::Serializable) {
583                isolation_level = Some(vibesql_ast::IsolationLevel::Serializable);
584            } else if self.try_consume_keyword(Keyword::Read) {
585                if self.try_consume_keyword(Keyword::Only) {
586                    access_mode = Some(vibesql_ast::TransactionAccessMode::ReadOnly);
587                } else if self.try_consume_keyword(Keyword::Write) {
588                    access_mode = Some(vibesql_ast::TransactionAccessMode::ReadWrite);
589                } else {
590                    return Err(ParseError {
591                        message: "Expected ONLY or WRITE after READ".to_string(),
592                    });
593                }
594            } else if self.try_consume_keyword(Keyword::Isolation) {
595                self.expect_keyword(Keyword::Level)?;
596                if self.try_consume_keyword(Keyword::Serializable) {
597                    isolation_level = Some(vibesql_ast::IsolationLevel::Serializable);
598                } else {
599                    return Err(ParseError {
600                        message: "Expected SERIALIZABLE after ISOLATION LEVEL".to_string(),
601                    });
602                }
603            } else {
604                break;
605            }
606
607            // Check for comma (more characteristics)
608            if !self.try_consume(&Token::Comma) {
609                break;
610            }
611        }
612
613        Ok(vibesql_ast::SetTransactionStmt { local, isolation_level, access_mode })
614    }
615
616    /// Parse DROP TYPE statement
617    pub fn parse_drop_type_statement(&mut self) -> Result<vibesql_ast::DropTypeStmt, ParseError> {
618        advanced_objects::parse_drop_type(self)
619    }
620
621    /// Parse CREATE COLLATION statement
622    pub fn parse_create_collation_statement(
623        &mut self,
624    ) -> Result<vibesql_ast::CreateCollationStmt, ParseError> {
625        advanced_objects::parse_create_collation(self)
626    }
627
628    /// Parse DROP COLLATION statement
629    pub fn parse_drop_collation_statement(
630        &mut self,
631    ) -> Result<vibesql_ast::DropCollationStmt, ParseError> {
632        advanced_objects::parse_drop_collation(self)
633    }
634
635    /// Parse CREATE CHARACTER SET statement
636    pub fn parse_create_character_set_statement(
637        &mut self,
638    ) -> Result<vibesql_ast::CreateCharacterSetStmt, ParseError> {
639        advanced_objects::parse_create_character_set(self)
640    }
641
642    /// Parse DROP CHARACTER SET statement
643    pub fn parse_drop_character_set_statement(
644        &mut self,
645    ) -> Result<vibesql_ast::DropCharacterSetStmt, ParseError> {
646        advanced_objects::parse_drop_character_set(self)
647    }
648
649    /// Parse CREATE TRANSLATION statement
650    pub fn parse_create_translation_statement(
651        &mut self,
652    ) -> Result<vibesql_ast::CreateTranslationStmt, ParseError> {
653        advanced_objects::parse_create_translation(self)
654    }
655
656    /// Parse DROP TRANSLATION statement
657    pub fn parse_drop_translation_statement(
658        &mut self,
659    ) -> Result<vibesql_ast::DropTranslationStmt, ParseError> {
660        advanced_objects::parse_drop_translation(self)
661    }
662
663    /// Parse CREATE ASSERTION statement
664    pub fn parse_create_assertion_statement(
665        &mut self,
666    ) -> Result<vibesql_ast::CreateAssertionStmt, ParseError> {
667        advanced_objects::parse_create_assertion(self)
668    }
669
670    /// Parse DROP ASSERTION statement
671    pub fn parse_drop_assertion_statement(
672        &mut self,
673    ) -> Result<vibesql_ast::DropAssertionStmt, ParseError> {
674        advanced_objects::parse_drop_assertion(self)
675    }
676
677    /// Parse CREATE PROCEDURE statement
678    pub fn parse_create_procedure_statement(
679        &mut self,
680    ) -> Result<vibesql_ast::CreateProcedureStmt, ParseError> {
681        self.advance(); // consume CREATE
682        self.advance(); // consume PROCEDURE
683        self.parse_create_procedure()
684    }
685
686    /// Parse DROP PROCEDURE statement
687    pub fn parse_drop_procedure_statement(
688        &mut self,
689    ) -> Result<vibesql_ast::DropProcedureStmt, ParseError> {
690        self.advance(); // consume DROP
691        self.advance(); // consume PROCEDURE
692        self.parse_drop_procedure()
693    }
694
695    /// Parse CREATE FUNCTION statement
696    pub fn parse_create_function_statement(
697        &mut self,
698    ) -> Result<vibesql_ast::CreateFunctionStmt, ParseError> {
699        self.advance(); // consume CREATE
700        self.advance(); // consume FUNCTION
701        self.parse_create_function()
702    }
703
704    /// Parse DROP FUNCTION statement
705    pub fn parse_drop_function_statement(
706        &mut self,
707    ) -> Result<vibesql_ast::DropFunctionStmt, ParseError> {
708        self.advance(); // consume DROP
709        self.advance(); // consume FUNCTION
710        self.parse_drop_function()
711    }
712
713    /// Parse CALL statement
714    pub fn parse_call_statement(&mut self) -> Result<vibesql_ast::CallStmt, ParseError> {
715        self.advance(); // consume CALL
716        self.parse_call()
717    }
718
719    /// Parse statement starting with WITH clause (CTEs)
720    ///
721    /// WITH can precede SELECT, INSERT, UPDATE, or DELETE statements.
722    /// This method parses the CTE list first, then dispatches to the appropriate
723    /// statement parser based on the following keyword.
724    fn parse_with_statement(&mut self) -> Result<vibesql_ast::Statement, ParseError> {
725        self.consume_keyword(Keyword::With)?;
726
727        // Check for optional RECURSIVE keyword
728        let recursive = if self.peek_keyword(Keyword::Recursive) {
729            self.consume_keyword(Keyword::Recursive)?;
730            true
731        } else {
732            false
733        };
734
735        // Parse CTE list
736        let cte_list = self.parse_cte_list(recursive)?;
737
738        // Check what statement follows the CTEs
739        match self.peek() {
740            Token::Keyword { keyword: Keyword::Select, .. } => {
741                // For SELECT, we need to reconstruct the statement with the CTEs
742                // The parse_select_statement expects to parse WITH itself, so we need
743                // to create a SelectStmt with the CTEs manually
744                let mut select_stmt = self.parse_select_statement_after_with()?;
745                select_stmt.with_clause = Some(cte_list);
746                Ok(vibesql_ast::Statement::Select(Box::new(select_stmt)))
747            }
748            Token::Keyword { keyword: Keyword::Insert, .. } => {
749                // Parse INSERT with pre-parsed CTEs
750                let insert_stmt = self.parse_insert_statement_with_cte(cte_list)?;
751                Ok(vibesql_ast::Statement::Insert(insert_stmt))
752            }
753            Token::Keyword { keyword: Keyword::Update, .. } => {
754                // Parse UPDATE with pre-parsed CTEs
755                let update_stmt = self.parse_update_statement_with_cte(cte_list)?;
756                Ok(vibesql_ast::Statement::Update(update_stmt))
757            }
758            Token::Keyword { keyword: Keyword::Delete, .. } => {
759                // Parse DELETE with pre-parsed CTEs
760                let delete_stmt = self.parse_delete_statement_with_cte(cte_list)?;
761                Ok(vibesql_ast::Statement::Delete(delete_stmt))
762            }
763            _ => Err(ParseError {
764                message: format!(
765                    "Expected SELECT, INSERT, UPDATE, or DELETE after WITH clause, found {}",
766                    self.peek().syntax_error()
767                ),
768            }),
769        }
770    }
771
772    /// Parse SELECT statement after WITH clause has been consumed
773    /// This is similar to parse_select_statement but expects SELECT (not WITH)
774    fn parse_select_statement_after_with(&mut self) -> Result<vibesql_ast::SelectStmt, ParseError> {
775        self.expect_keyword(Keyword::Select)?;
776
777        // Parse optional set quantifier (DISTINCT or ALL)
778        let distinct = if self.peek_keyword(Keyword::Distinct) {
779            self.consume_keyword(Keyword::Distinct)?;
780            true
781        } else if self.peek_keyword(Keyword::All) {
782            self.consume_keyword(Keyword::All)?;
783            false
784        } else {
785            false
786        };
787
788        // Parse SELECT list
789        let select_list = self.parse_select_list()?;
790
791        // Parse optional INTO clause
792        let (into_table, into_variables) = if self.peek_keyword(Keyword::Into) {
793            self.consume_keyword(Keyword::Into)?;
794            if matches!(self.peek(), Token::UserVariable(_)) {
795                let variables = self.parse_comma_separated_list(|p| match p.peek() {
796                    Token::UserVariable(var_name) => {
797                        let name = var_name.clone();
798                        p.advance();
799                        Ok(name)
800                    }
801                    _ => Err(ParseError {
802                        message: "Expected user variable (@var) in procedural SELECT INTO"
803                            .to_string(),
804                    }),
805                })?;
806                (None, Some(variables))
807            } else {
808                (Some(self.parse_identifier()?), None)
809            }
810        } else {
811            (None, None)
812        };
813
814        // Parse optional FROM clause
815        let from = if self.peek_keyword(Keyword::From) {
816            self.consume_keyword(Keyword::From)?;
817            Some(self.parse_from_clause()?)
818        } else {
819            None
820        };
821
822        // Parse optional WHERE clause
823        let where_clause = if self.peek_keyword(Keyword::Where) {
824            self.consume_keyword(Keyword::Where)?;
825            Some(self.parse_expression()?)
826        } else {
827            None
828        };
829
830        // Parse optional GROUP BY clause
831        let group_by = if self.peek_keyword(Keyword::Group) {
832            self.consume_keyword(Keyword::Group)?;
833            self.expect_keyword(Keyword::By)?;
834            Some(self.parse_group_by_clause()?)
835        } else {
836            None
837        };
838
839        // Parse optional HAVING clause
840        let having = if self.peek_keyword(Keyword::Having) {
841            self.consume_keyword(Keyword::Having)?;
842            Some(self.parse_expression()?)
843        } else {
844            None
845        };
846
847        // Parse set operations (UNION, INTERSECT, EXCEPT)
848        let set_operation = if self.peek_keyword(Keyword::Union)
849            || self.peek_keyword(Keyword::Intersect)
850            || self.peek_keyword(Keyword::Except)
851        {
852            let op = if self.peek_keyword(Keyword::Union) {
853                self.consume_keyword(Keyword::Union)?;
854                vibesql_ast::SetOperator::Union
855            } else if self.peek_keyword(Keyword::Intersect) {
856                self.consume_keyword(Keyword::Intersect)?;
857                vibesql_ast::SetOperator::Intersect
858            } else {
859                self.consume_keyword(Keyword::Except)?;
860                vibesql_ast::SetOperator::Except
861            };
862
863            let all = if self.peek_keyword(Keyword::All) {
864                self.consume_keyword(Keyword::All)?;
865                true
866            } else if self.peek_keyword(Keyword::Distinct) {
867                self.consume_keyword(Keyword::Distinct)?;
868                false
869            } else {
870                false
871            };
872
873            let right = if matches!(self.peek(), Token::LParen) {
874                self.advance();
875                let stmt = if self.peek_keyword(Keyword::Values) {
876                    self.parse_values_statement()?
877                } else {
878                    self.parse_select_statement()?
879                };
880                if !matches!(self.peek(), Token::RParen) {
881                    return Err(ParseError {
882                        message: "Expected ')' after parenthesized statement in set operation"
883                            .to_string(),
884                    });
885                }
886                self.advance();
887                Box::new(stmt)
888            } else if self.peek_keyword(Keyword::Values) {
889                Box::new(self.parse_values_statement()?)
890            } else {
891                Box::new(self.parse_select_statement()?)
892            };
893
894            Some(vibesql_ast::SetOperation { op, all, right })
895        } else {
896            None
897        };
898
899        // Parse ORDER BY
900        let order_by = if self.peek_keyword(Keyword::Order) {
901            self.consume_keyword(Keyword::Order)?;
902            self.expect_keyword(Keyword::By)?;
903
904            let order_items = self.parse_comma_separated_list(|p| {
905                let expr = p.parse_expression()?;
906                let direction = if p.peek_keyword(Keyword::Asc) {
907                    p.consume_keyword(Keyword::Asc)?;
908                    vibesql_ast::OrderDirection::Asc
909                } else if p.peek_keyword(Keyword::Desc) {
910                    p.consume_keyword(Keyword::Desc)?;
911                    vibesql_ast::OrderDirection::Desc
912                } else {
913                    vibesql_ast::OrderDirection::Asc
914                };
915
916                let nulls_order = if p.peek_keyword(Keyword::Nulls) {
917                    p.consume_keyword(Keyword::Nulls)?;
918                    if p.peek_keyword(Keyword::First) {
919                        p.consume_keyword(Keyword::First)?;
920                        Some(vibesql_ast::NullsOrder::First)
921                    } else if p.peek_keyword(Keyword::Last) {
922                        p.consume_keyword(Keyword::Last)?;
923                        Some(vibesql_ast::NullsOrder::Last)
924                    } else {
925                        return Err(ParseError {
926                            message: format!(
927                                "Expected FIRST or LAST after NULLS, found {}",
928                                p.peek().syntax_error()
929                            ),
930                        });
931                    }
932                } else {
933                    None
934                };
935
936                Ok(vibesql_ast::OrderByItem { expr, direction, nulls_order })
937            })?;
938
939            // Check for too many ORDER BY terms (SQLite compatibility)
940            if order_items.len() > MAX_ORDER_BY_TERMS {
941                return Err(ParseError {
942                    message: "too many terms in ORDER BY clause".to_string(),
943                });
944            }
945
946            Some(order_items)
947        } else {
948            None
949        };
950
951        // Parse LIMIT (supports comma syntax)
952        let (limit, offset_from_limit) = if self.peek_keyword(Keyword::Limit) {
953            self.consume_keyword(Keyword::Limit)?;
954            let first_expr = self.parse_expression()?;
955
956            if matches!(self.peek(), Token::Comma) {
957                self.advance();
958                let second_expr = self.parse_expression()?;
959                (Some(second_expr), Some(first_expr))
960            } else {
961                (Some(first_expr), None)
962            }
963        } else {
964            (None, None)
965        };
966
967        // Parse OFFSET
968        let offset = if offset_from_limit.is_some() {
969            offset_from_limit
970        } else if self.peek_keyword(Keyword::Offset) {
971            self.consume_keyword(Keyword::Offset)?;
972            Some(self.parse_expression()?)
973        } else {
974            None
975        };
976
977        // Consume optional semicolon
978        if matches!(self.peek(), Token::Semicolon) {
979            self.advance();
980        }
981
982        Ok(vibesql_ast::SelectStmt {
983            with_clause: None, // Will be set by caller
984            distinct,
985            select_list,
986            into_table,
987            into_variables,
988            from,
989            where_clause,
990            group_by,
991            having,
992            order_by,
993            limit,
994            offset,
995            set_operation,
996            values: None,
997        })
998    }
999}