AdbcStatusCode AdbcLoadDriver()

in c/driver_manager/adbc_driver_manager.cc [634:766]


AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint,
                              int version, void* raw_driver, struct AdbcError* error) {
  AdbcDriverInitFunc init_func;
  std::string error_message;

  if (version != ADBC_VERSION_1_0_0) {
    SetError(error, "Only ADBC 1.0.0 is supported");
    return ADBC_STATUS_NOT_IMPLEMENTED;
  }

  auto* driver = reinterpret_cast<struct AdbcDriver*>(raw_driver);

  if (!entrypoint) {
    // Default entrypoint (see adbc.h)
    entrypoint = "AdbcDriverInit";
  }

#if defined(_WIN32)

  HMODULE handle = LoadLibraryExA(driver_name, NULL, 0);
  if (!handle) {
    error_message += driver_name;
    error_message += ": LoadLibraryExA() failed: ";
    GetWinError(&error_message);

    std::string full_driver_name = driver_name;
    full_driver_name += ".lib";
    handle = LoadLibraryExA(full_driver_name.c_str(), NULL, 0);
    if (!handle) {
      error_message += '\n';
      error_message += full_driver_name;
      error_message += ": LoadLibraryExA() failed: ";
      GetWinError(&error_message);
    }
  }
  if (!handle) {
    SetError(error, error_message);
    return ADBC_STATUS_INTERNAL;
  }

  void* load_handle = reinterpret_cast<void*>(GetProcAddress(handle, entrypoint));
  init_func = reinterpret_cast<AdbcDriverInitFunc>(load_handle);
  if (!init_func) {
    std::string message = "GetProcAddress(";
    message += entrypoint;
    message += ") failed: ";
    GetWinError(&message);
    if (!FreeLibrary(handle)) {
      message += "\nFreeLibrary() failed: ";
      GetWinError(&message);
    }
    SetError(error, message);
    return ADBC_STATUS_INTERNAL;
  }

#else

#if defined(__APPLE__)
  static const std::string kPlatformLibraryPrefix = "lib";
  static const std::string kPlatformLibrarySuffix = ".dylib";
#else
  static const std::string kPlatformLibraryPrefix = "lib";
  static const std::string kPlatformLibrarySuffix = ".so";
#endif  // defined(__APPLE__)

  void* handle = dlopen(driver_name, RTLD_NOW | RTLD_LOCAL);
  if (!handle) {
    error_message = "dlopen() failed: ";
    error_message += dlerror();

    // If applicable, append the shared library prefix/extension and
    // try again (this way you don't have to hardcode driver names by
    // platform in the application)
    const std::string driver_str = driver_name;

    std::string full_driver_name;
    if (driver_str.size() < kPlatformLibraryPrefix.size() ||
        driver_str.compare(0, kPlatformLibraryPrefix.size(), kPlatformLibraryPrefix) !=
            0) {
      full_driver_name += kPlatformLibraryPrefix;
    }
    full_driver_name += driver_name;
    if (driver_str.size() < kPlatformLibrarySuffix.size() ||
        driver_str.compare(full_driver_name.size() - kPlatformLibrarySuffix.size(),
                           kPlatformLibrarySuffix.size(), kPlatformLibrarySuffix) != 0) {
      full_driver_name += kPlatformLibrarySuffix;
    }
    handle = dlopen(full_driver_name.c_str(), RTLD_NOW | RTLD_LOCAL);
    if (!handle) {
      error_message += "\ndlopen() failed: ";
      error_message += dlerror();
    }
  }
  if (!handle) {
    SetError(error, error_message);
    // AdbcDatabaseInit tries to call this if set
    driver->release = nullptr;
    return ADBC_STATUS_INTERNAL;
  }

  void* load_handle = dlsym(handle, entrypoint);
  if (!load_handle) {
    std::string message = "dlsym(";
    message += entrypoint;
    message += ") failed: ";
    message += dlerror();
    SetError(error, message);
    return ADBC_STATUS_INTERNAL;
  }
  init_func = reinterpret_cast<AdbcDriverInitFunc>(load_handle);

#endif  // defined(_WIN32)

  AdbcStatusCode status = AdbcLoadDriverFromInitFunc(init_func, version, driver, error);
  if (status == ADBC_STATUS_OK) {
    ManagerDriverState* state = new ManagerDriverState;
    state->driver_release = driver->release;
#if defined(_WIN32)
    state->handle = handle;
#endif  // defined(_WIN32)
    driver->release = &ReleaseDriver;
    driver->private_manager = state;
  } else {
#if defined(_WIN32)
    if (!FreeLibrary(handle)) {
      std::string message = "FreeLibrary() failed: ";
      GetWinError(&message);
      SetError(error, message);
    }
#endif  // defined(_WIN32)
  }
  return status;
}