From 7dd0c67a617000887fcd37179d65e9e70afb668d Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 1 Oct 2024 22:04:09 +0200 Subject: [PATCH 01/20] feat(rust/driver/snowflake): add `adbc_snowflake` crate with Go driver wrapper --- .github/workflows/rust.yml | 9 ++ rust/Cargo.lock | 9 ++ rust/Cargo.toml | 4 +- rust/drivers/snowflake/Cargo.toml | 29 +++++ rust/drivers/snowflake/README.md | 20 ++++ rust/drivers/snowflake/build.rs | 57 ++++++++++ rust/drivers/snowflake/src/connection.rs | 131 +++++++++++++++++++++++ rust/drivers/snowflake/src/database.rs | 69 ++++++++++++ rust/drivers/snowflake/src/driver.rs | 61 +++++++++++ rust/drivers/snowflake/src/lib.rs | 44 ++++++++ rust/drivers/snowflake/src/statement.rs | 98 +++++++++++++++++ 11 files changed, 530 insertions(+), 1 deletion(-) create mode 100644 rust/drivers/snowflake/Cargo.toml create mode 100644 rust/drivers/snowflake/README.md create mode 100644 rust/drivers/snowflake/build.rs create mode 100644 rust/drivers/snowflake/src/connection.rs create mode 100644 rust/drivers/snowflake/src/database.rs create mode 100644 rust/drivers/snowflake/src/driver.rs create mode 100644 rust/drivers/snowflake/src/lib.rs create mode 100644 rust/drivers/snowflake/src/statement.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8f2ff7ddf0..4254903e16 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -67,6 +67,15 @@ jobs: run: | rustup toolchain install stable --no-self-update rustup default stable + - name: Get required Go version + run: | + (. ../.env && echo "GO_VERSION=${GO}") >> $GITHUB_ENV + - uses: actions/setup-go@v5 + with: + go-version: "${{ env.GO_VERSION }}" + check-latest: true + cache: true + cache-dependency-path: go/adbc/go.sum - uses: actions/download-artifact@v4 with: name: driver-manager-${{ matrix.os }} diff --git a/rust/Cargo.lock b/rust/Cargo.lock index d89c533d8c..6412f5328b 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -19,6 +19,15 @@ dependencies = [ "arrow", ] +[[package]] +name = "adbc_snowflake" +version = "0.15.0" +dependencies = [ + "adbc_core", + "arrow-array", + "arrow-schema", +] + [[package]] name = "ahash" version = "0.8.11" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 21a0e20bc6..554ff3dde9 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -33,5 +33,7 @@ keywords = ["arrow"] categories = ["database"] [workspace.dependencies] -arrow = { version = "51.0.0", default-features = false, features = ["ffi"] } adbc_core = { path = "./core" } +arrow = { version = "51.0.0", default-features = false, features = ["ffi"] } +arrow-array = { version = "51.0.0", default-features = false } +arrow-schema = { version = "51.0.0", default-features = false } diff --git a/rust/drivers/snowflake/Cargo.toml b/rust/drivers/snowflake/Cargo.toml new file mode 100644 index 0000000000..5731668a4e --- /dev/null +++ b/rust/drivers/snowflake/Cargo.toml @@ -0,0 +1,29 @@ +# 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. + +[package] +name = "adbc_snowflake" +description = "Snowflake Arrow Database Connectivity (ADBC) driver" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +adbc_core = { path = "../../core", features = ["driver_manager"] } +arrow-array.workspace = true +arrow-schema.workspace = true diff --git a/rust/drivers/snowflake/README.md b/rust/drivers/snowflake/README.md new file mode 100644 index 0000000000..194f0f9855 --- /dev/null +++ b/rust/drivers/snowflake/README.md @@ -0,0 +1,20 @@ + + +# Snowflake driver for Arrow Database Connectivity (ADBC) diff --git a/rust/drivers/snowflake/build.rs b/rust/drivers/snowflake/build.rs new file mode 100644 index 0000000000..d9a922f467 --- /dev/null +++ b/rust/drivers/snowflake/build.rs @@ -0,0 +1,57 @@ +// 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. + +use std::{env, error::Error, path::PathBuf, process::Command}; + +fn main() -> Result<(), Box> { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + let go_dir = manifest_dir.ancestors().nth(3).unwrap().join("go"); + let go_pkg = go_dir.join("adbc/pkg/snowflake"); + + let out_dir = PathBuf::from(env::var("OUT_DIR")?); + let archive = out_dir.join("libsnowflake.a"); + + // Build the Go driver + let status = Command::new("go") + .current_dir(go_pkg.as_path()) + .arg("build") + .arg("-tags") + .arg("driverlib") + .arg("-buildmode=c-archive") + .arg("-o") + .arg(&archive) + .arg(".") + .status()?; + assert!(status.success(), "Go build failed"); + + // Rebuild when the Go pkg changes. + println!("cargo:rerun-if-changed={}", go_pkg.display()); + + // Link the driver statically. + println!("cargo:rustc-link-search=native={}", out_dir.display()); + println!("cargo:rustc-link-lib=static=snowflake"); + + // Link other dependencies. + println!("cargo:rustc-link-lib=resolv"); + #[cfg(target_os = "macos")] + { + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + println!("cargo:rustc-link-lib=framework=Security"); + } + + Ok(()) +} diff --git a/rust/drivers/snowflake/src/connection.rs b/rust/drivers/snowflake/src/connection.rs new file mode 100644 index 0000000000..d4cbd69c0a --- /dev/null +++ b/rust/drivers/snowflake/src/connection.rs @@ -0,0 +1,131 @@ +// 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. + +use std::collections::HashSet; + +use adbc_core::{ + driver_manager::ManagedConnection, + error::Result, + options::{InfoCode, OptionConnection, OptionValue}, + Connection, Optionable, +}; +use arrow_array::RecordBatchReader; +use arrow_schema::Schema; + +use crate::SnowflakeStatement; + +/// Snowflake ADBC Connection. +pub struct SnowflakeConnection(pub(crate) ManagedConnection); + +impl Optionable for SnowflakeConnection { + type Option = OptionConnection; + + fn set_option(&mut self, key: Self::Option, value: OptionValue) -> Result<()> { + self.0.set_option(key, value) + } + + fn get_option_string(&self, key: Self::Option) -> Result { + self.0.get_option_string(key) + } + + fn get_option_bytes(&self, key: Self::Option) -> Result> { + self.0.get_option_bytes(key) + } + + fn get_option_int(&self, key: Self::Option) -> Result { + self.0.get_option_int(key) + } + + fn get_option_double(&self, key: Self::Option) -> Result { + self.0.get_option_double(key) + } +} + +impl Connection for SnowflakeConnection { + type StatementType = SnowflakeStatement; + + fn new_statement(&mut self) -> Result { + self.0.new_statement().map(SnowflakeStatement) + } + + fn cancel(&mut self) -> Result<()> { + self.0.cancel() + } + + fn get_info(&self, codes: Option>) -> Result { + self.0.get_info(codes) + } + + fn get_objects( + &self, + depth: adbc_core::options::ObjectDepth, + catalog: Option<&str>, + db_schema: Option<&str>, + table_name: Option<&str>, + table_type: Option>, + column_name: Option<&str>, + ) -> Result { + self.0.get_objects( + depth, + catalog, + db_schema, + table_name, + table_type, + column_name, + ) + } + + fn get_table_schema( + &self, + catalog: Option<&str>, + db_schema: Option<&str>, + table_name: &str, + ) -> Result { + self.0.get_table_schema(catalog, db_schema, table_name) + } + + fn get_table_types(&self) -> Result { + self.0.get_table_types() + } + + fn get_statistic_names(&self) -> Result { + self.0.get_statistic_names() + } + + fn get_statistics( + &self, + catalog: Option<&str>, + db_schema: Option<&str>, + table_name: Option<&str>, + approximate: bool, + ) -> Result { + self.0 + .get_statistics(catalog, db_schema, table_name, approximate) + } + + fn commit(&mut self) -> Result<()> { + self.0.commit() + } + + fn rollback(&mut self) -> Result<()> { + self.0.rollback() + } + + fn read_partition(&self, partition: impl AsRef<[u8]>) -> Result { + self.0.read_partition(partition) + } +} diff --git a/rust/drivers/snowflake/src/database.rs b/rust/drivers/snowflake/src/database.rs new file mode 100644 index 0000000000..1f22102b8f --- /dev/null +++ b/rust/drivers/snowflake/src/database.rs @@ -0,0 +1,69 @@ +// 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. + +use adbc_core::{ + driver_manager::ManagedDatabase, + error::Result, + options::{OptionConnection, OptionDatabase, OptionValue}, + Database, Optionable, +}; + +use crate::SnowflakeConnection; + +/// Snowflake ADBC Database. +pub struct SnowflakeDatabase(pub(crate) ManagedDatabase); + +impl Optionable for SnowflakeDatabase { + type Option = OptionDatabase; + + fn set_option(&mut self, key: Self::Option, value: OptionValue) -> Result<()> { + self.0.set_option(key, value) + } + + fn get_option_string(&self, key: Self::Option) -> Result { + self.0.get_option_string(key) + } + + fn get_option_bytes(&self, key: Self::Option) -> Result> { + self.0.get_option_bytes(key) + } + + fn get_option_int(&self, key: Self::Option) -> Result { + self.0.get_option_int(key) + } + + fn get_option_double(&self, key: Self::Option) -> Result { + self.0.get_option_double(key) + } +} + +impl Database for SnowflakeDatabase { + type ConnectionType = SnowflakeConnection; + + fn new_connection(&mut self) -> Result { + self.0.new_connection().map(SnowflakeConnection) + } + + fn new_connection_with_opts( + &mut self, + opts: impl IntoIterator, + ) -> Result { + self.0 + .new_connection_with_opts(opts) + .map(SnowflakeConnection) + } +} diff --git a/rust/drivers/snowflake/src/driver.rs b/rust/drivers/snowflake/src/driver.rs new file mode 100644 index 0000000000..ea9bfe2e23 --- /dev/null +++ b/rust/drivers/snowflake/src/driver.rs @@ -0,0 +1,61 @@ +// 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. + +use std::ffi::{c_int, c_void}; + +use adbc_core::{ + driver_manager::ManagedDriver, + error::Result, + ffi::{FFI_AdbcDriverInitFunc, FFI_AdbcError, FFI_AdbcStatusCode}, + options::{AdbcVersion, OptionDatabase, OptionValue}, + Driver, +}; + +use crate::SnowflakeDatabase; + +/// Snowflake ADBC Driver. +pub struct SnowflakeDriver(ManagedDriver); + +#[link(name = "snowflake", kind = "static")] +extern "C" { + #[link_name = "SnowflakeDriverInit"] + fn init(version: c_int, raw_driver: *mut c_void, err: *mut FFI_AdbcError) + -> FFI_AdbcStatusCode; +} + +impl SnowflakeDriver { + /// Returns a [`SnowflakeDriver`] using the provided [`AdbcVersion`]. + pub fn try_new(version: AdbcVersion) -> Result { + let driver_init: FFI_AdbcDriverInitFunc = init; + ManagedDriver::load_static(&driver_init, version).map(Self) + } +} + +impl Driver for SnowflakeDriver { + type DatabaseType = SnowflakeDatabase; + + fn new_database(&mut self) -> Result { + self.0.new_database().map(SnowflakeDatabase) + } + + fn new_database_with_opts( + &mut self, + opts: impl IntoIterator, + ) -> Result { + self.0.new_database_with_opts(opts).map(SnowflakeDatabase) + } +} diff --git a/rust/drivers/snowflake/src/lib.rs b/rust/drivers/snowflake/src/lib.rs new file mode 100644 index 0000000000..e14884c2d3 --- /dev/null +++ b/rust/drivers/snowflake/src/lib.rs @@ -0,0 +1,44 @@ +// 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. + +//! Snowflake ADBC driver, based on the Go driver. + +mod driver; +pub use driver::*; + +mod database; +pub use database::*; + +mod connection; +pub use connection::*; + +mod statement; +pub use statement::*; + +#[cfg(test)] +mod tests { + use adbc_core::{error::Result, options::AdbcVersion}; + + use super::*; + + #[test] + fn load_driver() -> Result<()> { + SnowflakeDriver::try_new(AdbcVersion::V100)?; + SnowflakeDriver::try_new(AdbcVersion::V110)?; + Ok(()) + } +} diff --git a/rust/drivers/snowflake/src/statement.rs b/rust/drivers/snowflake/src/statement.rs new file mode 100644 index 0000000000..2715f185af --- /dev/null +++ b/rust/drivers/snowflake/src/statement.rs @@ -0,0 +1,98 @@ +// 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. + +use adbc_core::{ + driver_manager::ManagedStatement, + error::Result, + options::{OptionStatement, OptionValue}, + Optionable, PartitionedResult, Statement, +}; +use arrow_array::{RecordBatch, RecordBatchReader}; +use arrow_schema::Schema; + +/// Snowflake ADBC Statement. +pub struct SnowflakeStatement(pub(crate) ManagedStatement); + +impl Optionable for SnowflakeStatement { + type Option = OptionStatement; + + fn set_option(&mut self, key: Self::Option, value: OptionValue) -> Result<()> { + self.0.set_option(key, value) + } + + fn get_option_string(&self, key: Self::Option) -> Result { + self.0.get_option_string(key) + } + + fn get_option_bytes(&self, key: Self::Option) -> Result> { + self.0.get_option_bytes(key) + } + + fn get_option_int(&self, key: Self::Option) -> Result { + self.0.get_option_int(key) + } + + fn get_option_double(&self, key: Self::Option) -> Result { + self.0.get_option_double(key) + } +} + +impl Statement for SnowflakeStatement { + fn bind(&mut self, batch: RecordBatch) -> Result<()> { + self.0.bind(batch) + } + + fn bind_stream(&mut self, reader: Box) -> Result<()> { + self.0.bind_stream(reader) + } + + fn execute(&mut self) -> Result { + self.0.execute() + } + + fn execute_update(&mut self) -> Result> { + self.0.execute_update() + } + + fn execute_schema(&mut self) -> Result { + self.0.execute_schema() + } + + fn execute_partitions(&mut self) -> Result { + self.0.execute_partitions() + } + + fn get_parameter_schema(&self) -> Result { + self.0.get_parameter_schema() + } + + fn prepare(&mut self) -> Result<()> { + self.0.prepare() + } + + fn set_sql_query(&mut self, query: impl AsRef) -> Result<()> { + self.0.set_sql_query(query) + } + + fn set_substrait_plan(&mut self, plan: impl AsRef<[u8]>) -> Result<()> { + self.0.set_substrait_plan(plan) + } + + fn cancel(&mut self) -> Result<()> { + self.0.cancel() + } +} From 0ed54ab300a8dc992b606538df2c88f0e4af4ad1 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 1 Oct 2024 22:15:03 +0200 Subject: [PATCH 02/20] Rename `rust/drivers` to `rust/driver` --- rust/Cargo.toml | 2 +- rust/{drivers => driver}/dummy/Cargo.toml | 0 rust/{drivers => driver}/dummy/src/lib.rs | 0 rust/{drivers => driver}/dummy/tests/driver_exporter_dummy.rs | 0 rust/{drivers => driver}/snowflake/Cargo.toml | 0 rust/{drivers => driver}/snowflake/README.md | 0 rust/{drivers => driver}/snowflake/build.rs | 0 rust/{drivers => driver}/snowflake/src/connection.rs | 0 rust/{drivers => driver}/snowflake/src/database.rs | 0 rust/{drivers => driver}/snowflake/src/driver.rs | 0 rust/{drivers => driver}/snowflake/src/lib.rs | 0 rust/{drivers => driver}/snowflake/src/statement.rs | 0 12 files changed, 1 insertion(+), 1 deletion(-) rename rust/{drivers => driver}/dummy/Cargo.toml (100%) rename rust/{drivers => driver}/dummy/src/lib.rs (100%) rename rust/{drivers => driver}/dummy/tests/driver_exporter_dummy.rs (100%) rename rust/{drivers => driver}/snowflake/Cargo.toml (100%) rename rust/{drivers => driver}/snowflake/README.md (100%) rename rust/{drivers => driver}/snowflake/build.rs (100%) rename rust/{drivers => driver}/snowflake/src/connection.rs (100%) rename rust/{drivers => driver}/snowflake/src/database.rs (100%) rename rust/{drivers => driver}/snowflake/src/driver.rs (100%) rename rust/{drivers => driver}/snowflake/src/lib.rs (100%) rename rust/{drivers => driver}/snowflake/src/statement.rs (100%) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 554ff3dde9..63fbdd6b26 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -16,7 +16,7 @@ # under the License. [workspace] -members = ["core", "drivers/*"] +members = ["core", "driver/*"] resolver = "2" [workspace.package] diff --git a/rust/drivers/dummy/Cargo.toml b/rust/driver/dummy/Cargo.toml similarity index 100% rename from rust/drivers/dummy/Cargo.toml rename to rust/driver/dummy/Cargo.toml diff --git a/rust/drivers/dummy/src/lib.rs b/rust/driver/dummy/src/lib.rs similarity index 100% rename from rust/drivers/dummy/src/lib.rs rename to rust/driver/dummy/src/lib.rs diff --git a/rust/drivers/dummy/tests/driver_exporter_dummy.rs b/rust/driver/dummy/tests/driver_exporter_dummy.rs similarity index 100% rename from rust/drivers/dummy/tests/driver_exporter_dummy.rs rename to rust/driver/dummy/tests/driver_exporter_dummy.rs diff --git a/rust/drivers/snowflake/Cargo.toml b/rust/driver/snowflake/Cargo.toml similarity index 100% rename from rust/drivers/snowflake/Cargo.toml rename to rust/driver/snowflake/Cargo.toml diff --git a/rust/drivers/snowflake/README.md b/rust/driver/snowflake/README.md similarity index 100% rename from rust/drivers/snowflake/README.md rename to rust/driver/snowflake/README.md diff --git a/rust/drivers/snowflake/build.rs b/rust/driver/snowflake/build.rs similarity index 100% rename from rust/drivers/snowflake/build.rs rename to rust/driver/snowflake/build.rs diff --git a/rust/drivers/snowflake/src/connection.rs b/rust/driver/snowflake/src/connection.rs similarity index 100% rename from rust/drivers/snowflake/src/connection.rs rename to rust/driver/snowflake/src/connection.rs diff --git a/rust/drivers/snowflake/src/database.rs b/rust/driver/snowflake/src/database.rs similarity index 100% rename from rust/drivers/snowflake/src/database.rs rename to rust/driver/snowflake/src/database.rs diff --git a/rust/drivers/snowflake/src/driver.rs b/rust/driver/snowflake/src/driver.rs similarity index 100% rename from rust/drivers/snowflake/src/driver.rs rename to rust/driver/snowflake/src/driver.rs diff --git a/rust/drivers/snowflake/src/lib.rs b/rust/driver/snowflake/src/lib.rs similarity index 100% rename from rust/drivers/snowflake/src/lib.rs rename to rust/driver/snowflake/src/lib.rs diff --git a/rust/drivers/snowflake/src/statement.rs b/rust/driver/snowflake/src/statement.rs similarity index 100% rename from rust/drivers/snowflake/src/statement.rs rename to rust/driver/snowflake/src/statement.rs From ea19114757f0a03f93055532a35d783a73ddaf8f Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 1 Oct 2024 22:20:15 +0200 Subject: [PATCH 03/20] Add required permissions for `native-unix` workflow --- .github/workflows/rust.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4254903e16..424ab603c5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -44,6 +44,8 @@ defaults: jobs: native-unix: uses: ./.github/workflows/native-unix.yml + permissions: + id-token: write rust: needs: [native-unix] From 691785ab2c7ec288bb7c79a2eb6123c647b2320b Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 1 Oct 2024 22:25:27 +0200 Subject: [PATCH 04/20] Also add `contents: read` to permissions for `native-unix` workflow --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 424ab603c5..870d8c77d6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -45,6 +45,7 @@ jobs: native-unix: uses: ./.github/workflows/native-unix.yml permissions: + contents: read id-token: write rust: From b541e07b124ae20b144c552e5bc1b960d55cef13 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 14 Nov 2024 12:50:55 +0100 Subject: [PATCH 05/20] Also move `datafusion` to `driver` --- rust/Cargo.lock | 2848 ++++++++++++++++- .../{drivers => driver}/datafusion/Cargo.toml | 0 rust/{drivers => driver}/datafusion/README.md | 0 .../{drivers => driver}/datafusion/src/lib.rs | 0 .../datafusion/tests/test_datafusion.rs | 0 5 files changed, 2717 insertions(+), 131 deletions(-) rename rust/{drivers => driver}/datafusion/Cargo.toml (100%) rename rust/{drivers => driver}/datafusion/README.md (100%) rename rust/{drivers => driver}/datafusion/src/lib.rs (100%) rename rust/{drivers => driver}/datafusion/tests/test_datafusion.rs (100%) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 372beb39db..e257e0525c 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -13,6 +13,21 @@ dependencies = [ "once_cell", ] +[[package]] +name = "adbc_datafusion" +version = "0.16.0" +dependencies = [ + "adbc_core", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "arrow-select", + "datafusion", + "datafusion-substrait", + "prost", + "tokio", +] + [[package]] name = "adbc_dummy" version = "0.16.0" @@ -33,6 +48,27 @@ dependencies = [ "arrow-schema", ] +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -47,6 +83,36 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -62,6 +128,60 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arrow" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ba0d7248932f4e2a12fb37f0a2e3ec82b3bdedbac2a1dce186e036843b8f8c" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60afcdc004841a5c8d8da4f4fa22d64eb19c0c01ef4bcedd77f175a7cf6e38f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "num", +] + [[package]] name = "arrow-array" version = "53.1.0" @@ -73,8 +193,9 @@ dependencies = [ "arrow-data", "arrow-schema", "chrono", + "chrono-tz", "half", - "hashbrown", + "hashbrown 0.14.5", "num", ] @@ -89,6 +210,46 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-cast" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "450e4abb5775bca0740bec0bcf1b1a5ae07eff43bd625661c4436d8e8e4540c4" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a4e4d63830a341713e35d9a42452fbc6241d5f42fa5cf6a4681b8ad91370c4" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "lazy_static", + "lexical-core", + "regex", +] + [[package]] name = "arrow-data" version = "53.1.0" @@ -101,13 +262,77 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-ipc" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98e983549259a2b97049af7edfb8f28b8911682040e99a94e4ceb1196bd65c2" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "flatbuffers", + "lz4_flex", +] + +[[package]] +name = "arrow-json" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b198b9c6fcf086501730efbbcb483317b39330a116125af7bb06467d04b352a3" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap", + "lexical-core", + "num", + "serde", + "serde_json", +] + +[[package]] +name = "arrow-ord" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2427f37b4459a4b9e533045abe87a5183a5e0995a3fc2c2fd45027ae2cc4ef3f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "half", + "num", +] + +[[package]] +name = "arrow-row" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15959657d92e2261a7a323517640af87f5afd9fd8a6492e424ebee2203c567f6" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + [[package]] name = "arrow-schema" version = "53.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf0388a18fd7f7f3fe3de01852d30f54ed5182f9004db700fbe3ba843ed2794" dependencies = [ - "bitflags", + "bitflags 2.5.0", ] [[package]] @@ -124,36 +349,216 @@ dependencies = [ "num", ] +[[package]] +name = "arrow-string" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab3db7c09dd826e74079661d84ed01ed06547cf75d52c2818ef776d0d852305" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax", +] + +[[package]] +name = "async-compression" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" +dependencies = [ + "bzip2", + "flate2", + "futures-core", + "futures-io", + "memchr", + "pin-project-lite", + "tokio", + "xz2", + "zstd", + "zstd-safe", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.7.4", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cc" version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -176,31 +581,93 @@ dependencies = [ ] [[package]] -name = "const-random" -version = "0.1.18" +name = "chrono-tz" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" dependencies = [ - "const-random-macro", + "chrono", + "chrono-tz-build", + "phf", ] [[package]] -name = "const-random-macro" -version = "0.1.16" +name = "chrono-tz-build" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", + "parse-zoneinfo", + "phf_codegen", ] +[[package]] +name = "comfy-table" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d05af1e006a2407bedef5af410552494ce5be9090444dbbcb57258c1af3d56" +dependencies = [ + "strum", + "strum_macros", + "unicode-width", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cpufeatures" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crunchy" version = "0.2.2" @@ -208,222 +675,2186 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] -name = "getrandom" -version = "0.2.15" +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "datafusion" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae5f2abc725737d6e87b6d348a5aa2d0a77e4cf873045f004546da946e6e619" +dependencies = [ + "ahash", + "arrow", + "arrow-array", + "arrow-ipc", + "arrow-schema", + "async-compression", + "async-trait", + "bytes", + "bzip2", + "chrono", + "dashmap", + "datafusion-catalog", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-functions-nested", + "datafusion-functions-window", + "datafusion-optimizer", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "datafusion-physical-optimizer", + "datafusion-physical-plan", + "datafusion-sql", + "flate2", + "futures", + "glob", + "half", + "hashbrown 0.14.5", + "indexmap", + "itertools", + "log", + "num_cpus", + "object_store", + "parking_lot", + "parquet", + "paste", + "pin-project-lite", + "rand", + "sqlparser", + "tempfile", + "tokio", + "tokio-util", + "url", + "uuid", + "xz2", + "zstd", +] + +[[package]] +name = "datafusion-catalog" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998761705551f11ffa4ee692cc285b44eb1def6e0d28c4eaf5041b9e2810dc1e" +dependencies = [ + "arrow-schema", + "async-trait", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", +] + +[[package]] +name = "datafusion-common" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11986f191e88d950f10a5cc512a598afba27d92e04a0201215ad60785005115a" +dependencies = [ + "ahash", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.14.5", + "instant", + "libc", + "num_cpus", + "object_store", + "parquet", + "paste", + "sqlparser", + "tokio", +] + +[[package]] +name = "datafusion-common-runtime" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694c9d7ea1b82f95768215c4cb5c2d5c613690624e832a7ee64be563139d582f" +dependencies = [ + "log", + "tokio", +] + +[[package]] +name = "datafusion-execution" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b4cedcd98151e0a297f34021b6b232ff0ebc0f2f18ea5e7446b5ebda99b1a1" +dependencies = [ + "arrow", + "chrono", + "dashmap", + "datafusion-common", + "datafusion-expr", + "futures", + "hashbrown 0.14.5", + "log", + "object_store", + "parking_lot", + "rand", + "tempfile", + "url", +] + +[[package]] +name = "datafusion-expr" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8dd114dc0296cacaee98ad3165724529fcca9a65b2875abcd447b9cc02b2b74" +dependencies = [ + "ahash", + "arrow", + "arrow-array", + "arrow-buffer", + "chrono", + "datafusion-common", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr-common", + "paste", + "serde_json", + "sqlparser", + "strum", + "strum_macros", +] + +[[package]] +name = "datafusion-expr-common" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1ba2bb018218d9260bbd7de6a46a20f61b93d4911dba8aa07735625004c4fb" +dependencies = [ + "arrow", + "datafusion-common", + "paste", +] + +[[package]] +name = "datafusion-functions" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "547cb780a4ac51fd8e52c0fb9188bc16cea4e35aebf6c454bda0b82a7a417304" +dependencies = [ + "arrow", + "arrow-buffer", + "base64 0.22.1", + "blake2", + "blake3", + "chrono", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "hashbrown 0.14.5", + "hex", + "itertools", + "log", + "md-5", + "rand", + "regex", + "sha2", + "unicode-segmentation", + "uuid", +] + +[[package]] +name = "datafusion-functions-aggregate" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68cf5aa7ebcac08bd04bb709a9a6d4963eafd227da62b628133bc509c40f5a0" +dependencies = [ + "ahash", + "arrow", + "arrow-schema", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "half", + "log", + "paste", + "sqlparser", +] + +[[package]] +name = "datafusion-functions-aggregate-common" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2285d080dfecdfb8605b0ab2f1a41e2473208dc8e9bd6f5d1dbcfe97f517e6f" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-expr-common", + "datafusion-physical-expr-common", + "rand", +] + +[[package]] +name = "datafusion-functions-nested" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6ffbbb7cf7bf0c0e05eb6207023fef341cac83a593a5365a6fc83803c572a9" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-physical-expr-common", + "itertools", + "log", + "paste", + "rand", +] + +[[package]] +name = "datafusion-functions-window" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e78d30ebd6e9f74d4aeddec32744f5a18b5f9584591bc586fb5259c4848bac5" +dependencies = [ + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr-common", + "log", +] + +[[package]] +name = "datafusion-optimizer" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be172c44bf344df707e0c041fa3f41e6dc5fb0976f539c68bc442bca150ee58c" +dependencies = [ + "arrow", + "async-trait", + "chrono", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr", + "hashbrown 0.14.5", + "indexmap", + "itertools", + "log", + "paste", + "regex-syntax", +] + +[[package]] +name = "datafusion-physical-expr" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b86b7fa0b8161c49b0f005b0df193fc6d9b65ceec675f155422cda5d1583ca" +dependencies = [ + "ahash", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "arrow-string", + "base64 0.22.1", + "chrono", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr-common", + "half", + "hashbrown 0.14.5", + "hex", + "indexmap", + "itertools", + "log", + "paste", + "petgraph", + "regex", +] + +[[package]] +name = "datafusion-physical-expr-common" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "242ba8a26351d9ca16295814c46743b0d1b00ec372174bdfbba991d0953dd596" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-expr-common", + "hashbrown 0.14.5", + "rand", +] + +[[package]] +name = "datafusion-physical-optimizer" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca088eb904bf1cfc9c5e5653110c70a6eaba43164085a9d180b35b77ce3b8b" +dependencies = [ + "arrow-schema", + "datafusion-common", + "datafusion-execution", + "datafusion-physical-expr", + "datafusion-physical-plan", + "itertools", +] + +[[package]] +name = "datafusion-physical-plan" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4989a53b824abc759685eb643f4d604c2fc2fea4e2c309ac3473bea263ecbbeb" +dependencies = [ + "ahash", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "async-trait", + "chrono", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-aggregate", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "futures", + "half", + "hashbrown 0.14.5", + "indexmap", + "itertools", + "log", + "once_cell", + "parking_lot", + "pin-project-lite", + "rand", + "tokio", +] + +[[package]] +name = "datafusion-sql" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b9b75b9da10ed656073ac0553708f17eb8fa5a7b065ef9848914c93150ab9e" +dependencies = [ + "arrow", + "arrow-array", + "arrow-schema", + "datafusion-common", + "datafusion-expr", + "log", + "regex", + "sqlparser", + "strum", +] + +[[package]] +name = "datafusion-substrait" +version = "42.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220d7ab0ffadd8b1af753904b18dd92d270271810b1ce9f8be3c3dbe2392b636" +dependencies = [ + "arrow-buffer", + "async-recursion", + "chrono", + "datafusion", + "itertools", + "object_store", + "pbjson-types", + "prost", + "substrait", + "url", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flatbuffers" +version = "24.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "integer-encoding" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lexical-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431c65b318a590c1de6b8fd6e72798c92291d27762d94c9e6c37ed7a73d8458" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb17a4bdb9b418051aa59d41d65b1c9be5affab314a872e5ad7f06231fb3b4e0" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df98f4a4ab53bf8b175b363a34c7af608fe31f93cc1fb1bf07130622ca4ef61" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85314db53332e5c192b6bca611fb10c114a80d1b831ddac0af1e9be1b9232ca0" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7c3ad4e37db81c1cbe7cf34610340adc09c322871972f74877a712abc6c809" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb89e9f6958b83258afa3deed90b5de9ef68eef090ad5086c791cd2345610162" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "object_store" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eb4c22c6154a1e759d7099f9ffad7cc5ef8245f9efbab4a41b92623079c82f3" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "humantime", + "itertools", + "parking_lot", + "percent-encoding", + "snafu", + "tokio", + "tracing", + "url", + "walkdir", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "parquet" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310c46a70a3ba90d98fec39fa2da6d9d731e544191da6fb56c9d199484d0dd3e" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ipc", + "arrow-schema", + "arrow-select", + "base64 0.22.1", + "brotli", + "bytes", + "chrono", + "flate2", + "futures", + "half", + "hashbrown 0.14.5", + "lz4_flex", + "num", + "num-bigint", + "object_store", + "paste", + "seq-macro", + "snap", + "thrift", + "tokio", + "twox-hash", + "zstd", + "zstd-sys", +] + +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbjson" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "pbjson-build" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9" +dependencies = [ + "heck", + "itertools", + "prost", + "prost-types", +] + +[[package]] +name = "pbjson-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887" +dependencies = [ + "bytes", + "chrono", + "pbjson", + "pbjson-build", + "prost", + "prost-build", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "regress" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eae2a1ebfecc58aff952ef8ccd364329abe627762f5bf09ff42eb9d98522479" +dependencies = [ + "hashbrown 0.14.5", + "memchr", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_tokenstream" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "snafu" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + +[[package]] +name = "sqlparser" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5b515a2bd5168426033e9efbfd05500114833916f1d5c268f938b4ee130ac" +dependencies = [ + "log", + "sqlparser_derive", +] + +[[package]] +name = "sqlparser_derive" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b2e185515564f15375f593fb966b5718bc624ba77fe49fa4616ad619690554" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "substrait" +version = "0.41.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3bf05f1d7a3fd7a97790d410f6e859b3a98dcde05e7a3fc00b31b0f60fe7cb" +dependencies = [ + "heck", + "pbjson", + "pbjson-build", + "pbjson-types", + "prettyplease", + "prost", + "prost-build", + "prost-types", + "schemars", + "semver", + "serde", + "serde_json", + "serde_yaml", + "syn", + "typify", + "walkdir", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" dependencies = [ "cfg-if", - "libc", - "wasi", + "fastrand", + "once_cell", + "rustix", + "windows-sys", ] [[package]] -name = "half" -version = "2.4.1" +name = "thiserror" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ - "cfg-if", - "crunchy", - "num-traits", + "thiserror-impl", ] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "thiserror-impl" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "iana-time-zone" -version = "0.1.60" +name = "thrift" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", + "byteorder", + "integer-encoding", + "ordered-float", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "tiny-keccak" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ - "cc", + "crunchy", ] [[package]] -name = "js-sys" -version = "0.3.69" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "wasm-bindgen", + "displaydoc", + "zerovec", ] [[package]] -name = "libc" -version = "0.2.155" +name = "tokio" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "bytes", + "pin-project-lite", + "tokio-macros", +] [[package]] -name = "libloading" -version = "0.8.3" +name = "tokio-macros" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "cfg-if", - "windows-targets", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "libm" -version = "0.2.8" +name = "tokio-util" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] [[package]] -name = "log" -version = "0.4.21" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] [[package]] -name = "num" -version = "0.4.3" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "num-bigint" -version = "0.4.5" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "num-integer", - "num-traits", + "once_cell", ] [[package]] -name = "num-complex" -version = "0.4.6" +name = "twox-hash" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "num-traits", + "cfg-if", + "static_assertions", ] [[package]] -name = "num-integer" -version = "0.1.46" +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "num-iter" -version = "0.1.45" +name = "typify" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "adb6beec125971dda80a086f90b4a70f60f222990ce4d63ad0fc140492f53444" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "typify-impl", + "typify-macro", ] [[package]] -name = "num-rational" -version = "0.4.2" +name = "typify-impl" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +checksum = "93bbb24e990654aff858d80fee8114f4322f7d7a1b1ecb45129e2fcb0d0ad5ae" dependencies = [ - "num-bigint", - "num-integer", - "num-traits", + "heck", + "log", + "proc-macro2", + "quote", + "regress", + "schemars", + "semver", + "serde", + "serde_json", + "syn", + "thiserror", + "unicode-ident", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "typify-macro" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "f8e6491896e955692d68361c68db2b263e3bec317ec0b684e0e2fa882fb6e31e" dependencies = [ - "autocfg", - "libm", + "proc-macro2", + "quote", + "schemars", + "semver", + "serde", + "serde_json", + "serde_tokenstream", + "syn", + "typify-impl", ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "proc-macro2" -version = "1.0.83" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" -dependencies = [ - "unicode-ident", -] +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] -name = "quote" -version = "1.0.36" +name = "unicode-width" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] -name = "shlex" -version = "1.3.0" +name = "unsafe-libyaml" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] -name = "syn" -version = "2.0.82" +name = "url" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "form_urlencoded", + "idna", + "percent-encoding", ] [[package]] -name = "tiny-keccak" -version = "2.0.2" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", +] [[package]] name = "version_check" @@ -431,6 +2862,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -491,6 +2932,25 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -500,6 +2960,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.5" @@ -564,12 +3033,58 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -583,3 +3098,74 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/rust/drivers/datafusion/Cargo.toml b/rust/driver/datafusion/Cargo.toml similarity index 100% rename from rust/drivers/datafusion/Cargo.toml rename to rust/driver/datafusion/Cargo.toml diff --git a/rust/drivers/datafusion/README.md b/rust/driver/datafusion/README.md similarity index 100% rename from rust/drivers/datafusion/README.md rename to rust/driver/datafusion/README.md diff --git a/rust/drivers/datafusion/src/lib.rs b/rust/driver/datafusion/src/lib.rs similarity index 100% rename from rust/drivers/datafusion/src/lib.rs rename to rust/driver/datafusion/src/lib.rs diff --git a/rust/drivers/datafusion/tests/test_datafusion.rs b/rust/driver/datafusion/tests/test_datafusion.rs similarity index 100% rename from rust/drivers/datafusion/tests/test_datafusion.rs rename to rust/driver/datafusion/tests/test_datafusion.rs From 277bbc9ad0efa8d28b3a3cabf7d308baed6a6ddf Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 14 Nov 2024 12:52:46 +0100 Subject: [PATCH 06/20] Fix unused warning --- rust/core/src/ffi/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/core/src/ffi/methods.rs b/rust/core/src/ffi/methods.rs index e47fe4fff0..0b065c3bee 100644 --- a/rust/core/src/ffi/methods.rs +++ b/rust/core/src/ffi/methods.rs @@ -64,7 +64,7 @@ method!(StatementSetSqlQuery ; FuncStatementSetSqlQuery ; FFI_AdbcStatusCode ; A method!(StatementSetSubstraitPlan ; FuncStatementSetSubstraitPlan ; FFI_AdbcStatusCode ; ADBC_STATUS_NOT_IMPLEMENTED ; *mut FFI_AdbcStatement, *const u8, usize, *mut FFI_AdbcError); method!(ErrorGetDetailCount ; FuncErrorGetDetailCount ; c_int ; 0 ; *const FFI_AdbcError); method!(ErrorGetDetail ; FuncErrorGetDetail ; FFI_AdbcErrorDetail ; FFI_AdbcErrorDetail::default() ; *const FFI_AdbcError, c_int); -method!(ErrorFromArrayStream ; FuncErrorFromArrayStream ; *const FFI_AdbcError ; std::ptr::null() ; *mut FFI_ArrowArrayStream, *mut FFI_AdbcStatusCode); +method!(_ErrorFromArrayStream ; FuncErrorFromArrayStream ; *const FFI_AdbcError ; std::ptr::null() ; *mut FFI_ArrowArrayStream, *mut FFI_AdbcStatusCode); method!(DatabaseGetOption ; FuncDatabaseGetOption ; FFI_AdbcStatusCode ; ADBC_STATUS_NOT_IMPLEMENTED ; *mut FFI_AdbcDatabase, *const c_char, *mut c_char, *mut usize, *mut FFI_AdbcError); method!(DatabaseGetOptionBytes ; FuncDatabaseGetOptionBytes ; FFI_AdbcStatusCode ; ADBC_STATUS_NOT_IMPLEMENTED ; *mut FFI_AdbcDatabase, *const c_char, *mut u8, *mut usize, *mut FFI_AdbcError); method!(DatabaseGetOptionDouble ; FuncDatabaseGetOptionDouble ; FFI_AdbcStatusCode ; ADBC_STATUS_NOT_IMPLEMENTED ; *mut FFI_AdbcDatabase, *const c_char, *mut f64, *mut FFI_AdbcError); From 4e6d9ceb1b9f0b211bec9d97295e505847d2a2da Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 15:41:50 +0100 Subject: [PATCH 07/20] Add configuration builders --- .github/workflows/rust.yml | 3 + rust/Cargo.lock | 45 + rust/core/src/driver_manager.rs | 5 + rust/core/src/options.rs | 28 +- rust/driver/snowflake/.gitignore | 1 + rust/driver/snowflake/Cargo.toml | 11 + rust/driver/snowflake/build.rs | 3 + rust/driver/snowflake/src/builder.rs | 32 + rust/driver/snowflake/src/connection.rs | 17 +- .../snowflake/src/connection/builder.rs | 98 ++ rust/driver/snowflake/src/database.rs | 22 +- rust/driver/snowflake/src/database/builder.rs | 1061 +++++++++++++++++ rust/driver/snowflake/src/driver.rs | 77 +- rust/driver/snowflake/src/driver/builder.rs | 64 + rust/driver/snowflake/src/duration.rs | 263 ++++ rust/driver/snowflake/src/lib.rs | 42 +- rust/driver/snowflake/src/statement.rs | 8 +- rust/driver/snowflake/tests/driver.rs | 46 + 18 files changed, 1771 insertions(+), 55 deletions(-) create mode 100644 rust/driver/snowflake/.gitignore create mode 100644 rust/driver/snowflake/src/builder.rs create mode 100644 rust/driver/snowflake/src/connection/builder.rs create mode 100644 rust/driver/snowflake/src/database/builder.rs create mode 100644 rust/driver/snowflake/src/driver/builder.rs create mode 100644 rust/driver/snowflake/src/duration.rs create mode 100644 rust/driver/snowflake/tests/driver.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9bbf0436d4..e6fc5a5b39 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -117,6 +117,9 @@ jobs: run: cargo clippy --workspace --all-targets --all-features -- -Dwarnings - name: Test run: cargo test --workspace --all-targets --all-features + env: + ADBC_SNOWFLAKE_TESTS: 1 + ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} - name: Doctests run: cargo test --workspace --doc --all-features - name: Check docs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index e257e0525c..405a2c1c71 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -46,6 +46,10 @@ dependencies = [ "adbc_core", "arrow-array", "arrow-schema", + "dotenvy", + "regex", + "test-with", + "url", ] [[package]] @@ -1148,6 +1152,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dyn-clone" version = "1.0.17" @@ -2124,6 +2134,28 @@ dependencies = [ "syn", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.83" @@ -2620,6 +2652,19 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "test-with" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68b467eef3b91443aaf01fee27fa016ea346d8c5b4ea1b85d0bd2375fa4c72f" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "regex", + "syn", +] + [[package]] name = "thiserror" version = "1.0.65" diff --git a/rust/core/src/driver_manager.rs b/rust/core/src/driver_manager.rs index c486aaaabb..8e066a0275 100644 --- a/rust/core/src/driver_manager.rs +++ b/rust/core/src/driver_manager.rs @@ -168,6 +168,11 @@ pub struct ManagedDriver { } impl ManagedDriver { + /// Returns the [`AdbcVersion`] of this driver. + pub fn version(&self) -> AdbcVersion { + self.inner.version + } + /// Load a driver from an initialization function. pub fn load_static(init: &ffi::FFI_AdbcDriverInitFunc, version: AdbcVersion) -> Result { let driver = Self::load_impl(init, version)?; diff --git a/rust/core/src/options.rs b/rust/core/src/options.rs index 144e46aeb1..2dd7f6aec5 100644 --- a/rust/core/src/options.rs +++ b/rust/core/src/options.rs @@ -16,7 +16,7 @@ // under the License. //! Various option and configuration types. -use std::os::raw::c_int; +use std::{os::raw::c_int, str::FromStr}; use crate::{ error::{Error, Status}, @@ -96,12 +96,17 @@ impl From<&[u8; N]> for OptionValue { } /// ADBC revision versions. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +/// +/// The [`Default`] implementation returns the latest version. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] #[non_exhaustive] pub enum AdbcVersion { /// Version 1.0.0. V100, /// Version 1.1.0. + /// + /// + #[default] V110, } @@ -120,8 +125,23 @@ impl TryFrom for AdbcVersion { match value { constants::ADBC_VERSION_1_0_0 => Ok(AdbcVersion::V100), constants::ADBC_VERSION_1_1_0 => Ok(AdbcVersion::V110), - _ => Err(Error::with_message_and_status( - format!("Unknown ADBC version: {}", value), + value => Err(Error::with_message_and_status( + format!("Unknown ADBC version: {value}"), + Status::InvalidArguments, + )), + } + } +} + +impl FromStr for AdbcVersion { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "1.0.0" | "1_0_0" | "100" => Ok(AdbcVersion::V100), + "1.1.0" | "1_1_0" | "110" => Ok(AdbcVersion::V110), + value => Err(Error::with_message_and_status( + format!("Unknown ADBC version: {value}"), Status::InvalidArguments, )), } diff --git a/rust/driver/snowflake/.gitignore b/rust/driver/snowflake/.gitignore new file mode 100644 index 0000000000..4c49bd78f1 --- /dev/null +++ b/rust/driver/snowflake/.gitignore @@ -0,0 +1 @@ +.env diff --git a/rust/driver/snowflake/Cargo.toml b/rust/driver/snowflake/Cargo.toml index 5731668a4e..569e9efe05 100644 --- a/rust/driver/snowflake/Cargo.toml +++ b/rust/driver/snowflake/Cargo.toml @@ -23,7 +23,18 @@ edition.workspace = true authors.workspace = true license.workspace = true +[features] +default = ["env", "dotenv"] +env = ["dep:regex"] +dotenv = ["env", "dep:dotenvy"] + [dependencies] adbc_core = { path = "../../core", features = ["driver_manager"] } arrow-array.workspace = true arrow-schema.workspace = true +dotenvy = { version = "0.15.7", default-features = false, optional = true } +regex = { version = "1.11.1", default-features = false, optional = true } +url = "2.5.3" + +[dev-dependencies] +test-with = { version = "0.14.4", default-features = false } diff --git a/rust/driver/snowflake/build.rs b/rust/driver/snowflake/build.rs index d9a922f467..ef0851b526 100644 --- a/rust/driver/snowflake/build.rs +++ b/rust/driver/snowflake/build.rs @@ -53,5 +53,8 @@ fn main() -> Result<(), Box> { println!("cargo:rustc-link-lib=framework=Security"); } + // Rebuild when tests are enabled. + println!("cargo:rerun-if-env-changed=ADBC_SNOWFLAKE_TESTS"); + Ok(()) } diff --git a/rust/driver/snowflake/src/builder.rs b/rust/driver/snowflake/src/builder.rs new file mode 100644 index 0000000000..b7eda8ad60 --- /dev/null +++ b/rust/driver/snowflake/src/builder.rs @@ -0,0 +1,32 @@ +//! Builder utility. +//! + +use std::iter::{Chain, Flatten}; + +use adbc_core::options::OptionValue; + +/// An iterator over the builder options. +pub struct BuilderIter( + #[allow(clippy::type_complexity)] + Chain< + Flatten<<[Option<(T, OptionValue)>; COUNT] as IntoIterator>::IntoIter>, + as IntoIterator>::IntoIter, + >, +); + +impl BuilderIter { + pub(crate) fn new( + fixed: [Option<(T, OptionValue)>; COUNT], + other: Vec<(T, OptionValue)>, + ) -> Self { + Self(fixed.into_iter().flatten().chain(other)) + } +} + +impl Iterator for BuilderIter { + type Item = (T, OptionValue); + + fn next(&mut self) -> Option { + self.0.next() + } +} diff --git a/rust/driver/snowflake/src/connection.rs b/rust/driver/snowflake/src/connection.rs index d4cbd69c0a..0ed9feb5cc 100644 --- a/rust/driver/snowflake/src/connection.rs +++ b/rust/driver/snowflake/src/connection.rs @@ -21,17 +21,20 @@ use adbc_core::{ driver_manager::ManagedConnection, error::Result, options::{InfoCode, OptionConnection, OptionValue}, - Connection, Optionable, + Optionable, }; use arrow_array::RecordBatchReader; use arrow_schema::Schema; -use crate::SnowflakeStatement; +use crate::Statement; + +mod builder; +pub use builder::*; /// Snowflake ADBC Connection. -pub struct SnowflakeConnection(pub(crate) ManagedConnection); +pub struct Connection(pub(crate) ManagedConnection); -impl Optionable for SnowflakeConnection { +impl Optionable for Connection { type Option = OptionConnection; fn set_option(&mut self, key: Self::Option, value: OptionValue) -> Result<()> { @@ -55,11 +58,11 @@ impl Optionable for SnowflakeConnection { } } -impl Connection for SnowflakeConnection { - type StatementType = SnowflakeStatement; +impl adbc_core::Connection for Connection { + type StatementType = Statement; fn new_statement(&mut self) -> Result { - self.0.new_statement().map(SnowflakeStatement) + self.0.new_statement().map(Statement) } fn cancel(&mut self) -> Result<()> { diff --git a/rust/driver/snowflake/src/connection/builder.rs b/rust/driver/snowflake/src/connection/builder.rs new file mode 100644 index 0000000000..e7401e1d82 --- /dev/null +++ b/rust/driver/snowflake/src/connection/builder.rs @@ -0,0 +1,98 @@ +//! A builder for a [`Connection`]. +//! +//! + +#[cfg(feature = "env")] +use std::env; +use std::fmt; + +use adbc_core::{ + error::Result, + options::{OptionConnection, OptionValue}, + Database as _, +}; + +#[cfg(feature = "env")] +use crate::database; +use crate::{builder::BuilderIter, Connection, Database}; + +/// A builder for [`Connection`]. +/// +/// The builder can be used to initialize a [`Connection`] with +/// [`Builder::build`] or by directly passing it to +/// [`Database::new_connection_with_opts`]. +#[derive(Clone, Default)] +#[non_exhaustive] +pub struct Builder { + /// Use high precision ([`Self::USE_HIGH_PRECISION`]). + pub use_high_precision: Option, + + /// Other options. + pub other: Vec<(OptionConnection, OptionValue)>, +} + +impl fmt::Debug for Builder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Builder").field("...", &self.other).finish() + } +} + +#[cfg(feature = "env")] +impl Builder { + /// See [`Self::use_high_precision`]. + pub const USE_HIGH_PRECISION_ENV: &str = database::Builder::USE_HIGH_PRECISION_ENV; + + /// Construct a builder, setting values based on values of the + /// configuration environment variables. + pub fn from_env() -> Self { + #[cfg(feature = "dotenv")] + let _ = dotenvy::dotenv(); + + let use_high_precision = env::var(Self::USE_HIGH_PRECISION_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + Self { + use_high_precision, + ..Default::default() + } + } +} + +impl Builder { + /// Number of fields in the builder (except other). + const COUNT: usize = 1; + + pub const USE_HIGH_PRECISION: &str = "adbc.snowflake.sql.client_option.use_high_precision"; + + /// Use high precision ([`Self::use_high_precision`]). + pub fn with_high_precision(mut self, use_high_precision: bool) -> Self { + self.use_high_precision = Some(use_high_precision); + self + } +} + +impl Builder { + /// Attempt to initialize a [`Connection`] using the values provided to + /// this builder using the provided [`Database`]. + pub fn build(self, database: &mut Database) -> Result { + database.new_connection_with_opts(self) + } +} + +impl IntoIterator for Builder { + type Item = (OptionConnection, OptionValue); + type IntoIter = BuilderIter; + + fn into_iter(self) -> Self::IntoIter { + BuilderIter::new( + [self + .use_high_precision + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::USE_HIGH_PRECISION.into(), value))], + self.other, + ) + } +} diff --git a/rust/driver/snowflake/src/database.rs b/rust/driver/snowflake/src/database.rs index 1f22102b8f..db1771c07e 100644 --- a/rust/driver/snowflake/src/database.rs +++ b/rust/driver/snowflake/src/database.rs @@ -19,15 +19,19 @@ use adbc_core::{ driver_manager::ManagedDatabase, error::Result, options::{OptionConnection, OptionDatabase, OptionValue}, - Database, Optionable, + Optionable, }; -use crate::SnowflakeConnection; +use crate::Connection; + +mod builder; +pub use builder::*; /// Snowflake ADBC Database. -pub struct SnowflakeDatabase(pub(crate) ManagedDatabase); +#[derive(Clone)] +pub struct Database(pub(crate) ManagedDatabase); -impl Optionable for SnowflakeDatabase { +impl Optionable for Database { type Option = OptionDatabase; fn set_option(&mut self, key: Self::Option, value: OptionValue) -> Result<()> { @@ -51,19 +55,17 @@ impl Optionable for SnowflakeDatabase { } } -impl Database for SnowflakeDatabase { - type ConnectionType = SnowflakeConnection; +impl adbc_core::Database for Database { + type ConnectionType = Connection; fn new_connection(&mut self) -> Result { - self.0.new_connection().map(SnowflakeConnection) + self.0.new_connection().map(Connection) } fn new_connection_with_opts( &mut self, opts: impl IntoIterator, ) -> Result { - self.0 - .new_connection_with_opts(opts) - .map(SnowflakeConnection) + self.0.new_connection_with_opts(opts).map(Connection) } } diff --git a/rust/driver/snowflake/src/database/builder.rs b/rust/driver/snowflake/src/database/builder.rs new file mode 100644 index 0000000000..e7f61c8fb1 --- /dev/null +++ b/rust/driver/snowflake/src/database/builder.rs @@ -0,0 +1,1061 @@ +//! A builder for a [`Database`]. +//! +//! + +use core::str; +#[cfg(feature = "env")] +use std::env; +use std::{fmt, path::PathBuf, str::FromStr, time::Duration}; + +use adbc_core::{ + error::{Error, Result, Status}, + options::{OptionDatabase, OptionValue}, + Driver as _, +}; +use url::{Host, Url}; + +#[cfg(feature = "env")] +use crate::duration::parse_duration; +use crate::{builder::BuilderIter, Database, Driver}; + +/// Authentication types. +#[derive(Copy, Clone, Debug, Default)] +#[non_exhaustive] +pub enum AuthType { + /// General username password authentication + #[default] + Snowflake, + /// OAuth authentication + OAuth, + /// Use a browser to access an Fed and perform SSO authentication + ExternalBrowser, + /// Native okta URL to perform SSO authentication on Okta + Okta, + /// Use Jwt to perform authentication + Jwt, + /// Username and password with mfa + UsernamePasswordMFA, +} + +impl fmt::Display for AuthType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Snowflake => "auth_snowflake", + Self::OAuth => "auth_oauth", + Self::ExternalBrowser => "auth_ext_browser", + Self::Okta => "auth_okta", + Self::Jwt => "auth_jwt", + Self::UsernamePasswordMFA => "auth_mfa", + } + ) + } +} + +impl str::FromStr for AuthType { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "auth_snowflake" => Ok(Self::Snowflake), + "auth_oauth" => Ok(Self::OAuth), + "auth_ext_browser" => Ok(Self::ExternalBrowser), + "auth_okta" => Ok(Self::Okta), + "auth_jwt" => Ok(Self::Jwt), + "auth_mfa" => Ok(Self::UsernamePasswordMFA), + _ => Err(Error::with_message_and_status( + format!("invalid auth type: {s}"), + Status::InvalidArguments, + )), + } + } +} + +/// Protocol types. +#[derive(Copy, Clone, Debug, Default)] +#[non_exhaustive] +pub enum Protocol { + /// Use `https`. + #[default] + Https, + /// Use `http`. + Http, +} + +impl fmt::Display for Protocol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Https => "https", + Self::Http => "http", + } + ) + } +} + +impl str::FromStr for Protocol { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "https" | "HTTPS" => Ok(Self::Https), + "http" | "HTTP" => Ok(Self::Http), + _ => Err(Error::with_message_and_status( + format!("invalid protocol type: {s}"), + Status::InvalidArguments, + )), + } + } +} + +/// Log levels. +#[derive(Copy, Clone, Debug, Default)] +#[non_exhaustive] +pub enum LogLevel { + /// Trace level + Trace, + /// Debug level + Debug, + /// Info level + Info, + /// Warn level + Warn, + /// Error level + Error, + /// Fatal level + Fatal, + /// Off + #[default] + Off, +} + +impl fmt::Display for LogLevel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Trace => "trace", + Self::Debug => "debug", + Self::Info => "info", + Self::Warn => "warn", + Self::Error => "error", + Self::Fatal => "fatal", + Self::Off => "off", + } + ) + } +} + +impl str::FromStr for LogLevel { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "trace" => Ok(Self::Trace), + "debug" => Ok(Self::Debug), + "info" => Ok(Self::Info), + "warn" => Ok(Self::Warn), + "error" => Ok(Self::Error), + "fatal" => Ok(Self::Fatal), + "off" => Ok(Self::Off), + _ => Err(Error::with_message_and_status( + format!("invalid log level: {s}"), + Status::InvalidArguments, + )), + } + } +} + +/// A builder for [`Database`]. +/// +/// The builder can be used to initialize a [`Database`] with +/// [`Builder::build`] or by directly passing it to +/// [`Driver::new_database_with_opts`]. +#[derive(Clone, Default)] +#[non_exhaustive] +pub struct Builder { + /// The URI ([`OptionDatabase::Uri`]). + pub uri: Option, + + /// The username ([`OptionDatabase::Username`]). + pub username: Option, + + /// The password ([`OptionDatabase::Password`]). + pub password: Option, + + /// The name of the database ([`Self::DATABASE`]). + pub database: Option, + + /// The name of the schema ([`Self::SCHEMA`]). + pub schema: Option, + + /// The name of the warehouse ([`Self::WAREHOUSE`]). + pub warehouse: Option, + + /// The name of the role ([`Self::ROLE`]). + pub role: Option, + + /// The name of the region ([`Self::REGION`]). + pub region: Option, + + /// The name of the account ([`Self::ACCOUNT`]). + pub account: Option, + + /// The protocol ([`Self::PROTOCOL`]). + pub protocol: Option, + + /// The port ([`Self::PORT`]). + pub port: Option, + + /// The host ([`Self::HOST`]). + pub host: Option, + + /// The authentication type ([`Self::AUTH_TYPE`]). + pub auth_type: Option, + + /// Login timeout duration ([`Self::LOGIN_TIMEOUT`]). + pub login_timeout: Option, + + /// Request timeout duration ([`Self::REQUEST_TIMEOUT`]). + pub request_timeout: Option, + + /// JWT expire timeout duration ([`Self::JWT_EXPIRE_TIMEOUT`]). + pub jwt_expire_timeout: Option, + + /// Client timeout duration ([`Self::CLIENT_TIMEOUT`]). + pub client_timeout: Option, + + /// Use high precision ([`Self::USE_HIGH_PRECISION`]). + pub use_high_precision: Option, + + /// Application name ([`Self::APPLICATION_NAME`]). + pub application_name: Option, + + /// SSL skip verify ([`Self::SSL_SKIP_VERIFY`]). + pub ssl_skip_verify: Option, + + /// OCSP fail open mode ([`Self::OCSP_FAIL_OPEN_MODE`]). + pub ocsp_fail_open_mode: Option, + + /// Auth token ([`Self::AUTH_TOKEN`]). + pub auth_token: Option, + + /// Auth Okta url ([`Self::AUTH_OKTA_URL`]). + pub auth_okta_url: Option, + + /// Keep session alive ([`Self::KEEP_SESSION_ALIVE`]). + pub keep_session_alive: Option, + + /// JWT private key file path ([`Self::JWT_PRIVATE_KEY`]). + pub jwt_private_key: Option, + + /// JWT private key PKCS 8 value ([`Self::JWT_PRIVATE_KEY_PKCS8_VALUE`]). + pub jwt_private_key_pkcs8_value: Option, + + /// JWT private key PKCS 8 password ([`Self::JWT_PRIVATE_KEY_PKCS8_PASSWORD`]). + pub jwt_private_key_pkcs8_password: Option, + + /// Disable telemetry ([`Self::DISABLE_TELEMETRY`]). + pub disable_telemetry: Option, + + /// Log tracing level ([`Self::LOG_TRACING`]). + pub log_tracing: Option, + + /// Client config file path ([`Self::CLIENT_CONFIG_FILE`]). + pub client_config_file: Option, + + /// Client cache MFA token ([`Self::CLIENT_CACHE_MFA_TOKEN`]). + pub client_cache_mfa_token: Option, + + /// Client store temporary credentials ([`Self::CLIENT_STORE_TEMP_CREDS`]). + pub client_store_temp_creds: Option, + + /// Other options. + pub other: Vec<(OptionDatabase, OptionValue)>, +} + +impl fmt::Debug for Builder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const HIDDEN: &str = "*****"; + f.debug_struct("Builder") + .field( + "uri", + &self.uri.clone().map(|mut url| { + let _ = url.set_password(url.password().and(Some(HIDDEN))); + url + }), + ) + .field("username", &self.username) + .field("password", &self.password.as_ref().map(|_| HIDDEN)) + .field("database", &self.database) + .field("schema", &self.schema) + .field("warehouse", &self.warehouse) + .field("role", &self.role) + .field("region", &self.region) + .field("account", &self.account) + .field("protocol", &self.protocol) + .field("port", &self.port) + .field("host", &self.host) + .field("auth_type", &self.auth_type) + .field("login_timeout", &self.login_timeout) + .field("request_timeout", &self.request_timeout) + .field("jwt_expire_timeout", &self.jwt_expire_timeout) + .field("client_timeout", &self.client_timeout) + .field("use_high_precision", &self.use_high_precision) + .field("application_name", &self.application_name) + .field("ssl_skip_verify", &self.ssl_skip_verify) + .field("ocsp_fail_open_mode", &self.ocsp_fail_open_mode) + .field("auth_token", &self.auth_token.as_ref().map(|_| HIDDEN)) + .field("auth_okta_url", &self.auth_okta_url) + .field("keep_session_alive", &self.keep_session_alive) + .field("jwt_private_key", &self.jwt_private_key) + .field( + "jwt_private_key_pkcs8_value", + &self.jwt_private_key_pkcs8_value.as_ref().map(|_| HIDDEN), + ) + .field( + "jwt_private_key_pkcs8_password", + &self.jwt_private_key_pkcs8_password.as_ref().map(|_| HIDDEN), + ) + .field("disable_telemetry", &self.disable_telemetry) + .field("log_tracing", &self.log_tracing) + .field("client_config_file", &self.client_config_file) + .field("client_cache_mfa_token", &self.client_cache_mfa_token) + .field("client_store_temp_creds", &self.client_store_temp_creds) + .field("...", &self.other) + .finish() + } +} + +#[cfg(feature = "env")] +impl Builder { + /// See [`Self::uri`]. + pub const URI_ENV: &str = "ADBC_SNOWFLAKE_URI"; + + /// See [`Self::username`]. + pub const USERNAME_ENV: &str = "ADBC_SNOWFLAKE_USERNAME"; + + /// See [`Self::password`]. + pub const PASSWORD_ENV: &str = "ADBC_SNOWFLAKE_PASSWORD"; + + /// See [`Self::database`]. + pub const DATABASE_ENV: &str = "ADBC_SNOWFLAKE_SQL_DB"; + + /// See [`Self::schema`]. + pub const SCHEMA_ENV: &str = "ADBC_SNOWFLAKE_SQL_SCHEMA"; + + /// See [`Self::warehouse`]. + pub const WAREHOUSE_ENV: &str = "ADBC_SNOWFLAKE_SQL_WAREHOUSE"; + + /// See [`Self::role`]. + pub const ROLE_ENV: &str = "ADBC_SNOWFLAKE_SQL_ROLE"; + + /// See [`Self::region`]. + pub const REGION_ENV: &str = "ADBC_SNOWFLAKE_SQL_REGION"; + + /// See [`Self::account`]. + pub const ACCOUNT_ENV: &str = "ADBC_SNOWFLAKE_SQL_ACCOUNT"; + + /// See [`Self::protocol`]. + pub const PROTOCOL_ENV: &str = "ADBC_SNOWFLAKE_SQL_URI_PROTOCOL"; + + /// See [`Self::port`]. + pub const PORT_ENV: &str = "ADBC_SNOWFLAKE_SQL_URI_PORT"; + + /// See [`Self::host`]. + pub const HOST_ENV: &str = "ADBC_SNOWFLAKE_SQL_URI_HOST"; + + /// See [`Self::auth_type`]. + pub const AUTH_TYPE_ENV: &str = "ADBC_SNOWFLAKE_SQL_AUTH_TYPE"; + + /// See [`Self::login_timeout`]. + pub const LOGIN_TIMEOUT_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTIONS_LOGIN_TIMEOUT"; + + /// See [`Self::request_timeout`]. + pub const REQUEST_TIMEOUT_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_REQUEST_TIMEOUT"; + + /// See [`Self::jwt_expire_timeout`]. + pub const JWT_EXPIRE_TIMEOUT_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_JWT_EXPIRE_TIMEOUT"; + + /// See [`Self::client_timeout`]. + pub const CLIENT_TIMEOUT_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_CLIENT_TIMEOUT"; + + /// See [`Self::use_high_precision`]. + pub const USE_HIGH_PRECISION_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_USE_HIGH_PRECISION"; + + /// See [`Self::application_name`]. + pub const APPLICATION_NAME_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_APP_NAME"; + + /// See [`Self::ssl_skip_verify`]. + pub const SSL_SKIP_VERIFY_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_TLS_SKIP_VERIFY"; + + /// See [`Self::ocsp_fail_open_mode`]. + pub const OCSP_FAIL_OPEN_MODE_ENV: &str = + "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_OCSP_FAIL_OPEN_MODE"; + + /// See [`Self::auth_token`]. + pub const AUTH_TOKEN_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_AUTH_TOKEN"; + + /// See [`Self::auth_okta_url`]. + pub const AUTH_OKTA_URL_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_OKTA_URL"; + + /// See [`Self::keep_session_alive`]. + pub const KEEP_SESSION_ALIVE_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_KEEP_SESSION_ALIVE"; + + /// See [`Self::jwt_private_key`]. + pub const JWT_PRIVATE_KEY_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_JWT_PRIVATE_KEY"; + + /// See [`Self::jwt_private_key_pkcs8_value`]. + pub const JWT_PRIVATE_KEY_PKCS8_VALUE_ENV: &str = + "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_JWT_PRIVATE_KEY_PKCS8_VALUE"; + + /// See [`Self::jwt_private_key_pkcs8_password`]. + pub const JWT_PRIVATE_KEY_PKCS8_PASSWORD_ENV: &str = + "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_JWT_PRIVATE_KEY_PKCS8_PASSWORD"; + + /// See [`Self::disable_telemetry`]. + pub const DISABLE_TELEMETRY_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_DISABLE_TELEMETRY"; + + /// See [`Self::log_tracing`]. + pub const LOG_TRACING_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_TRACING"; + + /// See [`Self::client_config_file`]. + pub const CLIENT_CONFIG_FILE_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_CONFIG_FILE"; + + /// See [`Self::client_cache_mfa_token`]. + pub const CLIENT_CACHE_MFA_TOKEN_ENV: &str = "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_CACHE_MFA_TOKEN"; + + /// See [`Self::client_store_temp_creds`]. + pub const CLIENT_STORE_TEMP_CREDS_ENV: &str = + "ADBC_SNOWFLAKE_SQL_CLIENT_OPTION_STORE_TEMP_CREDS"; + + /// Construct a builder, setting values based on values of the + /// configuration environment variables. + pub fn from_env() -> Self { + #[cfg(feature = "dotenv")] + let _ = dotenvy::dotenv(); + + let uri = env::var(Self::URI_ENV) + .ok() + .as_deref() + .and_then(|value| Url::parse(value).ok()); + let username = env::var(Self::USERNAME_ENV).ok(); + let password = env::var(Self::PASSWORD_ENV).ok(); + let database = env::var(Self::DATABASE_ENV).ok(); + let schema = env::var(Self::SCHEMA_ENV).ok(); + let warehouse = env::var(Self::WAREHOUSE_ENV).ok(); + let role = env::var(Self::ROLE_ENV).ok(); + let region = env::var(Self::REGION_ENV).ok(); + let account = env::var(Self::ACCOUNT_ENV).ok(); + let protocol = env::var(Self::PROTOCOL_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let port = env::var(Self::PORT_ENV) + .ok() + .and_then(|value| value.parse().ok()); + let host = env::var(Self::HOST_ENV) + .ok() + .as_deref() + .and_then(|value| Host::parse(value).ok()); + let auth_type = env::var(Self::AUTH_TYPE_ENV) + .ok() + .and_then(|value| value.parse().ok()); + let login_timeout = env::var(Self::LOGIN_TIMEOUT_ENV) + .ok() + .as_deref() + .and_then(|value| parse_duration(value).ok()); + let request_timeout = env::var(Self::REQUEST_TIMEOUT_ENV) + .ok() + .as_deref() + .and_then(|value| parse_duration(value).ok()); + let jwt_expire_timeout = env::var(Self::JWT_EXPIRE_TIMEOUT_ENV) + .ok() + .as_deref() + .and_then(|value| parse_duration(value).ok()); + let client_timeout = env::var(Self::CLIENT_TIMEOUT_ENV) + .ok() + .as_deref() + .and_then(|value| parse_duration(value).ok()); + let use_high_precision = env::var(Self::USE_HIGH_PRECISION_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let application_name = env::var(Self::APPLICATION_NAME_ENV).ok(); + let ssl_skip_verify = env::var(Self::SSL_SKIP_VERIFY_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let ocsp_fail_open_mode = env::var(Self::OCSP_FAIL_OPEN_MODE_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let auth_token = env::var(Self::AUTH_TOKEN_ENV).ok(); + let auth_okta_url = env::var(Self::AUTH_OKTA_URL_ENV) + .ok() + .as_deref() + .and_then(|value| Url::parse(value).ok()); + let keep_session_alive = env::var(Self::OCSP_FAIL_OPEN_MODE_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let jwt_private_key = env::var(Self::JWT_PRIVATE_KEY_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let jwt_private_key_pkcs8_value = env::var(Self::JWT_PRIVATE_KEY_PKCS8_VALUE_ENV).ok(); + let jwt_private_key_pkcs8_password = + env::var(Self::JWT_PRIVATE_KEY_PKCS8_PASSWORD_ENV).ok(); + let disable_telemetry = env::var(Self::DISABLE_TELEMETRY_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let log_tracing = env::var(Self::LOG_TRACING_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let client_config_file = env::var(Self::CLIENT_CONFIG_FILE_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let client_cache_mfa_token = env::var(Self::CLIENT_CACHE_MFA_TOKEN_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + let client_store_temp_creds = env::var(Self::CLIENT_STORE_TEMP_CREDS_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + Self { + uri, + username, + password, + database, + schema, + warehouse, + role, + region, + account, + protocol, + port, + host, + auth_type, + login_timeout, + request_timeout, + jwt_expire_timeout, + client_timeout, + use_high_precision, + application_name, + ssl_skip_verify, + ocsp_fail_open_mode, + auth_token, + auth_okta_url, + keep_session_alive, + jwt_private_key, + jwt_private_key_pkcs8_value, + jwt_private_key_pkcs8_password, + disable_telemetry, + log_tracing, + client_config_file, + client_cache_mfa_token, + client_store_temp_creds, + ..Default::default() + } + } +} + +impl Builder { + /// Number of fields in the builder (except other). + const COUNT: usize = 32; + + pub const DATABASE: &str = "adbc.snowflake.sql.db"; + pub const SCHEMA: &str = "adbc.snowflake.sql.schema"; + pub const WAREHOUSE: &str = "adbc.snowflake.sql.warehouse"; + pub const ROLE: &str = "adbc.snowflake.sql.role"; + pub const REGION: &str = "adbc.snowflake.sql.region"; + pub const ACCOUNT: &str = "adbc.snowflake.sql.account"; + pub const PROTOCOL: &str = "adbc.snowflake.sql.uri.protocol"; + pub const PORT: &str = "adbc.snowflake.sql.uri.port"; + pub const HOST: &str = "adbc.snowflake.sql.uri.host"; + pub const AUTH_TYPE: &str = "adbc.snowflake.sql.auth_type"; + pub const LOGIN_TIMEOUT: &str = "adbc.snowflake.sql.client_option.login_timeout"; + pub const REQUEST_TIMEOUT: &str = "adbc.snowflake.sql.client_option.request_timeout"; + pub const JWT_EXPIRE_TIMEOUT: &str = "adbc.snowflake.sql.client_option.jwt_expire_timeout"; + pub const CLIENT_TIMEOUT: &str = "adbc.snowflake.sql.client_option.client_timeout"; + pub const USE_HIGH_PRECISION: &str = "adbc.snowflake.sql.client_option.use_high_precision"; + pub const APPLICATION_NAME: &str = "adbc.snowflake.sql.client_option.app_name"; + pub const SSL_SKIP_VERIFY: &str = "adbc.snowflake.sql.client_option.tls_skip_verify"; + pub const OCSP_FAIL_OPEN_MODE: &str = "adbc.snowflake.sql.client_option.ocsp_fail_open_mode"; + pub const AUTH_TOKEN: &str = "adbc.snowflake.sql.client_option.auth_token"; + pub const AUTH_OKTA_URL: &str = "adbc.snowflake.sql.client_option.okta_url"; + pub const KEEP_SESSION_ALIVE: &str = "adbc.snowflake.sql.client_option.keep_session_alive"; + pub const JWT_PRIVATE_KEY: &str = "adbc.snowflake.sql.client_option.jwt_private_key"; + pub const JWT_PRIVATE_KEY_PKCS8_VALUE: &str = + "adbc.snowflake.sql.client_option.jwt_private_key_pkcs8_value"; + pub const JWT_PRIVATE_KEY_PKCS8_PASSWORD: &str = + "adbc.snowflake.sql.client_option.jwt_private_key_pkcs8_password"; + pub const DISABLE_TELEMETRY: &str = "adbc.snowflake.sql.client_option.disable_telemetry"; + pub const LOG_TRACING: &str = "adbc.snowflake.sql.client_option.tracing"; + pub const CLIENT_CONFIG_FILE: &str = "adbc.snowflake.sql.client_option.config_file"; + pub const CLIENT_CACHE_MFA_TOKEN: &str = "adbc.snowflake.sql.client_option.cache_mfa_token"; + pub const CLIENT_STORE_TEMP_CREDS: &str = "adbc.snowflake.sql.client_option.store_temp_creds"; + + /// Use the provided URI ([`Self::uri`]). + pub fn with_uri(mut self, uri: Url) -> Self { + self.uri = Some(uri); + self + } + + /// Parse and use the provided URI ([`Self::uri`]). + /// + /// Returns an error when parsing fails. + pub fn with_parse_uri(self, uri: impl AsRef) -> Result { + Url::parse(uri.as_ref()) + .map_err(|error| { + Error::with_message_and_status(error.to_string(), Status::InvalidArguments) + }) + .map(|uri| self.with_uri(uri)) + } + + /// Use the provided username ([`Self::username`]). + pub fn with_username(mut self, username: impl Into) -> Self { + self.username = Some(username.into()); + self + } + + /// Use the provided password ([`Self::password`]). + pub fn with_password(mut self, password: impl Into) -> Self { + self.password = Some(password.into()); + self + } + + /// Use the provided database ([`Self::database`]). + pub fn with_database(mut self, database: impl Into) -> Self { + self.database = Some(database.into()); + self + } + + /// Use the provided schema ([`Self::schema`]). + pub fn with_schema(mut self, schema: impl Into) -> Self { + self.schema = Some(schema.into()); + self + } + + /// Use the provided warehouse ([`Self::warehouse`]). + pub fn with_warehouse(mut self, warehouse: impl Into) -> Self { + self.warehouse = Some(warehouse.into()); + self + } + + /// Use the provided role ([`Self::role`]). + pub fn with_role(mut self, role: impl Into) -> Self { + self.role = Some(role.into()); + self + } + + /// Use the provided region ([`Self::region`]). + pub fn with_region(mut self, region: impl Into) -> Self { + self.region = Some(region.into()); + self + } + + /// Use the provided account ([`Self::account`]). + pub fn with_account(mut self, account: impl Into) -> Self { + self.account = Some(account.into()); + self + } + + /// Use the provided protocol ([`Self::protocol`]). + pub fn with_protocol(mut self, protocol: Protocol) -> Self { + self.protocol = Some(protocol); + self + } + + /// Parse and use the provided protocol ([`Self::protocol`]). + /// + /// Returns an error when parsing fails. + pub fn with_parse_protocol(self, protocol: impl AsRef) -> Result { + Protocol::from_str(protocol.as_ref()).map(|protocol| self.with_protocol(protocol)) + } + + /// Use the provided port ([`Self::port`]). + /// + /// # Example + /// + /// ``` + /// # use adbc_snowflake::database::Builder; + /// let builder = Builder::default().with_port(443); + /// + /// assert_eq!(builder.port, Some(443)); + /// ``` + pub fn with_port(mut self, port: u16) -> Self { + self.port = Some(port); + self + } + + /// Use the provided host ([`Self::host`]). + pub fn with_host(mut self, host: Host) -> Self { + self.host = Some(host); + self + } + + /// Parse and use the provided host ([`Self::host`]). + /// + /// Returns an error when parsing fails. + pub fn with_parse_host(self, host: impl AsRef) -> Result { + Host::parse(host.as_ref()) + .map_err(|error| { + Error::with_message_and_status(error.to_string(), Status::InvalidArguments) + }) + .map(|host| self.with_host(host)) + } + + /// Use the provided auth type ([`Self::auth_type`]). + pub fn with_auth_type(mut self, auth_type: AuthType) -> Self { + self.auth_type = Some(auth_type); + self + } + + /// Parse and use the provided auth type ([`Self::auth_type`]). + /// + /// Returns an error when parsing fails. + pub fn with_parse_auth_type(self, auth_type: impl AsRef) -> Result { + AuthType::from_str(auth_type.as_ref()).map(|auth_type| self.with_auth_type(auth_type)) + } + + /// Use the provided login timeout ([`Self::login_timeout`]). + pub fn with_login_timeout(mut self, login_timeout: Duration) -> Self { + self.login_timeout = Some(login_timeout); + self + } + + /// Parse and use the provided login timeout ([`Self::login_timeout`]). + /// + /// Returns an error when parsing fails. + #[cfg(feature = "env")] + pub fn with_parse_login_timeout(self, login_timeout: impl AsRef) -> Result { + parse_duration(login_timeout.as_ref()) + .map(|login_timeout| self.with_login_timeout(login_timeout)) + } + + /// Use the provided request timeout ([`Self::request_timeout`]). + pub fn with_request_timeout(mut self, request_timeout: Duration) -> Self { + self.request_timeout = Some(request_timeout); + self + } + + /// Parse and use the provided request timeout ([`Self::request_timeout`]). + /// + /// Returns an error when parsing fails. + #[cfg(feature = "env")] + pub fn with_parse_request_timeout(self, request_timeout: impl AsRef) -> Result { + parse_duration(request_timeout.as_ref()) + .map(|request_timeout| self.with_request_timeout(request_timeout)) + } + + /// Use the provided JWT expire timeout ([`Self::jwt_expire_timeout`]). + pub fn with_jwt_expire_timeout(mut self, jwt_expire_timeout: Duration) -> Self { + self.jwt_expire_timeout = Some(jwt_expire_timeout); + self + } + + /// Parse and use the provided JWT expire timeout ([`Self::jwt_expire_timeout`]). + /// + /// Returns an error when parsing fails. + #[cfg(feature = "env")] + pub fn with_parse_jwt_expire_timeout( + self, + jwt_expire_timeout: impl AsRef, + ) -> Result { + parse_duration(jwt_expire_timeout.as_ref()) + .map(|jwt_expire_timeout| self.with_jwt_expire_timeout(jwt_expire_timeout)) + } + + /// Use the provided client timeout ([`Self::client_timeout`]). + pub fn with_client_timeout(mut self, client_timeout: Duration) -> Self { + self.client_timeout = Some(client_timeout); + self + } + + /// Parse and use the provided client timeout ([`Self::client_timeout`]). + /// + /// Returns an error when parsing fails. + #[cfg(feature = "env")] + pub fn with_parse_client_timeout(self, client_timeout: impl AsRef) -> Result { + parse_duration(client_timeout.as_ref()) + .map(|client_timeout| self.with_client_timeout(client_timeout)) + } + + /// Use high precision ([`Self::use_high_precision`]). + pub fn with_high_precision(mut self, use_high_precision: bool) -> Self { + self.use_high_precision = Some(use_high_precision); + self + } + + /// Use the provided application name ([`Self::application_name`]). + pub fn with_application_name(mut self, application_name: impl Into) -> Self { + self.application_name = Some(application_name.into()); + self + } + + /// Use SSL skip verify ([`Self::ssl_skip_verify`]). + pub fn with_ssl_skip_verify(mut self, ssl_skip_verify: bool) -> Self { + self.ssl_skip_verify = Some(ssl_skip_verify); + self + } + + /// Use OCSP fail open mode ([`Self::ocsp_fail_open_mode`]). + pub fn with_ocsp_fail_open_mode(mut self, ocsp_fail_open_mode: bool) -> Self { + self.ocsp_fail_open_mode = Some(ocsp_fail_open_mode); + self + } + + /// Use the provided auth token ([`Self::auth_token`]). + pub fn with_auth_token(mut self, auth_token: impl Into) -> Self { + self.auth_token = Some(auth_token.into()); + self + } + + /// Use the provided auth Okta URL ([`Self::auth_okta_url`]). + pub fn with_auth_okta_url(mut self, auth_okta_url: Url) -> Self { + self.auth_okta_url = Some(auth_okta_url); + self + } + + /// Parse and use the provided auth Okta URL ([`Self::auth_okta_url`]). + /// + /// Returns an error when parsing fails. + pub fn with_parse_auth_okta_url(self, auth_okta_url: impl AsRef) -> Result { + Url::parse(auth_okta_url.as_ref()) + .map_err(|error| { + Error::with_message_and_status(error.to_string(), Status::InvalidArguments) + }) + .map(|auth_okta_url| self.with_auth_okta_url(auth_okta_url)) + } + + /// Use keep session alive ([`Self::keep_session_alive`]). + pub fn with_keep_session_alive(mut self, keep_session_alive: bool) -> Self { + self.keep_session_alive = Some(keep_session_alive); + self + } + + /// Use the provided JWT private key path ([`Self::jwt_private_key`]). + pub fn with_jwt_private_key(mut self, jwt_private_key: PathBuf) -> Self { + self.jwt_private_key = Some(jwt_private_key); + self + } + + /// Use the provided JWT private key PKCS 8 value ([`Self::jwt_private_key_pkcs8_value`]). + pub fn with_jwt_private_key_pkcs8_value(mut self, jwt_private_key_pkcs8_value: String) -> Self { + self.jwt_private_key_pkcs8_value = Some(jwt_private_key_pkcs8_value); + self + } + + /// Use the provided JWT private key PKCS 8 password ([`Self::jwt_private_key_pkcs8_password`]). + pub fn with_jwt_private_key_pkcs8_password( + mut self, + jwt_private_key_pkcs8_password: String, + ) -> Self { + self.jwt_private_key_pkcs8_password = Some(jwt_private_key_pkcs8_password); + self + } + + /// Use disable telemetry ([`Self::disable_telemetry`]). + pub fn with_disable_telemetry(mut self, disable_telemetry: bool) -> Self { + self.disable_telemetry = Some(disable_telemetry); + self + } + + /// Use the provided tracing log level ([`Self::log_tracing`]). + pub fn with_log_tracing(mut self, log_tracing: LogLevel) -> Self { + self.log_tracing = Some(log_tracing); + self + } + + /// Use the provided client config file path ([`Self::client_config_file`]). + pub fn with_client_config_file(mut self, client_config_file: PathBuf) -> Self { + self.client_config_file = Some(client_config_file); + self + } + + /// Use cache MFA token ([`Self::client_cache_mfa_token`]). + pub fn with_client_cache_mfa_token(mut self, client_cache_mfa_token: bool) -> Self { + self.client_cache_mfa_token = Some(client_cache_mfa_token); + self + } + + /// Use store temporary credentials ([`Self::client_store_temp_creds`]). + pub fn with_client_store_temp_creds(mut self, client_store_temp_creds: bool) -> Self { + self.client_store_temp_creds = Some(client_store_temp_creds); + self + } +} + +impl Builder { + /// Attempt to initialize a [`Database`] using the values provided to this + /// builder using the provided [`Driver`]. + pub fn build(self, driver: &mut Driver) -> Result { + driver.new_database_with_opts(self) + } +} + +impl IntoIterator for Builder { + type Item = (OptionDatabase, OptionValue); + type IntoIter = BuilderIter; + + fn into_iter(self) -> Self::IntoIter { + BuilderIter::new( + [ + self.uri + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (OptionDatabase::Uri, value)), + self.username + .map(OptionValue::String) + .map(|value| (OptionDatabase::Username, value)), + self.password + .map(OptionValue::String) + .map(|value| (OptionDatabase::Password, value)), + self.database + .map(OptionValue::String) + .map(|value| (Builder::DATABASE.into(), value)), + self.schema + .map(OptionValue::String) + .map(|value| (Builder::SCHEMA.into(), value)), + self.warehouse + .map(OptionValue::String) + .map(|value| (Builder::WAREHOUSE.into(), value)), + self.role + .map(OptionValue::String) + .map(|value| (Builder::ROLE.into(), value)), + self.region + .map(OptionValue::String) + .map(|value| (Builder::REGION.into(), value)), + self.account + .map(OptionValue::String) + .map(|value| (Builder::ACCOUNT.into(), value)), + self.protocol + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::PROTOCOL.into(), value)), + self.port + .as_ref() + // TODO(mbrobbel): the driver expects a string here? + // .map(i64::from) + // .map(OptionValue::Int) + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::PORT.into(), value)), + self.host + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::HOST.into(), value)), + self.auth_type + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::AUTH_TYPE.into(), value)), + self.login_timeout + .as_ref() + .map(|duration| format!("{duration:?}")) + .map(OptionValue::String) + .map(|value| (Builder::LOGIN_TIMEOUT.into(), value)), + self.request_timeout + .as_ref() + .map(|duration| format!("{duration:?}")) + .map(OptionValue::String) + .map(|value| (Builder::REQUEST_TIMEOUT.into(), value)), + self.jwt_expire_timeout + .as_ref() + .map(|duration| format!("{duration:?}")) + .map(OptionValue::String) + .map(|value| (Builder::JWT_EXPIRE_TIMEOUT.into(), value)), + self.client_timeout + .as_ref() + .map(|duration| format!("{duration:?}")) + .map(OptionValue::String) + .map(|value| (Builder::CLIENT_TIMEOUT.into(), value)), + self.use_high_precision + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::USE_HIGH_PRECISION.into(), value)), + self.application_name + .map(OptionValue::String) + .map(|value| (Builder::APPLICATION_NAME.into(), value)), + self.ssl_skip_verify + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::SSL_SKIP_VERIFY.into(), value)), + self.ocsp_fail_open_mode + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::OCSP_FAIL_OPEN_MODE.into(), value)), + self.auth_token + .map(OptionValue::String) + .map(|value| (Builder::AUTH_TOKEN.into(), value)), + self.auth_okta_url + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::AUTH_OKTA_URL.into(), value)), + self.keep_session_alive + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::KEEP_SESSION_ALIVE.into(), value)), + self.jwt_private_key + .as_ref() + .map(|path| path.display().to_string()) + .map(OptionValue::String) + .map(|value| (Builder::JWT_PRIVATE_KEY.into(), value)), + self.jwt_private_key_pkcs8_value + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::JWT_PRIVATE_KEY_PKCS8_VALUE.into(), value)), + self.jwt_private_key_pkcs8_password + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::JWT_PRIVATE_KEY_PKCS8_PASSWORD.into(), value)), + self.disable_telemetry + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::DISABLE_TELEMETRY.into(), value)), + self.log_tracing + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::LOG_TRACING.into(), value)), + self.client_config_file + .as_ref() + .map(|path| path.display().to_string()) + .map(OptionValue::String) + .map(|value| (Builder::CLIENT_CONFIG_FILE.into(), value)), + self.client_cache_mfa_token + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::CLIENT_CACHE_MFA_TOKEN.into(), value)), + self.client_store_temp_creds + .as_ref() + .map(ToString::to_string) + .map(OptionValue::String) + .map(|value| (Builder::CLIENT_STORE_TEMP_CREDS.into(), value)), + ], + self.other, + ) + } +} diff --git a/rust/driver/snowflake/src/driver.rs b/rust/driver/snowflake/src/driver.rs index ea9bfe2e23..12f6d53b47 100644 --- a/rust/driver/snowflake/src/driver.rs +++ b/rust/driver/snowflake/src/driver.rs @@ -15,21 +15,43 @@ // specific language governing permissions and limitations // under the License. -use std::ffi::{c_int, c_void}; +use std::{ + ffi::{c_int, c_void}, + fmt, +}; use adbc_core::{ driver_manager::ManagedDriver, error::Result, ffi::{FFI_AdbcDriverInitFunc, FFI_AdbcError, FFI_AdbcStatusCode}, options::{AdbcVersion, OptionDatabase, OptionValue}, - Driver, }; -use crate::SnowflakeDatabase; +use crate::Database; + +mod builder; +pub use builder::*; /// Snowflake ADBC Driver. -pub struct SnowflakeDriver(ManagedDriver); +#[derive(Clone)] +pub struct Driver(ManagedDriver); + +/// Panics when the drivers fails to load. +impl Default for Driver { + fn default() -> Self { + Self::try_load().expect("driver init") + } +} +impl fmt::Debug for Driver { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SnowflakeDriver") + .field("version", &self.0.version()) + .finish_non_exhaustive() + } +} + +// TODO(mbrobbel): support different linking methods through crate features #[link(name = "snowflake", kind = "static")] extern "C" { #[link_name = "SnowflakeDriverInit"] @@ -37,25 +59,58 @@ extern "C" { -> FFI_AdbcStatusCode; } -impl SnowflakeDriver { - /// Returns a [`SnowflakeDriver`] using the provided [`AdbcVersion`]. - pub fn try_new(version: AdbcVersion) -> Result { +impl Driver { + /// Returns a [`Driver`]. + /// + /// Defaults to the loading the latest [`AdbcVersion`]. To load the + /// [`Driver`] with a different version use [`Builder::with_adbc_version`], + /// or to load the configuration from environment variables use + /// [`Builder::from_env`]. + /// + /// # Error + /// + /// Returns an error when the driver fails to load. + pub fn try_load() -> Result { + Self::try_new(Default::default()) + } + + fn try_new(version: AdbcVersion) -> Result { let driver_init: FFI_AdbcDriverInitFunc = init; ManagedDriver::load_static(&driver_init, version).map(Self) } } -impl Driver for SnowflakeDriver { - type DatabaseType = SnowflakeDatabase; +impl adbc_core::Driver for Driver { + type DatabaseType = Database; fn new_database(&mut self) -> Result { - self.0.new_database().map(SnowflakeDatabase) + self.0.new_database().map(Database) } fn new_database_with_opts( &mut self, opts: impl IntoIterator, ) -> Result { - self.0.new_database_with_opts(opts).map(SnowflakeDatabase) + self.0.new_database_with_opts(opts).map(Database) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn try_load(version: AdbcVersion) -> Result<()> { + Builder::default().with_adbc_version(version).try_load()?; + Ok(()) + } + + #[test] + fn load_v1_0_0() -> Result<()> { + try_load(AdbcVersion::V100) + } + + #[test] + fn load_v1_1_0() -> Result<()> { + try_load(AdbcVersion::V110) } } diff --git a/rust/driver/snowflake/src/driver/builder.rs b/rust/driver/snowflake/src/driver/builder.rs new file mode 100644 index 0000000000..79a699615c --- /dev/null +++ b/rust/driver/snowflake/src/driver/builder.rs @@ -0,0 +1,64 @@ +//! A builder for [`Driver`]. +//! +//! + +#[cfg(feature = "env")] +use std::env; + +use adbc_core::{ + error::{Error, Result}, + options::AdbcVersion, +}; + +use crate::Driver; + +/// A builder for [`Driver`]. +/// +/// The builder can be used to initialize a [`Driver`] with +/// [`Builder::try_load`]. +#[derive(Clone, Debug, Default)] +#[non_exhaustive] +pub struct Builder { + /// The [`AdbcVersion`] version of the driver. + pub adbc_version: Option, +} + +#[cfg(feature = "env")] +impl Builder { + /// See [`Self::adbc_version`]. + pub const ADBC_VERSION_ENV: &str = "ADBC_SNOWFLAKE_ADBC_VERSION"; + + /// Construct a builder, setting values based on values of the + /// configuration environment variables. + pub fn from_env() -> Self { + #[cfg(feature = "dotenv")] + let _ = dotenvy::dotenv(); + + let adbc_version = env::var(Self::ADBC_VERSION_ENV) + .ok() + .as_deref() + .and_then(|value| value.parse().ok()); + Self { adbc_version } + } +} + +impl Builder { + /// Use the provided [`AdbcVersion`] when loading the driver. + pub fn with_adbc_version(mut self, version: AdbcVersion) -> Self { + self.adbc_version = Some(version); + self + } + + /// Try to load the [`Driver`] using the values provided to this builder. + pub fn try_load(self) -> Result { + Driver::try_new(self.adbc_version.unwrap_or_default()) + } +} + +impl TryFrom for Driver { + type Error = Error; + + fn try_from(value: Builder) -> Result { + value.try_load() + } +} diff --git a/rust/driver/snowflake/src/duration.rs b/rust/driver/snowflake/src/duration.rs new file mode 100644 index 0000000000..88c16df545 --- /dev/null +++ b/rust/driver/snowflake/src/duration.rs @@ -0,0 +1,263 @@ +//! A parser for [`Duration`] following . +//! + +use std::{error::Error as StdError, num::IntErrorKind, sync::LazyLock, time::Duration}; + +use adbc_core::error::{Error, Result, Status}; +use regex::Regex; + +// The regular expression used to parse durations. +static RE: LazyLock = LazyLock::new(|| { + Regex::new(r"(?P[0-9]*)\.?(?P[0-9]*)(?Pns|us|µs|μs|ms|s|m|h)") + .expect("valid regex") +}); + +fn invalid_arg(err: impl Into) -> Error { + Error::with_message_and_status(err.into(), Status::InvalidArguments) +} + +fn arg_err(err: impl StdError) -> Error { + invalid_arg(err.to_string()) +} + +fn overflow() -> Error { + invalid_arg("overflow") +} + +fn bad_input() -> Result { + Err(invalid_arg("bad input")) +} + +/// Parse the given string to a [`Duration`], returning an eror when parsing +/// fails. +/// +/// Following the logic of , except this +/// implementation does not support negative values i.e. it ignores sign +/// symbols, because [`Duration`] does not support negative values, and the Go +/// Snowflake driver uses absolute values for these durations. +pub(crate) fn parse_duration(input: &str) -> Result { + // Drop sign symbols. + let input = input.replace(['+', '-'], ""); + + // Special case for zero. + if input == "0" { + return Ok(Duration::ZERO); + } + + // Other bad input when there is no match. + if RE.find(&input).is_none() { + return bad_input(); + } + + // Aggregate durations. + RE.captures_iter(&input) + .map(|caps| caps.extract()) + .try_fold(Duration::ZERO, |mut duration, (_, [int, frac, unit])| { + // Int and frac can't both be empty. + if int.is_empty() && frac.is_empty() { + return bad_input(); + } + + // Parse int part. + let int = int + .parse::() + .or_else(|err| match err.kind() { + // Int can be empty to support . notation. + &IntErrorKind::Empty => Ok(0), + _ => Err(err), + }) + .map_err(arg_err)?; + + // Parse frac part. + let frac = format!("0.{frac}").parse::().map_err(arg_err)?; + + // Add this part to the duration. + duration += match unit { + "h" => { + Duration::from_secs(3600u64.checked_mul(int).ok_or(overflow())?) + + Duration::try_from_secs_f64(3600f64 * frac).map_err(arg_err)? + } + "m" => { + Duration::from_secs(60u64.checked_mul(int).ok_or(overflow())?) + + Duration::try_from_secs_f64(60f64 * frac).map_err(arg_err)? + } + "s" => { + Duration::from_secs(int) + Duration::try_from_secs_f64(frac).map_err(arg_err)? + } + "ms" => { + Duration::from_millis(int) + + Duration::try_from_secs_f64(frac / 1e3).map_err(arg_err)? + } + "us" | "µs" | "μs" => { + Duration::from_micros(int) + + Duration::try_from_secs_f64(frac / 1e6).map_err(arg_err)? + } + "ns" => { + if frac != 0f64 { + return Err(invalid_arg( + "unexpected fractional part for duration with ns unit", + )); + } + Duration::from_nanos(int) + } + _ => unreachable!(" matching group prevents this branch"), + }; + + Ok(duration) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse() { + assert_eq!(parse_duration("0"), Ok(Duration::from_secs(0))); + assert_eq!(parse_duration("0000.0000s"), Ok(Duration::from_secs(0))); + assert_eq!(parse_duration("5s"), Ok(Duration::from_secs(5))); + assert_eq!(parse_duration("30s"), Ok(Duration::from_secs(30))); + assert_eq!(parse_duration("1478s"), Ok(Duration::from_secs(1478))); + assert_eq!(parse_duration("-5s"), Ok(Duration::from_secs(5))); + assert_eq!(parse_duration("+5s"), Ok(Duration::from_secs(5))); + assert_eq!(parse_duration("-0"), Ok(Duration::from_secs(0))); + assert_eq!(parse_duration("+0"), Ok(Duration::from_secs(0))); + assert_eq!(parse_duration("5.0s"), Ok(Duration::from_secs(5))); + assert_eq!( + parse_duration("5.6s"), + Ok(Duration::from_secs(5) + Duration::from_millis(600)) + ); + assert_eq!(parse_duration("5.s"), Ok(Duration::from_secs(5))); + assert_eq!(parse_duration(".5s"), Ok(Duration::from_millis(500))); + assert_eq!(parse_duration("1.0s"), Ok(Duration::from_secs(1))); + assert_eq!(parse_duration("1.00s"), Ok(Duration::from_secs(1))); + assert_eq!( + parse_duration("1.004s"), + Ok(Duration::from_secs(1) + Duration::from_millis(4)) + ); + assert_eq!( + parse_duration("1.0040s"), + Ok(Duration::from_secs(1) + Duration::from_millis(4)) + ); + assert_eq!( + parse_duration("100.00100s"), + Ok(Duration::from_secs(100) + Duration::from_millis(1)) + ); + assert_eq!(parse_duration("10ns"), Ok(Duration::from_nanos(10))); + assert_eq!(parse_duration("11us"), Ok(Duration::from_micros(11))); + assert_eq!(parse_duration("12µs"), Ok(Duration::from_micros(12))); + assert_eq!(parse_duration("12μs"), Ok(Duration::from_micros(12))); + assert_eq!(parse_duration("13ms"), Ok(Duration::from_millis(13))); + assert_eq!(parse_duration("14s"), Ok(Duration::from_secs(14))); + assert_eq!(parse_duration("15m"), Ok(Duration::from_secs(60 * 15))); + assert_eq!(parse_duration("16h"), Ok(Duration::from_secs(60 * 60 * 16))); + assert_eq!( + parse_duration("3h30m"), + Ok(Duration::from_secs(60 * 60 * 3) + Duration::from_secs(60 * 30)) + ); + assert_eq!( + parse_duration("10.5s4m"), + Ok(Duration::from_secs(10) + Duration::from_millis(500) + Duration::from_secs(60 * 4)) + ); + assert_eq!( + parse_duration("-2m3.4s"), + Ok(Duration::from_secs(60 * 2) + Duration::from_secs(3) + Duration::from_millis(400)) + ); + assert_eq!( + parse_duration("1h2m3s4ms5us6ns"), + Ok(Duration::from_secs(60 * 60 * 1) + + Duration::from_secs(60 * 2) + + Duration::from_secs(3) + + Duration::from_millis(4) + + Duration::from_micros(5) + + Duration::from_nanos(6)) + ); + assert_eq!( + parse_duration("39h9m14.425s"), + Ok(Duration::from_secs(60 * 60 * 39) + + Duration::from_secs(60 * 9) + + Duration::from_secs(14) + + Duration::from_millis(425)) + ); + assert_eq!( + parse_duration("52763797000ns"), + Ok(Duration::from_nanos(52763797000)) + ); + assert_eq!( + parse_duration("0.3333333333333333333h"), + Ok(Duration::from_secs(60 * 20)) + ); + assert_eq!( + parse_duration("9007199254740993ns"), + Ok(Duration::from_nanos(9007199254740993)) + ); + assert_eq!( + parse_duration("9223372036854775807ns"), + Ok(Duration::from_nanos(9223372036854775807)) + ); + assert_eq!( + parse_duration("9223372036854775.807us"), + Ok(Duration::from_micros(9223372036854775) + Duration::from_nanos(807)) + ); + assert_eq!( + parse_duration("9223372036s854ms775us807ns"), + Ok(Duration::from_secs(9223372036) + + Duration::from_millis(854) + + Duration::from_micros(775) + + Duration::from_nanos(807)) + ); + assert_eq!( + parse_duration("-9223372036854775808ns"), + Ok(Duration::from_nanos(9223372036854775808)) + ); + assert_eq!( + parse_duration("-9223372036854775.808us"), + Ok(Duration::from_micros(9223372036854775) + Duration::from_nanos(808)) + ); + assert_eq!( + parse_duration("-9223372036s854ms775us808ns"), + Ok(Duration::from_secs(9223372036) + + Duration::from_millis(854) + + Duration::from_micros(775) + + Duration::from_nanos(808)) + ); + assert_eq!( + parse_duration("-9223372036854775808ns"), + Ok(Duration::from_nanos(9223372036854775808)) + ); + assert_eq!( + parse_duration("-2562047h47m16.854775808s"), + Ok(Duration::from_secs(60 * 60 * 2562047) + + Duration::from_secs(60 * 47) + + Duration::from_secs(16) + + Duration::from_nanos(854775808)) + ); + assert_eq!( + parse_duration("0.100000000000000000000h"), + Ok(Duration::from_secs(60 * 6)) + ); + assert_eq!( + parse_duration("0.830103483285477580700h"), + Ok(Duration::from_secs(60 * 49) + + Duration::from_secs(48) + + Duration::from_nanos(372539828)) + ); + let bad_input = Err(invalid_arg("bad input")); + assert_eq!(parse_duration(""), bad_input); + assert_eq!(parse_duration("3"), bad_input); + assert_eq!(parse_duration("-"), bad_input); + assert_eq!(parse_duration("s"), bad_input); + assert_eq!(parse_duration("."), bad_input); + assert_eq!(parse_duration("-."), bad_input); + assert_eq!(parse_duration(".s"), bad_input); + assert_eq!(parse_duration("+.s"), bad_input); + assert_eq!(parse_duration("1d"), bad_input); + assert_eq!( + parse_duration("1.1ns"), + Err(invalid_arg( + "unexpected fractional part for duration with ns unit" + )) + ); + assert_eq!(parse_duration("9999999999999999h"), Err(overflow())); + } +} diff --git a/rust/driver/snowflake/src/lib.rs b/rust/driver/snowflake/src/lib.rs index e14884c2d3..27e28b8e64 100644 --- a/rust/driver/snowflake/src/lib.rs +++ b/rust/driver/snowflake/src/lib.rs @@ -16,29 +16,33 @@ // under the License. //! Snowflake ADBC driver, based on the Go driver. +//! +//! ## Crate features +//! +//! ### `env` +//! +//! Adds `from_env` methods to initialize builders from environment variables. +//! +//! ### `dotenv`: `env` +//! +//! Loads environment variables from `.env` files in `from_env` methods. +//! -mod driver; -pub use driver::*; +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] -mod database; -pub use database::*; +pub mod driver; +pub use driver::Driver; -mod connection; -pub use connection::*; +pub mod database; +pub use database::Database; -mod statement; -pub use statement::*; +pub mod connection; +pub use connection::Connection; -#[cfg(test)] -mod tests { - use adbc_core::{error::Result, options::AdbcVersion}; +pub mod statement; +pub use statement::Statement; - use super::*; +pub mod builder; - #[test] - fn load_driver() -> Result<()> { - SnowflakeDriver::try_new(AdbcVersion::V100)?; - SnowflakeDriver::try_new(AdbcVersion::V110)?; - Ok(()) - } -} +#[cfg(feature = "env")] +pub(crate) mod duration; diff --git a/rust/driver/snowflake/src/statement.rs b/rust/driver/snowflake/src/statement.rs index 2715f185af..ed3d1cdb0c 100644 --- a/rust/driver/snowflake/src/statement.rs +++ b/rust/driver/snowflake/src/statement.rs @@ -19,15 +19,15 @@ use adbc_core::{ driver_manager::ManagedStatement, error::Result, options::{OptionStatement, OptionValue}, - Optionable, PartitionedResult, Statement, + Optionable, PartitionedResult, }; use arrow_array::{RecordBatch, RecordBatchReader}; use arrow_schema::Schema; /// Snowflake ADBC Statement. -pub struct SnowflakeStatement(pub(crate) ManagedStatement); +pub struct Statement(pub(crate) ManagedStatement); -impl Optionable for SnowflakeStatement { +impl Optionable for Statement { type Option = OptionStatement; fn set_option(&mut self, key: Self::Option, value: OptionValue) -> Result<()> { @@ -51,7 +51,7 @@ impl Optionable for SnowflakeStatement { } } -impl Statement for SnowflakeStatement { +impl adbc_core::Statement for Statement { fn bind(&mut self, batch: RecordBatch) -> Result<()> { self.0.bind(batch) } diff --git a/rust/driver/snowflake/tests/driver.rs b/rust/driver/snowflake/tests/driver.rs new file mode 100644 index 0000000000..a606567d7e --- /dev/null +++ b/rust/driver/snowflake/tests/driver.rs @@ -0,0 +1,46 @@ +//! Snowflake ADBC driver tests +//! +//! These tests are disabled by default because they require a Snowflake +//! account. +//! +//! To enable these tests set the `ADBC_SNOWFLAKE_TESTS` environment variable +//! when building these tests. +//! +//! These tests load the configuration from environment variables: +//! - Driver: [`driver::Builder::from_env`] +//! - Database: [`database::Builder::from_env`] +//! - Connection: ... +//! - Statement: ... +//! +//! These methods are available when the `env` crate feature is enabled. +//! + +#[cfg(feature = "env")] +#[test_with::env(ADBC_SNOWFLAKE_TESTS)] +mod tests { + use adbc_core::{error::Result, Database as _}; + use adbc_snowflake::{database, driver, Connection, Database, Driver}; + + fn with_driver(func: impl FnOnce(Driver) -> Result<()>) -> Result<()> { + driver::Builder::from_env().try_load().and_then(func) + } + + fn with_database(func: impl FnOnce(Database) -> Result<()>) -> Result<()> { + with_driver(|mut driver| { + database::Builder::from_env() + .build(&mut driver) + .and_then(func) + }) + } + + fn with_connection(func: impl FnOnce(Connection) -> Result<()>) -> Result<()> { + with_database(|mut database| database.new_connection().and_then(func)) + } + + #[test] + /// Test the configuration by constructing a connection. + fn connection() -> Result<()> { + with_connection(|_connection| Ok(()))?; + Ok(()) + } +} From e6f36389b55cd1b578fb841856ff2b121e6c99dd Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 15:48:23 +0100 Subject: [PATCH 08/20] Add missing license headers --- rust/driver/snowflake/.gitignore | 17 +++++++++++++++++ rust/driver/snowflake/src/builder.rs | 17 +++++++++++++++++ rust/driver/snowflake/src/connection/builder.rs | 17 +++++++++++++++++ rust/driver/snowflake/src/database/builder.rs | 17 +++++++++++++++++ rust/driver/snowflake/src/driver/builder.rs | 17 +++++++++++++++++ rust/driver/snowflake/src/duration.rs | 17 +++++++++++++++++ rust/driver/snowflake/tests/driver.rs | 17 +++++++++++++++++ 7 files changed, 119 insertions(+) diff --git a/rust/driver/snowflake/.gitignore b/rust/driver/snowflake/.gitignore index 4c49bd78f1..fed460a7c2 100644 --- a/rust/driver/snowflake/.gitignore +++ b/rust/driver/snowflake/.gitignore @@ -1 +1,18 @@ +# 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. + .env diff --git a/rust/driver/snowflake/src/builder.rs b/rust/driver/snowflake/src/builder.rs index b7eda8ad60..44a2b19a8f 100644 --- a/rust/driver/snowflake/src/builder.rs +++ b/rust/driver/snowflake/src/builder.rs @@ -1,3 +1,20 @@ +// 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. + //! Builder utility. //! diff --git a/rust/driver/snowflake/src/connection/builder.rs b/rust/driver/snowflake/src/connection/builder.rs index e7401e1d82..3c229de31c 100644 --- a/rust/driver/snowflake/src/connection/builder.rs +++ b/rust/driver/snowflake/src/connection/builder.rs @@ -1,3 +1,20 @@ +// 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. + //! A builder for a [`Connection`]. //! //! diff --git a/rust/driver/snowflake/src/database/builder.rs b/rust/driver/snowflake/src/database/builder.rs index e7f61c8fb1..d6ff8fdc5d 100644 --- a/rust/driver/snowflake/src/database/builder.rs +++ b/rust/driver/snowflake/src/database/builder.rs @@ -1,3 +1,20 @@ +// 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. + //! A builder for a [`Database`]. //! //! diff --git a/rust/driver/snowflake/src/driver/builder.rs b/rust/driver/snowflake/src/driver/builder.rs index 79a699615c..5c592cc236 100644 --- a/rust/driver/snowflake/src/driver/builder.rs +++ b/rust/driver/snowflake/src/driver/builder.rs @@ -1,3 +1,20 @@ +// 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. + //! A builder for [`Driver`]. //! //! diff --git a/rust/driver/snowflake/src/duration.rs b/rust/driver/snowflake/src/duration.rs index 88c16df545..096908a83d 100644 --- a/rust/driver/snowflake/src/duration.rs +++ b/rust/driver/snowflake/src/duration.rs @@ -1,3 +1,20 @@ +// 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. + //! A parser for [`Duration`] following . //! diff --git a/rust/driver/snowflake/tests/driver.rs b/rust/driver/snowflake/tests/driver.rs index a606567d7e..978b4cdac2 100644 --- a/rust/driver/snowflake/tests/driver.rs +++ b/rust/driver/snowflake/tests/driver.rs @@ -1,3 +1,20 @@ +// 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. + //! Snowflake ADBC driver tests //! //! These tests are disabled by default because they require a Snowflake From b6e7cd16d7b49f9f126e0cd5e4f61af6c6eb3d04 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 17:34:03 +0100 Subject: [PATCH 09/20] Fix clippy warning --- rust/driver/snowflake/src/duration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/driver/snowflake/src/duration.rs b/rust/driver/snowflake/src/duration.rs index 096908a83d..15549f8421 100644 --- a/rust/driver/snowflake/src/duration.rs +++ b/rust/driver/snowflake/src/duration.rs @@ -182,7 +182,7 @@ mod tests { ); assert_eq!( parse_duration("1h2m3s4ms5us6ns"), - Ok(Duration::from_secs(60 * 60 * 1) + Ok(Duration::from_secs(60 * 60) + Duration::from_secs(60 * 2) + Duration::from_secs(3) + Duration::from_millis(4) From c686f2edcf439cb8154cc53d415055a3b019dc04 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 17:34:39 +0100 Subject: [PATCH 10/20] Add `bundled` and `linked` features to control linking --- rust/driver/snowflake/Cargo.toml | 8 ++++- rust/driver/snowflake/build.rs | 37 ++++++++++++++++++-- rust/driver/snowflake/src/driver.rs | 54 ++++++++++++++++++++++++----- rust/driver/snowflake/src/lib.rs | 21 +++++++++-- 4 files changed, 105 insertions(+), 15 deletions(-) diff --git a/rust/driver/snowflake/Cargo.toml b/rust/driver/snowflake/Cargo.toml index 569e9efe05..852a85569b 100644 --- a/rust/driver/snowflake/Cargo.toml +++ b/rust/driver/snowflake/Cargo.toml @@ -24,7 +24,13 @@ authors.workspace = true license.workspace = true [features] -default = ["env", "dotenv"] +default = ["bundled", "env", "dotenv"] + +# Building/linking Go driver +bundled = [] +linked = [] + +# Configuration env = ["dep:regex"] dotenv = ["env", "dep:dotenvy"] diff --git a/rust/driver/snowflake/build.rs b/rust/driver/snowflake/build.rs index ef0851b526..914595064f 100644 --- a/rust/driver/snowflake/build.rs +++ b/rust/driver/snowflake/build.rs @@ -15,9 +15,13 @@ // specific language governing permissions and limitations // under the License. -use std::{env, error::Error, path::PathBuf, process::Command}; +use std::error::Error; + +/// Build and link the Go driver statically. +#[cfg(feature = "bundled")] +fn bundled() -> Result<(), Box> { + use std::{env, path::PathBuf, process::Command}; -fn main() -> Result<(), Box> { let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); let go_dir = manifest_dir.ancestors().nth(3).unwrap().join("go"); let go_pkg = go_dir.join("adbc/pkg/snowflake"); @@ -53,6 +57,35 @@ fn main() -> Result<(), Box> { println!("cargo:rustc-link-lib=framework=Security"); } + Ok(()) +} + +/// Link the Go driver. +#[cfg(feature = "linked")] +fn linked() -> Result<(), Box> { + // Rebuild when config var changes. + println!("cargo:rerun-if-env-changed=ADBC_SNOWFLAKE_GO_LIB_DIR"); + + // Add search path if requested. + if let Some(path) = option_env!("ADBC_SNOWFLAKE_GO_LIB_DIR") { + println!("cargo:rustc-link-search={path}"); + } + + // Link the driver. + println!("cargo:rustc-link-lib=adbc_driver_snowflake"); + + Ok(()) +} + +fn main() -> Result<(), Box> { + // Bundle the Go driver. + #[cfg(feature = "bundled")] + bundled()?; + + // Link the Go driver. + #[cfg(feature = "linked")] + linked()?; + // Rebuild when tests are enabled. println!("cargo:rerun-if-env-changed=ADBC_SNOWFLAKE_TESTS"); diff --git a/rust/driver/snowflake/src/driver.rs b/rust/driver/snowflake/src/driver.rs index 12f6d53b47..de3f51410e 100644 --- a/rust/driver/snowflake/src/driver.rs +++ b/rust/driver/snowflake/src/driver.rs @@ -15,15 +15,15 @@ // specific language governing permissions and limitations // under the License. -use std::{ - ffi::{c_int, c_void}, - fmt, -}; +#[cfg(any(feature = "bundled", feature = "linked"))] +use std::ffi::{c_int, c_void}; +use std::{fmt, sync::LazyLock}; +#[cfg(any(feature = "bundled", feature = "linked"))] +use adbc_core::ffi::{FFI_AdbcDriverInitFunc, FFI_AdbcError, FFI_AdbcStatusCode}; use adbc_core::{ driver_manager::ManagedDriver, error::Result, - ffi::{FFI_AdbcDriverInitFunc, FFI_AdbcError, FFI_AdbcStatusCode}, options::{AdbcVersion, OptionDatabase, OptionValue}, }; @@ -32,6 +32,14 @@ use crate::Database; mod builder; pub use builder::*; +static DRIVER: LazyLock> = LazyLock::new(|| { + ManagedDriver::load_dynamic_from_name( + "adbc_driver_snowflake", + Some(b"SnowflakeDriverInit"), + Default::default(), + ) +}); + /// Snowflake ADBC Driver. #[derive(Clone)] pub struct Driver(ManagedDriver); @@ -51,8 +59,7 @@ impl fmt::Debug for Driver { } } -// TODO(mbrobbel): support different linking methods through crate features -#[link(name = "snowflake", kind = "static")] +#[cfg(any(feature = "bundled", feature = "linked"))] extern "C" { #[link_name = "SnowflakeDriverInit"] fn init(version: c_int, raw_driver: *mut c_void, err: *mut FFI_AdbcError) @@ -75,8 +82,30 @@ impl Driver { } fn try_new(version: AdbcVersion) -> Result { - let driver_init: FFI_AdbcDriverInitFunc = init; - ManagedDriver::load_static(&driver_init, version).map(Self) + // Load the bundled or linked driver. + #[cfg(any(feature = "bundled", feature = "linked"))] + { + let driver_init: FFI_AdbcDriverInitFunc = init; + ManagedDriver::load_static(&driver_init, version).map(Self) + } + // Fallback: attempt to dynamically load the driver. + #[cfg(not(any(feature = "bundled", feature = "linked")))] + { + let _ = version; + Self::try_new_dynamic() + } + } + + fn try_new_dynamic() -> Result { + DRIVER.clone().map(Self) + } + + /// Returns a dynamically loaded [`Driver`]. + /// + /// This attempts to load the `adbc_driver_snowflake` library using the + /// default `AdbcVersion`. + pub fn try_load_dynamic() -> Result { + Self::try_new_dynamic() } } @@ -113,4 +142,11 @@ mod tests { fn load_v1_1_0() -> Result<()> { try_load(AdbcVersion::V110) } + + #[test] + fn dynamic() -> Result<()> { + let _a = Driver::try_load_dynamic()?; + let _b = Driver::try_load_dynamic()?; + Ok(()) + } } diff --git a/rust/driver/snowflake/src/lib.rs b/rust/driver/snowflake/src/lib.rs index 27e28b8e64..a3ff958631 100644 --- a/rust/driver/snowflake/src/lib.rs +++ b/rust/driver/snowflake/src/lib.rs @@ -17,16 +17,31 @@ //! Snowflake ADBC driver, based on the Go driver. //! -//! ## Crate features +//! # Features //! -//! ### `env` +//! ## Linking +//! +//! ### `bundled` (default) +//! +//! Builds the Go Snowflake driver from source and links it statically. This +//! requires a Go compiler to be installed. +//! +//! ### `linked` +//! +//! Link the Go Snowflake driver at build time. Set `ADBC_SNOWFLAKE_GO_LIB_DIR` +//! to add a search paths for the linker. +//! +//! ## Configuration +//! +//! ### `env` (default) //! //! Adds `from_env` methods to initialize builders from environment variables. //! -//! ### `dotenv`: `env` +//! ### `dotenv`: `env` (default) //! //! Loads environment variables from `.env` files in `from_env` methods. //! +//! #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] From 032cb92013eb6c558f6de97e74f328a1ae72fecd Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 18:22:59 +0100 Subject: [PATCH 11/20] Use testing database in CI --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e6fc5a5b39..a0daa40fb7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -120,6 +120,7 @@ jobs: env: ADBC_SNOWFLAKE_TESTS: 1 ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} + ADBC_SNOWFLAKE_SQL_DB: ADBC_TESTING - name: Doctests run: cargo test --workspace --doc --all-features - name: Check docs From 80898f1e6a940704670ca795de7d2e8389773218 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 22:35:33 +0100 Subject: [PATCH 12/20] Add go lib dir to search path --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a0daa40fb7..376f949670 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -121,6 +121,7 @@ jobs: ADBC_SNOWFLAKE_TESTS: 1 ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} ADBC_SNOWFLAKE_SQL_DB: ADBC_TESTING + ADBC_SNOWFLAKE_GO_LIB_DIR: ${{ github.workspace }}/build/lib - name: Doctests run: cargo test --workspace --doc --all-features - name: Check docs From cf5421327010939a2eb96dd388ab41494110a70f Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Tue, 19 Nov 2024 23:05:25 +0100 Subject: [PATCH 13/20] Disable integration tests for now --- .github/workflows/rust.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 376f949670..ccf2d19fbf 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -118,9 +118,9 @@ jobs: - name: Test run: cargo test --workspace --all-targets --all-features env: - ADBC_SNOWFLAKE_TESTS: 1 - ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} - ADBC_SNOWFLAKE_SQL_DB: ADBC_TESTING + # ADBC_SNOWFLAKE_TESTS: 1 + # ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} + # ADBC_SNOWFLAKE_SQL_DB: ADBC_TESTING ADBC_SNOWFLAKE_GO_LIB_DIR: ${{ github.workspace }}/build/lib - name: Doctests run: cargo test --workspace --doc --all-features From 7b3ed839ab198d3f1d86e4fe511784fa25c7bf50 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 20 Nov 2024 10:00:07 +0100 Subject: [PATCH 14/20] Ignore load dynamic driver test when `linked` feature is not set --- rust/driver/snowflake/src/driver.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/driver/snowflake/src/driver.rs b/rust/driver/snowflake/src/driver.rs index de3f51410e..48b05fcfb0 100644 --- a/rust/driver/snowflake/src/driver.rs +++ b/rust/driver/snowflake/src/driver.rs @@ -144,6 +144,10 @@ mod tests { } #[test] + #[cfg_attr( + not(feature = "linked"), + ignore = "because the `linked` feature is not enabled" + )] fn dynamic() -> Result<()> { let _a = Driver::try_load_dynamic()?; let _b = Driver::try_load_dynamic()?; From af70f82d8cad3615e4e46356f751985c3c1d922d Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 20 Nov 2024 10:04:10 +0100 Subject: [PATCH 15/20] Set `ADBC_SNOWFLAKE_GO_LIB_DIR` for all steps --- .github/workflows/rust.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ccf2d19fbf..ab0554fe2b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -113,15 +113,16 @@ jobs: if: matrix.os == 'macos-13' run: | echo "DYLD_LIBRARY_PATH=/usr/local/opt/sqlite/lib:${{ github.workspace }}/build/lib:$DYLD_LIBRARY_PATH" >> "$GITHUB_ENV" + - name: Set search dir for Snowflake Go lib + run: echo "ADBC_SNOWFLAKE_GO_LIB_DIR=${{ github.workspace }}/build/lib" >> "$GITHUB_ENV" - name: Clippy run: cargo clippy --workspace --all-targets --all-features -- -Dwarnings - name: Test run: cargo test --workspace --all-targets --all-features - env: - # ADBC_SNOWFLAKE_TESTS: 1 - # ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} - # ADBC_SNOWFLAKE_SQL_DB: ADBC_TESTING - ADBC_SNOWFLAKE_GO_LIB_DIR: ${{ github.workspace }}/build/lib + # env: + # ADBC_SNOWFLAKE_TESTS: 1 + # ADBC_SNOWFLAKE_URI: ${{ secrets.SNOWFLAKE_URI }} + # ADBC_SNOWFLAKE_SQL_DB: ADBC_TESTING - name: Doctests run: cargo test --workspace --doc --all-features - name: Check docs From 041f72ded9b594efa950454a6284385319ef3f9e Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 20 Nov 2024 11:46:38 +0100 Subject: [PATCH 16/20] Add `adbc_snowflake` to release script --- dev/release/post-08-rust.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/release/post-08-rust.sh b/dev/release/post-08-rust.sh index e31427d5b7..1d9eaf54b8 100755 --- a/dev/release/post-08-rust.sh +++ b/dev/release/post-08-rust.sh @@ -42,10 +42,12 @@ main() { pushd "${SOURCE_TOP_DIR}/rust" cargo publish --all-features -p adbc_core + cargo publish -p adbc_snowflake popd - echo "Success! The released Cargo crate is available here:" + echo "Success! The released Cargo crates are available here:" echo " https://crates.io/crates/adbc_core" + echo " https://crates.io/crates/adbc_snowflake" } main "$@" From 0229b4174834b3286df66e0ee0b264128143fa60 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 20 Nov 2024 14:18:41 +0100 Subject: [PATCH 17/20] Add some get info methods and tests --- rust/core/src/options.rs | 2 +- rust/driver/snowflake/src/database.rs | 112 +++++++++++++++++++++++++- rust/driver/snowflake/tests/driver.rs | 38 ++++++++- 3 files changed, 144 insertions(+), 8 deletions(-) diff --git a/rust/core/src/options.rs b/rust/core/src/options.rs index 2dd7f6aec5..0d3af92fff 100644 --- a/rust/core/src/options.rs +++ b/rust/core/src/options.rs @@ -149,7 +149,7 @@ impl FromStr for AdbcVersion { } /// Info codes for database/driver metadata. -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum InfoCode { /// The database vendor/product name (type: utf8). diff --git a/rust/driver/snowflake/src/database.rs b/rust/driver/snowflake/src/database.rs index db1771c07e..ba497adb9d 100644 --- a/rust/driver/snowflake/src/database.rs +++ b/rust/driver/snowflake/src/database.rs @@ -15,11 +15,18 @@ // specific language governing permissions and limitations // under the License. +use std::{collections::HashSet, ffi::c_int, sync::Arc}; + use adbc_core::{ driver_manager::ManagedDatabase, - error::Result, - options::{OptionConnection, OptionDatabase, OptionValue}, - Optionable, + error::{Error, Result, Status}, + options::{AdbcVersion, InfoCode, OptionConnection, OptionDatabase, OptionValue}, + Connection as _, Database as _, Optionable, +}; +use arrow_array::{ + cast::AsArray, + types::{Int64Type, UInt32Type}, + Array, }; use crate::Connection; @@ -31,6 +38,105 @@ pub use builder::*; #[derive(Clone)] pub struct Database(pub(crate) ManagedDatabase); +impl Database { + fn get_info(&mut self, info_code: InfoCode) -> Result> { + self.new_connection()? + .get_info(Some(HashSet::from_iter([info_code])))? + .next() + .ok_or(Error::with_message_and_status( + "failed to get info", + Status::Internal, + ))? + .map_err(Into::into) + .and_then(|record_batch| { + if InfoCode::try_from(record_batch.column(0).as_primitive::().value(0))? + == info_code + { + Ok(record_batch.column(1).as_union().value(0)) + } else { + Err(Error::with_message_and_status( + "invalid get info reply", + Status::Internal, + )) + } + }) + } + + /// Returns the name of the vendor. + pub fn vendor_name(&mut self) -> Result { + self.get_info(InfoCode::VendorName) + .map(|array| array.as_string::().value(0).to_owned()) + } + + /// Returns the version of the vendor. + pub fn vendor_version(&mut self) -> Result { + self.get_info(InfoCode::VendorVersion) + .map(|array| array.as_string::().value(0).to_owned()) + } + + /// Returns the Arrow version of the vendor. + pub fn vendor_arrow_version(&mut self) -> Result { + self.get_info(InfoCode::VendorArrowVersion) + .map(|array| array.as_string::().value(0).to_owned()) + } + + /// Returns true if SQL queries are supported. + pub fn vendor_sql(&mut self) -> Result { + self.get_info(InfoCode::VendorSql) + .map(|array| array.as_boolean().value(0)) + } + + /// Returns true if Substrait queries are supported. + pub fn vendor_substrait(&mut self) -> Result { + self.get_info(InfoCode::VendorSubstrait) + .map(|array| array.as_boolean().value(0)) + } + + /// Returns the name of the wrapped Go driver. + pub fn driver_name(&mut self) -> Result { + self.get_info(InfoCode::DriverName) + .map(|array| array.as_string::().value(0).to_owned()) + } + + /// Returns the version of the wrapped Go driver. + pub fn driver_version(&mut self) -> Result { + self.get_info(InfoCode::DriverVersion) + .map(|array| array.as_string::().value(0).to_owned()) + } + + /// Returns the Arrow version of the wrapped Go driver. + pub fn driver_arrow_version(&mut self) -> Result { + self.get_info(InfoCode::DriverArrowVersion) + .map(|array| array.as_string::().value(0).to_owned()) + } + + /// Returns the [`AdbcVersion`] reported by the driver. + pub fn adbc_version(&mut self) -> Result { + self.new_connection()? + .get_info(Some(HashSet::from_iter([InfoCode::DriverAdbcVersion])))? + .next() + .ok_or(Error::with_message_and_status( + "failed to get info", + Status::Internal, + ))? + .map_err(Into::into) + .and_then(|record_batch| { + assert_eq!( + record_batch.column(0).as_primitive::().value(0), + u32::from(&InfoCode::DriverAdbcVersion) + ); + AdbcVersion::try_from( + record_batch + .column(1) + .as_union() + .value(0) + .as_primitive::() + .value(0) as c_int, + ) + }) + } +} + impl Optionable for Database { type Option = OptionDatabase; diff --git a/rust/driver/snowflake/tests/driver.rs b/rust/driver/snowflake/tests/driver.rs index 978b4cdac2..b6892e807f 100644 --- a/rust/driver/snowflake/tests/driver.rs +++ b/rust/driver/snowflake/tests/driver.rs @@ -32,14 +32,19 @@ //! These methods are available when the `env` crate feature is enabled. //! +#[cfg(test)] #[cfg(feature = "env")] -#[test_with::env(ADBC_SNOWFLAKE_TESTS)] mod tests { - use adbc_core::{error::Result, Database as _}; + use adbc_core::{error::Result, options::AdbcVersion, Database as _}; use adbc_snowflake::{database, driver, Connection, Database, Driver}; + const ADBC_VERSION: AdbcVersion = AdbcVersion::V110; + fn with_driver(func: impl FnOnce(Driver) -> Result<()>) -> Result<()> { - driver::Builder::from_env().try_load().and_then(func) + driver::Builder::from_env() + .with_adbc_version(ADBC_VERSION) + .try_load() + .and_then(func) } fn with_database(func: impl FnOnce(Database) -> Result<()>) -> Result<()> { @@ -54,10 +59,35 @@ mod tests { with_database(|mut database| database.new_connection().and_then(func)) } - #[test] + #[test_with::env(ADBC_SNOWFLAKE_TESTS)] /// Test the configuration by constructing a connection. fn connection() -> Result<()> { with_connection(|_connection| Ok(()))?; Ok(()) } + + #[test_with::env(ADBC_SNOWFLAKE_TESTS)] + /// Check the returned info by the driver. + fn get_info() -> Result<()> { + with_database(|mut database| { + assert_eq!(database.vendor_name(), Ok("Snowflake".to_owned())); + assert!(database + .vendor_version() + .is_ok_and(|version| version.starts_with("v"))); + assert!(database.vendor_arrow_version().is_ok()); + assert_eq!(database.vendor_sql(), Ok(true)); + assert_eq!(database.vendor_substrait(), Ok(false)); + assert_eq!( + database.driver_name(), + Ok("ADBC Snowflake Driver - Go".to_owned()) + ); + assert!(database.driver_version().is_ok()); + assert!(database + .driver_arrow_version() + .is_ok_and(|version| version.starts_with("v"))); + assert_eq!(database.adbc_version(), Ok(ADBC_VERSION)); + Ok(()) + })?; + Ok(()) + } } From 2b5a8b9be7de2434ae9433eb8e1dc6763b690205 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 20 Nov 2024 16:50:12 +0100 Subject: [PATCH 18/20] Add a few more tests --- rust/driver/snowflake/src/connection.rs | 1 + rust/driver/snowflake/tests/driver.rs | 127 +++++++++++++++++++----- 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/rust/driver/snowflake/src/connection.rs b/rust/driver/snowflake/src/connection.rs index 0ed9feb5cc..4aea39ccb3 100644 --- a/rust/driver/snowflake/src/connection.rs +++ b/rust/driver/snowflake/src/connection.rs @@ -32,6 +32,7 @@ mod builder; pub use builder::*; /// Snowflake ADBC Connection. +#[derive(Clone)] pub struct Connection(pub(crate) ManagedConnection); impl Optionable for Connection { diff --git a/rust/driver/snowflake/tests/driver.rs b/rust/driver/snowflake/tests/driver.rs index b6892e807f..8f2a28d72e 100644 --- a/rust/driver/snowflake/tests/driver.rs +++ b/rust/driver/snowflake/tests/driver.rs @@ -24,51 +24,61 @@ //! when building these tests. //! //! These tests load the configuration from environment variables: -//! - Driver: [`driver::Builder::from_env`] -//! - Database: [`database::Builder::from_env`] -//! - Connection: ... +//! - Driver: [`adbc_snowflake::driver::Builder::from_env`] +//! - Database: [`adbc_snowflake::database::Builder::from_env`] +//! - Connection: [`adbc_snowflake::connection::Builder::from_env`] //! - Statement: ... //! //! These methods are available when the `env` crate feature is enabled. //! -#[cfg(test)] #[cfg(feature = "env")] mod tests { - use adbc_core::{error::Result, options::AdbcVersion, Database as _}; - use adbc_snowflake::{database, driver, Connection, Database, Driver}; + use std::{collections::HashSet, ops::Deref, sync::LazyLock}; + + use adbc_core::{ + error::{Error, Result}, + options::AdbcVersion, + Connection as _, Statement as _, + }; + use adbc_snowflake::{connection, database, driver, Connection, Database, Driver, Statement}; + use arrow_array::{cast::AsArray, types::Decimal128Type}; const ADBC_VERSION: AdbcVersion = AdbcVersion::V110; - fn with_driver(func: impl FnOnce(Driver) -> Result<()>) -> Result<()> { + static DRIVER: LazyLock> = LazyLock::new(|| { driver::Builder::from_env() .with_adbc_version(ADBC_VERSION) .try_load() - .and_then(func) - } + }); + + static DATABASE: LazyLock> = + LazyLock::new(|| database::Builder::from_env().build(&mut DRIVER.deref().clone()?)); + + static CONNECTION: LazyLock> = + LazyLock::new(|| connection::Builder::from_env().build(&mut DATABASE.deref().clone()?)); fn with_database(func: impl FnOnce(Database) -> Result<()>) -> Result<()> { - with_driver(|mut driver| { - database::Builder::from_env() - .build(&mut driver) - .and_then(func) - }) + DATABASE.deref().clone().and_then(func) } fn with_connection(func: impl FnOnce(Connection) -> Result<()>) -> Result<()> { - with_database(|mut database| database.new_connection().and_then(func)) + // This always clones the connection because connection methods require + // exclusive access (&mut Connection). The alternative would be an + // `Arc>` however any test failure is a panic and + // would trigger mutex poisoning. + // + // TODO(mbrobbel): maybe force interior mutability via the core traits? + CONNECTION.deref().clone().and_then(func) } - #[test_with::env(ADBC_SNOWFLAKE_TESTS)] - /// Test the configuration by constructing a connection. - fn connection() -> Result<()> { - with_connection(|_connection| Ok(()))?; - Ok(()) + fn with_empty_statement(func: impl FnOnce(Statement) -> Result<()>) -> Result<()> { + with_connection(|mut connection| connection.new_statement().and_then(func)) } #[test_with::env(ADBC_SNOWFLAKE_TESTS)] - /// Check the returned info by the driver. - fn get_info() -> Result<()> { + /// Check the returned info by the driver using the database methods. + fn database_get_info() -> Result<()> { with_database(|mut database| { assert_eq!(database.vendor_name(), Ok("Snowflake".to_owned())); assert!(database @@ -87,7 +97,76 @@ mod tests { .is_ok_and(|version| version.starts_with("v"))); assert_eq!(database.adbc_version(), Ok(ADBC_VERSION)); Ok(()) - })?; - Ok(()) + }) + } + + #[test_with::env(ADBC_SNOWFLAKE_TESTS)] + /// Check execute of statement with `SELECT 21 + 21` query. + fn statement_execute() -> Result<()> { + with_empty_statement(|mut statement| { + statement.set_sql_query("SELECT 21 + 21")?; + let batch = statement + .execute()? + .next() + .expect("a record batch") + .map_err(Error::from)?; + assert_eq!( + batch.column(0).as_primitive::().value(0), + 42 + ); + Ok(()) + }) + } + + #[test_with::env(ADBC_SNOWFLAKE_TESTS)] + /// Check execute schema of statement with `SHOW WAREHOUSES` query. + fn statement_execute_schema() -> Result<()> { + with_empty_statement(|mut statement| { + statement.set_sql_query("SHOW WAREHOUSES")?; + let schema = statement.execute_schema()?; + let field_names = schema + .fields() + .into_iter() + .map(|field| field.name().as_ref()) + .collect::>(); + let expected_field_names = [ + "name", + "state", + "type", + "size", + "running", + "queued", + "is_default", + "is_current", + "auto_suspend", + "auto_resume", + "available", + "provisioning", + "quiescing", + "other", + "created_on", + "resumed_on", + "updated_on", + "owner", + "comment", + "resource_monitor", + "actives", + "pendings", + "failed", + "suspended", + "uuid", + "budget", + "owner_role_type", + ] + .into_iter() + .collect::>(); + assert_eq!( + expected_field_names + .difference(&field_names) + .collect::>(), + Vec::<&&str>::default() + ); + Ok(()) + }) } } From 61bc5585e407b0c6ef95d7adc9e7a82a3cb50df2 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 21 Nov 2024 11:07:41 +0100 Subject: [PATCH 19/20] Add some docs --- rust/Cargo.toml | 1 + rust/driver/snowflake/Cargo.toml | 7 ++ rust/driver/snowflake/README.md | 85 +++++++++++++++++++ rust/driver/snowflake/src/builder.rs | 3 +- rust/driver/snowflake/src/connection.rs | 4 + .../snowflake/src/connection/builder.rs | 2 +- rust/driver/snowflake/src/database.rs | 4 + rust/driver/snowflake/src/database/builder.rs | 2 +- rust/driver/snowflake/src/driver.rs | 45 ++++++++++ rust/driver/snowflake/src/driver/builder.rs | 2 +- rust/driver/snowflake/src/duration.rs | 3 +- rust/driver/snowflake/src/lib.rs | 35 ++------ rust/driver/snowflake/src/statement.rs | 4 + 13 files changed, 163 insertions(+), 34 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 97e990e931..dfb056422d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -23,6 +23,7 @@ resolver = "2" version = "0.16.0" description = "Rust implementation of Arrow Database Connectivity (ADBC)" edition = "2021" +rust-version = "1.80.1" authors = ["Apache Arrow "] license = "Apache-2.0" documentation = "https://docs.rs/adbc_core/" diff --git a/rust/driver/snowflake/Cargo.toml b/rust/driver/snowflake/Cargo.toml index 852a85569b..d563f219a5 100644 --- a/rust/driver/snowflake/Cargo.toml +++ b/rust/driver/snowflake/Cargo.toml @@ -22,6 +22,13 @@ version.workspace = true edition.workspace = true authors.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true +rust-version.workspace = true +keywords.workspace = true +categories.workspace = true +documentation = "http://docs.rs/adbc_snowflake/" +readme = "README.md" [features] default = ["bundled", "env", "dotenv"] diff --git a/rust/driver/snowflake/README.md b/rust/driver/snowflake/README.md index 194f0f9855..82f2b57790 100644 --- a/rust/driver/snowflake/README.md +++ b/rust/driver/snowflake/README.md @@ -17,4 +17,89 @@ under the License. --> +![logo](https://raw.githubusercontent.com/apache/arrow/refs/heads/main/docs/source/_static/favicon.ico) + +[![crates.io](https://img.shields.io/crates/v/adbc_snowflake.svg)](https://crates.io/crates/adbc_snowflake) +[![docs.rs](https://docs.rs/adbc_snowflake/badge.svg)](https://docs.rs/c) + # Snowflake driver for Arrow Database Connectivity (ADBC) + +A [Snowflake](https://www.snowflake.com) [ADBC](https://arrow.apache.org/adbc/) +driver, based on the +[ADBC Snowflake Go driver](https://github.com/apache/arrow-adbc/tree/main/go/adbc/driver/snowflake). + +## Example + +```rust +# #![doc(test(attr(test_with::env(ADBC_SNOWFLAKE_TESTS))))] +use adbc_core::{Connection, Statement}; +use adbc_snowflake::{connection, database, Driver}; +use arrow_array::{cast::AsArray, types::Decimal128Type}; + +# #[cfg(feature = "env")] +# fn main() -> Result<(), Box> { + +// Load the driver +let mut driver = Driver::try_load()?; + +// Construct a database using environment variables +let mut database = database::Builder::from_env().build(&mut driver)?; + +// Create a connection to the database +let mut connection = connection::Builder::from_env().build(&mut database)?; + +// Construct a statement to execute a query +let mut statement = connection.new_statement()?; + +// Execute a query +statement.set_sql_query("SELECT 21 + 21")?; +let mut reader = statement.execute()?; + +// Check the result +let batch = reader.next().expect("a record batch")?; +assert_eq!( + batch.column(0).as_primitive::().value(0), + 42 +); + +# Ok(()) } +# #[cfg(not(feature = "env"))] +# fn main() {} +``` + +## Crate features + +### Linking Go driver + +This crate is a wrapper around the Go driver. + +There are different methods to load the Go driver: + +#### `bundled` (default) + +Builds the driver from source and links it statically. This requires a Go +compiler to be available at build time. This is the default behavior. + +#### `linked` + +Link the driver at build time. This requires the driver library to be available +both at build- and runtime. Set `ADBC_SNOWFLAKE_GO_LIB_DIR` during the build to +add search paths for the linker. + +#### Runtime only + +It's also possible to build this crate without the driver and only link at +runtime. This requires disabling the `bundled` and `linked` features. Linking +at runtime is also available when the other features are enabled. + +### Configuration + +The crate provides builders that can be initialized from environment variables. + +#### `env` (default) + +Adds `from_env` methods to initialize builders from environment variables. + +#### `dotenv`: `env` (default) + +Loads environment variables from `.env` files in `from_env` methods. diff --git a/rust/driver/snowflake/src/builder.rs b/rust/driver/snowflake/src/builder.rs index 44a2b19a8f..766cb6beda 100644 --- a/rust/driver/snowflake/src/builder.rs +++ b/rust/driver/snowflake/src/builder.rs @@ -15,7 +15,8 @@ // specific language governing permissions and limitations // under the License. -//! Builder utility. +//! Builder utilities +//! //! use std::iter::{Chain, Flatten}; diff --git a/rust/driver/snowflake/src/connection.rs b/rust/driver/snowflake/src/connection.rs index 4aea39ccb3..222cf3b01a 100644 --- a/rust/driver/snowflake/src/connection.rs +++ b/rust/driver/snowflake/src/connection.rs @@ -15,6 +15,10 @@ // specific language governing permissions and limitations // under the License. +//! Snowflake ADBC Connection +//! +//! + use std::collections::HashSet; use adbc_core::{ diff --git a/rust/driver/snowflake/src/connection/builder.rs b/rust/driver/snowflake/src/connection/builder.rs index 3c229de31c..8b6f0e8570 100644 --- a/rust/driver/snowflake/src/connection/builder.rs +++ b/rust/driver/snowflake/src/connection/builder.rs @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -//! A builder for a [`Connection`]. +//! A builder for a [`Connection`] //! //! diff --git a/rust/driver/snowflake/src/database.rs b/rust/driver/snowflake/src/database.rs index ba497adb9d..006c208022 100644 --- a/rust/driver/snowflake/src/database.rs +++ b/rust/driver/snowflake/src/database.rs @@ -15,6 +15,10 @@ // specific language governing permissions and limitations // under the License. +//! Snowflake ADBC Database +//! +//! + use std::{collections::HashSet, ffi::c_int, sync::Arc}; use adbc_core::{ diff --git a/rust/driver/snowflake/src/database/builder.rs b/rust/driver/snowflake/src/database/builder.rs index d6ff8fdc5d..3279927bc2 100644 --- a/rust/driver/snowflake/src/database/builder.rs +++ b/rust/driver/snowflake/src/database/builder.rs @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -//! A builder for a [`Database`]. +//! A builder for a [`Database`] //! //! diff --git a/rust/driver/snowflake/src/driver.rs b/rust/driver/snowflake/src/driver.rs index 48b05fcfb0..840e1f7e80 100644 --- a/rust/driver/snowflake/src/driver.rs +++ b/rust/driver/snowflake/src/driver.rs @@ -15,6 +15,10 @@ // specific language governing permissions and limitations // under the License. +//! Snowflake ADBC Driver +//! +//! + #[cfg(any(feature = "bundled", feature = "linked"))] use std::ffi::{c_int, c_void}; use std::{fmt, sync::LazyLock}; @@ -74,9 +78,36 @@ impl Driver { /// or to load the configuration from environment variables use /// [`Builder::from_env`]. /// + /// If the crate was built without the `bundled` and `linked` features this + /// will attempt to dynamically load the driver. + /// /// # Error /// /// Returns an error when the driver fails to load. + /// + /// # Example + /// + /// ## Using the default ADBC version + /// + /// ```rust + /// # use adbc_core::error::Result; + /// # use adbc_snowflake::Driver; + /// # fn main() -> Result<()> { + /// let mut driver = Driver::try_load()?; + /// # Ok(()) } + /// ``` + /// + /// ## Using a different ADBC version + /// + /// ```rust + /// # use adbc_core::{error::Result, options::AdbcVersion}; + /// # use adbc_snowflake::{driver::Builder, Driver}; + /// # fn main() -> Result<()> { + /// let mut driver = Builder::default() + /// .with_adbc_version(AdbcVersion::V100) + /// .try_load()?; + /// # Ok(()) } + /// ``` pub fn try_load() -> Result { Self::try_new(Default::default()) } @@ -104,6 +135,20 @@ impl Driver { /// /// This attempts to load the `adbc_driver_snowflake` library using the /// default `AdbcVersion`. + /// + /// # Error + /// + /// Returns an error when the driver fails to load. + /// + /// # Example + /// + /// ```rust,ignore + /// # use adbc_core::error::Result; + /// # use adbc_snowflake::Driver; + /// # fn main() -> Result<()> { + /// let mut driver = Driver::try_load_dynamic()?; + /// # Ok(()) } + /// ``` pub fn try_load_dynamic() -> Result { Self::try_new_dynamic() } diff --git a/rust/driver/snowflake/src/driver/builder.rs b/rust/driver/snowflake/src/driver/builder.rs index 5c592cc236..d1137cc3e3 100644 --- a/rust/driver/snowflake/src/driver/builder.rs +++ b/rust/driver/snowflake/src/driver/builder.rs @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -//! A builder for [`Driver`]. +//! A builder for [`Driver`] //! //! diff --git a/rust/driver/snowflake/src/duration.rs b/rust/driver/snowflake/src/duration.rs index 15549f8421..642851e653 100644 --- a/rust/driver/snowflake/src/duration.rs +++ b/rust/driver/snowflake/src/duration.rs @@ -15,7 +15,8 @@ // specific language governing permissions and limitations // under the License. -//! A parser for [`Duration`] following . +//! A parser for [`Duration`] following +//! //! use std::{error::Error as StdError, num::IntErrorKind, sync::LazyLock, time::Duration}; diff --git a/rust/driver/snowflake/src/lib.rs b/rust/driver/snowflake/src/lib.rs index a3ff958631..9ce3b07659 100644 --- a/rust/driver/snowflake/src/lib.rs +++ b/rust/driver/snowflake/src/lib.rs @@ -15,35 +15,12 @@ // specific language governing permissions and limitations // under the License. -//! Snowflake ADBC driver, based on the Go driver. -//! -//! # Features -//! -//! ## Linking -//! -//! ### `bundled` (default) -//! -//! Builds the Go Snowflake driver from source and links it statically. This -//! requires a Go compiler to be installed. -//! -//! ### `linked` -//! -//! Link the Go Snowflake driver at build time. Set `ADBC_SNOWFLAKE_GO_LIB_DIR` -//! to add a search paths for the linker. -//! -//! ## Configuration -//! -//! ### `env` (default) -//! -//! Adds `from_env` methods to initialize builders from environment variables. -//! -//! ### `dotenv`: `env` (default) -//! -//! Loads environment variables from `.env` files in `from_env` methods. -//! -//! - #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/apache/arrow/refs/heads/main/docs/source/_static/favicon.ico", + html_favicon_url = "https://raw.githubusercontent.com/apache/arrow/refs/heads/main/docs/source/_static/favicon.ico" +)] +#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] pub mod driver; pub use driver::Driver; @@ -57,7 +34,7 @@ pub use connection::Connection; pub mod statement; pub use statement::Statement; -pub mod builder; +pub(crate) mod builder; #[cfg(feature = "env")] pub(crate) mod duration; diff --git a/rust/driver/snowflake/src/statement.rs b/rust/driver/snowflake/src/statement.rs index ed3d1cdb0c..34b83f09b7 100644 --- a/rust/driver/snowflake/src/statement.rs +++ b/rust/driver/snowflake/src/statement.rs @@ -15,6 +15,10 @@ // specific language governing permissions and limitations // under the License. +//! Snowflake ADBC Statement +//! +//! + use adbc_core::{ driver_manager::ManagedStatement, error::Result, From 029ccaef9d8d8bd0500865f6b8079c524634b31d Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 21 Nov 2024 12:29:47 +0100 Subject: [PATCH 20/20] Mark doctests that require a Snowflake account as `no_run` --- rust/driver/snowflake/README.md | 6 +----- rust/driver/snowflake/src/driver.rs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rust/driver/snowflake/README.md b/rust/driver/snowflake/README.md index 82f2b57790..5f8c143f0a 100644 --- a/rust/driver/snowflake/README.md +++ b/rust/driver/snowflake/README.md @@ -30,13 +30,11 @@ driver, based on the ## Example -```rust -# #![doc(test(attr(test_with::env(ADBC_SNOWFLAKE_TESTS))))] +```rust,no_run use adbc_core::{Connection, Statement}; use adbc_snowflake::{connection, database, Driver}; use arrow_array::{cast::AsArray, types::Decimal128Type}; -# #[cfg(feature = "env")] # fn main() -> Result<(), Box> { // Load the driver @@ -63,8 +61,6 @@ assert_eq!( ); # Ok(()) } -# #[cfg(not(feature = "env"))] -# fn main() {} ``` ## Crate features diff --git a/rust/driver/snowflake/src/driver.rs b/rust/driver/snowflake/src/driver.rs index 840e1f7e80..825cd61ae1 100644 --- a/rust/driver/snowflake/src/driver.rs +++ b/rust/driver/snowflake/src/driver.rs @@ -142,7 +142,7 @@ impl Driver { /// /// # Example /// - /// ```rust,ignore + /// ```rust,no_run /// # use adbc_core::error::Result; /// # use adbc_snowflake::Driver; /// # fn main() -> Result<()> {