From 0c459201fb63a2053168d6d4bf30ea1adf1b0648 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Thu, 3 Jun 2021 10:39:14 -0500 Subject: [PATCH 1/2] extract enum fields to named structs --- src/ast/mod.rs | 426 +++++++++++++++++++++-------------- src/parser.rs | 64 +++--- tests/sqlparser_common.rs | 110 ++++----- tests/sqlparser_mysql.rs | 4 +- tests/sqlparser_postgres.rs | 40 ++-- tests/sqlparser_snowflake.rs | 2 +- tests/sqlparser_sqlite.rs | 12 +- 7 files changed, 375 insertions(+), 283 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 462dae516..131d44b68 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -485,168 +485,242 @@ impl fmt::Display for AddDropSync { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct AnalyzeStatement { + pub table_name: ObjectName, + pub partitions: Option>, + pub for_columns: bool, + pub columns: Vec, + pub cache_metadata: bool, + pub noscan: bool, + pub compute_statistics: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct TruncateStatement { + pub table_name: ObjectName, + pub partitions: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct MsckStatement { + pub table_name: ObjectName, + pub repair: bool, + pub partition_action: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct InsertStatement { + /// Only for Sqlite + pub or: Option, + /// TABLE + pub table_name: ObjectName, + /// COLUMNS + pub columns: Vec, + /// Overwrite (Hive) + pub overwrite: bool, + /// A SQL query that specifies what to insert + pub source: Box, + /// partitioned insert (Hive) + pub partitioned: Option>, + /// Columns defined after PARTITION + pub after_columns: Vec, + /// whether the insert has the table keyword (Hive) + pub table: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct DirectoryStatement { + pub overwrite: bool, + pub local: bool, + pub path: String, + pub file_format: Option, + pub source: Box, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct CopyStatement { + /// TABLE + pub table_name: ObjectName, + /// COLUMNS + pub columns: Vec, + /// VALUES a vector of values to be copied + pub values: Vec>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct UpdateStatement { + /// TABLE + pub table_name: ObjectName, + /// Column assignments + pub assignments: Vec, + /// WHERE + pub selection: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct DeleteStatement { + /// FROM + pub table_name: ObjectName, + /// WHERE + pub selection: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct CreateTableStatement { + pub or_replace: bool, + pub temporary: bool, + pub external: bool, + pub if_not_exists: bool, + /// Table name + pub name: ObjectName, + /// Optional schema + pub columns: Vec, + pub constraints: Vec, + pub hive_distribution: HiveDistributionStyle, + pub hive_formats: Option, + pub table_properties: Vec, + pub with_options: Vec, + pub file_format: Option, + pub location: Option, + pub query: Option>, + pub without_rowid: bool, + pub like: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct CreateViewStatement { + pub or_replace: bool, + pub materialized: bool, + /// View name + pub name: ObjectName, + pub columns: Vec, + pub query: Box, + pub with_options: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct CreateVirtualTableStatement { + pub name: ObjectName, + pub if_not_exists: bool, + pub module_name: Ident, + pub module_args: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct CreateIndexStatement { + /// index name + pub name: ObjectName, + pub table_name: ObjectName, + pub columns: Vec, + pub unique: bool, + pub if_not_exists: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct AlterTableStatement { + /// Table name + pub name: ObjectName, + pub operation: AlterTableOperation, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct DropStatement { + /// The type of the object to drop: TABLE, VIEW, etc. + pub object_type: ObjectType, + /// An optional `IF EXISTS` clause. (Non-standard.) + pub if_exists: bool, + /// One or more objects to drop. (ANSI SQL requires exactly one.) + pub names: Vec, + /// Whether `CASCADE` was specified. This will be `false` when + /// `RESTRICT` or no drop behavior at all was specified. + pub cascade: bool, + /// Hive allows you specify whether the table's stored data will be + /// deleted along with the dropped table + pub purge: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct SetVariableStatement { + pub local: bool, + pub hivevar: bool, + pub variable: Ident, + pub value: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ShowVariableStatement {} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ShowColumnsStatement {} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct StartTransactionStatement {} + /// A top-level statement (SELECT, INSERT, CREATE, etc.) #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Statement { /// Analyze (Hive) - Analyze { - table_name: ObjectName, - partitions: Option>, - for_columns: bool, - columns: Vec, - cache_metadata: bool, - noscan: bool, - compute_statistics: bool, - }, + Analyze(AnalyzeStatement), /// Truncate (Hive) - Truncate { - table_name: ObjectName, - partitions: Option>, - }, + Truncate(TruncateStatement), /// Msck (Hive) - Msck { - table_name: ObjectName, - repair: bool, - partition_action: Option, - }, + Msck(MsckStatement), /// SELECT Query(Box), /// INSERT - Insert { - /// Only for Sqlite - or: Option, - /// TABLE - table_name: ObjectName, - /// COLUMNS - columns: Vec, - /// Overwrite (Hive) - overwrite: bool, - /// A SQL query that specifies what to insert - source: Box, - /// partitioned insert (Hive) - partitioned: Option>, - /// Columns defined after PARTITION - after_columns: Vec, - /// whether the insert has the table keyword (Hive) - table: bool, - }, + Insert(InsertStatement), // TODO: Support ROW FORMAT - Directory { - overwrite: bool, - local: bool, - path: String, - file_format: Option, - source: Box, - }, - Copy { - /// TABLE - table_name: ObjectName, - /// COLUMNS - columns: Vec, - /// VALUES a vector of values to be copied - values: Vec>, - }, + Directory(DirectoryStatement), + Copy(CopyStatement), /// UPDATE - Update { - /// TABLE - table_name: ObjectName, - /// Column assignments - assignments: Vec, - /// WHERE - selection: Option, - }, + Update(UpdateStatement), /// DELETE - Delete { - /// FROM - table_name: ObjectName, - /// WHERE - selection: Option, - }, + Delete(DeleteStatement), /// CREATE VIEW - CreateView { - or_replace: bool, - materialized: bool, - /// View name - name: ObjectName, - columns: Vec, - query: Box, - with_options: Vec, - }, + CreateView(CreateViewStatement), /// CREATE TABLE - CreateTable { - or_replace: bool, - temporary: bool, - external: bool, - if_not_exists: bool, - /// Table name - name: ObjectName, - /// Optional schema - columns: Vec, - constraints: Vec, - hive_distribution: HiveDistributionStyle, - hive_formats: Option, - table_properties: Vec, - with_options: Vec, - file_format: Option, - location: Option, - query: Option>, - without_rowid: bool, - like: Option, - }, + CreateTable(CreateTableStatement), /// SQLite's `CREATE VIRTUAL TABLE .. USING ()` - CreateVirtualTable { - name: ObjectName, - if_not_exists: bool, - module_name: Ident, - module_args: Vec, - }, + CreateVirtualTable(CreateVirtualTableStatement), /// CREATE INDEX - CreateIndex { - /// index name - name: ObjectName, - table_name: ObjectName, - columns: Vec, - unique: bool, - if_not_exists: bool, - }, + CreateIndex(CreateIndexStatement), /// ALTER TABLE - AlterTable { - /// Table name - name: ObjectName, - operation: AlterTableOperation, - }, + AlterTable(AlterTableStatement), /// DROP - Drop { - /// The type of the object to drop: TABLE, VIEW, etc. - object_type: ObjectType, - /// An optional `IF EXISTS` clause. (Non-standard.) - if_exists: bool, - /// One or more objects to drop. (ANSI SQL requires exactly one.) - names: Vec, - /// Whether `CASCADE` was specified. This will be `false` when - /// `RESTRICT` or no drop behavior at all was specified. - cascade: bool, - /// Hive allows you specify whether the table's stored data will be - /// deleted along with the dropped table - purge: bool, - }, + Drop(DropStatement), /// SET /// /// Note: this is not a standard SQL statement, but it is supported by at /// least MySQL and PostgreSQL. Not all MySQL-specific syntatic forms are /// supported yet. - SetVariable { - local: bool, - hivevar: bool, - variable: Ident, - value: Vec, - }, + SetVariable(SetVariableStatement), /// SHOW /// /// Note: this is a PostgreSQL-specific statement. - ShowVariable { variable: Vec }, + ShowVariable { + variable: Vec, + }, /// SHOW COLUMNS /// /// Note: this is a MySQL-specific statement. @@ -657,13 +731,21 @@ pub enum Statement { filter: Option, }, /// `{ BEGIN [ TRANSACTION | WORK ] | START TRANSACTION } ...` - StartTransaction { modes: Vec }, + StartTransaction { + modes: Vec, + }, /// `SET TRANSACTION ...` - SetTransaction { modes: Vec }, + SetTransaction { + modes: Vec, + }, /// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]` - Commit { chain: bool }, + Commit { + chain: bool, + }, /// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]` - Rollback { chain: bool }, + Rollback { + chain: bool, + }, /// CREATE SCHEMA CreateSchema { schema_name: ObjectName, @@ -684,11 +766,17 @@ pub enum Statement { /// `DEALLOCATE [ PREPARE ] { name | ALL }` /// /// Note: this is a PostgreSQL-specific statement. - Deallocate { name: Ident, prepare: bool }, + Deallocate { + name: Ident, + prepare: bool, + }, /// `EXECUTE name [ ( parameter [, ...] ) ]` /// /// Note: this is a PostgreSQL-specific statement. - Execute { name: Ident, parameters: Vec }, + Execute { + name: Ident, + parameters: Vec, + }, /// `PREPARE name [ ( data_type [, ...] ) ] AS statement` /// /// Note: this is a PostgreSQL-specific statement. @@ -732,13 +820,13 @@ impl fmt::Display for Statement { write!(f, "{}", statement) } Statement::Query(s) => write!(f, "{}", s), - Statement::Directory { + Statement::Directory(DirectoryStatement { overwrite, local, path, file_format, source, - } => { + }) => { write!( f, "INSERT{overwrite}{local} DIRECTORY '{path}'", @@ -751,11 +839,11 @@ impl fmt::Display for Statement { } write!(f, " {}", source) } - Statement::Msck { + Statement::Msck(MsckStatement { table_name, repair, partition_action, - } => { + }) => { write!( f, "MSCK {repair}TABLE {table}", @@ -767,10 +855,10 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::Truncate { + Statement::Truncate(TruncateStatement { table_name, partitions, - } => { + }) => { write!(f, "TRUNCATE TABLE {}", table_name)?; if let Some(ref parts) = partitions { if !parts.is_empty() { @@ -779,7 +867,7 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::Analyze { + Statement::Analyze(AnalyzeStatement { table_name, partitions, for_columns, @@ -787,7 +875,7 @@ impl fmt::Display for Statement { cache_metadata, noscan, compute_statistics, - } => { + }) => { write!(f, "ANALYZE TABLE {}", table_name)?; if let Some(ref parts) = partitions { if !parts.is_empty() { @@ -812,7 +900,7 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::Insert { + Statement::Insert(InsertStatement { or, table_name, overwrite, @@ -821,7 +909,7 @@ impl fmt::Display for Statement { after_columns, source, table, - } => { + }) => { if let Some(action) = or { write!(f, "INSERT OR {} INTO {} ", action, table_name)?; } else { @@ -847,11 +935,11 @@ impl fmt::Display for Statement { write!(f, "{}", source) } - Statement::Copy { + Statement::Copy(CopyStatement { table_name, columns, values, - } => { + }) => { write!(f, "COPY {}", table_name)?; if !columns.is_empty() { write!(f, " ({})", display_comma_separated(columns))?; @@ -872,11 +960,11 @@ impl fmt::Display for Statement { } write!(f, "\n\\.") } - Statement::Update { + Statement::Update(UpdateStatement { table_name, assignments, selection, - } => { + }) => { write!(f, "UPDATE {}", table_name)?; if !assignments.is_empty() { write!(f, " SET {}", display_comma_separated(assignments))?; @@ -886,10 +974,10 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::Delete { + Statement::Delete(DeleteStatement { table_name, selection, - } => { + }) => { write!(f, "DELETE FROM {}", table_name)?; if let Some(selection) = selection { write!(f, " WHERE {}", selection)?; @@ -915,14 +1003,14 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::CreateView { + Statement::CreateView(CreateViewStatement { name, or_replace, columns, query, materialized, with_options, - } => { + }) => { write!( f, "CREATE {or_replace}{materialized}VIEW {name}", @@ -938,7 +1026,7 @@ impl fmt::Display for Statement { } write!(f, " AS {}", query) } - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, columns, constraints, @@ -955,7 +1043,7 @@ impl fmt::Display for Statement { query, without_rowid, like, - } => { + }) => { // We want to allow the following options // Empty column list, allowed by PostgreSQL: // `CREATE TABLE t ()` @@ -1082,12 +1170,12 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::CreateVirtualTable { + Statement::CreateVirtualTable(CreateVirtualTableStatement { name, if_not_exists, module_name, module_args, - } => { + }) => { write!( f, "CREATE VIRTUAL TABLE {if_not_exists}{name} USING {module_name}", @@ -1100,13 +1188,13 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::CreateIndex { + Statement::CreateIndex(CreateIndexStatement { name, table_name, columns, unique, if_not_exists, - } => write!( + }) => write!( f, "CREATE {unique}INDEX {if_not_exists}{name} ON {table_name}({columns})", unique = if *unique { "UNIQUE " } else { "" }, @@ -1115,16 +1203,16 @@ impl fmt::Display for Statement { table_name = table_name, columns = display_separated(columns, ",") ), - Statement::AlterTable { name, operation } => { + Statement::AlterTable(AlterTableStatement { name, operation }) => { write!(f, "ALTER TABLE {} {}", name, operation) } - Statement::Drop { + Statement::Drop(DropStatement { object_type, if_exists, names, cascade, purge, - } => write!( + }) => write!( f, "DROP {}{} {}{}{}", object_type, @@ -1133,12 +1221,12 @@ impl fmt::Display for Statement { if *cascade { " CASCADE" } else { "" }, if *purge { " PURGE" } else { "" } ), - Statement::SetVariable { + Statement::SetVariable(SetVariableStatement { local, variable, hivevar, value, - } => { + }) => { f.write_str("SET ")?; if *local { f.write_str("LOCAL ")?; diff --git a/src/parser.rs b/src/parser.rs index 863fc66d0..e80e44d4c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -197,11 +197,11 @@ impl<'a> Parser<'a> { Ok(pa) }) .unwrap_or_default(); - Ok(Statement::Msck { + Ok(Statement::Msck(MsckStatement { repair, table_name, partition_action, - }) + })) } pub fn parse_truncate(&mut self) -> Result { @@ -213,10 +213,10 @@ impl<'a> Parser<'a> { partitions = Some(self.parse_comma_separated(Parser::parse_expr)?); self.expect_token(&Token::RParen)?; } - Ok(Statement::Truncate { + Ok(Statement::Truncate(TruncateStatement { table_name, partitions, - }) + })) } pub fn parse_analyze(&mut self) -> Result { @@ -264,7 +264,7 @@ impl<'a> Parser<'a> { } } - Ok(Statement::Analyze { + Ok(Statement::Analyze(AnalyzeStatement { table_name, for_columns, columns, @@ -272,7 +272,7 @@ impl<'a> Parser<'a> { cache_metadata, noscan, compute_statistics, - }) + })) } /// Parse a new expression @@ -1248,12 +1248,12 @@ impl<'a> Parser<'a> { // definitions in a traditional CREATE TABLE statement", but // we don't implement that. let module_args = self.parse_parenthesized_column_list(Optional)?; - Ok(CreateVirtualTable { + Ok(CreateVirtualTable(CreateVirtualTableStatement { name: table_name, if_not_exists, module_name, module_args, - }) + })) } pub fn parse_create_schema(&mut self) -> Result { @@ -1309,7 +1309,7 @@ impl<'a> Parser<'a> { }; let location = hive_formats.location.clone(); let table_properties = self.parse_options(Keyword::TBLPROPERTIES)?; - Ok(Statement::CreateTable { + Ok(Statement::CreateTable(CreateTableStatement { name: table_name, columns, constraints, @@ -1326,7 +1326,7 @@ impl<'a> Parser<'a> { query: None, without_rowid: false, like: None, - }) + })) } pub fn parse_file_format(&mut self) -> Result { @@ -1356,14 +1356,14 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::AS)?; let query = Box::new(self.parse_query()?); // Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here. - Ok(Statement::CreateView { + Ok(Statement::CreateView(CreateViewStatement { name, columns, query, materialized, or_replace, with_options, - }) + })) } pub fn parse_drop(&mut self) -> Result { @@ -1388,13 +1388,13 @@ impl<'a> Parser<'a> { if cascade && restrict { return parser_err!("Cannot specify both CASCADE and RESTRICT in DROP"); } - Ok(Statement::Drop { + Ok(Statement::Drop(DropStatement { object_type, if_exists, names, cascade, purge, - }) + })) } pub fn parse_create_index(&mut self, unique: bool) -> Result { @@ -1405,13 +1405,13 @@ impl<'a> Parser<'a> { self.expect_token(&Token::LParen)?; let columns = self.parse_comma_separated(Parser::parse_order_by_expr)?; self.expect_token(&Token::RParen)?; - Ok(Statement::CreateIndex { + Ok(Statement::CreateIndex(CreateIndexStatement { name: index_name, table_name, columns, unique, if_not_exists, - }) + })) } //TODO: Implement parsing for Skewed and Clustered @@ -1500,7 +1500,7 @@ impl<'a> Parser<'a> { None }; - Ok(Statement::CreateTable { + Ok(Statement::CreateTable(CreateTableStatement { name: table_name, temporary, columns, @@ -1517,7 +1517,7 @@ impl<'a> Parser<'a> { query, without_rowid, like, - }) + })) } fn parse_columns(&mut self) -> Result<(Vec, Vec), ParserError> { @@ -1813,10 +1813,10 @@ impl<'a> Parser<'a> { self.peek_token(), ); }; - Ok(Statement::AlterTable { + Ok(Statement::AlterTable(AlterTableStatement { name: table_name, operation, - }) + })) } /// Parse a copy statement @@ -1826,11 +1826,11 @@ impl<'a> Parser<'a> { self.expect_keywords(&[Keyword::FROM, Keyword::STDIN])?; self.expect_token(&Token::SemiColon)?; let values = self.parse_tsv(); - Ok(Statement::Copy { + Ok(Statement::Copy(CopyStatement { table_name, columns, values, - }) + })) } /// Parse a tab separated values in @@ -2139,10 +2139,10 @@ impl<'a> Parser<'a> { None }; - Ok(Statement::Delete { + Ok(Statement::Delete(DeleteStatement { table_name, selection, - }) + })) } pub fn parse_explain(&mut self) -> Result { @@ -2444,12 +2444,12 @@ impl<'a> Parser<'a> { if self.consume_token(&Token::Comma) { continue; } - return Ok(Statement::SetVariable { + return Ok(Statement::SetVariable(SetVariableStatement { local: modifier == Some(Keyword::LOCAL), hivevar: Some(Keyword::HIVEVAR) == modifier, variable, value: values, - }); + })); } } else if variable.value == "TRANSACTION" && modifier.is_none() { Ok(Statement::SetTransaction { @@ -2774,13 +2774,13 @@ impl<'a> Parser<'a> { None }; let source = Box::new(self.parse_query()?); - Ok(Statement::Directory { + Ok(Statement::Directory(DirectoryStatement { local, path, overwrite, file_format, source, - }) + })) } else { // Hive lets you put table here regardless let table = self.parse_keyword(Keyword::TABLE); @@ -2800,7 +2800,7 @@ impl<'a> Parser<'a> { let after_columns = self.parse_parenthesized_column_list(Optional)?; let source = Box::new(self.parse_query()?); - Ok(Statement::Insert { + Ok(Statement::Insert(InsertStatement { or, table_name, overwrite, @@ -2809,7 +2809,7 @@ impl<'a> Parser<'a> { after_columns, source, table, - }) + })) } } @@ -2822,11 +2822,11 @@ impl<'a> Parser<'a> { } else { None }; - Ok(Statement::Update { + Ok(Statement::Update(UpdateStatement { table_name, assignments, selection, - }) + })) } /// Parse a `var = expr` assignment, used in an UPDATE statement diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index e43bd12ce..243be2cf1 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -64,12 +64,12 @@ fn parse_insert_values() { expected_rows: &[Vec], ) { match verified_stmt(sql) { - Statement::Insert { + Statement::Insert(InsertStatement { table_name, columns, source, .. - } => { + }) => { assert_eq!(table_name.to_string(), expected_table_name); assert_eq!(columns.len(), expected_columns.len()); for (index, column) in columns.iter().enumerate() { @@ -108,7 +108,7 @@ fn parse_insert_sqlite() { .pop() .unwrap() { - Statement::Insert { or, .. } => assert_eq!(or, expected_action), + Statement::Insert(InsertStatement { or, .. }) => assert_eq!(or, expected_action), _ => panic!(sql.to_string()), }; @@ -138,12 +138,12 @@ fn parse_insert_sqlite() { fn parse_update() { let sql = "UPDATE t SET a = 1, b = 2, c = 3 WHERE d"; match verified_stmt(sql) { - Statement::Update { + Statement::Update(UpdateStatement { table_name, assignments, selection, .. - } => { + }) => { assert_eq!(table_name.to_string(), "t".to_string()); assert_eq!( assignments, @@ -201,7 +201,7 @@ fn parse_no_table_name() { fn parse_delete_statement() { let sql = "DELETE FROM \"table\""; match verified_stmt(sql) { - Statement::Delete { table_name, .. } => { + Statement::Delete(DeleteStatement { table_name, .. }) => { assert_eq!( ObjectName(vec![Ident::with_quote('"', "table")]), table_name @@ -217,11 +217,11 @@ fn parse_where_delete_statement() { let sql = "DELETE FROM foo WHERE name = 5"; match verified_stmt(sql) { - Statement::Delete { + Statement::Delete(DeleteStatement { table_name, selection, .. - } => { + }) => { assert_eq!(ObjectName(vec![Ident::new("foo")]), table_name); assert_eq!( @@ -1155,7 +1155,7 @@ fn parse_create_table() { ref2 INT REFERENCES othertable2 ON DELETE CASCADE ON UPDATE NO ACTION)", ); match ast { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, columns, constraints, @@ -1165,7 +1165,7 @@ fn parse_create_table() { file_format: None, location: None, .. - } => { + }) => { assert_eq!("uk_cities", name.to_string()); assert_eq!( columns, @@ -1336,7 +1336,9 @@ fn parse_drop_schema() { let sql = "DROP SCHEMA X"; match verified_stmt(sql) { - Statement::Drop { object_type, .. } => assert_eq!(object_type, ObjectType::Schema), + Statement::Drop(DropStatement { object_type, .. }) => { + assert_eq!(object_type, ObjectType::Schema) + } _ => unreachable!(), } } @@ -1346,7 +1348,7 @@ fn parse_create_table_as() { let sql = "CREATE TABLE t AS SELECT * FROM a"; match verified_stmt(sql) { - Statement::CreateTable { name, query, .. } => { + Statement::CreateTable(CreateTableStatement { name, query, .. }) => { assert_eq!(name.to_string(), "t".to_string()); assert_eq!(query, Some(Box::new(verified_query("SELECT * FROM a")))); } @@ -1358,7 +1360,7 @@ fn parse_create_table_as() { // (without data types) in a CTAS, but we have yet to support that. let sql = "CREATE TABLE t (a INT, b INT) AS SELECT 1 AS b, 2 AS a"; match verified_stmt(sql) { - Statement::CreateTable { columns, query, .. } => { + Statement::CreateTable(CreateTableStatement { columns, query, .. }) => { assert_eq!(columns.len(), 2); assert_eq!(columns[0].to_string(), "a INT".to_string()); assert_eq!(columns[1].to_string(), "b INT".to_string()); @@ -1376,9 +1378,9 @@ fn parse_create_or_replace_table() { let sql = "CREATE OR REPLACE TABLE t (a INT)"; match verified_stmt(sql) { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, or_replace, .. - } => { + }) => { assert_eq!(name.to_string(), "t".to_string()); assert!(or_replace); } @@ -1387,7 +1389,7 @@ fn parse_create_or_replace_table() { let sql = "CREATE TABLE t (a INT, b INT) AS SELECT 1 AS b, 2 AS a"; match verified_stmt(sql) { - Statement::CreateTable { columns, query, .. } => { + Statement::CreateTable(CreateTableStatement { columns, query, .. }) => { assert_eq!(columns.len(), 2); assert_eq!(columns[0].to_string(), "a INT".to_string()); assert_eq!(columns[1].to_string(), "b INT".to_string()); @@ -1418,7 +1420,7 @@ fn parse_create_table_with_on_delete_on_update_2in_any_order() -> Result<(), Par fn parse_create_table_with_options() { let sql = "CREATE TABLE t (c INT) WITH (foo = 'bar', a = 123)"; match verified_stmt(sql) { - Statement::CreateTable { with_options, .. } => { + Statement::CreateTable(CreateTableStatement { with_options, .. }) => { assert_eq!( vec![ SqlOption { @@ -1459,7 +1461,7 @@ fn parse_create_external_table() { STORED AS TEXTFILE LOCATION '/tmp/example.csv'", ); match ast { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, columns, constraints, @@ -1469,7 +1471,7 @@ fn parse_create_external_table() { file_format, location, .. - } => { + }) => { assert_eq!("uk_cities", name.to_string()); assert_eq!( columns, @@ -1527,7 +1529,7 @@ fn parse_create_or_replace_external_table() { STORED AS TEXTFILE LOCATION '/tmp/example.csv'", ); match ast { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, columns, constraints, @@ -1538,7 +1540,7 @@ fn parse_create_or_replace_external_table() { location, or_replace, .. - } => { + }) => { assert_eq!("uk_cities", name.to_string()); assert_eq!( columns, @@ -1588,10 +1590,10 @@ fn parse_create_external_table_lowercase() { fn parse_alter_table() { let add_column = "ALTER TABLE tab ADD COLUMN foo TEXT;"; match one_statement_parses_to(add_column, "ALTER TABLE tab ADD COLUMN foo TEXT") { - Statement::AlterTable { + Statement::AlterTable(AlterTableStatement { name, operation: AlterTableOperation::AddColumn { column_def }, - } => { + }) => { assert_eq!("tab", name.to_string()); assert_eq!("foo", column_def.name.to_string()); assert_eq!("TEXT", column_def.data_type.to_string()); @@ -1601,10 +1603,10 @@ fn parse_alter_table() { let rename_table = "ALTER TABLE tab RENAME TO new_tab"; match verified_stmt(rename_table) { - Statement::AlterTable { + Statement::AlterTable(AlterTableStatement { name, operation: AlterTableOperation::RenameTable { table_name }, - } => { + }) => { assert_eq!("tab", name.to_string()); assert_eq!("new_tab", table_name.to_string()) } @@ -1613,14 +1615,14 @@ fn parse_alter_table() { let rename_column = "ALTER TABLE tab RENAME COLUMN foo TO new_foo"; match verified_stmt(rename_column) { - Statement::AlterTable { + Statement::AlterTable(AlterTableStatement { name, operation: AlterTableOperation::RenameColumn { old_column_name, new_column_name, }, - } => { + }) => { assert_eq!("tab", name.to_string()); assert_eq!(old_column_name.to_string(), "foo"); assert_eq!(new_column_name.to_string(), "new_foo"); @@ -1646,10 +1648,10 @@ fn parse_alter_table_constraints() { fn check_one(constraint_text: &str) { match verified_stmt(&format!("ALTER TABLE tab ADD {}", constraint_text)) { - Statement::AlterTable { + Statement::AlterTable(AlterTableStatement { name, operation: AlterTableOperation::AddConstraint(constraint), - } => { + }) => { assert_eq!("tab", name.to_string()); assert_eq!(constraint_text, constraint.to_string()); } @@ -1673,7 +1675,7 @@ fn parse_alter_table_drop_column() { fn check_one(constraint_text: &str) { match verified_stmt(&format!("ALTER TABLE tab {}", constraint_text)) { - Statement::AlterTable { + Statement::AlterTable(AlterTableStatement { name, operation: AlterTableOperation::DropColumn { @@ -1681,7 +1683,7 @@ fn parse_alter_table_drop_column() { if_exists, cascade, }, - } => { + }) => { assert_eq!("tab", name.to_string()); assert_eq!("is_active", column_name.to_string()); assert_eq!(true, if_exists); @@ -2527,7 +2529,9 @@ fn parse_ctes() { // CTE in a view let sql = &format!("CREATE VIEW v AS {}", with); match verified_stmt(sql) { - Statement::CreateView { query, .. } => assert_ctes_in_select(&cte_sqls, &query), + Statement::CreateView(CreateViewStatement { query, .. }) => { + assert_ctes_in_select(&cte_sqls, &query) + } _ => panic!("Expected CREATE VIEW"), } // CTE in a CTE... @@ -2771,14 +2775,14 @@ fn parse_exists_subquery() { fn parse_create_view() { let sql = "CREATE VIEW myschema.myview AS SELECT foo FROM bar"; match verified_stmt(sql) { - Statement::CreateView { + Statement::CreateView(CreateViewStatement { name, columns, query, or_replace, materialized, with_options, - } => { + }) => { assert_eq!("myschema.myview", name.to_string()); assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); @@ -2794,7 +2798,7 @@ fn parse_create_view() { fn parse_create_view_with_options() { let sql = "CREATE VIEW v WITH (foo = 'bar', a = 123) AS SELECT 1"; match verified_stmt(sql) { - Statement::CreateView { with_options, .. } => { + Statement::CreateView(CreateViewStatement { with_options, .. }) => { assert_eq!( vec![ SqlOption { @@ -2817,14 +2821,14 @@ fn parse_create_view_with_options() { fn parse_create_view_with_columns() { let sql = "CREATE VIEW v (has, cols) AS SELECT 1, 2"; match verified_stmt(sql) { - Statement::CreateView { + Statement::CreateView(CreateViewStatement { name, columns, or_replace, with_options, query, materialized, - } => { + }) => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![Ident::new("has"), Ident::new("cols")]); assert_eq!(with_options, vec![]); @@ -2839,14 +2843,14 @@ fn parse_create_view_with_columns() { fn parse_create_or_replace_view() { let sql = "CREATE OR REPLACE VIEW v AS SELECT 1"; match verified_stmt(sql) { - Statement::CreateView { + Statement::CreateView(CreateViewStatement { name, columns, or_replace, with_options, query, materialized, - } => { + }) => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![]); assert_eq!(with_options, vec![]); @@ -2866,14 +2870,14 @@ fn parse_create_or_replace_materialized_view() { // https://docs.snowflake.com/en/sql-reference/sql/create-materialized-view.html let sql = "CREATE OR REPLACE MATERIALIZED VIEW v AS SELECT 1"; match verified_stmt(sql) { - Statement::CreateView { + Statement::CreateView(CreateViewStatement { name, columns, or_replace, with_options, query, materialized, - } => { + }) => { assert_eq!("v", name.to_string()); assert_eq!(columns, vec![]); assert_eq!(with_options, vec![]); @@ -2889,14 +2893,14 @@ fn parse_create_or_replace_materialized_view() { fn parse_create_materialized_view() { let sql = "CREATE MATERIALIZED VIEW myschema.myview AS SELECT foo FROM bar"; match verified_stmt(sql) { - Statement::CreateView { + Statement::CreateView(CreateViewStatement { name, or_replace, columns, query, materialized, with_options, - } => { + }) => { assert_eq!("myschema.myview", name.to_string()); assert_eq!(Vec::::new(), columns); assert_eq!("SELECT foo FROM bar", query.to_string()); @@ -2912,13 +2916,13 @@ fn parse_create_materialized_view() { fn parse_drop_table() { let sql = "DROP TABLE foo"; match verified_stmt(sql) { - Statement::Drop { + Statement::Drop(DropStatement { object_type, if_exists, names, cascade, purge: _, - } => { + }) => { assert_eq!(false, if_exists); assert_eq!(ObjectType::Table, object_type); assert_eq!( @@ -2932,13 +2936,13 @@ fn parse_drop_table() { let sql = "DROP TABLE IF EXISTS foo, bar CASCADE"; match verified_stmt(sql) { - Statement::Drop { + Statement::Drop(DropStatement { object_type, if_exists, names, cascade, purge: _, - } => { + }) => { assert_eq!(true, if_exists); assert_eq!(ObjectType::Table, object_type); assert_eq!( @@ -2967,9 +2971,9 @@ fn parse_drop_table() { fn parse_drop_view() { let sql = "DROP VIEW myschema.myview"; match verified_stmt(sql) { - Statement::Drop { + Statement::Drop(DropStatement { names, object_type, .. - } => { + }) => { assert_eq!( vec!["myschema.myview"], names.iter().map(ToString::to_string).collect::>() @@ -3370,13 +3374,13 @@ fn parse_create_index() { }, ]; match verified_stmt(sql) { - Statement::CreateIndex { + Statement::CreateIndex(CreateIndexStatement { name, table_name, columns, unique, if_not_exists, - } => { + }) => { assert_eq!("idx_name", name.to_string()); assert_eq!("test", table_name.to_string()); assert_eq!(indexed_columns, columns); @@ -3390,9 +3394,9 @@ fn parse_create_index() { fn parse_drop_index() { let sql = "DROP INDEX idx_a"; match verified_stmt(sql) { - Statement::Drop { + Statement::Drop(DropStatement { names, object_type, .. - } => { + }) => { assert_eq!( vec!["idx_a"], names.iter().map(ToString::to_string).collect::>() diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index a8f85584c..f3ffff198 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -104,7 +104,7 @@ fn parse_show_columns() { fn parse_create_table_auto_increment() { let sql = "CREATE TABLE foo (bar INT PRIMARY KEY AUTO_INCREMENT)"; match mysql().verified_stmt(sql) { - Statement::CreateTable { name, columns, .. } => { + Statement::CreateTable(CreateTableStatement { name, columns, .. }) => { assert_eq!(name.to_string(), "foo"); assert_eq!( vec![ColumnDef { @@ -135,7 +135,7 @@ fn parse_create_table_auto_increment() { fn parse_quote_identifiers() { let sql = "CREATE TABLE `PRIMARY` (`BEGIN` INT PRIMARY KEY)"; match mysql().verified_stmt(sql) { - Statement::CreateTable { name, columns, .. } => { + Statement::CreateTable(CreateTableStatement { name, columns, .. }) => { assert_eq!(name.to_string(), "`PRIMARY`"); assert_eq!( vec![ColumnDef { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index bcfce30fc..7bd8cac14 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -37,7 +37,7 @@ fn parse_create_table_with_defaults() { active integer NOT NULL ) WITH (fillfactor = 20, user_catalog_table = true, autovacuum_vacuum_threshold = 100)"; match pg_and_generic().one_statement_parses_to(sql, "") { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, columns, constraints, @@ -47,7 +47,7 @@ fn parse_create_table_with_defaults() { file_format: None, location: None, .. - } => { + }) => { assert_eq!("public.customer", name.to_string()); assert_eq!( columns, @@ -243,12 +243,12 @@ fn parse_create_table_constraints_only() { let sql = "CREATE TABLE t (CONSTRAINT positive CHECK (2 > 1))"; let ast = pg_and_generic().verified_stmt(sql); match ast { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, columns, constraints, .. - } => { + }) => { assert_eq!("t", name.to_string()); assert!(columns.is_empty()); assert_eq!( @@ -265,11 +265,11 @@ fn parse_create_table_if_not_exists() { let sql = "CREATE TABLE IF NOT EXISTS uk_cities ()"; let ast = pg_and_generic().verified_stmt(sql); match ast { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, if_not_exists: true, .. - } => { + }) => { assert_eq!("uk_cities", name.to_string()); } _ => unreachable!(), @@ -321,11 +321,11 @@ fn parse_drop_schema_if_exists() { let sql = "DROP SCHEMA IF EXISTS schema_name"; let ast = pg().verified_stmt(sql); match ast { - Statement::Drop { + Statement::Drop(DropStatement { object_type, if_exists: true, .. - } => assert_eq!(object_type, ObjectType::Schema), + }) => assert_eq!(object_type, ObjectType::Schema), _ => unreachable!(), } } @@ -362,58 +362,58 @@ fn parse_set() { let stmt = pg_and_generic().verified_stmt("SET a = b"); assert_eq!( stmt, - Statement::SetVariable { + Statement::SetVariable(SetVariableStatement { local: false, hivevar: false, variable: "a".into(), value: vec![SetVariableValue::Ident("b".into())], - } + }) ); let stmt = pg_and_generic().verified_stmt("SET a = 'b'"); assert_eq!( stmt, - Statement::SetVariable { + Statement::SetVariable(SetVariableStatement { local: false, hivevar: false, variable: "a".into(), value: vec![SetVariableValue::Literal(Value::SingleQuotedString( "b".into() ))], - } + }) ); let stmt = pg_and_generic().verified_stmt("SET a = 0"); assert_eq!( stmt, - Statement::SetVariable { + Statement::SetVariable(SetVariableStatement { local: false, hivevar: false, variable: "a".into(), value: vec![SetVariableValue::Literal(number("0"))], - } + }) ); let stmt = pg_and_generic().verified_stmt("SET a = DEFAULT"); assert_eq!( stmt, - Statement::SetVariable { + Statement::SetVariable(SetVariableStatement { local: false, hivevar: false, variable: "a".into(), value: vec![SetVariableValue::Ident("DEFAULT".into())], - } + }) ); let stmt = pg_and_generic().verified_stmt("SET LOCAL a = b"); assert_eq!( stmt, - Statement::SetVariable { + Statement::SetVariable(SetVariableStatement { local: true, hivevar: false, variable: "a".into(), value: vec![SetVariableValue::Ident("b".into())], - } + }) ); pg_and_generic().one_statement_parses_to("SET a TO b", "SET a = b"); @@ -542,12 +542,12 @@ fn parse_prepare() { _ => unreachable!(), }; match sub_stmt.as_ref() { - Statement::Insert { + Statement::Insert(InsertStatement { table_name, columns, source, .. - } => { + }) => { assert_eq!(table_name.to_string(), "customers"); assert!(columns.is_empty()); diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 1b1aaec9b..ccc1a1e52 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -27,7 +27,7 @@ use sqlparser::tokenizer::*; fn test_snowflake_create_table() { let sql = "CREATE TABLE _my_$table (am00unt number)"; match snowflake_and_generic().verified_stmt(sql) { - Statement::CreateTable { name, .. } => { + Statement::CreateTable(CreateTableStatement { name, .. }) => { assert_eq!("_my_$table", name.to_string()); } _ => unreachable!(), diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs index 10816e1bb..b7c197266 100644 --- a/tests/sqlparser_sqlite.rs +++ b/tests/sqlparser_sqlite.rs @@ -26,11 +26,11 @@ use sqlparser::tokenizer::Token; fn parse_create_table_without_rowid() { let sql = "CREATE TABLE t (a INT) WITHOUT ROWID"; match sqlite_and_generic().verified_stmt(sql) { - Statement::CreateTable { + Statement::CreateTable(CreateTableStatement { name, without_rowid: true, .. - } => { + }) => { assert_eq!("t", name.to_string()); } _ => unreachable!(), @@ -41,12 +41,12 @@ fn parse_create_table_without_rowid() { fn parse_create_virtual_table() { let sql = "CREATE VIRTUAL TABLE IF NOT EXISTS t USING module_name (arg1, arg2)"; match sqlite_and_generic().verified_stmt(sql) { - Statement::CreateVirtualTable { + Statement::CreateVirtualTable(CreateVirtualTableStatement { name, if_not_exists: true, module_name, module_args, - } => { + }) => { let args = vec![Ident::new("arg1"), Ident::new("arg2")]; assert_eq!("t", name.to_string()); assert_eq!("module_name", module_name.to_string()); @@ -63,7 +63,7 @@ fn parse_create_virtual_table() { fn parse_create_table_auto_increment() { let sql = "CREATE TABLE foo (bar INT PRIMARY KEY AUTOINCREMENT)"; match sqlite_and_generic().verified_stmt(sql) { - Statement::CreateTable { name, columns, .. } => { + Statement::CreateTable(CreateTableStatement { name, columns, .. }) => { assert_eq!(name.to_string(), "foo"); assert_eq!( vec![ColumnDef { @@ -94,7 +94,7 @@ fn parse_create_table_auto_increment() { fn parse_create_sqlite_quote() { let sql = "CREATE TABLE `PRIMARY` (\"KEY\" INT, [INDEX] INT)"; match sqlite().verified_stmt(sql) { - Statement::CreateTable { name, columns, .. } => { + Statement::CreateTable(CreateTableStatement { name, columns, .. }) => { assert_eq!(name.to_string(), "`PRIMARY`"); assert_eq!( vec![ From 6c7617a8839de44400847f592db561f04c560d2e Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Thu, 3 Jun 2021 10:48:00 -0500 Subject: [PATCH 2/2] fixup! extract enum fields to named structs --- src/ast/mod.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 131d44b68..f474f25de 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -663,18 +663,6 @@ pub struct SetVariableStatement { pub value: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ShowVariableStatement {} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ShowColumnsStatement {} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct StartTransactionStatement {} - /// A top-level statement (SELECT, INSERT, CREATE, etc.) #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]