You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by li...@apache.org on 2023/06/06 20:09:48 UTC

[arrow-adbc] branch spec-1.1.0 updated: test(c): add backwards compatibility tests for 1.1.0/1.0.0 (#698)

This is an automated email from the ASF dual-hosted git repository.

lidavidm pushed a commit to branch spec-1.1.0
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/spec-1.1.0 by this push:
     new 0692bf42 test(c): add backwards compatibility tests for 1.1.0/1.0.0 (#698)
0692bf42 is described below

commit 0692bf42f2ff07d7bece4fcda26d4ff4d1642aea
Author: David Li <li...@gmail.com>
AuthorDate: Tue Jun 6 16:09:43 2023 -0400

    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(-)

diff --git a/c/driver_manager/CMakeLists.txt b/c/driver_manager/CMakeLists.txt
index e062b113..8f879111 100644
--- a/c/driver_manager/CMakeLists.txt
+++ b/c/driver_manager/CMakeLists.txt
@@ -63,4 +63,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 4ad77f2e..e0315d86 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<std::string, std::string> options;
+  std::unordered_map<std::string, int64_t> int_options;
+  std::unordered_map<std::string, double> 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<std::string, std::string> options;
+  std::unordered_map<std::string, int64_t> int_options;
+  std::unordered_map<std::string, double> 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<const TempDatabase*>(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<const TempDatabase*>(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<const TempDatabase*>(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<TempDatabase*>(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<TempDatabase*>(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<const TempConnection*>(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<const TempConnection*>(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<const TempConnection*>(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<TempConnection*>(connection->private_data);
   connection->private_data = nullptr;
   std::unordered_map<std::string, std::string> options = std::move(args->options);
+  std::unordered_map<std::string, int64_t> int_options = std::move(args->int_options);
+  std::unordered_map<std::string, double> 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<TempConnection*>(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<TempConnection*>(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<struct AdbcDriver*>(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 97743e70..99fa477b 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 00000000..48114cdb
--- /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 <string.h>
+
+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 00000000..b4a8b949
--- /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 <adbc.h>
+
+#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 00000000..634c126c
--- /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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#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