Skip to content

Commit b1a4556

Browse files
committed
feat: Support CLOSE (cursors)
1 parent 93781d7 commit b1a4556

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
@@ -770,6 +770,11 @@ pub enum Statement {
770770
/// VALUES a vector of values to be copied
771771
values: Vec<Option<String>>,
772772
},
773+
/// Close - closes the portal underlying an open cursor.
774+
Close {
775+
/// Cursor name
776+
cursor: CloseCursor,
777+
},
773778
/// UPDATE
774779
Update {
775780
/// TABLE
@@ -1363,6 +1368,11 @@ impl fmt::Display for Statement {
13631368
}
13641369
Ok(())
13651370
}
1371+
Statement::Close { cursor } => {
1372+
write!(f, "CLOSE {}", cursor)?;
1373+
1374+
Ok(())
1375+
}
13661376
Statement::CreateDatabase {
13671377
db_name,
13681378
if_not_exists,
@@ -2178,6 +2188,22 @@ impl fmt::Display for FunctionArg {
21782188
}
21792189
}
21802190

2191+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2192+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2193+
pub enum CloseCursor {
2194+
All,
2195+
Specific { name: Ident },
2196+
}
2197+
2198+
impl fmt::Display for CloseCursor {
2199+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2200+
match self {
2201+
CloseCursor::All => write!(f, "ALL"),
2202+
CloseCursor::Specific { name } => write!(f, "{}", name),
2203+
}
2204+
}
2205+
}
2206+
21812207
/// A function call
21822208
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21832209
#[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()?),
@@ -2522,6 +2523,18 @@ impl<'a> Parser<'a> {
25222523
})
25232524
}
25242525

2526+
pub fn parse_close(&mut self) -> Result<Statement, ParserError> {
2527+
let cursor = if self.parse_keyword(Keyword::ALL) {
2528+
CloseCursor::All
2529+
} else {
2530+
let name = self.parse_identifier()?;
2531+
2532+
CloseCursor::Specific { name }
2533+
};
2534+
2535+
Ok(Statement::Close { cursor })
2536+
}
2537+
25252538
fn parse_copy_option(&mut self) -> Result<CopyOption, ParserError> {
25262539
let ret = match self.parse_one_of_keywords(&[
25272540
Keyword::FORMAT,

tests/sqlparser_common.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
2121
#[macro_use]
2222
mod test_utils;
23+
2324
use matches::assert_matches;
2425
use sqlparser::ast::*;
2526
use sqlparser::dialect::{
2627
AnsiDialect, GenericDialect, MsSqlDialect, PostgreSqlDialect, SQLiteDialect, SnowflakeDialect,
2728
};
2829
use sqlparser::keywords::ALL_KEYWORDS;
2930
use sqlparser::parser::{Parser, ParserError};
31+
3032
use test_utils::{
3133
all_dialects, expr_from_projection, join, number, only, table, table_alias, TestedDialects,
3234
};
@@ -4779,3 +4781,23 @@ fn parse_discard() {
47794781
_ => unreachable!(),
47804782
}
47814783
}
4784+
4785+
#[test]
4786+
fn parse_cursor() {
4787+
let sql = r#"CLOSE my_cursor"#;
4788+
match verified_stmt(sql) {
4789+
Statement::Close { cursor } => assert_eq!(
4790+
cursor,
4791+
CloseCursor::Specific {
4792+
name: Ident::new("my_cursor"),
4793+
}
4794+
),
4795+
_ => unreachable!(),
4796+
}
4797+
4798+
let sql = r#"CLOSE ALL"#;
4799+
match verified_stmt(sql) {
4800+
Statement::Close { cursor } => assert_eq!(cursor, CloseCursor::All),
4801+
_ => unreachable!(),
4802+
}
4803+
}

0 commit comments

Comments
 (0)