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::physical_plan::ExecutionPlan;
30use futures::TryStreamExt;
31use orc_rust::reader::metadata::read_metadata_async;
32
33use crate::OrcSource;
34use async_trait::async_trait;
35use datafusion::catalog::Session;
36use datafusion::datasource::source::DataSourceExec;
37use futures_util::StreamExt;
38use object_store::path::Path;
39use object_store::{ObjectMeta, ObjectStore};
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(state.config_options().execution.meta_fetch_concurrency)
82 .try_collect()
83 .await?;
84
85 schemas.sort_by(|(location1, _), (location2, _)| location1.cmp(location2));
92
93 let schemas = schemas
94 .into_iter()
95 .map(|(_, schema)| schema)
96 .collect::<Vec<_>>();
97
98 let schema = Schema::try_merge(schemas)?;
99
100 Ok(Arc::new(schema))
101 }
102
103 async fn infer_stats(
104 &self,
105 _state: &dyn Session,
106 _store: &Arc<dyn ObjectStore>,
107 table_schema: SchemaRef,
108 _object: &ObjectMeta,
109 ) -> Result<Statistics> {
110 Ok(Statistics::new_unknown(&table_schema))
111 }
112
113 async fn create_physical_plan(
114 &self,
115 _state: &dyn Session,
116 conf: FileScanConfig,
117 ) -> Result<Arc<dyn ExecutionPlan>> {
118 Ok(DataSourceExec::from_data_source(conf))
119 }
120
121 fn file_source(&self, table_schema: TableSchema) -> Arc<dyn FileSource> {
122 Arc::new(OrcSource::new(table_schema))
123 }
124}