快速入門

食譜來源: 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

讓我們先從一些包含檔開始

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}