mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-08 01:15:00 +00:00
Add support for MySQL's INSERT INTO ... SET syntax (#1641)
This commit is contained in:
parent
4c6af0ae4f
commit
8cfc46277f
7 changed files with 43 additions and 20 deletions
|
@ -32,8 +32,8 @@ use sqlparser_derive::{Visit, VisitMut};
|
||||||
pub use super::ddl::{ColumnDef, TableConstraint};
|
pub use super::ddl::{ColumnDef, TableConstraint};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
display_comma_separated, display_separated, ClusteredBy, CommentDef, Expr, FileFormat,
|
display_comma_separated, display_separated, Assignment, ClusteredBy, CommentDef, Expr,
|
||||||
FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident,
|
FileFormat, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident,
|
||||||
InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OneOrManyWithParens,
|
InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OneOrManyWithParens,
|
||||||
OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption, SqliteOnConflict, TableEngine,
|
OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption, SqliteOnConflict, TableEngine,
|
||||||
TableWithJoins, Tag, WrappedCollection,
|
TableWithJoins, Tag, WrappedCollection,
|
||||||
|
@ -480,6 +480,9 @@ pub struct Insert {
|
||||||
pub overwrite: bool,
|
pub overwrite: bool,
|
||||||
/// A SQL query that specifies what to insert
|
/// A SQL query that specifies what to insert
|
||||||
pub source: Option<Box<Query>>,
|
pub source: Option<Box<Query>>,
|
||||||
|
/// MySQL `INSERT INTO ... SET`
|
||||||
|
/// See: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
|
||||||
|
pub assignments: Vec<Assignment>,
|
||||||
/// partitioned insert (Hive)
|
/// partitioned insert (Hive)
|
||||||
pub partitioned: Option<Vec<Expr>>,
|
pub partitioned: Option<Vec<Expr>>,
|
||||||
/// Columns defined after PARTITION
|
/// Columns defined after PARTITION
|
||||||
|
@ -545,9 +548,10 @@ impl Display for Insert {
|
||||||
|
|
||||||
if let Some(source) = &self.source {
|
if let Some(source) = &self.source {
|
||||||
write!(f, "{source}")?;
|
write!(f, "{source}")?;
|
||||||
}
|
} else if !self.assignments.is_empty() {
|
||||||
|
write!(f, "SET ")?;
|
||||||
if self.source.is_none() && self.columns.is_empty() {
|
write!(f, "{}", display_comma_separated(&self.assignments))?;
|
||||||
|
} else if self.source.is_none() && self.columns.is_empty() {
|
||||||
write!(f, "DEFAULT VALUES")?;
|
write!(f, "DEFAULT VALUES")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1153,6 +1153,7 @@ impl Spanned for Insert {
|
||||||
replace_into: _, // bool
|
replace_into: _, // bool
|
||||||
priority: _, // todo, mysql specific
|
priority: _, // todo, mysql specific
|
||||||
insert_alias: _, // todo, mysql specific
|
insert_alias: _, // todo, mysql specific
|
||||||
|
assignments,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
union_spans(
|
union_spans(
|
||||||
|
@ -1160,6 +1161,7 @@ impl Spanned for Insert {
|
||||||
.chain(table_alias.as_ref().map(|i| i.span))
|
.chain(table_alias.as_ref().map(|i| i.span))
|
||||||
.chain(columns.iter().map(|i| i.span))
|
.chain(columns.iter().map(|i| i.span))
|
||||||
.chain(source.as_ref().map(|q| q.span()))
|
.chain(source.as_ref().map(|q| q.span()))
|
||||||
|
.chain(assignments.iter().map(|i| i.span()))
|
||||||
.chain(partitioned.iter().flat_map(|i| i.iter().map(|k| k.span())))
|
.chain(partitioned.iter().flat_map(|i| i.iter().map(|k| k.span())))
|
||||||
.chain(after_columns.iter().map(|i| i.span))
|
.chain(after_columns.iter().map(|i| i.span))
|
||||||
.chain(on.as_ref().map(|i| i.span()))
|
.chain(on.as_ref().map(|i| i.span()))
|
||||||
|
|
|
@ -775,6 +775,13 @@ pub trait Dialect: Debug + Any {
|
||||||
fn supports_table_sample_before_alias(&self) -> bool {
|
fn supports_table_sample_before_alias(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this dialect supports the `INSERT INTO ... SET col1 = 1, ...` syntax.
|
||||||
|
///
|
||||||
|
/// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
|
||||||
|
fn supports_insert_set(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This represents the operators for which precedence must be defined
|
/// This represents the operators for which precedence must be defined
|
||||||
|
|
|
@ -98,10 +98,15 @@ impl Dialect for MySqlDialect {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// see <https://dev.mysql.com/doc/refman/8.4/en/create-table-select.html>
|
/// See: <https://dev.mysql.com/doc/refman/8.4/en/create-table-select.html>
|
||||||
fn supports_create_table_select(&self) -> bool {
|
fn supports_create_table_select(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
|
||||||
|
fn supports_insert_set(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `LOCK TABLES`
|
/// `LOCK TABLES`
|
||||||
|
|
|
@ -11899,9 +11899,9 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
let is_mysql = dialect_of!(self is MySqlDialect);
|
let is_mysql = dialect_of!(self is MySqlDialect);
|
||||||
|
|
||||||
let (columns, partitioned, after_columns, source) =
|
let (columns, partitioned, after_columns, source, assignments) =
|
||||||
if self.parse_keywords(&[Keyword::DEFAULT, Keyword::VALUES]) {
|
if self.parse_keywords(&[Keyword::DEFAULT, Keyword::VALUES]) {
|
||||||
(vec![], None, vec![], None)
|
(vec![], None, vec![], None, vec![])
|
||||||
} else {
|
} else {
|
||||||
let (columns, partitioned, after_columns) = if !self.peek_subquery_start() {
|
let (columns, partitioned, after_columns) = if !self.peek_subquery_start() {
|
||||||
let columns = self.parse_parenthesized_column_list(Optional, is_mysql)?;
|
let columns = self.parse_parenthesized_column_list(Optional, is_mysql)?;
|
||||||
|
@ -11918,9 +11918,14 @@ impl<'a> Parser<'a> {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = Some(self.parse_query()?);
|
let (source, assignments) =
|
||||||
|
if self.dialect.supports_insert_set() && self.parse_keyword(Keyword::SET) {
|
||||||
|
(None, self.parse_comma_separated(Parser::parse_assignment)?)
|
||||||
|
} else {
|
||||||
|
(Some(self.parse_query()?), vec![])
|
||||||
|
};
|
||||||
|
|
||||||
(columns, partitioned, after_columns, source)
|
(columns, partitioned, after_columns, source, assignments)
|
||||||
};
|
};
|
||||||
|
|
||||||
let insert_alias = if dialect_of!(self is MySqlDialect | GenericDialect)
|
let insert_alias = if dialect_of!(self is MySqlDialect | GenericDialect)
|
||||||
|
@ -12000,6 +12005,7 @@ impl<'a> Parser<'a> {
|
||||||
columns,
|
columns,
|
||||||
after_columns,
|
after_columns,
|
||||||
source,
|
source,
|
||||||
|
assignments,
|
||||||
table,
|
table,
|
||||||
on,
|
on,
|
||||||
returning,
|
returning,
|
||||||
|
@ -14228,16 +14234,6 @@ mod tests {
|
||||||
assert!(Parser::parse_sql(&GenericDialect {}, sql).is_err());
|
assert!(Parser::parse_sql(&GenericDialect {}, sql).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_replace_into_set() {
|
|
||||||
// NOTE: This is actually valid MySQL syntax, REPLACE and INSERT,
|
|
||||||
// but the parser does not yet support it.
|
|
||||||
// https://dev.mysql.com/doc/refman/8.3/en/insert.html
|
|
||||||
let sql = "REPLACE INTO t SET a='1'";
|
|
||||||
|
|
||||||
assert!(Parser::parse_sql(&MySqlDialect {}, sql).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_replace_into_set_placeholder() {
|
fn test_replace_into_set_placeholder() {
|
||||||
let sql = "REPLACE INTO t SET ?";
|
let sql = "REPLACE INTO t SET ?";
|
||||||
|
|
|
@ -119,6 +119,12 @@ 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_set() {
|
||||||
|
let dialects = all_dialects_where(|d| d.supports_insert_set());
|
||||||
|
dialects.verified_stmt("INSERT INTO tbl1 SET col1 = 1, col2 = 'abc', col3 = current_date()");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_replace_into() {
|
fn parse_replace_into() {
|
||||||
let dialect = PostgreSqlDialect {};
|
let dialect = PostgreSqlDialect {};
|
||||||
|
|
|
@ -4423,6 +4423,7 @@ fn test_simple_postgres_insert_with_alias() {
|
||||||
settings: None,
|
settings: None,
|
||||||
format_clause: None,
|
format_clause: None,
|
||||||
})),
|
})),
|
||||||
|
assignments: vec![],
|
||||||
partitioned: None,
|
partitioned: None,
|
||||||
after_columns: vec![],
|
after_columns: vec![],
|
||||||
table: false,
|
table: false,
|
||||||
|
@ -4493,6 +4494,7 @@ fn test_simple_postgres_insert_with_alias() {
|
||||||
settings: None,
|
settings: None,
|
||||||
format_clause: None,
|
format_clause: None,
|
||||||
})),
|
})),
|
||||||
|
assignments: vec![],
|
||||||
partitioned: None,
|
partitioned: None,
|
||||||
after_columns: vec![],
|
after_columns: vec![],
|
||||||
table: false,
|
table: false,
|
||||||
|
@ -4559,6 +4561,7 @@ fn test_simple_insert_with_quoted_alias() {
|
||||||
settings: None,
|
settings: None,
|
||||||
format_clause: None,
|
format_clause: None,
|
||||||
})),
|
})),
|
||||||
|
assignments: vec![],
|
||||||
partitioned: None,
|
partitioned: None,
|
||||||
after_columns: vec![],
|
after_columns: vec![],
|
||||||
table: false,
|
table: false,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue