mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-21 22:44:08 +00:00
into keyword is optional (#473)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
This commit is contained in:
parent
8ef5fc8624
commit
835bb2f9ad
3 changed files with 58 additions and 25 deletions
|
@ -770,6 +770,8 @@ pub enum Statement {
|
||||||
Insert {
|
Insert {
|
||||||
/// Only for Sqlite
|
/// Only for Sqlite
|
||||||
or: Option<SqliteOnConflict>,
|
or: Option<SqliteOnConflict>,
|
||||||
|
/// INTO - optional keyword
|
||||||
|
into: bool,
|
||||||
/// TABLE
|
/// TABLE
|
||||||
table_name: ObjectName,
|
table_name: ObjectName,
|
||||||
/// COLUMNS
|
/// COLUMNS
|
||||||
|
@ -1043,6 +1045,8 @@ pub enum Statement {
|
||||||
Savepoint { name: Ident },
|
Savepoint { name: Ident },
|
||||||
// MERGE INTO statement, based on Snowflake. See <https://docs.snowflake.com/en/sql-reference/sql/merge.html>
|
// MERGE INTO statement, based on Snowflake. See <https://docs.snowflake.com/en/sql-reference/sql/merge.html>
|
||||||
Merge {
|
Merge {
|
||||||
|
// optional INTO keyword
|
||||||
|
into: bool,
|
||||||
// Specifies the table to merge
|
// Specifies the table to merge
|
||||||
table: TableFactor,
|
table: TableFactor,
|
||||||
// Specifies the table or subquery to join with the target table
|
// Specifies the table or subquery to join with the target table
|
||||||
|
@ -1188,6 +1192,7 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
Statement::Insert {
|
Statement::Insert {
|
||||||
or,
|
or,
|
||||||
|
into,
|
||||||
table_name,
|
table_name,
|
||||||
overwrite,
|
overwrite,
|
||||||
partitioned,
|
partitioned,
|
||||||
|
@ -1202,9 +1207,10 @@ impl fmt::Display for Statement {
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"INSERT {act}{tbl} {table_name} ",
|
"INSERT{over}{int}{tbl} {table_name} ",
|
||||||
table_name = table_name,
|
table_name = table_name,
|
||||||
act = if *overwrite { "OVERWRITE" } else { "INTO" },
|
over = if *overwrite { " OVERWRITE" } else { "" },
|
||||||
|
int = if *into { " INTO" } else { "" },
|
||||||
tbl = if *table { " TABLE" } else { "" }
|
tbl = if *table { " TABLE" } else { "" }
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -1755,13 +1761,18 @@ impl fmt::Display for Statement {
|
||||||
write!(f, "{}", name)
|
write!(f, "{}", name)
|
||||||
}
|
}
|
||||||
Statement::Merge {
|
Statement::Merge {
|
||||||
|
into,
|
||||||
table,
|
table,
|
||||||
source,
|
source,
|
||||||
alias,
|
alias,
|
||||||
on,
|
on,
|
||||||
clauses,
|
clauses,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "MERGE INTO {} USING {} ", table, source)?;
|
write!(
|
||||||
|
f,
|
||||||
|
"MERGE{int} {table} USING {source} ",
|
||||||
|
int = if *into { " INTO" } else { "" }
|
||||||
|
)?;
|
||||||
if let Some(a) = alias {
|
if let Some(a) = alias {
|
||||||
write!(f, "as {} ", a)?;
|
write!(f, "as {} ", a)?;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3802,8 +3802,11 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let action = self.expect_one_of_keywords(&[Keyword::INTO, Keyword::OVERWRITE])?;
|
|
||||||
let overwrite = action == Keyword::OVERWRITE;
|
let action = self.parse_one_of_keywords(&[Keyword::INTO, Keyword::OVERWRITE]);
|
||||||
|
let into = action == Some(Keyword::INTO);
|
||||||
|
let overwrite = action == Some(Keyword::OVERWRITE);
|
||||||
|
|
||||||
let local = self.parse_keyword(Keyword::LOCAL);
|
let local = self.parse_keyword(Keyword::LOCAL);
|
||||||
|
|
||||||
if self.parse_keyword(Keyword::DIRECTORY) {
|
if self.parse_keyword(Keyword::DIRECTORY) {
|
||||||
|
@ -3854,6 +3857,7 @@ impl<'a> Parser<'a> {
|
||||||
Ok(Statement::Insert {
|
Ok(Statement::Insert {
|
||||||
or,
|
or,
|
||||||
table_name,
|
table_name,
|
||||||
|
into,
|
||||||
overwrite,
|
overwrite,
|
||||||
partitioned,
|
partitioned,
|
||||||
columns,
|
columns,
|
||||||
|
@ -4266,7 +4270,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_merge(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_merge(&mut self) -> Result<Statement, ParserError> {
|
||||||
self.expect_keyword(Keyword::INTO)?;
|
let into = self.parse_keyword(Keyword::INTO);
|
||||||
|
|
||||||
let table = self.parse_table_factor()?;
|
let table = self.parse_table_factor()?;
|
||||||
|
|
||||||
|
@ -4278,6 +4282,7 @@ impl<'a> Parser<'a> {
|
||||||
let clauses = self.parse_merge_clauses()?;
|
let clauses = self.parse_merge_clauses()?;
|
||||||
|
|
||||||
Ok(Statement::Merge {
|
Ok(Statement::Merge {
|
||||||
|
into,
|
||||||
table,
|
table,
|
||||||
source: Box::new(source),
|
source: Box::new(source),
|
||||||
alias,
|
alias,
|
||||||
|
|
|
@ -41,6 +41,9 @@ fn parse_insert_values() {
|
||||||
let rows1 = vec![row.clone()];
|
let rows1 = vec![row.clone()];
|
||||||
let rows2 = vec![row.clone(), row];
|
let rows2 = vec![row.clone(), row];
|
||||||
|
|
||||||
|
let sql = "INSERT customer VALUES (1, 2, 3)";
|
||||||
|
check_one(sql, "customer", &[], &rows1);
|
||||||
|
|
||||||
let sql = "INSERT INTO customer VALUES (1, 2, 3)";
|
let sql = "INSERT INTO customer VALUES (1, 2, 3)";
|
||||||
check_one(sql, "customer", &[], &rows1);
|
check_one(sql, "customer", &[], &rows1);
|
||||||
|
|
||||||
|
@ -91,16 +94,6 @@ fn parse_insert_values() {
|
||||||
verified_stmt("INSERT INTO customer WITH foo AS (SELECT 1) SELECT * FROM foo UNION VALUES (1)");
|
verified_stmt("INSERT INTO customer WITH foo AS (SELECT 1) SELECT * FROM foo UNION VALUES (1)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_insert_invalid() {
|
|
||||||
let sql = "INSERT public.customer (id, name, active) VALUES (1, 2, 3)";
|
|
||||||
let res = parse_sql_statements(sql);
|
|
||||||
assert_eq!(
|
|
||||||
ParserError::ParserError("Expected one of INTO or OVERWRITE, found: public".to_string()),
|
|
||||||
res.unwrap_err()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_insert_sqlite() {
|
fn parse_insert_sqlite() {
|
||||||
let dialect = SQLiteDialect {};
|
let dialect = SQLiteDialect {};
|
||||||
|
@ -4357,14 +4350,29 @@ fn test_revoke() {
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_merge() {
|
fn parse_merge() {
|
||||||
let sql = "MERGE INTO s.bar AS dest USING (SELECT * FROM s.foo) as stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE";
|
let sql = "MERGE INTO s.bar AS dest USING (SELECT * FROM s.foo) as stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE";
|
||||||
match verified_stmt(sql) {
|
let sql_no_into = "MERGE s.bar AS dest USING (SELECT * FROM s.foo) as stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE";
|
||||||
|
match (verified_stmt(sql), verified_stmt(sql_no_into)) {
|
||||||
|
(
|
||||||
Statement::Merge {
|
Statement::Merge {
|
||||||
|
into,
|
||||||
table,
|
table,
|
||||||
source,
|
source,
|
||||||
alias,
|
alias,
|
||||||
on,
|
on,
|
||||||
clauses,
|
clauses,
|
||||||
} => {
|
},
|
||||||
|
Statement::Merge {
|
||||||
|
into: no_into,
|
||||||
|
table: table_no_into,
|
||||||
|
source: source_no_into,
|
||||||
|
alias: alias_no_into,
|
||||||
|
on: on_no_into,
|
||||||
|
clauses: clauses_no_into,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
assert!(into);
|
||||||
|
assert!(!no_into);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table,
|
table,
|
||||||
TableFactor::Table {
|
TableFactor::Table {
|
||||||
|
@ -4377,6 +4385,8 @@ fn parse_merge() {
|
||||||
with_hints: vec![]
|
with_hints: vec![]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
assert_eq!(table, table_no_into);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
source,
|
source,
|
||||||
Box::new(SetExpr::Query(Box::new(Query {
|
Box::new(SetExpr::Query(Box::new(Query {
|
||||||
|
@ -4411,6 +4421,8 @@ fn parse_merge() {
|
||||||
lock: None
|
lock: None
|
||||||
})))
|
})))
|
||||||
);
|
);
|
||||||
|
assert_eq!(source, source_no_into);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
alias,
|
alias,
|
||||||
Some(TableAlias {
|
Some(TableAlias {
|
||||||
|
@ -4418,6 +4430,8 @@ fn parse_merge() {
|
||||||
columns: vec![]
|
columns: vec![]
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
assert_eq!(alias, alias_no_into);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
on,
|
on,
|
||||||
Box::new(Expr::BinaryOp {
|
Box::new(Expr::BinaryOp {
|
||||||
|
@ -4446,6 +4460,8 @@ fn parse_merge() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
assert_eq!(on, on_no_into);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
clauses,
|
clauses,
|
||||||
vec![
|
vec![
|
||||||
|
@ -4488,7 +4504,8 @@ fn parse_merge() {
|
||||||
},
|
},
|
||||||
MergeClause::MatchedDelete(None)
|
MergeClause::MatchedDelete(None)
|
||||||
]
|
]
|
||||||
)
|
);
|
||||||
|
assert_eq!(clauses, clauses_no_into);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue