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 truncate;
13mod expressions;
14mod grant;
15mod helpers;
16mod index;
17mod insert;
18mod introspection;
19mod prepared;
20mod revoke;
21mod role;
22mod schema;
23mod select;
24mod table_options;
25mod transaction;
26mod trigger;
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    /// ```ignore
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) && matches!(self.peek_at_offset(2), Token::Keyword(Keyword::Replace)) {
132                    // Could be CREATE OR REPLACE VIEW or CREATE OR REPLACE TEMP/TEMPORARY VIEW
133                    if matches!(self.peek_at_offset(3), Token::Keyword(Keyword::View))
134                        || matches!(self.peek_at_offset(3), Token::Keyword(Keyword::Temp))
135                        || matches!(self.peek_at_offset(3), Token::Keyword(Keyword::Temporary))
136                    {
137                        return Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?));
138                    }
139                }
140                if self.peek_next_keyword(Keyword::Table) {
141                    Ok(vibesql_ast::Statement::CreateTable(self.parse_create_table_statement()?))
142                } else if self.peek_next_keyword(Keyword::Schema) {
143                    Ok(vibesql_ast::Statement::CreateSchema(self.parse_create_schema_statement()?))
144                } else if self.peek_next_keyword(Keyword::Role) {
145                    Ok(vibesql_ast::Statement::CreateRole(self.parse_create_role_statement()?))
146                } else if self.peek_next_keyword(Keyword::Domain) {
147                    Ok(vibesql_ast::Statement::CreateDomain(self.parse_create_domain_statement()?))
148                } else if self.peek_next_keyword(Keyword::Sequence) {
149                    Ok(vibesql_ast::Statement::CreateSequence(self.parse_create_sequence_statement()?))
150                } else if self.peek_next_keyword(Keyword::Type) {
151                    Ok(vibesql_ast::Statement::CreateType(self.parse_create_type_statement()?))
152                } else if self.peek_next_keyword(Keyword::Collation) {
153                    Ok(vibesql_ast::Statement::CreateCollation(self.parse_create_collation_statement()?))
154                } else if self.peek_next_keyword(Keyword::Character) {
155                    Ok(vibesql_ast::Statement::CreateCharacterSet(
156                        self.parse_create_character_set_statement()?,
157                    ))
158                } else if self.peek_next_keyword(Keyword::Translation) {
159                    Ok(vibesql_ast::Statement::CreateTranslation(
160                        self.parse_create_translation_statement()?,
161                    ))
162                } else if self.peek_next_keyword(Keyword::View) {
163                    Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?))
164                } else if self.peek_next_keyword(Keyword::Temp) || self.peek_next_keyword(Keyword::Temporary) {
165                    // CREATE TEMP VIEW or CREATE TEMPORARY VIEW
166                    Ok(vibesql_ast::Statement::CreateView(self.parse_create_view_statement()?))
167                } else if self.peek_next_keyword(Keyword::Trigger) {
168                    Ok(vibesql_ast::Statement::CreateTrigger(self.parse_create_trigger_statement()?))
169                } else if self.peek_next_keyword(Keyword::Index)
170                    || self.peek_next_keyword(Keyword::Unique)
171                    || self.peek_next_keyword(Keyword::Fulltext)
172                    || self.peek_next_keyword(Keyword::Spatial)
173                {
174                    Ok(vibesql_ast::Statement::CreateIndex(self.parse_create_index_statement()?))
175                } else if self.peek_next_keyword(Keyword::Assertion) {
176                    Ok(vibesql_ast::Statement::CreateAssertion(self.parse_create_assertion_statement()?))
177                } else if self.peek_next_keyword(Keyword::Procedure) {
178                    Ok(vibesql_ast::Statement::CreateProcedure(self.parse_create_procedure_statement()?))
179                } else if self.peek_next_keyword(Keyword::Function) {
180                    Ok(vibesql_ast::Statement::CreateFunction(self.parse_create_function_statement()?))
181                } else {
182                    Err(ParseError {
183                        message:
184                            "Expected TABLE, SCHEMA, ROLE, DOMAIN, SEQUENCE, TYPE, COLLATION, CHARACTER, TRANSLATION, VIEW, TRIGGER, INDEX, ASSERTION, PROCEDURE, or FUNCTION after CREATE"
185                                .to_string(),
186                    })
187                }
188            }
189            Token::Keyword(Keyword::Drop) => {
190                if self.peek_next_keyword(Keyword::Table) {
191                    Ok(vibesql_ast::Statement::DropTable(self.parse_drop_table_statement()?))
192                } else if self.peek_next_keyword(Keyword::Schema) {
193                    Ok(vibesql_ast::Statement::DropSchema(self.parse_drop_schema_statement()?))
194                } else if self.peek_next_keyword(Keyword::Role) {
195                    Ok(vibesql_ast::Statement::DropRole(self.parse_drop_role_statement()?))
196                } else if self.peek_next_keyword(Keyword::Domain) {
197                    Ok(vibesql_ast::Statement::DropDomain(self.parse_drop_domain_statement()?))
198                } else if self.peek_next_keyword(Keyword::Sequence) {
199                    Ok(vibesql_ast::Statement::DropSequence(self.parse_drop_sequence_statement()?))
200                } else if self.peek_next_keyword(Keyword::Type) {
201                    Ok(vibesql_ast::Statement::DropType(self.parse_drop_type_statement()?))
202                } else if self.peek_next_keyword(Keyword::Collation) {
203                    Ok(vibesql_ast::Statement::DropCollation(self.parse_drop_collation_statement()?))
204                } else if self.peek_next_keyword(Keyword::Character) {
205                    Ok(vibesql_ast::Statement::DropCharacterSet(self.parse_drop_character_set_statement()?))
206                } else if self.peek_next_keyword(Keyword::Translation) {
207                    Ok(vibesql_ast::Statement::DropTranslation(self.parse_drop_translation_statement()?))
208                } else if self.peek_next_keyword(Keyword::View) {
209                    Ok(vibesql_ast::Statement::DropView(self.parse_drop_view_statement()?))
210                } else if self.peek_next_keyword(Keyword::Trigger) {
211                    Ok(vibesql_ast::Statement::DropTrigger(self.parse_drop_trigger_statement()?))
212                } else if self.peek_next_keyword(Keyword::Index) {
213                    Ok(vibesql_ast::Statement::DropIndex(self.parse_drop_index_statement()?))
214                } else if self.peek_next_keyword(Keyword::Assertion) {
215                    Ok(vibesql_ast::Statement::DropAssertion(self.parse_drop_assertion_statement()?))
216                } else if self.peek_next_keyword(Keyword::Procedure) {
217                    Ok(vibesql_ast::Statement::DropProcedure(self.parse_drop_procedure_statement()?))
218                } else if self.peek_next_keyword(Keyword::Function) {
219                    Ok(vibesql_ast::Statement::DropFunction(self.parse_drop_function_statement()?))
220                } else {
221                    Err(ParseError {
222                        message:
223                            "Expected TABLE, SCHEMA, ROLE, DOMAIN, SEQUENCE, TYPE, COLLATION, CHARACTER, TRANSLATION, VIEW, TRIGGER, INDEX, ASSERTION, PROCEDURE, or FUNCTION after DROP"
224                                .to_string(),
225                    })
226                }
227            }
228            Token::Keyword(Keyword::Truncate) => {
229                let truncate_stmt = self.parse_truncate_table_statement()?;
230                Ok(vibesql_ast::Statement::TruncateTable(truncate_stmt))
231            }
232            Token::Keyword(Keyword::Alter) => {
233                if self.peek_next_keyword(Keyword::Table) {
234                    let alter_stmt = self.parse_alter_table_statement()?;
235                    Ok(vibesql_ast::Statement::AlterTable(alter_stmt))
236                } else if self.peek_next_keyword(Keyword::Sequence) {
237                    let alter_stmt = self.parse_alter_sequence_statement()?;
238                    Ok(vibesql_ast::Statement::AlterSequence(alter_stmt))
239                } else if self.peek_next_keyword(Keyword::Trigger) {
240                    let alter_stmt = self.parse_alter_trigger_statement()?;
241                    Ok(vibesql_ast::Statement::AlterTrigger(alter_stmt))
242                } else {
243                    Err(ParseError {
244                        message: "Expected TABLE, SEQUENCE, or TRIGGER after ALTER".to_string(),
245                    })
246                }
247            }
248            Token::Keyword(Keyword::Reindex) => {
249                let reindex_stmt = self.parse_reindex_statement()?;
250                Ok(vibesql_ast::Statement::Reindex(reindex_stmt))
251            }
252            Token::Keyword(Keyword::Analyze) => {
253                let analyze_stmt = self.parse_analyze_statement()?;
254                Ok(vibesql_ast::Statement::Analyze(analyze_stmt))
255            }
256            Token::Keyword(Keyword::Explain) => {
257                let explain_stmt = self.parse_explain_statement()?;
258                Ok(vibesql_ast::Statement::Explain(explain_stmt))
259            }
260            Token::Keyword(Keyword::Begin) | Token::Keyword(Keyword::Start) => {
261                let begin_stmt = self.parse_begin_statement()?;
262                Ok(vibesql_ast::Statement::BeginTransaction(begin_stmt))
263            }
264            Token::Keyword(Keyword::Commit) => {
265                let commit_stmt = self.parse_commit_statement()?;
266                Ok(vibesql_ast::Statement::Commit(commit_stmt))
267            }
268            Token::Keyword(Keyword::Rollback) => {
269                // Check if this is ROLLBACK TO SAVEPOINT by looking ahead
270                let saved_position = self.position;
271                self.advance(); // consume ROLLBACK
272                if self.peek_keyword(Keyword::To) {
273                    // Reset and parse as ROLLBACK TO SAVEPOINT
274                    self.position = saved_position;
275                    let rollback_to_stmt = self.parse_rollback_to_savepoint_statement()?;
276                    Ok(vibesql_ast::Statement::RollbackToSavepoint(rollback_to_stmt))
277                } else {
278                    // Reset and parse as regular ROLLBACK
279                    self.position = saved_position;
280                    let rollback_stmt = self.parse_rollback_statement()?;
281                    Ok(vibesql_ast::Statement::Rollback(rollback_stmt))
282                }
283            }
284            Token::Keyword(Keyword::Savepoint) => {
285                let savepoint_stmt = self.parse_savepoint_statement()?;
286                Ok(vibesql_ast::Statement::Savepoint(savepoint_stmt))
287            }
288            Token::Keyword(Keyword::Release) => {
289                let release_stmt = self.parse_release_savepoint_statement()?;
290                Ok(vibesql_ast::Statement::ReleaseSavepoint(release_stmt))
291            }
292            Token::Keyword(Keyword::Set) => {
293                // Look ahead to determine which SET statement this is
294                if self.peek_next_keyword(Keyword::Schema) {
295                    let set_stmt = self.parse_set_schema_statement()?;
296                    Ok(vibesql_ast::Statement::SetSchema(set_stmt))
297                } else if self.peek_next_keyword(Keyword::Catalog) {
298                    let set_stmt = schema::parse_set_catalog(self)?;
299                    Ok(vibesql_ast::Statement::SetCatalog(set_stmt))
300                } else if self.peek_next_keyword(Keyword::Names) {
301                    let set_stmt = schema::parse_set_names(self)?;
302                    Ok(vibesql_ast::Statement::SetNames(set_stmt))
303                } else if self.peek_next_keyword(Keyword::Time) {
304                    let set_stmt = schema::parse_set_time_zone(self)?;
305                    Ok(vibesql_ast::Statement::SetTimeZone(set_stmt))
306                } else if self.peek_next_keyword(Keyword::Transaction) {
307                    let set_stmt = self.parse_set_transaction_statement()?;
308                    Ok(vibesql_ast::Statement::SetTransaction(set_stmt))
309                } else if self.peek_next_keyword(Keyword::Local) {
310                    // SET LOCAL TRANSACTION
311                    let set_stmt = self.parse_set_transaction_statement()?;
312                    Ok(vibesql_ast::Statement::SetTransaction(set_stmt))
313                } else {
314                    // Try to parse as SET variable statement (SESSION/GLOBAL or direct variable)
315                    let set_stmt = schema::parse_set_variable(self)?;
316                    Ok(vibesql_ast::Statement::SetVariable(set_stmt))
317                }
318            }
319            Token::Keyword(Keyword::Grant) => {
320                let grant_stmt = self.parse_grant_statement()?;
321                Ok(vibesql_ast::Statement::Grant(grant_stmt))
322            }
323            Token::Keyword(Keyword::Revoke) => {
324                let revoke_stmt = self.parse_revoke_statement()?;
325                Ok(vibesql_ast::Statement::Revoke(revoke_stmt))
326            }
327            Token::Keyword(Keyword::Declare) => {
328                let declare_cursor_stmt = self.parse_declare_cursor_statement()?;
329                Ok(vibesql_ast::Statement::DeclareCursor(declare_cursor_stmt))
330            }
331            Token::Keyword(Keyword::Open) => {
332                let open_cursor_stmt = self.parse_open_cursor_statement()?;
333                Ok(vibesql_ast::Statement::OpenCursor(open_cursor_stmt))
334            }
335            Token::Keyword(Keyword::Fetch) => {
336                let fetch_stmt = self.parse_fetch_statement()?;
337                Ok(vibesql_ast::Statement::Fetch(fetch_stmt))
338            }
339            Token::Keyword(Keyword::Close) => {
340                let close_cursor_stmt = self.parse_close_cursor_statement()?;
341                Ok(vibesql_ast::Statement::CloseCursor(close_cursor_stmt))
342            }
343            Token::Keyword(Keyword::Call) => {
344                let call_stmt = self.parse_call_statement()?;
345                Ok(vibesql_ast::Statement::Call(call_stmt))
346            }
347            Token::Keyword(Keyword::Show) => self.parse_show_statement(),
348            Token::Keyword(Keyword::Describe) => {
349                let describe_stmt = self.parse_describe_statement()?;
350                Ok(vibesql_ast::Statement::Describe(describe_stmt))
351            }
352            Token::Keyword(Keyword::Prepare) => {
353                let prepare_stmt = self.parse_prepare_statement()?;
354                Ok(vibesql_ast::Statement::Prepare(prepare_stmt))
355            }
356            Token::Keyword(Keyword::Execute) => {
357                let execute_stmt = self.parse_execute_statement()?;
358                Ok(vibesql_ast::Statement::Execute(execute_stmt))
359            }
360            Token::Keyword(Keyword::Deallocate) => {
361                let deallocate_stmt = self.parse_deallocate_statement()?;
362                Ok(vibesql_ast::Statement::Deallocate(deallocate_stmt))
363            }
364            _ => {
365                Err(ParseError { message: format!("Expected statement, found {:?}", self.peek()) })
366            }
367        }
368    }
369
370    /// Parse BEGIN [TRANSACTION] statement
371    pub fn parse_begin_statement(&mut self) -> Result<vibesql_ast::BeginStmt, ParseError> {
372        transaction::parse_begin_statement(self)
373    }
374
375    /// Parse COMMIT statement
376    pub fn parse_commit_statement(&mut self) -> Result<vibesql_ast::CommitStmt, ParseError> {
377        transaction::parse_commit_statement(self)
378    }
379
380    /// Parse ROLLBACK statement
381    pub fn parse_rollback_statement(&mut self) -> Result<vibesql_ast::RollbackStmt, ParseError> {
382        transaction::parse_rollback_statement(self)
383    }
384
385    /// Parse ALTER TABLE statement
386    pub fn parse_alter_table_statement(&mut self) -> Result<vibesql_ast::AlterTableStmt, ParseError> {
387        alter::parse_alter_table(self)
388    }
389
390    /// Parse SAVEPOINT statement
391    pub fn parse_savepoint_statement(&mut self) -> Result<vibesql_ast::SavepointStmt, ParseError> {
392        transaction::parse_savepoint_statement(self)
393    }
394
395    /// Parse ROLLBACK TO SAVEPOINT statement
396    pub fn parse_rollback_to_savepoint_statement(
397        &mut self,
398    ) -> Result<vibesql_ast::RollbackToSavepointStmt, ParseError> {
399        transaction::parse_rollback_to_savepoint_statement(self)
400    }
401
402    /// Parse RELEASE SAVEPOINT statement
403    pub fn parse_release_savepoint_statement(
404        &mut self,
405    ) -> Result<vibesql_ast::ReleaseSavepointStmt, ParseError> {
406        transaction::parse_release_savepoint_statement(self)
407    }
408
409    /// Parse CREATE SCHEMA statement
410    pub fn parse_create_schema_statement(&mut self) -> Result<vibesql_ast::CreateSchemaStmt, ParseError> {
411        schema::parse_create_schema(self)
412    }
413
414    /// Parse DROP SCHEMA statement
415    pub fn parse_drop_schema_statement(&mut self) -> Result<vibesql_ast::DropSchemaStmt, ParseError> {
416        schema::parse_drop_schema(self)
417    }
418
419    /// Parse SET SCHEMA statement
420    pub fn parse_set_schema_statement(&mut self) -> Result<vibesql_ast::SetSchemaStmt, ParseError> {
421        schema::parse_set_schema(self)
422    }
423
424    /// Parse GRANT statement
425    pub fn parse_grant_statement(&mut self) -> Result<vibesql_ast::GrantStmt, ParseError> {
426        grant::parse_grant(self)
427    }
428
429    /// Parse REVOKE statement
430    pub fn parse_revoke_statement(&mut self) -> Result<vibesql_ast::RevokeStmt, ParseError> {
431        revoke::parse_revoke(self)
432    }
433
434    /// Parse CREATE ROLE statement
435    pub fn parse_create_role_statement(&mut self) -> Result<vibesql_ast::CreateRoleStmt, ParseError> {
436        role::parse_create_role(self)
437    }
438
439    /// Parse DROP ROLE statement
440    pub fn parse_drop_role_statement(&mut self) -> Result<vibesql_ast::DropRoleStmt, ParseError> {
441        role::parse_drop_role(self)
442    }
443
444    // ========================================================================
445    // Advanced SQL Object Parsers (SQL:1999)
446    // ========================================================================
447
448    /// Parse CREATE DOMAIN statement (uses full implementation from domain module)
449    pub fn parse_create_domain_statement(&mut self) -> Result<vibesql_ast::CreateDomainStmt, ParseError> {
450        domain::parse_create_domain(self)
451    }
452
453    /// Parse DROP DOMAIN statement (uses full implementation from domain module)
454    pub fn parse_drop_domain_statement(&mut self) -> Result<vibesql_ast::DropDomainStmt, ParseError> {
455        domain::parse_drop_domain(self)
456    }
457
458    /// Parse CREATE SEQUENCE statement
459    pub fn parse_create_sequence_statement(
460        &mut self,
461    ) -> Result<vibesql_ast::CreateSequenceStmt, ParseError> {
462        advanced_objects::parse_create_sequence(self)
463    }
464
465    /// Parse DROP SEQUENCE statement
466    pub fn parse_drop_sequence_statement(&mut self) -> Result<vibesql_ast::DropSequenceStmt, ParseError> {
467        advanced_objects::parse_drop_sequence(self)
468    }
469
470    /// Parse ALTER SEQUENCE statement
471    pub fn parse_alter_sequence_statement(&mut self) -> Result<vibesql_ast::AlterSequenceStmt, ParseError> {
472        advanced_objects::parse_alter_sequence(self)
473    }
474
475    /// Parse CREATE TYPE statement
476    pub fn parse_create_type_statement(&mut self) -> Result<vibesql_ast::CreateTypeStmt, ParseError> {
477        advanced_objects::parse_create_type(self)
478    }
479
480    /// Parse SET TRANSACTION statement
481    pub fn parse_set_transaction_statement(
482        &mut self,
483    ) -> Result<vibesql_ast::SetTransactionStmt, ParseError> {
484        // SET keyword
485        self.expect_keyword(Keyword::Set)?;
486
487        // Optional LOCAL keyword
488        let local = self.try_consume_keyword(Keyword::Local);
489
490        // TRANSACTION keyword
491        self.expect_keyword(Keyword::Transaction)?;
492
493        // Parse optional characteristics
494        let mut isolation_level = None;
495        let mut access_mode = None;
496
497        loop {
498            if self.try_consume_keyword(Keyword::Serializable) {
499                isolation_level = Some(vibesql_ast::IsolationLevel::Serializable);
500            } else if self.try_consume_keyword(Keyword::Read) {
501                if self.try_consume_keyword(Keyword::Only) {
502                    access_mode = Some(vibesql_ast::TransactionAccessMode::ReadOnly);
503                } else if self.try_consume_keyword(Keyword::Write) {
504                    access_mode = Some(vibesql_ast::TransactionAccessMode::ReadWrite);
505                } else {
506                    return Err(ParseError {
507                        message: "Expected ONLY or WRITE after READ".to_string(),
508                    });
509                }
510            } else if self.try_consume_keyword(Keyword::Isolation) {
511                self.expect_keyword(Keyword::Level)?;
512                if self.try_consume_keyword(Keyword::Serializable) {
513                    isolation_level = Some(vibesql_ast::IsolationLevel::Serializable);
514                } else {
515                    return Err(ParseError {
516                        message: "Expected SERIALIZABLE after ISOLATION LEVEL".to_string(),
517                    });
518                }
519            } else {
520                break;
521            }
522
523            // Check for comma (more characteristics)
524            if !self.try_consume(&Token::Comma) {
525                break;
526            }
527        }
528
529        Ok(vibesql_ast::SetTransactionStmt { local, isolation_level, access_mode })
530    }
531
532    /// Parse DROP TYPE statement
533    pub fn parse_drop_type_statement(&mut self) -> Result<vibesql_ast::DropTypeStmt, ParseError> {
534        advanced_objects::parse_drop_type(self)
535    }
536
537    /// Parse CREATE COLLATION statement
538    pub fn parse_create_collation_statement(
539        &mut self,
540    ) -> Result<vibesql_ast::CreateCollationStmt, ParseError> {
541        advanced_objects::parse_create_collation(self)
542    }
543
544    /// Parse DROP COLLATION statement
545    pub fn parse_drop_collation_statement(&mut self) -> Result<vibesql_ast::DropCollationStmt, ParseError> {
546        advanced_objects::parse_drop_collation(self)
547    }
548
549    /// Parse CREATE CHARACTER SET statement
550    pub fn parse_create_character_set_statement(
551        &mut self,
552    ) -> Result<vibesql_ast::CreateCharacterSetStmt, ParseError> {
553        advanced_objects::parse_create_character_set(self)
554    }
555
556    /// Parse DROP CHARACTER SET statement
557    pub fn parse_drop_character_set_statement(
558        &mut self,
559    ) -> Result<vibesql_ast::DropCharacterSetStmt, ParseError> {
560        advanced_objects::parse_drop_character_set(self)
561    }
562
563    /// Parse CREATE TRANSLATION statement
564    pub fn parse_create_translation_statement(
565        &mut self,
566    ) -> Result<vibesql_ast::CreateTranslationStmt, ParseError> {
567        advanced_objects::parse_create_translation(self)
568    }
569
570    /// Parse DROP TRANSLATION statement
571    pub fn parse_drop_translation_statement(
572        &mut self,
573    ) -> Result<vibesql_ast::DropTranslationStmt, ParseError> {
574        advanced_objects::parse_drop_translation(self)
575    }
576
577    /// Parse CREATE ASSERTION statement
578    pub fn parse_create_assertion_statement(
579        &mut self,
580    ) -> Result<vibesql_ast::CreateAssertionStmt, ParseError> {
581        advanced_objects::parse_create_assertion(self)
582    }
583
584    /// Parse DROP ASSERTION statement
585    pub fn parse_drop_assertion_statement(&mut self) -> Result<vibesql_ast::DropAssertionStmt, ParseError> {
586        advanced_objects::parse_drop_assertion(self)
587    }
588
589    /// Parse CREATE PROCEDURE statement
590    pub fn parse_create_procedure_statement(
591        &mut self,
592    ) -> Result<vibesql_ast::CreateProcedureStmt, ParseError> {
593        self.advance(); // consume CREATE
594        self.advance(); // consume PROCEDURE
595        self.parse_create_procedure()
596    }
597
598    /// Parse DROP PROCEDURE statement
599    pub fn parse_drop_procedure_statement(
600        &mut self,
601    ) -> Result<vibesql_ast::DropProcedureStmt, ParseError> {
602        self.advance(); // consume DROP
603        self.advance(); // consume PROCEDURE
604        self.parse_drop_procedure()
605    }
606
607    /// Parse CREATE FUNCTION statement
608    pub fn parse_create_function_statement(
609        &mut self,
610    ) -> Result<vibesql_ast::CreateFunctionStmt, ParseError> {
611        self.advance(); // consume CREATE
612        self.advance(); // consume FUNCTION
613        self.parse_create_function()
614    }
615
616    /// Parse DROP FUNCTION statement
617    pub fn parse_drop_function_statement(
618        &mut self,
619    ) -> Result<vibesql_ast::DropFunctionStmt, ParseError> {
620        self.advance(); // consume DROP
621        self.advance(); // consume FUNCTION
622        self.parse_drop_function()
623    }
624
625    /// Parse CALL statement
626    pub fn parse_call_statement(&mut self) -> Result<vibesql_ast::CallStmt, ParseError> {
627        self.advance(); // consume CALL
628        self.parse_call()
629    }
630}