diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 922f022e6..c5130c8d2 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2001,6 +2001,7 @@ pub enum Statement { if_exists: bool, only: bool, operations: Vec, + location: Option, }, /// ```sql /// ALTER INDEX @@ -3244,12 +3245,10 @@ impl fmt::Display for Statement { } } if *external { - write!( - f, - " STORED AS {} LOCATION '{}'", - file_format.as_ref().unwrap(), - location.as_ref().unwrap() - )?; + if let Some(file_format) = &file_format { + write!(f, " STORED AS {file_format}")?; + } + write!(f, " LOCATION '{}'", location.as_ref().unwrap())?; } if !table_properties.is_empty() { write!( @@ -3499,6 +3498,7 @@ impl fmt::Display for Statement { if_exists, only, operations, + location, } => { write!(f, "ALTER TABLE ")?; if *if_exists { @@ -3511,7 +3511,11 @@ impl fmt::Display for Statement { f, "{name} {operations}", operations = display_comma_separated(operations) - ) + )?; + if let Some(loc) = location { + write!(f, " {loc}")? + } + Ok(()) } Statement::AlterIndex { name, operation } => { write!(f, "ALTER INDEX {name} {operation}") @@ -5794,6 +5798,23 @@ impl fmt::Display for LockTableType { } } +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub struct HiveSetLocation { + pub has_set: bool, + pub location: Ident, +} + +impl fmt::Display for HiveSetLocation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.has_set { + write!(f, "SET ")?; + } + write!(f, "LOCATION {}", self.location) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 436782fd6..66952f018 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -5444,11 +5444,26 @@ impl<'a> Parser<'a> { let only = self.parse_keyword(Keyword::ONLY); // [ ONLY ] let table_name = self.parse_object_name(false)?; let operations = self.parse_comma_separated(Parser::parse_alter_table_operation)?; + + let mut location = None; + if self.parse_keyword(Keyword::LOCATION) { + location = Some(HiveSetLocation { + has_set: false, + location: self.parse_identifier(false)?, + }); + } else if self.parse_keywords(&[Keyword::SET, Keyword::LOCATION]) { + location = Some(HiveSetLocation { + has_set: true, + location: self.parse_identifier(false)?, + }); + } + Ok(Statement::AlterTable { name: table_name, if_exists, only, operations, + location, }) } Keyword::INDEX => { diff --git a/src/test_utils.rs b/src/test_utils.rs index e72403f65..4a54a6826 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -256,6 +256,7 @@ pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTa if_exists, only: is_only, operations, + location: _, } => { assert_eq!(name.to_string(), expected_name); assert!(!if_exists); @@ -265,6 +266,7 @@ pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTa _ => panic!("Expected ALTER TABLE statement"), } } + pub fn alter_table_op(stmt: Statement) -> AlterTableOperation { alter_table_op_with_name(stmt, "tab") } diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index acf6c5829..473e80f62 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -124,6 +124,19 @@ fn test_alter_partition() { hive().verified_stmt(alter); } +#[test] +fn test_alter_with_location() { + let alter = + "ALTER TABLE db.table PARTITION (a = 2) RENAME TO PARTITION (a = 1) LOCATION 's3://...'"; + hive().verified_stmt(alter); +} + +#[test] +fn test_alter_with_set_location() { + let alter = "ALTER TABLE db.table PARTITION (a = 2) RENAME TO PARTITION (a = 1) SET LOCATION 's3://...'"; + hive().verified_stmt(alter); +} + #[test] fn test_add_partition() { let add = "ALTER TABLE db.table ADD IF NOT EXISTS PARTITION (a = 'asdf', b = 2)"; diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 028f40ab9..45ec277e9 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -677,6 +677,7 @@ fn parse_alter_table_add_columns() { if_exists, only, operations, + location: _, } => { assert_eq!(name.to_string(), "tab"); assert!(if_exists);