CurtHagenlocher commented on code in PR #4075:
URL: https://github.com/apache/arrow-adbc/pull/4075#discussion_r3249482111


##########
csharp/test/Apache.Arrow.Adbc.Tests/Apache.Arrow.Adbc.Testing.csproj:
##########
@@ -1,12 +1,19 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks 
Condition="'$(IsWindows)'=='true'">net8.0;net472</TargetFrameworks>
-    <TargetFrameworks 
Condition="'$(TargetFrameworks)'==''">net8.0</TargetFrameworks>
+    <TargetFrameworks 
Condition="'$(IsWindows)'=='true'">net8.0;net10.0;net472</TargetFrameworks>
+    <TargetFrameworks 
Condition="'$(TargetFrameworks)'==''">net8.0;net10.0</TargetFrameworks>
     <IsPackable>true</IsPackable>
     <IsTestProject>true</IsTestProject>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     
<ProcessArchitecture>$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant())</ProcessArchitecture>
+    <!--
+      net10's NuGet audit elevates known vulnerabilities of transitive 
packages to errors.
+      The OpenTelemetry.Api 1.12.0 advisory (GHSA-g94r-2vxg-569j) is pulled in 
transitively

Review Comment:
   o.0



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/ManagedDriverLoader.cs:
##########
@@ -0,0 +1,172 @@
+/*
+ * 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.Concurrent;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Loader;
+#endif
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Provides cross-platform assembly loading functionality for managed 
ADBC drivers.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This type abstracts the differences in assembly loading between .NET 
Framework
+    /// (which uses Fusion / <c>LoadFrom</c> probing) and modern .NET (which 
uses
+    /// <c>AssemblyLoadContext</c> and <c>.deps.json</c>-driven resolution).
+    /// </para>
+    /// <para>
+    /// <b>Dependency resolution on .NET Framework (net472, netstandard2.0 
build):</b>
+    /// <see cref="Assembly.LoadFrom(string)"/> probes the assembly's 
directory for
+    /// dependencies. Drop the driver assembly and all of its dependencies in 
the same
+    /// directory and they will be found.
+    /// </para>
+    /// <para>
+    /// <b>Dependency resolution on .NET 6 / .NET 8 / .NET 10:</b>
+    /// </para>
+    /// <list type="bullet">
+    ///   <item>
+    ///     <description>
+    ///       The driver assembly is loaded with <see 
cref="Assembly.LoadFrom(string)"/>
+    ///       into <see cref="AssemblyLoadContext.Default"/>. This is 
intentional: it keeps
+    ///       a single identity for <c>Apache.Arrow.Adbc.AdbcDriver</c> across 
the host
+    ///       and the driver so that <c>IsAssignableFrom</c> checks work 
correctly.
+    ///     </description>
+    ///   </item>
+    ///   <item>
+    ///     <description>
+    ///       Loading into the default context means the <b>host's</b> 
<c>.deps.json</c>
+    ///       drives resolution, not the driver's. Dependencies that are not 
already known
+    ///       to the host will not be found by default. To bridge that gap, 
this loader
+    ///       registers an <see cref="AssemblyDependencyResolver"/> for each 
driver
+    ///       assembly and attaches a single
+    ///       <see cref="AssemblyLoadContext.Resolving"/> handler to
+    ///       <see cref="AssemblyLoadContext.Default"/>. When the runtime 
fails to resolve
+    ///       a dependency, the handler consults each registered driver's 
resolver, which
+    ///       reads the driver's <c>.deps.json</c> next to it on disk.
+    ///     </description>
+    ///   </item>
+    ///   <item>
+    ///     <description>
+    ///       Drivers should be published with their <c>.deps.json</c> file 
alongside the
+    ///       assembly (the default when building with the .NET SDK). Native 
dependencies
+    ///       should follow the standard <c>runtimes/&lt;rid&gt;/native</c> 
layout.
+    ///     </description>
+    ///   </item>
+    ///   <item>
+    ///     <description>
+    ///       If a driver does not ship a <c>.deps.json</c>, the loader still 
works but

Review Comment:
   In my experience, loading a driver without a `.deps.json` file did not 
generally work. Has it worked for you?



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs:
##########
@@ -0,0 +1,787 @@
+/*
+ * 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.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+#endif
+using Apache.Arrow.Adbc.C;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Provides methods to locate and load ADBC drivers, optionally using 
TOML manifest
+    /// files and connection profiles.
+    /// Mirrors the free functions declared in <c>adbc_driver_manager.h</c>:
+    /// <c>AdbcLoadDriver</c> and <c>AdbcFindLoadDriver</c>.
+    /// </summary>
+    public static class AdbcDriverManager
+    {
+        /// <summary>
+        /// The environment variable that specifies additional driver search 
paths.
+        /// </summary>
+        public const string DriverPathEnvVar = "ADBC_DRIVER_PATH";
+
+        private static readonly string[] s_nativeExtensions = { ".so", ".dll", 
".dylib" };
+
+        // 
-----------------------------------------------------------------------
+        // AdbcLoadDriver – load a driver directly from an absolute or 
relative path
+        // 
-----------------------------------------------------------------------
+
+        /// <summary>
+        /// Loads an ADBC driver from an explicit file path.
+        /// Mirrors <c>AdbcLoadDriver</c> in <c>adbc_driver_manager.h</c>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// If a TOML manifest file with the same base name exists in the same 
directory
+        /// as the driver file, it will be automatically detected and used. 
For example,
+        /// loading <c>libadbc_driver_snowflake.dll</c> will automatically use
+        /// <c>libadbc_driver_snowflake.toml</c> if present.
+        /// </para>
+        /// <para>
+        /// The co-located manifest can specify default options, override the 
driver path,
+        /// or provide additional metadata. The <paramref name="entrypoint"/> 
parameter
+        /// always takes precedence over any entrypoint derived from the 
manifest or filename.
+        /// </para>
+        /// </remarks>
+        /// <param name="driverPath">
+        /// The absolute or relative path to the driver shared library.
+        /// </param>
+        /// <param name="entrypoint">
+        /// The symbol name of the driver initialisation function. When 
<c>null</c> the

Review Comment:
   total nit: we have one instance of the American spelling `initialization` 
and two instances of the British spelling `initialisation`. My desire for 
consistency is warring with my desire for cultural inclusiveness, and my spell 
checker definitely has feelings.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/TomlConnectionProfile.cs:
##########
@@ -0,0 +1,269 @@
+/*
+ * 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.Globalization;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// An <see cref="IConnectionProfile"/> loaded from a TOML file.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// The expected file format for profiles is:
+    /// </para>
+    /// <code>
+    /// profile_version = 1
+    /// driver = "driver_name"
+    ///
+    /// [Options]
+    /// option1 = "value1"
+    /// option2 = 42
+    /// option3 = 3.14
+    /// </code>
+    /// <para>
+    /// For backward compatibility, the following legacy field names are also 
supported:
+    /// </para>
+    /// <list type="bullet">
+    ///   <item><c>version</c> (use <c>profile_version</c> instead)</item>
+    ///   <item><c>[options]</c> section (use <c>[Options]</c> instead)</item>
+    /// </list>
+    /// <para>
+    /// Boolean option values are converted to the string equivalents 
<c>"true"</c> or
+    /// <c>"false"</c> and placed in <see cref="StringOptions"/>.
+    /// Integer values are placed in <see cref="IntOptions"/> and double 
values in
+    /// <see cref="DoubleOptions"/>.
+    /// Values of the form <c>env_var(ENV_VAR_NAME)</c> are expanded from the 
named
+    /// environment variable when <see cref="ResolveEnvVars"/> is called.
+    /// </para>
+    /// </remarks>
+    public sealed class TomlConnectionProfile : IConnectionProfile

Review Comment:
   To the point of my other comment, this is basically a data transfer object 
plus some static helpers which could live on the public 
`IConnectionProfileProvider` implementation.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/ManagedDriverLoader.cs:
##########
@@ -0,0 +1,172 @@
+/*
+ * 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.Concurrent;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Loader;
+#endif
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Provides cross-platform assembly loading functionality for managed 
ADBC drivers.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This type abstracts the differences in assembly loading between .NET 
Framework
+    /// (which uses Fusion / <c>LoadFrom</c> probing) and modern .NET (which 
uses
+    /// <c>AssemblyLoadContext</c> and <c>.deps.json</c>-driven resolution).
+    /// </para>
+    /// <para>
+    /// <b>Dependency resolution on .NET Framework (net472, netstandard2.0 
build):</b>
+    /// <see cref="Assembly.LoadFrom(string)"/> probes the assembly's 
directory for
+    /// dependencies. Drop the driver assembly and all of its dependencies in 
the same
+    /// directory and they will be found.
+    /// </para>
+    /// <para>
+    /// <b>Dependency resolution on .NET 6 / .NET 8 / .NET 10:</b>
+    /// </para>
+    /// <list type="bullet">
+    ///   <item>
+    ///     <description>
+    ///       The driver assembly is loaded with <see 
cref="Assembly.LoadFrom(string)"/>
+    ///       into <see cref="AssemblyLoadContext.Default"/>. This is 
intentional: it keeps
+    ///       a single identity for <c>Apache.Arrow.Adbc.AdbcDriver</c> across 
the host
+    ///       and the driver so that <c>IsAssignableFrom</c> checks work 
correctly.
+    ///     </description>
+    ///   </item>
+    ///   <item>
+    ///     <description>
+    ///       Loading into the default context means the <b>host's</b> 
<c>.deps.json</c>
+    ///       drives resolution, not the driver's. Dependencies that are not 
already known
+    ///       to the host will not be found by default. To bridge that gap, 
this loader
+    ///       registers an <see cref="AssemblyDependencyResolver"/> for each 
driver
+    ///       assembly and attaches a single
+    ///       <see cref="AssemblyLoadContext.Resolving"/> handler to
+    ///       <see cref="AssemblyLoadContext.Default"/>. When the runtime 
fails to resolve
+    ///       a dependency, the handler consults each registered driver's 
resolver, which
+    ///       reads the driver's <c>.deps.json</c> next to it on disk.
+    ///     </description>
+    ///   </item>
+    ///   <item>
+    ///     <description>
+    ///       Drivers should be published with their <c>.deps.json</c> file 
alongside the
+    ///       assembly (the default when building with the .NET SDK). Native 
dependencies
+    ///       should follow the standard <c>runtimes/&lt;rid&gt;/native</c> 
layout.
+    ///     </description>
+    ///   </item>
+    ///   <item>
+    ///     <description>
+    ///       If a driver does not ship a <c>.deps.json</c>, the loader still 
works but
+    ///       falls back to whatever the host can resolve plus the driver's 
directory.
+    ///       Callers needing strong isolation should load the driver into a 
custom
+    ///       <see cref="AssemblyLoadContext"/> themselves.
+    ///     </description>
+    ///   </item>
+    /// </list>
+    /// </remarks>
+    internal static class ManagedDriverLoader
+    {
+#if NET6_0_OR_GREATER
+        private static readonly ConcurrentDictionary<string, 
AssemblyDependencyResolver> resolvers
+            = new ConcurrentDictionary<string, 
AssemblyDependencyResolver>(StringComparer.OrdinalIgnoreCase);
+
+        private static int s_resolveHookInstalled;
+
+        private static void EnsureResolveHookInstalled()
+        {
+            if (Interlocked.CompareExchange(ref s_resolveHookInstalled, 1, 0) 
== 0)
+            {
+                AssemblyLoadContext.Default.Resolving += 
OnDefaultContextResolving;
+            }
+        }
+
+        [UnconditionalSuppressMessage("Trimming", 
"IL2026:RequiresUnreferencedCode",
+            Justification = "Dynamic driver loading is inherently incompatible 
with full trimming. " +
+                            "Drivers must opt out of trimming or be preserved 
by the host.")]
+        private static Assembly? OnDefaultContextResolving(AssemblyLoadContext 
context, AssemblyName assemblyName)
+        {
+            foreach (AssemblyDependencyResolver resolver in resolvers.Values)
+            {
+                string? path = resolver.ResolveAssemblyToPath(assemblyName);
+                if (!string.IsNullOrEmpty(path) && File.Exists(path))
+                {
+                    return context.LoadFromAssemblyPath(path!);
+                }
+            }
+            return null;
+        }
+#endif
+
+        /// <summary>
+        /// Loads a managed driver assembly from the specified path.
+        /// </summary>
+        /// <param name="assemblyPath">The path to the assembly to 
load.</param>
+        /// <returns>The loaded assembly.</returns>
+        /// <exception cref="FileNotFoundException">The assembly file was not 
found.</exception>
+        /// <exception cref="BadImageFormatException">The file is not a valid 
managed assembly.</exception>
+        /// <remarks>
+        /// See the documentation on <see cref="ManagedDriverLoader"/> for 
dependency
+        /// resolution semantics on .NET Framework versus modern .NET.
+        /// </remarks>
+#if NET6_0_OR_GREATER
+        [UnconditionalSuppressMessage("Trimming", 
"IL2026:RequiresUnreferencedCode",
+            Justification = "Dynamic driver loading is inherently incompatible 
with full trimming. " +
+                            "Drivers must opt out of trimming or be preserved 
by the host.")]
+#endif
+        internal static Assembly LoadAssembly(string assemblyPath)
+        {
+            string fullPath = Path.GetFullPath(assemblyPath);
+
+            if (!File.Exists(fullPath))
+            {
+                throw new FileNotFoundException($"Assembly not found: 
{fullPath}", fullPath);
+            }
+
+#if NET6_0_OR_GREATER
+            // Register an AssemblyDependencyResolver for this driver so that 
its own
+            // .deps.json is consulted when the default AssemblyLoadContext 
fails to
+            // resolve a dependency. AssemblyDependencyResolver throws if no 
.deps.json
+            // is present next to the assembly; in that case we silently fall 
back to
+            // the host's normal probing behavior.

Review Comment:
   I found that it was necessary to *always* reference the host's version of 
the following three assemblies regardless of the driver's dependencies: 
`Apache.Arrow`, `Apache.Arrow.Adbc` and `System.Diagnostics.DiagnosticSource`. 
That's because these three assemblies contain types that are in the public ADBC 
contracts. If the driver resolves to a different version of these assemblies 
than the host, an attempt to use an API with one of these types will produce a 
`MethodMissingException`.
   
   A test which covers this scenario would need to have the driver built 
against a different version of one or more of these than the test code is built 
against.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs:
##########
@@ -0,0 +1,787 @@
+/*
+ * 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.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+#endif
+using Apache.Arrow.Adbc.C;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Provides methods to locate and load ADBC drivers, optionally using 
TOML manifest
+    /// files and connection profiles.
+    /// Mirrors the free functions declared in <c>adbc_driver_manager.h</c>:
+    /// <c>AdbcLoadDriver</c> and <c>AdbcFindLoadDriver</c>.
+    /// </summary>
+    public static class AdbcDriverManager
+    {
+        /// <summary>
+        /// The environment variable that specifies additional driver search 
paths.
+        /// </summary>
+        public const string DriverPathEnvVar = "ADBC_DRIVER_PATH";
+
+        private static readonly string[] s_nativeExtensions = { ".so", ".dll", 
".dylib" };
+
+        // 
-----------------------------------------------------------------------
+        // AdbcLoadDriver – load a driver directly from an absolute or 
relative path

Review Comment:
   Relative paths can be dangerous from a security perspective. What is the 
path relative to? At first glance it appears that (at least sometimes) it's 
relative to the current process directory, which I think is a very bad idea. If 
we really want support for relative loading, then I think the best combination 
of safety and usefulness is to make it relative to the location of the 
executing process. But I'd rather force it to be absolute here and leave the 
path resolution explicitly up to the host program.
   
   I'd also be in favor of preventing a relative path from being applied to a 
search path if the relative path contains any directory separators -- 
especially if it also contains `".."` segments.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs:
##########
@@ -0,0 +1,787 @@
+/*
+ * 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.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+#endif
+using Apache.Arrow.Adbc.C;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Provides methods to locate and load ADBC drivers, optionally using 
TOML manifest
+    /// files and connection profiles.
+    /// Mirrors the free functions declared in <c>adbc_driver_manager.h</c>:
+    /// <c>AdbcLoadDriver</c> and <c>AdbcFindLoadDriver</c>.
+    /// </summary>
+    public static class AdbcDriverManager
+    {
+        /// <summary>
+        /// The environment variable that specifies additional driver search 
paths.
+        /// </summary>
+        public const string DriverPathEnvVar = "ADBC_DRIVER_PATH";
+
+        private static readonly string[] s_nativeExtensions = { ".so", ".dll", 
".dylib" };

Review Comment:
   This appears to be unused.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcLoadFlags.cs:
##########
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Flags to control how the ADBC driver manager searches for and loads 
drivers.
+    /// Mirrors the <c>AdbcLoadFlags</c> type and <c>ADBC_LOAD_FLAG_*</c> 
constants
+    /// defined in <c>adbc_driver_manager.h</c>.
+    /// </summary>
+    [Flags]
+    public enum AdbcLoadFlags : uint

Review Comment:
   Is there any specific reason to make this a `uint` enum rather than the 
default?



##########
csharp/src/Apache.Arrow.Adbc/Apache.Arrow.Adbc.csproj:
##########
@@ -20,6 +20,11 @@
     <Compile Remove="C\NativeLibrary.cs" />
   </ItemGroup>
   <ItemGroup>
+    <Content Include="DriverManager\readme.md">
+      <PackagePath>\</PackagePath>

Review Comment:
   Does this preserve the subdirectory `DriverManager` or might it override the 
other `readme.md`?



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/TomlParser.cs:
##########
@@ -0,0 +1,178 @@
+/*
+ * 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.Globalization;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// A minimal TOML parser that handles the subset of TOML used by ADBC 
driver
+    /// manifests and connection profiles:
+    /// <list type="bullet">
+    ///   <item><description>Root-level key = value 
assignments</description></item>
+    ///   <item><description>Table section headers: 
<c>[section]</c></description></item>
+    ///   <item><description>String values (double-quoted), integer values, 
floating-point
+    ///     values, and boolean values 
(<c>true</c>/<c>false</c>)</description></item>
+    ///   <item><description>Line comments beginning with 
<c>#</c></description></item>
+    /// </list>
+    /// This parser intentionally does not support the full TOML specification.
+    /// A full-featured TOML library (e.g. Tomlyn) was considered but cannot 
be used here
+    /// because the assembly is strongly-named and Tomlyn does not publish a 
strongly-named
+    /// package that is compatible with the project's pinned dependency 
versions.
+    /// </summary>
+    internal static class TomlParser
+    {
+        private const string RootSection = "";
+
+        /// <summary>
+        /// Parses <paramref name="content"/> and returns a dictionary keyed 
by section name.
+        /// Root-level keys are stored under the empty string key.
+        /// Values are typed as <see cref="string"/>, <see cref="long"/>, <see 
cref="double"/>,
+        /// or <see cref="bool"/>.
+        /// </summary>
+        internal static Dictionary<string, Dictionary<string, object>> 
Parse(string content)
+        {
+            if (content == null)
+            {
+                throw new ArgumentNullException(nameof(content));
+            }
+
+            Dictionary<string, Dictionary<string, object>> result = new 
Dictionary<string, Dictionary<string, object>>(StringComparer.OrdinalIgnoreCase)
+            {
+                [RootSection] = new Dictionary<string, 
object>(StringComparer.OrdinalIgnoreCase),
+            };
+
+            string currentSection = RootSection;
+
+            foreach (string rawLine in content.Split('\n'))
+            {
+                string line = StripComment(rawLine).Trim();
+
+                if (line.Length == 0)
+                {
+                    continue;
+                }
+
+                if (line.StartsWith("[", StringComparison.Ordinal) && 
line.EndsWith("]", StringComparison.Ordinal))

Review Comment:
   Should this throw an exception if the section name contains anything other 
than `A-Za-z0-9_-`? I know we don't want or need a full-featured parser, but 
perhaps we should try to be overly strict in what we accept rather than reading 
something incorrectly.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/IConnectionProfile.cs:
##########
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Represents an ADBC connection profile, which specifies a driver and a 
set of
+    /// options to apply when initializing a database connection.
+    /// Mirrors the <c>AdbcConnectionProfile</c> struct defined in 
<c>adbc_driver_manager.h</c>.
+    /// </summary>
+    /// <remarks>
+    /// The profile specifies a driver (optionally) and key/value options of 
three types:
+    /// string, 64-bit integer, and double. String option values of the form
+    /// <c>env_var(ENV_VAR_NAME)</c> are expanded from the named environment 
variable
+    /// before being applied to the database.
+    /// </remarks>
+    public interface IConnectionProfile : IDisposable

Review Comment:
   Is there any real benefit to this being an interface versus a simple data 
transfer object? It feels like the `IConnectionProfileProvider` ought to be 
sufficient as an extensibility point without needing to also implement this 
interface.



##########
csharp/src/Apache.Arrow.Adbc/DriverManager/AdbcDriverManager.cs:
##########
@@ -0,0 +1,787 @@
+/*
+ * 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.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+#endif
+using Apache.Arrow.Adbc.C;
+
+namespace Apache.Arrow.Adbc.DriverManager
+{
+    /// <summary>
+    /// Provides methods to locate and load ADBC drivers, optionally using 
TOML manifest
+    /// files and connection profiles.
+    /// Mirrors the free functions declared in <c>adbc_driver_manager.h</c>:
+    /// <c>AdbcLoadDriver</c> and <c>AdbcFindLoadDriver</c>.
+    /// </summary>
+    public static class AdbcDriverManager
+    {
+        /// <summary>
+        /// The environment variable that specifies additional driver search 
paths.
+        /// </summary>
+        public const string DriverPathEnvVar = "ADBC_DRIVER_PATH";
+
+        private static readonly string[] s_nativeExtensions = { ".so", ".dll", 
".dylib" };
+
+        // 
-----------------------------------------------------------------------
+        // AdbcLoadDriver – load a driver directly from an absolute or 
relative path
+        // 
-----------------------------------------------------------------------
+
+        /// <summary>
+        /// Loads an ADBC driver from an explicit file path.
+        /// Mirrors <c>AdbcLoadDriver</c> in <c>adbc_driver_manager.h</c>.

Review Comment:
   It might be worth calling out that loading a managed driver always requires 
a manifest.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to