From 362638da63d164c9781c355ae156bf07979ed301 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