use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Arc;
use datafusion::arrow::datatypes::{Schema, SchemaRef};
use datafusion::common::Statistics;
use datafusion::datasource::file_format::file_compression_type::FileCompressionType;
use datafusion::datasource::file_format::FileFormat;
use datafusion::datasource::physical_plan::{FileScanConfig, FileSource};
use datafusion::datasource::table_schema::TableSchema;
use datafusion::error::{DataFusionError, Result};
use datafusion::object_store::path::Path;
use datafusion::object_store::{ObjectMeta, ObjectStore};
use datafusion::physical_plan::ExecutionPlan;
use futures::TryStreamExt;
use orc_rust::reader::metadata::read_metadata_async;
use crate::OrcSource;
use async_trait::async_trait;
use datafusion::catalog::Session;
use datafusion::datasource::source::DataSourceExec;
use futures_util::StreamExt;
use super::object_store_reader::ObjectStoreReader;
async fn fetch_schema(store: &Arc<dyn ObjectStore>, file: &ObjectMeta) -> Result<(Path, Schema)> {
let loc_path = file.location.clone();
let mut reader = ObjectStoreReader::new(Arc::clone(store), file.clone());
let metadata = read_metadata_async(&mut reader)
.await
.map_err(|e| DataFusionError::External(Box::new(e)))?;
let schema = metadata
.root_data_type()
.create_arrow_schema(&HashMap::default());
Ok((loc_path, schema))
}
#[derive(Clone, Debug)]
pub struct OrcFormat;
#[async_trait]
impl FileFormat for OrcFormat {
fn get_ext(&self) -> String {
"orc".to_string()
}
fn get_ext_with_compression(&self, _compression: &FileCompressionType) -> Result<String> {
Ok("orc".to_string())
}
fn compression_type(&self) -> Option<FileCompressionType> {
None
}
async fn infer_schema(
&self,
state: &dyn Session,
store: &Arc<dyn ObjectStore>,
objects: &[ObjectMeta],
) -> Result<SchemaRef> {
let mut schemas: Vec<_> = futures::stream::iter(objects)
.map(|object| fetch_schema(store, object))
.boxed() .buffered(
state
.config_options()
.execution
.meta_fetch_concurrency
.into(),
)
.try_collect()
.await?;
schemas.sort_by(|(location1, _), (location2, _)| location1.cmp(location2));
let schemas = schemas
.into_iter()
.map(|(_, schema)| schema)
.collect::<Vec<_>>();
let schema = Schema::try_merge(schemas)?;
Ok(Arc::new(schema))
}
async fn infer_stats(
&self,
_state: &dyn Session,
_store: &Arc<dyn ObjectStore>,
table_schema: SchemaRef,
_object: &ObjectMeta,
) -> Result<Statistics> {
Ok(Statistics::new_unknown(&table_schema))
}
async fn create_physical_plan(
&self,
_state: &dyn Session,
conf: FileScanConfig,
) -> Result<Arc<dyn ExecutionPlan>> {
Ok(DataSourceExec::from_data_source(conf))
}
fn file_source(&self, table_schema: TableSchema) -> Arc<dyn FileSource> {
Arc::new(OrcSource::new(table_schema))
}
}