Skip to content

Commit

Permalink
parser: support for the DETACH stmt
Browse files Browse the repository at this point in the history
  • Loading branch information
xNaCly committed Nov 15, 2024
1 parent ea4a6bc commit 43b3aab
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ dynamic correctness. See below for a list of currently implemented features.
| | `create-virtual-table-stmt` | | |
| | `delete-stmt` | | |
| | `delete-stmt-limited` | | |
| | `detach-stmt` | | |
| | `detach-stmt` | `DETACH DATABASE my_database` | |
| | `drop-index-stmt` | | |
| | `drop-table-stmt` | | |
| | `drop-view-stmt` | | |
Expand Down
48 changes: 44 additions & 4 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
rules::Rule,
types::{Keyword, Token, Type},
};
use nodes::{Begin, Commit, Explain, Literal, Node, Rollback, Vacuum};
use nodes::{Begin, Commit, Detach, Explain, Literal, Node, Rollback, Vacuum};

mod nodes;
mod tests;
Expand Down Expand Up @@ -229,10 +229,14 @@ impl<'a> Parser<'a> {
/// see: https://www.sqlite.org/syntax/sql-stmt.html
fn sql_stmt(&mut self) -> Option<Box<dyn Node>> {
match self.cur()?.ttype {
Type::Keyword(Keyword::VACUUM) => self.vacuum_stmt(),
Type::Keyword(Keyword::BEGIN) => self.begin_stmt(),
Type::Keyword(Keyword::COMMIT) | Type::Keyword(Keyword::END) => self.commit_stmt(),
// TODO: add new statement starts here
Type::Keyword(Keyword::DETACH) => self.detach_stmt(),
Type::Keyword(Keyword::ROLLBACK) => self.rollback_stmt(),
Type::Keyword(Keyword::COMMIT) | Type::Keyword(Keyword::END) => self.commit_stmt(),
Type::Keyword(Keyword::BEGIN) => self.begin_stmt(),
Type::Keyword(Keyword::VACUUM) => self.vacuum_stmt(),

// statement should not start with a semicolon 󰚌
Type::Semicolon => {
self.errors.push(self.err(
"Unexpected Token",
Expand Down Expand Up @@ -281,6 +285,42 @@ impl<'a> Parser<'a> {
}
}

// TODO: add new statement function here *_stmt()
// fn $1_stmt(&mut self) -> Option<Box<dyn Node>> {}

fn detach_stmt(&mut self) -> Option<Box<dyn Node>> {
let t = self.cur()?.clone();
self.advance();

// skip optional DATABASE path
if self.is(Type::Keyword(Keyword::DATABASE)) {
self.advance();
}

let r: Option<Box<dyn Node>> = if let Type::Ident(schema_name) = self.cur()?.ttype.clone() {
self.advance();
some_box!(Detach {
t,
schema_name: schema_name.into()
})
} else {
let mut err = self.err(
"Unexpected Token",
&format!(
"DETACH requires Ident(<schema_name>) at this point, got {:?}",
self.cur()?.ttype
),
self.cur()?,
Rule::Syntax,
);
err.doc_url = Some("https://www.sqlite.org/lang_detach.html");
self.errors.push(err);
None
};
self.expect_end("https://www.sqlite.org/lang_detach.html");
r
}

/// https://www.sqlite.org/syntax/rollback-stmt.html
fn rollback_stmt(&mut self) -> Option<Box<dyn Node>> {
let mut rollback = Rollback {
Expand Down
12 changes: 11 additions & 1 deletion src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ EXPLAIN VACUUM;
test_group_pass_assert! {
detach_stmt,

detach:r"DETACH;"=vec![Type::Keyword(Keyword::DETACH)],
detach_schema_name:r"DETACH schema_name;"=vec![Type::Keyword(Keyword::DETACH)],
detach_database_schema_name:r"DETACH DATABASE schema_name;"=vec![Type::Keyword(Keyword::DETACH)]
}
Expand Down Expand Up @@ -186,4 +185,15 @@ mod should_fail {

rollback_transaction_to_literal_save_point:r"ROLLBACK TRANSACTION TO SAVEPOINT 'hello';"
}

test_group_fail! {
detach_stmt,

detach_schema_name_no_semicolon:r"DETACH schema_name",
detach_database_schema_name_no_semicolon:r"DETACH DATABASE schema_name",

detach_schema_no_name:r"DETACH;",
detach_database_no_schema_name:r"DETACH DATABASE;",
detach_schema_literal_instead_of_name:r"DETACH 'this string should not be here';"
}
}

0 comments on commit 43b3aab

Please sign in to comment.