⌘+k ctrl+k
1.4 (LTS)
搜索快捷键 cmd + k | ctrl + k
C++ API

最新稳定版的 DuckDB C++ API 为 1.5.0。

警告:DuckDB 的 C++ API 为内部 API。它不保证稳定性,且可能随时更改,恕不另行通知。如果您希望基于 DuckDB 构建应用程序,我们建议使用 C API

安装

DuckDB C++ API 可以作为 libduckdb 软件包的一部分进行安装。详细信息请参阅安装页面

基本 API 用法

DuckDB 实现了一个自定义的 C++ API。它围绕数据库实例(DuckDB 类)、针对该数据库实例的多个 Connection(连接)以及作为查询结果的 QueryResult 实例进行抽象构建。C++ API 的头文件为 duckdb.hpp

启动与关闭

要使用 DuckDB,必须首先使用构造函数初始化一个 DuckDB 实例。DuckDB() 的参数是用于读写的数据库文件。特殊值 nullptr 可用于创建内存数据库。请注意,内存数据库的数据不会持久化到磁盘(即当您退出进程时,所有数据都会丢失)。DuckDB 构造函数的第二个参数是一个可选的 DBConfig 对象。在 DBConfig 中,您可以设置各种数据库参数,例如读写模式或内存限制。DuckDB 构造函数可能会抛出异常,例如当数据库文件不可用时。

利用 DuckDB 实例,您可以使用 Connection() 构造函数创建一个或多个 Connection 实例。虽然连接应当是线程安全的,但它们在查询期间会被锁定。因此,如果您处于多线程环境中,建议每个线程使用自己的连接。

DuckDB db(nullptr);
Connection con(db);

查询

连接提供了 Query() 方法,用于从 C++ 向 DuckDB 发送 SQL 查询字符串。Query() 会在返回之前将查询结果完全实例化为内存中的 MaterializedQueryResult,此时即可使用该查询结果。此外还有用于查询的流式 API,详见下文。

// create a table
con.Query("CREATE TABLE integers (i INTEGER, j INTEGER)");

// insert three rows into the table
con.Query("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL)");

auto result = con.Query("SELECT * FROM integers");
if (result->HasError()) {
    cerr << result->GetError() << endl;
} else {
    cout << result->ToString() << endl;
}

MaterializedQueryResult 实例首先包含两个字段,用以指示查询是否成功。在正常情况下,Query 不会抛出异常。相反,无效的查询或其他问题会导致查询结果实例中的 success 布尔字段被设为 false。在这种情况下,错误消息可能会以字符串形式出现在 error 字段中。对于任何 QueryResult 实例,还可以使用 GetErrorType()GetErrorObject() 方法,这些方法有助于更明确地处理错误。

auto result = con.Query("INSERT INTO integers VALUES (1, 2)");
if (result->HasError()) {
    auto errorType = result->GetErrorType();
    switch (errorType) {
    case duckdb::ExceptionType::CONSTRAINT: {
        // Example handling
        auto errorObject = result->GetErrorObject();
        errorObject.ConvertErrorToJSON(); 
        std::cout << errorObject.Message() << std::endl;
        break;
    }
    // More handling
    }
} else {
    // Normal code
}

如果执行成功,其他字段将被设置:刚执行的语句类型(例如 StatementType::INSERT_STATEMENT)包含在 statement_type 中。结果集列的高级类型(“逻辑类型”/“SQL 类型”)位于 types 中。结果列的名称位于 names 字符串向量中。如果返回多个结果集(例如因为结果集包含多条语句),则可以使用 next 字段链接结果集。

DuckDB 的 C++ API 还通过 Prepare() 方法支持预处理语句。该方法返回一个 PreparedStatement 实例。该实例可用于执行带参数的预处理语句。以下是一个示例。

std::unique_ptr<PreparedStatement> prepare = con.Prepare("SELECT count(*) FROM a WHERE i = $1");
std::unique_ptr<QueryResult> result = prepare->Execute(12);

警告:请不要使用预处理语句将大量数据插入 DuckDB。请查看数据导入文档以获取更好的方案。

UDF API

UDF API 允许定义用户自定义函数。它在 duckdb::Connection 中通过以下方法公开:CreateScalarFunction()CreateVectorizedFunction() 及其变体。这些方法将 UDF 创建在所属连接的临时模式(TEMP_SCHEMA)中,只有该连接被允许使用和更改它们。

CreateScalarFunction

用户可以编写普通的标量函数,并调用 CreateScalarFunction() 进行注册,之后即可在 SELECT 语句中使用该 UDF,例如:

bool bigger_than_four(int value) {
    return value > 4;
}

connection.CreateScalarFunction<bool, int>("bigger_than_four", &bigger_than_four);

connection.Query("SELECT bigger_than_four(i) FROM (VALUES (3), (5)) tbl(i)")->Print();

CreateScalarFunction() 方法会自动创建向量化标量 UDF,使其像内置函数一样高效。该方法接口有两种变体,如下所示:

1.

template<typename TR, typename... Args>
void CreateScalarFunction(string name, TR (*udf_func)(Args))
  • 模板参数
    • TR 是 UDF 函数的返回类型。
    • Args 是 UDF 函数的参数(最多支持 3 个,此方法仅支持到三元函数)。
  • name 是注册 UDF 函数时使用的名称。
  • udf_func 是指向 UDF 函数的指针。

此方法会自动从模板类型名称中发现相应的 LogicalTypes:

  • boolLogicalType::BOOLEAN
  • int8_tLogicalType::TINYINT
  • int16_tLogicalType::SMALLINT
  • int32_tLogicalType::INTEGER
  • int64_tLogicalType::BIGINT
  • floatLogicalType::FLOAT
  • doubleLogicalType::DOUBLE
  • string_tLogicalType::VARCHAR

在 DuckDB 中,一些原始类型(例如 int32_t)会被映射到相同的 LogicalTypeINTEGERTIMEDATE。为了消除歧义,用户可以使用以下重载方法。

2.

template<typename TR, typename... Args>
void CreateScalarFunction(string name, vector<LogicalType> args, LogicalType ret_type, TR (*udf_func)(Args))

使用示例如下:

int32_t udf_date(int32_t a) {
    return a;
}

con.Query("CREATE TABLE dates (d DATE)");
con.Query("INSERT INTO dates VALUES ('1992-01-01')");

con.CreateScalarFunction<int32_t, int32_t>("udf_date", {LogicalType::DATE}, LogicalType::DATE, &udf_date);

con.Query("SELECT udf_date(d) FROM dates")->Print();
  • 模板参数
    • TR 是 UDF 函数的返回类型。
    • Args 是 UDF 函数的参数(最多支持 3 个,此方法仅支持到三元函数)。
  • name 是注册 UDF 函数时使用的名称。
  • args 是函数使用的 LogicalType 参数,应与模板 Args 类型匹配。
  • ret_type 是函数的返回 LogicalType,应与模板 TR 类型匹配。
  • udf_func 是指向 UDF 函数的指针。

此函数会根据作为参数传递的 LogicalTypes 检查模板类型,且它们必须满足以下匹配关系:

  • LogicalTypeId::BOOLEAN → bool
  • LogicalTypeId::TINYINT → int8_t
  • LogicalTypeId::SMALLINT → int16_t
  • LogicalTypeId::DATE, LogicalTypeId::TIME, LogicalTypeId::INTEGER → int32_t
  • LogicalTypeId::BIGINT, LogicalTypeId::TIMESTAMP → int64_t
  • LogicalTypeId::FLOAT, LogicalTypeId::DOUBLE, LogicalTypeId::DECIMAL → double
  • LogicalTypeId::VARCHAR, LogicalTypeId::CHAR, LogicalTypeId::BLOB → string_t
  • LogicalTypeId::VARBINARY → blob_t

CreateVectorizedFunction

CreateVectorizedFunction() 方法用于注册向量化 UDF,例如:

/*
* This vectorized function copies the input values to the result vector
*/
template<typename TYPE>
static void udf_vectorized(DataChunk &args, ExpressionState &state, Vector &result) {
    // set the result vector type
    result.vector_type = VectorType::FLAT_VECTOR;
    // get a raw array from the result
    auto result_data = FlatVector::GetData<TYPE>(result);

    // get the solely input vector
    auto &input = args.data[0];
    // now get an orrified vector
    VectorData vdata;
    input.Orrify(args.size(), vdata);

    // get a raw array from the orrified input
    auto input_data = (TYPE *)vdata.data;

    // handling the data
    for (idx_t i = 0; i < args.size(); i++) {
        auto idx = vdata.sel->get_index(i);
        if ((*vdata.nullmask)[idx]) {
            continue;
        }
        result_data[i] = input_data[idx];
    }
}

con.Query("CREATE TABLE integers (i INTEGER)");
con.Query("INSERT INTO integers VALUES (1), (2), (3), (999)");

con.CreateVectorizedFunction<int, int>("udf_vectorized_int", &&udf_vectorized<int>);

con.Query("SELECT udf_vectorized_int(i) FROM integers")->Print();

向量化 UDF 是一个类型为 scalar_function_t 的指针。

typedef std::function<void(DataChunk &args, ExpressionState &expr, Vector &result)> scalar_function_t;
  • args 是一个 DataChunk,它持有一组长度相同的 UDF 输入向量。
  • expr 是一个 ExpressionState,它提供有关查询表达式状态的信息。
  • result 是一个用于存储结果值的 Vector

在向量化 UDF 中有多种需要处理的向量类型:

  • ConstantVector
  • DictionaryVector
  • FlatVector
  • ListVector
  • StringVector
  • StructVector
  • SequenceVector

CreateVectorizedFunction() 方法的通用 API 如下:

1.

template<typename TR, typename... Args>
void CreateVectorizedFunction(string name, scalar_function_t udf_func, LogicalType varargs = LogicalType::INVALID)
  • 模板参数
    • TR 是 UDF 函数的返回类型。
    • Args 是 UDF 函数的参数(最多支持 3 个)。
  • name 是注册 UDF 函数时使用的名称。
  • udf_func 是一个向量化 UDF 函数。
  • varargs:支持的可变参数类型,如果函数不接受可变长参数,则为 LogicalTypeId::INVALID(默认值)。

此方法会自动从模板类型名称中发现相应的 LogicalTypes:

  • boolLogicalType::BOOLEAN
  • int8_tLogicalType::TINYINT
  • int16_tLogicalType::SMALLINT
  • int32_tLogicalType::INTEGER
  • int64_tLogicalType::BIGINT
  • floatLogicalType::FLOAT
  • doubleLogicalType::DOUBLE
  • string_tLogicalType::VARCHAR

2.

template<typename TR, typename... Args>
void CreateVectorizedFunction(string name, vector<LogicalType> args, LogicalType ret_type, scalar_function_t udf_func, LogicalType varargs = LogicalType::INVALID)
© 2025 DuckDB 基金会,阿姆斯特丹,荷兰
行为准则 商标使用指南