快速入门

食谱来源:quickstart.cc

我们将简要介绍使用 C++17 中的 SQLite 驱动程序的 ADBC 基本功能。

安装

本快速入门实际上是一个可读的 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

让我们从一些包含文件开始

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 作为构建的一部分。)

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

169  ArrowSchema schema = {};
170  CHECK_STREAM(stream, stream.get_schema(&stream, &schema));

然后我们可以使用 Nanoarrow 来打印它

173  char buf[1024] = {};
174  ArrowSchemaToString(&schema, buf, sizeof(buf), /*recursive=*/1);
175  std::cout << buf << std::endl;

现在我们可以读取数据了。数据作为 Arrow 记录批处理流返回。

179  while (true) {
180    ArrowArray batch = {};
181    CHECK_STREAM(stream, stream.get_next(&stream, &batch));
182
183    if (batch.release == nullptr) {
184      // Stream has ended
185      break;
186    }

我们也可以使用 Nanoarrow 来打印数据。

189    ArrowArrayView view = {};
190    CHECK_NANOARROW(ArrowArrayViewInitFromSchema(&view, &schema, nullptr));
191    CHECK_NANOARROW(ArrowArrayViewSetArray(&view, &batch, nullptr));
192    std::cout << "Got a batch with " << batch.length << " rows" << std::endl;
193    for (int64_t i = 0; i < batch.length; i++) {
194      std::cout << "THEANSWER[" << i
195                << "] = " << view.children[0]->buffer_views[1].data.as_int64[i]
196                << std::endl;
197    }
198    ArrowArrayViewReset(&view);
199  }
200
201  std::cout << "Finished reading result set" << std::endl;
202  stream.release(&stream);

清理

最后,我们必须释放所有资源。

208  CHECK_ADBC(AdbcStatementRelease(&statement, &error));
209  CHECK_ADBC(AdbcConnectionRelease(&connection, &error));
210  CHECK_ADBC(AdbcDatabaseRelease(&database, &error));
211  return EXIT_SUCCESS;
212}