Skip to content

Commit 08d6d82

Browse files
ovrmcheshkov
authored andcommitted
feat: Initial support for DECLARE (cursors)
Can drop this after rebase on commit 3f1c642 "feat: Initial support for DECLARE (cursors) (apache#509)", first released in 0.18.0
1 parent d29cec9 commit 08d6d82

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

src/ast/mod.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,29 @@ pub enum Statement {
911911
/// deleted along with the dropped table
912912
purge: bool,
913913
},
914+
/// DECLARE - Declaring Cursor Variables
915+
///
916+
/// Note: this is a PostgreSQL-specific statement,
917+
/// but may also compatible with other SQL.
918+
Declare {
919+
/// Cursor name
920+
name: Ident,
921+
/// Causes the cursor to return data in binary rather than in text format.
922+
binary: bool,
923+
/// None = Not specified
924+
/// Some(true) = INSENSITIVE
925+
/// Some(false) = ASENSITIVE
926+
sensitive: Option<bool>,
927+
/// None = Not specified
928+
/// Some(true) = SCROLL
929+
/// Some(false) = NO SCROLL
930+
scroll: Option<bool>,
931+
/// None = Not specified
932+
/// Some(true) = WITH HOLD, specifies that the cursor can continue to be used after the transaction that created it successfully commits
933+
/// Some(false) = WITHOUT HOLD, specifies that the cursor cannot be used outside of the transaction that created it
934+
hold: Option<bool>,
935+
query: Box<Query>,
936+
},
914937
/// FETCH - retrieve rows from a query using a cursor
915938
///
916939
/// Note: this is a PostgreSQL-specific statement,
@@ -1132,6 +1155,48 @@ impl fmt::Display for Statement {
11321155
write!(f, "{}", statement)
11331156
}
11341157
Statement::Query(s) => write!(f, "{}", s),
1158+
Statement::Declare {
1159+
name,
1160+
binary,
1161+
sensitive,
1162+
scroll,
1163+
hold,
1164+
query,
1165+
} => {
1166+
write!(f, "DECLARE {} ", name)?;
1167+
1168+
if *binary {
1169+
write!(f, "BINARY ")?;
1170+
}
1171+
1172+
if let Some(sensitive) = sensitive {
1173+
if *sensitive {
1174+
write!(f, "INSENSITIVE ")?;
1175+
} else {
1176+
write!(f, "ASENSITIVE ")?;
1177+
}
1178+
}
1179+
1180+
if let Some(scroll) = scroll {
1181+
if *scroll {
1182+
write!(f, "SCROLL ")?;
1183+
} else {
1184+
write!(f, "NO SCROLL ")?;
1185+
}
1186+
}
1187+
1188+
write!(f, "CURSOR ")?;
1189+
1190+
if let Some(hold) = hold {
1191+
if *hold {
1192+
write!(f, "WITH HOLD ")?;
1193+
} else {
1194+
write!(f, "WITHOUT HOLD ")?;
1195+
}
1196+
}
1197+
1198+
write!(f, "FOR {}", query)
1199+
}
11351200
Statement::Fetch {
11361201
name,
11371202
direction,

src/parser.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ impl<'a> Parser<'a> {
167167
Keyword::CREATE => Ok(self.parse_create()?),
168168
Keyword::DROP => Ok(self.parse_drop()?),
169169
Keyword::DISCARD => Ok(self.parse_discard()?),
170+
Keyword::DECLARE => Ok(self.parse_declare()?),
170171
Keyword::FETCH => Ok(self.parse_fetch_statement()?),
171172
Keyword::DELETE => Ok(self.parse_delete()?),
172173
Keyword::INSERT => Ok(self.parse_insert()?),
@@ -1794,6 +1795,56 @@ impl<'a> Parser<'a> {
17941795
})
17951796
}
17961797

1798+
/// DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ]
1799+
// CURSOR [ { WITH | WITHOUT } HOLD ] FOR query
1800+
pub fn parse_declare(&mut self) -> Result<Statement, ParserError> {
1801+
let name = self.parse_identifier()?;
1802+
1803+
let binary = self.parse_keyword(Keyword::BINARY);
1804+
let sensitive = if self.parse_keyword(Keyword::INSENSITIVE) {
1805+
Some(true)
1806+
} else if self.parse_keyword(Keyword::ASENSITIVE) {
1807+
Some(false)
1808+
} else {
1809+
None
1810+
};
1811+
let scroll = if self.parse_keyword(Keyword::SCROLL) {
1812+
Some(true)
1813+
} else if self.parse_keywords(&[Keyword::NO, Keyword::SCROLL]) {
1814+
Some(false)
1815+
} else {
1816+
None
1817+
};
1818+
1819+
self.expect_keyword(Keyword::CURSOR)?;
1820+
1821+
let hold = match self.parse_one_of_keywords(&[Keyword::WITH, Keyword::WITHOUT]) {
1822+
Some(keyword) => {
1823+
self.expect_keyword(Keyword::HOLD)?;
1824+
1825+
match keyword {
1826+
Keyword::WITH => Some(true),
1827+
Keyword::WITHOUT => Some(false),
1828+
_ => unreachable!(),
1829+
}
1830+
}
1831+
None => None,
1832+
};
1833+
1834+
self.expect_keyword(Keyword::FOR)?;
1835+
1836+
let query = self.parse_query()?;
1837+
1838+
Ok(Statement::Declare {
1839+
name,
1840+
binary,
1841+
sensitive,
1842+
scroll,
1843+
hold,
1844+
query: Box::new(query),
1845+
})
1846+
}
1847+
17971848
// FETCH [ direction { FROM | IN } ] cursor INTO target;
17981849
pub fn parse_fetch_statement(&mut self) -> Result<Statement, ParserError> {
17991850
let direction = if self.parse_keyword(Keyword::NEXT) {

tests/sqlparser_postgres.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,23 @@ fn parse_escaped_literal_string() {
15061506
);
15071507
}
15081508

1509+
#[test]
1510+
fn parse_declare() {
1511+
pg_and_generic()
1512+
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" CURSOR WITH HOLD FOR SELECT 1");
1513+
pg_and_generic()
1514+
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" CURSOR WITHOUT HOLD FOR SELECT 1");
1515+
pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" BINARY CURSOR FOR SELECT 1");
1516+
pg_and_generic()
1517+
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" ASENSITIVE CURSOR FOR SELECT 1");
1518+
pg_and_generic()
1519+
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" INSENSITIVE CURSOR FOR SELECT 1");
1520+
pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" SCROLL CURSOR FOR SELECT 1");
1521+
pg_and_generic()
1522+
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" NO SCROLL CURSOR FOR SELECT 1");
1523+
pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" BINARY INSENSITIVE SCROLL CURSOR WITH HOLD FOR SELECT * FROM table_name LIMIT 2222");
1524+
}
1525+
15091526
#[test]
15101527
fn parse_fetch() {
15111528
pg_and_generic().verified_stmt("FETCH 2048 IN \"SQL_CUR0x7fa44801bc00\"");

0 commit comments

Comments
 (0)