Skip to main content

linkrs_query/parser/parsing/
transaction_parser.rs

1//! Transaction Statement Parsing Module
2//!
3//! Responsible for parsing transaction-related statements: BEGIN, COMMIT,
4//! ROLLBACK, SAVEPOINT, and RELEASE SAVEPOINT.
5
6use crate::parser::ast::stmt::*;
7use crate::parser::core::error::{ParseError, ParseErrorKind};
8use crate::parser::parsing::parse_context::ParseContext;
9use crate::parser::TokenKind;
10
11/// Transaction Parser
12pub struct TransactionParser;
13
14impl Default for TransactionParser {
15    fn default() -> Self {
16        Self
17    }
18}
19
20impl TransactionParser {
21    pub fn new() -> Self {
22        Self
23    }
24
25    /// Parse BEGIN TRANSACTION statement
26    ///
27    /// Grammar: `BEGIN [TRANSACTION] [READ ONLY | READ WRITE]`
28    pub fn parse_begin_transaction(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
29        let start_span = ctx.current_span();
30        ctx.expect_token(TokenKind::Begin)?;
31
32        if ctx.check_token(TokenKind::Transaction) {
33            ctx.expect_token(TokenKind::Transaction)?;
34        }
35
36        let mut read_only = None;
37        if ctx.check_token(TokenKind::Read) {
38            ctx.expect_token(TokenKind::Read)?;
39            let mode = if ctx.check_token(TokenKind::Only) {
40                ctx.expect_token(TokenKind::Only)?;
41                true
42            } else if ctx.check_token(TokenKind::Write) {
43                ctx.expect_token(TokenKind::Write)?;
44                false
45            } else {
46                let pos = ctx.current_position();
47                return Err(ParseError::new(
48                    ParseErrorKind::UnexpectedToken,
49                    format!(
50                        "Expected READ ONLY or READ WRITE, found {:?}",
51                        ctx.current_token().kind
52                    ),
53                    pos,
54                )
55                .with_expected_tokens(vec!["READ ONLY".to_string(), "READ WRITE".to_string()]));
56            };
57            read_only = Some(mode);
58        }
59
60        let span = ctx.span_since(start_span.start);
61
62        Ok(Stmt::BeginTransaction(BeginTransactionStmt {
63            span,
64            read_only,
65        }))
66    }
67
68    /// Parse COMMIT TRANSACTION statement
69    pub fn parse_commit_transaction(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
70        let start_span = ctx.current_span();
71        ctx.expect_token(TokenKind::Commit)?;
72
73        if ctx.check_token(TokenKind::Transaction) {
74            ctx.expect_token(TokenKind::Transaction)?;
75        }
76
77        let span = ctx.span_since(start_span.start);
78
79        Ok(Stmt::CommitTransaction(CommitTransactionStmt { span }))
80    }
81
82    /// Parse ROLLBACK TRANSACTION statement
83    ///
84    /// Grammar: `ROLLBACK [TRANSACTION] [TO [SAVEPOINT] <savepoint-name>]`.
85    /// The SAVEPOINT keyword is optional; a savepoint literally named
86    /// `savepoint` is unreachable because the name position never accepts
87    /// the reserved word (see `expect_identifier`).
88    pub fn parse_rollback_transaction(
89        &mut self,
90        ctx: &mut ParseContext,
91    ) -> Result<Stmt, ParseError> {
92        let start_span = ctx.current_span();
93        ctx.expect_token(TokenKind::Rollback)?;
94
95        if ctx.check_token(TokenKind::Transaction) {
96            ctx.expect_token(TokenKind::Transaction)?;
97        }
98
99        let savepoint_name = if ctx.check_token(TokenKind::To) {
100            ctx.expect_token(TokenKind::To)?;
101            ctx.match_token(TokenKind::Savepoint);
102            Some(ctx.expect_identifier()?)
103        } else {
104            None
105        };
106
107        let span = ctx.span_since(start_span.start);
108
109        Ok(Stmt::RollbackTransaction(RollbackTransactionStmt {
110            span,
111            savepoint_name,
112        }))
113    }
114
115    /// Parse SAVEPOINT statement
116    ///
117    /// Grammar: `SAVEPOINT <savepoint-name>`
118    pub fn parse_savepoint_statement(
119        &mut self,
120        ctx: &mut ParseContext,
121    ) -> Result<Stmt, ParseError> {
122        let start_span = ctx.current_span();
123        ctx.expect_token(TokenKind::Savepoint)?;
124        let name = ctx.expect_identifier()?;
125        let span = ctx.span_since(start_span.start);
126        Ok(Stmt::Savepoint(SavepointStmt { span, name }))
127    }
128
129    /// Parse RELEASE SAVEPOINT statement
130    ///
131    /// Grammar: `RELEASE SAVEPOINT <savepoint-name>`
132    pub fn parse_release_savepoint(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
133        let start_span = ctx.current_span();
134        ctx.expect_token(TokenKind::Release)?;
135        ctx.expect_token(TokenKind::Savepoint)?;
136        let name = ctx.expect_identifier()?;
137        let span = ctx.span_since(start_span.start);
138        Ok(Stmt::ReleaseSavepoint(ReleaseSavepointStmt { span, name }))
139    }
140}