From d379f848ec849bbe6c85a6657216941fc9e39780 Mon Sep 17 00:00:00 2001 From: David Li Date: Fri, 12 May 2023 11:20:19 -0400 Subject: [PATCH] feat(format): introduce AdbcDriver110 Fixes #317. --- adbc.h | 24 +- c/driver_manager/adbc_driver_manager.cc | 269 +++++++++++-------- c/driver_manager/adbc_driver_manager_test.cc | 30 +++ 3 files changed, 213 insertions(+), 110 deletions(-) diff --git a/adbc.h b/adbc.h index 154e881255..27450faf57 100644 --- a/adbc.h +++ b/adbc.h @@ -279,6 +279,12 @@ struct ADBC_EXPORT AdbcError { /// point to an AdbcDriver. #define ADBC_VERSION_1_0_0 1000000 +/// \brief ADBC revision 1.1.0. +/// +/// When passed to an AdbcDriverInitFunc(), the driver parameter must +/// point to an AdbcDriver110. +#define ADBC_VERSION_1_1_0 1001000 + /// \brief Canonical option value for enabling an option. /// /// For use as the value in SetOption calls. @@ -479,7 +485,7 @@ struct ADBC_EXPORT AdbcDatabase { void* private_data; /// \brief The associated driver (used by the driver manager to help /// track state). - struct AdbcDriver* private_driver; + void* private_driver; }; /// @} @@ -502,7 +508,7 @@ struct ADBC_EXPORT AdbcConnection { void* private_data; /// \brief The associated driver (used by the driver manager to help /// track state). - struct AdbcDriver* private_driver; + void* private_driver; }; /// @} @@ -541,7 +547,7 @@ struct ADBC_EXPORT AdbcStatement { /// \brief The associated driver (used by the driver manager to help /// track state). - struct AdbcDriver* private_driver; + void* private_driver; }; /// \defgroup adbc-statement-partition Partitioned Results @@ -595,7 +601,7 @@ struct AdbcPartitions { /// driver and the driver manager. /// @{ -/// \brief An instance of an initialized database driver. +/// \brief An instance of an initialized database driver (API 1.0.0). /// /// This provides a common interface for vendor-specific driver /// initialization routines. Drivers should populate this struct, and @@ -669,6 +675,16 @@ struct ADBC_EXPORT AdbcDriver { size_t, struct AdbcError*); }; +/// \brief An instance of an initialized database driver (API 1.1.0). +/// +/// This provides a common interface for vendor-specific driver +/// initialization routines. Drivers should populate this struct, and +/// applications can call ADBC functions through this struct, without +/// worrying about multiple definitions of the same symbol. +struct ADBC_EXPORT AdbcDriver110 { + struct AdbcDriver base; +}; + /// @} /// \addtogroup adbc-database diff --git a/c/driver_manager/adbc_driver_manager.cc b/c/driver_manager/adbc_driver_manager.cc index c63560a40e..afe44a908a 100644 --- a/c/driver_manager/adbc_driver_manager.cc +++ b/c/driver_manager/adbc_driver_manager.cc @@ -243,7 +243,8 @@ AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct AdbcError* AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const char* key, const char* value, struct AdbcError* error) { if (database->private_driver) { - return database->private_driver->DatabaseSetOption(database, key, value, error); + return static_cast(database->private_driver) + ->base.DatabaseSetOption(database, key, value, error); } TempDatabase* args = reinterpret_cast(database->private_data); @@ -282,48 +283,52 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase* database, struct AdbcError* return ADBC_STATUS_INVALID_ARGUMENT; } - database->private_driver = new AdbcDriver; - std::memset(database->private_driver, 0, sizeof(AdbcDriver)); + database->private_driver = new AdbcDriver110; + std::memset(database->private_driver, 0, sizeof(AdbcDriver110)); + + auto* driver110 = static_cast(database->private_driver); + struct AdbcDriver* driver100 = &driver110->base; + AdbcStatusCode status; // So we don't confuse a driver into thinking it's initialized already database->private_data = nullptr; if (args->init_func) { - status = AdbcLoadDriverFromInitFunc(args->init_func, ADBC_VERSION_1_0_0, - database->private_driver, error); + status = + AdbcLoadDriverFromInitFunc(args->init_func, ADBC_VERSION_1_0_0, driver100, error); } else { status = AdbcLoadDriver(args->driver.c_str(), args->entrypoint.c_str(), - ADBC_VERSION_1_0_0, database->private_driver, error); + ADBC_VERSION_1_0_0, driver100, error); } if (status != ADBC_STATUS_OK) { // Restore private_data so it will be released by AdbcDatabaseRelease database->private_data = args; - if (database->private_driver->release) { - database->private_driver->release(database->private_driver, error); + if (driver100->release) { + driver100->release(driver100, error); } - delete database->private_driver; + delete static_cast(database->private_driver); database->private_driver = nullptr; return status; } - status = database->private_driver->DatabaseNew(database, error); + status = driver100->DatabaseNew(database, error); if (status != ADBC_STATUS_OK) { - if (database->private_driver->release) { - database->private_driver->release(database->private_driver, error); + if (driver100->release) { + driver100->release(driver100, error); } - delete database->private_driver; + delete static_cast(database->private_driver); database->private_driver = nullptr; return status; } for (const auto& option : args->options) { - status = database->private_driver->DatabaseSetOption(database, option.first.c_str(), - option.second.c_str(), error); + status = driver100->DatabaseSetOption(database, option.first.c_str(), + option.second.c_str(), error); if (status != ADBC_STATUS_OK) { delete args; // Release the database - std::ignore = database->private_driver->DatabaseRelease(database, error); - if (database->private_driver->release) { - database->private_driver->release(database->private_driver, error); + std::ignore = driver100->DatabaseRelease(database, error); + if (driver100->release) { + driver100->release(driver100, error); } - delete database->private_driver; + delete static_cast(database->private_driver); database->private_driver = nullptr; // Should be redundant, but ensure that AdbcDatabaseRelease // below doesn't think that it contains a TempDatabase @@ -332,7 +337,7 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase* database, struct AdbcError* } } delete args; - return database->private_driver->DatabaseInit(database, error); + return driver100->DatabaseInit(database, error); } AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase* database, @@ -346,11 +351,13 @@ AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase* database, } return ADBC_STATUS_INVALID_STATE; } - auto status = database->private_driver->DatabaseRelease(database, error); - if (database->private_driver->release) { - database->private_driver->release(database->private_driver, error); + auto* driver110 = static_cast(database->private_driver); + struct AdbcDriver* driver100 = &driver110->base; + auto status = driver100->DatabaseRelease(database, error); + if (driver100->release) { + driver100->release(driver100, error); } - delete database->private_driver; + delete static_cast(database->private_driver); database->private_data = nullptr; database->private_driver = nullptr; return status; @@ -361,7 +368,8 @@ AdbcStatusCode AdbcConnectionCommit(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionCommit(connection, error); + return static_cast(connection->private_driver) + ->base.ConnectionCommit(connection, error); } AdbcStatusCode AdbcConnectionGetInfo(struct AdbcConnection* connection, @@ -371,8 +379,8 @@ AdbcStatusCode AdbcConnectionGetInfo(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionGetInfo(connection, info_codes, - info_codes_length, out, error); + return static_cast(connection->private_driver) + ->base.ConnectionGetInfo(connection, info_codes, info_codes_length, out, error); } AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection* connection, int depth, @@ -384,9 +392,9 @@ AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection* connection, int d if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionGetObjects( - connection, depth, catalog, db_schema, table_name, table_types, column_name, stream, - error); + return static_cast(connection->private_driver) + ->base.ConnectionGetObjects(connection, depth, catalog, db_schema, table_name, + table_types, column_name, stream, error); } AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection* connection, @@ -397,8 +405,9 @@ AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionGetTableSchema( - connection, catalog, db_schema, table_name, schema, error); + return static_cast(connection->private_driver) + ->base.ConnectionGetTableSchema(connection, catalog, db_schema, table_name, schema, + error); } AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection* connection, @@ -407,7 +416,8 @@ AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionGetTableTypes(connection, stream, error); + return static_cast(connection->private_driver) + ->base.ConnectionGetTableTypes(connection, stream, error); } AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection, @@ -425,16 +435,19 @@ AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection, std::unordered_map options = std::move(args->options); delete args; - auto status = database->private_driver->ConnectionNew(connection, error); + auto status = static_cast(database->private_driver) + ->base.ConnectionNew(connection, error); if (status != ADBC_STATUS_OK) return status; connection->private_driver = database->private_driver; for (const auto& option : options) { - status = database->private_driver->ConnectionSetOption( - connection, option.first.c_str(), option.second.c_str(), error); + status = static_cast(database->private_driver) + ->base.ConnectionSetOption(connection, option.first.c_str(), + option.second.c_str(), error); if (status != ADBC_STATUS_OK) return status; } - return connection->private_driver->ConnectionInit(connection, database, error); + return static_cast(connection->private_driver) + ->base.ConnectionInit(connection, database, error); } AdbcStatusCode AdbcConnectionNew(struct AdbcConnection* connection, @@ -455,8 +468,9 @@ AdbcStatusCode AdbcConnectionReadPartition(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionReadPartition( - connection, serialized_partition, serialized_length, out, error); + return static_cast(connection->private_driver) + ->base.ConnectionReadPartition(connection, serialized_partition, serialized_length, + out, error); } AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection, @@ -470,7 +484,8 @@ AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection, } return ADBC_STATUS_INVALID_STATE; } - auto status = connection->private_driver->ConnectionRelease(connection, error); + auto status = static_cast(connection->private_driver) + ->base.ConnectionRelease(connection, error); connection->private_driver = nullptr; return status; } @@ -480,7 +495,8 @@ AdbcStatusCode AdbcConnectionRollback(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return connection->private_driver->ConnectionRollback(connection, error); + return static_cast(connection->private_driver) + ->base.ConnectionRollback(connection, error); } AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection, const char* key, @@ -495,7 +511,8 @@ AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection, const args->options[key] = value; return ADBC_STATUS_OK; } - return connection->private_driver->ConnectionSetOption(connection, key, value, error); + return static_cast(connection->private_driver) + ->base.ConnectionSetOption(connection, key, value, error); } AdbcStatusCode AdbcStatementBind(struct AdbcStatement* statement, @@ -504,7 +521,8 @@ AdbcStatusCode AdbcStatementBind(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementBind(statement, values, schema, error); + return static_cast(statement->private_driver) + ->base.StatementBind(statement, values, schema, error); } AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement* statement, @@ -513,7 +531,8 @@ AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementBindStream(statement, stream, error); + return static_cast(statement->private_driver) + ->base.StatementBindStream(statement, stream, error); } // XXX: cpplint gets confused here if declared as 'struct ArrowSchema* schema' @@ -525,8 +544,9 @@ AdbcStatusCode AdbcStatementExecutePartitions(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementExecutePartitions( - statement, schema, partitions, rows_affected, error); + return static_cast(statement->private_driver) + ->base.StatementExecutePartitions(statement, schema, partitions, rows_affected, + error); } AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, @@ -536,8 +556,8 @@ AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementExecuteQuery(statement, out, rows_affected, - error); + return static_cast(statement->private_driver) + ->base.StatementExecuteQuery(statement, out, rows_affected, error); } AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, @@ -546,7 +566,8 @@ AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementGetParameterSchema(statement, schema, error); + return static_cast(statement->private_driver) + ->base.StatementGetParameterSchema(statement, schema, error); } AdbcStatusCode AdbcStatementNew(struct AdbcConnection* connection, @@ -555,7 +576,8 @@ AdbcStatusCode AdbcStatementNew(struct AdbcConnection* connection, if (!connection->private_driver) { return ADBC_STATUS_INVALID_STATE; } - auto status = connection->private_driver->StatementNew(connection, statement, error); + auto status = static_cast(connection->private_driver) + ->base.StatementNew(connection, statement, error); statement->private_driver = connection->private_driver; return status; } @@ -565,7 +587,8 @@ AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementPrepare(statement, error); + return static_cast(statement->private_driver) + ->base.StatementPrepare(statement, error); } AdbcStatusCode AdbcStatementRelease(struct AdbcStatement* statement, @@ -573,7 +596,8 @@ AdbcStatusCode AdbcStatementRelease(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - auto status = statement->private_driver->StatementRelease(statement, error); + auto status = static_cast(statement->private_driver) + ->base.StatementRelease(statement, error); statement->private_driver = nullptr; return status; } @@ -583,7 +607,8 @@ AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const cha if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementSetOption(statement, key, value, error); + return static_cast(statement->private_driver) + ->base.StatementSetOption(statement, key, value, error); } AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement* statement, @@ -591,7 +616,8 @@ AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementSetSqlQuery(statement, query, error); + return static_cast(statement->private_driver) + ->base.StatementSetSqlQuery(statement, query, error); } AdbcStatusCode AdbcStatementSetSubstraitPlan(struct AdbcStatement* statement, @@ -600,8 +626,8 @@ AdbcStatusCode AdbcStatementSetSubstraitPlan(struct AdbcStatement* statement, if (!statement->private_driver) { return ADBC_STATUS_INVALID_STATE; } - return statement->private_driver->StatementSetSubstraitPlan(statement, plan, length, - error); + return static_cast(statement->private_driver) + ->base.StatementSetSubstraitPlan(statement, plan, length, error); } const char* AdbcStatusCodeMessage(AdbcStatusCode code) { @@ -640,13 +666,11 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, AdbcDriverInitFunc init_func; std::string error_message; - if (version != ADBC_VERSION_1_0_0) { - SetError(error, "Only ADBC 1.0.0 is supported"); + if (version != ADBC_VERSION_1_0_0 && version != ADBC_VERSION_1_1_0) { + SetError(error, "Only ADBC 1.0.0 and 1.1.0 are supported"); return ADBC_STATUS_NOT_IMPLEMENTED; } - auto* driver = reinterpret_cast(raw_driver); - if (!entrypoint) { // Default entrypoint (see adbc.h) entrypoint = "AdbcDriverInit"; @@ -730,8 +754,6 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, } if (!handle) { SetError(error, error_message); - // AdbcDatabaseInit tries to call this if set - driver->release = nullptr; return ADBC_STATUS_INTERNAL; } @@ -748,29 +770,46 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, #endif // defined(_WIN32) - AdbcStatusCode status = AdbcLoadDriverFromInitFunc(init_func, version, driver, error); - if (status == ADBC_STATUS_OK) { - ManagerDriverState* state = new ManagerDriverState; - state->driver_release = driver->release; + AdbcStatusCode status = ADBC_STATUS_OK; + if (version == ADBC_VERSION_1_0_0) { + auto* driver = reinterpret_cast(raw_driver); + status = AdbcLoadDriverFromInitFunc(init_func, version, driver, error); + if (status == ADBC_STATUS_OK) { + ManagerDriverState* state = new ManagerDriverState; + state->driver_release = driver->release; #if defined(_WIN32) - state->handle = handle; + state->handle = handle; #endif // defined(_WIN32) - driver->release = &ReleaseDriver; - driver->private_manager = state; - } else { -#if defined(_WIN32) - if (!FreeLibrary(handle)) { - std::string message = "FreeLibrary() failed: "; - GetWinError(&message); - SetError(error, message); + driver->release = &ReleaseDriver; + driver->private_manager = state; } + } else if (version == ADBC_VERSION_1_1_0) { + auto* driver = reinterpret_cast(raw_driver); + status = AdbcLoadDriverFromInitFunc(init_func, version, driver, error); + if (status == ADBC_STATUS_OK) { + ManagerDriverState* state = new ManagerDriverState; + state->driver_release = driver->base.release; +#if defined(_WIN32) + state->handle = handle; #endif // defined(_WIN32) + driver->base.release = &ReleaseDriver; + driver->base.private_manager = state; + } + } else { + SetError(error, "ADBC version not supported"); + status = ADBC_STATUS_NOT_IMPLEMENTED; + } + +#if defined(_WIN32) + if (status != ADBC_STATUS_OK && !FreeLibrary(handle)) { + std::string message = "FreeLibrary() failed: "; + GetWinError(&message); + SetError(error, message); } +#endif // defined(_WIN32) return status; } -AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int version, - void* raw_driver, struct AdbcError* error) { #define FILL_DEFAULT(DRIVER, STUB) \ if (!DRIVER->STUB) { \ DRIVER->STUB = &STUB; \ @@ -781,44 +820,62 @@ AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int vers return ADBC_STATUS_INTERNAL; \ } +AdbcStatusCode PolyfillDriver100(AdbcDriver* driver, AdbcError* error) { + CHECK_REQUIRED(driver, DatabaseNew); + CHECK_REQUIRED(driver, DatabaseInit); + CHECK_REQUIRED(driver, DatabaseRelease); + FILL_DEFAULT(driver, DatabaseSetOption); + + CHECK_REQUIRED(driver, ConnectionNew); + CHECK_REQUIRED(driver, ConnectionInit); + CHECK_REQUIRED(driver, ConnectionRelease); + FILL_DEFAULT(driver, ConnectionCommit); + FILL_DEFAULT(driver, ConnectionGetInfo); + FILL_DEFAULT(driver, ConnectionGetObjects); + FILL_DEFAULT(driver, ConnectionGetTableSchema); + FILL_DEFAULT(driver, ConnectionGetTableTypes); + FILL_DEFAULT(driver, ConnectionReadPartition); + FILL_DEFAULT(driver, ConnectionRollback); + FILL_DEFAULT(driver, ConnectionSetOption); + + FILL_DEFAULT(driver, StatementExecutePartitions); + CHECK_REQUIRED(driver, StatementExecuteQuery); + CHECK_REQUIRED(driver, StatementNew); + CHECK_REQUIRED(driver, StatementRelease); + FILL_DEFAULT(driver, StatementBind); + FILL_DEFAULT(driver, StatementGetParameterSchema); + FILL_DEFAULT(driver, StatementPrepare); + FILL_DEFAULT(driver, StatementSetOption); + FILL_DEFAULT(driver, StatementSetSqlQuery); + FILL_DEFAULT(driver, StatementSetSubstraitPlan); + return ADBC_STATUS_OK; +} + +AdbcStatusCode PolyfillDriver110(AdbcDriver110* driver, AdbcError* error) { + // No new functions yet + return PolyfillDriver100(&driver->base, error); +} + +AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int version, + void* raw_driver, struct AdbcError* error) { auto result = init_func(version, raw_driver, error); + if (version == ADBC_VERSION_1_1_0 && result == ADBC_STATUS_NOT_IMPLEMENTED) { + auto* driver = reinterpret_cast(raw_driver); + result = init_func(ADBC_VERSION_1_0_0, &driver->base, error); + } if (result != ADBC_STATUS_OK) { return result; } if (version == ADBC_VERSION_1_0_0) { auto* driver = reinterpret_cast(raw_driver); - CHECK_REQUIRED(driver, DatabaseNew); - CHECK_REQUIRED(driver, DatabaseInit); - CHECK_REQUIRED(driver, DatabaseRelease); - FILL_DEFAULT(driver, DatabaseSetOption); - - CHECK_REQUIRED(driver, ConnectionNew); - CHECK_REQUIRED(driver, ConnectionInit); - CHECK_REQUIRED(driver, ConnectionRelease); - FILL_DEFAULT(driver, ConnectionCommit); - FILL_DEFAULT(driver, ConnectionGetInfo); - FILL_DEFAULT(driver, ConnectionGetObjects); - FILL_DEFAULT(driver, ConnectionGetTableSchema); - FILL_DEFAULT(driver, ConnectionGetTableTypes); - FILL_DEFAULT(driver, ConnectionReadPartition); - FILL_DEFAULT(driver, ConnectionRollback); - FILL_DEFAULT(driver, ConnectionSetOption); - - FILL_DEFAULT(driver, StatementExecutePartitions); - CHECK_REQUIRED(driver, StatementExecuteQuery); - CHECK_REQUIRED(driver, StatementNew); - CHECK_REQUIRED(driver, StatementRelease); - FILL_DEFAULT(driver, StatementBind); - FILL_DEFAULT(driver, StatementGetParameterSchema); - FILL_DEFAULT(driver, StatementPrepare); - FILL_DEFAULT(driver, StatementSetOption); - FILL_DEFAULT(driver, StatementSetSqlQuery); - FILL_DEFAULT(driver, StatementSetSubstraitPlan); + return PolyfillDriver100(driver, error); + } else if (version == ADBC_VERSION_1_1_0) { + auto* driver = reinterpret_cast(raw_driver); + return PolyfillDriver110(driver, error); } - return ADBC_STATUS_OK; +} #undef FILL_DEFAULT #undef CHECK_REQUIRED -} diff --git a/c/driver_manager/adbc_driver_manager_test.cc b/c/driver_manager/adbc_driver_manager_test.cc index 99fa477bfa..9a1c0bdeb4 100644 --- a/c/driver_manager/adbc_driver_manager_test.cc +++ b/c/driver_manager/adbc_driver_manager_test.cc @@ -157,6 +157,36 @@ TEST_F(DriverManager, MultiDriverTest) { error->release(&error.value); } +class AdbcVersion : public ::testing::Test { + public: + void SetUp() override { + std::memset(&driver, 0, sizeof(driver)); + std::memset(&error, 0, sizeof(error)); + } + + void TearDown() override { + if (error.release) { + error.release(&error); + } + + if (driver.base.release) { + ASSERT_THAT(driver.base.release(&driver.base, &error), IsOkStatus(&error)); + ASSERT_EQ(driver.base.private_data, nullptr); + ASSERT_EQ(driver.base.private_manager, nullptr); + } + } + + protected: + struct AdbcDriver110 driver = {}; + struct AdbcError error = {}; +}; + +TEST_F(AdbcVersion, ForwardsCompatible) { + ASSERT_THAT( + AdbcLoadDriver("adbc_driver_sqlite", nullptr, ADBC_VERSION_1_1_0, &driver, &error), + IsOkStatus(&error)); +} + class SqliteQuirks : public adbc_validation::DriverQuirks { public: AdbcStatusCode SetupDatabase(struct AdbcDatabase* database,