This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 09dffb32e refactor(c/driver/framework): Separate C/C++ conversions and
error handling into minimal "base" framework (#2090)
09dffb32e is described below
commit 09dffb32e8ac8b25be3e2f31554ebe6f2e39c383
Author: Dewey Dunnington <[email protected]>
AuthorDate: Thu Aug 22 07:22:02 2024 -0300
refactor(c/driver/framework): Separate C/C++ conversions and error handling
into minimal "base" framework (#2090)
This PR removes the previous `driver/common/driver_base.h` and refactors
`driver/framework/base_driver.h` such that it can be a (almost) drop-in
replacement. This is basically to separate the nanoarrow helpers such
that framework drivers don't have to use them (or can adopt them
incrementally to improve/simplify their implementation if they would
like): driver authors can implement the low-level methods with C inputs,
implement slightly higher level C++-y methods with `Status` error
handling and inputs already converted to C++ objects, or link to the
framework. All of our C++ drivers will continue to (or should
eventually) link to/use the framework.
I am not sure the separation is perfect here and I'm happy to change
things that don't make sense!
---
.github/workflows/r-check.yml | 6 +-
c/driver/common/CMakeLists.txt | 1 -
c/driver/common/driver_base.h | 770 ---------------------
c/driver/common/driver_test.cc | 271 --------
c/driver/common/meson.build | 1 -
c/driver/framework/CMakeLists.txt | 2 +-
c/driver/framework/base_driver.cc | 178 -----
c/driver/framework/base_driver.h | 532 +++++++++++++-
c/driver/framework/base_driver_test.cc | 109 ++-
.../framework/{base_connection.h => connection.h} | 8 +-
c/driver/framework/{base_database.h => database.h} | 34 +-
c/driver/framework/meson.build | 1 -
.../framework/{base_statement.h => statement.h} | 10 +-
c/driver/sqlite/sqlite.cc | 18 +-
r/adbcdrivermanager/bootstrap.R | 68 +-
r/adbcdrivermanager/configure | 9 -
r/adbcdrivermanager/src/.gitignore | 5 +-
r/adbcdrivermanager/src/Makevars | 10 +-
r/adbcdrivermanager/src/driver_test.cc | 178 +++--
.../tests/testthat/_snaps/driver_log.md | 16 +-
.../tests/testthat/test-driver_log.R | 6 +-
r/adbcdrivermanager/tests/testthat/test-error.R | 4 +-
r/adbcdrivermanager/tests/testthat/test-options.R | 29 +-
r/adbcsqlite/src/Makevars.in | 1 -
24 files changed, 829 insertions(+), 1438 deletions(-)
diff --git a/.github/workflows/r-check.yml b/.github/workflows/r-check.yml
index 39cc965b7..cc4cd9b7c 100644
--- a/.github/workflows/r-check.yml
+++ b/.github/workflows/r-check.yml
@@ -64,15 +64,17 @@ jobs:
- name: Bootstrap R Package
run: |
pushd r/adbcdrivermanager
- Rscript bootstrap.R
+ R -e 'if (!requireNamespace("nanoarrow", quietly = TRUE))
install.packages("nanoarrow", repos = "https://cloud.r-project.org/")'
+ R CMD INSTALL . --preclean
popd
pushd "r/${{ inputs.pkg }}"
Rscript bootstrap.R
popd
+ shell: bash
- uses:
r-lib/actions/setup-r-dependencies@f4937e0dc26f9b99c969cd3e4ca943b576e7f991
with:
- extra-packages: any::rcmdcheck, local::../adbcdrivermanager
+ extra-packages: any::rcmdcheck
needs: check
working-directory: r/${{ inputs.pkg }}
diff --git a/c/driver/common/CMakeLists.txt b/c/driver/common/CMakeLists.txt
index 77999f39d..751eda363 100644
--- a/c/driver/common/CMakeLists.txt
+++ b/c/driver/common/CMakeLists.txt
@@ -29,7 +29,6 @@ if(ADBC_BUILD_TESTS)
driver-common
SOURCES
utils_test.cc
- driver_test.cc
EXTRA_LINK_LIBS
adbc_driver_common
nanoarrow)
diff --git a/c/driver/common/driver_base.h b/c/driver/common/driver_base.h
deleted file mode 100644
index 0cfb05bd3..000000000
--- a/c/driver/common/driver_base.h
+++ /dev/null
@@ -1,770 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#include <cstring>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include <arrow-adbc/adbc.h>
-
-// This file defines a developer-friendly way to create an ADBC driver,
currently intended
-// for testing the R driver manager. It handles errors, option
getting/setting, and
-// managing the export of the many C callables that compose an AdbcDriver. In
general,
-// functions or methods intended to be called from C are prefixed with "C" and
are private
-// (i.e., the public and protected methods are the only ones that driver
authors should
-// ever interact with).
-//
-// Example:
-// class MyDatabase: public DatabaseObjectBase {};
-// class MyConnection: public ConnectionObjectBase {};
-// class MyStatement: public StatementObjectbase {};
-// AdbcStatusCode VoidDriverInitFunc(int version, void* raw_driver, AdbcError*
error) {
-// return Driver<MyDatabase, MyConnection, MyStatement>::Init(
-// version, raw_driver, error);
-// }
-
-namespace adbc {
-
-namespace common {
-
-class Error {
- public:
- explicit Error(std::string message) : message_(std::move(message)) {
- std::memset(sql_state_, 0, sizeof(sql_state_));
- }
-
- explicit Error(const char* message) : Error(std::string(message)) {}
-
- Error(std::string message, std::vector<std::pair<std::string, std::string>>
details)
- : message_(std::move(message)), details_(std::move(details)) {
- std::memset(sql_state_, 0, sizeof(sql_state_));
- }
-
- void AddDetail(std::string key, std::string value) {
- details_.push_back({std::move(key), std::move(value)});
- }
-
- void ToAdbc(AdbcError* adbc_error, AdbcDriver* driver = nullptr) {
- if (adbc_error == nullptr) {
- return;
- }
-
- if (adbc_error->vendor_code == ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA) {
- auto error_owned_by_adbc_error =
- new Error(std::move(message_), std::move(details_));
- adbc_error->message =
- const_cast<char*>(error_owned_by_adbc_error->message_.c_str());
- adbc_error->private_data = error_owned_by_adbc_error;
- adbc_error->private_driver = driver;
- } else {
- adbc_error->message =
reinterpret_cast<char*>(std::malloc(message_.size() + 1));
- if (adbc_error->message != nullptr) {
- std::memcpy(adbc_error->message, message_.c_str(), message_.size() +
1);
- }
- }
-
- std::memcpy(adbc_error->sqlstate, sql_state_, sizeof(sql_state_));
- adbc_error->release = &CRelease;
- }
-
- private:
- std::string message_;
- std::vector<std::pair<std::string, std::string>> details_;
- char sql_state_[5];
-
- // Let the Driver use these to expose C callables wrapping option
setters/getters
- template <typename DatabaseT, typename ConnectionT, typename StatementT>
- friend class Driver;
-
- int CDetailCount() const { return details_.size(); }
-
- AdbcErrorDetail CDetail(int index) const {
- const auto& detail = details_[index];
- return {detail.first.c_str(), reinterpret_cast<const
uint8_t*>(detail.second.data()),
- detail.second.size() + 1};
- }
-
- static void CRelease(AdbcError* error) {
- if (error->vendor_code == ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA) {
- auto error_obj = reinterpret_cast<Error*>(error->private_data);
- delete error_obj;
- } else {
- std::free(error->message);
- }
-
- std::memset(error, 0, sizeof(AdbcError));
- }
-};
-
-// Variant that handles the option types that can be get/set by databases,
-// connections, and statements. It currently does not attempt conversion
-// (i.e., getting a double option as a string).
-class Option {
- public:
- enum Type { TYPE_MISSING, TYPE_STRING, TYPE_BYTES, TYPE_INT, TYPE_DOUBLE };
-
- Option() : type_(TYPE_MISSING) {}
- explicit Option(const std::string& value) : type_(TYPE_STRING),
value_string_(value) {}
- explicit Option(const std::vector<uint8_t>& value)
- : type_(TYPE_BYTES), value_bytes_(value) {}
- explicit Option(double value) : type_(TYPE_DOUBLE), value_double_(value) {}
- explicit Option(int64_t value) : type_(TYPE_INT), value_int_(value) {}
-
- Type type() const { return type_; }
-
- const std::string& GetStringUnsafe() const { return value_string_; }
-
- const std::vector<uint8_t>& GetBytesUnsafe() const { return value_bytes_; }
-
- int64_t GetIntUnsafe() const { return value_int_; }
-
- double GetDoubleUnsafe() const { return value_double_; }
-
- private:
- Type type_;
- std::string value_string_;
- std::vector<uint8_t> value_bytes_;
- double value_double_;
- int64_t value_int_;
-
- // Methods used by trampolines to export option values in C below
- friend class ObjectBase;
-
- AdbcStatusCode CGet(char* out, size_t* length) const {
- switch (type_) {
- case TYPE_STRING: {
- const std::string& value = GetStringUnsafe();
- size_t value_size_with_terminator = value.size() + 1;
- if (*length < value_size_with_terminator) {
- *length = value_size_with_terminator;
- } else {
- memcpy(out, value.data(), value_size_with_terminator);
- }
-
- return ADBC_STATUS_OK;
- }
- default:
- return ADBC_STATUS_NOT_FOUND;
- }
- }
-
- AdbcStatusCode CGet(uint8_t* out, size_t* length) const {
- switch (type_) {
- case TYPE_BYTES: {
- const std::vector<uint8_t>& value = GetBytesUnsafe();
- if (*length < value.size()) {
- *length = value.size();
- } else {
- memcpy(out, value.data(), value.size());
- }
-
- return ADBC_STATUS_OK;
- }
- default:
- return ADBC_STATUS_NOT_FOUND;
- }
- }
-
- AdbcStatusCode CGet(int64_t* value) const {
- switch (type_) {
- case TYPE_INT:
- *value = GetIntUnsafe();
- return ADBC_STATUS_OK;
- default:
- return ADBC_STATUS_NOT_FOUND;
- }
- }
-
- AdbcStatusCode CGet(double* value) const {
- switch (type_) {
- case TYPE_DOUBLE:
- *value = GetDoubleUnsafe();
- return ADBC_STATUS_OK;
- default:
- return ADBC_STATUS_NOT_FOUND;
- }
- }
-};
-
-// Base class for private_data of AdbcDatabase, AdbcConnection, and
AdbcStatement
-// This class handles option setting and getting.
-class ObjectBase {
- public:
- ObjectBase() : driver_(nullptr) {}
-
- virtual ~ObjectBase() {}
-
- // Driver authors can override this method to reject options that are not
supported or
- // that are set at a time not supported by the driver (e.g., to reject
options that are
- // set after Init() is called if this is not supported).
- virtual AdbcStatusCode SetOption(const std::string& key, const Option&
value) {
- options_[key] = value;
- return ADBC_STATUS_OK;
- }
-
- // Called After zero or more SetOption() calls. The parent is the
private_data of
- // the AdbcDriver, AdbcDatabase, or AdbcConnection when initializing a
subclass of
- // DatabaseObjectBase, ConnectionObjectBase, and StatementObjectBase
(respectively).
- // For example, if you have defined Driver<MyDatabase, MyConnection,
MyStatement>,
- // you can reinterpret_cast<MyDatabase>(parent) in MyConnection::Init().
- virtual AdbcStatusCode Init(void* parent, AdbcError* error) { return
ADBC_STATUS_OK; }
-
- // Called when the corresponding AdbcXXXRelease() function is invoked from C.
- // Driver authors can override this method to return an error if the object
is
- // not in a valid state (e.g., if a connection has open statements) or to
clean
- // up resources when resource cleanup could fail. Resource cleanup that
cannot fail
- // (e.g., releasing memory) should generally be handled in the deleter.
- virtual AdbcStatusCode Release(AdbcError* error) { return ADBC_STATUS_OK; }
-
- // Get an option that was previously set, providing an optional default
value.
- virtual const Option& GetOption(const std::string& key,
- const Option& default_value = Option())
const {
- auto result = options_.find(key);
- if (result == options_.end()) {
- return default_value;
- } else {
- return result->second;
- }
- }
-
- protected:
- // Needed to export errors using Error::ToAdbc() that use 1.1.0 extensions
- // (i.e., error details). This will be nullptr before Init() is called.
- AdbcDriver* driver() const { return driver_; }
-
- private:
- AdbcDriver* driver_;
- std::unordered_map<std::string, Option> options_;
-
- // Let the Driver use these to expose C callables wrapping option
setters/getters
- template <typename DatabaseT, typename ConnectionT, typename StatementT>
- friend class Driver;
-
- // The AdbcDriver* struct is set right before Init() is called by the Driver
- // trampoline.
- void set_driver(AdbcDriver* driver) { driver_ = driver; }
-
- template <typename T>
- AdbcStatusCode CSetOption(const char* key, T value, AdbcError* error) {
- Option option(value);
- return SetOption(key, option);
- }
-
- AdbcStatusCode CSetOptionBytes(const char* key, const uint8_t* value, size_t
length,
- AdbcError* error) {
- std::vector<uint8_t> cppvalue(value, value + length);
- Option option(cppvalue);
- return SetOption(key, option);
- }
-
- template <typename T>
- AdbcStatusCode CGetOptionStringLike(const char* key, T* value, size_t*
length,
- AdbcError* error) const {
- Option result = GetOption(key);
- if (result.type() == Option::TYPE_MISSING) {
- InitErrorNotFound(key, error);
- return ADBC_STATUS_NOT_FOUND;
- } else {
- AdbcStatusCode status = result.CGet(value, length);
- if (status != ADBC_STATUS_OK) {
- InitErrorWrongType(key, error);
- }
-
- return status;
- }
- }
-
- template <typename T>
- AdbcStatusCode CGetOptionNumeric(const char* key, T* value, AdbcError*
error) const {
- Option result = GetOption(key);
- if (result.type() == Option::TYPE_MISSING) {
- InitErrorNotFound(key, error);
- return ADBC_STATUS_NOT_FOUND;
- } else {
- AdbcStatusCode status = result.CGet(value);
- if (status != ADBC_STATUS_OK) {
- InitErrorWrongType(key, error);
- }
-
- return status;
- }
- }
-
- void InitErrorNotFound(const char* key, AdbcError* error) const {
- std::stringstream msg_builder;
- msg_builder << "Option not found for key '" << key << "'";
- Error cpperror(msg_builder.str());
- cpperror.AddDetail("adbc.driver_base.option_key", key);
- cpperror.ToAdbc(error, driver());
- }
-
- void InitErrorWrongType(const char* key, AdbcError* error) const {
- std::stringstream msg_builder;
- msg_builder << "Wrong type requested for option key '" << key << "'";
- Error cpperror(msg_builder.str());
- cpperror.AddDetail("adbc.driver_base.option_key", key);
- cpperror.ToAdbc(error, driver());
- }
-};
-
-// Driver authors can subclass DatabaseObjectBase to track driver-specific
-// state pertaining to the AdbcDatbase. The private_data member of an
-// AdbcDatabase initialized by the driver will be a pointer to the
-// subclass of DatbaseObjectBase.
-class DatabaseObjectBase : public ObjectBase {
- public:
- // (there are no database functions other than option getting/setting)
-};
-
-// Driver authors can subclass ConnectionObjectBase to track driver-specific
-// state pertaining to the AdbcConnection. The private_data member of an
-// AdbcConnection initialized by the driver will be a pointer to the
-// subclass of ConnectionObjectBase. Driver authors can override methods to
-// implement the corresponding ConnectionXXX driver methods.
-class ConnectionObjectBase : public ObjectBase {
- public:
- virtual AdbcStatusCode Commit(AdbcError* error) { return
ADBC_STATUS_NOT_IMPLEMENTED; }
-
- virtual AdbcStatusCode GetInfo(const uint32_t* info_codes, size_t
info_codes_length,
- ArrowArrayStream* out, AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode GetObjects(int depth, const char* catalog, const
char* db_schema,
- const char* table_name, const char**
table_type,
- const char* column_name, ArrowArrayStream*
out,
- AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode GetTableSchema(const char* catalog, const char*
db_schema,
- const char* table_name, ArrowSchema*
schema,
- AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode GetTableTypes(ArrowArrayStream* out, AdbcError*
error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode ReadPartition(const uint8_t* serialized_partition,
- size_t serialized_length,
ArrowArrayStream* out,
- AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode Rollback(AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode Cancel(AdbcError* error) { return
ADBC_STATUS_NOT_IMPLEMENTED; }
-
- virtual AdbcStatusCode GetStatistics(const char* catalog, const char*
db_schema,
- const char* table_name, char
approximate,
- ArrowArrayStream* out, AdbcError*
error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode GetStatisticNames(ArrowArrayStream* out, AdbcError*
error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-};
-
-// Driver authors can subclass StatementObjectBase to track driver-specific
-// state pertaining to the AdbcStatement. The private_data member of an
-// AdbcStatement initialized by the driver will be a pointer to the
-// subclass of StatementObjectBase. Driver authors can override methods to
-// implement the corresponding StatementXXX driver methods.
-class StatementObjectBase : public ObjectBase {
- public:
- virtual AdbcStatusCode ExecuteQuery(ArrowArrayStream* stream, int64_t*
rows_affected,
- AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode ExecuteSchema(ArrowSchema* schema, AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode Prepare(AdbcError* error) { return
ADBC_STATUS_NOT_IMPLEMENTED; }
-
- virtual AdbcStatusCode SetSqlQuery(const char* query, AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode SetSubstraitPlan(const uint8_t* plan, size_t length,
- AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode Bind(ArrowArray* values, ArrowSchema* schema,
AdbcError* error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode BindStream(ArrowArrayStream* stream, AdbcError*
error) {
- return ADBC_STATUS_NOT_IMPLEMENTED;
- }
-
- virtual AdbcStatusCode Cancel(AdbcError* error) { return
ADBC_STATUS_NOT_IMPLEMENTED; }
-};
-
-// Driver authors can declare a template specialization of the Driver class
-// and use it to provide their driver init function. It is possible, but
-// rarely useful, to subclass a driver.
-template <typename DatabaseT, typename ConnectionT, typename StatementT>
-class Driver {
- public:
- static AdbcStatusCode Init(int version, void* raw_driver, AdbcError* error) {
- if (version != ADBC_VERSION_1_1_0) return ADBC_STATUS_NOT_IMPLEMENTED;
- AdbcDriver* driver = (AdbcDriver*)raw_driver;
- std::memset(driver, 0, sizeof(AdbcDriver));
-
- // Driver lifecycle
- driver->private_data = new Driver();
- driver->release = &CDriverRelease;
-
- // Driver functions
- driver->ErrorGetDetailCount = &CErrorGetDetailCount;
- driver->ErrorGetDetail = &CErrorGetDetail;
-
- // Database lifecycle
- driver->DatabaseNew = &CNew<AdbcDatabase, DatabaseT>;
- driver->DatabaseInit = &CDatabaseInit;
- driver->DatabaseRelease = &CRelease<AdbcDatabase, DatabaseT>;
-
- // Database functions
- driver->DatabaseSetOption = &CSetOption<AdbcDatabase, DatabaseT>;
- driver->DatabaseSetOptionBytes = &CSetOptionBytes<AdbcDatabase, DatabaseT>;
- driver->DatabaseSetOptionInt = &CSetOptionInt<AdbcDatabase, DatabaseT>;
- driver->DatabaseSetOptionDouble = &CSetOptionDouble<AdbcDatabase,
DatabaseT>;
- driver->DatabaseGetOption = &CGetOption<AdbcDatabase, DatabaseT>;
- driver->DatabaseGetOptionBytes = &CGetOptionBytes<AdbcDatabase, DatabaseT>;
- driver->DatabaseGetOptionInt = &CGetOptionInt<AdbcDatabase, DatabaseT>;
- driver->DatabaseGetOptionDouble = &CGetOptionDouble<AdbcDatabase,
DatabaseT>;
-
- // Connection lifecycle
- driver->ConnectionNew = &CNew<AdbcConnection, ConnectionT>;
- driver->ConnectionInit = &CConnectionInit;
- driver->ConnectionRelease = &CRelease<AdbcConnection, ConnectionT>;
-
- // Connection functions
- driver->ConnectionSetOption = &CSetOption<AdbcConnection, ConnectionT>;
- driver->ConnectionSetOptionBytes = &CSetOptionBytes<AdbcConnection,
ConnectionT>;
- driver->ConnectionSetOptionInt = &CSetOptionInt<AdbcConnection,
ConnectionT>;
- driver->ConnectionSetOptionDouble = &CSetOptionDouble<AdbcConnection,
ConnectionT>;
- driver->ConnectionGetOption = &CGetOption<AdbcConnection, ConnectionT>;
- driver->ConnectionGetOptionBytes = &CGetOptionBytes<AdbcConnection,
ConnectionT>;
- driver->ConnectionGetOptionInt = &CGetOptionInt<AdbcConnection,
ConnectionT>;
- driver->ConnectionGetOptionDouble = &CGetOptionDouble<AdbcConnection,
ConnectionT>;
- driver->ConnectionCommit = &CConnectionCommit;
- driver->ConnectionGetInfo = &CConnectionGetInfo;
- driver->ConnectionGetObjects = &CConnectionGetObjects;
- driver->ConnectionGetTableSchema = &CConnectionGetTableSchema;
- driver->ConnectionGetTableTypes = &CConnectionGetTableTypes;
- driver->ConnectionReadPartition = &CConnectionReadPartition;
- driver->ConnectionRollback = &CConnectionRollback;
- driver->ConnectionCancel = &CConnectionCancel;
- driver->ConnectionGetStatistics = &CConnectionGetStatistics;
- driver->ConnectionGetStatisticNames = &CConnectionGetStatisticNames;
-
- // Statement lifecycle
- driver->StatementNew = &CStatementNew;
- driver->StatementRelease = &CRelease<AdbcStatement, StatementT>;
-
- // Statement functions
- driver->StatementSetOption = &CSetOption<AdbcStatement, StatementT>;
- driver->StatementSetOptionBytes = &CSetOptionBytes<AdbcStatement,
StatementT>;
- driver->StatementSetOptionInt = &CSetOptionInt<AdbcStatement, StatementT>;
- driver->StatementSetOptionDouble = &CSetOptionDouble<AdbcStatement,
StatementT>;
- driver->StatementGetOption = &CGetOption<AdbcStatement, StatementT>;
- driver->StatementGetOptionBytes = &CGetOptionBytes<AdbcStatement,
StatementT>;
- driver->StatementGetOptionInt = &CGetOptionInt<AdbcStatement, StatementT>;
- driver->StatementGetOptionDouble = &CGetOptionDouble<AdbcStatement,
StatementT>;
-
- driver->StatementExecuteQuery = &CStatementExecuteQuery;
- driver->StatementExecuteSchema = &CStatementExecuteSchema;
- driver->StatementPrepare = &CStatementPrepare;
- driver->StatementSetSqlQuery = &CStatementSetSqlQuery;
- driver->StatementSetSubstraitPlan = &CStatementSetSubstraitPlan;
- driver->StatementBind = &CStatementBind;
- driver->StatementBindStream = &CStatementBindStream;
- driver->StatementCancel = &CStatementCancel;
-
- return ADBC_STATUS_OK;
- }
-
- private:
- // Driver trampolines
- static AdbcStatusCode CDriverRelease(AdbcDriver* driver, AdbcError* error) {
- auto driver_private = reinterpret_cast<Driver*>(driver->private_data);
- delete driver_private;
- driver->private_data = nullptr;
- return ADBC_STATUS_OK;
- }
-
- static int CErrorGetDetailCount(const AdbcError* error) {
- if (error->vendor_code != ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA) {
- return 0;
- }
-
- auto error_obj = reinterpret_cast<Error*>(error->private_data);
- return error_obj->CDetailCount();
- }
-
- static AdbcErrorDetail CErrorGetDetail(const AdbcError* error, int index) {
- auto error_obj = reinterpret_cast<Error*>(error->private_data);
- return error_obj->CDetail(index);
- }
-
- // Templatable trampolines
- template <typename T, typename ObjectT>
- static AdbcStatusCode CNew(T* obj, AdbcError* error) {
- auto private_data = new ObjectT();
- obj->private_data = private_data;
- return ADBC_STATUS_OK;
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CRelease(T* obj, AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- AdbcStatusCode result = private_data->Release(error);
- if (result != ADBC_STATUS_OK) {
- return result;
- }
-
- delete private_data;
- obj->private_data = nullptr;
- return ADBC_STATUS_OK;
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CSetOption(T* obj, const char* key, const char* value,
- AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CSetOption<>(key, value, error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CSetOptionBytes(T* obj, const char* key, const
uint8_t* value,
- size_t length, AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->CSetOptionBytes(key, value, length, error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CSetOptionInt(T* obj, const char* key, int64_t value,
- AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CSetOption<>(key, value, error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CSetOptionDouble(T* obj, const char* key, double value,
- AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CSetOption<>(key, value, error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CGetOption(T* obj, const char* key, char* value,
size_t* length,
- AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CGetOptionStringLike<>(key, value, length,
error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CGetOptionBytes(T* obj, const char* key, uint8_t*
value,
- size_t* length, AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CGetOptionStringLike<>(key, value, length,
error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CGetOptionInt(T* obj, const char* key, int64_t* value,
- AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CGetOptionNumeric<>(key, value, error);
- }
-
- template <typename T, typename ObjectT>
- static AdbcStatusCode CGetOptionDouble(T* obj, const char* key, double*
value,
- AdbcError* error) {
- auto private_data = reinterpret_cast<ObjectT*>(obj->private_data);
- return private_data->template CGetOptionNumeric<>(key, value, error);
- }
-
- // Database trampolines
- static AdbcStatusCode CDatabaseInit(AdbcDatabase* database, AdbcError*
error) {
- auto private_data = reinterpret_cast<DatabaseT*>(database->private_data);
- private_data->set_driver(database->private_driver);
- return private_data->Init(database->private_driver->private_data, error);
- }
-
- // Connection trampolines
- static AdbcStatusCode CConnectionInit(AdbcConnection* connection,
- AdbcDatabase* database, AdbcError*
error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- private_data->set_driver(connection->private_driver);
- return private_data->Init(database->private_data, error);
- }
-
- static AdbcStatusCode CConnectionCancel(AdbcConnection* connection,
AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->Cancel(error);
- }
-
- static AdbcStatusCode CConnectionGetInfo(AdbcConnection* connection,
- const uint32_t* info_codes,
- size_t info_codes_length,
- ArrowArrayStream* out, AdbcError*
error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->GetInfo(info_codes, info_codes_length, out, error);
- }
-
- static AdbcStatusCode CConnectionGetObjects(AdbcConnection* connection, int
depth,
- const char* catalog, const char*
db_schema,
- const char* table_name,
- const char** table_type,
- const char* column_name,
- ArrowArrayStream* out,
AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->GetObjects(depth, catalog, db_schema, table_name,
table_type,
- column_name, out, error);
- }
-
- static AdbcStatusCode CConnectionGetStatistics(
- AdbcConnection* connection, const char* catalog, const char* db_schema,
- const char* table_name, char approximate, ArrowArrayStream* out,
AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->GetStatistics(catalog, db_schema, table_name,
approximate, out,
- error);
- }
-
- static AdbcStatusCode CConnectionGetStatisticNames(AdbcConnection*
connection,
- ArrowArrayStream* out,
- AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->GetStatisticNames(out, error);
- }
-
- static AdbcStatusCode CConnectionGetTableSchema(AdbcConnection* connection,
- const char* catalog,
- const char* db_schema,
- const char* table_name,
- ArrowSchema* schema,
AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->GetTableSchema(catalog, db_schema, table_name,
schema, error);
- }
-
- static AdbcStatusCode CConnectionGetTableTypes(AdbcConnection* connection,
- ArrowArrayStream* out,
- AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->GetTableTypes(out, error);
- }
-
- static AdbcStatusCode CConnectionReadPartition(AdbcConnection* connection,
- const uint8_t*
serialized_partition,
- size_t serialized_length,
- ArrowArrayStream* out,
- AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->ReadPartition(serialized_partition,
serialized_length, out,
- error);
- }
-
- static AdbcStatusCode CConnectionCommit(AdbcConnection* connection,
AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->Commit(error);
- }
-
- static AdbcStatusCode CConnectionRollback(AdbcConnection* connection,
- AdbcError* error) {
- auto private_data =
reinterpret_cast<ConnectionT*>(connection->private_data);
- return private_data->Rollback(error);
- }
-
- // Statement trampolines
- static AdbcStatusCode CStatementNew(AdbcConnection* connection,
- AdbcStatement* statement, AdbcError*
error) {
- auto private_data = new StatementT();
- private_data->set_driver(connection->private_driver);
- AdbcStatusCode status = private_data->Init(connection->private_data,
error);
- if (status != ADBC_STATUS_OK) {
- delete private_data;
- }
-
- statement->private_data = private_data;
- return ADBC_STATUS_OK;
- }
-
- static AdbcStatusCode CStatementExecuteQuery(AdbcStatement* statement,
- ArrowArrayStream* stream,
- int64_t* rows_affected,
AdbcError* error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->ExecuteQuery(stream, rows_affected, error);
- }
-
- static AdbcStatusCode CStatementExecuteSchema(AdbcStatement* statement,
- ArrowSchema* schema,
AdbcError* error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->ExecuteSchema(schema, error);
- }
-
- static AdbcStatusCode CStatementPrepare(AdbcStatement* statement, AdbcError*
error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->Prepare(error);
- }
-
- static AdbcStatusCode CStatementSetSqlQuery(AdbcStatement* statement, const
char* query,
- AdbcError* error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->SetSqlQuery(query, error);
- }
-
- static AdbcStatusCode CStatementSetSubstraitPlan(AdbcStatement* statement,
- const uint8_t* plan, size_t
length,
- AdbcError* error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->SetSubstraitPlan(plan, length, error);
- }
-
- static AdbcStatusCode CStatementBind(AdbcStatement* statement, ArrowArray*
values,
- ArrowSchema* schema, AdbcError* error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->Bind(values, schema, error);
- }
-
- static AdbcStatusCode CStatementBindStream(AdbcStatement* statement,
- ArrowArrayStream* stream,
AdbcError* error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->BindStream(stream, error);
- }
-
- static AdbcStatusCode CStatementCancel(AdbcStatement* statement, AdbcError*
error) {
- auto private_data = reinterpret_cast<StatementT*>(statement->private_data);
- return private_data->Cancel(error);
- }
-};
-
-} // namespace common
-
-} // namespace adbc
diff --git a/c/driver/common/driver_test.cc b/c/driver/common/driver_test.cc
deleted file mode 100644
index 85d24826c..000000000
--- a/c/driver/common/driver_test.cc
+++ /dev/null
@@ -1,271 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#include <gtest/gtest.h>
-#include <cstring>
-
-#include <arrow-adbc/adbc.h>
-#include "driver_base.h"
-
-// Self-contained version of the Handle
-static inline void clean_up(AdbcDriver* ptr) { ptr->release(ptr, nullptr); }
-
-static inline void clean_up(AdbcDatabase* ptr) {
- ptr->private_driver->DatabaseRelease(ptr, nullptr);
-}
-
-static inline void clean_up(AdbcConnection* ptr) {
- ptr->private_driver->ConnectionRelease(ptr, nullptr);
-}
-
-static inline void clean_up(AdbcStatement* ptr) {
- ptr->private_driver->StatementRelease(ptr, nullptr);
-}
-
-static inline void clean_up(AdbcError* ptr) {
- if (ptr->release != nullptr) {
- ptr->release(ptr);
- }
-}
-
-template <typename T>
-class Handle {
- public:
- explicit Handle(T* value) : value_(value) {}
-
- ~Handle() { clean_up(value_); }
-
- private:
- T* value_;
-};
-
-class VoidDatabase : public adbc::common::DatabaseObjectBase {};
-
-class VoidConnection : public adbc::common::ConnectionObjectBase {};
-
-class VoidStatement : public adbc::common::StatementObjectBase {};
-
-using VoidDriver = adbc::common::Driver<VoidDatabase, VoidConnection,
VoidStatement>;
-
-AdbcStatusCode VoidDriverInitFunc(int version, void* raw_driver, AdbcError*
error) {
- return VoidDriver::Init(version, raw_driver, error);
-}
-
-TEST(TestDriverBase, TestVoidDriverOptions) {
- // Test the get/set option implementation in the base driver
- struct AdbcDriver driver;
- memset(&driver, 0, sizeof(driver));
- ASSERT_EQ(VoidDriverInitFunc(ADBC_VERSION_1_1_0, &driver, nullptr),
ADBC_STATUS_OK);
- Handle<AdbcDriver> driver_handle(&driver);
-
- struct AdbcDatabase database;
- memset(&database, 0, sizeof(database));
- ASSERT_EQ(driver.DatabaseNew(&database, nullptr), ADBC_STATUS_OK);
- database.private_driver = &driver;
- Handle<AdbcDatabase> database_handle(&database);
- ASSERT_EQ(driver.DatabaseInit(&database, nullptr), ADBC_STATUS_OK);
-
- std::vector<char> opt_string;
- std::vector<uint8_t> opt_bytes;
- size_t opt_size = 0;
- int64_t opt_int = 0;
- double opt_double = 0;
-
- // Check return codes without an error pointer for non-existent keys
- ASSERT_EQ(driver.DatabaseGetOption(&database, "key_that_does_not_exist",
nullptr,
- &opt_size, nullptr),
- ADBC_STATUS_NOT_FOUND);
- ASSERT_EQ(driver.DatabaseGetOptionBytes(&database,
"key_that_does_not_exist", nullptr,
- &opt_size, nullptr),
- ADBC_STATUS_NOT_FOUND);
- ASSERT_EQ(driver.DatabaseGetOptionInt(&database, "key_that_does_not_exist",
&opt_int,
- nullptr),
- ADBC_STATUS_NOT_FOUND);
- ASSERT_EQ(driver.DatabaseGetOptionDouble(&database,
"key_that_does_not_exist",
- &opt_double, nullptr),
- ADBC_STATUS_NOT_FOUND);
-
- // Check set/get for string
- ASSERT_EQ(driver.DatabaseSetOption(&database, "key_string", "value_string",
nullptr),
- ADBC_STATUS_OK);
- opt_size = 0;
- ASSERT_EQ(
- driver.DatabaseGetOption(&database, "key_string", nullptr, &opt_size,
nullptr),
- ADBC_STATUS_OK);
- ASSERT_EQ(opt_size, strlen("value_string") + 1);
- opt_string.resize(opt_size);
- ASSERT_EQ(driver.DatabaseGetOption(&database, "key_string",
opt_string.data(),
- &opt_size, nullptr),
- ADBC_STATUS_OK);
-
- // Check set/get for bytes
- const uint8_t test_bytes[] = {0x01, 0x02, 0x03};
- ASSERT_EQ(driver.DatabaseSetOptionBytes(&database, "key_bytes", test_bytes,
- sizeof(test_bytes), nullptr),
- ADBC_STATUS_OK);
- opt_size = 0;
- ASSERT_EQ(
- driver.DatabaseGetOptionBytes(&database, "key_bytes", nullptr,
&opt_size, nullptr),
- ADBC_STATUS_OK);
- ASSERT_EQ(opt_size, sizeof(test_bytes));
- opt_bytes.resize(opt_size);
- ASSERT_EQ(driver.DatabaseGetOptionBytes(&database, "key_bytes",
opt_bytes.data(),
- &opt_size, nullptr),
- ADBC_STATUS_OK);
-
- // Check set/get for int
- ASSERT_EQ(driver.DatabaseSetOptionInt(&database, "key_int", 1234, nullptr),
- ADBC_STATUS_OK);
- ASSERT_EQ(driver.DatabaseGetOptionInt(&database, "key_int", &opt_int,
nullptr),
- ADBC_STATUS_OK);
- ASSERT_EQ(opt_int, 1234);
-
- // Check set/get for double
- ASSERT_EQ(driver.DatabaseSetOptionDouble(&database, "key_double", 1234.5,
nullptr),
- ADBC_STATUS_OK);
- ASSERT_EQ(driver.DatabaseGetOptionDouble(&database, "key_double",
&opt_double, nullptr),
- ADBC_STATUS_OK);
- ASSERT_EQ(opt_double, 1234.5);
-
- // Check error code for getting a key of an incorrect type
- opt_size = 0;
- ASSERT_EQ(driver.DatabaseGetOption(&database, "key_bytes", nullptr,
&opt_size, nullptr),
- ADBC_STATUS_NOT_FOUND);
- ASSERT_EQ(
- driver.DatabaseGetOptionBytes(&database, "key_string", nullptr,
&opt_size, nullptr),
- ADBC_STATUS_NOT_FOUND);
- ASSERT_EQ(driver.DatabaseGetOptionInt(&database, "key_bytes", &opt_int,
nullptr),
- ADBC_STATUS_NOT_FOUND);
- ASSERT_EQ(driver.DatabaseGetOptionDouble(&database, "key_bytes",
&opt_double, nullptr),
- ADBC_STATUS_NOT_FOUND);
-}
-
-TEST(TestDriverBase, TestVoidDriverError) {
- // Test the extended error detail implementation in the base driver
- struct AdbcDriver driver;
- memset(&driver, 0, sizeof(driver));
- ASSERT_EQ(VoidDriverInitFunc(ADBC_VERSION_1_1_0, &driver, nullptr),
ADBC_STATUS_OK);
- Handle<AdbcDriver> driver_handle(&driver);
-
- struct AdbcDatabase database;
- memset(&database, 0, sizeof(database));
- ASSERT_EQ(driver.DatabaseNew(&database, nullptr), ADBC_STATUS_OK);
- database.private_driver = &driver;
- Handle<AdbcDatabase> database_handle(&database);
- ASSERT_EQ(driver.DatabaseInit(&database, nullptr), ADBC_STATUS_OK);
-
- struct AdbcError error;
- memset(&error, 0, sizeof(error));
- Handle<AdbcError> error_handle(&error);
- size_t opt_size = 0;
-
- // With zero-initialized error, should populate message but not details
- ASSERT_EQ(driver.DatabaseGetOption(&database, "key_does_not_exist", nullptr,
&opt_size,
- &error),
- ADBC_STATUS_NOT_FOUND);
- EXPECT_EQ(error.vendor_code, 0);
- EXPECT_STREQ(error.message, "Option not found for key 'key_does_not_exist'");
- EXPECT_EQ(error.private_data, nullptr);
- EXPECT_EQ(error.private_driver, nullptr);
-
- // Release callback implementation should reset callback
- error.release(&error);
- ASSERT_EQ(error.release, nullptr);
-
- // With the vendor code pre-set, should populate a version with details
- memset(&error, 0, sizeof(error));
- error.vendor_code = ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA;
-
- ASSERT_EQ(driver.DatabaseGetOption(&database, "key_does_not_exist", nullptr,
&opt_size,
- &error),
- ADBC_STATUS_NOT_FOUND);
- EXPECT_NE(error.private_data, nullptr);
- EXPECT_EQ(error.private_driver, &driver);
-
- ASSERT_EQ(error.private_driver->ErrorGetDetailCount(&error), 1);
-
- struct AdbcErrorDetail detail = error.private_driver->ErrorGetDetail(&error,
0);
- ASSERT_STREQ(detail.key, "adbc.driver_base.option_key");
- ASSERT_EQ(detail.value_length, strlen("key_does_not_exist") + 1);
- ASSERT_STREQ(reinterpret_cast<const char*>(detail.value),
"key_does_not_exist");
-}
-
-TEST(TestDriverBase, TestVoidDriverMethods) {
- struct AdbcDriver driver;
- memset(&driver, 0, sizeof(driver));
- ASSERT_EQ(VoidDriverInitFunc(ADBC_VERSION_1_1_0, &driver, nullptr),
ADBC_STATUS_OK);
- Handle<AdbcDriver> driver_handle(&driver);
-
- // Database methods are only option related
- struct AdbcDatabase database;
- memset(&database, 0, sizeof(database));
- ASSERT_EQ(driver.DatabaseNew(&database, nullptr), ADBC_STATUS_OK);
- database.private_driver = &driver;
- Handle<AdbcDatabase> database_handle(&database);
- ASSERT_EQ(driver.DatabaseInit(&database, nullptr), ADBC_STATUS_OK);
-
- // Test connection methods
- struct AdbcConnection connection;
- memset(&connection, 0, sizeof(connection));
- ASSERT_EQ(driver.ConnectionNew(&connection, nullptr), ADBC_STATUS_OK);
- connection.private_driver = &driver;
- Handle<AdbcConnection> connection_handle(&connection);
- ASSERT_EQ(driver.ConnectionInit(&connection, &database, nullptr),
ADBC_STATUS_OK);
-
- EXPECT_EQ(driver.ConnectionCommit(&connection, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionGetInfo(&connection, nullptr, 0, nullptr,
nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionGetObjects(&connection, 0, nullptr, nullptr, 0,
nullptr,
- nullptr, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionGetTableSchema(&connection, nullptr, nullptr,
nullptr,
- nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionGetTableTypes(&connection, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionReadPartition(&connection, nullptr, 0, nullptr,
nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionRollback(&connection, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionCancel(&connection, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionGetStatistics(&connection, nullptr, nullptr,
nullptr, 0,
- nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.ConnectionGetStatisticNames(&connection, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
-
- // Test statement methods
- struct AdbcStatement statement;
- memset(&statement, 0, sizeof(statement));
- ASSERT_EQ(driver.StatementNew(&connection, &statement, nullptr),
ADBC_STATUS_OK);
- statement.private_driver = &driver;
- Handle<AdbcStatement> statement_handle(&statement);
-
- EXPECT_EQ(driver.StatementExecuteQuery(&statement, nullptr, nullptr,
nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementExecuteSchema(&statement, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementPrepare(&statement, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementSetSqlQuery(&statement, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementSetSubstraitPlan(&statement, nullptr, 0, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementBind(&statement, nullptr, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementBindStream(&statement, nullptr, nullptr),
- ADBC_STATUS_NOT_IMPLEMENTED);
- EXPECT_EQ(driver.StatementCancel(&statement, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
-}
diff --git a/c/driver/common/meson.build b/c/driver/common/meson.build
index a0999431c..b1423f0e5 100644
--- a/c/driver/common/meson.build
+++ b/c/driver/common/meson.build
@@ -27,7 +27,6 @@ if get_option('tests')
exc = executable(
'adbc-driver-common-test',
'utils_test.cc',
- 'driver_test.cc',
include_directories: [include_dir],
link_with: [adbc_common_lib],
dependencies: [nanoarrow_dep, gtest_main_dep, gmock_dep],
diff --git a/c/driver/framework/CMakeLists.txt
b/c/driver/framework/CMakeLists.txt
index 1dd81f78a..3efc3f1da 100644
--- a/c/driver/framework/CMakeLists.txt
+++ b/c/driver/framework/CMakeLists.txt
@@ -17,7 +17,7 @@
include(FetchContent)
-add_library(adbc_driver_framework STATIC base_driver.cc catalog.cc objects.cc)
+add_library(adbc_driver_framework STATIC catalog.cc objects.cc)
adbc_configure_target(adbc_driver_framework)
set_target_properties(adbc_driver_framework PROPERTIES
POSITION_INDEPENDENT_CODE ON)
target_include_directories(adbc_driver_framework
diff --git a/c/driver/framework/base_driver.cc
b/c/driver/framework/base_driver.cc
deleted file mode 100644
index 49b2406c7..000000000
--- a/c/driver/framework/base_driver.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#include "driver/framework/base_driver.h"
-
-namespace adbc::driver {
-Result<bool> Option::AsBool() const {
- return std::visit(
- [&](auto&& value) -> Result<bool> {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, std::string>) {
- if (value == ADBC_OPTION_VALUE_ENABLED) {
- return true;
- } else if (value == ADBC_OPTION_VALUE_DISABLED) {
- return false;
- }
- }
- return status::InvalidArgument("Invalid boolean value ",
this->Format());
- },
- value_);
-}
-
-Result<int64_t> Option::AsInt() const {
- return std::visit(
- [&](auto&& value) -> Result<int64_t> {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, int64_t>) {
- return value;
- } else if constexpr (std::is_same_v<T, std::string>) {
- int64_t parsed = 0;
- auto begin = value.data();
- auto end = value.data() + value.size();
- auto result = std::from_chars(begin, end, parsed);
- if (result.ec != std::errc()) {
- return status::InvalidArgument("Invalid integer value '", value,
- "': not an integer", value);
- } else if (result.ptr != end) {
- return status::InvalidArgument("Invalid integer value '", value,
- "': trailing data", value);
- }
- return parsed;
- }
- return status::InvalidArgument("Invalid integer value ",
this->Format());
- },
- value_);
-}
-
-Result<std::string_view> Option::AsString() const {
- return std::visit(
- [&](auto&& value) -> Result<std::string_view> {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, std::string>) {
- return value;
- }
- return status::InvalidArgument("Invalid string value {}",
this->Format());
- },
- value_);
-}
-
-std::string Option::Format() const {
- return std::visit(
- [&](auto&& value) -> std::string {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, adbc::driver::Option::Unset>) {
- return "(NULL)";
- } else if constexpr (std::is_same_v<T, std::string>) {
- return std::string("'") + value + "'";
- } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
- return std::string("(") + std::to_string(value.size()) + " bytes)";
- } else {
- return std::to_string(value);
- }
- },
- value_);
-}
-
-AdbcStatusCode Option::CGet(char* out, size_t* length, AdbcError* error) const
{
- if (!out || !length) {
- return status::InvalidArgument("Must provide both out and length to
GetOption")
- .ToAdbc(error);
- }
- return std::visit(
- [&](auto&& value) -> AdbcStatusCode {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, std::string>) {
- size_t value_size_with_terminator = value.size() + 1;
- if (*length >= value_size_with_terminator) {
- std::memcpy(out, value.data(), value.size());
- out[value.size()] = 0;
- }
- *length = value_size_with_terminator;
- return ADBC_STATUS_OK;
- } else if constexpr (std::is_same_v<T, Unset>) {
- return status::NotFound("Unknown option").ToAdbc(error);
- } else {
- return status::NotFound("Option value is not a
string").ToAdbc(error);
- }
- },
- value_);
-}
-
-AdbcStatusCode Option::CGet(uint8_t* out, size_t* length, AdbcError* error)
const {
- if (!out || !length) {
- return status::InvalidArgument("Must provide both out and length to
GetOption")
- .ToAdbc(error);
- }
- return std::visit(
- [&](auto&& value) -> AdbcStatusCode {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, std::string> ||
- std::is_same_v<T, std::vector<uint8_t>>) {
- if (*length >= value.size()) {
- std::memcpy(out, value.data(), value.size());
- }
- *length = value.size();
- return ADBC_STATUS_OK;
- } else if constexpr (std::is_same_v<T, Unset>) {
- return status::NotFound("Unknown option").ToAdbc(error);
- } else {
- return status::NotFound("Option value is not a
bytestring").ToAdbc(error);
- }
- },
- value_);
-}
-
-AdbcStatusCode Option::CGet(int64_t* out, AdbcError* error) const {
- if (!out) {
- return status::InvalidArgument("Must provide out to
GetOption").ToAdbc(error);
- }
- return std::visit(
- [&](auto&& value) -> AdbcStatusCode {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, int64_t>) {
- *out = value;
- return ADBC_STATUS_OK;
- } else if constexpr (std::is_same_v<T, Unset>) {
- return status::NotFound("Unknown option").ToAdbc(error);
- } else {
- return status::NotFound("Option value is not an
integer").ToAdbc(error);
- }
- },
- value_);
-}
-
-AdbcStatusCode Option::CGet(double* out, AdbcError* error) const {
- if (!out) {
- return status::InvalidArgument("Must provide out to
GetOption").ToAdbc(error);
- }
- return std::visit(
- [&](auto&& value) -> AdbcStatusCode {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, double> || std::is_same_v<T, int64_t>)
{
- *out = static_cast<double>(value);
- return ADBC_STATUS_OK;
- } else if constexpr (std::is_same_v<T, Unset>) {
- return status::NotFound("Unknown option").ToAdbc(error);
- } else {
- return status::NotFound("Option value is not a
double").ToAdbc(error);
- }
- },
- value_);
-}
-
-} // namespace adbc::driver
diff --git a/c/driver/framework/base_driver.h b/c/driver/framework/base_driver.h
index e241f6e83..b52e47412 100644
--- a/c/driver/framework/base_driver.h
+++ b/c/driver/framework/base_driver.h
@@ -80,26 +80,171 @@ class Option {
bool has_value() const { return !std::holds_alternative<Unset>(value_); }
/// \brief Try to parse a string value as a boolean.
- Result<bool> AsBool() const;
+ Result<bool> AsBool() const {
+ return std::visit(
+ [&](auto&& value) -> Result<bool> {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, std::string>) {
+ if (value == ADBC_OPTION_VALUE_ENABLED) {
+ return true;
+ } else if (value == ADBC_OPTION_VALUE_DISABLED) {
+ return false;
+ }
+ }
+ return status::InvalidArgument("Invalid boolean value ",
this->Format());
+ },
+ value_);
+ }
/// \brief Try to parse a string or integer value as an integer.
- Result<int64_t> AsInt() const;
+ Result<int64_t> AsInt() const {
+ return std::visit(
+ [&](auto&& value) -> Result<int64_t> {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, int64_t>) {
+ return value;
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ int64_t parsed = 0;
+ auto begin = value.data();
+ auto end = value.data() + value.size();
+ auto result = std::from_chars(begin, end, parsed);
+ if (result.ec != std::errc()) {
+ return status::InvalidArgument("Invalid integer value '", value,
+ "': not an integer", value);
+ } else if (result.ptr != end) {
+ return status::InvalidArgument("Invalid integer value '", value,
+ "': trailing data", value);
+ }
+ return parsed;
+ }
+ return status::InvalidArgument("Invalid integer value ",
this->Format());
+ },
+ value_);
+ }
/// \brief Get the value if it is a string.
- Result<std::string_view> AsString() const;
+ Result<std::string_view> AsString() const {
+ return std::visit(
+ [&](auto&& value) -> Result<std::string_view> {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, std::string>) {
+ return value;
+ }
+ return status::InvalidArgument("Invalid string value ",
this->Format());
+ },
+ value_);
+ }
/// \brief Provide a human-readable summary of the value
- std::string Format() const;
+ std::string Format() const {
+ return std::visit(
+ [&](auto&& value) -> std::string {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, adbc::driver::Option::Unset>) {
+ return "(NULL)";
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ return std::string("'") + value + "'";
+ } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
+ return std::string("(") + std::to_string(value.size()) + " bytes)";
+ } else {
+ return std::to_string(value);
+ }
+ },
+ value_);
+ }
private:
Value value_;
// Methods used by trampolines to export option values in C below
friend class ObjectBase;
- AdbcStatusCode CGet(char* out, size_t* length, AdbcError* error) const;
- AdbcStatusCode CGet(uint8_t* out, size_t* length, AdbcError* error) const;
- AdbcStatusCode CGet(int64_t* out, AdbcError* error) const;
- AdbcStatusCode CGet(double* out, AdbcError* error) const;
+ AdbcStatusCode CGet(char* out, size_t* length, AdbcError* error) const {
+ {
+ if (!length || (!out && *length > 0)) {
+ return status::InvalidArgument("Must provide both out and length to
GetOption")
+ .ToAdbc(error);
+ }
+ return std::visit(
+ [&](auto&& value) -> AdbcStatusCode {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, std::string>) {
+ size_t value_size_with_terminator = value.size() + 1;
+ if (*length >= value_size_with_terminator) {
+ std::memcpy(out, value.data(), value.size());
+ out[value.size()] = 0;
+ }
+ *length = value_size_with_terminator;
+ return ADBC_STATUS_OK;
+ } else if constexpr (std::is_same_v<T, Unset>) {
+ return status::NotFound("Unknown option").ToAdbc(error);
+ } else {
+ return status::NotFound("Option value is not a
string").ToAdbc(error);
+ }
+ },
+ value_);
+ }
+ }
+ AdbcStatusCode CGet(uint8_t* out, size_t* length, AdbcError* error) const {
+ if (!length || (!out && *length > 0)) {
+ return status::InvalidArgument("Must provide both out and length to
GetOption")
+ .ToAdbc(error);
+ }
+ return std::visit(
+ [&](auto&& value) -> AdbcStatusCode {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, std::string> ||
+ std::is_same_v<T, std::vector<uint8_t>>) {
+ if (*length >= value.size()) {
+ std::memcpy(out, value.data(), value.size());
+ }
+ *length = value.size();
+ return ADBC_STATUS_OK;
+ } else if constexpr (std::is_same_v<T, Unset>) {
+ return status::NotFound("Unknown option").ToAdbc(error);
+ } else {
+ return status::NotFound("Option value is not a
bytestring").ToAdbc(error);
+ }
+ },
+ value_);
+ }
+ AdbcStatusCode CGet(int64_t* out, AdbcError* error) const {
+ {
+ if (!out) {
+ return status::InvalidArgument("Must provide out to
GetOption").ToAdbc(error);
+ }
+ return std::visit(
+ [&](auto&& value) -> AdbcStatusCode {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, int64_t>) {
+ *out = value;
+ return ADBC_STATUS_OK;
+ } else if constexpr (std::is_same_v<T, Unset>) {
+ return status::NotFound("Unknown option").ToAdbc(error);
+ } else {
+ return status::NotFound("Option value is not an
integer").ToAdbc(error);
+ }
+ },
+ value_);
+ }
+ }
+ AdbcStatusCode CGet(double* out, AdbcError* error) const {
+ if (!out) {
+ return status::InvalidArgument("Must provide out to
GetOption").ToAdbc(error);
+ }
+ return std::visit(
+ [&](auto&& value) -> AdbcStatusCode {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, double> || std::is_same_v<T,
int64_t>) {
+ *out = static_cast<double>(value);
+ return ADBC_STATUS_OK;
+ } else if constexpr (std::is_same_v<T, Unset>) {
+ return status::NotFound("Unknown option").ToAdbc(error);
+ } else {
+ return status::NotFound("Option value is not a
double").ToAdbc(error);
+ }
+ },
+ value_);
+ }
};
/// \brief Base class for private_data of AdbcDatabase, AdbcConnection, and
@@ -122,7 +267,7 @@ class ObjectBase {
///
/// Called after 0 or more SetOption calls. Generally, you won't need to
/// override this directly. Instead, use the typed InitImpl provided by
- /// DatabaseBase/ConnectionBase/StatementBase.
+ /// Database/Connection/Statement.
///
/// \param[in] parent A pointer to the AdbcDatabase or AdbcConnection
/// implementation as appropriate, or nullptr.
@@ -140,7 +285,7 @@ class ObjectBase {
/// the destructor.
///
/// Generally, you won't need to override this directly. Instead, use the
- /// typed ReleaseImpl provided by DatabaseBase/ConnectionBase/StatementBase.
+ /// typed ReleaseImpl provided by Database/Connection/Statement.
virtual AdbcStatusCode Release(AdbcError* error) { return ADBC_STATUS_OK; }
/// \brief Get an option value.
@@ -622,4 +767,371 @@ class Driver {
#undef CHECK_INIT
};
+template <typename Derived>
+class BaseDatabase : public ObjectBase {
+ public:
+ using Base = BaseDatabase<Derived>;
+
+ BaseDatabase() : ObjectBase() {}
+ ~BaseDatabase() = default;
+
+ /// \internal
+ AdbcStatusCode Init(void* parent, AdbcError* error) override {
+ RAISE_STATUS(error, impl().InitImpl());
+ return ObjectBase::Init(parent, error);
+ }
+
+ /// \internal
+ AdbcStatusCode Release(AdbcError* error) override {
+ RAISE_STATUS(error, impl().ReleaseImpl());
+ return ADBC_STATUS_OK;
+ }
+
+ /// \internal
+ AdbcStatusCode SetOption(std::string_view key, Option value,
+ AdbcError* error) override {
+ RAISE_STATUS(error, impl().SetOptionImpl(key, std::move(value)));
+ return ADBC_STATUS_OK;
+ }
+
+ /// \brief Initialize the database.
+ virtual Status InitImpl() { return status::Ok(); }
+
+ /// \brief Release the database.
+ virtual Status ReleaseImpl() { return status::Ok(); }
+
+ /// \brief Set an option. May be called prior to InitImpl.
+ virtual Status SetOptionImpl(std::string_view key, Option value) {
+ return status::NotImplemented(Derived::kErrorPrefix, " Unknown database
option ", key,
+ "=", value.Format());
+ }
+
+ private:
+ Derived& impl() { return static_cast<Derived&>(*this); }
+};
+
+template <typename Derived>
+class BaseConnection : public ObjectBase {
+ public:
+ using Base = BaseConnection<Derived>;
+
+ /// \brief Whether autocommit is enabled or not (by default: enabled).
+ enum class AutocommitState {
+ kAutocommit,
+ kTransaction,
+ };
+
+ BaseConnection() : ObjectBase() {}
+ ~BaseConnection() = default;
+
+ /// \internal
+ AdbcStatusCode Init(void* parent, AdbcError* error) override {
+ RAISE_STATUS(error, impl().InitImpl(parent));
+ return ObjectBase::Init(parent, error);
+ }
+
+ /// \brief Initialize the database.
+ virtual Status InitImpl(void* parent) { return status::Ok(); }
+
+ /// \internal
+ AdbcStatusCode Cancel(AdbcError* error) { return
impl().CancelImpl().ToAdbc(error); }
+
+ Status CancelImpl() { return status::NotImplemented("Cancel"); }
+
+ /// \internal
+ AdbcStatusCode Commit(AdbcError* error) { return
impl().CommitImpl().ToAdbc(error); }
+
+ Status CommitImpl() { return status::NotImplemented("Commit"); }
+
+ /// \internal
+ AdbcStatusCode GetInfo(const uint32_t* info_codes, size_t info_codes_length,
+ ArrowArrayStream* out, AdbcError* error) {
+ std::vector<uint32_t> codes(info_codes, info_codes + info_codes_length);
+ RAISE_STATUS(error, impl().GetInfoImpl(codes, out));
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetInfoImpl(const std::vector<uint32_t> info_codes, ArrowArrayStream*
out) {
+ return status::NotImplemented("GetInfo");
+ }
+
+ /// \internal
+ AdbcStatusCode GetObjects(int c_depth, const char* catalog, const char*
db_schema,
+ const char* table_name, const char** table_type,
+ const char* column_name, ArrowArrayStream* out,
+ AdbcError* error) {
+ const auto catalog_filter =
+ catalog ? std::make_optional(std::string_view(catalog)) : std::nullopt;
+ const auto schema_filter =
+ db_schema ? std::make_optional(std::string_view(db_schema)) :
std::nullopt;
+ const auto table_filter =
+ table_name ? std::make_optional(std::string_view(table_name)) :
std::nullopt;
+ const auto column_filter =
+ column_name ? std::make_optional(std::string_view(column_name)) :
std::nullopt;
+ std::vector<std::string_view> table_type_filter;
+ while (table_type && *table_type) {
+ if (*table_type) {
+ table_type_filter.push_back(std::string_view(*table_type));
+ }
+ table_type++;
+ }
+
+ RAISE_STATUS(
+ error, impl().GetObjectsImpl(c_depth, catalog_filter, schema_filter,
table_filter,
+ column_filter, table_type_filter, out));
+
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetObjectsImpl(int c_depth, std::optional<std::string_view>
catalog_filter,
+ std::optional<std::string_view> schema_filter,
+ std::optional<std::string_view> table_filter,
+ std::optional<std::string_view> column_filter,
+ const std::vector<std::string_view>& table_types,
+ struct ArrowArrayStream* out) {
+ return status::NotImplemented("GetObjects");
+ }
+
+ /// \internal
+ AdbcStatusCode GetStatistics(const char* catalog, const char* db_schema,
+ const char* table_name, char approximate,
+ ArrowArrayStream* out, AdbcError* error) {
+ const auto catalog_filter =
+ catalog ? std::make_optional(std::string_view(catalog)) : std::nullopt;
+ const auto schema_filter =
+ db_schema ? std::make_optional(std::string_view(db_schema)) :
std::nullopt;
+ const auto table_filter =
+ table_name ? std::make_optional(std::string_view(table_name)) :
std::nullopt;
+ RAISE_STATUS(error, impl().GetStatisticsImpl(catalog_filter, schema_filter,
+ table_filter, approximate !=
0, out));
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetStatisticsImpl(std::optional<std::string_view> catalog,
+ std::optional<std::string_view> db_schema,
+ std::optional<std::string_view> table_name, bool
approximate,
+ ArrowArrayStream* out) {
+ return status::NotImplemented("GetStatistics");
+ }
+
+ /// \internal
+ AdbcStatusCode GetStatisticNames(ArrowArrayStream* out, AdbcError* error) {
+ RAISE_STATUS(error, impl().GetStatisticNames(out));
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetStatisticNames(ArrowArrayStream* out) {
+ return status::NotImplemented("GetStatisticNames");
+ }
+
+ /// \internal
+ AdbcStatusCode GetTableSchema(const char* catalog, const char* db_schema,
+ const char* table_name, ArrowSchema* schema,
+ AdbcError* error) {
+ if (!table_name) {
+ return status::InvalidArgument(Derived::kErrorPrefix,
+ " GetTableSchema: must provide
table_name")
+ .ToAdbc(error);
+ }
+
+ std::optional<std::string_view> catalog_param =
+ catalog ? std::make_optional(std::string_view(catalog)) : std::nullopt;
+ std::optional<std::string_view> db_schema_param =
+ db_schema ? std::make_optional(std::string_view(db_schema)) :
std::nullopt;
+
+ RAISE_STATUS(error, impl().GetTableSchemaImpl(catalog_param,
db_schema_param,
+ table_name, schema));
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetTableSchemaImpl(std::optional<std::string_view> catalog,
+ std::optional<std::string_view> db_schema,
+ std::string_view table_name, ArrowSchema* out) {
+ return status::NotImplemented("GetTableSchema");
+ }
+
+ /// \internal
+ AdbcStatusCode GetTableTypes(ArrowArrayStream* out, AdbcError* error) {
+ RAISE_STATUS(error, impl().GetTableTypesImpl(out));
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetTableTypesImpl(ArrowArrayStream* out) {
+ return status::NotImplemented("GetTableTypes");
+ }
+
+ /// \internal
+ AdbcStatusCode ReadPartition(const uint8_t* serialized_partition,
+ size_t serialized_length, ArrowArrayStream* out,
+ AdbcError* error) {
+ std::string_view partition(reinterpret_cast<const
char*>(serialized_partition),
+ serialized_length);
+ RAISE_STATUS(error, impl().ReadPartitionImpl(partition, out));
+ return ADBC_STATUS_OK;
+ }
+
+ Status ReadPartitionImpl(std::string_view serialized_partition,
ArrowArrayStream* out) {
+ return status::NotImplemented("ReadPartition");
+ }
+
+ /// \internal
+ AdbcStatusCode Release(AdbcError* error) override {
+ RAISE_STATUS(error, impl().ReleaseImpl());
+ return ADBC_STATUS_OK;
+ }
+
+ Status ReleaseImpl() { return status::Ok(); }
+
+ /// \internal
+ AdbcStatusCode Rollback(AdbcError* error) {
+ RAISE_STATUS(error, impl().RollbackImpl());
+ return ADBC_STATUS_OK;
+ }
+
+ Status RollbackImpl() { return status::NotImplemented("Rollback"); }
+
+ /// \internal
+ AdbcStatusCode SetOption(std::string_view key, Option value,
+ AdbcError* error) override {
+ RAISE_STATUS(error, impl().SetOptionImpl(key, value));
+ return ADBC_STATUS_OK;
+ }
+
+ /// \brief Set an option. May be called prior to InitImpl.
+ virtual Status SetOptionImpl(std::string_view key, Option value) {
+ return status::NotImplemented(Derived::kErrorPrefix, " Unknown connection
option ",
+ key, "=", value.Format());
+ }
+
+ private:
+ Derived& impl() { return static_cast<Derived&>(*this); }
+};
+
+template <typename Derived>
+class BaseStatement : public ObjectBase {
+ public:
+ using Base = BaseStatement<Derived>;
+
+ /// \internal
+ AdbcStatusCode Init(void* parent, AdbcError* error) override {
+ RAISE_STATUS(error, impl().InitImpl(parent));
+ return ObjectBase::Init(parent, error);
+ }
+
+ /// \brief Initialize the statement.
+ Status InitImpl(void* parent) { return status::Ok(); }
+
+ /// \internal
+ AdbcStatusCode Release(AdbcError* error) override {
+ RAISE_STATUS(error, impl().ReleaseImpl());
+ return ADBC_STATUS_OK;
+ }
+
+ Status ReleaseImpl() { return status::Ok(); }
+
+ /// \internal
+ AdbcStatusCode SetOption(std::string_view key, Option value,
+ AdbcError* error) override {
+ RAISE_STATUS(error, impl().SetOptionImpl(key, value));
+ return ADBC_STATUS_OK;
+ }
+
+ /// \brief Set an option. May be called prior to InitImpl.
+ virtual Status SetOptionImpl(std::string_view key, Option value) {
+ return status::NotImplemented(Derived::kErrorPrefix, " Unknown statement
option ",
+ key, "=", value.Format());
+ }
+
+ AdbcStatusCode ExecuteQuery(ArrowArrayStream* stream, int64_t* rows_affected,
+ AdbcError* error) {
+ RAISE_RESULT(error, int64_t rows_affected_result,
impl().ExecuteQueryImpl(stream));
+ if (rows_affected) {
+ *rows_affected = rows_affected_result;
+ }
+
+ return ADBC_STATUS_OK;
+ }
+
+ Result<int64_t> ExecuteQueryImpl(ArrowArrayStream* stream) {
+ return status::NotImplemented("ExecuteQuery");
+ }
+
+ AdbcStatusCode ExecuteSchema(ArrowSchema* schema, AdbcError* error) {
+ RAISE_STATUS(error, impl().ExecuteSchemaImpl(schema));
+ return ADBC_STATUS_OK;
+ }
+
+ Status ExecuteSchemaImpl(ArrowSchema* schema) {
+ return status::NotImplemented("ExecuteSchema");
+ }
+
+ AdbcStatusCode Prepare(AdbcError* error) {
+ RAISE_STATUS(error, impl().PrepareImpl());
+ return ADBC_STATUS_OK;
+ }
+
+ Status PrepareImpl() { return status::NotImplemented("Prepare"); }
+
+ AdbcStatusCode SetSqlQuery(const char* query, AdbcError* error) {
+ RAISE_STATUS(error, impl().SetSqlQueryImpl(query));
+ return ADBC_STATUS_OK;
+ }
+
+ Status SetSqlQueryImpl(std::string_view query) {
+ return status::NotImplemented("SetSqlQuery");
+ }
+
+ AdbcStatusCode SetSubstraitPlan(const uint8_t* plan, size_t length,
AdbcError* error) {
+ RAISE_STATUS(error, impl().SetSubstraitPlanImpl(std::string_view(
+ reinterpret_cast<const char*>(plan), length)));
+ return ADBC_STATUS_OK;
+ }
+
+ Status SetSubstraitPlanImpl(std::string_view plan) {
+ return status::NotImplemented("SetSubstraitPlan");
+ }
+
+ AdbcStatusCode Bind(ArrowArray* values, ArrowSchema* schema, AdbcError*
error) {
+ RAISE_STATUS(error, impl().BindImpl(values, schema));
+ return ADBC_STATUS_OK;
+ }
+
+ Status BindImpl(ArrowArray* values, ArrowSchema* schema) {
+ return status::NotImplemented("Bind");
+ }
+
+ AdbcStatusCode BindStream(ArrowArrayStream* stream, AdbcError* error) {
+ RAISE_STATUS(error, impl().BindStreamImpl(stream));
+ return ADBC_STATUS_OK;
+ }
+
+ Status BindStreamImpl(ArrowArrayStream* stream) {
+ return status::NotImplemented("BindStream");
+ }
+
+ AdbcStatusCode GetParameterSchema(ArrowSchema* schema, AdbcError* error) {
+ RAISE_STATUS(error, impl().GetParameterSchemaImpl(schema));
+ return ADBC_STATUS_OK;
+ }
+
+ Status GetParameterSchemaImpl(struct ArrowSchema* schema) {
+ return status::NotImplemented("GetParameterSchema");
+ }
+
+ AdbcStatusCode ExecutePartitions(ArrowSchema* schema, AdbcPartitions*
partitions,
+ int64_t* rows_affected, AdbcError* error) {
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+ }
+
+ AdbcStatusCode Cancel(AdbcError* error) {
+ RAISE_STATUS(error, impl().Cancel());
+ return ADBC_STATUS_OK;
+ }
+
+ Status Cancel() { return status::NotImplemented("Cancel"); }
+
+ private:
+ Derived& impl() { return static_cast<Derived&>(*this); }
+};
+
} // namespace adbc::driver
diff --git a/c/driver/framework/base_driver_test.cc
b/c/driver/framework/base_driver_test.cc
index dfc1e38ea..1d8d61f60 100644
--- a/c/driver/framework/base_driver_test.cc
+++ b/c/driver/framework/base_driver_test.cc
@@ -19,10 +19,10 @@
#include <cstring>
#include <arrow-adbc/adbc.h>
-#include "driver/framework/base_connection.h"
-#include "driver/framework/base_database.h"
#include "driver/framework/base_driver.h"
-#include "driver/framework/base_statement.h"
+#include "driver/framework/connection.h"
+#include "driver/framework/database.h"
+#include "driver/framework/statement.h"
// Self-contained version of the Handle
static inline void clean_up(AdbcDriver* ptr) { ptr->release(ptr, nullptr); }
@@ -52,17 +52,111 @@ class Handle {
namespace {
-class VoidDatabase : public adbc::driver::DatabaseBase<VoidDatabase> {
+class BaseVoidDatabase : public adbc::driver::BaseDatabase<BaseVoidDatabase> {
public:
[[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
};
-class VoidConnection : public adbc::driver::ConnectionBase<VoidConnection> {
+class BaseVoidConnection : public
adbc::driver::BaseConnection<BaseVoidConnection> {
public:
[[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
};
-class VoidStatement : public adbc::driver::StatementBase<VoidStatement> {
+class BaseVoidStatement : public
adbc::driver::BaseStatement<BaseVoidStatement> {
+ public:
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
+};
+
+using BaseVoidDriver =
+ adbc::driver::Driver<BaseVoidDatabase, BaseVoidConnection,
BaseVoidStatement>;
+} // namespace
+
+AdbcStatusCode BaseVoidDriverInitFunc(int version, void* raw_driver,
AdbcError* error) {
+ return BaseVoidDriver::Init(version, raw_driver, error);
+}
+
+TEST(TestDriverBase, TestBaseVoidDriverMethods) {
+ // Checks that wires are plugged in for a framework-based driver based only
on what is
+ // available in base_driver.h
+
+ struct AdbcDriver driver;
+ memset(&driver, 0, sizeof(driver));
+ ASSERT_EQ(BaseVoidDriverInitFunc(ADBC_VERSION_1_1_0, &driver, nullptr),
ADBC_STATUS_OK);
+ Handle<AdbcDriver> driver_handle(&driver);
+
+ // Database methods are only option related
+ struct AdbcDatabase database;
+ memset(&database, 0, sizeof(database));
+ ASSERT_EQ(driver.DatabaseNew(&database, nullptr), ADBC_STATUS_OK);
+ database.private_driver = &driver;
+ Handle<AdbcDatabase> database_handle(&database);
+ ASSERT_EQ(driver.DatabaseInit(&database, nullptr), ADBC_STATUS_OK);
+
+ // Test connection methods
+ struct AdbcConnection connection;
+ memset(&connection, 0, sizeof(connection));
+ ASSERT_EQ(driver.ConnectionNew(&connection, nullptr), ADBC_STATUS_OK);
+ connection.private_driver = &driver;
+ Handle<AdbcConnection> connection_handle(&connection);
+ ASSERT_EQ(driver.ConnectionInit(&connection, &database, nullptr),
ADBC_STATUS_OK);
+
+ EXPECT_EQ(driver.ConnectionCommit(&connection, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionGetInfo(&connection, nullptr, 0, nullptr,
nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionGetObjects(&connection, 0, nullptr, nullptr, 0,
nullptr,
+ nullptr, nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionGetTableSchema(&connection, nullptr, nullptr,
nullptr,
+ nullptr, nullptr),
+ ADBC_STATUS_INVALID_ARGUMENT);
+ EXPECT_EQ(driver.ConnectionGetTableTypes(&connection, nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionReadPartition(&connection, nullptr, 0, nullptr,
nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionRollback(&connection, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionCancel(&connection, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionGetStatistics(&connection, nullptr, nullptr,
nullptr, 0,
+ nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.ConnectionGetStatisticNames(&connection, nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+
+ // Test statement methods
+ struct AdbcStatement statement;
+ memset(&statement, 0, sizeof(statement));
+ ASSERT_EQ(driver.StatementNew(&connection, &statement, nullptr),
ADBC_STATUS_OK);
+ statement.private_driver = &driver;
+ Handle<AdbcStatement> statement_handle(&statement);
+
+ EXPECT_EQ(driver.StatementExecuteQuery(&statement, nullptr, nullptr,
nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementExecuteSchema(&statement, nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementPrepare(&statement, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementSetSqlQuery(&statement, "", nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementSetSubstraitPlan(&statement, nullptr, 0, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementBind(&statement, nullptr, nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementBindStream(&statement, nullptr, nullptr),
+ ADBC_STATUS_NOT_IMPLEMENTED);
+ EXPECT_EQ(driver.StatementCancel(&statement, nullptr),
ADBC_STATUS_NOT_IMPLEMENTED);
+}
+
+namespace {
+
+class VoidDatabase : public adbc::driver::Database<VoidDatabase> {
+ public:
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
+};
+
+class VoidConnection : public adbc::driver::Connection<VoidConnection> {
+ public:
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
+};
+
+class VoidStatement : public adbc::driver::Statement<VoidStatement> {
public:
[[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
};
@@ -75,7 +169,8 @@ AdbcStatusCode VoidDriverInitFunc(int version, void*
raw_driver, AdbcError* erro
}
TEST(TestDriverBase, TestVoidDriverMethods) {
- // Checks that wires are plugged in for a framework-based driver
+ // Checks that wires are plugged in for a framework-based driver based on
+ // the more-batteries-included Database, Connection, and Statement
struct AdbcDriver driver;
memset(&driver, 0, sizeof(driver));
diff --git a/c/driver/framework/base_connection.h
b/c/driver/framework/connection.h
similarity index 98%
rename from c/driver/framework/base_connection.h
rename to c/driver/framework/connection.h
index d75265bde..f9e329ec1 100644
--- a/c/driver/framework/base_connection.h
+++ b/c/driver/framework/connection.h
@@ -39,9 +39,9 @@ namespace adbc::driver {
/// define a constexpr static symbol called kErrorPrefix that is used to
/// construct error messages.
template <typename Derived>
-class ConnectionBase : public ObjectBase {
+class Connection : public ObjectBase {
public:
- using Base = ConnectionBase<Derived>;
+ using Base = Connection<Derived>;
/// \brief Whether autocommit is enabled or not (by default: enabled).
enum class AutocommitState {
@@ -49,8 +49,8 @@ class ConnectionBase : public ObjectBase {
kTransaction,
};
- ConnectionBase() : ObjectBase() {}
- ~ConnectionBase() = default;
+ Connection() : ObjectBase() {}
+ ~Connection() = default;
/// \internal
AdbcStatusCode Init(void* parent, AdbcError* error) override {
diff --git a/c/driver/framework/base_database.h b/c/driver/framework/database.h
similarity index 64%
rename from c/driver/framework/base_database.h
rename to c/driver/framework/database.h
index 28201b055..ff0dd756c 100644
--- a/c/driver/framework/base_database.h
+++ b/c/driver/framework/database.h
@@ -34,42 +34,22 @@ namespace adbc::driver {
/// define a constexpr static symbol called kErrorPrefix that is used to
/// construct error messages.
template <typename Derived>
-class DatabaseBase : public ObjectBase {
+class Database : public BaseDatabase<Derived> {
public:
- using Base = DatabaseBase<Derived>;
+ using Base = Database<Derived>;
- DatabaseBase() : ObjectBase() {}
- ~DatabaseBase() = default;
-
- /// \internal
- AdbcStatusCode Init(void* parent, AdbcError* error) override {
- if (auto status = impl().InitImpl(); !status.ok()) {
- return status.ToAdbc(error);
- }
- return ObjectBase::Init(parent, error);
- }
-
- /// \internal
- AdbcStatusCode Release(AdbcError* error) override {
- return impl().ReleaseImpl().ToAdbc(error);
- }
-
- /// \internal
- AdbcStatusCode SetOption(std::string_view key, Option value,
- AdbcError* error) override {
- return impl().SetOptionImpl(key, std::move(value)).ToAdbc(error);
- }
+ Database() : BaseDatabase<Derived>() {}
+ ~Database() = default;
/// \brief Initialize the database.
- virtual Status InitImpl() { return status::Ok(); }
+ virtual Status InitImpl() { return BaseDatabase<Derived>::InitImpl(); }
/// \brief Release the database.
- virtual Status ReleaseImpl() { return status::Ok(); }
+ virtual Status ReleaseImpl() { return BaseDatabase<Derived>::ReleaseImpl(); }
/// \brief Set an option. May be called prior to InitImpl.
virtual Status SetOptionImpl(std::string_view key, Option value) {
- return status::NotImplemented(Derived::kErrorPrefix, " Unknown database
option ", key,
- "=", value.Format());
+ return BaseDatabase<Derived>::SetOptionImpl(key, value);
}
private:
diff --git a/c/driver/framework/meson.build b/c/driver/framework/meson.build
index dfd32d261..432cc5bb7 100644
--- a/c/driver/framework/meson.build
+++ b/c/driver/framework/meson.build
@@ -18,7 +18,6 @@
adbc_framework_lib = library(
'adbc_driver_framework',
sources: [
- 'base_driver.cc',
'catalog.cc',
'objects.cc',
],
diff --git a/c/driver/framework/base_statement.h
b/c/driver/framework/statement.h
similarity index 98%
rename from c/driver/framework/base_statement.h
rename to c/driver/framework/statement.h
index e3bd0fc0f..af9eee03f 100644
--- a/c/driver/framework/base_statement.h
+++ b/c/driver/framework/statement.h
@@ -32,9 +32,9 @@ namespace adbc::driver {
/// \brief A base implementation of a statement.
template <typename Derived>
-class StatementBase : public ObjectBase {
+class Statement : public BaseStatement<Derived> {
public:
- using Base = StatementBase<Derived>;
+ using Base = Statement<Derived>;
/// \brief What to do in ingestion when the table does not exist.
enum class TableDoesNotExist {
@@ -71,10 +71,10 @@ class StatementBase : public ObjectBase {
/// \brief Statement state: one of the above.
using State = std::variant<EmptyState, IngestState, PreparedState,
QueryState>;
- StatementBase() : ObjectBase() {
+ Statement() : BaseStatement<Derived>() {
std::memset(&bind_parameters_, 0, sizeof(bind_parameters_));
}
- ~StatementBase() = default;
+ ~Statement() = default;
AdbcStatusCode Bind(ArrowArray* values, ArrowSchema* schema, AdbcError*
error) {
if (!values || !values->release) {
@@ -183,7 +183,7 @@ class StatementBase : public ObjectBase {
}
AdbcStatusCode Init(void* parent, AdbcError* error) {
- lifecycle_state_ = LifecycleState::kInitialized;
+ this->lifecycle_state_ = LifecycleState::kInitialized;
if (auto status = impl().InitImpl(parent); !status.ok()) {
return status.ToAdbc(error);
}
diff --git a/c/driver/sqlite/sqlite.cc b/c/driver/sqlite/sqlite.cc
index debec7193..6628acdd9 100644
--- a/c/driver/sqlite/sqlite.cc
+++ b/c/driver/sqlite/sqlite.cc
@@ -26,11 +26,11 @@
#define ADBC_FRAMEWORK_USE_FMT
#include "driver/common/options.h"
#include "driver/common/utils.h"
-#include "driver/framework/base_connection.h"
-#include "driver/framework/base_database.h"
#include "driver/framework/base_driver.h"
-#include "driver/framework/base_statement.h"
#include "driver/framework/catalog.h"
+#include "driver/framework/connection.h"
+#include "driver/framework/database.h"
+#include "driver/framework/statement.h"
#include "driver/framework/status.h"
#include "driver/sqlite/statement_reader.h"
@@ -502,7 +502,7 @@ struct SqliteGetObjectsHelper : public
driver::GetObjectsHelper {
size_t next_constraint = 0;
};
-class SqliteDatabase : public driver::DatabaseBase<SqliteDatabase> {
+class SqliteDatabase : public driver::Database<SqliteDatabase> {
public:
[[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[SQLite]";
@@ -558,7 +558,7 @@ class SqliteDatabase : public
driver::DatabaseBase<SqliteDatabase> {
sqlite3* conn_ = nullptr;
};
-class SqliteConnection : public driver::ConnectionBase<SqliteConnection> {
+class SqliteConnection : public driver::Connection<SqliteConnection> {
public:
[[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[SQLite]";
@@ -672,7 +672,7 @@ class SqliteConnection : public
driver::ConnectionBase<SqliteConnection> {
}
conn_ = nullptr;
}
- return ConnectionBase::ReleaseImpl();
+ return Connection::ReleaseImpl();
}
Status RollbackImpl() {
@@ -760,7 +760,7 @@ class SqliteConnection : public
driver::ConnectionBase<SqliteConnection> {
std::string extension_path_;
};
-class SqliteStatement : public driver::StatementBase<SqliteStatement> {
+class SqliteStatement : public driver::Statement<SqliteStatement> {
public:
[[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[SQLite]";
@@ -1083,7 +1083,7 @@ class SqliteStatement : public
driver::StatementBase<SqliteStatement> {
Status InitImpl(void* parent) {
conn_ = reinterpret_cast<SqliteConnection*>(parent)->conn();
- return StatementBase::InitImpl(parent);
+ return Statement::InitImpl(parent);
}
Status PrepareImpl(QueryState& state) {
@@ -1119,7 +1119,7 @@ class SqliteStatement : public
driver::StatementBase<SqliteStatement> {
}
}
AdbcSqliteBinderRelease(&binder_);
- return StatementBase::ReleaseImpl();
+ return Statement::ReleaseImpl();
}
Status SetOptionImpl(std::string_view key, driver::Option value) {
diff --git a/r/adbcdrivermanager/bootstrap.R b/r/adbcdrivermanager/bootstrap.R
index 6eb725adf..73506902a 100644
--- a/r/adbcdrivermanager/bootstrap.R
+++ b/r/adbcdrivermanager/bootstrap.R
@@ -15,60 +15,18 @@
# specific language governing permissions and limitations
# under the License.
-# If we are building within the repo, copy the latest adbc.h and driver manager
-# implementation from the repo. We also run this from configure, so do nothing
-# if we aren't sitting within the repo (e.g., installing a source package from
a
-# tarball).
-dir.create("src/arrow-adbc", showWarnings=FALSE)
-headers_to_vendor <- c(
- "../../c/include/arrow-adbc/adbc.h",
- "../../c/include/arrow-adbc/adbc_driver_manager.h"
-)
-if (all(file.exists(headers_to_vendor))) {
- files_dst <- file.path("src/arrow-adbc", basename(headers_to_vendor))
-
- n_removed <- sum(file.remove(files_dst))
- if (n_removed > 0) {
- cat(sprintf("Removed %d previously vendored files from src/arrow-adbc/\n",
n_removed))
- }
-
- cat(
- sprintf(
- "Vendoring headers to src/arrow-adbc/:\n%s\n",
- paste("-", headers_to_vendor, collapse = "\n")
- )
- )
-
- if (all(file.copy(headers_to_vendor, "src/arrow-adbc"))) {
- cat("All files successfully copied to src/arrow-adbc/\n")
- } else {
- stop("Failed to vendor all headers")
- }
+source_files <- list.files("../../c", "\\.(h|c|cc|hpp)$", recursive = TRUE)
+source_files <- source_files[!grepl("_test\\.cc", source_files)]
+source_files <- source_files[!grepl("^(build|out)/", source_files)]
+# backward C++ causes CRAN warnings and the drivers do not use it
+source_files <- source_files[!grepl("^vendor/backward", source_files)]
+source_files <- file.path("c", source_files)
+src <- file.path("../..", source_files)
+dst <- file.path("src", source_files)
+
+unlink("src/c", recursive = TRUE)
+for (dir_name in rev(unique(dirname(dst)))) {
+ dir.create(dir_name, showWarnings = FALSE, recursive = TRUE)
}
-files_to_vendor <- c(
- "../../c/driver_manager/adbc_driver_manager.cc",
- "../../c/driver/common/driver_base.h"
-)
-
-if (all(file.exists(files_to_vendor))) {
- files_dst <- file.path("src", basename(files_to_vendor))
-
- n_removed <- sum(file.remove(files_dst))
- if (n_removed > 0) {
- cat(sprintf("Removed %d previously vendored files from src/\n", n_removed))
- }
-
- cat(
- sprintf(
- "Vendoring files from arrow-adbc to src/:\n%s\n",
- paste("-", files_to_vendor, collapse = "\n")
- )
- )
-
- if (all(file.copy(files_to_vendor, "src"))) {
- cat("All files successfully copied to src/\n")
- } else {
- stop("Failed to vendor all files")
- }
-}
+stopifnot(all(file.copy(src, dst)))
diff --git a/r/adbcdrivermanager/configure b/r/adbcdrivermanager/configure
index 0bfdfcd42..a0bec8830 100755
--- a/r/adbcdrivermanager/configure
+++ b/r/adbcdrivermanager/configure
@@ -24,12 +24,3 @@
if [ -f bootstrap.R ]; then
$R_HOME/bin/Rscript bootstrap.R --vanilla
fi
-
-if [ -f "src/arrow-adbc/adbc.h" ] && [ -f
"src/arrow-adbc/adbc_driver_manager.h" ] && [ -f "src/adbc_driver_manager.cc"
]; then
- echo "Found vendored ADBC"
- exit 0
-fi
-
-echo "Vendored src/arrow-adbc/adbc.h and/or src/adbc_driver_manager.cc are
missing"
-echo "This source package was probably built incorrectly and it's probably not
your fault"
-exit 1
diff --git a/r/adbcdrivermanager/src/.gitignore
b/r/adbcdrivermanager/src/.gitignore
index 7b75640dc..81aa3fbde 100644
--- a/r/adbcdrivermanager/src/.gitignore
+++ b/r/adbcdrivermanager/src/.gitignore
@@ -18,7 +18,4 @@
*.o
*.so
*.dll
-adbc.h
-adbc_driver_manager.h
-adbc_driver_manager.cc
-driver_base.h
+c/
diff --git a/r/adbcdrivermanager/src/Makevars b/r/adbcdrivermanager/src/Makevars
index ffcee27b8..b42e5c457 100644
--- a/r/adbcdrivermanager/src/Makevars
+++ b/r/adbcdrivermanager/src/Makevars
@@ -16,4 +16,12 @@
# under the License.
CXX_STD = CXX17
-PKG_CPPFLAGS=-I../src -DADBC_EXPORT=""
+PKG_CPPFLAGS=-I../src/c/include -I../src/c -DADBC_EXPORT=""
+
+OBJECTS = driver_test.o \
+ error.o \
+ init.o \
+ options.o \
+ radbc.o \
+ utils.o \
+ c/driver_manager/adbc_driver_manager.o
diff --git a/r/adbcdrivermanager/src/driver_test.cc
b/r/adbcdrivermanager/src/driver_test.cc
index 5172f004b..7032d38b3 100644
--- a/r/adbcdrivermanager/src/driver_test.cc
+++ b/r/adbcdrivermanager/src/driver_test.cc
@@ -20,21 +20,91 @@
#include <Rinternals.h>
#include <cstring>
+#include <unordered_map>
-#include "driver_base.h"
+#include "driver/framework/base_driver.h"
#include "arrow-adbc/adbc.h"
-using adbc::common::ConnectionObjectBase;
-using adbc::common::DatabaseObjectBase;
-using adbc::common::Option;
-using adbc::common::StatementObjectBase;
+using adbc::driver::Option;
+using adbc::driver::Result;
+using adbc::driver::Status;
-using VoidDriver =
- adbc::common::Driver<DatabaseObjectBase, ConnectionObjectBase,
StatementObjectBase>;
+class VoidDatabase : public adbc::driver::BaseDatabase<VoidDatabase> {
+ public:
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
+
+ Status SetOptionImpl(std::string_view key, Option value) override {
+ options_[std::string(key)] = value;
+ return adbc::driver::status::Ok();
+ }
+
+ Result<Option> GetOption(std::string_view key) override {
+ auto result = options_.find(std::string(key));
+ if (result == options_.end()) {
+ Status out(ADBC_STATUS_NOT_FOUND, "option not found");
+ out.AddDetail("r.driver_test.option_key", std::string(key));
+ return out;
+ } else {
+ return result->second;
+ }
+ }
+
+ private:
+ std::unordered_map<std::string, Option> options_;
+};
+
+class VoidConnection : public adbc::driver::BaseConnection<VoidConnection> {
+ public:
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
+
+ Status SetOptionImpl(std::string_view key, Option value) override {
+ options_[std::string(key)] = value;
+ return adbc::driver::status::Ok();
+ }
+
+ Result<Option> GetOption(std::string_view key) override {
+ auto result = options_.find(std::string(key));
+ if (result == options_.end()) {
+ Status out(ADBC_STATUS_NOT_FOUND, "option not found");
+ out.AddDetail("r.driver_test.option_key", std::string(key));
+ return out;
+ } else {
+ return result->second;
+ }
+ }
+
+ private:
+ std::unordered_map<std::string, Option> options_;
+};
+
+class VoidStatement : public adbc::driver::BaseStatement<VoidStatement> {
+ public:
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[void]";
+
+ Status SetOptionImpl(std::string_view key, Option value) override {
+ options_[std::string(key)] = value;
+ return adbc::driver::status::Ok();
+ }
+
+ Result<Option> GetOption(std::string_view key) override {
+ auto result = options_.find(std::string(key));
+ if (result == options_.end()) {
+ Status out(ADBC_STATUS_NOT_FOUND, "option not found");
+ out.AddDetail("r.driver_test.option_key", std::string(key));
+ return out;
+ } else {
+ return result->second;
+ }
+ }
+
+ private:
+ std::unordered_map<std::string, Option> options_;
+};
static AdbcStatusCode VoidDriverInitFunc(int version, void* raw_driver,
AdbcError* error) {
+ using VoidDriver = adbc::driver::Driver<VoidDatabase, VoidConnection,
VoidStatement>;
return VoidDriver::Init(version, raw_driver, error);
}
@@ -46,46 +116,42 @@ extern "C" SEXP RAdbcVoidDriverInitFunc(void) {
return xptr;
}
-class MonkeyDriverStatement : public StatementObjectBase {
+class MonkeyStatement : public adbc::driver::BaseStatement<MonkeyStatement> {
public:
- MonkeyDriverStatement() { stream_.release = nullptr; }
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[monkey]";
- ~MonkeyDriverStatement() {
+ MonkeyStatement() { stream_.release = nullptr; }
+
+ ~MonkeyStatement() {
if (stream_.release != nullptr) {
stream_.release(&stream_);
}
}
- AdbcStatusCode BindStream(ArrowArrayStream* stream, AdbcError* error) {
+ Status BindStreamImpl(ArrowArrayStream* stream) {
if (stream_.release != nullptr) {
stream_.release(&stream_);
}
std::memcpy(&stream_, stream, sizeof(ArrowArrayStream));
stream->release = nullptr;
- return ADBC_STATUS_OK;
+ return adbc::driver::status::Ok();
}
- AdbcStatusCode ExecuteQuery(ArrowArrayStream* stream, int64_t* rows_affected,
- AdbcError* error) {
+ Result<int64_t> ExecuteQueryImpl(ArrowArrayStream* stream) {
if (stream != nullptr) {
std::memcpy(stream, &stream_, sizeof(ArrowArrayStream));
stream_.release = nullptr;
}
- if (rows_affected != nullptr) {
- *rows_affected = -1;
- }
-
- return ADBC_STATUS_OK;
+ return -1;
}
private:
ArrowArrayStream stream_;
};
-using MonkeyDriver =
- adbc::common::Driver<DatabaseObjectBase, ConnectionObjectBase,
MonkeyDriverStatement>;
+using MonkeyDriver = adbc::driver::Driver<VoidDatabase, VoidConnection,
MonkeyStatement>;
static AdbcStatusCode MonkeyDriverInitFunc(int version, void* raw_driver,
AdbcError* error) {
@@ -100,49 +166,46 @@ extern "C" SEXP RAdbcMonkeyDriverInitFunc(void) {
return xptr;
}
-class LogDriverDatabase : public DatabaseObjectBase {
+class LogDatabase : public adbc::driver::BaseDatabase<LogDatabase> {
public:
- LogDriverDatabase() { Rprintf("LogDatabaseNew()\n"); }
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[log]";
- ~LogDriverDatabase() { Rprintf("LogDatabaseRelease()\n"); }
+ LogDatabase() { Rprintf("LogDatabaseNew()\n"); }
- AdbcStatusCode Init(void* parent, AdbcError* error) {
+ ~LogDatabase() { Rprintf("LogDatabaseRelease()\n"); }
+
+ AdbcStatusCode Init(void* parent, AdbcError* error) override {
Rprintf("LogDatabaseInit()\n");
- return DatabaseObjectBase::Init(parent, error);
+ return Base::Init(parent, error);
}
- const Option& GetOption(const std::string& key,
- const Option& default_value = Option()) const {
- Rprintf("LogDatabaseGetOption()\n");
- return DatabaseObjectBase::GetOption(key, default_value);
+ Status SetOptionImpl(std::string_view key, Option value) override {
+ Rprintf("LogDatabaseSetOption()\n");
+ return adbc::driver::status::Ok();
}
- AdbcStatusCode SetOption(const std::string& key, const Option& value) {
- Rprintf("LogDatabaseSetOption()\n");
- return DatabaseObjectBase::SetOption(key, value);
+ Result<Option> GetOption(std::string_view key) override {
+ Rprintf("LogDatabaseGetOption()\n");
+ return Base::GetOption(key);
}
};
-class LogDriverConnection : public ConnectionObjectBase {
+class LogConnection : public adbc::driver::BaseConnection<LogConnection> {
public:
- LogDriverConnection() { Rprintf("LogConnectionNew()\n"); }
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[log]";
- ~LogDriverConnection() { Rprintf("LogConnectionRelease()\n"); }
+ LogConnection() { Rprintf("LogConnectionNew()\n"); }
- AdbcStatusCode Init(void* parent, AdbcError* error) {
- Rprintf("LogConnectionInit()\n");
- return ConnectionObjectBase::Init(parent, error);
- }
+ ~LogConnection() { Rprintf("LogConnectionRelease()\n"); }
- const Option& GetOption(const std::string& key,
- const Option& default_value = Option()) const {
- Rprintf("LogConnectionGetOption()\n");
- return ConnectionObjectBase::GetOption(key, default_value);
+ AdbcStatusCode Init(void* parent, AdbcError* error) override {
+ Rprintf("LogConnectionInit()\n");
+ return Base::Init(parent, error);
}
- AdbcStatusCode SetOption(const std::string& key, const Option& value) {
+ Status SetOptionImpl(std::string_view key, Option value) override {
Rprintf("LogConnectionSetOption()\n");
- return ConnectionObjectBase::SetOption(key, value);
+ return adbc::driver::status::Ok();
}
AdbcStatusCode Commit(AdbcError* error) {
@@ -206,24 +269,20 @@ class LogDriverConnection : public ConnectionObjectBase {
}
};
-class LogDriverStatement : public StatementObjectBase {
+class LogStatement : public adbc::driver::BaseStatement<LogStatement> {
public:
- ~LogDriverStatement() { Rprintf("LogStatementRelease()\n"); }
+ [[maybe_unused]] constexpr static std::string_view kErrorPrefix = "[log]";
- AdbcStatusCode Init(void* parent, AdbcError* error) {
- Rprintf("LogStatementNew()\n");
- return StatementObjectBase::Init(parent, error);
- }
+ ~LogStatement() { Rprintf("LogStatementRelease()\n"); }
- const Option& GetOption(const std::string& key,
- const Option& default_value = Option()) const {
- Rprintf("LogStatementGetOption()\n");
- return StatementObjectBase::GetOption(key, default_value);
+ AdbcStatusCode Init(void* parent, AdbcError* error) override {
+ Rprintf("LogStatementNew()\n");
+ return Base::Init(parent, error);
}
- AdbcStatusCode SetOption(const std::string& key, const Option& value) {
+ Status SetOptionImpl(std::string_view key, Option value) override {
Rprintf("LogStatementSetOption()\n");
- return StatementObjectBase::SetOption(key, value);
+ return adbc::driver::status::Ok();
}
AdbcStatusCode ExecuteQuery(ArrowArrayStream* stream, int64_t* rows_affected,
@@ -268,8 +327,7 @@ class LogDriverStatement : public StatementObjectBase {
}
};
-using LogDriver =
- adbc::common::Driver<LogDriverDatabase, LogDriverConnection,
LogDriverStatement>;
+using LogDriver = adbc::driver::Driver<LogDatabase, LogConnection,
LogStatement>;
static AdbcStatusCode LogDriverInitFunc(int version, void* raw_driver,
AdbcError* error) {
return LogDriver::Init(version, raw_driver, error);
diff --git a/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
b/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
index 82b7e6041..268f0cf36 100644
--- a/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
+++ b/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
@@ -7,10 +7,10 @@
LogDatabaseSetOption()
LogDatabaseInit()
Code
- expect_identical(adbc_database_get_option(db, "key"), "value")
+ try(adbc_database_get_option(db, "key"))
Output
LogDatabaseGetOption()
- LogDatabaseGetOption()
+ Error in adbc_database_get_option(db, "key") : NOT_FOUND: Unknown option
Code
con <- adbc_connection_init(db, key = "value")
Output
@@ -18,10 +18,10 @@
LogConnectionSetOption()
LogConnectionInit()
Code
- expect_identical(adbc_connection_get_option(con, "key"), "value")
+ try(adbc_connection_get_option(con, "key"))
Output
- LogConnectionGetOption()
- LogConnectionGetOption()
+ Error in adbc_connection_get_option(con, "key") :
+ NOT_FOUND: Unknown option
Code
try(adbc_connection_commit(con))
Output
@@ -80,10 +80,10 @@
LogStatementNew()
LogStatementSetOption()
Code
- expect_identical(adbc_statement_get_option(stmt, "key"), "value")
+ try(adbc_statement_get_option(stmt, "key"))
Output
- LogStatementGetOption()
- LogStatementGetOption()
+ Error in adbc_statement_get_option(stmt, "key") :
+ NOT_FOUND: Unknown option
Code
try(adbc_statement_execute_query(stmt))
Output
diff --git a/r/adbcdrivermanager/tests/testthat/test-driver_log.R
b/r/adbcdrivermanager/tests/testthat/test-driver_log.R
index dd2e097e0..de49ede28 100644
--- a/r/adbcdrivermanager/tests/testthat/test-driver_log.R
+++ b/r/adbcdrivermanager/tests/testthat/test-driver_log.R
@@ -18,10 +18,10 @@
test_that("The log driver logs", {
expect_snapshot({
db <- adbc_database_init(adbc_driver_log(), key = "value")
- expect_identical(adbc_database_get_option(db, "key"), "value")
+ try(adbc_database_get_option(db, "key"))
con <- adbc_connection_init(db, key = "value")
- expect_identical(adbc_connection_get_option(con, "key"), "value")
+ try(adbc_connection_get_option(con, "key"))
try(adbc_connection_commit(con))
try(adbc_connection_get_info(con))
try(adbc_connection_get_objects(con))
@@ -34,7 +34,7 @@ test_that("The log driver logs", {
try(adbc_connection_get_statistic_names(con))
stmt <- adbc_statement_init(con, key = "value")
- expect_identical(adbc_statement_get_option(stmt, "key"), "value")
+ try(adbc_statement_get_option(stmt, "key"))
try(adbc_statement_execute_query(stmt))
try(adbc_statement_execute_schema(stmt))
diff --git a/r/adbcdrivermanager/tests/testthat/test-error.R
b/r/adbcdrivermanager/tests/testthat/test-error.R
index 8f053d375..afffa241e 100644
--- a/r/adbcdrivermanager/tests/testthat/test-error.R
+++ b/r/adbcdrivermanager/tests/testthat/test-error.R
@@ -52,8 +52,8 @@ test_that("stop_for_error() gives a custom error class with
extra info", {
expect_s3_class(e, "adbc_status_not_found")
expect_identical(e$error$status, 3L)
expect_identical(
- e$error$detail[["adbc.driver_base.option_key"]],
- c(charToRaw("this option does not exist"), as.raw(0x00))
+ e$error$detail[["r.driver_test.option_key"]],
+ charToRaw("this option does not exist")
)
})
diff --git a/r/adbcdrivermanager/tests/testthat/test-options.R
b/r/adbcdrivermanager/tests/testthat/test-options.R
index 85ee78f72..8d978f838 100644
--- a/r/adbcdrivermanager/tests/testthat/test-options.R
+++ b/r/adbcdrivermanager/tests/testthat/test-options.R
@@ -206,15 +206,10 @@ test_that("get/set option can roundtrip double options
for statement", {
)
})
-test_that("void driver errors getting string option of incorrect type", {
+test_that("void driver errors getting string option of incompatible type", {
db <- adbc_database_init(adbc_driver_void())
adbc_database_set_options(db, list("some_key" = "some value"))
- expect_error(
- adbc_database_get_option_bytes(db, "some_key"),
- class = "adbc_status_not_found"
- )
-
expect_error(
adbc_database_get_option_int(db, "some_key"),
class = "adbc_status_not_found"
@@ -226,6 +221,16 @@ test_that("void driver errors getting string option of
incorrect type", {
)
})
+test_that("void driver can get string option of compatible type", {
+ db <- adbc_database_init(adbc_driver_void())
+ adbc_database_set_options(db, list("some_key" = "some value"))
+
+ expect_identical(
+ adbc_database_get_option_bytes(db, "some_key"),
+ charToRaw("some value")
+ )
+})
+
test_that("void driver errors getting bytes option of incorrect type", {
db <- adbc_database_init(adbc_driver_void())
adbc_database_set_options(db, list("some_key" = charToRaw("some value")))
@@ -260,12 +265,20 @@ test_that("void driver errors getting integer option of
incorrect type", {
class = "adbc_status_not_found"
)
- expect_error(
+
+})
+
+test_that("void driver can get integer option of compatible type", {
+ db <- adbc_database_init(adbc_driver_void())
+ adbc_database_set_options(db, list("some_key" = 123L))
+
+ expect_identical(
adbc_database_get_option_double(db, "some_key"),
- class = "adbc_status_not_found"
+ 123.0
)
})
+
test_that("void driver errors getting double option of incorrect type", {
db <- adbc_database_init(adbc_driver_void())
adbc_database_set_options(db, list("some_key" = 123.4))
diff --git a/r/adbcsqlite/src/Makevars.in b/r/adbcsqlite/src/Makevars.in
index 7ed49a9ad..e4da67dc8 100644
--- a/r/adbcsqlite/src/Makevars.in
+++ b/r/adbcsqlite/src/Makevars.in
@@ -21,7 +21,6 @@ PKG_LIBS=@libs@
OBJECTS = init.o \
c/driver/common/utils.o \
- c/driver/framework/base_driver.o \
c/driver/framework/catalog.o \
c/driver/framework/objects.o \
c/driver/sqlite/sqlite.o \