vibesql_parser/parser/
mod.rs

1use std::fmt;
2
3use crate::{keywords::Keyword, lexer::Lexer, token::Token};
4
5mod advanced_objects;
6mod alter;
7mod create;
8mod cursor;
9mod delete;
10mod domain;
11mod drop;
12mod expressions;
13mod grant;
14mod helpers;
15mod index;
16mod insert;
17mod introspection;
18mod prepared;
19mod revoke;
20mod role;
21mod schema;
22mod select;
23mod table_options;
24mod transaction;
25mod trigger;
26mod truncate;
27mod update;
28mod view;
29
30/// Parser error
31#[derive(Debug, Clone, PartialEq)]
32pub struct ParseError {
33    pub message: String,
34}
35
36impl fmt::Display for ParseError {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "Parse error: {}", self.message)
39    }
40}
41
42/// SQL Parser - converts tokens into AST
43pub struct Parser {
44    tokens: Vec<Token>,
45    position: usize,
46    /// Counter for placeholder parameters (?)
47    /// Incremented each time a placeholder is parsed, providing 0-indexed parameter positions
48    placeholder_count: usize,
49}
50
51impl Parser {
52    /// Create a new parser from tokens
53    pub fn new(tokens: Vec<Token>) -> Self {
54        Parser { tokens, position: 0, placeholder_count: 0 }
55    }
56
57    /// Parse a comma-separated list of items using a provided parser function
58    ///
59    /// This is a generic helper that consolidates the common pattern of parsing
60    /// comma-separated lists throughout the parser (e.g., GROUP BY expressions,
61    /// ORDER BY items, identifier lists, etc.)
62    ///
63    /// # Arguments
64    /// * `parse_item` - Closure that parses a single item of type T
65    ///
66    /// # Returns
67    /// * `Ok(Vec<T>)` - Successfully parsed list of items
68    /// * `Err(ParseError)` - Error parsing an item
69    ///
70    /// # Example
71    /// ```text
72    /// // Parse comma-separated expressions (for GROUP BY)
73    /// let exprs = self.parse_comma_separated_list(|p| p.parse_expression())?;
74    ///
75    /// // Parse comma-separated identifiers
76    /// let ids = self.parse_comma_separated_list(|p| p.parse_identifier())?;
77    /// ```
78    pub fn parse_comma_separated_list<T, F>(&mut self, parse_item: F) -> Result<Vec<T>, ParseError>
79    where
80        F: Fn(&mut Self) -> Result<T, ParseError>,
81    {
82        let mut items = Vec::new();
83
84        // Parse first item
85        items.push(parse_item(self)?);
86
87        // Parse remaining items (preceded by commas)
88        while matches!(self.peek(), Token::Comma) {
89            self.advance(); // consume comma
90            items.push(parse_item(self)?);
91        }
92
93        Ok(items)
94    }
95
96    /// Parse SQL input string into a Statement
97    pub fn parse_sql(input: &str) -> Result<vibesql_ast::Statement, ParseError> {
98        let mut lexer = Lexer::new(input);
99        let tokens =
100            lexer.tokenize().map_err(|e| ParseError { message: format!("Lexer error: {}", e) })?;
101
102        let mut parser = Parser::new(tokens);
103        parser.parse_statement()
104    }
105
106    /// Parse a statement
107    pub fn parse_statement(&mut self) -> Result<vibesql_ast::Statement, ParseError> {
108        match self.peek() {
109            Token::Keyword(Keyword::Select) | Token::Keyword(Keyword::With) => {
110                let select_stmt = self.parse_select_statement()?;
111                Ok(vibesql_ast::Statement::Select(Box::new(select_stmt)))
112            }
113            Token::Keyword(Keyword::Insert) => {
114                let insert_stmt = self.parse_insert_statement()?;
115                Ok(vibesql_ast::Statement::Insert(insert_stmt))
116            }
117            Token::Keyword(Keyword::Replace) => {
118                let insert_stmt = self.parse_replace_statement()?;
119                Ok(vibesql_ast::Statement::Insert(insert_stmt))
120            }
121            Token::Keyword(Keyword::Update) => {
122                let update_stmt = self.parse_update_statement()?;
123                Ok(vibesql_ast::Statement::Update(update_stmt))
124            }
125            Token::Keyword(Keyword::Delete) => {
126                let delete_stmt = self.parse_delete_statement()?;
127                Ok(vibesql_ast::Statement::Delete(delete_stmt))
128            }
129            Token::Keyword(Keyword::Create) => {
130                // Check for CREATE OR REPLACE VIEW and CREATE OR REPLACE TEMP/TEMPORARY VIEW
131                if self.peek_next_keyword(Keyword::Or)
132                    && matches!(self.peek_at_offset(2), Token::Keyword(Keyword::Replace))
133                {
134                    // Could be CREATE OR REPLACE VIEW or CREATE OR REPLACE TEMP/TEMPORARY VIEW
135                    if matches!(self.peek_at_offset(3), Token::Keyword(Keyword::View))
136                        || matches!(self.peek_at_offset(3), Token::Keyword(Keyword::Temp))
137                        || matches!(self.peek_at_offset(3), Token::Keyword(Keyword::Temporary))
138                    {
139                        return Ok(vibesql_ast::Statement::CreateView(
140                            self.parse_create_view_statement()?,
141                        ));
142                    }
143                }
144                if self.peek_next_keyword(Keyword::Table) {
145                    Ok(vibesql_ast::Statement::CreateTable(self.parse_create_table_statement()?))
146                } else if self.peek_next_keyword(Keyword::Schema) {
147                    Ok(vibesql_ast::Statement::CreateSchema(self.parse_create_schema_statement()?))
148                } else if self.peek_next_keyword(Keyword::Role) {
149                    Ok(vibesql_ast::Statement::CreateRole(self.parse_create_role_statement()?))
150                } else if self.peek_next_keyword(Keyword::Domain) {
151                    Ok(vibesql_ast::Statement::CreateDomain(self.parse_create_domain_statement()?))
152                } else if self.peek_next_keyword(Keyword::Sequence) {
153                    Ok(vibesql_ast::Statement::CreateSequence(
154                        self.parse_create_sequence_statement()?,
155                    ))
156                } else if self.peek_next_keyword(Keyword::Type) {
157                    Ok(vibesql_ast::Statement::CreateType(self.parse_create_type_statement()?))
158                } else if self.peek_next_keyword(Keyword::Collation) {
159                    Ok(vibesql_ast::Statement::CreateCollation(
160                        self.parse_create_collation_statement()?,
161                    ))
162                } else if self.peek_next_keyword(Keyword::Character) {
163                    Ok(vibesql_ast::Statement::CreateCharacterSet(
164                        self.parse_create_character_set_statement()?,
165                    ))
166                } else if self.peek_next_keyword(Keyword::Translation) {
167                    Ok(vibesql_ast::Statement::CreateTranslation(
168                        self.parse_create_translation_statement()?,
169                    ))
170                } else if self.peek_next_keyword(Keyword::View) {
171                    Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?))
172                } else if self.peek_next_keyword(Keyword::Temp)
173                    || self.peek_next_keyword(Keyword::Temporary)
174                {
175                    // CREATE TEMP VIEW or CREATE TEMPORARY VIEW
176                    Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?))
177                } else if self.peek_next_keyword(Keyword::Trigger) {
178                    Ok(vibesql_ast::Statement::CreateTrigger(
179                        self.parse_create_trigger_statement()?,
180                    ))
181                } else if self.peek_next_keyword(Keyword::Index)
182                    || self.peek_next_keyword(Keyword::Unique)
183                    || self.peek_next_keyword(Keyword::Fulltext)
184                    || self.peek_next_keyword(Keyword::Spatial)
185                {
186                    Ok(vibesql_ast::Statement::CreateIndex(self.parse_create_index_statement()?))
187                } else if self.peek_next_keyword(Keyword::Assertion) {
188                    Ok(vibesql_ast::Statement::CreateAssertion(
189                        self.parse_create_assertion_statement()?,
190                    ))
191                } else if self.peek_next_keyword(Keyword::Procedure) {
192                    Ok(vibesql_ast::Statement::CreateProcedure(
193                        self.parse_create_procedure_statement()?,
194                    ))
195                } else if self.peek_next_keyword(Keyword::Function) {
196                    Ok(vibesql_ast::Statement::CreateFunction(
197                        self.parse_create_function_statement()?,
198                    ))
199                } else {
200                    Err(ParseError {
201                        message:
202                            "Expected TABLE, SCHEMA, ROLE, DOMAIN, SEQUENCE, TYPE, COLLATION, CHARACTER, TRANSLATION, VIEW, TRIGGER, INDEX, ASSERTION, PROCEDURE, or FUNCTION after CREATE"
203                                .to_string(),
204                    })
205                }
206            }
207            Token::Keyword(Keyword::Drop) => {
208                if self.peek_next_keyword(Keyword::Table) {
209                    Ok(vibesql_ast::Statement::DropTable(self.parse_drop_table_statement()?))
210                } else if self.peek_next_keyword(Keyword::Schema) {
211                    Ok(vibesql_ast::Statement::DropSchema(self.parse_drop_schema_statement()?))
212                } else if self.peek_next_keyword(Keyword::Role) {
213                    Ok(vibesql_ast::Statement::DropRole(self.parse_drop_role_statement()?))
214                } else if self.peek_next_keyword(Keyword::Domain) {
215                    Ok(vibesql_ast::Statement::DropDomain(self.parse_drop_domain_statement()?))
216                } else if self.peek_next_keyword(Keyword::Sequence) {
217                    Ok(vibesql_ast::Statement::DropSequence(self.parse_drop_sequence_statement()?))
218                } else if self.peek_next_keyword(Keyword::Type) {
219                    Ok(vibesql_ast::Statement::DropType(self.parse_drop_type_statement()?))
220                } else if self.peek_next_keyword(Keyword::Collation) {
221                    Ok(vibesql_ast::Statement::DropCollation(
222                        self.parse_drop_collation_statement()?,
223                    ))
224                } else if self.peek_next_keyword(Keyword::Character) {
225                    Ok(vibesql_ast::Statement::DropCharacterSet(
226                        self.parse_drop_character_set_statement()?,
227                    ))
228                } else if self.peek_next_keyword(Keyword::Translation) {
229                    Ok(vibesql_ast::Statement::DropTranslation(
230                        self.parse_drop_translation_statement()?,
231                    ))
232                } else if self.peek_next_keyword(Keyword::View) {
233                    Ok(vibesql_ast::Statement::DropView(self.parse_drop_view_statement()?))
234                } else if self.peek_next_keyword(Keyword::Trigger) {
235                    Ok(vibesql_ast::Statement::DropTrigger(self.parse_drop_trigger_statement()?))
236                } else if self.peek_next_keyword(Keyword::Index) {
237                    Ok(vibesql_ast::Statement::DropIndex(self.parse_drop_index_statement()?))
238                } else if self.peek_next_keyword(Keyword::Assertion) {
239                    Ok(vibesql_ast::Statement::DropAssertion(
240                        self.parse_drop_assertion_statement()?,
241                    ))
242                } else if self.peek_next_keyword(Keyword::Procedure) {
243                    Ok(vibesql_ast::Statement::DropProcedure(
244                        self.parse_drop_procedure_statement()?,
245                    ))
246                } else if self.peek_next_keyword(Keyword::Function) {
247                    Ok(vibesql_ast::Statement::DropFunction(self.parse_drop_function_statement()?))
248                } else {
249                    Err(ParseError {
250                        message:
251                            "Expected TABLE, SCHEMA, ROLE, DOMAIN, SEQUENCE, TYPE, COLLATION, CHARACTER, TRANSLATION, VIEW, TRIGGER, INDEX, ASSERTION, PROCEDURE, or FUNCTION after DROP"
252                                .to_string(),
253                    })
254                }
255            }
256            Token::Keyword(Keyword::Truncate) => {
257                let truncate_stmt = self.parse_truncate_table_statement()?;
258                Ok(vibesql_ast::Statement::TruncateTable(truncate_stmt))
259            }
260            Token::Keyword(Keyword::Alter) => {
261                if self.peek_next_keyword(Keyword::Table) {
262                    let alter_stmt = self.parse_alter_table_statement()?;
263                    Ok(vibesql_ast::Statement::AlterTable(alter_stmt))
264                } else if self.peek_next_keyword(Keyword::Sequence) {
265                    let alter_stmt = self.parse_alter_sequence_statement()?;
266                    Ok(vibesql_ast::Statement::AlterSequence(alter_stmt))
267                } else if self.peek_next_keyword(Keyword::Trigger) {
268                    let alter_stmt = self.parse_alter_trigger_statement()?;
269                    Ok(vibesql_ast::Statement::AlterTrigger(alter_stmt))
270                } else {
271                    Err(ParseError {
272                        message: "Expected TABLE, SEQUENCE, or TRIGGER after ALTER".to_string(),
273                    })
274                }
275            }
276            Token::Keyword(Keyword::Reindex) => {
277                let reindex_stmt = self.parse_reindex_statement()?;
278                Ok(vibesql_ast::Statement::Reindex(reindex_stmt))
279            }
280            Token::Keyword(Keyword::Analyze) => {
281                let analyze_stmt = self.parse_analyze_statement()?;
282                Ok(vibesql_ast::Statement::Analyze(analyze_stmt))
283            }
284            Token::Keyword(Keyword::Explain) => {
285                let explain_stmt = self.parse_explain_statement()?;
286                Ok(vibesql_ast::Statement::Explain(explain_stmt))
287            }
288            Token::Keyword(Keyword::Begin) | Token::Keyword(Keyword::Start) => {
289                let begin_stmt = self.parse_begin_statement()?;
290                Ok(vibesql_ast::Statement::BeginTransaction(begin_stmt))
291            }
292            Token::Keyword(Keyword::Commit) => {
293                let commit_stmt = self.parse_commit_statement()?;
294                Ok(vibesql_ast::Statement::Commit(commit_stmt))
295            }
296            Token::Keyword(Keyword::Rollback) => {
297                // Check if this is ROLLBACK TO SAVEPOINT by looking ahead
298                let saved_position = self.position;
299                self.advance(); // consume ROLLBACK
300                if self.peek_keyword(Keyword::To) {
301                    // Reset and parse as ROLLBACK TO SAVEPOINT
302                    self.position = saved_position;
303                    let rollback_to_stmt = self.parse_rollback_to_savepoint_statement()?;
304                    Ok(vibesql_ast::Statement::RollbackToSavepoint(rollback_to_stmt))
305                } else {
306                    // Reset and parse as regular ROLLBACK
307                    self.position = saved_position;
308                    let rollback_stmt = self.parse_rollback_statement()?;
309                    Ok(vibesql_ast::Statement::Rollback(rollback_stmt))
310                }
311            }
312            Token::Keyword(Keyword::Savepoint) => {
313                let savepoint_stmt = self.parse_savepoint_statement()?;
314                Ok(vibesql_ast::Statement::Savepoint(savepoint_stmt))
315            }
316            Token::Keyword(Keyword::Release) => {
317                let release_stmt = self.parse_release_savepoint_statement()?;
318                Ok(vibesql_ast::Statement::ReleaseSavepoint(release_stmt))
319            }
320            Token::Keyword(Keyword::Set) => {
321                // Look ahead to determine which SET statement this is
322                if self.peek_next_keyword(Keyword::Schema) {
323                    let set_stmt = self.parse_set_schema_statement()?;
324                    Ok(vibesql_ast::Statement::SetSchema(set_stmt))
325                } else if self.peek_next_keyword(Keyword::Catalog) {
326                    let set_stmt = schema::parse_set_catalog(self)?;
327                    Ok(vibesql_ast::Statement::SetCatalog(set_stmt))
328                } else if self.peek_next_keyword(Keyword::Names) {
329                    let set_stmt = schema::parse_set_names(self)?;
330                    Ok(vibesql_ast::Statement::SetNames(set_stmt))
331                } else if self.peek_next_keyword(Keyword::Time) {
332                    let set_stmt = schema::parse_set_time_zone(self)?;
333                    Ok(vibesql_ast::Statement::SetTimeZone(set_stmt))
334                } else if self.peek_next_keyword(Keyword::Transaction) {
335                    let set_stmt = self.parse_set_transaction_statement()?;
336                    Ok(vibesql_ast::Statement::SetTransaction(set_stmt))
337                } else if self.peek_next_keyword(Keyword::Local) {
338                    // SET LOCAL TRANSACTION
339                    let set_stmt = self.parse_set_transaction_statement()?;
340                    Ok(vibesql_ast::Statement::SetTransaction(set_stmt))
341                } else {
342                    // Try to parse as SET variable statement (SESSION/GLOBAL or direct variable)
343                    let set_stmt = schema::parse_set_variable(self)?;
344                    Ok(vibesql_ast::Statement::SetVariable(set_stmt))
345                }
346            }
347            Token::Keyword(Keyword::Grant) => {
348                let grant_stmt = self.parse_grant_statement()?;
349                Ok(vibesql_ast::Statement::Grant(grant_stmt))
350            }
351            Token::Keyword(Keyword::Revoke) => {
352                let revoke_stmt = self.parse_revoke_statement()?;
353                Ok(vibesql_ast::Statement::Revoke(revoke_stmt))
354            }
355            Token::Keyword(Keyword::Declare) => {
356                let declare_cursor_stmt = self.parse_declare_cursor_statement()?;
357                Ok(vibesql_ast::Statement::DeclareCursor(declare_cursor_stmt))
358            }
359            Token::Keyword(Keyword::Open) => {
360                let open_cursor_stmt = self.parse_open_cursor_statement()?;
361                Ok(vibesql_ast::Statement::OpenCursor(open_cursor_stmt))
362            }
363            Token::Keyword(Keyword::Fetch) => {
364                let fetch_stmt = self.parse_fetch_statement()?;
365                Ok(vibesql_ast::Statement::Fetch(fetch_stmt))
366            }
367            Token::Keyword(Keyword::Close) => {
368                let close_cursor_stmt = self.parse_close_cursor_statement()?;
369                Ok(vibesql_ast::Statement::CloseCursor(close_cursor_stmt))
370            }
371            Token::Keyword(Keyword::Call) => {
372                let call_stmt = self.parse_call_statement()?;
373                Ok(vibesql_ast::Statement::Call(call_stmt))
374            }
375            Token::Keyword(Keyword::Show) => self.parse_show_statement(),
376            Token::Keyword(Keyword::Describe) => {
377                let describe_stmt = self.parse_describe_statement()?;
378                Ok(vibesql_ast::Statement::Describe(describe_stmt))
379            }
380            Token::Keyword(Keyword::Prepare) => {
381                let prepare_stmt = self.parse_prepare_statement()?;
382                Ok(vibesql_ast::Statement::Prepare(prepare_stmt))
383            }
384            Token::Keyword(Keyword::Execute) => {
385                let execute_stmt = self.parse_execute_statement()?;
386                Ok(vibesql_ast::Statement::Execute(execute_stmt))
387            }
388            Token::Keyword(Keyword::Deallocate) => {
389                let deallocate_stmt = self.parse_deallocate_statement()?;
390                Ok(vibesql_ast::Statement::Deallocate(deallocate_stmt))
391            }
392            _ => {
393                Err(ParseError { message: format!("Expected statement, found {:?}", self.peek()) })
394            }
395        }
396    }
397
398    /// Parse BEGIN [TRANSACTION] statement
399    pub fn parse_begin_statement(&mut self) -> Result<vibesql_ast::BeginStmt, ParseError> {
400        transaction::parse_begin_statement(self)
401    }
402
403    /// Parse COMMIT statement
404    pub fn parse_commit_statement(&mut self) -> Result<vibesql_ast::CommitStmt, ParseError> {
405        transaction::parse_commit_statement(self)
406    }
407
408    /// Parse ROLLBACK statement
409    pub fn parse_rollback_statement(&mut self) -> Result<vibesql_ast::RollbackStmt, ParseError> {
410        transaction::parse_rollback_statement(self)
411    }
412
413    /// Parse ALTER TABLE statement
414    pub fn parse_alter_table_statement(
415        &mut self,
416    ) -> Result<vibesql_ast::AlterTableStmt, ParseError> {
417        alter::parse_alter_table(self)
418    }
419
420    /// Parse SAVEPOINT statement
421    pub fn parse_savepoint_statement(&mut self) -> Result<vibesql_ast::SavepointStmt, ParseError> {
422        transaction::parse_savepoint_statement(self)
423    }
424
425    /// Parse ROLLBACK TO SAVEPOINT statement
426    pub fn parse_rollback_to_savepoint_statement(
427        &mut self,
428    ) -> Result<vibesql_ast::RollbackToSavepointStmt, ParseError> {
429        transaction::parse_rollback_to_savepoint_statement(self)
430    }
431
432    /// Parse RELEASE SAVEPOINT statement
433    pub fn parse_release_savepoint_statement(
434        &mut self,
435    ) -> Result<vibesql_ast::ReleaseSavepointStmt, ParseError> {
436        transaction::parse_release_savepoint_statement(self)
437    }
438
439    /// Parse CREATE SCHEMA statement
440    pub fn parse_create_schema_statement(
441        &mut self,
442    ) -> Result<vibesql_ast::CreateSchemaStmt, ParseError> {
443        schema::parse_create_schema(self)
444    }
445
446    /// Parse DROP SCHEMA statement
447    pub fn parse_drop_schema_statement(
448        &mut self,
449    ) -> Result<vibesql_ast::DropSchemaStmt, ParseError> {
450        schema::parse_drop_schema(self)
451    }
452
453    /// Parse SET SCHEMA statement
454    pub fn parse_set_schema_statement(&mut self) -> Result<vibesql_ast::SetSchemaStmt, ParseError> {
455        schema::parse_set_schema(self)
456    }
457
458    /// Parse GRANT statement
459    pub fn parse_grant_statement(&mut self) -> Result<vibesql_ast::GrantStmt, ParseError> {
460        grant::parse_grant(self)
461    }
462
463    /// Parse REVOKE statement
464    pub fn parse_revoke_statement(&mut self) -> Result<vibesql_ast::RevokeStmt, ParseError> {
465        revoke::parse_revoke(self)
466    }
467
468    /// Parse CREATE ROLE statement
469    pub fn parse_create_role_statement(
470        &mut self,
471    ) -> Result<vibesql_ast::CreateRoleStmt, ParseError> {
472        role::parse_create_role(self)
473    }
474
475    /// Parse DROP ROLE statement
476    pub fn parse_drop_role_statement(&mut self) -> Result<vibesql_ast::DropRoleStmt, ParseError> {
477        role::parse_drop_role(self)
478    }
479
480    // ========================================================================
481    // Advanced SQL Object Parsers (SQL:1999)
482    // ========================================================================
483
484    /// Parse CREATE DOMAIN statement (uses full implementation from domain module)
485    pub fn parse_create_domain_statement(
486        &mut self,
487    ) -> Result<vibesql_ast::CreateDomainStmt, ParseError> {
488        domain::parse_create_domain(self)
489    }
490
491    /// Parse DROP DOMAIN statement (uses full implementation from domain module)
492    pub fn parse_drop_domain_statement(
493        &mut self,
494    ) -> Result<vibesql_ast::DropDomainStmt, ParseError> {
495        domain::parse_drop_domain(self)
496    }
497
498    /// Parse CREATE SEQUENCE statement
499    pub fn parse_create_sequence_statement(
500        &mut self,
501    ) -> Result<vibesql_ast::CreateSequenceStmt, ParseError> {
502        advanced_objects::parse_create_sequence(self)
503    }
504
505    /// Parse DROP SEQUENCE statement
506    pub fn parse_drop_sequence_statement(
507        &mut self,
508    ) -> Result<vibesql_ast::DropSequenceStmt, ParseError> {
509        advanced_objects::parse_drop_sequence(self)
510    }
511
512    /// Parse ALTER SEQUENCE statement
513    pub fn parse_alter_sequence_statement(
514        &mut self,
515    ) -> Result<vibesql_ast::AlterSequenceStmt, ParseError> {
516        advanced_objects::parse_alter_sequence(self)
517    }
518
519    /// Parse CREATE TYPE statement
520    pub fn parse_create_type_statement(
521        &mut self,
522    ) -> Result<vibesql_ast::CreateTypeStmt, ParseError> {
523        advanced_objects::parse_create_type(self)
524    }
525
526    /// Parse SET TRANSACTION statement
527    pub fn parse_set_transaction_statement(
528        &mut self,
529    ) -> Result<vibesql_ast::SetTransactionStmt, ParseError> {
530        // SET keyword
531        self.expect_keyword(Keyword::Set)?;
532
533        // Optional LOCAL keyword
534        let local = self.try_consume_keyword(Keyword::Local);
535
536        // TRANSACTION keyword
537        self.expect_keyword(Keyword::Transaction)?;
538
539        // Parse optional characteristics
540        let mut isolation_level = None;
541        let mut access_mode = None;
542
543        loop {
544            if self.try_consume_keyword(Keyword::Serializable) {
545                isolation_level = Some(vibesql_ast::IsolationLevel::Serializable);
546            } else if self.try_consume_keyword(Keyword::Read) {
547                if self.try_consume_keyword(Keyword::Only) {
548                    access_mode = Some(vibesql_ast::TransactionAccessMode::ReadOnly);
549                } else if self.try_consume_keyword(Keyword::Write) {
550                    access_mode = Some(vibesql_ast::TransactionAccessMode::ReadWrite);
551                } else {
552                    return Err(ParseError {
553                        message: "Expected ONLY or WRITE after READ".to_string(),
554                    });
555                }
556            } else if self.try_consume_keyword(Keyword::Isolation) {
557                self.expect_keyword(Keyword::Level)?;
558                if self.try_consume_keyword(Keyword::Serializable) {
559                    isolation_level = Some(vibesql_ast::IsolationLevel::Serializable);
560                } else {
561                    return Err(ParseError {
562                        message: "Expected SERIALIZABLE after ISOLATION LEVEL".to_string(),
563                    });
564                }
565            } else {
566                break;
567            }
568
569            // Check for comma (more characteristics)
570            if !self.try_consume(&Token::Comma) {
571                break;
572            }
573        }
574
575        Ok(vibesql_ast::SetTransactionStmt { local, isolation_level, access_mode })
576    }
577
578    /// Parse DROP TYPE statement
579    pub fn parse_drop_type_statement(&mut self) -> Result<vibesql_ast::DropTypeStmt, ParseError> {
580        advanced_objects::parse_drop_type(self)
581    }
582
583    /// Parse CREATE COLLATION statement
584    pub fn parse_create_collation_statement(
585        &mut self,
586    ) -> Result<vibesql_ast::CreateCollationStmt, ParseError> {
587        advanced_objects::parse_create_collation(self)
588    }
589
590    /// Parse DROP COLLATION statement
591    pub fn parse_drop_collation_statement(
592        &mut self,
593    ) -> Result<vibesql_ast::DropCollationStmt, ParseError> {
594        advanced_objects::parse_drop_collation(self)
595    }
596
597    /// Parse CREATE CHARACTER SET statement
598    pub fn parse_create_character_set_statement(
599        &mut self,
600    ) -> Result<vibesql_ast::CreateCharacterSetStmt, ParseError> {
601        advanced_objects::parse_create_character_set(self)
602    }
603
604    /// Parse DROP CHARACTER SET statement
605    pub fn parse_drop_character_set_statement(
606        &mut self,
607    ) -> Result<vibesql_ast::DropCharacterSetStmt, ParseError> {
608        advanced_objects::parse_drop_character_set(self)
609    }
610
611    /// Parse CREATE TRANSLATION statement
612    pub fn parse_create_translation_statement(
613        &mut self,
614    ) -> Result<vibesql_ast::CreateTranslationStmt, ParseError> {
615        advanced_objects::parse_create_translation(self)
616    }
617
618    /// Parse DROP TRANSLATION statement
619    pub fn parse_drop_translation_statement(
620        &mut self,
621    ) -> Result<vibesql_ast::DropTranslationStmt, ParseError> {
622        advanced_objects::parse_drop_translation(self)
623    }
624
625    /// Parse CREATE ASSERTION statement
626    pub fn parse_create_assertion_statement(
627        &mut self,
628    ) -> Result<vibesql_ast::CreateAssertionStmt, ParseError> {
629        advanced_objects::parse_create_assertion(self)
630    }
631
632    /// Parse DROP ASSERTION statement
633    pub fn parse_drop_assertion_statement(
634        &mut self,
635    ) -> Result<vibesql_ast::DropAssertionStmt, ParseError> {
636        advanced_objects::parse_drop_assertion(self)
637    }
638
639    /// Parse CREATE PROCEDURE statement
640    pub fn parse_create_procedure_statement(
641        &mut self,
642    ) -> Result<vibesql_ast::CreateProcedureStmt, ParseError> {
643        self.advance(); // consume CREATE
644        self.advance(); // consume PROCEDURE
645        self.parse_create_procedure()
646    }
647
648    /// Parse DROP PROCEDURE statement
649    pub fn parse_drop_procedure_statement(
650        &mut self,
651    ) -> Result<vibesql_ast::DropProcedureStmt, ParseError> {
652        self.advance(); // consume DROP
653        self.advance(); // consume PROCEDURE
654        self.parse_drop_procedure()
655    }
656
657    /// Parse CREATE FUNCTION statement
658    pub fn parse_create_function_statement(
659        &mut self,
660    ) -> Result<vibesql_ast::CreateFunctionStmt, ParseError> {
661        self.advance(); // consume CREATE
662        self.advance(); // consume FUNCTION
663        self.parse_create_function()
664    }
665
666    /// Parse DROP FUNCTION statement
667    pub fn parse_drop_function_statement(
668        &mut self,
669    ) -> Result<vibesql_ast::DropFunctionStmt, ParseError> {
670        self.advance(); // consume DROP
671        self.advance(); // consume FUNCTION
672        self.parse_drop_function()
673    }
674
675    /// Parse CALL statement
676    pub fn parse_call_statement(&mut self) -> Result<vibesql_ast::CallStmt, ParseError> {
677        self.advance(); // consume CALL
678        self.parse_call()
679    }
680}