datafusion_orc/
file_format.rs1use std::collections::HashMap;
19use std::fmt::Debug;
20use std::sync::Arc;
21
22use datafusion::arrow::datatypes::{Schema, SchemaRef};
23use datafusion::common::Statistics;
24use datafusion::datasource::file_format::file_compression_type::FileCompressionType;
25use datafusion::datasource::file_format::FileFormat;
26use datafusion::datasource::physical_plan::{FileScanConfig, FileSource};
27use datafusion::datasource::table_schema::TableSchema;
28use datafusion::error::{DataFusionError, Result};
29use datafusion::object_store::path::Path;
30use datafusion::object_store::{ObjectMeta, ObjectStore};
31use datafusion::physical_plan::ExecutionPlan;
32use futures::TryStreamExt;
33use orc_rust::reader::metadata::read_metadata_async;
34
35use crate::OrcSource;
36use async_trait::async_trait;
37use datafusion::catalog::Session;
38use datafusion::datasource::source::DataSourceExec;
39use futures_util::StreamExt;
40
41use super::object_store_reader::ObjectStoreReader;
42
43async fn fetch_schema(store: &Arc<dyn ObjectStore>, file: &ObjectMeta) -> Result<(Path, Schema)> {
44 let loc_path = file.location.clone();
45 let mut reader = ObjectStoreReader::new(Arc::clone(store), file.clone());
46 let metadata = read_metadata_async(&mut reader)
47 .await
48 .map_err(|e| DataFusionError::External(Box::new(e)))?;
49 let schema = metadata
50 .root_data_type()
51 .create_arrow_schema(&HashMap::default());
52 Ok((loc_path, schema))
53}
54
55#[derive(Clone, Debug)]
56pub struct OrcFormat;
57
58#[async_trait]
59impl FileFormat for OrcFormat {
60 fn get_ext(&self) -> String {
61 "orc".to_string()
62 }
63
64 fn get_ext_with_compression(&self, _compression: &FileCompressionType) -> Result<String> {
65 Ok("orc".to_string())
66 }
67
68 fn compression_type(&self) -> Option<FileCompressionType> {
69 None
70 }
71
72 async fn infer_schema(
73 &self,
74 state: &dyn Session,
75 store: &Arc<dyn ObjectStore>,
76 objects: &[ObjectMeta],
77 ) -> Result<SchemaRef> {
78 let mut schemas: Vec<_> = futures::stream::iter(objects)
79 .map(|object| fetch_schema(store, object))
80 .boxed() .buffered(
82 state
83 .config_options()
84 .execution
85 .meta_fetch_concurrency
86 .into(),
87 )
88 .try_collect()
89 .await?;
90
91 schemas.sort_by(|(location1, _), (location2, _)| location1.cmp(location2));
98
99 let schemas = schemas
100 .into_iter()
101 .map(|(_, schema)| schema)
102 .collect::<Vec<_>>();
103
104 let schema = Schema::try_merge(schemas)?;
105
106 Ok(Arc::new(schema))
107 }
108
109 async fn infer_stats(
110 &self,
111 _state: &dyn Session,
112 _store: &Arc<dyn ObjectStore>,
113 table_schema: SchemaRef,
114 _object: &ObjectMeta,
115 ) -> Result<Statistics> {
116 Ok(Statistics::new_unknown(&table_schema))
117 }
118
119 async fn create_physical_plan(
120 &self,
121 _state: &dyn Session,
122 conf: FileScanConfig,
123 ) -> Result<Arc<dyn ExecutionPlan>> {
124 Ok(DataSourceExec::from_data_source(conf))
125 }
126
127 fn file_source(&self, table_schema: TableSchema) -> Arc<dyn FileSource> {
128 Arc::new(OrcSource::new(table_schema))
129 }
130}