mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 23:14:07 +00:00
Support Unload
statement (#1150)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
4d1eecd0fc
commit
e2ce324722
4 changed files with 96 additions and 1 deletions
|
@ -2547,6 +2547,16 @@ pub enum Statement {
|
|||
/// ```
|
||||
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
|
||||
UnlockTables,
|
||||
/// ```sql
|
||||
/// UNLOAD(statement) TO <destination> [ WITH options ]
|
||||
/// ```
|
||||
/// See Redshift <https://docs.aws.amazon.com/redshift/latest/dg/r_UNLOAD.html> and
|
||||
// Athena <https://docs.aws.amazon.com/athena/latest/ug/unload.html>
|
||||
Unload {
|
||||
query: Box<Query>,
|
||||
to: Ident,
|
||||
with: Vec<SqlOption>,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for Statement {
|
||||
|
@ -4060,6 +4070,15 @@ impl fmt::Display for Statement {
|
|||
Statement::UnlockTables => {
|
||||
write!(f, "UNLOCK TABLES")
|
||||
}
|
||||
Statement::Unload { query, to, with } => {
|
||||
write!(f, "UNLOAD({query}) TO {to}")?;
|
||||
|
||||
if !with.is_empty() {
|
||||
write!(f, " WITH ({})", display_comma_separated(with))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -689,6 +689,7 @@ define_keywords!(
|
|||
UNION,
|
||||
UNIQUE,
|
||||
UNKNOWN,
|
||||
UNLOAD,
|
||||
UNLOCK,
|
||||
UNLOGGED,
|
||||
UNNEST,
|
||||
|
|
|
@ -516,6 +516,7 @@ impl<'a> Parser<'a> {
|
|||
Keyword::MERGE => Ok(self.parse_merge()?),
|
||||
// `PRAGMA` is sqlite specific https://www.sqlite.org/pragma.html
|
||||
Keyword::PRAGMA => Ok(self.parse_pragma()?),
|
||||
Keyword::UNLOAD => Ok(self.parse_unload()?),
|
||||
// `INSTALL` is duckdb specific https://duckdb.org/docs/extensions/overview
|
||||
Keyword::INSTALL if dialect_of!(self is DuckDbDialect | GenericDialect) => {
|
||||
Ok(self.parse_install()?)
|
||||
|
@ -524,7 +525,6 @@ impl<'a> Parser<'a> {
|
|||
Keyword::LOAD if dialect_of!(self is DuckDbDialect | GenericDialect) => {
|
||||
Ok(self.parse_load()?)
|
||||
}
|
||||
|
||||
_ => self.expected("an SQL statement", next_token),
|
||||
},
|
||||
Token::LParen => {
|
||||
|
@ -8947,6 +8947,23 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn parse_unload(&mut self) -> Result<Statement, ParserError> {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
let query = self.parse_query()?;
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
||||
self.expect_keyword(Keyword::TO)?;
|
||||
let to = self.parse_identifier(false)?;
|
||||
|
||||
let with_options = self.parse_options(Keyword::WITH)?;
|
||||
|
||||
Ok(Statement::Unload {
|
||||
query: Box::new(query),
|
||||
to,
|
||||
with: with_options,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_merge_clauses(&mut self) -> Result<Vec<MergeClause>, ParserError> {
|
||||
let mut clauses: Vec<MergeClause> = vec![];
|
||||
loop {
|
||||
|
|
|
@ -8434,6 +8434,64 @@ fn parse_binary_operators_without_whitespace() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_unload() {
|
||||
let unload = verified_stmt("UNLOAD(SELECT cola FROM tab) TO 's3://...' WITH (format = 'AVRO')");
|
||||
assert_eq!(
|
||||
unload,
|
||||
Statement::Unload {
|
||||
query: Box::new(Query {
|
||||
body: Box::new(SetExpr::Select(Box::new(Select {
|
||||
distinct: None,
|
||||
top: None,
|
||||
projection: vec![UnnamedExpr(Expr::Identifier(Ident::new("cola"))),],
|
||||
into: None,
|
||||
from: vec![TableWithJoins {
|
||||
relation: TableFactor::Table {
|
||||
name: ObjectName(vec![Ident::new("tab")]),
|
||||
alias: None,
|
||||
args: None,
|
||||
with_hints: vec![],
|
||||
version: None,
|
||||
partitions: vec![],
|
||||
},
|
||||
joins: vec![],
|
||||
}],
|
||||
lateral_views: vec![],
|
||||
selection: None,
|
||||
group_by: GroupByExpr::Expressions(vec![]),
|
||||
cluster_by: vec![],
|
||||
distribute_by: vec![],
|
||||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
}))),
|
||||
with: None,
|
||||
limit: None,
|
||||
limit_by: vec![],
|
||||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
order_by: vec![],
|
||||
}),
|
||||
to: Ident {
|
||||
value: "s3://...".to_string(),
|
||||
quote_style: Some('\'')
|
||||
},
|
||||
with: vec![SqlOption {
|
||||
name: Ident {
|
||||
value: "format".to_string(),
|
||||
quote_style: None
|
||||
},
|
||||
value: Expr::Value(Value::SingleQuotedString("AVRO".to_string()))
|
||||
}]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_savepoint() {
|
||||
match verified_stmt("SAVEPOINT test1") {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue