Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 46 additions & 37 deletions docs/source/format/connection_profiles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,37 @@
.. specific language governing permissions and limitations
.. under the License.

==================================
Driver Manager Connection Profiles
==================================
===========================================
ADBC Driver Manager and Connection Profiles
===========================================

Overview
========
.. note:: This document describes using the :term:`driver manager` to load
drivers. The driver manager is not required to use ADBC in general
but it allows loading drivers written in a different language from the
application and improves the experience when using multiple drivers in
a single application. For more information on how the driver manager
works see :doc:`how_manager`.

There are two ways to pass connection options to driver managers:
There are two ways to pass driver options through the driver manager:

1. Directly specifying all connection options as arguments to driver manager functions in your
application code. (see the `SetOption` family of functions in :doc:`specification` for details)
2. Referring to a **connection profile** which contains connection options, and optionally overriding
some options in your application code.
1. Directly specifying all options as arguments to the driver manager in your
application code (see the `SetOption` family of functions in
:doc:`specification` for details).
2. Referring to a :term:`connection profile` which contains options, and
optionally overriding some options by setting them through the above
method.

The ADBC driver manager supports **connection profiles** that specify a driver and connection options
in a reusable configuration. This allows users to:
Connection profiles combine a driver and driver options in a reusable
configuration. This allows users to:

- Define connection information in files or environment variables
- Share connection configurations across applications
- Distribute standardized connection settings
- Avoid hardcoding driver names and credentials in application code

Profiles are loaded during ``AdbcDatabaseInit()`` before initializing the driver. Options
from the profile are applied automatically but do not override options already set via ``AdbcDatabaseSetOption()``.
Profiles are loaded during ``AdbcDatabaseInit()`` before initializing the
driver. Options from the profile are applied automatically but do not override
options already set via ``AdbcDatabaseSetOption()``.

Quick Start
===========
Expand Down Expand Up @@ -74,9 +81,12 @@ Filesystem-based profiles use TOML format with the following structure:

.. code-block:: toml

# The version is required.
profile_version = 1
# It is optional to provide the driver.
driver = "snowflake"

# The Options table is required, even if empty
[Options]
# String options
adbc.snowflake.sql.account = "mycompany"
Expand Down Expand Up @@ -111,18 +121,19 @@ driver

The ``driver`` field specifies which ADBC driver to load. This can be:

- A driver name (e.g., ``"snowflake"``)
- A driver or driver manifest name (e.g., ``"snowflake"``)
- A path to a shared library (e.g., ``"/usr/local/lib/libadbc_driver_snowflake.so"``)
- A path to a driver manifest (e.g., ``"/etc/adbc/drivers/snowflake.toml"``)

If omitted, the driver must be specified through other means (e.g., the ``driver`` option or ``uri`` parameter).
If the application specifies a driver, and specifies a profile that itself references a driver, the two must match exactly, or it is an error.
The driver will be loaded identically to if it was specified via ``AdbcDatabaseSetOption("driver", "<driver>")``.
For more detils, see :doc:`driver_manifests`.

Options Section
---------------

The ``[Options]`` section contains driver-specific configuration options. Options can be of the following types:
The ``[Options]`` section contains driver-specific configuration options. This section must be present, even if empty. Options can be of the following types:

**String values**
Applied using ``AdbcDatabaseSetOption()``
Expand Down Expand Up @@ -153,6 +164,10 @@ The ``[Options]`` section contains driver-specific configuration options. Option

adbc.snowflake.sql.client_session_keep_alive = true

.. warning:: If the application overrides option values but uses a different
type for the value than the profile does, it is undefined which
will take effect.

Value Substitution
------------------

Expand Down Expand Up @@ -190,7 +205,7 @@ Profile Search Locations

When using a profile name (not an absolute path), the driver manager searches for ``<profile_name>.toml`` in the following locations:

1. **Additional Search Paths** (if configured via ``AdbcDriverManagerDatabaseSetAdditionalSearchPathList()``)
1. **Additional Search Paths** (if configured via ``additional_profile_search_path_list`` option)
2. **ADBC_PROFILE_PATH** environment variable (colon-separated on Unix, semicolon-separated on Windows)
3. **Conda Environment** (if built with Conda support and ``CONDA_PREFIX`` is set):

Expand Down Expand Up @@ -561,34 +576,28 @@ Sets a custom connection profile provider. Must be called before ``AdbcDatabaseI
Setting Additional Search Paths
--------------------------------

.. code-block:: c

AdbcStatusCode AdbcDriverManagerDatabaseSetAdditionalSearchPathList(
struct AdbcDatabase* database,
const char* path_list,
struct AdbcError* error);

Adds additional directories to search for profiles. Must be called before ``AdbcDatabaseInit()``.

**Parameters:**

- ``database``: Database object to configure
- ``path_list``: OS-specific path separator delimited list (``:``) on Unix, ``;`` on Windows), or ``NULL`` to clear
- ``error``: Optional error output

**Returns:** ``ADBC_STATUS_OK`` on success, error code otherwise.
This can be done via the ``additional_profile_search_path_list`` option. It
must be set before ``AdbcDatabaseInit()``. The value of this option is an
OS-specific delimited list (``:`` on Unix, ``;`` on Windows), or ``NULL`` to
clear.

**Example:**

.. code-block:: c

// Unix/Linux/macOS
AdbcDriverManagerDatabaseSetAdditionalSearchPathList(
&database, "/opt/app/profiles:/etc/app/profiles", &error);
AdbcDatabaseSetOption(
&database,
"additional_profile_search_path_list",
"/opt/app/profiles:/etc/app/profiles",
&error);

// Windows
AdbcDriverManagerDatabaseSetAdditionalSearchPathList(
&database, "C:\\App\\Profiles;C:\\ProgramData\\App\\Profiles", &error);
AdbcDatabaseSetOption(
&database,
"additional_profile_search_path_list",
"C:\\App\\Profiles;C:\\ProgramData\\App\\Profiles",
&error);


See Also
Expand Down
6 changes: 3 additions & 3 deletions docs/source/format/driver_manifests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ ADBC Driver Manager and Manifests

There are two ways to load a driver with the driver manager:

1. Directly specifying the dynamic library to load
2. Referring to a driver manifest file which contains metadata along with the
location of the dynamic library to be loaded
1. Directly specifying the dynamic library to load.
2. Referring to a :term:`driver manifest` file which contains metadata along
with the location of the dynamic library to be loaded.

With either method, you specify the dynamic library or driver manifest as the
``driver`` option to the driver manager or you can use an explicit function for
Expand Down
5 changes: 5 additions & 0 deletions docs/source/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ Glossary
In ADBC, the connection object/struct represents a single connection to a
database. Multiple connections may be created from one :term:`database`.

connection profile
A preconfigured driver and options that can be loaded by the
:term:`driver manager` for convenience. Specified via a TOML file. See
:doc:`format/connection_profiles`.

database
In ADBC, the database object/struct holds state that is shared across
connections.
Expand Down
2 changes: 1 addition & 1 deletion javascript/__test__/profile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ test('profile: load database from profile:// URI', async () => {

const db = new AdbcDatabase({
driver: 'profile://test_sqlite',
searchPaths: [tmpDir],
profileSearchPaths: [tmpDir],
})
const conn = await db.connect()

Expand Down
3 changes: 2 additions & 1 deletion javascript/binding.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions javascript/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export interface ConnectOptions {
* - URI-style string: `"sqlite:file::memory:"`, `"postgresql://user:pass@host/db"` — the
* driver name is the URI scheme and the remainder is passed as the connection URI.
* - Connection profile URI: `"profile://my_profile"` — loads a named profile from a
* `.toml` file found in {@link searchPaths} or the default search directories.
* `.toml` file found in {@link profileSearchPaths} or the default search directories.
*/
driver: string
/**
Expand All @@ -127,10 +127,15 @@ export interface ConnectOptions {
*/
entrypoint?: string
/**
* Additional directories to search for drivers and driver manifest (`.toml`) profile files (optional).
* Additional directories to search for drivers and driver manifest (`.toml`) files (optional).
* Searched before the default system and user configuration directories.
*/
searchPaths?: string[]
manifestSearchPaths?: string[]
/**
* Additional directories to search for connection profile (`.toml`) files (optional).
* Searched before the default system and user configuration directories.
*/
profileSearchPaths?: string[]
/**
* Bitmask controlling how the driver name is resolved (optional).
* Use the {@link LoadFlags} constants to compose a value.
Expand Down
21 changes: 15 additions & 6 deletions javascript/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ pub type Result<T> = std::result::Result<T, ClientError>;
pub struct ConnectOptions {
pub driver: String,
pub entrypoint: Option<String>,
pub search_paths: Option<Vec<String>>,
pub manifest_search_paths: Option<Vec<String>>,
pub profile_search_paths: Option<Vec<String>>,
pub load_flags: Option<u32>,
pub database_options: Option<HashMap<String, String>>,
}
Expand Down Expand Up @@ -76,20 +77,28 @@ impl AdbcDatabaseCore {
let load_flags = opts.load_flags.unwrap_or(LOAD_FLAG_DEFAULT);
let entrypoint = opts.entrypoint.as_ref().map(|s| s.as_bytes().to_vec());

let search_paths: Option<Vec<PathBuf>> = opts
.search_paths
let manifest_search_paths: Option<Vec<PathBuf>> = opts
.manifest_search_paths
.map(|paths| paths.into_iter().map(PathBuf::from).collect());

let profile_search_paths: Option<Vec<PathBuf>> = opts
.profile_search_paths
.map(|paths| paths.into_iter().map(PathBuf::from).collect());

let database_opts = opts.database_options.map(map_database_options);

let database = if opts.driver.contains(':') {
let provider = adbc_driver_manager::profile::FilesystemProfileProvider::new_with_search_paths(
profile_search_paths,
);
// URI-style ("sqlite:file::memory:") or profile URI ("profile://my_profile")
ManagedDatabase::from_uri_with_opts(
ManagedDatabase::from_uri_with_profile_provider(
&opts.driver,
entrypoint.as_deref(),
version,
load_flags,
search_paths,
manifest_search_paths,
provider,
database_opts.into_iter().flatten(),
)?
} else {
Expand All @@ -99,7 +108,7 @@ impl AdbcDatabaseCore {
entrypoint.as_deref(),
version,
load_flags,
search_paths,
manifest_search_paths,
)?;
match database_opts {
Some(db_opts) => driver.new_database_with_opts(db_opts)?,
Expand Down
6 changes: 4 additions & 2 deletions javascript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ pub fn default_load_flags() -> u32 {
pub struct ConnectOptions {
pub driver: String,
pub entrypoint: Option<String>,
pub search_paths: Option<Vec<String>>,
pub manifest_search_paths: Option<Vec<String>>,
pub profile_search_paths: Option<Vec<String>>,
pub load_flags: Option<u32>,
pub database_options: Option<HashMap<String, String>>,
}
Expand All @@ -154,7 +155,8 @@ impl From<ConnectOptions> for CoreConnectOptions {
Self {
driver: opts.driver,
entrypoint: opts.entrypoint,
search_paths: opts.search_paths,
manifest_search_paths: opts.manifest_search_paths,
profile_search_paths: opts.profile_search_paths,
load_flags: opts.load_flags,
database_options: opts.database_options,
}
Expand Down
8 changes: 3 additions & 5 deletions rust/driver_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,14 +494,13 @@ impl ManagedDatabase {
additional_search_paths: Option<Vec<PathBuf>>,
opts: impl IntoIterator<Item = (<Self as Optionable>::Option, OptionValue)>,
) -> Result<Self> {
let profile_provider = FilesystemProfileProvider;
Self::from_uri_with_profile_provider(
uri,
entrypoint,
version,
load_flags,
additional_search_paths,
profile_provider,
FilesystemProfileProvider::default(),
opts,
)
}
Expand Down Expand Up @@ -534,7 +533,7 @@ impl ManagedDatabase {
/// use adbc_driver_manager::profile::FilesystemProfileProvider;
/// use adbc_core::LOAD_FLAG_DEFAULT;
///
/// let provider = FilesystemProfileProvider;
/// let provider = FilesystemProfileProvider::default();
/// let opts = vec![(OptionDatabase::Username, OptionValue::String("admin".to_string()))];
///
/// let db = ManagedDatabase::from_uri_with_profile_provider(
Expand Down Expand Up @@ -575,8 +574,7 @@ impl ManagedDatabase {
(drv, final_opts)
}
DriverLocator::Profile(profile) => {
let profile =
profile_provider.get_profile(profile, additional_search_paths.clone())?;
let profile = profile_provider.get_profile(profile)?;
let (driver_name, init_func) = profile.get_driver_name()?;

let drv: ManagedDriver;
Expand Down
Loading
Loading