From f18f1cca47d548d98798b87256e0dddb49eb1a41 Mon Sep 17 00:00:00 2001 From: David Li Date: Tue, 6 Jun 2023 16:09:43 -0400 Subject: [PATCH] test(c): add backwards compatibility tests for 1.1.0/1.0.0 (#698) Requires #692. --- c/driver_manager/CMakeLists.txt | 16 + c/driver_manager/adbc_driver_manager.cc | 370 +++++++++++++++++- c/driver_manager/adbc_driver_manager_test.cc | 32 -- c/driver_manager/adbc_version_100.c | 117 ++++++ c/driver_manager/adbc_version_100.h | 87 ++++ .../adbc_version_100_compatibility_test.cc | 103 +++++ 6 files changed, 678 insertions(+), 47 deletions(-) create mode 100644 c/driver_manager/adbc_version_100.c create mode 100644 c/driver_manager/adbc_version_100.h create mode 100644 c/driver_manager/adbc_version_100_compatibility_test.cc diff --git a/c/driver_manager/CMakeLists.txt b/c/driver_manager/CMakeLists.txt index dd28470cf6..637843fff5 100644 --- a/c/driver_manager/CMakeLists.txt +++ b/c/driver_manager/CMakeLists.txt @@ -64,4 +64,20 @@ if(ADBC_BUILD_TESTS) target_compile_features(adbc-driver-manager-test PRIVATE cxx_std_17) target_include_directories(adbc-driver-manager-test SYSTEM PRIVATE ${REPOSITORY_ROOT}/c/vendor/nanoarrow/) + + add_test_case(version_100_compatibility_test + PREFIX + adbc + EXTRA_LABELS + driver-manager + SOURCES + adbc_version_100.c + adbc_version_100_compatibility_test.cc + ../validation/adbc_validation_util.cc + EXTRA_LINK_LIBS + nanoarrow + ${TEST_LINK_LIBS}) + target_compile_features(adbc-version-100-compatibility-test PRIVATE cxx_std_17) + target_include_directories(adbc-version-100-compatibility-test SYSTEM + PRIVATE ${REPOSITORY_ROOT}/c/vendor/nanoarrow/) endif() diff --git a/c/driver_manager/adbc_driver_manager.cc b/c/driver_manager/adbc_driver_manager.cc index 4ad77f2ed9..e0315d8662 100644 --- a/c/driver_manager/adbc_driver_manager.cc +++ b/c/driver_manager/adbc_driver_manager.cc @@ -130,11 +130,36 @@ static AdbcStatusCode ReleaseDriver(struct AdbcDriver* driver, struct AdbcError* // Default stubs +AdbcStatusCode DatabaseGetOption(struct AdbcDatabase* database, const char* key, + const char** value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode DatabaseGetOptionInt(struct AdbcDatabase* database, const char* key, + int64_t* value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode DatabaseGetOptionDouble(struct AdbcDatabase* database, const char* key, + double* value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode DatabaseSetOption(struct AdbcDatabase* database, const char* key, const char* value, struct AdbcError* error) { return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode DatabaseSetOptionInt(struct AdbcDatabase* database, const char* key, + int64_t value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode DatabaseSetOptionDouble(struct AdbcDatabase* database, const char* key, + double value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode ConnectionCommit(struct AdbcConnection*, struct AdbcError* error) { return ADBC_STATUS_NOT_IMPLEMENTED; } @@ -151,6 +176,22 @@ AdbcStatusCode ConnectionGetObjects(struct AdbcConnection*, int, const char*, co return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode ConnectionGetOption(struct AdbcConnection* connection, const char* key, + const char** value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode ConnectionGetOptionInt(struct AdbcConnection* connection, const char* key, + int64_t* value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode ConnectionGetOptionDouble(struct AdbcConnection* connection, + const char* key, double* value, + struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode ConnectionGetTableSchema(struct AdbcConnection*, const char*, const char*, const char*, struct ArrowSchema*, struct AdbcError* error) { @@ -179,11 +220,26 @@ AdbcStatusCode ConnectionSetOption(struct AdbcConnection*, const char*, const ch return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode ConnectionSetOptionInt(struct AdbcConnection* connection, const char* key, + int64_t value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode ConnectionSetOptionDouble(struct AdbcConnection* connection, + const char* key, double value, + struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode StatementBind(struct AdbcStatement*, struct ArrowArray*, struct ArrowSchema*, struct AdbcError* error) { return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode StatementCancel(struct AdbcStatement* statement, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode StatementExecutePartitions(struct AdbcStatement* statement, struct ArrowSchema* schema, struct AdbcPartitions* partitions, @@ -198,6 +254,21 @@ AdbcStatusCode StatementExecuteSchema(struct AdbcStatement* statement, return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode StatementGetOption(struct AdbcStatement* statement, const char* key, + const char** value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode StatementGetOptionInt(struct AdbcStatement* statement, const char* key, + int64_t* value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode StatementGetOptionDouble(struct AdbcStatement* statement, const char* key, + double* value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode StatementGetParameterSchema(struct AdbcStatement* statement, struct ArrowSchema* schema, struct AdbcError* error) { @@ -213,6 +284,16 @@ AdbcStatusCode StatementSetOption(struct AdbcStatement*, const char*, const char return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode StatementSetOptionInt(struct AdbcStatement* statement, const char* key, + int64_t value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode StatementSetOptionDouble(struct AdbcStatement* statement, const char* key, + double value, struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode StatementSetSqlQuery(struct AdbcStatement*, const char*, struct AdbcError* error) { return ADBC_STATUS_NOT_IMPLEMENTED; @@ -226,6 +307,8 @@ AdbcStatusCode StatementSetSubstraitPlan(struct AdbcStatement*, const uint8_t*, /// Temporary state while the database is being configured. struct TempDatabase { std::unordered_map options; + std::unordered_map int_options; + std::unordered_map double_options; std::string driver; // Default name (see adbc.h) std::string entrypoint = "AdbcDriverInit"; @@ -235,6 +318,8 @@ struct TempDatabase { /// Temporary state while the database is being configured. struct TempConnection { std::unordered_map options; + std::unordered_map int_options; + std::unordered_map double_options; }; } // namespace @@ -247,6 +332,54 @@ AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct AdbcError* return ADBC_STATUS_OK; } +AdbcStatusCode AdbcDatabaseGetOption(struct AdbcDatabase* database, const char* key, + const char** value, struct AdbcError* error) { + if (database->private_driver) { + return database->private_driver->DatabaseGetOption(database, key, value, error); + } + const auto* args = reinterpret_cast(database->private_data); + if (std::strcmp(key, "driver") == 0) { + *value = args->driver.c_str(); + } else if (std::strcmp(key, "entrypoint") == 0) { + *value = args->entrypoint.c_str(); + } else { + const auto it = args->options.find(key); + if (it == args->options.end()) { + return ADBC_STATUS_NOT_FOUND; + } + *value = it->second.c_str(); + } + return ADBC_STATUS_OK; +} + +AdbcStatusCode AdbcDatabaseGetOptionInt(struct AdbcDatabase* database, const char* key, + int64_t* value, struct AdbcError* error) { + if (database->private_driver) { + return database->private_driver->DatabaseGetOptionInt(database, key, value, error); + } + const auto* args = reinterpret_cast(database->private_data); + const auto it = args->int_options.find(key); + if (it == args->int_options.end()) { + return ADBC_STATUS_NOT_FOUND; + } + *value = it->second; + return ADBC_STATUS_OK; +} + +AdbcStatusCode AdbcDatabaseGetOptionDouble(struct AdbcDatabase* database, const char* key, + double* value, struct AdbcError* error) { + if (database->private_driver) { + return database->private_driver->DatabaseGetOptionDouble(database, key, value, error); + } + const auto* args = reinterpret_cast(database->private_data); + const auto it = args->double_options.find(key); + if (it == args->double_options.end()) { + return ADBC_STATUS_NOT_FOUND; + } + *value = it->second; + return ADBC_STATUS_OK; +} + AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const char* key, const char* value, struct AdbcError* error) { if (database->private_driver) { @@ -264,6 +397,28 @@ AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const char* return ADBC_STATUS_OK; } +AdbcStatusCode AdbcDatabaseSetOptionInt(struct AdbcDatabase* database, const char* key, + int64_t value, struct AdbcError* error) { + if (database->private_driver) { + return database->private_driver->DatabaseSetOptionInt(database, key, value, error); + } + + TempDatabase* args = reinterpret_cast(database->private_data); + args->int_options[key] = value; + return ADBC_STATUS_OK; +} + +AdbcStatusCode AdbcDatabaseSetOptionDouble(struct AdbcDatabase* database, const char* key, + double value, struct AdbcError* error) { + if (database->private_driver) { + return database->private_driver->DatabaseSetOptionDouble(database, key, value, error); + } + + TempDatabase* args = reinterpret_cast(database->private_data); + args->double_options[key] = value; + return ADBC_STATUS_OK; +} + AdbcStatusCode AdbcDriverManagerDatabaseSetInitFunc(struct AdbcDatabase* database, AdbcDriverInitFunc init_func, struct AdbcError* error) { @@ -320,25 +475,40 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase* database, struct AdbcError* database->private_driver = nullptr; return status; } - for (const auto& option : args->options) { + auto options = std::move(args->options); + auto int_options = std::move(args->int_options); + auto double_options = std::move(args->double_options); + delete args; + + for (const auto& option : options) { status = database->private_driver->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); - } - delete database->private_driver; - database->private_driver = nullptr; - // Should be redundant, but ensure that AdbcDatabaseRelease - // below doesn't think that it contains a TempDatabase - database->private_data = nullptr; - return status; + if (status != ADBC_STATUS_OK) break; + } + for (const auto& option : int_options) { + status = database->private_driver->DatabaseSetOptionInt( + database, option.first.c_str(), option.second, error); + if (status != ADBC_STATUS_OK) break; + } + for (const auto& option : double_options) { + status = database->private_driver->DatabaseSetOptionDouble( + database, option.first.c_str(), option.second, error); + if (status != ADBC_STATUS_OK) break; + } + + if (status != ADBC_STATUS_OK) { + // Release the database + std::ignore = database->private_driver->DatabaseRelease(database, error); + if (database->private_driver->release) { + database->private_driver->release(database->private_driver, error); } + delete database->private_driver; + database->private_driver = nullptr; + // Should be redundant, but ensure that AdbcDatabaseRelease + // below doesn't think that it contains a TempDatabase + database->private_data = nullptr; + return status; } - delete args; return database->private_driver->DatabaseInit(database, error); } @@ -396,6 +566,67 @@ AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection* connection, int d error); } +AdbcStatusCode AdbcConnectionGetOption(struct AdbcConnection* connection, const char* key, + const char** value, struct AdbcError* error) { + if (!connection->private_data) { + SetError(error, "AdbcConnectionGetOption: must AdbcConnectionNew first"); + return ADBC_STATUS_INVALID_STATE; + } + if (!connection->private_driver) { + // Init not yet called, get the saved option + const auto* args = reinterpret_cast(connection->private_data); + const auto it = args->options.find(key); + if (it == args->options.end()) { + return ADBC_STATUS_NOT_FOUND; + } + *value = it->second.c_str(); + return ADBC_STATUS_OK; + } + return connection->private_driver->ConnectionGetOption(connection, key, value, error); +} + +AdbcStatusCode AdbcConnectionGetOptionInt(struct AdbcConnection* connection, + const char* key, int64_t* value, + struct AdbcError* error) { + if (!connection->private_data) { + SetError(error, "AdbcConnectionGetOption: must AdbcConnectionNew first"); + return ADBC_STATUS_INVALID_STATE; + } + if (!connection->private_driver) { + // Init not yet called, get the saved option + const auto* args = reinterpret_cast(connection->private_data); + const auto it = args->int_options.find(key); + if (it == args->int_options.end()) { + return ADBC_STATUS_NOT_FOUND; + } + *value = it->second; + return ADBC_STATUS_OK; + } + return connection->private_driver->ConnectionGetOptionInt(connection, key, value, + error); +} + +AdbcStatusCode AdbcConnectionGetOptionDouble(struct AdbcConnection* connection, + const char* key, double* value, + struct AdbcError* error) { + if (!connection->private_data) { + SetError(error, "AdbcConnectionGetOption: must AdbcConnectionNew first"); + return ADBC_STATUS_INVALID_STATE; + } + if (!connection->private_driver) { + // Init not yet called, get the saved option + const auto* args = reinterpret_cast(connection->private_data); + const auto it = args->double_options.find(key); + if (it == args->double_options.end()) { + return ADBC_STATUS_NOT_FOUND; + } + *value = it->second; + return ADBC_STATUS_OK; + } + return connection->private_driver->ConnectionGetOptionDouble(connection, key, value, + error); +} + AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection* connection, const char* catalog, const char* db_schema, const char* table_name, @@ -430,6 +661,9 @@ AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection, TempConnection* args = reinterpret_cast(connection->private_data); connection->private_data = nullptr; std::unordered_map options = std::move(args->options); + std::unordered_map int_options = std::move(args->int_options); + std::unordered_map double_options = + std::move(args->double_options); delete args; auto status = database->private_driver->ConnectionNew(connection, error); @@ -441,6 +675,16 @@ AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection, connection, option.first.c_str(), option.second.c_str(), error); if (status != ADBC_STATUS_OK) return status; } + for (const auto& option : int_options) { + status = database->private_driver->ConnectionSetOptionInt( + connection, option.first.c_str(), option.second, error); + if (status != ADBC_STATUS_OK) return status; + } + for (const auto& option : double_options) { + status = database->private_driver->ConnectionSetOptionDouble( + connection, option.first.c_str(), option.second, error); + if (status != ADBC_STATUS_OK) return status; + } return connection->private_driver->ConnectionInit(connection, database, error); } @@ -505,6 +749,40 @@ AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection, const return connection->private_driver->ConnectionSetOption(connection, key, value, error); } +AdbcStatusCode AdbcConnectionSetOptionInt(struct AdbcConnection* connection, + const char* key, int64_t value, + struct AdbcError* error) { + if (!connection->private_data) { + SetError(error, "AdbcConnectionSetOptionInt: must AdbcConnectionNew first"); + return ADBC_STATUS_INVALID_STATE; + } + if (!connection->private_driver) { + // Init not yet called, save the option + TempConnection* args = reinterpret_cast(connection->private_data); + args->int_options[key] = value; + return ADBC_STATUS_OK; + } + return connection->private_driver->ConnectionSetOptionInt(connection, key, value, + error); +} + +AdbcStatusCode AdbcConnectionSetOptionDouble(struct AdbcConnection* connection, + const char* key, double value, + struct AdbcError* error) { + if (!connection->private_data) { + SetError(error, "AdbcConnectionSetOptionDouble: must AdbcConnectionNew first"); + return ADBC_STATUS_INVALID_STATE; + } + if (!connection->private_driver) { + // Init not yet called, save the option + TempConnection* args = reinterpret_cast(connection->private_data); + args->double_options[key] = value; + return ADBC_STATUS_OK; + } + return connection->private_driver->ConnectionSetOptionDouble(connection, key, value, + error); +} + AdbcStatusCode AdbcStatementBind(struct AdbcStatement* statement, struct ArrowArray* values, struct ArrowSchema* schema, struct AdbcError* error) { @@ -556,6 +834,32 @@ AdbcStatusCode AdbcStatementExecuteSchema(struct AdbcStatement* statement, return statement->private_driver->StatementExecuteSchema(statement, schema, error); } +AdbcStatusCode AdbcStatementGetOption(struct AdbcStatement* statement, const char* key, + const char** value, struct AdbcError* error) { + if (!statement->private_driver) { + return ADBC_STATUS_INVALID_STATE; + } + return statement->private_driver->StatementGetOption(statement, key, value, error); +} + +AdbcStatusCode AdbcStatementGetOptionInt(struct AdbcStatement* statement, const char* key, + int64_t* value, struct AdbcError* error) { + if (!statement->private_driver) { + return ADBC_STATUS_INVALID_STATE; + } + return statement->private_driver->StatementGetOptionInt(statement, key, value, error); +} + +AdbcStatusCode AdbcStatementGetOptionDouble(struct AdbcStatement* statement, + const char* key, double* value, + struct AdbcError* error) { + if (!statement->private_driver) { + return ADBC_STATUS_INVALID_STATE; + } + return statement->private_driver->StatementGetOptionDouble(statement, key, value, + error); +} + AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, struct ArrowSchema* schema, struct AdbcError* error) { @@ -602,6 +906,24 @@ AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const cha return statement->private_driver->StatementSetOption(statement, key, value, error); } +AdbcStatusCode AdbcStatementSetOptionInt(struct AdbcStatement* statement, const char* key, + int64_t value, struct AdbcError* error) { + if (!statement->private_driver) { + return ADBC_STATUS_INVALID_STATE; + } + return statement->private_driver->StatementSetOptionInt(statement, key, value, error); +} + +AdbcStatusCode AdbcStatementSetOptionDouble(struct AdbcStatement* statement, + const char* key, double value, + struct AdbcError* error) { + if (!statement->private_driver) { + return ADBC_STATUS_INVALID_STATE; + } + return statement->private_driver->StatementSetOptionDouble(statement, key, value, + error); +} + AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement* statement, const char* query, struct AdbcError* error) { if (!statement->private_driver) { @@ -869,7 +1191,25 @@ AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int vers } if (version >= ADBC_VERSION_1_1_0) { auto* driver = reinterpret_cast(raw_driver); + FILL_DEFAULT(driver, DatabaseGetOption); + FILL_DEFAULT(driver, DatabaseGetOptionInt); + FILL_DEFAULT(driver, DatabaseGetOptionDouble); + FILL_DEFAULT(driver, DatabaseSetOptionInt); + FILL_DEFAULT(driver, DatabaseSetOptionDouble); + + FILL_DEFAULT(driver, ConnectionGetOption); + FILL_DEFAULT(driver, ConnectionGetOptionInt); + FILL_DEFAULT(driver, ConnectionGetOptionDouble); + FILL_DEFAULT(driver, ConnectionSetOptionInt); + FILL_DEFAULT(driver, ConnectionSetOptionDouble); + + FILL_DEFAULT(driver, StatementCancel); FILL_DEFAULT(driver, StatementExecuteSchema); + FILL_DEFAULT(driver, StatementGetOption); + FILL_DEFAULT(driver, StatementGetOptionInt); + FILL_DEFAULT(driver, StatementGetOptionDouble); + FILL_DEFAULT(driver, StatementSetOptionInt); + FILL_DEFAULT(driver, StatementSetOptionDouble); } return ADBC_STATUS_OK; diff --git a/c/driver_manager/adbc_driver_manager_test.cc b/c/driver_manager/adbc_driver_manager_test.cc index 97743e702a..99fa477bfa 100644 --- a/c/driver_manager/adbc_driver_manager_test.cc +++ b/c/driver_manager/adbc_driver_manager_test.cc @@ -157,38 +157,6 @@ 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.release) { - ASSERT_THAT(driver.release(&driver, &error), IsOkStatus(&error)); - ASSERT_EQ(driver.private_data, nullptr); - ASSERT_EQ(driver.private_manager, nullptr); - } - } - - protected: - struct AdbcDriver driver = {}; - struct AdbcError error = {}; -}; - -// TODO: set up a dummy driver to test behavior more deterministically - -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, diff --git a/c/driver_manager/adbc_version_100.c b/c/driver_manager/adbc_version_100.c new file mode 100644 index 0000000000..48114cdb43 --- /dev/null +++ b/c/driver_manager/adbc_version_100.c @@ -0,0 +1,117 @@ +// 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 "adbc_version_100.h" + +#include + +struct Version100Database { + int dummy; +}; + +static struct Version100Database kDatabase; + +struct Version100Connection { + int dummy; +}; + +static struct Version100Connection kConnection; + +struct Version100Statement { + int dummy; +}; + +static struct Version100Statement kStatement; + +AdbcStatusCode Version100DatabaseInit(struct AdbcDatabase* database, + struct AdbcError* error) { + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100DatabaseNew(struct AdbcDatabase* database, + struct AdbcError* error) { + database->private_data = &kDatabase; + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100DatabaseRelease(struct AdbcDatabase* database, + struct AdbcError* error) { + database->private_data = NULL; + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100ConnectionInit(struct AdbcConnection* connection, + struct AdbcDatabase* database, + struct AdbcError* error) { + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100ConnectionNew(struct AdbcConnection* connection, + struct AdbcError* error) { + connection->private_data = &kConnection; + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100StatementExecuteQuery(struct AdbcStatement* statement, + struct ArrowArrayStream* stream, + int64_t* rows_affected, + struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode Version100StatementNew(struct AdbcConnection* connection, + struct AdbcStatement* statement, + struct AdbcError* error) { + statement->private_data = &kStatement; + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100StatementRelease(struct AdbcStatement* statement, + struct AdbcError* error) { + statement->private_data = NULL; + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100ConnectionRelease(struct AdbcConnection* connection, + struct AdbcError* error) { + connection->private_data = NULL; + return ADBC_STATUS_OK; +} + +AdbcStatusCode Version100DriverInit(int version, void* raw_driver, + struct AdbcError* error) { + if (version != ADBC_VERSION_1_0_0) { + return ADBC_STATUS_NOT_IMPLEMENTED; + } + + struct AdbcDriverVersion100* driver = (struct AdbcDriverVersion100*)raw_driver; + memset(driver, 0, sizeof(struct AdbcDriverVersion100)); + + driver->DatabaseInit = &Version100DatabaseInit; + driver->DatabaseNew = &Version100DatabaseNew; + driver->DatabaseRelease = &Version100DatabaseRelease; + + driver->ConnectionInit = &Version100ConnectionInit; + driver->ConnectionNew = &Version100ConnectionNew; + driver->ConnectionRelease = &Version100ConnectionRelease; + + driver->StatementExecuteQuery = &Version100StatementExecuteQuery; + driver->StatementNew = &Version100StatementNew; + driver->StatementRelease = &Version100StatementRelease; + + return ADBC_STATUS_OK; +} diff --git a/c/driver_manager/adbc_version_100.h b/c/driver_manager/adbc_version_100.h new file mode 100644 index 0000000000..b4a8b949f8 --- /dev/null +++ b/c/driver_manager/adbc_version_100.h @@ -0,0 +1,87 @@ +// 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. + +// A dummy version 1.0.0 ADBC driver to test compatibility. + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct AdbcDriverVersion100 { + void* private_data; + void* private_manager; + AdbcStatusCode (*release)(struct AdbcDriver* driver, struct AdbcError* error); + + AdbcStatusCode (*DatabaseInit)(struct AdbcDatabase*, struct AdbcError*); + AdbcStatusCode (*DatabaseNew)(struct AdbcDatabase*, struct AdbcError*); + AdbcStatusCode (*DatabaseSetOption)(struct AdbcDatabase*, const char*, const char*, + struct AdbcError*); + AdbcStatusCode (*DatabaseRelease)(struct AdbcDatabase*, struct AdbcError*); + + AdbcStatusCode (*ConnectionCommit)(struct AdbcConnection*, struct AdbcError*); + AdbcStatusCode (*ConnectionGetInfo)(struct AdbcConnection*, uint32_t*, size_t, + struct ArrowArrayStream*, struct AdbcError*); + AdbcStatusCode (*ConnectionGetObjects)(struct AdbcConnection*, int, const char*, + const char*, const char*, const char**, + const char*, struct ArrowArrayStream*, + struct AdbcError*); + AdbcStatusCode (*ConnectionGetTableSchema)(struct AdbcConnection*, const char*, + const char*, const char*, + struct ArrowSchema*, struct AdbcError*); + AdbcStatusCode (*ConnectionGetTableTypes)(struct AdbcConnection*, + struct ArrowArrayStream*, struct AdbcError*); + AdbcStatusCode (*ConnectionInit)(struct AdbcConnection*, struct AdbcDatabase*, + struct AdbcError*); + AdbcStatusCode (*ConnectionNew)(struct AdbcConnection*, struct AdbcError*); + AdbcStatusCode (*ConnectionSetOption)(struct AdbcConnection*, const char*, const char*, + struct AdbcError*); + AdbcStatusCode (*ConnectionReadPartition)(struct AdbcConnection*, const uint8_t*, + size_t, struct ArrowArrayStream*, + struct AdbcError*); + AdbcStatusCode (*ConnectionRelease)(struct AdbcConnection*, struct AdbcError*); + AdbcStatusCode (*ConnectionRollback)(struct AdbcConnection*, struct AdbcError*); + + AdbcStatusCode (*StatementBind)(struct AdbcStatement*, struct ArrowArray*, + struct ArrowSchema*, struct AdbcError*); + AdbcStatusCode (*StatementBindStream)(struct AdbcStatement*, struct ArrowArrayStream*, + struct AdbcError*); + AdbcStatusCode (*StatementExecuteQuery)(struct AdbcStatement*, struct ArrowArrayStream*, + int64_t*, struct AdbcError*); + AdbcStatusCode (*StatementExecutePartitions)(struct AdbcStatement*, struct ArrowSchema*, + struct AdbcPartitions*, int64_t*, + struct AdbcError*); + AdbcStatusCode (*StatementGetParameterSchema)(struct AdbcStatement*, + struct ArrowSchema*, struct AdbcError*); + AdbcStatusCode (*StatementNew)(struct AdbcConnection*, struct AdbcStatement*, + struct AdbcError*); + AdbcStatusCode (*StatementPrepare)(struct AdbcStatement*, struct AdbcError*); + AdbcStatusCode (*StatementRelease)(struct AdbcStatement*, struct AdbcError*); + AdbcStatusCode (*StatementSetOption)(struct AdbcStatement*, const char*, const char*, + struct AdbcError*); + AdbcStatusCode (*StatementSetSqlQuery)(struct AdbcStatement*, const char*, + struct AdbcError*); + AdbcStatusCode (*StatementSetSubstraitPlan)(struct AdbcStatement*, const uint8_t*, + size_t, struct AdbcError*); +}; + +AdbcStatusCode Version100DriverInit(int version, void* driver, struct AdbcError* error); + +#ifdef __cplusplus +} +#endif diff --git a/c/driver_manager/adbc_version_100_compatibility_test.cc b/c/driver_manager/adbc_version_100_compatibility_test.cc new file mode 100644 index 0000000000..634c126c55 --- /dev/null +++ b/c/driver_manager/adbc_version_100_compatibility_test.cc @@ -0,0 +1,103 @@ +// 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 +#include + +#include + +#include "adbc.h" +#include "adbc_driver_manager.h" +#include "adbc_version_100.h" +#include "validation/adbc_validation_util.h" + +namespace adbc { + +using adbc_validation::IsOkStatus; +using adbc_validation::IsStatus; + +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.release) { + ASSERT_THAT(driver.release(&driver, &error), IsOkStatus(&error)); + ASSERT_EQ(driver.private_data, nullptr); + ASSERT_EQ(driver.private_manager, nullptr); + } + } + + protected: + struct AdbcDriver driver = {}; + struct AdbcError error = {}; +}; + +TEST_F(AdbcVersion, StructSize) { + ASSERT_EQ(sizeof(AdbcDriverVersion100), ADBC_DRIVER_1_0_0_SIZE); + ASSERT_EQ(sizeof(AdbcDriver), ADBC_DRIVER_1_1_0_SIZE); +} + +// Initialize a version 1.0.0 driver with the version 1.1.0 driver struct. +TEST_F(AdbcVersion, OldDriverNewLayout) { + ASSERT_THAT(Version100DriverInit(ADBC_VERSION_1_1_0, &driver, &error), + IsStatus(ADBC_STATUS_NOT_IMPLEMENTED, &error)); + + ASSERT_THAT(Version100DriverInit(ADBC_VERSION_1_0_0, &driver, &error), + IsOkStatus(&error)); +} + +// Initialize a version 1.0.0 driver with the new driver manager/new version. +TEST_F(AdbcVersion, OldDriverNewManager) { + ASSERT_THAT(AdbcLoadDriverFromInitFunc(&Version100DriverInit, ADBC_VERSION_1_1_0, + &driver, &error), + IsOkStatus(&error)); + + ASSERT_NE(driver.DatabaseGetOption, nullptr); + ASSERT_NE(driver.DatabaseGetOptionInt, nullptr); + ASSERT_NE(driver.DatabaseGetOptionDouble, nullptr); + ASSERT_NE(driver.DatabaseSetOptionInt, nullptr); + ASSERT_NE(driver.DatabaseSetOptionDouble, nullptr); + + ASSERT_NE(driver.ConnectionGetOption, nullptr); + ASSERT_NE(driver.ConnectionGetOptionInt, nullptr); + ASSERT_NE(driver.ConnectionGetOptionDouble, nullptr); + ASSERT_NE(driver.ConnectionSetOptionInt, nullptr); + ASSERT_NE(driver.ConnectionSetOptionDouble, nullptr); + + ASSERT_NE(driver.StatementCancel, nullptr); + ASSERT_NE(driver.StatementExecuteSchema, nullptr); + ASSERT_NE(driver.StatementGetOption, nullptr); + ASSERT_NE(driver.StatementGetOptionInt, nullptr); + ASSERT_NE(driver.StatementGetOptionDouble, nullptr); + ASSERT_NE(driver.StatementSetOptionInt, nullptr); + ASSERT_NE(driver.StatementSetOptionDouble, nullptr); +} + +// Initialize a version 1.1.0 driver with the version 1.0.0 driver struct. +TEST_F(AdbcVersion, NewDriverOldLayout) { + // TODO: no new drivers yet. +} + +} // namespace adbc