This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new fa50636c6a Implement physical plan serialization for parquet Copy
plans (#11735)
fa50636c6a is described below
commit fa50636c6aec0f321212ed8678c77de25b71a8f9
Author: Lordworms <[email protected]>
AuthorDate: Wed Jul 31 09:23:14 2024 -0700
Implement physical plan serialization for parquet Copy plans (#11735)
* Implement physical plan serialization for parquet Copy plans
* fix clippy
---
.../core/src/datasource/file_format/parquet.rs | 3 +-
.../proto-common/proto/datafusion_common.proto | 1 +
datafusion/proto-common/src/from_proto/mod.rs | 22 +-
datafusion/proto-common/src/generated/pbjson.rs | 900 +++++++++++----------
datafusion/proto-common/src/generated/prost.rs | 53 +-
datafusion/proto-common/src/to_proto/mod.rs | 29 +-
.../proto/src/generated/datafusion_proto_common.rs | 5 +
datafusion/proto/src/logical_plan/file_formats.rs | 264 +++++-
.../proto/tests/cases/roundtrip_logical_plan.rs | 82 ++
9 files changed, 867 insertions(+), 492 deletions(-)
diff --git a/datafusion/core/src/datasource/file_format/parquet.rs
b/datafusion/core/src/datasource/file_format/parquet.rs
index 8a1cd2a147..25956665d5 100644
--- a/datafusion/core/src/datasource/file_format/parquet.rs
+++ b/datafusion/core/src/datasource/file_format/parquet.rs
@@ -93,7 +93,8 @@ const BUFFER_FLUSH_BYTES: usize = 1024000;
#[derive(Default)]
/// Factory struct used to create [ParquetFormat]
pub struct ParquetFormatFactory {
- options: Option<TableParquetOptions>,
+ /// inner options for parquet
+ pub options: Option<TableParquetOptions>,
}
impl ParquetFormatFactory {
diff --git a/datafusion/proto-common/proto/datafusion_common.proto
b/datafusion/proto-common/proto/datafusion_common.proto
index c59aaa2d42..9268ccca0b 100644
--- a/datafusion/proto-common/proto/datafusion_common.proto
+++ b/datafusion/proto-common/proto/datafusion_common.proto
@@ -434,6 +434,7 @@ message JsonOptions {
message TableParquetOptions {
ParquetOptions global = 1;
repeated ParquetColumnSpecificOptions column_specific_options = 2;
+ map<string, string> key_value_metadata = 3;
}
message ParquetColumnSpecificOptions {
diff --git a/datafusion/proto-common/src/from_proto/mod.rs
b/datafusion/proto-common/src/from_proto/mod.rs
index 45703d8b9f..3487f43ae2 100644
--- a/datafusion/proto-common/src/from_proto/mod.rs
+++ b/datafusion/proto-common/src/from_proto/mod.rs
@@ -961,48 +961,48 @@ impl TryFrom<&protobuf::ParquetOptions> for
ParquetOptions {
}
}
-impl TryFrom<&protobuf::ColumnOptions> for ParquetColumnOptions {
+impl TryFrom<&protobuf::ParquetColumnOptions> for ParquetColumnOptions {
type Error = DataFusionError;
fn try_from(
- value: &protobuf::ColumnOptions,
+ value: &protobuf::ParquetColumnOptions,
) -> datafusion_common::Result<Self, Self::Error> {
Ok(ParquetColumnOptions {
compression: value.compression_opt.clone().map(|opt| match opt {
- protobuf::column_options::CompressionOpt::Compression(v) =>
Some(v),
+
protobuf::parquet_column_options::CompressionOpt::Compression(v) => Some(v),
}).unwrap_or(None),
- dictionary_enabled:
value.dictionary_enabled_opt.as_ref().map(|protobuf::column_options::DictionaryEnabledOpt::DictionaryEnabled(v)|
*v),
+ dictionary_enabled:
value.dictionary_enabled_opt.as_ref().map(|protobuf::parquet_column_options::DictionaryEnabledOpt::DictionaryEnabled(v)|
*v),
statistics_enabled: value
.statistics_enabled_opt.clone()
.map(|opt| match opt {
-
protobuf::column_options::StatisticsEnabledOpt::StatisticsEnabled(v) => Some(v),
+
protobuf::parquet_column_options::StatisticsEnabledOpt::StatisticsEnabled(v) =>
Some(v),
})
.unwrap_or(None),
max_statistics_size: value
.max_statistics_size_opt.clone()
.map(|opt| match opt {
-
protobuf::column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(v) => Some(v
as usize),
+
protobuf::parquet_column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(v) =>
Some(v as usize),
})
.unwrap_or(None),
encoding: value
.encoding_opt.clone()
.map(|opt| match opt {
- protobuf::column_options::EncodingOpt::Encoding(v) =>
Some(v),
+ protobuf::parquet_column_options::EncodingOpt::Encoding(v)
=> Some(v),
})
.unwrap_or(None),
bloom_filter_enabled:
value.bloom_filter_enabled_opt.clone().map(|opt| match opt {
-
protobuf::column_options::BloomFilterEnabledOpt::BloomFilterEnabled(v) =>
Some(v),
+
protobuf::parquet_column_options::BloomFilterEnabledOpt::BloomFilterEnabled(v)
=> Some(v),
})
.unwrap_or(None),
bloom_filter_fpp: value
.bloom_filter_fpp_opt.clone()
.map(|opt| match opt {
-
protobuf::column_options::BloomFilterFppOpt::BloomFilterFpp(v) => Some(v),
+
protobuf::parquet_column_options::BloomFilterFppOpt::BloomFilterFpp(v) =>
Some(v),
})
.unwrap_or(None),
bloom_filter_ndv: value
.bloom_filter_ndv_opt.clone()
.map(|opt| match opt {
-
protobuf::column_options::BloomFilterNdvOpt::BloomFilterNdv(v) => Some(v),
+
protobuf::parquet_column_options::BloomFilterNdvOpt::BloomFilterNdv(v) =>
Some(v),
})
.unwrap_or(None),
})
@@ -1016,7 +1016,7 @@ impl TryFrom<&protobuf::TableParquetOptions> for
TableParquetOptions {
) -> datafusion_common::Result<Self, Self::Error> {
let mut column_specific_options: HashMap<String, ParquetColumnOptions>
=
HashMap::new();
- for protobuf::ColumnSpecificOptions {
+ for protobuf::ParquetColumnSpecificOptions {
column_name,
options: maybe_options,
} in &value.column_specific_options
diff --git a/datafusion/proto-common/src/generated/pbjson.rs
b/datafusion/proto-common/src/generated/pbjson.rs
index 23dd574692..05e57f5585 100644
--- a/datafusion/proto-common/src/generated/pbjson.rs
+++ b/datafusion/proto-common/src/generated/pbjson.rs
@@ -880,347 +880,7 @@ impl<'de> serde::Deserialize<'de> for Column {
deserializer.deserialize_struct("datafusion_common.Column", FIELDS,
GeneratedVisitor)
}
}
-impl serde::Serialize for ColumnOptions {
- #[allow(deprecated)]
- fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
- where
- S: serde::Serializer,
- {
- use serde::ser::SerializeStruct;
- let mut len = 0;
- if self.bloom_filter_enabled_opt.is_some() {
- len += 1;
- }
- if self.encoding_opt.is_some() {
- len += 1;
- }
- if self.dictionary_enabled_opt.is_some() {
- len += 1;
- }
- if self.compression_opt.is_some() {
- len += 1;
- }
- if self.statistics_enabled_opt.is_some() {
- len += 1;
- }
- if self.bloom_filter_fpp_opt.is_some() {
- len += 1;
- }
- if self.bloom_filter_ndv_opt.is_some() {
- len += 1;
- }
- if self.max_statistics_size_opt.is_some() {
- len += 1;
- }
- let mut struct_ser =
serializer.serialize_struct("datafusion_common.ColumnOptions", len)?;
- if let Some(v) = self.bloom_filter_enabled_opt.as_ref() {
- match v {
- column_options::BloomFilterEnabledOpt::BloomFilterEnabled(v)
=> {
- struct_ser.serialize_field("bloomFilterEnabled", v)?;
- }
- }
- }
- if let Some(v) = self.encoding_opt.as_ref() {
- match v {
- column_options::EncodingOpt::Encoding(v) => {
- struct_ser.serialize_field("encoding", v)?;
- }
- }
- }
- if let Some(v) = self.dictionary_enabled_opt.as_ref() {
- match v {
- column_options::DictionaryEnabledOpt::DictionaryEnabled(v) => {
- struct_ser.serialize_field("dictionaryEnabled", v)?;
- }
- }
- }
- if let Some(v) = self.compression_opt.as_ref() {
- match v {
- column_options::CompressionOpt::Compression(v) => {
- struct_ser.serialize_field("compression", v)?;
- }
- }
- }
- if let Some(v) = self.statistics_enabled_opt.as_ref() {
- match v {
- column_options::StatisticsEnabledOpt::StatisticsEnabled(v) => {
- struct_ser.serialize_field("statisticsEnabled", v)?;
- }
- }
- }
- if let Some(v) = self.bloom_filter_fpp_opt.as_ref() {
- match v {
- column_options::BloomFilterFppOpt::BloomFilterFpp(v) => {
- struct_ser.serialize_field("bloomFilterFpp", v)?;
- }
- }
- }
- if let Some(v) = self.bloom_filter_ndv_opt.as_ref() {
- match v {
- column_options::BloomFilterNdvOpt::BloomFilterNdv(v) => {
- #[allow(clippy::needless_borrow)]
- struct_ser.serialize_field("bloomFilterNdv",
ToString::to_string(&v).as_str())?;
- }
- }
- }
- if let Some(v) = self.max_statistics_size_opt.as_ref() {
- match v {
- column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(v) => {
- struct_ser.serialize_field("maxStatisticsSize", v)?;
- }
- }
- }
- struct_ser.end()
- }
-}
-impl<'de> serde::Deserialize<'de> for ColumnOptions {
- #[allow(deprecated)]
- fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- const FIELDS: &[&str] = &[
- "bloom_filter_enabled",
- "bloomFilterEnabled",
- "encoding",
- "dictionary_enabled",
- "dictionaryEnabled",
- "compression",
- "statistics_enabled",
- "statisticsEnabled",
- "bloom_filter_fpp",
- "bloomFilterFpp",
- "bloom_filter_ndv",
- "bloomFilterNdv",
- "max_statistics_size",
- "maxStatisticsSize",
- ];
-
- #[allow(clippy::enum_variant_names)]
- enum GeneratedField {
- BloomFilterEnabled,
- Encoding,
- DictionaryEnabled,
- Compression,
- StatisticsEnabled,
- BloomFilterFpp,
- BloomFilterNdv,
- MaxStatisticsSize,
- }
- impl<'de> serde::Deserialize<'de> for GeneratedField {
- fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
- 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<E>(self, value: &str) ->
std::result::Result<GeneratedField, E>
- where
- E: serde::de::Error,
- {
- match value {
- "bloomFilterEnabled" | "bloom_filter_enabled" =>
Ok(GeneratedField::BloomFilterEnabled),
- "encoding" => Ok(GeneratedField::Encoding),
- "dictionaryEnabled" | "dictionary_enabled" =>
Ok(GeneratedField::DictionaryEnabled),
- "compression" => Ok(GeneratedField::Compression),
- "statisticsEnabled" | "statistics_enabled" =>
Ok(GeneratedField::StatisticsEnabled),
- "bloomFilterFpp" | "bloom_filter_fpp" =>
Ok(GeneratedField::BloomFilterFpp),
- "bloomFilterNdv" | "bloom_filter_ndv" =>
Ok(GeneratedField::BloomFilterNdv),
- "maxStatisticsSize" | "max_statistics_size" =>
Ok(GeneratedField::MaxStatisticsSize),
- _ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
- }
- }
- }
- deserializer.deserialize_identifier(GeneratedVisitor)
- }
- }
- struct GeneratedVisitor;
- impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
- type Value = ColumnOptions;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
- formatter.write_str("struct datafusion_common.ColumnOptions")
- }
-
- fn visit_map<V>(self, mut map_: V) ->
std::result::Result<ColumnOptions, V::Error>
- where
- V: serde::de::MapAccess<'de>,
- {
- let mut bloom_filter_enabled_opt__ = None;
- let mut encoding_opt__ = None;
- let mut dictionary_enabled_opt__ = None;
- let mut compression_opt__ = None;
- let mut statistics_enabled_opt__ = None;
- let mut bloom_filter_fpp_opt__ = None;
- let mut bloom_filter_ndv_opt__ = None;
- let mut max_statistics_size_opt__ = None;
- while let Some(k) = map_.next_key()? {
- match k {
- GeneratedField::BloomFilterEnabled => {
- if bloom_filter_enabled_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("bloomFilterEnabled"));
- }
- bloom_filter_enabled_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(column_options::BloomFilterEnabledOpt::BloomFilterEnabled);
- }
- GeneratedField::Encoding => {
- if encoding_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("encoding"));
- }
- encoding_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(column_options::EncodingOpt::Encoding);
- }
- GeneratedField::DictionaryEnabled => {
- if dictionary_enabled_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("dictionaryEnabled"));
- }
- dictionary_enabled_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(column_options::DictionaryEnabledOpt::DictionaryEnabled);
- }
- GeneratedField::Compression => {
- if compression_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("compression"));
- }
- compression_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(column_options::CompressionOpt::Compression);
- }
- GeneratedField::StatisticsEnabled => {
- if statistics_enabled_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("statisticsEnabled"));
- }
- statistics_enabled_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(column_options::StatisticsEnabledOpt::StatisticsEnabled);
- }
- GeneratedField::BloomFilterFpp => {
- if bloom_filter_fpp_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("bloomFilterFpp"));
- }
- bloom_filter_fpp_opt__ =
map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x|
column_options::BloomFilterFppOpt::BloomFilterFpp(x.0));
- }
- GeneratedField::BloomFilterNdv => {
- if bloom_filter_ndv_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("bloomFilterNdv"));
- }
- bloom_filter_ndv_opt__ =
map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x|
column_options::BloomFilterNdvOpt::BloomFilterNdv(x.0));
- }
- GeneratedField::MaxStatisticsSize => {
- if max_statistics_size_opt__.is_some() {
- return
Err(serde::de::Error::duplicate_field("maxStatisticsSize"));
- }
- max_statistics_size_opt__ =
map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x|
column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(x.0));
- }
- }
- }
- Ok(ColumnOptions {
- bloom_filter_enabled_opt: bloom_filter_enabled_opt__,
- encoding_opt: encoding_opt__,
- dictionary_enabled_opt: dictionary_enabled_opt__,
- compression_opt: compression_opt__,
- statistics_enabled_opt: statistics_enabled_opt__,
- bloom_filter_fpp_opt: bloom_filter_fpp_opt__,
- bloom_filter_ndv_opt: bloom_filter_ndv_opt__,
- max_statistics_size_opt: max_statistics_size_opt__,
- })
- }
- }
- deserializer.deserialize_struct("datafusion_common.ColumnOptions",
FIELDS, GeneratedVisitor)
- }
-}
-impl serde::Serialize for ColumnRelation {
- #[allow(deprecated)]
- fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
- where
- S: serde::Serializer,
- {
- use serde::ser::SerializeStruct;
- let mut len = 0;
- if !self.relation.is_empty() {
- len += 1;
- }
- let mut struct_ser =
serializer.serialize_struct("datafusion_common.ColumnRelation", len)?;
- if !self.relation.is_empty() {
- struct_ser.serialize_field("relation", &self.relation)?;
- }
- struct_ser.end()
- }
-}
-impl<'de> serde::Deserialize<'de> for ColumnRelation {
- #[allow(deprecated)]
- fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- const FIELDS: &[&str] = &[
- "relation",
- ];
-
- #[allow(clippy::enum_variant_names)]
- enum GeneratedField {
- Relation,
- }
- impl<'de> serde::Deserialize<'de> for GeneratedField {
- fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
- 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<E>(self, value: &str) ->
std::result::Result<GeneratedField, E>
- where
- E: serde::de::Error,
- {
- match value {
- "relation" => Ok(GeneratedField::Relation),
- _ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
- }
- }
- }
- deserializer.deserialize_identifier(GeneratedVisitor)
- }
- }
- struct GeneratedVisitor;
- impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
- type Value = ColumnRelation;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
- formatter.write_str("struct datafusion_common.ColumnRelation")
- }
-
- fn visit_map<V>(self, mut map_: V) ->
std::result::Result<ColumnRelation, V::Error>
- where
- V: serde::de::MapAccess<'de>,
- {
- let mut relation__ = None;
- while let Some(k) = map_.next_key()? {
- match k {
- GeneratedField::Relation => {
- if relation__.is_some() {
- return
Err(serde::de::Error::duplicate_field("relation"));
- }
- relation__ = Some(map_.next_value()?);
- }
- }
- }
- Ok(ColumnRelation {
- relation: relation__.unwrap_or_default(),
- })
- }
- }
- deserializer.deserialize_struct("datafusion_common.ColumnRelation",
FIELDS, GeneratedVisitor)
- }
-}
-impl serde::Serialize for ColumnSpecificOptions {
+impl serde::Serialize for ColumnRelation {
#[allow(deprecated)]
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
where
@@ -1228,38 +888,29 @@ impl serde::Serialize for ColumnSpecificOptions {
{
use serde::ser::SerializeStruct;
let mut len = 0;
- if !self.column_name.is_empty() {
- len += 1;
- }
- if self.options.is_some() {
+ if !self.relation.is_empty() {
len += 1;
}
- let mut struct_ser =
serializer.serialize_struct("datafusion_common.ColumnSpecificOptions", len)?;
- if !self.column_name.is_empty() {
- struct_ser.serialize_field("columnName", &self.column_name)?;
- }
- if let Some(v) = self.options.as_ref() {
- struct_ser.serialize_field("options", v)?;
+ let mut struct_ser =
serializer.serialize_struct("datafusion_common.ColumnRelation", len)?;
+ if !self.relation.is_empty() {
+ struct_ser.serialize_field("relation", &self.relation)?;
}
struct_ser.end()
}
}
-impl<'de> serde::Deserialize<'de> for ColumnSpecificOptions {
+impl<'de> serde::Deserialize<'de> for ColumnRelation {
#[allow(deprecated)]
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
- "column_name",
- "columnName",
- "options",
+ "relation",
];
#[allow(clippy::enum_variant_names)]
enum GeneratedField {
- ColumnName,
- Options,
+ Relation,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
@@ -1281,8 +932,7 @@ impl<'de> serde::Deserialize<'de> for
ColumnSpecificOptions {
E: serde::de::Error,
{
match value {
- "columnName" | "column_name" =>
Ok(GeneratedField::ColumnName),
- "options" => Ok(GeneratedField::Options),
+ "relation" => Ok(GeneratedField::Relation),
_ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
}
}
@@ -1292,41 +942,33 @@ impl<'de> serde::Deserialize<'de> for
ColumnSpecificOptions {
}
struct GeneratedVisitor;
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
- type Value = ColumnSpecificOptions;
+ type Value = ColumnRelation;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
- formatter.write_str("struct
datafusion_common.ColumnSpecificOptions")
+ formatter.write_str("struct datafusion_common.ColumnRelation")
}
- fn visit_map<V>(self, mut map_: V) ->
std::result::Result<ColumnSpecificOptions, V::Error>
+ fn visit_map<V>(self, mut map_: V) ->
std::result::Result<ColumnRelation, V::Error>
where
V: serde::de::MapAccess<'de>,
{
- let mut column_name__ = None;
- let mut options__ = None;
+ let mut relation__ = None;
while let Some(k) = map_.next_key()? {
match k {
- GeneratedField::ColumnName => {
- if column_name__.is_some() {
- return
Err(serde::de::Error::duplicate_field("columnName"));
- }
- column_name__ = Some(map_.next_value()?);
- }
- GeneratedField::Options => {
- if options__.is_some() {
- return
Err(serde::de::Error::duplicate_field("options"));
+ GeneratedField::Relation => {
+ if relation__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("relation"));
}
- options__ = map_.next_value()?;
+ relation__ = Some(map_.next_value()?);
}
}
}
- Ok(ColumnSpecificOptions {
- column_name: column_name__.unwrap_or_default(),
- options: options__,
+ Ok(ColumnRelation {
+ relation: relation__.unwrap_or_default(),
})
}
}
-
deserializer.deserialize_struct("datafusion_common.ColumnSpecificOptions",
FIELDS, GeneratedVisitor)
+ deserializer.deserialize_struct("datafusion_common.ColumnRelation",
FIELDS, GeneratedVisitor)
}
}
impl serde::Serialize for ColumnStats {
@@ -4448,30 +4090,231 @@ impl serde::Serialize for List {
{
use serde::ser::SerializeStruct;
let mut len = 0;
- if self.field_type.is_some() {
+ if self.field_type.is_some() {
+ len += 1;
+ }
+ let mut struct_ser =
serializer.serialize_struct("datafusion_common.List", len)?;
+ if let Some(v) = self.field_type.as_ref() {
+ struct_ser.serialize_field("fieldType", v)?;
+ }
+ struct_ser.end()
+ }
+}
+impl<'de> serde::Deserialize<'de> for List {
+ #[allow(deprecated)]
+ fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ const FIELDS: &[&str] = &[
+ "field_type",
+ "fieldType",
+ ];
+
+ #[allow(clippy::enum_variant_names)]
+ enum GeneratedField {
+ FieldType,
+ }
+ impl<'de> serde::Deserialize<'de> for GeneratedField {
+ fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
+ 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<E>(self, value: &str) ->
std::result::Result<GeneratedField, E>
+ where
+ E: serde::de::Error,
+ {
+ match value {
+ "fieldType" | "field_type" =>
Ok(GeneratedField::FieldType),
+ _ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
+ }
+ }
+ }
+ deserializer.deserialize_identifier(GeneratedVisitor)
+ }
+ }
+ struct GeneratedVisitor;
+ impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
+ type Value = List;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
+ formatter.write_str("struct datafusion_common.List")
+ }
+
+ fn visit_map<V>(self, mut map_: V) -> std::result::Result<List,
V::Error>
+ where
+ V: serde::de::MapAccess<'de>,
+ {
+ let mut field_type__ = None;
+ while let Some(k) = map_.next_key()? {
+ match k {
+ GeneratedField::FieldType => {
+ if field_type__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("fieldType"));
+ }
+ field_type__ = map_.next_value()?;
+ }
+ }
+ }
+ Ok(List {
+ field_type: field_type__,
+ })
+ }
+ }
+ deserializer.deserialize_struct("datafusion_common.List", FIELDS,
GeneratedVisitor)
+ }
+}
+impl serde::Serialize for Map {
+ #[allow(deprecated)]
+ fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
+ where
+ S: serde::Serializer,
+ {
+ use serde::ser::SerializeStruct;
+ let mut len = 0;
+ if self.field_type.is_some() {
+ len += 1;
+ }
+ if self.keys_sorted {
+ len += 1;
+ }
+ let mut struct_ser =
serializer.serialize_struct("datafusion_common.Map", len)?;
+ if let Some(v) = self.field_type.as_ref() {
+ struct_ser.serialize_field("fieldType", v)?;
+ }
+ if self.keys_sorted {
+ struct_ser.serialize_field("keysSorted", &self.keys_sorted)?;
+ }
+ struct_ser.end()
+ }
+}
+impl<'de> serde::Deserialize<'de> for Map {
+ #[allow(deprecated)]
+ fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ const FIELDS: &[&str] = &[
+ "field_type",
+ "fieldType",
+ "keys_sorted",
+ "keysSorted",
+ ];
+
+ #[allow(clippy::enum_variant_names)]
+ enum GeneratedField {
+ FieldType,
+ KeysSorted,
+ }
+ impl<'de> serde::Deserialize<'de> for GeneratedField {
+ fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
+ 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<E>(self, value: &str) ->
std::result::Result<GeneratedField, E>
+ where
+ E: serde::de::Error,
+ {
+ match value {
+ "fieldType" | "field_type" =>
Ok(GeneratedField::FieldType),
+ "keysSorted" | "keys_sorted" =>
Ok(GeneratedField::KeysSorted),
+ _ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
+ }
+ }
+ }
+ deserializer.deserialize_identifier(GeneratedVisitor)
+ }
+ }
+ struct GeneratedVisitor;
+ impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
+ type Value = Map;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
+ formatter.write_str("struct datafusion_common.Map")
+ }
+
+ fn visit_map<V>(self, mut map_: V) -> std::result::Result<Map,
V::Error>
+ where
+ V: serde::de::MapAccess<'de>,
+ {
+ let mut field_type__ = None;
+ let mut keys_sorted__ = None;
+ while let Some(k) = map_.next_key()? {
+ match k {
+ GeneratedField::FieldType => {
+ if field_type__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("fieldType"));
+ }
+ field_type__ = map_.next_value()?;
+ }
+ GeneratedField::KeysSorted => {
+ if keys_sorted__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("keysSorted"));
+ }
+ keys_sorted__ = Some(map_.next_value()?);
+ }
+ }
+ }
+ Ok(Map {
+ field_type: field_type__,
+ keys_sorted: keys_sorted__.unwrap_or_default(),
+ })
+ }
+ }
+ deserializer.deserialize_struct("datafusion_common.Map", FIELDS,
GeneratedVisitor)
+ }
+}
+impl serde::Serialize for NdJsonFormat {
+ #[allow(deprecated)]
+ fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
+ where
+ S: serde::Serializer,
+ {
+ use serde::ser::SerializeStruct;
+ let mut len = 0;
+ if self.options.is_some() {
len += 1;
}
- let mut struct_ser =
serializer.serialize_struct("datafusion_common.List", len)?;
- if let Some(v) = self.field_type.as_ref() {
- struct_ser.serialize_field("fieldType", v)?;
+ let mut struct_ser =
serializer.serialize_struct("datafusion_common.NdJsonFormat", len)?;
+ if let Some(v) = self.options.as_ref() {
+ struct_ser.serialize_field("options", v)?;
}
struct_ser.end()
}
}
-impl<'de> serde::Deserialize<'de> for List {
+impl<'de> serde::Deserialize<'de> for NdJsonFormat {
#[allow(deprecated)]
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
- "field_type",
- "fieldType",
+ "options",
];
#[allow(clippy::enum_variant_names)]
enum GeneratedField {
- FieldType,
+ Options,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
@@ -4493,7 +4336,7 @@ impl<'de> serde::Deserialize<'de> for List {
E: serde::de::Error,
{
match value {
- "fieldType" | "field_type" =>
Ok(GeneratedField::FieldType),
+ "options" => Ok(GeneratedField::Options),
_ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
}
}
@@ -4503,36 +4346,36 @@ impl<'de> serde::Deserialize<'de> for List {
}
struct GeneratedVisitor;
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
- type Value = List;
+ type Value = NdJsonFormat;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
- formatter.write_str("struct datafusion_common.List")
+ formatter.write_str("struct datafusion_common.NdJsonFormat")
}
- fn visit_map<V>(self, mut map_: V) -> std::result::Result<List,
V::Error>
+ fn visit_map<V>(self, mut map_: V) ->
std::result::Result<NdJsonFormat, V::Error>
where
V: serde::de::MapAccess<'de>,
{
- let mut field_type__ = None;
+ let mut options__ = None;
while let Some(k) = map_.next_key()? {
match k {
- GeneratedField::FieldType => {
- if field_type__.is_some() {
- return
Err(serde::de::Error::duplicate_field("fieldType"));
+ GeneratedField::Options => {
+ if options__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("options"));
}
- field_type__ = map_.next_value()?;
+ options__ = map_.next_value()?;
}
}
}
- Ok(List {
- field_type: field_type__,
+ Ok(NdJsonFormat {
+ options: options__,
})
}
}
- deserializer.deserialize_struct("datafusion_common.List", FIELDS,
GeneratedVisitor)
+ deserializer.deserialize_struct("datafusion_common.NdJsonFormat",
FIELDS, GeneratedVisitor)
}
}
-impl serde::Serialize for Map {
+impl serde::Serialize for ParquetColumnOptions {
#[allow(deprecated)]
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
where
@@ -4540,39 +4383,124 @@ impl serde::Serialize for Map {
{
use serde::ser::SerializeStruct;
let mut len = 0;
- if self.field_type.is_some() {
+ if self.bloom_filter_enabled_opt.is_some() {
len += 1;
}
- if self.keys_sorted {
+ if self.encoding_opt.is_some() {
len += 1;
}
- let mut struct_ser =
serializer.serialize_struct("datafusion_common.Map", len)?;
- if let Some(v) = self.field_type.as_ref() {
- struct_ser.serialize_field("fieldType", v)?;
+ if self.dictionary_enabled_opt.is_some() {
+ len += 1;
}
- if self.keys_sorted {
- struct_ser.serialize_field("keysSorted", &self.keys_sorted)?;
+ if self.compression_opt.is_some() {
+ len += 1;
+ }
+ if self.statistics_enabled_opt.is_some() {
+ len += 1;
+ }
+ if self.bloom_filter_fpp_opt.is_some() {
+ len += 1;
+ }
+ if self.bloom_filter_ndv_opt.is_some() {
+ len += 1;
+ }
+ if self.max_statistics_size_opt.is_some() {
+ len += 1;
+ }
+ let mut struct_ser =
serializer.serialize_struct("datafusion_common.ParquetColumnOptions", len)?;
+ if let Some(v) = self.bloom_filter_enabled_opt.as_ref() {
+ match v {
+
parquet_column_options::BloomFilterEnabledOpt::BloomFilterEnabled(v) => {
+ struct_ser.serialize_field("bloomFilterEnabled", v)?;
+ }
+ }
+ }
+ if let Some(v) = self.encoding_opt.as_ref() {
+ match v {
+ parquet_column_options::EncodingOpt::Encoding(v) => {
+ struct_ser.serialize_field("encoding", v)?;
+ }
+ }
+ }
+ if let Some(v) = self.dictionary_enabled_opt.as_ref() {
+ match v {
+
parquet_column_options::DictionaryEnabledOpt::DictionaryEnabled(v) => {
+ struct_ser.serialize_field("dictionaryEnabled", v)?;
+ }
+ }
+ }
+ if let Some(v) = self.compression_opt.as_ref() {
+ match v {
+ parquet_column_options::CompressionOpt::Compression(v) => {
+ struct_ser.serialize_field("compression", v)?;
+ }
+ }
+ }
+ if let Some(v) = self.statistics_enabled_opt.as_ref() {
+ match v {
+
parquet_column_options::StatisticsEnabledOpt::StatisticsEnabled(v) => {
+ struct_ser.serialize_field("statisticsEnabled", v)?;
+ }
+ }
+ }
+ if let Some(v) = self.bloom_filter_fpp_opt.as_ref() {
+ match v {
+ parquet_column_options::BloomFilterFppOpt::BloomFilterFpp(v)
=> {
+ struct_ser.serialize_field("bloomFilterFpp", v)?;
+ }
+ }
+ }
+ if let Some(v) = self.bloom_filter_ndv_opt.as_ref() {
+ match v {
+ parquet_column_options::BloomFilterNdvOpt::BloomFilterNdv(v)
=> {
+ #[allow(clippy::needless_borrow)]
+ struct_ser.serialize_field("bloomFilterNdv",
ToString::to_string(&v).as_str())?;
+ }
+ }
+ }
+ if let Some(v) = self.max_statistics_size_opt.as_ref() {
+ match v {
+
parquet_column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(v) => {
+ struct_ser.serialize_field("maxStatisticsSize", v)?;
+ }
+ }
}
struct_ser.end()
}
}
-impl<'de> serde::Deserialize<'de> for Map {
+impl<'de> serde::Deserialize<'de> for ParquetColumnOptions {
#[allow(deprecated)]
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
- "field_type",
- "fieldType",
- "keys_sorted",
- "keysSorted",
+ "bloom_filter_enabled",
+ "bloomFilterEnabled",
+ "encoding",
+ "dictionary_enabled",
+ "dictionaryEnabled",
+ "compression",
+ "statistics_enabled",
+ "statisticsEnabled",
+ "bloom_filter_fpp",
+ "bloomFilterFpp",
+ "bloom_filter_ndv",
+ "bloomFilterNdv",
+ "max_statistics_size",
+ "maxStatisticsSize",
];
#[allow(clippy::enum_variant_names)]
enum GeneratedField {
- FieldType,
- KeysSorted,
+ BloomFilterEnabled,
+ Encoding,
+ DictionaryEnabled,
+ Compression,
+ StatisticsEnabled,
+ BloomFilterFpp,
+ BloomFilterNdv,
+ MaxStatisticsSize,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
@@ -4594,8 +4522,14 @@ impl<'de> serde::Deserialize<'de> for Map {
E: serde::de::Error,
{
match value {
- "fieldType" | "field_type" =>
Ok(GeneratedField::FieldType),
- "keysSorted" | "keys_sorted" =>
Ok(GeneratedField::KeysSorted),
+ "bloomFilterEnabled" | "bloom_filter_enabled" =>
Ok(GeneratedField::BloomFilterEnabled),
+ "encoding" => Ok(GeneratedField::Encoding),
+ "dictionaryEnabled" | "dictionary_enabled" =>
Ok(GeneratedField::DictionaryEnabled),
+ "compression" => Ok(GeneratedField::Compression),
+ "statisticsEnabled" | "statistics_enabled" =>
Ok(GeneratedField::StatisticsEnabled),
+ "bloomFilterFpp" | "bloom_filter_fpp" =>
Ok(GeneratedField::BloomFilterFpp),
+ "bloomFilterNdv" | "bloom_filter_ndv" =>
Ok(GeneratedField::BloomFilterNdv),
+ "maxStatisticsSize" | "max_statistics_size" =>
Ok(GeneratedField::MaxStatisticsSize),
_ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
}
}
@@ -4605,44 +4539,92 @@ impl<'de> serde::Deserialize<'de> for Map {
}
struct GeneratedVisitor;
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
- type Value = Map;
+ type Value = ParquetColumnOptions;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
- formatter.write_str("struct datafusion_common.Map")
+ formatter.write_str("struct
datafusion_common.ParquetColumnOptions")
}
- fn visit_map<V>(self, mut map_: V) -> std::result::Result<Map,
V::Error>
+ fn visit_map<V>(self, mut map_: V) ->
std::result::Result<ParquetColumnOptions, V::Error>
where
V: serde::de::MapAccess<'de>,
{
- let mut field_type__ = None;
- let mut keys_sorted__ = None;
+ let mut bloom_filter_enabled_opt__ = None;
+ let mut encoding_opt__ = None;
+ let mut dictionary_enabled_opt__ = None;
+ let mut compression_opt__ = None;
+ let mut statistics_enabled_opt__ = None;
+ let mut bloom_filter_fpp_opt__ = None;
+ let mut bloom_filter_ndv_opt__ = None;
+ let mut max_statistics_size_opt__ = None;
while let Some(k) = map_.next_key()? {
match k {
- GeneratedField::FieldType => {
- if field_type__.is_some() {
- return
Err(serde::de::Error::duplicate_field("fieldType"));
+ GeneratedField::BloomFilterEnabled => {
+ if bloom_filter_enabled_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("bloomFilterEnabled"));
}
- field_type__ = map_.next_value()?;
+ bloom_filter_enabled_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(parquet_column_options::BloomFilterEnabledOpt::BloomFilterEnabled);
}
- GeneratedField::KeysSorted => {
- if keys_sorted__.is_some() {
- return
Err(serde::de::Error::duplicate_field("keysSorted"));
+ GeneratedField::Encoding => {
+ if encoding_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("encoding"));
}
- keys_sorted__ = Some(map_.next_value()?);
+ encoding_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(parquet_column_options::EncodingOpt::Encoding);
+ }
+ GeneratedField::DictionaryEnabled => {
+ if dictionary_enabled_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("dictionaryEnabled"));
+ }
+ dictionary_enabled_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(parquet_column_options::DictionaryEnabledOpt::DictionaryEnabled);
+ }
+ GeneratedField::Compression => {
+ if compression_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("compression"));
+ }
+ compression_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(parquet_column_options::CompressionOpt::Compression);
+ }
+ GeneratedField::StatisticsEnabled => {
+ if statistics_enabled_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("statisticsEnabled"));
+ }
+ statistics_enabled_opt__ =
map_.next_value::<::std::option::Option<_>>()?.map(parquet_column_options::StatisticsEnabledOpt::StatisticsEnabled);
+ }
+ GeneratedField::BloomFilterFpp => {
+ if bloom_filter_fpp_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("bloomFilterFpp"));
+ }
+ bloom_filter_fpp_opt__ =
map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x|
parquet_column_options::BloomFilterFppOpt::BloomFilterFpp(x.0));
+ }
+ GeneratedField::BloomFilterNdv => {
+ if bloom_filter_ndv_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("bloomFilterNdv"));
+ }
+ bloom_filter_ndv_opt__ =
map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x|
parquet_column_options::BloomFilterNdvOpt::BloomFilterNdv(x.0));
+ }
+ GeneratedField::MaxStatisticsSize => {
+ if max_statistics_size_opt__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("maxStatisticsSize"));
+ }
+ max_statistics_size_opt__ =
map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x|
parquet_column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(x.0));
}
}
}
- Ok(Map {
- field_type: field_type__,
- keys_sorted: keys_sorted__.unwrap_or_default(),
+ Ok(ParquetColumnOptions {
+ bloom_filter_enabled_opt: bloom_filter_enabled_opt__,
+ encoding_opt: encoding_opt__,
+ dictionary_enabled_opt: dictionary_enabled_opt__,
+ compression_opt: compression_opt__,
+ statistics_enabled_opt: statistics_enabled_opt__,
+ bloom_filter_fpp_opt: bloom_filter_fpp_opt__,
+ bloom_filter_ndv_opt: bloom_filter_ndv_opt__,
+ max_statistics_size_opt: max_statistics_size_opt__,
})
}
}
- deserializer.deserialize_struct("datafusion_common.Map", FIELDS,
GeneratedVisitor)
+
deserializer.deserialize_struct("datafusion_common.ParquetColumnOptions",
FIELDS, GeneratedVisitor)
}
}
-impl serde::Serialize for NdJsonFormat {
+impl serde::Serialize for ParquetColumnSpecificOptions {
#[allow(deprecated)]
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok,
S::Error>
where
@@ -4650,28 +4632,37 @@ impl serde::Serialize for NdJsonFormat {
{
use serde::ser::SerializeStruct;
let mut len = 0;
+ if !self.column_name.is_empty() {
+ len += 1;
+ }
if self.options.is_some() {
len += 1;
}
- let mut struct_ser =
serializer.serialize_struct("datafusion_common.NdJsonFormat", len)?;
+ let mut struct_ser =
serializer.serialize_struct("datafusion_common.ParquetColumnSpecificOptions",
len)?;
+ if !self.column_name.is_empty() {
+ struct_ser.serialize_field("columnName", &self.column_name)?;
+ }
if let Some(v) = self.options.as_ref() {
struct_ser.serialize_field("options", v)?;
}
struct_ser.end()
}
}
-impl<'de> serde::Deserialize<'de> for NdJsonFormat {
+impl<'de> serde::Deserialize<'de> for ParquetColumnSpecificOptions {
#[allow(deprecated)]
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
+ "column_name",
+ "columnName",
"options",
];
#[allow(clippy::enum_variant_names)]
enum GeneratedField {
+ ColumnName,
Options,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
@@ -4694,6 +4685,7 @@ impl<'de> serde::Deserialize<'de> for NdJsonFormat {
E: serde::de::Error,
{
match value {
+ "columnName" | "column_name" =>
Ok(GeneratedField::ColumnName),
"options" => Ok(GeneratedField::Options),
_ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
}
@@ -4704,19 +4696,26 @@ impl<'de> serde::Deserialize<'de> for NdJsonFormat {
}
struct GeneratedVisitor;
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
- type Value = NdJsonFormat;
+ type Value = ParquetColumnSpecificOptions;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) ->
std::fmt::Result {
- formatter.write_str("struct datafusion_common.NdJsonFormat")
+ formatter.write_str("struct
datafusion_common.ParquetColumnSpecificOptions")
}
- fn visit_map<V>(self, mut map_: V) ->
std::result::Result<NdJsonFormat, V::Error>
+ fn visit_map<V>(self, mut map_: V) ->
std::result::Result<ParquetColumnSpecificOptions, V::Error>
where
V: serde::de::MapAccess<'de>,
{
+ let mut column_name__ = None;
let mut options__ = None;
while let Some(k) = map_.next_key()? {
match k {
+ GeneratedField::ColumnName => {
+ if column_name__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("columnName"));
+ }
+ column_name__ = Some(map_.next_value()?);
+ }
GeneratedField::Options => {
if options__.is_some() {
return
Err(serde::de::Error::duplicate_field("options"));
@@ -4725,12 +4724,13 @@ impl<'de> serde::Deserialize<'de> for NdJsonFormat {
}
}
}
- Ok(NdJsonFormat {
+ Ok(ParquetColumnSpecificOptions {
+ column_name: column_name__.unwrap_or_default(),
options: options__,
})
}
}
- deserializer.deserialize_struct("datafusion_common.NdJsonFormat",
FIELDS, GeneratedVisitor)
+
deserializer.deserialize_struct("datafusion_common.ParquetColumnSpecificOptions",
FIELDS, GeneratedVisitor)
}
}
impl serde::Serialize for ParquetFormat {
@@ -7558,6 +7558,9 @@ impl serde::Serialize for TableParquetOptions {
if !self.column_specific_options.is_empty() {
len += 1;
}
+ if !self.key_value_metadata.is_empty() {
+ len += 1;
+ }
let mut struct_ser =
serializer.serialize_struct("datafusion_common.TableParquetOptions", len)?;
if let Some(v) = self.global.as_ref() {
struct_ser.serialize_field("global", v)?;
@@ -7565,6 +7568,9 @@ impl serde::Serialize for TableParquetOptions {
if !self.column_specific_options.is_empty() {
struct_ser.serialize_field("columnSpecificOptions",
&self.column_specific_options)?;
}
+ if !self.key_value_metadata.is_empty() {
+ struct_ser.serialize_field("keyValueMetadata",
&self.key_value_metadata)?;
+ }
struct_ser.end()
}
}
@@ -7578,12 +7584,15 @@ impl<'de> serde::Deserialize<'de> for
TableParquetOptions {
"global",
"column_specific_options",
"columnSpecificOptions",
+ "key_value_metadata",
+ "keyValueMetadata",
];
#[allow(clippy::enum_variant_names)]
enum GeneratedField {
Global,
ColumnSpecificOptions,
+ KeyValueMetadata,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) ->
std::result::Result<GeneratedField, D::Error>
@@ -7607,6 +7616,7 @@ impl<'de> serde::Deserialize<'de> for TableParquetOptions
{
match value {
"global" => Ok(GeneratedField::Global),
"columnSpecificOptions" |
"column_specific_options" => Ok(GeneratedField::ColumnSpecificOptions),
+ "keyValueMetadata" | "key_value_metadata" =>
Ok(GeneratedField::KeyValueMetadata),
_ => Err(serde::de::Error::unknown_field(value,
FIELDS)),
}
}
@@ -7628,6 +7638,7 @@ impl<'de> serde::Deserialize<'de> for TableParquetOptions
{
{
let mut global__ = None;
let mut column_specific_options__ = None;
+ let mut key_value_metadata__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::Global => {
@@ -7642,11 +7653,20 @@ impl<'de> serde::Deserialize<'de> for
TableParquetOptions {
}
column_specific_options__ =
Some(map_.next_value()?);
}
+ GeneratedField::KeyValueMetadata => {
+ if key_value_metadata__.is_some() {
+ return
Err(serde::de::Error::duplicate_field("keyValueMetadata"));
+ }
+ key_value_metadata__ = Some(
+ map_.next_value::<std::collections::HashMap<_,
_>>()?
+ );
+ }
}
}
Ok(TableParquetOptions {
global: global__,
column_specific_options:
column_specific_options__.unwrap_or_default(),
+ key_value_metadata:
key_value_metadata__.unwrap_or_default(),
})
}
}
diff --git a/datafusion/proto-common/src/generated/prost.rs
b/datafusion/proto-common/src/generated/prost.rs
index 9bea9be89e..ebc05718a4 100644
--- a/datafusion/proto-common/src/generated/prost.rs
+++ b/datafusion/proto-common/src/generated/prost.rs
@@ -670,46 +670,55 @@ pub struct TableParquetOptions {
#[prost(message, optional, tag = "1")]
pub global: ::core::option::Option<ParquetOptions>,
#[prost(message, repeated, tag = "2")]
- pub column_specific_options:
::prost::alloc::vec::Vec<ColumnSpecificOptions>,
+ pub column_specific_options:
::prost::alloc::vec::Vec<ParquetColumnSpecificOptions>,
+ #[prost(map = "string, string", tag = "3")]
+ pub key_value_metadata: ::std::collections::HashMap<
+ ::prost::alloc::string::String,
+ ::prost::alloc::string::String,
+ >,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
-pub struct ColumnSpecificOptions {
+pub struct ParquetColumnSpecificOptions {
#[prost(string, tag = "1")]
pub column_name: ::prost::alloc::string::String,
#[prost(message, optional, tag = "2")]
- pub options: ::core::option::Option<ColumnOptions>,
+ pub options: ::core::option::Option<ParquetColumnOptions>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
-pub struct ColumnOptions {
- #[prost(oneof = "column_options::BloomFilterEnabledOpt", tags = "1")]
+pub struct ParquetColumnOptions {
+ #[prost(oneof = "parquet_column_options::BloomFilterEnabledOpt", tags =
"1")]
pub bloom_filter_enabled_opt: ::core::option::Option<
- column_options::BloomFilterEnabledOpt,
+ parquet_column_options::BloomFilterEnabledOpt,
>,
- #[prost(oneof = "column_options::EncodingOpt", tags = "2")]
- pub encoding_opt: ::core::option::Option<column_options::EncodingOpt>,
- #[prost(oneof = "column_options::DictionaryEnabledOpt", tags = "3")]
+ #[prost(oneof = "parquet_column_options::EncodingOpt", tags = "2")]
+ pub encoding_opt:
::core::option::Option<parquet_column_options::EncodingOpt>,
+ #[prost(oneof = "parquet_column_options::DictionaryEnabledOpt", tags =
"3")]
pub dictionary_enabled_opt: ::core::option::Option<
- column_options::DictionaryEnabledOpt,
+ parquet_column_options::DictionaryEnabledOpt,
>,
- #[prost(oneof = "column_options::CompressionOpt", tags = "4")]
- pub compression_opt:
::core::option::Option<column_options::CompressionOpt>,
- #[prost(oneof = "column_options::StatisticsEnabledOpt", tags = "5")]
+ #[prost(oneof = "parquet_column_options::CompressionOpt", tags = "4")]
+ pub compression_opt:
::core::option::Option<parquet_column_options::CompressionOpt>,
+ #[prost(oneof = "parquet_column_options::StatisticsEnabledOpt", tags =
"5")]
pub statistics_enabled_opt: ::core::option::Option<
- column_options::StatisticsEnabledOpt,
+ parquet_column_options::StatisticsEnabledOpt,
+ >,
+ #[prost(oneof = "parquet_column_options::BloomFilterFppOpt", tags = "6")]
+ pub bloom_filter_fpp_opt: ::core::option::Option<
+ parquet_column_options::BloomFilterFppOpt,
+ >,
+ #[prost(oneof = "parquet_column_options::BloomFilterNdvOpt", tags = "7")]
+ pub bloom_filter_ndv_opt: ::core::option::Option<
+ parquet_column_options::BloomFilterNdvOpt,
>,
- #[prost(oneof = "column_options::BloomFilterFppOpt", tags = "6")]
- pub bloom_filter_fpp_opt:
::core::option::Option<column_options::BloomFilterFppOpt>,
- #[prost(oneof = "column_options::BloomFilterNdvOpt", tags = "7")]
- pub bloom_filter_ndv_opt:
::core::option::Option<column_options::BloomFilterNdvOpt>,
- #[prost(oneof = "column_options::MaxStatisticsSizeOpt", tags = "8")]
+ #[prost(oneof = "parquet_column_options::MaxStatisticsSizeOpt", tags =
"8")]
pub max_statistics_size_opt: ::core::option::Option<
- column_options::MaxStatisticsSizeOpt,
+ parquet_column_options::MaxStatisticsSizeOpt,
>,
}
-/// Nested message and enum types in `ColumnOptions`.
-pub mod column_options {
+/// Nested message and enum types in `ParquetColumnOptions`.
+pub mod parquet_column_options {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum BloomFilterEnabledOpt {
diff --git a/datafusion/proto-common/src/to_proto/mod.rs
b/datafusion/proto-common/src/to_proto/mod.rs
index a61a026089..4cf7e73ac9 100644
--- a/datafusion/proto-common/src/to_proto/mod.rs
+++ b/datafusion/proto-common/src/to_proto/mod.rs
@@ -15,6 +15,7 @@
// specific language governing permissions and limitations
// under the License.
+use std::collections::HashMap;
use std::sync::Arc;
use crate::protobuf_common as protobuf;
@@ -832,42 +833,42 @@ impl TryFrom<&ParquetOptions> for
protobuf::ParquetOptions {
}
}
-impl TryFrom<&ParquetColumnOptions> for protobuf::ColumnOptions {
+impl TryFrom<&ParquetColumnOptions> for protobuf::ParquetColumnOptions {
type Error = DataFusionError;
fn try_from(
value: &ParquetColumnOptions,
) -> datafusion_common::Result<Self, Self::Error> {
- Ok(protobuf::ColumnOptions {
+ Ok(protobuf::ParquetColumnOptions {
compression_opt: value
.compression
.clone()
- .map(protobuf::column_options::CompressionOpt::Compression),
+
.map(protobuf::parquet_column_options::CompressionOpt::Compression),
dictionary_enabled_opt: value
.dictionary_enabled
-
.map(protobuf::column_options::DictionaryEnabledOpt::DictionaryEnabled),
+
.map(protobuf::parquet_column_options::DictionaryEnabledOpt::DictionaryEnabled),
statistics_enabled_opt: value
.statistics_enabled
.clone()
-
.map(protobuf::column_options::StatisticsEnabledOpt::StatisticsEnabled),
+
.map(protobuf::parquet_column_options::StatisticsEnabledOpt::StatisticsEnabled),
max_statistics_size_opt: value.max_statistics_size.map(|v| {
-
protobuf::column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(
+
protobuf::parquet_column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(
v as u32,
)
}),
encoding_opt: value
.encoding
.clone()
- .map(protobuf::column_options::EncodingOpt::Encoding),
+ .map(protobuf::parquet_column_options::EncodingOpt::Encoding),
bloom_filter_enabled_opt: value
.bloom_filter_enabled
-
.map(protobuf::column_options::BloomFilterEnabledOpt::BloomFilterEnabled),
+
.map(protobuf::parquet_column_options::BloomFilterEnabledOpt::BloomFilterEnabled),
bloom_filter_fpp_opt: value
.bloom_filter_fpp
-
.map(protobuf::column_options::BloomFilterFppOpt::BloomFilterFpp),
+
.map(protobuf::parquet_column_options::BloomFilterFppOpt::BloomFilterFpp),
bloom_filter_ndv_opt: value
.bloom_filter_ndv
-
.map(protobuf::column_options::BloomFilterNdvOpt::BloomFilterNdv),
+
.map(protobuf::parquet_column_options::BloomFilterNdvOpt::BloomFilterNdv),
})
}
}
@@ -881,15 +882,21 @@ impl TryFrom<&TableParquetOptions> for
protobuf::TableParquetOptions {
.column_specific_options
.iter()
.map(|(k, v)| {
- Ok(protobuf::ColumnSpecificOptions {
+ Ok(protobuf::ParquetColumnSpecificOptions {
column_name: k.into(),
options: Some(v.try_into()?),
})
})
.collect::<datafusion_common::Result<Vec<_>>>()?;
+ let key_value_metadata = value
+ .key_value_metadata
+ .iter()
+ .filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone())))
+ .collect::<HashMap<String, String>>();
Ok(protobuf::TableParquetOptions {
global: Some((&value.global).try_into()?),
column_specific_options,
+ key_value_metadata,
})
}
}
diff --git a/datafusion/proto/src/generated/datafusion_proto_common.rs
b/datafusion/proto/src/generated/datafusion_proto_common.rs
index f48b05e8d3..ebc05718a4 100644
--- a/datafusion/proto/src/generated/datafusion_proto_common.rs
+++ b/datafusion/proto/src/generated/datafusion_proto_common.rs
@@ -671,6 +671,11 @@ pub struct TableParquetOptions {
pub global: ::core::option::Option<ParquetOptions>,
#[prost(message, repeated, tag = "2")]
pub column_specific_options:
::prost::alloc::vec::Vec<ParquetColumnSpecificOptions>,
+ #[prost(map = "string, string", tag = "3")]
+ pub key_value_metadata: ::std::collections::HashMap<
+ ::prost::alloc::string::String,
+ ::prost::alloc::string::String,
+ >,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
diff --git a/datafusion/proto/src/logical_plan/file_formats.rs
b/datafusion/proto/src/logical_plan/file_formats.rs
index ce9d24d94d..607a3d8642 100644
--- a/datafusion/proto/src/logical_plan/file_formats.rs
+++ b/datafusion/proto/src/logical_plan/file_formats.rs
@@ -18,7 +18,10 @@
use std::sync::Arc;
use datafusion::{
- config::{CsvOptions, JsonOptions},
+ config::{
+ CsvOptions, JsonOptions, ParquetColumnOptions, ParquetOptions,
+ TableParquetOptions,
+ },
datasource::file_format::{
arrow::ArrowFormatFactory, csv::CsvFormatFactory,
json::JsonFormatFactory,
parquet::ParquetFormatFactory, FileFormatFactory,
@@ -31,7 +34,12 @@ use datafusion_common::{
};
use prost::Message;
-use crate::protobuf::{CsvOptions as CsvOptionsProto, JsonOptions as
JsonOptionsProto};
+use crate::protobuf::{
+ parquet_column_options, parquet_options, CsvOptions as CsvOptionsProto,
+ JsonOptions as JsonOptionsProto, ParquetColumnOptions as
ParquetColumnOptionsProto,
+ ParquetColumnSpecificOptions, ParquetOptions as ParquetOptionsProto,
+ TableParquetOptions as TableParquetOptionsProto,
+};
use super::LogicalExtensionCodec;
@@ -337,6 +345,218 @@ impl LogicalExtensionCodec for JsonLogicalExtensionCodec {
}
}
+impl TableParquetOptionsProto {
+ fn from_factory(factory: &ParquetFormatFactory) -> Self {
+ let global_options = if let Some(ref options) = factory.options {
+ options.clone()
+ } else {
+ return TableParquetOptionsProto::default();
+ };
+
+ let column_specific_options = global_options.column_specific_options;
+ TableParquetOptionsProto {
+ global: Some(ParquetOptionsProto {
+ enable_page_index: global_options.global.enable_page_index,
+ pruning: global_options.global.pruning,
+ skip_metadata: global_options.global.skip_metadata,
+ metadata_size_hint_opt:
global_options.global.metadata_size_hint.map(|size| {
+
parquet_options::MetadataSizeHintOpt::MetadataSizeHint(size as u64)
+ }),
+ pushdown_filters: global_options.global.pushdown_filters,
+ reorder_filters: global_options.global.reorder_filters,
+ data_pagesize_limit: global_options.global.data_pagesize_limit
as u64,
+ write_batch_size: global_options.global.write_batch_size as
u64,
+ writer_version: global_options.global.writer_version.clone(),
+ compression_opt:
global_options.global.compression.map(|compression| {
+ parquet_options::CompressionOpt::Compression(compression)
+ }),
+ dictionary_enabled_opt:
global_options.global.dictionary_enabled.map(|enabled| {
+
parquet_options::DictionaryEnabledOpt::DictionaryEnabled(enabled)
+ }),
+ dictionary_page_size_limit:
global_options.global.dictionary_page_size_limit as u64,
+ statistics_enabled_opt:
global_options.global.statistics_enabled.map(|enabled| {
+
parquet_options::StatisticsEnabledOpt::StatisticsEnabled(enabled)
+ }),
+ max_statistics_size_opt:
global_options.global.max_statistics_size.map(|size| {
+
parquet_options::MaxStatisticsSizeOpt::MaxStatisticsSize(size as u64)
+ }),
+ max_row_group_size: global_options.global.max_row_group_size
as u64,
+ created_by: global_options.global.created_by.clone(),
+ column_index_truncate_length_opt:
global_options.global.column_index_truncate_length.map(|length| {
+
parquet_options::ColumnIndexTruncateLengthOpt::ColumnIndexTruncateLength(length
as u64)
+ }),
+ data_page_row_count_limit:
global_options.global.data_page_row_count_limit as u64,
+ encoding_opt: global_options.global.encoding.map(|encoding| {
+ parquet_options::EncodingOpt::Encoding(encoding)
+ }),
+ bloom_filter_on_read:
global_options.global.bloom_filter_on_read,
+ bloom_filter_on_write:
global_options.global.bloom_filter_on_write,
+ bloom_filter_fpp_opt:
global_options.global.bloom_filter_fpp.map(|fpp| {
+ parquet_options::BloomFilterFppOpt::BloomFilterFpp(fpp)
+ }),
+ bloom_filter_ndv_opt:
global_options.global.bloom_filter_ndv.map(|ndv| {
+ parquet_options::BloomFilterNdvOpt::BloomFilterNdv(ndv)
+ }),
+ allow_single_file_parallelism:
global_options.global.allow_single_file_parallelism,
+ maximum_parallel_row_group_writers:
global_options.global.maximum_parallel_row_group_writers as u64,
+ maximum_buffered_record_batches_per_stream:
global_options.global.maximum_buffered_record_batches_per_stream as u64,
+ schema_force_string_view:
global_options.global.schema_force_string_view,
+ }),
+ column_specific_options:
column_specific_options.into_iter().map(|(column_name, options)| {
+ ParquetColumnSpecificOptions {
+ column_name,
+ options: Some(ParquetColumnOptionsProto {
+ bloom_filter_enabled_opt:
options.bloom_filter_enabled.map(|enabled| {
+
parquet_column_options::BloomFilterEnabledOpt::BloomFilterEnabled(enabled)
+ }),
+ encoding_opt: options.encoding.map(|encoding| {
+
parquet_column_options::EncodingOpt::Encoding(encoding)
+ }),
+ dictionary_enabled_opt:
options.dictionary_enabled.map(|enabled| {
+
parquet_column_options::DictionaryEnabledOpt::DictionaryEnabled(enabled)
+ }),
+ compression_opt: options.compression.map(|compression|
{
+
parquet_column_options::CompressionOpt::Compression(compression)
+ }),
+ statistics_enabled_opt:
options.statistics_enabled.map(|enabled| {
+
parquet_column_options::StatisticsEnabledOpt::StatisticsEnabled(enabled)
+ }),
+ bloom_filter_fpp_opt:
options.bloom_filter_fpp.map(|fpp| {
+
parquet_column_options::BloomFilterFppOpt::BloomFilterFpp(fpp)
+ }),
+ bloom_filter_ndv_opt:
options.bloom_filter_ndv.map(|ndv| {
+
parquet_column_options::BloomFilterNdvOpt::BloomFilterNdv(ndv)
+ }),
+ max_statistics_size_opt:
options.max_statistics_size.map(|size| {
+
parquet_column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(size as u32)
+ }),
+ })
+ }
+ }).collect(),
+ key_value_metadata: global_options.key_value_metadata
+ .iter()
+ .filter_map(|(key, value)| {
+ value.as_ref().map(|v| (key.clone(), v.clone()))
+ })
+ .collect(),
+ }
+ }
+}
+
+impl From<&ParquetOptionsProto> for ParquetOptions {
+ fn from(proto: &ParquetOptionsProto) -> Self {
+ ParquetOptions {
+ enable_page_index: proto.enable_page_index,
+ pruning: proto.pruning,
+ skip_metadata: proto.skip_metadata,
+ metadata_size_hint:
proto.metadata_size_hint_opt.as_ref().map(|opt| match opt {
+ parquet_options::MetadataSizeHintOpt::MetadataSizeHint(size)
=> *size as usize,
+ }),
+ pushdown_filters: proto.pushdown_filters,
+ reorder_filters: proto.reorder_filters,
+ data_pagesize_limit: proto.data_pagesize_limit as usize,
+ write_batch_size: proto.write_batch_size as usize,
+ writer_version: proto.writer_version.clone(),
+ compression: proto.compression_opt.as_ref().map(|opt| match opt {
+ parquet_options::CompressionOpt::Compression(compression) =>
compression.clone(),
+ }),
+ dictionary_enabled:
proto.dictionary_enabled_opt.as_ref().map(|opt| match opt {
+
parquet_options::DictionaryEnabledOpt::DictionaryEnabled(enabled) => *enabled,
+ }),
+ dictionary_page_size_limit: proto.dictionary_page_size_limit as
usize,
+ statistics_enabled:
proto.statistics_enabled_opt.as_ref().map(|opt| match opt {
+
parquet_options::StatisticsEnabledOpt::StatisticsEnabled(statistics) =>
statistics.clone(),
+ }),
+ max_statistics_size:
proto.max_statistics_size_opt.as_ref().map(|opt| match opt {
+ parquet_options::MaxStatisticsSizeOpt::MaxStatisticsSize(size)
=> *size as usize,
+ }),
+ max_row_group_size: proto.max_row_group_size as usize,
+ created_by: proto.created_by.clone(),
+ column_index_truncate_length:
proto.column_index_truncate_length_opt.as_ref().map(|opt| match opt {
+
parquet_options::ColumnIndexTruncateLengthOpt::ColumnIndexTruncateLength(length)
=> *length as usize,
+ }),
+ data_page_row_count_limit: proto.data_page_row_count_limit as
usize,
+ encoding: proto.encoding_opt.as_ref().map(|opt| match opt {
+ parquet_options::EncodingOpt::Encoding(encoding) =>
encoding.clone(),
+ }),
+ bloom_filter_on_read: proto.bloom_filter_on_read,
+ bloom_filter_on_write: proto.bloom_filter_on_write,
+ bloom_filter_fpp: proto.bloom_filter_fpp_opt.as_ref().map(|opt|
match opt {
+ parquet_options::BloomFilterFppOpt::BloomFilterFpp(fpp) =>
*fpp,
+ }),
+ bloom_filter_ndv: proto.bloom_filter_ndv_opt.as_ref().map(|opt|
match opt {
+ parquet_options::BloomFilterNdvOpt::BloomFilterNdv(ndv) =>
*ndv,
+ }),
+ allow_single_file_parallelism: proto.allow_single_file_parallelism,
+ maximum_parallel_row_group_writers:
proto.maximum_parallel_row_group_writers as usize,
+ maximum_buffered_record_batches_per_stream:
proto.maximum_buffered_record_batches_per_stream as usize,
+ schema_force_string_view: proto.schema_force_string_view,
+ }
+ }
+}
+
+impl From<ParquetColumnOptionsProto> for ParquetColumnOptions {
+ fn from(proto: ParquetColumnOptionsProto) -> Self {
+ ParquetColumnOptions {
+ bloom_filter_enabled: proto.bloom_filter_enabled_opt.map(
+
|parquet_column_options::BloomFilterEnabledOpt::BloomFilterEnabled(v)| v,
+ ),
+ encoding: proto
+ .encoding_opt
+ .map(|parquet_column_options::EncodingOpt::Encoding(v)| v),
+ dictionary_enabled: proto.dictionary_enabled_opt.map(
+
|parquet_column_options::DictionaryEnabledOpt::DictionaryEnabled(v)| v,
+ ),
+ compression: proto
+ .compression_opt
+ .map(|parquet_column_options::CompressionOpt::Compression(v)|
v),
+ statistics_enabled: proto.statistics_enabled_opt.map(
+
|parquet_column_options::StatisticsEnabledOpt::StatisticsEnabled(v)| v,
+ ),
+ bloom_filter_fpp: proto
+ .bloom_filter_fpp_opt
+
.map(|parquet_column_options::BloomFilterFppOpt::BloomFilterFpp(v)| v),
+ bloom_filter_ndv: proto
+ .bloom_filter_ndv_opt
+
.map(|parquet_column_options::BloomFilterNdvOpt::BloomFilterNdv(v)| v),
+ max_statistics_size: proto.max_statistics_size_opt.map(
+
|parquet_column_options::MaxStatisticsSizeOpt::MaxStatisticsSize(v)| {
+ v as usize
+ },
+ ),
+ }
+ }
+}
+
+impl From<&TableParquetOptionsProto> for TableParquetOptions {
+ fn from(proto: &TableParquetOptionsProto) -> Self {
+ TableParquetOptions {
+ global: proto
+ .global
+ .as_ref()
+ .map(ParquetOptions::from)
+ .unwrap_or_default(),
+ column_specific_options: proto
+ .column_specific_options
+ .iter()
+ .map(|parquet_column_options| {
+ (
+ parquet_column_options.column_name.clone(),
+ ParquetColumnOptions::from(
+
parquet_column_options.options.clone().unwrap_or_default(),
+ ),
+ )
+ })
+ .collect(),
+ key_value_metadata: proto
+ .key_value_metadata
+ .iter()
+ .map(|(k, v)| (k.clone(), Some(v.clone())))
+ .collect(),
+ }
+ }
+}
+
#[derive(Debug)]
pub struct ParquetLogicalExtensionCodec;
@@ -382,17 +602,47 @@ impl LogicalExtensionCodec for
ParquetLogicalExtensionCodec {
fn try_decode_file_format(
&self,
- __buf: &[u8],
- __ctx: &SessionContext,
+ buf: &[u8],
+ _ctx: &SessionContext,
) -> datafusion_common::Result<Arc<dyn FileFormatFactory>> {
- Ok(Arc::new(ParquetFormatFactory::new()))
+ let proto = TableParquetOptionsProto::decode(buf).map_err(|e| {
+ DataFusionError::Execution(format!(
+ "Failed to decode TableParquetOptionsProto: {:?}",
+ e
+ ))
+ })?;
+ let options: TableParquetOptions = (&proto).into();
+ Ok(Arc::new(ParquetFormatFactory {
+ options: Some(options),
+ }))
}
fn try_encode_file_format(
&self,
- __buf: &mut Vec<u8>,
- __node: Arc<dyn FileFormatFactory>,
+ buf: &mut Vec<u8>,
+ node: Arc<dyn FileFormatFactory>,
) -> datafusion_common::Result<()> {
+ let options = if let Some(parquet_factory) =
+ node.as_any().downcast_ref::<ParquetFormatFactory>()
+ {
+ parquet_factory.options.clone().unwrap_or_default()
+ } else {
+ return Err(DataFusionError::Execution(
+ "Unsupported FileFormatFactory type".to_string(),
+ ));
+ };
+
+ let proto =
TableParquetOptionsProto::from_factory(&ParquetFormatFactory {
+ options: Some(options),
+ });
+
+ proto.encode(buf).map_err(|e| {
+ DataFusionError::Execution(format!(
+ "Failed to encode TableParquetOptionsProto: {:?}",
+ e
+ ))
+ })?;
+
Ok(())
}
}
diff --git a/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
b/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
index daa9247506..f7ad2b9b61 100644
--- a/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
+++ b/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
@@ -577,6 +577,74 @@ async fn roundtrip_logical_plan_copy_to_json() ->
Result<()> {
Ok(())
}
+#[tokio::test]
+async fn roundtrip_logical_plan_copy_to_parquet() -> Result<()> {
+ let ctx = SessionContext::new();
+
+ // Assume create_parquet_scan creates a logical plan for scanning a
Parquet file
+ let input = create_parquet_scan(&ctx).await?;
+
+ let table_options =
+
TableOptions::default_from_session_config(ctx.state().config_options());
+ let mut parquet_format = table_options.parquet;
+
+ // Set specific Parquet format options
+ let mut key_value_metadata = HashMap::new();
+ key_value_metadata.insert("test".to_string(), Some("test".to_string()));
+ parquet_format.key_value_metadata = key_value_metadata.clone();
+
+ parquet_format.global.allow_single_file_parallelism = false;
+ parquet_format.global.created_by = "test".to_string();
+
+ let file_type = format_as_file_type(Arc::new(
+ ParquetFormatFactory::new_with_options(parquet_format.clone()),
+ ));
+
+ let plan = LogicalPlan::Copy(CopyTo {
+ input: Arc::new(input),
+ output_url: "test.parquet".to_string(),
+ partition_by: vec!["a".to_string(), "b".to_string(), "c".to_string()],
+ file_type,
+ options: Default::default(),
+ });
+
+ // Assume ParquetLogicalExtensionCodec is implemented similarly to
JsonLogicalExtensionCodec
+ let codec = ParquetLogicalExtensionCodec {};
+ let bytes = logical_plan_to_bytes_with_extension_codec(&plan, &codec)?;
+ let logical_round_trip =
+ logical_plan_from_bytes_with_extension_codec(&bytes, &ctx, &codec)?;
+ assert_eq!(format!("{plan:?}"), format!("{logical_round_trip:?}"));
+
+ match logical_round_trip {
+ LogicalPlan::Copy(copy_to) => {
+ assert_eq!("test.parquet", copy_to.output_url);
+ assert_eq!("parquet".to_string(), copy_to.file_type.get_ext());
+ assert_eq!(vec!["a", "b", "c"], copy_to.partition_by);
+
+ let file_type = copy_to
+ .file_type
+ .as_ref()
+ .as_any()
+ .downcast_ref::<DefaultFileType>()
+ .unwrap();
+
+ let format_factory = file_type.as_format_factory();
+ let parquet_factory = format_factory
+ .as_ref()
+ .as_any()
+ .downcast_ref::<ParquetFormatFactory>()
+ .unwrap();
+ let parquet_config = parquet_factory.options.as_ref().unwrap();
+ assert_eq!(parquet_config.key_value_metadata, key_value_metadata);
+ assert!(!parquet_config.global.allow_single_file_parallelism);
+ assert_eq!(parquet_config.global.created_by, "test".to_string());
+ }
+ _ => panic!(),
+ }
+
+ Ok(())
+}
+
async fn create_csv_scan(ctx: &SessionContext) -> Result<LogicalPlan,
DataFusionError> {
ctx.register_csv("t1", "tests/testdata/test.csv",
CsvReadOptions::default())
.await?;
@@ -597,6 +665,20 @@ async fn create_json_scan(ctx: &SessionContext) ->
Result<LogicalPlan, DataFusio
Ok(input)
}
+async fn create_parquet_scan(
+ ctx: &SessionContext,
+) -> Result<LogicalPlan, DataFusionError> {
+ ctx.register_parquet(
+ "t1",
+ "../substrait/tests/testdata/empty.parquet",
+ ParquetReadOptions::default(),
+ )
+ .await?;
+
+ let input = ctx.table("t1").await?.into_optimized_plan()?;
+ Ok(input)
+}
+
#[tokio::test]
async fn roundtrip_logical_plan_distinct_on() -> Result<()> {
let ctx = SessionContext::new();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]