快速入门¶
配方来源:quickstart.cc
在这里,我们将简要介绍 ADBC 与 C++17 中 SQLite 驱动程序的基本功能。
安装¶
此快速入门实际上是一个文字 C++ 文件。您可以克隆存储库,构建示例,并跟着操作。
我们假设您使用conda-forge来管理依赖项。需要 CMake、C++17 编译器和 ADBC 库。它们可以按如下方式安装
mamba install cmake compilers libadbc-driver-manager libadbc-driver-sqlite
构建¶
我们这里将使用CMake。从 ADBC 存储库的源代码检出中
mkdir build
cd build
cmake ../docs/source/cpp/recipe
cmake --build . --target recipe-quickstart
./recipe-quickstart
使用 ADBC¶
让我们从一些包含文件开始
59// For EXIT_SUCCESS
60#include <cstdlib>
61// For strerror
62#include <cstring>
63#include <iostream>
64
65#include <arrow-adbc/adbc.h>
66#include <nanoarrow.h>
然后我们将添加一些(非常基本)的错误检查助手。
70// Error-checking helper for ADBC calls.
71// Assumes that there is an AdbcError named `error` in scope.
72#define CHECK_ADBC(EXPR) \
73 if (AdbcStatusCode status = (EXPR); status != ADBC_STATUS_OK) { \
74 if (error.message != nullptr) { \
75 std::cerr << error.message << std::endl; \
76 } \
77 return EXIT_FAILURE; \
78 }
79
80// Error-checking helper for ArrowArrayStream.
81#define CHECK_STREAM(STREAM, EXPR) \
82 if (int status = (EXPR); status != 0) { \
83 std::cerr << "(" << std::strerror(status) << "): "; \
84 const char* message = (STREAM).get_last_error(&(STREAM)); \
85 if (message != nullptr) { \
86 std::cerr << message << std::endl; \
87 } else { \
88 std::cerr << "(no error message)" << std::endl; \
89 } \
90 return EXIT_FAILURE; \
91 }
92
93// Error-checking helper for Nanoarrow.
94#define CHECK_NANOARROW(EXPR) \
95 if (int status = (EXPR); status != 0) { \
96 std::cerr << "(" << std::strerror(status) << "): failed" << std::endl; \
97 return EXIT_FAILURE; \
98 }
99
100int main() {
加载驱动程序¶
我们将使用驱动程序管理器加载 SQLite 驱动程序。这样我们就不必显式链接到驱动程序。
107 AdbcError error = {};
108
109 AdbcDatabase database = {};
110 CHECK_ADBC(AdbcDatabaseNew(&database, &error));
驱动程序管理器知道我们想要哪个驱动程序的方式是通过 driver 选项。
113 CHECK_ADBC(AdbcDatabaseSetOption(&database, "driver", "adbc_driver_sqlite", &error));
114 CHECK_ADBC(AdbcDatabaseInit(&database, &error));
创建连接¶
ADBC 区分“数据库”、“连接”和“语句”。“数据库”在多个连接之间持有共享状态。例如,在 SQLite 驱动程序中,它持有 SQLite 的实际实例。“连接”是对数据库的一个连接。
125 AdbcConnection connection = {};
126 CHECK_ADBC(AdbcConnectionNew(&connection, &error));
127 CHECK_ADBC(AdbcConnectionInit(&connection, &database, &error));
创建语句¶
语句允许我们执行查询。它们用于预准备查询和非预准备查询(“即席”查询)。
135 AdbcStatement statement = {};
136 CHECK_ADBC(AdbcStatementNew(&connection, &statement, &error));
执行查询¶
我们通过在语句上设置查询,然后调用 AdbcStatementExecuteQuery() 来执行查询。结果通过 Arrow C 数据接口返回。
147 struct ArrowArrayStream stream = {};
148 int64_t rows_affected = -1;
149
150 CHECK_ADBC(AdbcStatementSetSqlQuery(&statement, "SELECT 42 AS THEANSWER", &error));
151 CHECK_ADBC(AdbcStatementExecuteQuery(&statement, &stream, &rows_affected, &error));
虽然 API 提供了行数,但 SQLite 驱动程序实际上无法提前知道结果集中有多少行,因此此值实际上将只是 -1,表示该值未知。
157 std::cout << "Got " << rows_affected << " rows" << std::endl;
我们需要一个 Arrow 实现来读取实际结果。我们可以为此使用 Arrow C++ 或 Nanoarrow。为简单起见,我们这里将使用 Nanoarrow。(此示例的 CMake 配置会在构建过程中从源代码下载并构建 Nanoarrow。)
首先我们将获取数据的 schema
170 ArrowSchema schema = {};
171 CHECK_STREAM(stream, stream.get_schema(&stream, &schema));
然后我们可以使用 Nanoarrow 打印它
174 char buf[1024] = {};
175 ArrowSchemaToString(&schema, buf, sizeof(buf), /*recursive=*/1);
176 std::cout << "Result schema: " << buf << std::endl;
现在我们可以读取数据了。数据以 Arrow 记录批次流的形式出现。
182 while (true) {
183 ArrowArray batch = {};
184 CHECK_STREAM(stream, stream.get_next(&stream, &batch));
185
186 if (batch.release == nullptr) {
187 // Stream has ended
188 break;
189 }
我们也可以使用 Nanoarrow 打印数据。
192 ArrowArrayView view = {};
193 CHECK_NANOARROW(ArrowArrayViewInitFromSchema(&view, &schema, nullptr));
194 CHECK_NANOARROW(ArrowArrayViewSetArray(&view, &batch, nullptr));
195 std::cout << "Got a batch with " << batch.length << " rows" << std::endl;
196 for (int64_t i = 0; i < batch.length; i++) {
197 std::cout << "THEANSWER[" << i
198 << "] = " << view.children[0]->buffer_views[1].data.as_int64[i]
199 << std::endl;
200 }
201 ArrowArrayViewReset(&view);
202 }
203 // Output:
204 // Got a batch with 1 rows
205 // THEANSWER[0] = 42
206
207 stream.release(&stream);
清理¶
最后,我们必须释放所有资源。
213 CHECK_ADBC(AdbcStatementRelease(&statement, &error));
214 CHECK_ADBC(AdbcConnectionRelease(&connection, &error));
215 CHECK_ADBC(AdbcDatabaseRelease(&database, &error));
216 return EXIT_SUCCESS;
217}
Got -1 rows
Result schema: struct<THEANSWER: int64>
Got a batch with 1 rows
THEANSWER[0] = 42