mirror of
https://github.com/langchain-ai/datafusion.git
synced 2026-07-21 03:05:28 -04:00
59dcc362ca
## Which issue does this PR close? Closes https://github.com/apache/datafusion/issues/15804 ## Rationale for this change Now that we are on MSRV 1.88 we can use rust edition 2024, which brings let chains and other nice features. It also improves `unsafe` checking. In order to introduce these changes in slower way instead of one massive PR that is too difficult to manage we are updating a few crates at a time. ## What changes are included in this PR? Updates these crates to 2024. - datafusion-benchmarks - datafusion-ffi - datafusion-sqllogictest - datafusion-examples ## Are these changes tested? Existing unit tests. There are no functional code changes. ## Are there any user-facing changes? None. ## Note It is recommended to review with the ignore whitespace setting: https://github.com/apache/datafusion/pull/19361/files?w=1
241 lines
6.8 KiB
Rust
241 lines
6.8 KiB
Rust
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
//! See `main.rs` for how to run it.
|
|
|
|
use std::{any::Any, sync::Arc};
|
|
|
|
use arrow::{
|
|
array::{AsArray, RecordBatch, StringArray, UInt8Array},
|
|
datatypes::{DataType, Field, Schema, SchemaRef, UInt64Type},
|
|
};
|
|
use datafusion::{
|
|
catalog::Session,
|
|
common::{GetExt, Statistics},
|
|
datasource::{
|
|
MemTable,
|
|
file_format::{
|
|
FileFormat, FileFormatFactory, csv::CsvFormatFactory,
|
|
file_compression_type::FileCompressionType,
|
|
},
|
|
physical_plan::{FileScanConfig, FileSinkConfig, FileSource},
|
|
table_schema::TableSchema,
|
|
},
|
|
error::Result,
|
|
execution::session_state::SessionStateBuilder,
|
|
physical_expr_common::sort_expr::LexRequirement,
|
|
physical_plan::ExecutionPlan,
|
|
prelude::SessionContext,
|
|
};
|
|
|
|
use object_store::{ObjectMeta, ObjectStore};
|
|
use tempfile::tempdir;
|
|
|
|
/// Example of a custom file format that reads and writes TSV files.
|
|
///
|
|
/// TSVFileFormatFactory is responsible for creating instances of TSVFileFormat.
|
|
/// The former, once registered with the SessionState, will then be used
|
|
/// to facilitate SQL operations on TSV files, such as `COPY TO` shown here.
|
|
pub async fn custom_file_format() -> Result<()> {
|
|
// Create a new context with the default configuration
|
|
let mut state = SessionStateBuilder::new().with_default_features().build();
|
|
|
|
// Register the custom file format
|
|
let file_format = Arc::new(TSVFileFactory::new());
|
|
state.register_file_format(file_format, true)?;
|
|
|
|
// Create a new context with the custom file format
|
|
let ctx = SessionContext::new_with_state(state);
|
|
|
|
let mem_table = create_mem_table();
|
|
ctx.register_table("mem_table", mem_table)?;
|
|
|
|
let temp_dir = tempdir().unwrap();
|
|
let table_save_path = temp_dir.path().join("mem_table.tsv");
|
|
|
|
let d = ctx
|
|
.sql(&format!(
|
|
"COPY mem_table TO '{}' STORED AS TSV;",
|
|
table_save_path.display(),
|
|
))
|
|
.await?;
|
|
|
|
let results = d.collect().await?;
|
|
println!(
|
|
"Number of inserted rows: {:?}",
|
|
(results[0]
|
|
.column_by_name("count")
|
|
.unwrap()
|
|
.as_primitive::<UInt64Type>()
|
|
.value(0))
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
/// Custom file format that reads and writes TSV files
|
|
///
|
|
/// This file format is a wrapper around the CSV file format
|
|
/// for demonstration purposes.
|
|
struct TSVFileFormat {
|
|
csv_file_format: Arc<dyn FileFormat>,
|
|
}
|
|
|
|
impl TSVFileFormat {
|
|
pub fn new(csv_file_format: Arc<dyn FileFormat>) -> Self {
|
|
Self { csv_file_format }
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl FileFormat for TSVFileFormat {
|
|
fn as_any(&self) -> &dyn Any {
|
|
self
|
|
}
|
|
|
|
fn get_ext(&self) -> String {
|
|
"tsv".to_string()
|
|
}
|
|
|
|
fn get_ext_with_compression(&self, c: &FileCompressionType) -> Result<String> {
|
|
if c == &FileCompressionType::UNCOMPRESSED {
|
|
Ok("tsv".to_string())
|
|
} else {
|
|
todo!("Compression not supported")
|
|
}
|
|
}
|
|
|
|
fn compression_type(&self) -> Option<FileCompressionType> {
|
|
None
|
|
}
|
|
|
|
async fn infer_schema(
|
|
&self,
|
|
state: &dyn Session,
|
|
store: &Arc<dyn ObjectStore>,
|
|
objects: &[ObjectMeta],
|
|
) -> Result<SchemaRef> {
|
|
self.csv_file_format
|
|
.infer_schema(state, store, objects)
|
|
.await
|
|
}
|
|
|
|
async fn infer_stats(
|
|
&self,
|
|
state: &dyn Session,
|
|
store: &Arc<dyn ObjectStore>,
|
|
table_schema: SchemaRef,
|
|
object: &ObjectMeta,
|
|
) -> Result<Statistics> {
|
|
self.csv_file_format
|
|
.infer_stats(state, store, table_schema, object)
|
|
.await
|
|
}
|
|
|
|
async fn create_physical_plan(
|
|
&self,
|
|
state: &dyn Session,
|
|
conf: FileScanConfig,
|
|
) -> Result<Arc<dyn ExecutionPlan>> {
|
|
self.csv_file_format.create_physical_plan(state, conf).await
|
|
}
|
|
|
|
async fn create_writer_physical_plan(
|
|
&self,
|
|
input: Arc<dyn ExecutionPlan>,
|
|
state: &dyn Session,
|
|
conf: FileSinkConfig,
|
|
order_requirements: Option<LexRequirement>,
|
|
) -> Result<Arc<dyn ExecutionPlan>> {
|
|
self.csv_file_format
|
|
.create_writer_physical_plan(input, state, conf, order_requirements)
|
|
.await
|
|
}
|
|
|
|
fn file_source(&self, table_schema: TableSchema) -> Arc<dyn FileSource> {
|
|
self.csv_file_format.file_source(table_schema)
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Debug)]
|
|
/// Factory for creating TSV file formats
|
|
///
|
|
/// This factory is a wrapper around the CSV file format factory
|
|
/// for demonstration purposes.
|
|
pub struct TSVFileFactory {
|
|
csv_file_factory: CsvFormatFactory,
|
|
}
|
|
|
|
impl TSVFileFactory {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
csv_file_factory: CsvFormatFactory::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FileFormatFactory for TSVFileFactory {
|
|
fn create(
|
|
&self,
|
|
state: &dyn Session,
|
|
format_options: &std::collections::HashMap<String, String>,
|
|
) -> Result<Arc<dyn FileFormat>> {
|
|
let mut new_options = format_options.clone();
|
|
new_options.insert("format.delimiter".to_string(), "\t".to_string());
|
|
|
|
let csv_file_format = self.csv_file_factory.create(state, &new_options)?;
|
|
let tsv_file_format = Arc::new(TSVFileFormat::new(csv_file_format));
|
|
|
|
Ok(tsv_file_format)
|
|
}
|
|
|
|
fn default(&self) -> Arc<dyn FileFormat> {
|
|
todo!()
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn Any {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl GetExt for TSVFileFactory {
|
|
fn get_ext(&self) -> String {
|
|
"tsv".to_string()
|
|
}
|
|
}
|
|
|
|
// create a simple mem table
|
|
fn create_mem_table() -> Arc<MemTable> {
|
|
let fields = vec![
|
|
Field::new("id", DataType::UInt8, false),
|
|
Field::new("data", DataType::Utf8, false),
|
|
];
|
|
let schema = Arc::new(Schema::new(fields));
|
|
|
|
let partitions = RecordBatch::try_new(
|
|
schema.clone(),
|
|
vec![
|
|
Arc::new(UInt8Array::from(vec![1, 2])),
|
|
Arc::new(StringArray::from(vec!["foo", "bar"])),
|
|
],
|
|
)
|
|
.unwrap();
|
|
|
|
Arc::new(MemTable::try_new(schema, vec![vec![partitions]]).unwrap())
|
|
}
|