mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-19 05:30:19 +00:00
Add support for FROM <filename>
, DELIMITER
, and CSV HEADER
options for COPY
command (#409)
* add additional options for copy command Signed-off-by: password <rbalajis25@gmail.com> * cargo fmt Signed-off-by: password <rbalajis25@gmail.com>
This commit is contained in:
parent
33d4f27bfc
commit
2614576dbf
4 changed files with 118 additions and 5 deletions
|
@ -670,6 +670,12 @@ pub enum Statement {
|
|||
columns: Vec<Ident>,
|
||||
/// VALUES a vector of values to be copied
|
||||
values: Vec<Option<String>>,
|
||||
/// file name of the data to be copied from
|
||||
filename: Option<Ident>,
|
||||
/// delimiter character
|
||||
delimiter: Option<Ident>,
|
||||
/// CSV HEADER
|
||||
csv_header: bool,
|
||||
},
|
||||
/// UPDATE
|
||||
Update {
|
||||
|
@ -1043,13 +1049,28 @@ impl fmt::Display for Statement {
|
|||
table_name,
|
||||
columns,
|
||||
values,
|
||||
delimiter,
|
||||
filename,
|
||||
csv_header,
|
||||
} => {
|
||||
write!(f, "COPY {}", table_name)?;
|
||||
if !columns.is_empty() {
|
||||
write!(f, " ({})", display_comma_separated(columns))?;
|
||||
}
|
||||
write!(f, " FROM stdin; ")?;
|
||||
|
||||
if let Some(name) = filename {
|
||||
write!(f, " FROM {}", name)?;
|
||||
} else {
|
||||
write!(f, " FROM stdin ")?;
|
||||
}
|
||||
if let Some(delimiter) = delimiter {
|
||||
write!(f, " DELIMITER {}", delimiter)?;
|
||||
}
|
||||
if *csv_header {
|
||||
write!(f, " CSV HEADER")?;
|
||||
}
|
||||
if !values.is_empty() {
|
||||
write!(f, ";")?;
|
||||
writeln!(f)?;
|
||||
let mut delim = "";
|
||||
for v in values {
|
||||
|
@ -1062,7 +1083,10 @@ impl fmt::Display for Statement {
|
|||
}
|
||||
}
|
||||
}
|
||||
write!(f, "\n\\.")
|
||||
if filename.is_none() {
|
||||
write!(f, "\n\\.")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Statement::Update {
|
||||
table,
|
||||
|
|
|
@ -173,6 +173,7 @@ define_keywords!(
|
|||
DEFAULT,
|
||||
DELETE,
|
||||
DELIMITED,
|
||||
DELIMITER,
|
||||
DENSE_RANK,
|
||||
DEREF,
|
||||
DESC,
|
||||
|
|
|
@ -2087,13 +2087,44 @@ impl<'a> Parser<'a> {
|
|||
pub fn parse_copy(&mut self) -> Result<Statement, ParserError> {
|
||||
let table_name = self.parse_object_name()?;
|
||||
let columns = self.parse_parenthesized_column_list(Optional)?;
|
||||
self.expect_keywords(&[Keyword::FROM, Keyword::STDIN])?;
|
||||
self.expect_keywords(&[Keyword::FROM])?;
|
||||
let mut filename = None;
|
||||
// check whether data has to be copied form table or std in.
|
||||
if !self.parse_keyword(Keyword::STDIN) {
|
||||
filename = Some(self.parse_identifier()?)
|
||||
}
|
||||
// parse copy options.
|
||||
let mut delimiter = None;
|
||||
let mut csv_header = false;
|
||||
loop {
|
||||
if let Some(keyword) = self.parse_one_of_keywords(&[Keyword::DELIMITER, Keyword::CSV]) {
|
||||
match keyword {
|
||||
Keyword::DELIMITER => {
|
||||
delimiter = Some(self.parse_identifier()?);
|
||||
continue;
|
||||
}
|
||||
Keyword::CSV => {
|
||||
self.expect_keyword(Keyword::HEADER)?;
|
||||
csv_header = true
|
||||
}
|
||||
_ => unreachable!("something wrong while parsing copy statment :("),
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// copy the values from stdin if there is no file to be copied from.
|
||||
let mut values = vec![];
|
||||
if filename.is_none() {
|
||||
self.expect_token(&Token::SemiColon)?;
|
||||
let values = self.parse_tsv();
|
||||
values = self.parse_tsv();
|
||||
}
|
||||
Ok(Statement::Copy {
|
||||
table_name,
|
||||
columns,
|
||||
values,
|
||||
filename,
|
||||
delimiter,
|
||||
csv_header,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -404,6 +404,63 @@ PHP ₱ USD $
|
|||
//assert_eq!(sql, ast.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy() {
|
||||
let stmt = pg().verified_stmt("COPY users FROM 'data.csv'");
|
||||
assert_eq!(
|
||||
stmt,
|
||||
Statement::Copy {
|
||||
table_name: ObjectName(vec!["users".into()]),
|
||||
columns: vec![],
|
||||
filename: Some(Ident {
|
||||
value: "data.csv".to_string(),
|
||||
quote_style: Some('\'')
|
||||
}),
|
||||
values: vec![],
|
||||
delimiter: None,
|
||||
csv_header: false
|
||||
}
|
||||
);
|
||||
|
||||
let stmt = pg().verified_stmt("COPY users FROM 'data.csv' DELIMITER ','");
|
||||
assert_eq!(
|
||||
stmt,
|
||||
Statement::Copy {
|
||||
table_name: ObjectName(vec!["users".into()]),
|
||||
columns: vec![],
|
||||
filename: Some(Ident {
|
||||
value: "data.csv".to_string(),
|
||||
quote_style: Some('\'')
|
||||
}),
|
||||
values: vec![],
|
||||
delimiter: Some(Ident {
|
||||
value: ",".to_string(),
|
||||
quote_style: Some('\'')
|
||||
}),
|
||||
csv_header: false,
|
||||
}
|
||||
);
|
||||
|
||||
let stmt = pg().verified_stmt("COPY users FROM 'data.csv' DELIMITER ',' CSV HEADER");
|
||||
assert_eq!(
|
||||
stmt,
|
||||
Statement::Copy {
|
||||
table_name: ObjectName(vec!["users".into()]),
|
||||
columns: vec![],
|
||||
filename: Some(Ident {
|
||||
value: "data.csv".to_string(),
|
||||
quote_style: Some('\'')
|
||||
}),
|
||||
values: vec![],
|
||||
delimiter: Some(Ident {
|
||||
value: ",".to_string(),
|
||||
quote_style: Some('\'')
|
||||
}),
|
||||
csv_header: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_set() {
|
||||
let stmt = pg_and_generic().verified_stmt("SET a = b");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue