ADBC 驱动程序管理器与连接配置

注意

本文档介绍了如何使用 驱动程序管理器 来加载驱动程序。通常情况下,使用 ADBC 并不强制要求使用驱动程序管理器,但它允许加载与应用程序语言不同的驱动程序,并在单个应用程序中使用多个驱动程序时改善体验。有关驱动程序管理器工作原理的更多信息,请参阅 驱动程序与驱动程序管理器如何协同工作

有两种方法可以通过驱动程序管理器传递数据库选项:

  1. 在应用程序代码中将所有选项直接指定为驱动程序管理器的参数(有关详细信息,请参阅 ADBC API 标准 中的 SetOption 系列函数)。

  2. 引用包含选项的 连接配置,并可选择通过上述方法设置某些选项来覆盖部分默认配置。

连接配置将驱动程序和数据库选项组合在可重用的配置中。这允许用户:

  • 在文件或环境变量中定义连接信息

  • 在多个应用程序间共享连接配置

  • 分发标准化的连接设置

  • 避免在应用程序代码中硬编码驱动程序名称和凭据

配置会在 AdbcDatabaseInit() 期间、驱动程序初始化之前被加载。来自配置文件的选项会自动应用,但不会覆盖已通过 AdbcDatabaseSetOption() 设置的选项。

快速入门

通过 URI 使用配置

使用配置最简单的方法是通过 URI

AdbcDatabase database;
AdbcDatabaseNew(&database, &error);
AdbcDatabaseSetOption(&database, "uri", "profile://my_snowflake_prod", &error);
AdbcDatabaseInit(&database, &error);

通过选项使用配置

或者,直接指定配置名称

AdbcDatabase database;
AdbcDatabaseNew(&database, &error);
AdbcDatabaseSetOption(&database, "profile", "my_snowflake_prod", &error);
AdbcDatabaseInit(&database, &error);

配置文件格式

基于文件系统的配置使用 TOML 格式,结构如下:

# The version is required.
profile_version = 1
# The driver is optional, but if not provided it must be set by the application.
driver = "snowflake"

# The Options table is required, even if empty
[Options]
# String options
adbc.snowflake.sql.account = "mycompany"
adbc.snowflake.sql.warehouse = "COMPUTE_WH"
adbc.snowflake.sql.database = "PRODUCTION"
adbc.snowflake.sql.schema = "PUBLIC"

# Integer options
adbc.snowflake.sql.client_session_keep_alive_heartbeat_frequency = 3600

# Double options
adbc.snowflake.sql.client_timeout = 30.5

# Boolean options (converted to "true" or "false" strings)
adbc.snowflake.sql.client_session_keep_alive = true

profile_version

  • 必需:是

  • 类型:整数

  • 支持的值1

profile_version 字段指定配置文件格式的版本。目前仅支持版本 1。这将在保持向后兼容性的同时支持未来的更改。

driver

  • 必需:否

  • 类型:字符串

driver 字段指定要加载的 ADBC 驱动程序。这可以是:

  • 驱动程序或驱动程序清单名称(例如 "snowflake"

  • 共享库的路径(例如 "/usr/local/lib/libadbc_driver_snowflake.so"

  • 驱动程序清单的路径(例如 "/etc/adbc/drivers/snowflake.toml"

如果省略,则必须通过其他方式(例如 driver 选项或 uri 参数)指定驱动程序。如果应用程序指定了驱动程序,并且所指定的配置本身也引用了一个驱动程序,则两者必须完全匹配,否则会报错。驱动程序的加载方式与通过 AdbcDatabaseSetOption("driver", "<driver>") 指定时相同。有关详细信息,请参阅 ADBC 驱动程序管理器与清单

选项部分

[Options] 部分包含在创建 AdbcDatabase 时要应用的驱动程序特定配置选项。即使为空,也必须包含此部分。选项可以是以下类型:

字符串值

使用 AdbcDatabaseSetOption() 应用

adbc.snowflake.sql.account = "mycompany"
adbc.snowflake.sql.warehouse = "COMPUTE_WH"
整数值

使用 AdbcDatabaseSetOptionInt() 应用

adbc.snowflake.sql.client_session_keep_alive_heartbeat_frequency = 3600
双精度浮点值

使用 AdbcDatabaseSetOptionDouble() 应用

adbc.snowflake.sql.client_timeout = 30.5
布尔值

转换为字符串 "true""false" 并使用 AdbcDatabaseSetOption() 应用

adbc.snowflake.sql.client_session_keep_alive = true

警告

如果应用程序覆盖了选项值,但所使用的类型与配置文件中的类型不同,则结果将是未定义的。

值替换

配置文件值支持环境变量和其他动态内容的替换。这允许配置文件引用敏感信息(如密码或令牌),而无需在配置文件中硬编码。可以使用 {{ }} 语法注入动态值,类似于许多模板引擎。在双花括号内,驱动程序管理器可以识别某些函数来执行替换。

目前唯一可识别的函数是用于环境变量替换的 env_var(),但未来可能会扩展以支持其他类型的动态内容。

重要提示

动态内容替换仅适用于选项,而不适用于

环境变量替换

配置文件值可以使用 {{ env_var() }} 语法引用环境变量

profile_version = 1
driver = "adbc_driver_snowflake"

[Options]
adbc.snowflake.sql.account = "{{ env_var(SNOWFLAKE_ACCOUNT) }}"
adbc.snowflake.sql.auth_token = "{{ env_var(SNOWFLAKE_TOKEN) }}"
adbc.snowflake.sql.warehouse = "COMPUTE_WH"

当驱动程序管理器遇到 {{ env_var(VAR_NAME) }} 时,它会将占位符替换为环境变量 VAR_NAME 的内容。如果未设置该环境变量,则占位符被替换为空字符串,并继续处理值的其余部分(例如 "foo{{ env_var(MISSING) }}bar" 将变为 "foobar")。

配置搜索路径

当使用配置名称(而非绝对路径)时,驱动程序管理器会在以下位置搜索 <profile_name>.toml

  1. 附加搜索路径(如果已通过 additional_profile_search_path_list 选项配置)

  2. ADBC_PROFILE_PATH 环境变量(Unix 上使用冒号分隔,Windows 上使用分号分隔)

  3. Conda 环境(如果构建时启用了 Conda 支持且设置了 CONDA_PREFIX

    • $CONDA_PREFIX/etc/adbc/profiles/

  4. 用户配置目录:

    • Linux:若已设置 $XDG_CONFIG_HOME/adbc/profiles,否则为 ~/.config/adbc/profiles/

    • macOS:~/Library/Application Support/ADBC/Profiles/

    • Windows:%LOCALAPPDATA%\ADBC\Profiles\

驱动程序管理器按顺序搜索这些位置,并使用找到的第一个匹配配置文件。

使用绝对路径

若要指定配置文件的绝对路径:

// Via profile option
AdbcDatabaseSetOption(&database, "profile", "/etc/adbc/profiles/production.toml", &error);

// Via URI (must have .toml extension)
AdbcDatabaseSetOption(&database, "uri", "profile:///etc/adbc/profiles/production.toml", &error);

示例

示例 1:Snowflake 生产环境配置

文件:~/.config/adbc/profiles/snowflake_prod.toml

profile_version = 1
driver = "snowflake"

[Options]
adbc.snowflake.sql.account = "{{ env_var(SNOWFLAKE_ACCOUNT) }}"
adbc.snowflake.sql.auth_token = "{{ env_var(SNOWFLAKE_TOKEN) }}"
adbc.snowflake.sql.warehouse = "PRODUCTION_WH"
adbc.snowflake.sql.database = "PROD_DB"
adbc.snowflake.sql.schema = "PUBLIC"
adbc.snowflake.sql.client_session_keep_alive = true
adbc.snowflake.sql.client_session_keep_alive_heartbeat_frequency = 3600

用法

// Set environment variables
setenv("SNOWFLAKE_ACCOUNT", "mycompany", 1);
setenv("SNOWFLAKE_TOKEN", "secret_token", 1);

// Use profile
AdbcDatabase database;
AdbcDatabaseNew(&database, &error);
AdbcDatabaseSetOption(&database, "uri", "profile://snowflake_prod", &error);
AdbcDatabaseInit(&database, &error);

示例 2:PostgreSQL 开发环境配置

文件:~/.config/adbc/profiles/postgres_dev.toml

profile_version = 1
driver = "postgresql"

[Options]
uri = "postgresql://:5432/dev_db?sslmode=disable"
username = "dev_user"
password = "{{ env_var(POSTGRES_DEV_PASSWORD) }}"

示例 3:驱动程序无关的通用配置

配置文件可以省略驱动程序字段,以实现可重用的配置

文件:~/.config/adbc/profiles/default_timeouts.toml

profile_version = 1
# No driver specified - can be used with any driver

[Options]
adbc.connection.timeout = 30.0
adbc.statement.timeout = 60.0

用法(单独指定驱动程序)

AdbcDatabase database;
AdbcDatabaseNew(&database, &error);
AdbcDatabaseSetOption(&database, "driver", "adbc_driver_snowflake", &error);
AdbcDatabaseSetOption(&database, "profile", "default_timeouts", &error);
AdbcDatabaseInit(&database, &error);

高级用法

选项优先级

选项按以下顺序应用(后面的覆盖前面的):

  1. 驱动程序默认值

  2. 配置文件选项(来自 [Options] 部分)

  3. AdbcDatabaseInit() 之前通过 AdbcDatabaseSetOption() 设置的选项

示例

AdbcDatabase database;
AdbcDatabaseNew(&database, &error);

// Profile sets warehouse = "COMPUTE_WH"
AdbcDatabaseSetOption(&database, "profile", "snowflake_prod", &error);

// This overrides the profile setting
AdbcDatabaseSetOption(&database, "adbc.snowflake.sql.warehouse", "ANALYTICS_WH", &error);

AdbcDatabaseInit(&database, &error);
// Result: warehouse = "ANALYTICS_WH"

注意

不同类型的选项是单独设置的。例如,如果配置文件定义了一个整数值的选项,而应用程序设置了相同的选项但使用的是字符串值,则哪个值生效取决于实现定义。如果应用程序改用整数值,则应用程序的值会按预期生效。

自定义配置提供程序

应用程序可以实现自定义配置提供程序,以从替代来源(数据库、密钥保管库、配置服务等)加载配置。

接口定义

配置提供程序必须实现 AdbcConnectionProfile 接口

struct AdbcConnectionProfile {
    void* private_data;
    // this will be called by the driver manager after retrieving the necessary information from the profile.
    void (*release)(struct AdbcConnectionProfile* profile);
    AdbcStatusCode (*GetDriverName)(struct AdbcConnectionProfile* profile,
                                    const char** driver_name,
                                    AdbcDriverInit* init_func,
                                    struct AdbcError* error);
    AdbcStatusCode (*GetOptions)(struct AdbcConnectionProfile* profile,
                                 const char*** keys, const char*** values,
                                 size_t* num_options, struct AdbcError* error);
    AdbcStatusCode (*GetIntOptions)(struct AdbcConnectionProfile* profile,
                                    const char*** keys, const int64_t** values,
                                    size_t* num_options, struct AdbcError* error);
    AdbcStatusCode (*GetDoubleOptions)(struct AdbcConnectionProfile* profile,
                                       const char*** keys, const double** values,
                                       size_t* num_options, struct AdbcError* error);
};

提供程序函数

提供程序函数签名

typedef AdbcStatusCode (*AdbcConnectionProfileProvider)(
    const char* profile_name,
    const char* additional_search_path_list,
    struct AdbcConnectionProfile* out,
    struct AdbcError* error);

实现示例

// Example: Load profiles from a key-value store
AdbcStatusCode MyCustomProfileProvider(const char* profile_name,
                                       const char* additional_search_path_list,
                                       struct AdbcConnectionProfile* out,
                                       struct AdbcError* error) {
    // Fetch profile from custom source
    MyProfileData* data = LoadProfileFromKeyVault(profile_name);
    if (!data) {
        SetError(error, "Profile not found in key vault");
        return ADBC_STATUS_NOT_FOUND;
    }

    std::memset(out, 0, sizeof(struct AdbcConnectionProfile));
    // Populate profile structure
    out->private_data = data;
    out->release = MyProfileRelease;
    out->GetDriverName = MyGetDriverName;
    out->GetOptions = MyGetOptions;
    out->GetIntOptions = MyGetIntOptions;
    out->GetDoubleOptions = MyGetDoubleOptions;

    return ADBC_STATUS_OK;
}

// Register custom provider
AdbcDatabase database;
AdbcDatabaseNew(&database, &error);
AdbcDriverManagerDatabaseSetProfileProvider(&database, MyCustomProfileProvider, &error);
AdbcDatabaseSetOption(&database, "profile", "prod_config", &error);
AdbcDatabaseInit(&database, &error);

使用场景

开发与生产环境区分

为不同环境维护单独的配置文件

# Development
export ADBC_PROFILE=snowflake_dev

# Production
export ADBC_PROFILE=snowflake_prod

应用程序代码

const char* profile = getenv("ADBC_PROFILE");
if (!profile) profile = "default";

AdbcDatabaseSetOption(&database, "profile", profile, &error);

凭据管理

将凭据与代码分开存储

[Options]
adbc.snowflake.sql.account = "mycompany"
adbc.snowflake.sql.auth_token = "{{ env_var(SNOWFLAKE_TOKEN) }}"

然后通过环境变量、密钥管理器或配置服务设置 SNOWFLAKE_TOKEN

多租户应用程序

使用配置文件来支持不同的客户配置

char profile_name[256];
snprintf(profile_name, sizeof(profile_name), "customer_%s", customer_id);

AdbcDatabaseSetOption(&database, "profile", profile_name, &error);

测试

使用配置文件在模拟数据库和真实数据库之间切换

#ifdef TESTING
const char* profile = "mock_database";
#else
const char* profile = "production";
#endif

AdbcDatabaseSetOption(&database, "profile", profile, &error);

错误处理

找不到配置文件

如果找不到配置文件,AdbcDatabaseInit() 会返回 ADBC_STATUS_NOT_FOUND,并附带详细的错误消息,列出所有已搜索的位置

[Driver Manager] Profile not found: my_profile
Also searched these paths for profiles:
    ADBC_PROFILE_PATH: /custom/path
    user config dir: /home/user/.config/adbc/profiles
    system config dir: /etc/adbc/profiles

配置文件格式无效

如果配置文件存在但格式错误,AdbcDatabaseInit() 会返回 ADBC_STATUS_INVALID_ARGUMENT

[Driver Manager] Could not open profile. Error at line 5: expected '=' after key.
Profile: /home/user/.config/adbc/profiles/my_profile.toml

缺少驱动程序

如果配置文件未指定驱动程序,且未通过其他方式提供

[Driver Manager] Must provide 'driver' parameter
(or encode driver in 'uri' parameter)

最佳实践

  1. 使用环境变量存储密钥:切勿直接将凭据存储在配置文件中。

    # Good
    password = "{{ env_var(DB_PASSWORD) }}"
    
    # Bad
    password = "my_secret_password"
    
  2. 分层组织配置文件:使用附加搜索路径将相关配置文件分组到子目录中。

  3. 记录配置模式:维护每个配置文件所需环境变量的文档。

  4. 版本控制不含密钥:当使用 {{ env_var(VAR_NAME) }} 处理敏感值时,配置文件可以进行版本控制。

  5. 测试配置加载:在 CI/CD 流水线中验证配置文件是否正确加载。

  6. 使用有意义的名称:以描述性方式命名配置文件(例如 snowflake_prod_analytics 而非 profile1)。

  7. 验证环境变量:在调用 AdbcDatabaseInit() 之前,检查所需的环境变量是否已设置。

API 参考

设置配置提供程序

AdbcStatusCode AdbcDriverManagerDatabaseSetProfileProvider(
    struct AdbcDatabase* database,
    AdbcConnectionProfileProvider provider,
    struct AdbcError* error);

设置自定义连接配置提供程序。必须在 AdbcDatabaseInit() 之前调用。

参数

  • database:要配置的数据库对象

  • provider:配置提供程序函数,或 NULL(使用默认文件系统提供程序)

  • error:可选的错误输出

返回值: 成功时返回 ADBC_STATUS_OK,否则返回错误代码。

设置附加搜索路径

可以通过 additional_profile_search_path_list 选项完成。它必须在 AdbcDatabaseInit() 之前设置。此选项的值是一个操作系统特定的分隔列表(Unix 上为 :,Windows 上为 ;),或设为 NULL 以清除。

示例

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

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

另请参阅