diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index 16d56343..b4cf414e 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -38,7 +38,7 @@ jobs: name: Download duckdb with: repository: "duckdb/duckdb" - tag: "v1.1.0" + tag: "v1.1.1" fileName: ${{ matrix.duckdb }} out-file-path: . diff --git a/Cargo.toml b/Cargo.toml index dde285f2..68412b25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ ] [workspace.package] -version = "1.1.0" +version = "1.1.1" authors = ["wangfenjin "] edition = "2021" repository = "https://github.com/duckdb/duckdb-rs" @@ -19,8 +19,8 @@ license = "MIT" categories = ["database"] [workspace.dependencies] -duckdb = { version = "1.1.0", path = "crates/duckdb" } -libduckdb-sys = { version = "1.1.0", path = "crates/libduckdb-sys" } +duckdb = { version = "1.1.1", path = "crates/duckdb" } +libduckdb-sys = { version = "1.1.1", path = "crates/libduckdb-sys" } duckdb-loadable-macros = { version = "0.1.2", path = "crates/duckdb-loadable-macros" } autocfg = "1.0" bindgen = { version = "0.69", default-features = false } diff --git a/crates/duckdb-loadable-macros/src/lib.rs b/crates/duckdb-loadable-macros/src/lib.rs index d8099d20..3a7e7533 100644 --- a/crates/duckdb-loadable-macros/src/lib.rs +++ b/crates/duckdb-loadable-macros/src/lib.rs @@ -51,24 +51,49 @@ pub fn duckdb_entrypoint_c_api(attr: TokenStream, item: TokenStream) -> TokenStr let c_entrypoint = Ident::new(format!("{}_init_c_api", args.ext_name).as_str(), Span::call_site()); let original_funcname = func.sig.ident.to_string(); let prefixed_original_function = func.sig.ident.clone(); + let c_entrypoint_internal = Ident::new(format!("{}_init_c_api_internal", args.ext_name).as_str(), Span::call_site()); quote_spanned! {func.span()=> + pub unsafe fn #c_entrypoint_internal(info: ffi::duckdb_extension_info, access: *const ffi::duckdb_extension_access) -> Result> { + let have_api_struct = ffi::duckdb_rs_extension_api_init(info, access, #minimum_duckdb_version).unwrap(); + + if !have_api_struct { + // initialization failed to return an api struct, likely due to an API version mismatch, we can simply return here + return Ok(false); + } + + // TODO: handle error here? + let db : ffi::duckdb_database = *(*access).get_database.unwrap()(info); + let connection = Connection::open_from_raw(db.cast())?; + + #prefixed_original_function(connection)?; + + return Ok(true); + } /// # Safety /// - /// Will be called by duckdb + /// Entrypoint that will be called by DuckDB #[no_mangle] - pub unsafe extern "C" fn #c_entrypoint(info: ffi::duckdb_extension_info, access: *const ffi::duckdb_extension_access) { - let res = ffi::duckdb_rs_extension_api_init(info, access, #minimum_duckdb_version); - - if let Err(x) = res { - // Error will be handled by DuckDB - return; + pub unsafe extern "C" fn #c_entrypoint(info: ffi::duckdb_extension_info, access: *const ffi::duckdb_extension_access) -> bool { + let init_result = #c_entrypoint_internal(info, access); + + if let Err(x) = init_result { + let error_c_string = std::ffi::CString::new(x.description()); + + match error_c_string { + Ok(e) => { + (*access).set_error.unwrap()(info, e.as_ptr()); + }, + Err(e) => { + let error_alloc_failure = c"An error occured but the extension failed to allocate memory for an error string"; + (*access).set_error.unwrap()(info, error_alloc_failure.as_ptr()); + } + } + return false; } - let db : ffi::duckdb_database = *(*access).get_database.unwrap()(info); - let connection = Connection::open_from_raw(db.cast()).expect("can't open db connection"); - #prefixed_original_function(connection).expect("init failed"); + return init_result.unwrap(); } #func diff --git a/crates/duckdb/Cargo.toml b/crates/duckdb/Cargo.toml index 34d61b92..1c1832ec 100644 --- a/crates/duckdb/Cargo.toml +++ b/crates/duckdb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "duckdb" -version = "1.1.0" +version = "1.1.1" authors.workspace = true edition.workspace = true repository.workspace = true diff --git a/crates/duckdb/examples/hello-ext-capi/main.rs b/crates/duckdb/examples/hello-ext-capi/main.rs index 8c925e41..a20a619c 100644 --- a/crates/duckdb/examples/hello-ext-capi/main.rs +++ b/crates/duckdb/examples/hello-ext-capi/main.rs @@ -11,7 +11,7 @@ use duckdb_loadable_macros::duckdb_entrypoint_c_api; use libduckdb_sys as ffi; use std::{ error::Error, - ffi::{c_char, c_void, CString}, + ffi::{c_char, CString}, }; #[repr(C)] @@ -87,6 +87,7 @@ impl VTab for HelloVTab { #[duckdb_entrypoint_c_api(ext_name = "rusty_quack", min_duckdb_version = "v0.0.1")] pub unsafe fn ExtensionEntrypoint(con: Connection) -> Result<(), Box> { + return Err("SHIT THIS THE FAN request".into()); con.register_table_function::("hello") .expect("Failed to register hello table function"); Ok(()) diff --git a/crates/duckdb/src/appender/mod.rs b/crates/duckdb/src/appender/mod.rs index 488db82f..96d176c4 100644 --- a/crates/duckdb/src/appender/mod.rs +++ b/crates/duckdb/src/appender/mod.rs @@ -299,7 +299,7 @@ mod test { let mut appender = conn.appender("foo")?; match appender.append_row(["foo"]) { Err(crate::Error::DuckDBFailure(.., Some(msg))) => { - assert_eq!(msg, "Call to EndRow before all rows have been appended to!") + assert_eq!(msg, "Call to EndRow before all columns have been appended to!") } _ => panic!("expected error"), } diff --git a/crates/libduckdb-sys/Cargo.toml b/crates/libduckdb-sys/Cargo.toml index ee5609bf..513f586d 100644 --- a/crates/libduckdb-sys/Cargo.toml +++ b/crates/libduckdb-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libduckdb-sys" -version = "1.1.0" +version = "1.1.1" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/libduckdb-sys/build.rs b/crates/libduckdb-sys/build.rs index 84f03467..649c834f 100644 --- a/crates/libduckdb-sys/build.rs +++ b/crates/libduckdb-sys/build.rs @@ -431,14 +431,16 @@ mod bindings { // (3) generate rust code similar to DUCKDB_EXTENSION_API_INIT macro let tokens = quote::quote! { /// Like DUCKDB_EXTENSION_API_INIT macro - pub unsafe fn duckdb_rs_extension_api_init(info: duckdb_extension_info, access: *const duckdb_extension_access, version: &str) -> ::std::result::Result<(), &'static str> { + pub unsafe fn duckdb_rs_extension_api_init(info: duckdb_extension_info, access: *const duckdb_extension_access, version: &str) -> ::std::result::Result { let version_c_string = std::ffi::CString::new(version).unwrap(); let #p_api = (*access).get_api.unwrap()(info, version_c_string.as_ptr()) as *const duckdb_ext_api_v0; if #p_api.is_null() { - return Err("DuckDB passed a nullpointer while trying to initialize the extension"); + // get_api can return a nullptr when the version is not matched. In this case, we don't need to set + // an error, but can instead just stop the initialization process and let duckdb handle things + return Ok(false); } #(#stores)* - Ok(()) + Ok(true) } }; output.push_str(&prettyplease::unparse( diff --git a/crates/libduckdb-sys/duckdb-sources b/crates/libduckdb-sys/duckdb-sources index fa5c2fe1..af39bd0d 160000 --- a/crates/libduckdb-sys/duckdb-sources +++ b/crates/libduckdb-sys/duckdb-sources @@ -1 +1 @@ -Subproject commit fa5c2fe15f3da5f32397b009196c0895fce60820 +Subproject commit af39bd0dcf66876e09ac2a7c3baa28fe1b301151 diff --git a/crates/libduckdb-sys/duckdb.tar.gz b/crates/libduckdb-sys/duckdb.tar.gz index 3395296b..9e377593 100644 Binary files a/crates/libduckdb-sys/duckdb.tar.gz and b/crates/libduckdb-sys/duckdb.tar.gz differ diff --git a/crates/libduckdb-sys/src/bindgen_bundled_version.rs b/crates/libduckdb-sys/src/bindgen_bundled_version.rs index 25dc763c..d9ef9226 100644 --- a/crates/libduckdb-sys/src/bindgen_bundled_version.rs +++ b/crates/libduckdb-sys/src/bindgen_bundled_version.rs @@ -672,6 +672,7 @@ pub const DUCKDB_TYPE_DUCKDB_TYPE_TIME_TZ: DUCKDB_TYPE = 30; pub const DUCKDB_TYPE_DUCKDB_TYPE_TIMESTAMP_TZ: DUCKDB_TYPE = 31; pub const DUCKDB_TYPE_DUCKDB_TYPE_ANY: DUCKDB_TYPE = 34; pub const DUCKDB_TYPE_DUCKDB_TYPE_VARINT: DUCKDB_TYPE = 35; +pub const DUCKDB_TYPE_DUCKDB_TYPE_SQLNULL: DUCKDB_TYPE = 36; #[doc = "! An enum over DuckDB's internal types."] pub type DUCKDB_TYPE = ::std::os::raw::c_uint; #[doc = "! An enum over DuckDB's internal types."] diff --git a/crates/libduckdb-sys/src/bindgen_bundled_version_loadable.rs b/crates/libduckdb-sys/src/bindgen_bundled_version_loadable.rs index df2652d3..f6de8faa 100644 --- a/crates/libduckdb-sys/src/bindgen_bundled_version_loadable.rs +++ b/crates/libduckdb-sys/src/bindgen_bundled_version_loadable.rs @@ -675,6 +675,7 @@ pub const DUCKDB_TYPE_DUCKDB_TYPE_TIME_TZ: DUCKDB_TYPE = 30; pub const DUCKDB_TYPE_DUCKDB_TYPE_TIMESTAMP_TZ: DUCKDB_TYPE = 31; pub const DUCKDB_TYPE_DUCKDB_TYPE_ANY: DUCKDB_TYPE = 34; pub const DUCKDB_TYPE_DUCKDB_TYPE_VARINT: DUCKDB_TYPE = 35; +pub const DUCKDB_TYPE_DUCKDB_TYPE_SQLNULL: DUCKDB_TYPE = 36; #[doc = "! An enum over DuckDB's internal types."] pub type DUCKDB_TYPE = ::std::os::raw::c_uint; #[doc = "! An enum over DuckDB's internal types."] @@ -14026,14 +14027,12 @@ pub unsafe fn duckdb_rs_extension_api_init( info: duckdb_extension_info, access: *const duckdb_extension_access, version: &str, -) -> ::std::result::Result<(), &'static str> { +) -> ::std::result::Result { let version_c_string = std::ffi::CString::new(version).unwrap(); let p_api = (*access).get_api.unwrap()(info, version_c_string.as_ptr()) as *const duckdb_ext_api_v0; if p_api.is_null() { - return Err( - "DuckDB passed a nullpointer while trying to initialize the extension", - ); + return Ok(false); } if let Some(fun) = (*p_api).duckdb_open { __DUCKDB_OPEN @@ -15519,6 +15518,6 @@ pub unsafe fn duckdb_rs_extension_api_init( __DUCKDB_STREAM_FETCH_CHUNK .store(fun as usize as *mut (), ::std::sync::atomic::Ordering::Release); } - Ok(()) + Ok(true) } diff --git a/crates/libduckdb-sys/upgrade.sh b/crates/libduckdb-sys/upgrade.sh index ff47f343..ba4ea2a2 100755 --- a/crates/libduckdb-sys/upgrade.sh +++ b/crates/libduckdb-sys/upgrade.sh @@ -12,8 +12,7 @@ mkdir -p "$SCRIPT_DIR/../../target" "$SCRIPT_DIR/duckdb" export DUCKDB_LIB_DIR="$SCRIPT_DIR/duckdb" # Download and extract amalgamation -# todo: fix this version -DUCKDB_VERSION=v1.1.0 +DUCKDB_VERSION=v1.1.1 git submodule update --init --checkout cd "$SCRIPT_DIR/duckdb-sources" git fetch