Skip to content

Commit d361c3a

Browse files
authored
feat: Support CLOSE (cursors) (#515)
1 parent 3f1c642 commit d361c3a

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

src/ast/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,11 @@ pub enum Statement {
804804
/// VALUES a vector of values to be copied
805805
values: Vec<Option<String>>,
806806
},
807+
/// Close - closes the portal underlying an open cursor.
808+
Close {
809+
/// Cursor name
810+
cursor: CloseCursor,
811+
},
807812
/// UPDATE
808813
Update {
809814
/// TABLE
@@ -1393,6 +1398,11 @@ impl fmt::Display for Statement {
13931398
}
13941399
Ok(())
13951400
}
1401+
Statement::Close { cursor } => {
1402+
write!(f, "CLOSE {}", cursor)?;
1403+
1404+
Ok(())
1405+
}
13961406
Statement::CreateDatabase {
13971407
db_name,
13981408
if_not_exists,
@@ -2158,6 +2168,22 @@ impl fmt::Display for FunctionArg {
21582168
}
21592169
}
21602170

2171+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2172+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2173+
pub enum CloseCursor {
2174+
All,
2175+
Specific { name: Ident },
2176+
}
2177+
2178+
impl fmt::Display for CloseCursor {
2179+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2180+
match self {
2181+
CloseCursor::All => write!(f, "ALL"),
2182+
CloseCursor::Specific { name } => write!(f, "{}", name),
2183+
}
2184+
}
2185+
}
2186+
21612187
/// A function call
21622188
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21632189
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

src/parser.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ impl<'a> Parser<'a> {
174174
Keyword::UPDATE => Ok(self.parse_update()?),
175175
Keyword::ALTER => Ok(self.parse_alter()?),
176176
Keyword::COPY => Ok(self.parse_copy()?),
177+
Keyword::CLOSE => Ok(self.parse_close()?),
177178
Keyword::SET => Ok(self.parse_set()?),
178179
Keyword::SHOW => Ok(self.parse_show()?),
179180
Keyword::GRANT => Ok(self.parse_grant()?),
@@ -2563,6 +2564,18 @@ impl<'a> Parser<'a> {
25632564
})
25642565
}
25652566

2567+
pub fn parse_close(&mut self) -> Result<Statement, ParserError> {
2568+
let cursor = if self.parse_keyword(Keyword::ALL) {
2569+
CloseCursor::All
2570+
} else {
2571+
let name = self.parse_identifier()?;
2572+
2573+
CloseCursor::Specific { name }
2574+
};
2575+
2576+
Ok(Statement::Close { cursor })
2577+
}
2578+
25662579
fn parse_copy_option(&mut self) -> Result<CopyOption, ParserError> {
25672580
let ret = match self.parse_one_of_keywords(&[
25682581
Keyword::FORMAT,

tests/sqlparser_common.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
2121
#[macro_use]
2222
mod test_utils;
23+
2324
use matches::assert_matches;
2425
use sqlparser::ast::*;
2526
use sqlparser::dialect::{
@@ -28,6 +29,7 @@ use sqlparser::dialect::{
2829
};
2930
use sqlparser::keywords::ALL_KEYWORDS;
3031
use sqlparser::parser::{Parser, ParserError};
32+
3133
use test_utils::{
3234
all_dialects, expr_from_projection, join, number, only, table, table_alias, TestedDialects,
3335
};
@@ -4944,3 +4946,23 @@ fn parse_discard() {
49444946
_ => unreachable!(),
49454947
}
49464948
}
4949+
4950+
#[test]
4951+
fn parse_cursor() {
4952+
let sql = r#"CLOSE my_cursor"#;
4953+
match verified_stmt(sql) {
4954+
Statement::Close { cursor } => assert_eq!(
4955+
cursor,
4956+
CloseCursor::Specific {
4957+
name: Ident::new("my_cursor"),
4958+
}
4959+
),
4960+
_ => unreachable!(),
4961+
}
4962+
4963+
let sql = r#"CLOSE ALL"#;
4964+
match verified_stmt(sql) {
4965+
Statement::Close { cursor } => assert_eq!(cursor, CloseCursor::All),
4966+
_ => unreachable!(),
4967+
}
4968+
}

0 commit comments

Comments
 (0)