Files
email-tracker/external/duckdb/test/include/capi_tester.hpp
2025-10-24 19:21:19 -05:00

345 lines
8.2 KiB
C++

//===----------------------------------------------------------------------===//
//
// DuckDB
//
// capi_tester.hpp
//
//
//===----------------------------------------------------------------------===//
#pragma once
#include "catch.hpp"
#include "duckdb.h"
#include "test_helpers.hpp"
#include "duckdb/common/arrow/arrow.hpp"
#include "duckdb/common/exception.hpp"
namespace duckdb {
class CAPIDataChunk {
public:
CAPIDataChunk(duckdb_data_chunk chunk_p) : chunk(chunk_p) {
}
~CAPIDataChunk() {
duckdb_destroy_data_chunk(&chunk);
}
idx_t ColumnCount() {
return duckdb_data_chunk_get_column_count(chunk);
}
idx_t size() {
return duckdb_data_chunk_get_size(chunk);
}
duckdb_vector GetVector(idx_t col) {
return duckdb_data_chunk_get_vector(chunk, col);
}
void *GetData(idx_t col) {
return duckdb_vector_get_data(GetVector(col));
}
uint64_t *GetValidity(idx_t col) {
return duckdb_vector_get_validity(GetVector(col));
}
duckdb_vector GetListChildVector(idx_t col) {
return duckdb_list_vector_get_child(GetVector(col));
}
void *GetListChildData(idx_t col) {
return duckdb_vector_get_data(GetListChildVector(col));
}
duckdb_vector GetStructChildVector(idx_t col, idx_t idx) {
return duckdb_struct_vector_get_child(GetVector(col), idx);
}
void *GetStructChildData(idx_t col, idx_t idx) {
return duckdb_vector_get_data(GetStructChildVector(col, idx));
}
duckdb_vector GetArrayChildVector(idx_t col) {
return duckdb_array_vector_get_child(GetVector(col));
}
void *GetArrayChildData(idx_t col) {
return duckdb_vector_get_data(GetArrayChildVector(col));
}
duckdb_data_chunk GetChunk() {
return chunk;
}
private:
duckdb_data_chunk chunk;
};
class CAPIResult {
public:
CAPIResult() {
}
CAPIResult(duckdb_result result, bool success) : success(success), result(result) {
}
~CAPIResult() {
duckdb_destroy_result(&result);
}
public:
bool HasError() const {
return !success;
}
void Query(duckdb_connection connection, string query) {
success = (duckdb_query(connection, query.c_str(), &result) == DuckDBSuccess);
if (!success) {
REQUIRE(ErrorMessage() != nullptr);
REQUIRE(ErrorType() != DUCKDB_ERROR_INVALID);
}
}
void QueryPrepared(duckdb_prepared_statement statement) {
success = duckdb_execute_prepared(statement, &result) == DuckDBSuccess;
if (!success) {
REQUIRE(ErrorMessage() != nullptr);
REQUIRE(ErrorType() != DUCKDB_ERROR_INVALID);
}
}
duckdb_type ColumnType(idx_t col) {
return duckdb_column_type(&result, col);
}
idx_t ChunkCount() {
return duckdb_result_chunk_count(result);
}
unique_ptr<CAPIDataChunk> StreamChunk() {
auto chunk = duckdb_stream_fetch_chunk(result);
if (!chunk) {
return nullptr;
}
return make_uniq<CAPIDataChunk>(chunk);
}
bool IsStreaming() {
return duckdb_result_is_streaming(result);
}
unique_ptr<CAPIDataChunk> FetchChunk(idx_t chunk_idx) {
auto chunk = duckdb_result_get_chunk(result, chunk_idx);
if (!chunk) {
return nullptr;
}
return make_uniq<CAPIDataChunk>(chunk);
}
unique_ptr<CAPIDataChunk> NextChunk() {
auto chunk = duckdb_fetch_chunk(result);
if (!chunk) {
return nullptr;
}
return make_uniq<CAPIDataChunk>(chunk);
}
template <class T>
T *ColumnData(idx_t col) {
return (T *)duckdb_column_data(&result, col);
}
idx_t ColumnCount() {
return duckdb_column_count(&result);
}
idx_t row_count() {
return duckdb_row_count(&result);
}
idx_t rows_changed() {
return duckdb_rows_changed(&result);
}
template <class T>
T Fetch(idx_t col, idx_t row) {
throw NotImplementedException("Unimplemented type for fetch");
}
bool IsNull(idx_t col, idx_t row) {
auto nullmask_ptr = duckdb_nullmask_data(&result, col);
REQUIRE(duckdb_value_is_null(&result, col, row) == nullmask_ptr[row]);
return nullmask_ptr[row];
}
const char *ErrorMessage() {
return duckdb_result_error(&result);
}
duckdb_error_type ErrorType() {
return duckdb_result_error_type(&result);
}
string ColumnName(idx_t col) {
auto colname = duckdb_column_name(&result, col);
return colname ? string(colname) : string();
}
duckdb_result &InternalResult() {
return result;
}
public:
bool success = false;
protected:
duckdb_result result;
};
template <>
bool CAPIResult::Fetch(idx_t col, idx_t row);
template <>
int8_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
int16_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
int32_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
int64_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
uint8_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
uint16_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
uint32_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
uint64_t CAPIResult::Fetch(idx_t col, idx_t row);
template <>
float CAPIResult::Fetch(idx_t col, idx_t row);
template <>
double CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_decimal CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_date CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_time CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_time_ns CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_timestamp CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_timestamp_s CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_timestamp_ms CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_timestamp_ns CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_interval CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_blob CAPIResult::Fetch(idx_t col, idx_t row);
template <>
string CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_date_struct CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_time_struct CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_timestamp_struct CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_hugeint CAPIResult::Fetch(idx_t col, idx_t row);
template <>
duckdb_uhugeint CAPIResult::Fetch(idx_t col, idx_t row);
class CAPITester {
public:
CAPITester() : database(nullptr), connection(nullptr) {
}
~CAPITester() {
Cleanup();
}
void Cleanup() {
if (connection) {
duckdb_disconnect(&connection);
connection = nullptr;
}
if (database) {
duckdb_close(&database);
database = nullptr;
}
}
bool OpenDatabase(const char *path) {
Cleanup();
if (duckdb_open(path, &database) != DuckDBSuccess) {
return false;
}
return duckdb_connect(database, &connection) == DuckDBSuccess;
}
bool ChangeConnection() {
duckdb_disconnect(&connection);
return duckdb_connect(database, &connection) == DuckDBSuccess;
}
duckdb::unique_ptr<CAPIResult> Query(string query) {
D_ASSERT(connection);
auto result = make_uniq<CAPIResult>();
result->Query(connection, query);
return result;
}
duckdb::unique_ptr<CAPIResult> QueryPrepared(duckdb_prepared_statement prepared) {
D_ASSERT(connection);
auto result = make_uniq<CAPIResult>();
result->QueryPrepared(prepared);
return result;
}
duckdb_database database = nullptr;
duckdb_connection connection = nullptr;
};
struct CAPIPrepared {
CAPIPrepared() {
}
~CAPIPrepared() {
if (!prepared) {
return;
}
duckdb_destroy_prepare(&prepared);
}
bool Prepare(CAPITester &tester, const string &query) {
auto state = duckdb_prepare(tester.connection, query.c_str(), &prepared);
return state == DuckDBSuccess;
}
duckdb_prepared_statement prepared = nullptr;
};
struct CAPIPending {
CAPIPending() {
}
~CAPIPending() {
if (!pending) {
return;
}
duckdb_destroy_pending(&pending);
}
bool Pending(CAPIPrepared &prepared) {
auto state = duckdb_pending_prepared(prepared.prepared, &pending);
return state == DuckDBSuccess;
}
bool PendingStreaming(CAPIPrepared &prepared) {
auto state = duckdb_pending_prepared_streaming(prepared.prepared, &pending);
return state == DuckDBSuccess;
}
duckdb_pending_state ExecuteTask() {
REQUIRE(pending);
return duckdb_pending_execute_task(pending);
}
unique_ptr<CAPIResult> Execute() {
duckdb_result result;
auto success = duckdb_execute_pending(pending, &result) == DuckDBSuccess;
return make_uniq<CAPIResult>(result, success);
}
duckdb_pending_result pending = nullptr;
};
} // namespace duckdb
bool NO_FAIL(duckdb::CAPIResult &result);
bool NO_FAIL(duckdb::unique_ptr<duckdb::CAPIResult> result);