快速入门

配方来源: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 quickstart
./quickstart

使用 ADBC

让我们从一些 include 开始

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。)

首先,我们将获取数据的模式

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}
stdout
Got -1 rows
Result schema: struct<THEANSWER: int64>
Got a batch with 1 rows
THEANSWER[0] = 42