diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 176d36545..3a448312b 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2787,10 +2787,11 @@ impl fmt::Display for Declare { } /// Sql options of a `CREATE TABLE` statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CreateTableOptions { + #[default] None, /// Options specified using the `WITH` keyword. /// e.g. `WITH (description = "123")` @@ -2819,12 +2820,6 @@ pub enum CreateTableOptions { TableProperties(Vec), } -impl Default for CreateTableOptions { - fn default() -> Self { - Self::None - } -} - impl fmt::Display for CreateTableOptions { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/src/ast/query.rs b/src/ast/query.rs index 599b013ab..33c92614f 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -3135,12 +3135,18 @@ pub struct Values { /// Was there an explicit ROWs keyword (MySQL)? /// pub explicit_row: bool, + // MySql supports both VALUES and VALUE keywords. + // + pub value_keyword: bool, pub rows: Vec>, } impl fmt::Display for Values { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("VALUES")?; + match self.value_keyword { + true => f.write_str("VALUE")?, + false => f.write_str("VALUES")?, + }; let prefix = if self.explicit_row { "ROW" } else { "" }; let mut delim = ""; for row in &self.rows { diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 7d2a00095..c1ec5d10b 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -223,6 +223,7 @@ impl Spanned for Values { fn span(&self) -> Span { let Values { explicit_row: _, // bool, + value_keyword: _, rows, } = self; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 9a01e510b..30bf7ece5 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12528,7 +12528,10 @@ impl<'a> Parser<'a> { SetExpr::Query(subquery) } else if self.parse_keyword(Keyword::VALUES) { let is_mysql = dialect_of!(self is MySqlDialect); - SetExpr::Values(self.parse_values(is_mysql)?) + SetExpr::Values(self.parse_values(is_mysql, false)?) + } else if self.parse_keyword(Keyword::VALUE) { + let is_mysql = dialect_of!(self is MySqlDialect); + SetExpr::Values(self.parse_values(is_mysql, true)?) } else if self.parse_keyword(Keyword::TABLE) { SetExpr::Table(Box::new(self.parse_as_table()?)) } else { @@ -13832,7 +13835,7 @@ impl<'a> Parser<'a> { // Snowflake and Databricks allow syntax like below: // SELECT * FROM VALUES (1, 'a'), (2, 'b') AS t (col1, col2) // where there are no parentheses around the VALUES clause. - let values = SetExpr::Values(self.parse_values(false)?); + let values = SetExpr::Values(self.parse_values(false, false)?); let alias = self.maybe_parse_table_alias()?; Ok(TableFactor::Derived { lateral: false, @@ -16499,7 +16502,11 @@ impl<'a> Parser<'a> { }) } - pub fn parse_values(&mut self, allow_empty: bool) -> Result { + pub fn parse_values( + &mut self, + allow_empty: bool, + value_keyword: bool, + ) -> Result { let mut explicit_row = false; let rows = self.parse_comma_separated(|parser| { @@ -16517,7 +16524,11 @@ impl<'a> Parser<'a> { Ok(exprs) } })?; - Ok(Values { explicit_row, rows }) + Ok(Values { + explicit_row, + rows, + value_keyword, + }) } pub fn parse_start_transaction(&mut self) -> Result { @@ -16932,7 +16943,7 @@ impl<'a> Parser<'a> { MergeInsertKind::Row } else { self.expect_keyword_is(Keyword::VALUES)?; - let values = self.parse_values(is_mysql)?; + let values = self.parse_values(is_mysql, false)?; MergeInsertKind::Values(values) }; MergeAction::Insert(MergeInsertExpr { columns, kind }) diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 03a0ac813..0ef1c4f0c 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -1807,6 +1807,7 @@ fn parse_merge() { let insert_action = MergeAction::Insert(MergeInsertExpr { columns: vec![Ident::new("product"), Ident::new("quantity")], kind: MergeInsertKind::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![Expr::value(number("1")), Expr::value(number("2"))]], }), @@ -1951,6 +1952,7 @@ fn parse_merge() { action: MergeAction::Insert(MergeInsertExpr { columns: vec![Ident::new("a"), Ident::new("b"),], kind: MergeInsertKind::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::value(number("1")), @@ -1965,6 +1967,7 @@ fn parse_merge() { action: MergeAction::Insert(MergeInsertExpr { columns: vec![], kind: MergeInsertKind::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::value(number("1")), diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index f1ba5df04..5e682119f 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -106,19 +106,19 @@ fn parse_insert_values() { let rows2 = vec![row.clone(), row]; let sql = "INSERT customer VALUES (1, 2, 3)"; - check_one(sql, "customer", &[], &rows1); + check_one(sql, "customer", &[], &rows1, false); let sql = "INSERT INTO customer VALUES (1, 2, 3)"; - check_one(sql, "customer", &[], &rows1); + check_one(sql, "customer", &[], &rows1, false); let sql = "INSERT INTO customer VALUES (1, 2, 3), (1, 2, 3)"; - check_one(sql, "customer", &[], &rows2); + check_one(sql, "customer", &[], &rows2, false); let sql = "INSERT INTO public.customer VALUES (1, 2, 3)"; - check_one(sql, "public.customer", &[], &rows1); + check_one(sql, "public.customer", &[], &rows1, false); let sql = "INSERT INTO db.public.customer VALUES (1, 2, 3)"; - check_one(sql, "db.public.customer", &[], &rows1); + check_one(sql, "db.public.customer", &[], &rows1, false); let sql = "INSERT INTO public.customer (id, name, active) VALUES (1, 2, 3)"; check_one( @@ -126,6 +126,16 @@ fn parse_insert_values() { "public.customer", &["id".to_string(), "name".to_string(), "active".to_string()], &rows1, + false, + ); + + let sql = r"INSERT INTO t (id, name, active) VALUE (1, 2, 3)"; + check_one( + sql, + "t", + &["id".to_string(), "name".to_string(), "active".to_string()], + &rows1, + true, ); fn check_one( @@ -133,6 +143,7 @@ fn parse_insert_values() { expected_table_name: &str, expected_columns: &[String], expected_rows: &[Vec], + expected_value_keyword: bool, ) { match verified_stmt(sql) { Statement::Insert(Insert { @@ -147,8 +158,13 @@ fn parse_insert_values() { assert_eq!(column, &Ident::new(expected_columns[index].clone())); } match *source.body { - SetExpr::Values(Values { rows, .. }) => { - assert_eq!(rows.as_slice(), expected_rows) + SetExpr::Values(Values { + rows, + value_keyword, + .. + }) => { + assert_eq!(rows.as_slice(), expected_rows); + assert!(value_keyword == expected_value_keyword); } _ => unreachable!(), } @@ -9908,6 +9924,7 @@ fn parse_merge() { action: MergeAction::Insert(MergeInsertExpr { columns: vec![Ident::new("A"), Ident::new("B"), Ident::new("C")], kind: MergeInsertKind::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::CompoundIdentifier(vec![ diff --git a/tests/sqlparser_databricks.rs b/tests/sqlparser_databricks.rs index 92b635339..065e8f9e7 100644 --- a/tests/sqlparser_databricks.rs +++ b/tests/sqlparser_databricks.rs @@ -157,6 +157,7 @@ fn test_databricks_lambdas() { #[test] fn test_values_clause() { let values = Values { + value_keyword: false, explicit_row: false, rows: vec![ vec![ diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index e43df87ab..a5ca03bd8 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -1885,6 +1885,7 @@ fn parse_simple_insert() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![ vec![ @@ -1950,6 +1951,7 @@ fn parse_ignore_insert() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Value( @@ -1999,6 +2001,7 @@ fn parse_priority_insert() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Value( @@ -2045,6 +2048,7 @@ fn parse_priority_insert() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Value( @@ -2097,6 +2101,7 @@ fn parse_insert_as() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![Expr::Value( (Value::SingleQuotedString("2024-01-01".to_string())).with_empty_span() @@ -2156,6 +2161,7 @@ fn parse_insert_as() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::value(number("1")), @@ -2206,6 +2212,7 @@ fn parse_replace_insert() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Value( @@ -2253,6 +2260,7 @@ fn parse_empty_row_insert() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![], vec![]] })), @@ -2303,6 +2311,7 @@ fn parse_insert_with_on_duplicate_update() { Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Value( diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 9ba0fb978..87cb43edd 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -5169,6 +5169,7 @@ fn test_simple_postgres_insert_with_alias() { source: Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Identifier(Ident::new("DEFAULT")), @@ -5238,6 +5239,7 @@ fn test_simple_postgres_insert_with_alias() { source: Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Identifier(Ident::new("DEFAULT")), @@ -5309,6 +5311,7 @@ fn test_simple_insert_with_quoted_alias() { source: Some(Box::new(Query { with: None, body: Box::new(SetExpr::Values(Values { + value_keyword: false, explicit_row: false, rows: vec![vec![ Expr::Identifier(Ident::new("DEFAULT")),