From 8d65af192d31c127ae6e6710823051f5bfbe4ede Mon Sep 17 00:00:00 2001 From: Bryce Mecum Date: Tue, 27 Oct 2026 14:38:37 -0700 Subject: [PATCH 1/4] wip, add debugging test --- rust/driver_manager/src/search.rs | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/rust/driver_manager/src/search.rs b/rust/driver_manager/src/search.rs index 0573503b8c..01c2f5d2ed 100644 --- a/rust/driver_manager/src/search.rs +++ b/rust/driver_manager/src/search.rs @@ -1587,6 +1587,83 @@ mod tests { } } + /// Loading a driver that is not installed anywhere should return + /// NotFound on every platform. + /// + /// DEBUG: this test intentionally prints a lot of diagnostic output so we + /// can verify in CI what each platform actually returns. + #[test] + fn test_load_missing_driver_returns_not_found() { + let driver_name = "adbc_nonexistent_driver_for_not_found_test"; + + eprintln!("=== DEBUG test_load_missing_driver_returns_not_found ==="); + eprintln!("DEBUG target_os = {}", env::consts::OS); + eprintln!("DEBUG target_arch = {}", env::consts::ARCH); + eprintln!("DEBUG driver_name = {driver_name:?}"); + eprintln!( + "DEBUG ADBC_DRIVER_PATH = {:?}", + env::var_os("ADBC_DRIVER_PATH") + ); + eprintln!("DEBUG CONDA_PREFIX = {:?}", env::var_os("CONDA_PREFIX")); + eprintln!( + "DEBUG search paths (ENV) = {:?}", + get_search_paths(adbc_core::LOAD_FLAG_SEARCH_ENV) + ); + eprintln!( + "DEBUG search paths (USER) = {:?}", + get_search_paths(adbc_core::LOAD_FLAG_SEARCH_USER) + ); + eprintln!( + "DEBUG search paths (SYSTEM) = {:?}", + get_search_paths(adbc_core::LOAD_FLAG_SEARCH_SYSTEM) + ); + + let result = ManagedDriver::load_from_name( + driver_name, + None, + AdbcVersion::V110, + adbc_core::LOAD_FLAG_DEFAULT, + None, + ); + let err = match result { + Ok(_) => panic!("DEBUG unexpectedly loaded driver {driver_name:?}"), + Err(err) => err, + }; + + eprintln!("DEBUG err.status = {:?}", err.status); + eprintln!("DEBUG err.message = {:?}", err.message); + eprintln!("DEBUG err.vendor_code = {}", err.vendor_code); + eprintln!("DEBUG err.sqlstate = {:?}", err.sqlstate); + eprintln!("DEBUG err (Display) = {err}"); + match &err.details { + None => eprintln!("DEBUG err.details = None"), + Some(details) => { + eprintln!("DEBUG err.details has {} entries", details.len()); + for (key, value) in details { + eprintln!("DEBUG detail key = {key:?}"); + for line in String::from_utf8_lossy(value).lines() { + eprintln!("DEBUG | {line}"); + } + } + } + } + eprintln!("=== END DEBUG ==="); + + assert_eq!( + err.status, + Status::NotFound, + "expected NotFound for a missing driver on {}, got {:?}: {}", + env::consts::OS, + err.status, + err.message + ); + assert!( + err.message.contains("Driver not found"), + "unexpected message: {}", + err.message + ); + } + #[test] fn test_parse_driver_uri() { let cases = vec![ From acfa11858b38819fd8072aeadbb8dbaf02d061eb Mon Sep 17 00:00:00 2001 From: Bryce Mecum Date: Tue, 27 Oct 2026 14:50:44 -0700 Subject: [PATCH 2/4] Update search.rs --- rust/driver_manager/src/search.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/rust/driver_manager/src/search.rs b/rust/driver_manager/src/search.rs index 01c2f5d2ed..a2d9b7e24d 100644 --- a/rust/driver_manager/src/search.rs +++ b/rust/driver_manager/src/search.rs @@ -522,9 +522,15 @@ impl<'a> DriverLibrary<'a> { } let driver_name = driver_path.as_os_str().to_string_lossy().into_owned(); - let library = DriverLibrary::load_library_from_name(driver_name)?; - Ok(SearchHit::new(driver_path.to_path_buf(), library, None)) - // XXX: should we return NotFound like the non-Windows version? + match DriverLibrary::load_library_from_name(driver_name) { + Ok(library) => return Ok(SearchHit::new(driver_path.to_path_buf(), library, None)), + Err(err) => trace.push(err), + } + + Err(Error::with_message_and_status( + format!("Driver not found: {}", driver_path.display()), + Status::NotFound, + )) } #[cfg(not(windows))] @@ -1662,6 +1668,23 @@ mod tests { "unexpected message: {}", err.message ); + + // The underlying dynamic library load error must be preserved in the + // load trace rather than discarded. + let trace = err + .details + .as_ref() + .and_then(|details| { + details + .iter() + .find(|(key, _)| key == ERR_DETAIL_DRIVER_LOAD_TRACE) + }) + .map(|(_, value)| String::from_utf8_lossy(value).into_owned()) + .expect("expected a driver load trace in error details"); + assert!( + trace.contains("Error with dynamic library"), + "expected the dynamic library load error in the trace, got:\n{trace}" + ); } #[test] From 838fe4c98f5781db813df366643a27f62d312d85 Mon Sep 17 00:00:00 2001 From: Bryce Mecum Date: Tue, 27 Oct 2026 15:03:20 -0700 Subject: [PATCH 3/4] Update search.rs --- rust/driver_manager/src/search.rs | 121 ++++-------------------------- 1 file changed, 15 insertions(+), 106 deletions(-) diff --git a/rust/driver_manager/src/search.rs b/rust/driver_manager/src/search.rs index a2d9b7e24d..248a8eb73d 100644 --- a/rust/driver_manager/src/search.rs +++ b/rust/driver_manager/src/search.rs @@ -522,15 +522,9 @@ impl<'a> DriverLibrary<'a> { } let driver_name = driver_path.as_os_str().to_string_lossy().into_owned(); - match DriverLibrary::load_library_from_name(driver_name) { - Ok(library) => return Ok(SearchHit::new(driver_path.to_path_buf(), library, None)), - Err(err) => trace.push(err), - } - - Err(Error::with_message_and_status( - format!("Driver not found: {}", driver_path.display()), - Status::NotFound, - )) + let library = DriverLibrary::load_library_from_name(driver_name)?; + Ok(SearchHit::new(driver_path.to_path_buf(), library, None)) + // XXX: should we return NotFound like the non-Windows version? } #[cfg(not(windows))] @@ -1593,100 +1587,6 @@ mod tests { } } - /// Loading a driver that is not installed anywhere should return - /// NotFound on every platform. - /// - /// DEBUG: this test intentionally prints a lot of diagnostic output so we - /// can verify in CI what each platform actually returns. - #[test] - fn test_load_missing_driver_returns_not_found() { - let driver_name = "adbc_nonexistent_driver_for_not_found_test"; - - eprintln!("=== DEBUG test_load_missing_driver_returns_not_found ==="); - eprintln!("DEBUG target_os = {}", env::consts::OS); - eprintln!("DEBUG target_arch = {}", env::consts::ARCH); - eprintln!("DEBUG driver_name = {driver_name:?}"); - eprintln!( - "DEBUG ADBC_DRIVER_PATH = {:?}", - env::var_os("ADBC_DRIVER_PATH") - ); - eprintln!("DEBUG CONDA_PREFIX = {:?}", env::var_os("CONDA_PREFIX")); - eprintln!( - "DEBUG search paths (ENV) = {:?}", - get_search_paths(adbc_core::LOAD_FLAG_SEARCH_ENV) - ); - eprintln!( - "DEBUG search paths (USER) = {:?}", - get_search_paths(adbc_core::LOAD_FLAG_SEARCH_USER) - ); - eprintln!( - "DEBUG search paths (SYSTEM) = {:?}", - get_search_paths(adbc_core::LOAD_FLAG_SEARCH_SYSTEM) - ); - - let result = ManagedDriver::load_from_name( - driver_name, - None, - AdbcVersion::V110, - adbc_core::LOAD_FLAG_DEFAULT, - None, - ); - let err = match result { - Ok(_) => panic!("DEBUG unexpectedly loaded driver {driver_name:?}"), - Err(err) => err, - }; - - eprintln!("DEBUG err.status = {:?}", err.status); - eprintln!("DEBUG err.message = {:?}", err.message); - eprintln!("DEBUG err.vendor_code = {}", err.vendor_code); - eprintln!("DEBUG err.sqlstate = {:?}", err.sqlstate); - eprintln!("DEBUG err (Display) = {err}"); - match &err.details { - None => eprintln!("DEBUG err.details = None"), - Some(details) => { - eprintln!("DEBUG err.details has {} entries", details.len()); - for (key, value) in details { - eprintln!("DEBUG detail key = {key:?}"); - for line in String::from_utf8_lossy(value).lines() { - eprintln!("DEBUG | {line}"); - } - } - } - } - eprintln!("=== END DEBUG ==="); - - assert_eq!( - err.status, - Status::NotFound, - "expected NotFound for a missing driver on {}, got {:?}: {}", - env::consts::OS, - err.status, - err.message - ); - assert!( - err.message.contains("Driver not found"), - "unexpected message: {}", - err.message - ); - - // The underlying dynamic library load error must be preserved in the - // load trace rather than discarded. - let trace = err - .details - .as_ref() - .and_then(|details| { - details - .iter() - .find(|(key, _)| key == ERR_DETAIL_DRIVER_LOAD_TRACE) - }) - .map(|(_, value)| String::from_utf8_lossy(value).into_owned()) - .expect("expected a driver load trace in error details"); - assert!( - trace.contains("Error with dynamic library"), - "expected the dynamic library load error in the trace, got:\n{trace}" - ); - } - #[test] fn test_parse_driver_uri() { let cases = vec![ @@ -1751,7 +1651,7 @@ mod tests { } #[test] - fn test_load_from_name_includes_search_trace_in_error_details() { + fn test_load_from_name_missing_driver() { let err = ManagedDriver::load_from_name( "adbc_test_driver_manager_missing_driver_7c8f5482", None, @@ -1761,6 +1661,13 @@ mod tests { ) .unwrap_err(); + assert_eq!(err.status, Status::NotFound, "{}", err.message); + assert!( + err.message.contains("Driver not found"), + "Unexpected error message: {}", + err.message + ); + let details = err .details .expect("Expected load-from-name errors to include details"); @@ -1768,9 +1675,11 @@ mod tests { .iter() .find(|(key, _)| key == "adbc.drivermanager.driver_load_trace") .expect("Expected driver load trace in error details"); + // The underlying dynamic library error must be kept in the trace + let trace = String::from_utf8_lossy(&trace.1); assert!( - !trace.1.is_empty(), - "Expected driver load trace detail to be non-empty" + trace.contains("Error with dynamic library"), + "Expected dynamic library load error in driver load trace, got:\n{trace}" ); } From 2cecb13e37c67b71bc6d462eefd8909c82be96e3 Mon Sep 17 00:00:00 2001 From: Bryce Mecum Date: Tue, 27 Oct 2026 15:14:16 -0700 Subject: [PATCH 4/4] clean up and fix --- javascript/__test__/error_handling.spec.ts | 12 ++++++++++++ rust/driver_manager/src/search.rs | 12 +++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/javascript/__test__/error_handling.spec.ts b/javascript/__test__/error_handling.spec.ts index 980099b206..61f1cabbe7 100644 --- a/javascript/__test__/error_handling.spec.ts +++ b/javascript/__test__/error_handling.spec.ts @@ -190,3 +190,15 @@ test('error: conn.queryStream() error during iteration throws AdbcError', async assert.ok(error instanceof AdbcError) assert.match((error as AdbcError).message, /no such table/i) }) + +test('error: missing driver throws NotFound', () => { + assert.throws( + () => new AdbcDatabase({ driver: 'adbc_test_driver_manager_missing_driver_7c8f5482' }), + (e: unknown) => { + assert.ok(e instanceof AdbcError) + assert.strictEqual(e.code, 'NotFound', e.message) + assert.match(e.message, /Driver not found/) + return true + }, + ) +}) diff --git a/rust/driver_manager/src/search.rs b/rust/driver_manager/src/search.rs index 248a8eb73d..8b2c2c6b1a 100644 --- a/rust/driver_manager/src/search.rs +++ b/rust/driver_manager/src/search.rs @@ -522,9 +522,15 @@ impl<'a> DriverLibrary<'a> { } let driver_name = driver_path.as_os_str().to_string_lossy().into_owned(); - let library = DriverLibrary::load_library_from_name(driver_name)?; - Ok(SearchHit::new(driver_path.to_path_buf(), library, None)) - // XXX: should we return NotFound like the non-Windows version? + match DriverLibrary::load_library_from_name(driver_name) { + Ok(library) => return Ok(SearchHit::new(driver_path.to_path_buf(), library, None)), + Err(err) => trace.push(err), + } + + Err(Error::with_message_and_status( + format!("Driver not found: {}", driver_path.display()), + Status::NotFound, + )) } #[cfg(not(windows))]