diff --git a/csharp/src/Apache.Arrow.Adbc/C/CAdbcDriverImporter.cs b/csharp/src/Apache.Arrow.Adbc/C/CAdbcDriverImporter.cs
index 19b85e123a..57e96ef721 100644
--- a/csharp/src/Apache.Arrow.Adbc/C/CAdbcDriverImporter.cs
+++ b/csharp/src/Apache.Arrow.Adbc/C/CAdbcDriverImporter.cs
@@ -79,7 +79,9 @@ private static AdbcDriver Load(
IntPtr library = NativeLibrary.Load(file);
if (library == IntPtr.Zero)
{
- throw new ArgumentException("unable to load library", nameof(file));
+ // Only reachable with the netstandard2.0 NativeLibrary shim; the
+ // runtime's NativeLibrary.Load throws DllNotFoundException itself.
+ throw new DllNotFoundException($"Unable to load shared library '{file}'.");
}
try
diff --git a/csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs b/csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs
index 3ebfc3bfc8..8eb2df3be8 100644
--- a/csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs
+++ b/csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs
@@ -134,12 +134,42 @@ private static AdbcDriver LoadNativeDriver(string driverPath, string? entrypoint
typeName: null,
manifestPath: null,
loadMethod: loadMethod,
- () => entrypoint == null
- ? CAdbcDriverImporter.LoadWithFallback(
- driverPath,
- resolvedEntrypoint,
- DefaultNativeEntrypoint)
- : CAdbcDriverImporter.Load(driverPath, resolvedEntrypoint));
+ () => ImportNativeDriver(
+ driverPath,
+ () => entrypoint == null
+ ? CAdbcDriverImporter.LoadWithFallback(
+ driverPath,
+ resolvedEntrypoint,
+ DefaultNativeEntrypoint)
+ : CAdbcDriverImporter.Load(driverPath, resolvedEntrypoint)));
+ }
+
+ ///
+ /// Runs a native driver import, reporting a library that is missing or
+ /// cannot be loaded as to match the
+ /// C/C++ and Rust driver managers. The underlying load error is kept as
+ /// the inner exception.
+ ///
+ private static AdbcDriver ImportNativeDriver(string driverPath, Func import)
+ {
+ if (!File.Exists(driverPath))
+ {
+ throw new AdbcException(
+ $"Driver library file not found: '{driverPath}'.",
+ AdbcStatusCode.NotFound);
+ }
+
+ try
+ {
+ return import();
+ }
+ catch (Exception ex) when (ex is DllNotFoundException || ex is BadImageFormatException)
+ {
+ throw new AdbcException(
+ $"Could not load driver library '{driverPath}': {ex.Message}",
+ AdbcStatusCode.NotFound,
+ ex);
+ }
}
// -----------------------------------------------------------------------
@@ -853,11 +883,13 @@ private static AdbcDriver LoadFromAbsolutePath(string path, string? entrypoint)
private static AdbcDriver LoadFromManifest(string manifestPath, string? entrypoint)
{
+ // A manifest that can't be read is an invalid argument, as in the
+ // C/C++ and Rust driver managers
if (!File.Exists(manifestPath))
{
throw new AdbcException(
- $"Driver manifest file not found.",
- AdbcStatusCode.NotFound);
+ $"Driver manifest file not found: '{manifestPath}'.",
+ AdbcStatusCode.InvalidArgument);
}
DriverManifest manifest = DriverManifest.LoadFromFile(manifestPath);
@@ -948,12 +980,14 @@ private static AdbcDriver LoadByEntrypointScheme(
typeName: null,
manifestPath: manifestPath,
loadMethod: loadMethod,
- () => allowNativeFallback
- ? CAdbcDriverImporter.LoadWithFallback(
- driverPath,
- entrypoint,
- DefaultNativeEntrypoint)
- : CAdbcDriverImporter.Load(driverPath, entrypoint));
+ () => ImportNativeDriver(
+ driverPath,
+ () => allowNativeFallback
+ ? CAdbcDriverImporter.LoadWithFallback(
+ driverPath,
+ entrypoint,
+ DefaultNativeEntrypoint)
+ : CAdbcDriverImporter.Load(driverPath, entrypoint)));
}
///
@@ -997,8 +1031,9 @@ private static void EnsureRuntime(bool isNetFramework, string scheme)
// 2. Try native library extensions. If a matching file exists but fails
// to load (e.g., corrupt binary, wrong architecture, missing entrypoint),
- // surface that concrete error rather than silently degrading to a generic
- // NotFound -- the file is clearly the user's intended driver.
+ // stop here rather than trying other directories -- the file is clearly
+ // the user's intended driver. A library that cannot be loaded is reported
+ // as NotFound with the concrete error attached (see ImportNativeDriver).
foreach (string nativeExt in GetPlatformExtensions())
{
string libPath = Path.Combine(dir, driverName + nativeExt);
diff --git a/csharp/test/Apache.Arrow.Adbc.Tests/DriverManager/DriverNotFoundTests.cs b/csharp/test/Apache.Arrow.Adbc.Tests/DriverManager/DriverNotFoundTests.cs
new file mode 100644
index 0000000000..f57a8a047a
--- /dev/null
+++ b/csharp/test/Apache.Arrow.Adbc.Tests/DriverManager/DriverNotFoundTests.cs
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using Apache.Arrow.Adbc.DriverManager;
+using Xunit;
+
+namespace Apache.Arrow.Adbc.Tests.DriverManager
+{
+ ///
+ /// A driver that does not exist should be reported as an
+ /// with
+ /// no matter how it was specified or which search locations are enabled.
+ /// A library file that exists but cannot be loaded is also reported as
+ /// , with the load error attached,
+ /// matching the C/C++ driver manager. A manifest file that doesn't exist
+ /// is reported as .
+ ///
+ [Collection(DriverManagerSecurityCollection.Name)]
+ public class DriverNotFoundTests : IDisposable
+ {
+ private const string MissingDriverName = "adbc_test_driver_manager_missing_driver_7c8f5482";
+
+ private readonly List _tempDirs = new List();
+
+ public void Dispose()
+ {
+ foreach (string d in _tempDirs)
+ {
+ try { if (Directory.Exists(d)) Directory.Delete(d, true); } catch { }
+ }
+ }
+
+ public static IEnumerable