Note
警告 DuckDB 的 C++ API 是内部的。 它不保证稳定,并且可能会在没有通知的情况下更改。 如果您想在 DuckDB 上构建应用程序,我们建议使用 C API。
Note
警告 DuckDB 的 C++ API 是内部的。 它不保证稳定,并且可能会在没有通知的情况下更改。 如果您想在 DuckDB 上构建应用程序,我们建议使用 C API。
DuckDB C++ API 可以作为 libduckdb
包的一部分进行安装。详情请参阅 安装页面。
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
中。如果成功,其他字段将被设置:刚刚执行的语句类型(例如,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);
Note
警告 请不要使用预处理语句将大量数据插入DuckDB。有关更好的选项,请参阅数据导入文档。
UDF API 允许定义用户自定义函数。它通过以下方法在 duckdb:Connection
中暴露:CreateScalarFunction()
、CreateVectorizedFunction()
及其变体。
这些方法将 UDF 创建到所有者连接的临时模式(TEMP_SCHEMA
)中,只有该连接才能使用和修改它们。
用户可以编写一个普通的标量函数并调用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…))
此方法自动从模板类型名中发现相应的逻辑类型:
bool
→ LogicalType::BOOLEAN
int8_t
→ LogicalType::TINYINT
int16_t
→ LogicalType::SMALLINT
int32_t
→ LogicalType::INTEGER
int64_t
→ LogicalType::BIGINT
float
→ LogicalType::FLOAT
double
→ LogicalType::DOUBLE
string_t
→ LogicalType::VARCHAR
在DuckDB中,一些基本类型,例如int32_t
,被映射到相同的LogicalType
:INTEGER
、TIME
和DATE
,为了消除歧义,用户可以使用以下重载方法。
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();
此函数检查模板类型与作为参数传递的LogicalTypes,它们必须匹配如下:
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;
在向量化UDF中需要处理不同的向量类型:
CreateVectorizedFunction()
方法的一般API如下:
1.
template<typename TR, typename... Args>
void CreateVectorizedFunction(string name, scalar_function_t udf_func, LogicalType varargs = LogicalType::INVALID)
此方法自动从模板类型名中发现相应的逻辑类型:
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)