Skip to content

Commit

Permalink
feat: Initial support for DECLARE (cursors)
Browse files Browse the repository at this point in the history
  • Loading branch information
ovr committed May 25, 2022
1 parent 4070f3e commit 736cbce
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,29 @@ pub enum Statement {
/// deleted along with the dropped table
purge: bool,
},
/// DECLARE - Declaring Cursor Variables
///
/// Note: this is a PostgreSQL-specific statement,
/// but may also compatible with other SQL.
Declare {
/// Cursor name
name: ObjectName,
/// Causes the cursor to return data in binary rather than in text format.
binary: bool,
/// None = Not specified
/// Some(true) = INSENSITIVE
/// Some(false) = ASENSITIVE
sensitive: Option<bool>,
/// None = Not specified
/// Some(true) = SCROLL
/// Some(false) = NO SCROLL
scroll: Option<bool>,
/// None = Not specified
/// Some(true) = WITH HOLD, specifies that the cursor can continue to be used after the transaction that created it successfully commits
/// Some(false) = WITHOUT HOLD, specifies that the cursor cannot be used outside of the transaction that created it
hold: Option<bool>,
query: Box<Query>,
},
/// DISCARD [ ALL | PLANS | SEQUENCES | TEMPORARY | TEMP ]
///
/// Note: this is a PostgreSQL-specific statement,
Expand Down Expand Up @@ -1113,6 +1136,48 @@ impl fmt::Display for Statement {
write!(f, "{}", statement)
}
Statement::Query(s) => write!(f, "{}", s),
Statement::Declare {
name,
binary,
sensitive,
scroll,
hold,
query,
} => {
write!(f, "DECLARE {} ", name)?;

if *binary {
write!(f, "BINARY ")?;
}

if let Some(sensitive) = sensitive {
if *sensitive {
write!(f, "INSENSITIVE ")?;
} else {
write!(f, "ASENSITIVE ")?;
}
}

if let Some(scroll) = scroll {
if *scroll {
write!(f, "SCROLL ")?;
} else {
write!(f, "NO SCROLL ")?;
}
}

write!(f, "CURSOR ")?;

if let Some(hold) = hold {
if *hold {
write!(f, "WITH HOLD ")?;
} else {
write!(f, "WITHOUT HOLD ")?;
}
}

write!(f, "FOR {}", query)
}
Statement::Directory {
overwrite,
local,
Expand Down
51 changes: 51 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl<'a> Parser<'a> {
Keyword::CREATE => Ok(self.parse_create()?),
Keyword::DROP => Ok(self.parse_drop()?),
Keyword::DISCARD => Ok(self.parse_discard()?),
Keyword::DECLARE => Ok(self.parse_declare()?),
Keyword::DELETE => Ok(self.parse_delete()?),
Keyword::INSERT => Ok(self.parse_insert()?),
Keyword::UPDATE => Ok(self.parse_update()?),
Expand Down Expand Up @@ -1779,6 +1780,56 @@ impl<'a> Parser<'a> {
})
}

/// DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ]
// CURSOR [ { WITH | WITHOUT } HOLD ] FOR query
pub fn parse_declare(&mut self) -> Result<Statement, ParserError> {
let name = self.parse_object_name()?;

let binary = self.parse_keyword(Keyword::BINARY);
let sensitive = if self.parse_keyword(Keyword::INSENSITIVE) {
Some(true)
} else if self.parse_keyword(Keyword::ASENSITIVE) {
Some(false)
} else {
None
};
let scroll = if self.parse_keyword(Keyword::SCROLL) {
Some(true)
} else if self.parse_keywords(&[Keyword::NO, Keyword::SCROLL]) {
Some(false)
} else {
None
};

self.expect_keyword(Keyword::CURSOR)?;

let hold = match self.parse_one_of_keywords(&[Keyword::WITH, Keyword::WITHOUT]) {
Some(keyword) => {
self.expect_keyword(Keyword::HOLD)?;

match keyword {
Keyword::WITH => Some(true),
Keyword::WITHOUT => Some(false),
_ => unreachable!(),
}
}
None => None,
};

self.expect_keyword(Keyword::FOR)?;

let query = self.parse_query()?;

Ok(Statement::Declare {
name,
binary,
sensitive,
scroll,
hold,
query: Box::new(query),
})
}

pub fn parse_discard(&mut self) -> Result<Statement, ParserError> {
let object_type = if self.parse_keyword(Keyword::ALL) {
DiscardObject::ALL
Expand Down
17 changes: 17 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1467,3 +1467,20 @@ fn pg_and_generic() -> TestedDialects {
dialects: vec![Box::new(PostgreSqlDialect {}), Box::new(GenericDialect {})],
}
}

#[test]
fn parse_declare() {
pg_and_generic()
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" CURSOR WITH HOLD FOR SELECT 1");
pg_and_generic()
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" CURSOR WITHOUT HOLD FOR SELECT 1");
pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" BINARY CURSOR FOR SELECT 1");
pg_and_generic()
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" ASENSITIVE CURSOR FOR SELECT 1");
pg_and_generic()
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" INSENSITIVE CURSOR FOR SELECT 1");
pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" SCROLL CURSOR FOR SELECT 1");
pg_and_generic()
.verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" NO SCROLL CURSOR FOR SELECT 1");
pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" BINARY INSENSITIVE SCROLL CURSOR WITH HOLD FOR SELECT * FROM table_name LIMIT 2222");
}

0 comments on commit 736cbce

Please sign in to comment.