diff --git a/datafusion/proto/proto/datafusion.proto b/datafusion/proto/proto/datafusion.proto index 2f6367bc188b8..c23d585e61d72 100644 --- a/datafusion/proto/proto/datafusion.proto +++ b/datafusion/proto/proto/datafusion.proto @@ -72,6 +72,7 @@ message LogicalPlanNode { ViewTableScanNode view_scan = 24; CustomTableScanNode custom_scan = 25; PrepareNode prepare = 26; + DropViewNode drop_view = 27; } } @@ -210,6 +211,12 @@ message CreateCatalogNode { DfSchema schema = 3; } +message DropViewNode { + OwnedTableReference name = 1; + bool if_exists = 2; + DfSchema schema = 3; +} + message CreateViewNode { reserved 1; // was string name OwnedTableReference name = 5; diff --git a/datafusion/proto/src/generated/pbjson.rs b/datafusion/proto/src/generated/pbjson.rs index 0134c71e9a89b..369cc0b24e711 100644 --- a/datafusion/proto/src/generated/pbjson.rs +++ b/datafusion/proto/src/generated/pbjson.rs @@ -5397,6 +5397,132 @@ impl<'de> serde::Deserialize<'de> for DistinctNode { deserializer.deserialize_struct("datafusion.DistinctNode", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for DropViewNode { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.name.is_some() { + len += 1; + } + if self.if_exists { + len += 1; + } + if self.schema.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("datafusion.DropViewNode", len)?; + if let Some(v) = self.name.as_ref() { + struct_ser.serialize_field("name", v)?; + } + if self.if_exists { + struct_ser.serialize_field("ifExists", &self.if_exists)?; + } + if let Some(v) = self.schema.as_ref() { + struct_ser.serialize_field("schema", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for DropViewNode { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "name", + "if_exists", + "ifExists", + "schema", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Name, + IfExists, + Schema, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "name" => Ok(GeneratedField::Name), + "ifExists" | "if_exists" => Ok(GeneratedField::IfExists), + "schema" => Ok(GeneratedField::Schema), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = DropViewNode; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct datafusion.DropViewNode") + } + + fn visit_map(self, mut map: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut name__ = None; + let mut if_exists__ = None; + let mut schema__ = None; + while let Some(k) = map.next_key()? { + match k { + GeneratedField::Name => { + if name__.is_some() { + return Err(serde::de::Error::duplicate_field("name")); + } + name__ = map.next_value()?; + } + GeneratedField::IfExists => { + if if_exists__.is_some() { + return Err(serde::de::Error::duplicate_field("ifExists")); + } + if_exists__ = Some(map.next_value()?); + } + GeneratedField::Schema => { + if schema__.is_some() { + return Err(serde::de::Error::duplicate_field("schema")); + } + schema__ = map.next_value()?; + } + } + } + Ok(DropViewNode { + name: name__, + if_exists: if_exists__.unwrap_or_default(), + schema: schema__, + }) + } + } + deserializer.deserialize_struct("datafusion.DropViewNode", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for EmptyExecNode { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result @@ -11138,6 +11264,9 @@ impl serde::Serialize for LogicalPlanNode { logical_plan_node::LogicalPlanType::Prepare(v) => { struct_ser.serialize_field("prepare", v)?; } + logical_plan_node::LogicalPlanType::DropView(v) => { + struct_ser.serialize_field("dropView", v)?; + } } } struct_ser.end() @@ -11185,6 +11314,8 @@ impl<'de> serde::Deserialize<'de> for LogicalPlanNode { "custom_scan", "customScan", "prepare", + "drop_view", + "dropView", ]; #[allow(clippy::enum_variant_names)] @@ -11214,6 +11345,7 @@ impl<'de> serde::Deserialize<'de> for LogicalPlanNode { ViewScan, CustomScan, Prepare, + DropView, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -11260,6 +11392,7 @@ impl<'de> serde::Deserialize<'de> for LogicalPlanNode { "viewScan" | "view_scan" => Ok(GeneratedField::ViewScan), "customScan" | "custom_scan" => Ok(GeneratedField::CustomScan), "prepare" => Ok(GeneratedField::Prepare), + "dropView" | "drop_view" => Ok(GeneratedField::DropView), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -11455,6 +11588,13 @@ impl<'de> serde::Deserialize<'de> for LogicalPlanNode { return Err(serde::de::Error::duplicate_field("prepare")); } logical_plan_type__ = map.next_value::<::std::option::Option<_>>()?.map(logical_plan_node::LogicalPlanType::Prepare) +; + } + GeneratedField::DropView => { + if logical_plan_type__.is_some() { + return Err(serde::de::Error::duplicate_field("dropView")); + } + logical_plan_type__ = map.next_value::<::std::option::Option<_>>()?.map(logical_plan_node::LogicalPlanType::DropView) ; } } diff --git a/datafusion/proto/src/generated/prost.rs b/datafusion/proto/src/generated/prost.rs index bc8987b1d07c1..4cf50d70bf0e6 100644 --- a/datafusion/proto/src/generated/prost.rs +++ b/datafusion/proto/src/generated/prost.rs @@ -38,7 +38,7 @@ pub struct DfSchema { pub struct LogicalPlanNode { #[prost( oneof = "logical_plan_node::LogicalPlanType", - tags = "1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26" + tags = "1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27" )] pub logical_plan_type: ::core::option::Option, } @@ -97,6 +97,8 @@ pub mod logical_plan_node { CustomScan(super::CustomTableScanNode), #[prost(message, tag = "26")] Prepare(::prost::alloc::boxed::Box), + #[prost(message, tag = "27")] + DropView(super::DropViewNode), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -339,6 +341,16 @@ pub struct CreateCatalogNode { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct DropViewNode { + #[prost(message, optional, tag = "1")] + pub name: ::core::option::Option, + #[prost(bool, tag = "2")] + pub if_exists: bool, + #[prost(message, optional, tag = "3")] + pub schema: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct CreateViewNode { #[prost(message, optional, tag = "5")] pub name: ::core::option::Option, diff --git a/datafusion/proto/src/logical_plan/mod.rs b/datafusion/proto/src/logical_plan/mod.rs index d1102faee35ef..3774ce14305dc 100644 --- a/datafusion/proto/src/logical_plan/mod.rs +++ b/datafusion/proto/src/logical_plan/mod.rs @@ -43,6 +43,7 @@ use datafusion_common::{ Result, }; use datafusion_expr::logical_plan::DdlStatement; +use datafusion_expr::DropView; use datafusion_expr::{ logical_plan::{ builder::project, Aggregate, CreateCatalog, CreateCatalogSchema, @@ -769,6 +770,13 @@ impl AsLogicalPlan for LogicalPlanNode { .prepare(prepare.name.clone(), data_types)? .build() } + LogicalPlanType::DropView(dropview) => Ok(datafusion_expr::LogicalPlan::Ddl( + datafusion_expr::DdlStatement::DropView(DropView { + name: from_owned_table_reference(dropview.name.as_ref(), "DropView")?, + if_exists: dropview.if_exists, + schema: Arc::new(convert_required!(dropview.schema)?), + }), + )), } } @@ -1385,9 +1393,19 @@ impl AsLogicalPlan for LogicalPlanNode { LogicalPlan::Ddl(DdlStatement::DropTable(_)) => Err(proto_error( "LogicalPlan serde is not yet implemented for DropTable", )), - LogicalPlan::Ddl(DdlStatement::DropView(_)) => Err(proto_error( - "LogicalPlan serde is not yet implemented for DropView", - )), + LogicalPlan::Ddl(DdlStatement::DropView(DropView { + name, + if_exists, + schema, + })) => Ok(protobuf::LogicalPlanNode { + logical_plan_type: Some(LogicalPlanType::DropView( + protobuf::DropViewNode { + name: Some(name.clone().into()), + if_exists: *if_exists, + schema: Some(schema.try_into()?), + }, + )), + }), LogicalPlan::Ddl(DdlStatement::DropCatalogSchema(_)) => Err(proto_error( "LogicalPlan serde is not yet implemented for DropCatalogSchema", )), @@ -1658,13 +1676,23 @@ mod roundtrip_tests { .await?; ctx.sql("CREATE VIEW view_t1(a, b) AS SELECT a, b FROM t1") .await?; + + // SELECT let plan = ctx .sql("SELECT * FROM view_t1") .await? .into_optimized_plan()?; + + let bytes = logical_plan_to_bytes(&plan)?; + let logical_round_trip = logical_plan_from_bytes(&bytes, &ctx)?; + assert_eq!(format!("{plan:?}"), format!("{logical_round_trip:?}")); + + // DROP + let plan = ctx.sql("DROP VIEW view_t1").await?.into_optimized_plan()?; let bytes = logical_plan_to_bytes(&plan)?; let logical_round_trip = logical_plan_from_bytes(&bytes, &ctx)?; assert_eq!(format!("{plan:?}"), format!("{logical_round_trip:?}")); + Ok(()) }