This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 29f942a Fix Windows build (#16)
29f942a is described below
commit 29f942a1a9f165b52426e28bc9dae64459807916
Author: David Li <[email protected]>
AuthorDate: Tue Jun 14 10:55:47 2022 -0400
Fix Windows build (#16)
* Add Windows visibility specifiers
* Try to implement Windows loader
* Add driver cleanup
* Add driver cleanup
* Fix driver cleanup
* Address TODOs
---
adbc.h | 61 +++++++--
adbc_driver_manager/CMakeLists.txt | 9 +-
adbc_driver_manager/adbc_driver_manager.cc | 167 ++++++++++++++++++++++--
adbc_driver_manager/adbc_driver_manager.h | 2 +
adbc_driver_manager/adbc_driver_manager_test.cc | 8 ++
drivers/flight_sql/CMakeLists.txt | 5 +
drivers/sqlite/CMakeLists.txt | 5 +
drivers/sqlite/sqlite.cc | 21 +--
drivers/util.h | 7 -
9 files changed, 235 insertions(+), 50 deletions(-)
diff --git a/adbc.h b/adbc.h
index fb3db59..a1a3bda 100644
--- a/adbc.h
+++ b/adbc.h
@@ -116,6 +116,17 @@ struct ArrowArrayStream {
#ifndef ADBC
#define ADBC
+// Storage class macros for Windows
+#if defined(_WIN32)
+#if defined(ADBC_EXPORTING)
+#define ADBC_EXPORT __declspec(dllexport)
+#else
+#define ADBC_EXPORT __declspec(dllimport)
+#endif // defined(ADBC_EXPORTING)
+#else
+#define ADBC_EXPORT
+#endif // defined(_WIN32)
+
/// \file ADBC: Arrow DataBase connectivity (client API)
///
/// Implemented by libadbc.so (provided by Arrow/C++), which in turn
@@ -160,7 +171,7 @@ typedef uint8_t AdbcStatusCode;
#define ADBC_STATUS_IO 6
/// \brief A detailed error message for an operation.
-struct AdbcError {
+struct ADBC_EXPORT AdbcError {
/// \brief The error message.
char* message;
@@ -184,7 +195,7 @@ struct AdbcError {
/// \brief An instance of a database.
///
/// Must be kept alive as long as any connections exist.
-struct AdbcDatabase {
+struct ADBC_EXPORT AdbcDatabase {
/// \brief Opaque implementation-defined state.
/// This field is NULLPTR iff the connection is unintialized/freed.
void* private_data;
@@ -194,9 +205,11 @@ struct AdbcDatabase {
};
/// \brief Allocate a new (but uninitialized) database.
+ADBC_EXPORT
AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct
AdbcError* error);
/// \brief Set a char* option.
+ADBC_EXPORT
AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const
char* key,
const char* value, struct AdbcError*
error);
@@ -204,12 +217,14 @@ AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase*
database, const char*
///
/// Some backends may support setting options after initialization
/// as well.
+ADBC_EXPORT
AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase* database, struct
AdbcError* error);
/// \brief Destroy this database. No connections may exist.
/// \param[in] database The database to release.
/// \param[out] error An optional location to return an error
/// message if necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase* database,
struct AdbcError* error);
@@ -219,7 +234,7 @@ AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase*
database,
/// @{
/// \brief A set of connection options.
-struct AdbcConnectionOptions {
+struct ADBC_EXPORT AdbcConnectionOptions {
/// \brief The database to connect to.
struct AdbcDatabase* database;
@@ -236,7 +251,7 @@ struct AdbcConnectionOptions {
///
/// Connections are not thread-safe and clients should take care to
/// serialize accesses to a connection.
-struct AdbcConnection {
+struct ADBC_EXPORT AdbcConnection {
/// \brief Opaque implementation-defined state.
/// This field is NULLPTR iff the connection is unintialized/freed.
void* private_data;
@@ -246,14 +261,17 @@ struct AdbcConnection {
};
/// \brief Allocate a new (but uninitialized) connection.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionNew(struct AdbcDatabase* database,
struct AdbcConnection* connection,
struct AdbcError* error);
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection,
const char* key,
const char* value, struct AdbcError*
error);
/// \brief Finish setting options and initialize the connection.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection,
struct AdbcError* error);
@@ -261,6 +279,7 @@ AdbcStatusCode AdbcConnectionInit(struct AdbcConnection*
connection,
/// \param[in] connection The connection to release.
/// \param[out] error An optional location to return an error
/// message if necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection,
struct AdbcError* error);
@@ -281,6 +300,7 @@ AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection*
connection,
/// statement can then be read independently.
///
/// A partition can be retrieved from AdbcStatementGetPartitionDesc.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionDeserializePartitionDesc(struct AdbcConnection*
connection,
const uint8_t*
serialized_partition,
size_t serialized_length,
@@ -318,6 +338,7 @@ AdbcStatusCode
AdbcConnectionDeserializePartitionDesc(struct AdbcConnection* con
/// \param[in] connection The database connection.
/// \param[out] statement The result set.
/// \param[out] error Error details, if an error occurs.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetCatalogs(struct AdbcConnection* connection,
struct AdbcStatement* statement,
struct AdbcError* error);
@@ -334,6 +355,7 @@ AdbcStatusCode AdbcConnectionGetCatalogs(struct
AdbcConnection* connection,
/// \param[in] connection The database connection.
/// \param[out] statement The result set.
/// \param[out] error Error details, if an error occurs.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetDbSchemas(struct AdbcConnection* connection,
struct AdbcStatement* statement,
struct AdbcError* error);
@@ -349,6 +371,7 @@ AdbcStatusCode AdbcConnectionGetDbSchemas(struct
AdbcConnection* connection,
/// \param[in] connection The database connection.
/// \param[out] statement The result set.
/// \param[out] error Error details, if an error occurs.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection* connection,
struct AdbcStatement* statement,
struct AdbcError* error);
@@ -379,6 +402,7 @@ AdbcStatusCode AdbcConnectionGetTableTypes(struct
AdbcConnection* connection,
/// from get_table_types.
/// \param[out] statement The result set.
/// \param[out] error Error details, if an error occurs.
+ADBC_EXPORT
AdbcStatusCode AdbcConnectionGetTables(struct AdbcConnection* connection,
const char* catalog, const char*
db_schema,
const char* table_name, const char**
table_types,
@@ -402,7 +426,7 @@ AdbcStatusCode AdbcConnectionGetTables(struct
AdbcConnection* connection,
///
/// Statements are not thread-safe and clients should take care to
/// serialize access.
-struct AdbcStatement {
+struct ADBC_EXPORT AdbcStatement {
/// \brief Opaque implementation-defined state.
/// This field is NULLPTR iff the connection is unintialized/freed.
void* private_data;
@@ -416,6 +440,7 @@ struct AdbcStatement {
///
/// Set options on the statement, then call AdbcStatementExecute or
/// AdbcStatementPrepare.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementNew(struct AdbcConnection* connection,
struct AdbcStatement* statement, struct
AdbcError* error);
@@ -423,14 +448,17 @@ AdbcStatusCode AdbcStatementNew(struct AdbcConnection*
connection,
/// \param[in] statement The statement to release.
/// \param[out] error An optional location to return an error
/// message if necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementRelease(struct AdbcStatement* statement,
struct AdbcError* error);
/// \brief Execute a statement.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementExecute(struct AdbcStatement* statement,
struct AdbcError* error);
/// \brief Create a prepared statement to be executed multiple times.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement* statement,
struct AdbcError* error);
@@ -450,6 +478,7 @@ AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement*
statement,
/// \param[in] statement The statement.
/// \param[in] query The query to execute.
/// \param[out] error Error details, if an error occurs.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement* statement,
const char* query, struct AdbcError*
error);
@@ -472,6 +501,7 @@ AdbcStatusCode AdbcStatementSetSqlQuery(struct
AdbcStatement* statement,
/// \param[in] plan The serialized substrait.Plan to execute.
/// \param[in] length The length of the serialized plan.
/// \param[out] error Error details, if an error occurs.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementSetSubstraitPlan(struct AdbcStatement* statement,
const uint8_t* plan, size_t
length,
struct AdbcError* error);
@@ -487,6 +517,7 @@ AdbcStatusCode AdbcStatementSetSubstraitPlan(struct
AdbcStatement* statement,
/// \param[in] schema The schema of the values to bind.
/// \param[out] error An optional location to return an error message
/// if necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementBind(struct AdbcStatement* statement,
struct ArrowArray* values, struct
ArrowSchema* schema,
struct AdbcError* error);
@@ -499,6 +530,7 @@ AdbcStatusCode AdbcStatementBind(struct AdbcStatement*
statement,
/// statement is released.
/// \param[out] error An optional location to return an error message
/// if necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement* statement,
struct ArrowArrayStream* values,
struct AdbcError* error);
@@ -511,11 +543,13 @@ AdbcStatusCode AdbcStatementBindStream(struct
AdbcStatement* statement,
///
/// \return out A stream of Arrow data. The stream itself must be
/// released before the statement is released.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementGetStream(struct AdbcStatement* statement,
struct ArrowArrayStream* out,
struct AdbcError* error);
/// \brief Set a string option on a statement.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const
char* key,
const char* value, struct AdbcError*
error);
@@ -564,6 +598,7 @@ AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement*
statement, const cha
/// are no more partitions.
/// \param[out] error An optional location to return an error message if
/// necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementGetPartitionDescSize(struct AdbcStatement*
statement,
size_t* length, struct
AdbcError* error);
@@ -583,6 +618,7 @@ AdbcStatusCode AdbcStatementGetPartitionDescSize(struct
AdbcStatement* statement
/// queried with AdbcStatementGetPartitionDescSize.
/// \param[out] error An optional location to return an error message if
/// necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcStatementGetPartitionDesc(struct AdbcStatement* statement,
uint8_t* partition_desc,
struct AdbcError* error);
@@ -601,12 +637,21 @@ AdbcStatusCode AdbcStatementGetPartitionDesc(struct
AdbcStatement* statement,
/// struct, and applications can call ADBC functions through this
/// struct, without worrying about multiple definitions of the same
/// symbol.
-struct AdbcDriver {
- /// \brief Opaque implementation-defined state.
+struct ADBC_EXPORT AdbcDriver {
+ /// \brief Opaque driver-defined state.
/// This field is NULLPTR if the driver is unintialized/freed (but
/// it need not have a value even if the driver is initialized).
void* private_data;
- // TODO: DriverRelease
+ /// \brief Opaque driver manager-defined state.
+ /// This field is NULLPTR if the driver is unintialized/freed (but
+ /// it need not have a value even if the driver is initialized).
+ void* private_manager;
+
+ /// \brief Release the driver and perform any cleanup.
+ ///
+ /// Unlike other structures, this is an embedded callback to make it
+ /// easier for the driver manager and driver to cooperate.
+ AdbcStatusCode (*release)(struct AdbcDriver* driver, struct AdbcError*
error);
AdbcStatusCode (*DatabaseNew)(struct AdbcDatabase*, struct AdbcError*);
AdbcStatusCode (*DatabaseSetOption)(struct AdbcDatabase*, const char*, const
char*,
diff --git a/adbc_driver_manager/CMakeLists.txt
b/adbc_driver_manager/CMakeLists.txt
index 81887e7..2533e07 100644
--- a/adbc_driver_manager/CMakeLists.txt
+++ b/adbc_driver_manager/CMakeLists.txt
@@ -27,8 +27,15 @@ project(adbc_driver_manager
VERSION "${ADBC_BASE_VERSION}"
LANGUAGES CXX)
include(CTest)
-add_arrow_lib(adbc_driver_manager SOURCES adbc_driver_manager.cc)
+add_arrow_lib(adbc_driver_manager
+ SOURCES
+ adbc_driver_manager.cc
+ OUTPUTS
+ ADBC_LIBRARIES)
include_directories(SYSTEM ${REPOSITORY_ROOT})
+foreach(LIB_TARGET ${ADBC_LIBRARIES})
+ target_compile_definitions(${LIB_TARGET} PRIVATE ADBC_EXPORTING)
+endforeach()
if(ADBC_BUILD_TESTS)
find_package(Arrow REQUIRED)
diff --git a/adbc_driver_manager/adbc_driver_manager.cc
b/adbc_driver_manager/adbc_driver_manager.cc
index 7872bdf..c273fb4 100644
--- a/adbc_driver_manager/adbc_driver_manager.cc
+++ b/adbc_driver_manager/adbc_driver_manager.cc
@@ -17,12 +17,20 @@
#include "adbc_driver_manager.h"
-#include <dlfcn.h>
#include <algorithm>
#include <cstring>
#include <string>
#include <unordered_map>
+#if defined(_WIN32)
+#include <windows.h> // Must come first
+
+#include <libloaderapi.h>
+#include <strsafe.h>
+#else
+#include <dlfcn.h>
+#endif // defined(_WIN32)
+
namespace {
void ReleaseError(struct AdbcError* error) {
if (error) {
@@ -32,9 +40,23 @@ void ReleaseError(struct AdbcError* error) {
}
void SetError(struct AdbcError* error, const std::string& message) {
- error->message = new char[message.size() + 1];
- message.copy(error->message, message.size());
- error->message[message.size()] = '\0';
+ if (!error) return;
+ if (error->message) {
+ // Append
+ std::string buffer = error->message;
+ buffer.reserve(buffer.size() + message.size() + 1);
+ buffer += '\n';
+ buffer += message;
+ error->release(error);
+
+ error->message = new char[buffer.size() + 1];
+ buffer.copy(error->message, buffer.size());
+ error->message[buffer.size()] = '\0';
+ } else {
+ error->message = new char[message.size() + 1];
+ message.copy(error->message, message.size());
+ error->message[message.size()] = '\0';
+ }
error->release = ReleaseError;
}
@@ -74,6 +96,56 @@ struct TempDatabase {
std::string driver;
std::string entrypoint;
};
+
+#if defined(_WIN32)
+/// Append a description of the Windows error to the buffer.
+void GetWinError(std::string* buffer) {
+ DWORD rc = GetLastError();
+ LPVOID message;
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ /*lpSource=*/nullptr, rc, MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
+ reinterpret_cast<LPSTR>(&message), /*nSize=*/0,
/*Arguments=*/nullptr);
+
+ (*buffer) += '(';
+ (*buffer) += std::to_string(rc);
+ (*buffer) += ") ";
+ (*buffer) += reinterpret_cast<char*>(message);
+ LocalFree(message);
+}
+
+/// Hold the driver DLL and the driver release callback in the driver struct.
+struct ManagerDriverState {
+ // The loaded DLL
+ HMODULE handle;
+ // The original release callback
+ AdbcStatusCode (*driver_release)(struct AdbcDriver* driver, struct
AdbcError* error);
+};
+
+/// Unload the driver DLL.
+static AdbcStatusCode ReleaseDriver(struct AdbcDriver* driver, struct
AdbcError* error) {
+ AdbcStatusCode status = ADBC_STATUS_OK;
+
+ if (!driver->private_manager) return status;
+ ManagerDriverState* state =
+ reinterpret_cast<ManagerDriverState*>(driver->private_manager);
+
+ if (state->driver_release) {
+ status = state->driver_release(driver, error);
+ }
+
+ if (!FreeLibrary(state->handle)) {
+ std::string message = "FreeLibrary() failed: ";
+ GetWinError(&message);
+ SetError(error, message);
+ }
+
+ driver->private_manager = nullptr;
+ delete state;
+ return status;
+}
+#endif
} // namespace
// Direct implementations of API methods
@@ -125,17 +197,34 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase*
database, struct AdbcError*
database->private_driver, &initialized, error);
if (status != ADBC_STATUS_OK) {
delete args;
+
+ if (database->private_driver->release) {
+ database->private_driver->release(database->private_driver, error);
+ }
delete database->private_driver;
return status;
} else if (initialized < ADBC_VERSION_0_0_1) {
delete args;
+
+ if (database->private_driver->release) {
+ database->private_driver->release(database->private_driver, error);
+ }
delete database->private_driver;
- SetError(error, "Database version is too old"); // TODO: clearer error
+
+ std::string message = "Database version is too old, expected ";
+ message += std::to_string(ADBC_VERSION_0_0_1);
+ message += " but got ";
+ message += std::to_string(initialized);
+ SetError(error, message);
return status;
}
status = database->private_driver->DatabaseNew(database, error);
if (status != ADBC_STATUS_OK) {
delete args;
+
+ if (database->private_driver->release) {
+ database->private_driver->release(database->private_driver, error);
+ }
delete database->private_driver;
return status;
}
@@ -144,6 +233,10 @@ AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase*
database, struct AdbcError*
option.second.c_str(), error);
if (status != ADBC_STATUS_OK) {
delete args;
+
+ if (database->private_driver->release) {
+ database->private_driver->release(database->private_driver, error);
+ }
delete database->private_driver;
return status;
}
@@ -158,6 +251,9 @@ AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase*
database,
return ADBC_STATUS_UNINITIALIZED;
}
auto status = database->private_driver->DatabaseRelease(database, error);
+ if (database->private_driver->release) {
+ database->private_driver->release(database->private_driver, error);
+ }
delete database->private_driver;
return status;
}
@@ -176,7 +272,6 @@ AdbcStatusCode AdbcConnectionNew(struct AdbcDatabase*
database,
AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection,
struct AdbcError* error) {
if (!connection->private_driver) {
- // TODO: set error
return ADBC_STATUS_INVALID_ARGUMENT;
}
return connection->private_driver->ConnectionInit(connection, error);
@@ -318,16 +413,54 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name,
const char* entrypoint,
return ADBC_STATUS_INTERNAL;
\
}
- // TODO: handle Windows
+ AdbcDriverInitFunc init_func;
+ std::string error_message;
+
+#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 = GetProcAddress(handle, entrypoint);
+ init_func = reinterpret_cast<AdbcDriverInitFunc>(load_handle);
+ if (!init_func) {
+ std::string message = "GetProcAddress() 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
-
- std::string error_message;
+#endif // defined(__APPLE__)
void* handle = dlopen(driver_name, RTLD_NOW | RTLD_LOCAL);
if (!handle) {
@@ -359,19 +492,25 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name,
const char* entrypoint,
}
if (!handle) {
SetError(error, error_message);
- return ADBC_STATUS_UNKNOWN;
+ return ADBC_STATUS_INTERNAL;
}
void* load_handle = dlsym(handle, entrypoint);
- auto* load = reinterpret_cast<AdbcDriverInitFunc>(load_handle);
- if (!load) {
+ init_func = reinterpret_cast<AdbcDriverInitFunc>(load_handle);
+ if (!init_func) {
std::string message = "dlsym() failed: ";
message += dlerror();
SetError(error, message);
return ADBC_STATUS_INTERNAL;
}
- auto result = load(count, driver, initialized, error);
+#endif // defined(_WIN32)
+
+ auto result = init_func(count, driver, initialized, error);
+#if defined(_WIN32)
+ driver->private_manager = new ManagerDriverState{handle, driver->release};
+ driver->release = &ReleaseDriver;
+#endif // defined(_WIN32)
if (result != ADBC_STATUS_OK) {
return result;
}
diff --git a/adbc_driver_manager/adbc_driver_manager.h
b/adbc_driver_manager/adbc_driver_manager.h
index d20c4b1..bdc25a2 100644
--- a/adbc_driver_manager/adbc_driver_manager.h
+++ b/adbc_driver_manager/adbc_driver_manager.h
@@ -44,11 +44,13 @@ extern "C" {
/// initialized (can be less than count).
/// \param[out] error An optional location to return an error message
/// if necessary.
+ADBC_EXPORT
AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint,
size_t count, struct AdbcDriver* driver,
size_t* initialized, struct AdbcError* error);
/// \brief Get a human-friendly description of a status code.
+ADBC_EXPORT
const char* AdbcStatusCodeMessage(AdbcStatusCode code);
#endif // ADBC_DRIVER_MANAGER_H
diff --git a/adbc_driver_manager/adbc_driver_manager_test.cc
b/adbc_driver_manager/adbc_driver_manager_test.cc
index f365101..cdfc4e2 100644
--- a/adbc_driver_manager/adbc_driver_manager_test.cc
+++ b/adbc_driver_manager/adbc_driver_manager_test.cc
@@ -36,6 +36,8 @@ using arrow::PointeesEqual;
class DriverManager : public ::testing::Test {
public:
void SetUp() override {
+ std::memset(&driver, 0, sizeof(driver));
+
size_t initialized = 0;
ADBC_ASSERT_OK_WITH_ERROR(
error, AdbcLoadDriver("adbc_driver_sqlite", "AdbcSqliteDriverInit",
@@ -63,6 +65,12 @@ class DriverManager : public ::testing::Test {
ADBC_ASSERT_OK_WITH_ERROR(error, AdbcDatabaseRelease(&database, &error));
ASSERT_EQ(database.private_data, nullptr);
+
+ if (driver.release) {
+ ADBC_ASSERT_OK_WITH_ERROR(error, driver.release(&driver, &error));
+ ASSERT_EQ(driver.private_data, nullptr);
+ ASSERT_EQ(driver.private_manager, nullptr);
+ }
}
protected:
diff --git a/drivers/flight_sql/CMakeLists.txt
b/drivers/flight_sql/CMakeLists.txt
index 0841a9e..33f53e1 100644
--- a/drivers/flight_sql/CMakeLists.txt
+++ b/drivers/flight_sql/CMakeLists.txt
@@ -34,6 +34,8 @@ find_package(ArrowFlightSql REQUIRED HINTS
${ARROW_CONFIG_PATH})
add_arrow_lib(adbc_driver_flight_sql
SOURCES
flight_sql.cc
+ OUTPUTS
+ ADBC_LIBRARIES
SHARED_LINK_LIBS
arrow_flight_sql_shared
arrow_flight_shared
@@ -43,6 +45,9 @@ add_arrow_lib(adbc_driver_flight_sql
arrow_flight_static
arrow_static)
include_directories(SYSTEM ${REPOSITORY_ROOT})
+foreach(LIB_TARGET ${ADBC_LIBRARIES})
+ target_compile_definitions(${LIB_TARGET} PRIVATE ADBC_EXPORTING)
+endforeach()
if(ADBC_BUILD_TESTS)
if(ADBC_TEST_LINKAGE STREQUAL "shared")
diff --git a/drivers/sqlite/CMakeLists.txt b/drivers/sqlite/CMakeLists.txt
index 11b1b72..0872486 100644
--- a/drivers/sqlite/CMakeLists.txt
+++ b/drivers/sqlite/CMakeLists.txt
@@ -32,6 +32,8 @@ find_package(SQLite3 REQUIRED)
add_arrow_lib(adbc_driver_sqlite
SOURCES
sqlite.cc
+ OUTPUTS
+ ADBC_LIBRARIES
SHARED_LINK_LIBS
SQLite::SQLite3
arrow_shared
@@ -40,6 +42,9 @@ add_arrow_lib(adbc_driver_sqlite
arrow_static)
include_directories(SYSTEM ${REPOSITORY_ROOT})
include_directories(SYSTEM ${SQLite3_INCLUDE_DIRS})
+foreach(LIB_TARGET ${ADBC_LIBRARIES})
+ target_compile_definitions(${LIB_TARGET} PRIVATE ADBC_EXPORTING)
+endforeach()
if(ADBC_TEST_LINKAGE STREQUAL "shared")
set(TEST_LINK_LIBS adbc_driver_sqlite_shared)
diff --git a/drivers/sqlite/sqlite.cc b/drivers/sqlite/sqlite.cc
index e141fa6..2973794 100644
--- a/drivers/sqlite/sqlite.cc
+++ b/drivers/sqlite/sqlite.cc
@@ -777,127 +777,108 @@ AdbcStatusCode SqliteStatementSetSqlQuery(struct
AdbcStatement* statement,
} // namespace
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase* database, struct
AdbcError* error) {
return SqliteDatabaseInit(database, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct
AdbcError* error) {
return SqliteDatabaseNew(database, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const
char* key,
const char* value, struct AdbcError*
error) {
return SqliteDatabaseSetOption(database, key, value, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase* database,
struct AdbcError* error) {
return SqliteDatabaseRelease(database, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcConnectionNew(struct AdbcDatabase* database,
struct AdbcConnection* connection,
struct AdbcError* error) {
return SqliteConnectionNew(database, connection, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection,
const char* key,
const char* value, struct AdbcError*
error) {
return SqliteConnectionSetOption(connection, key, value, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection,
struct AdbcError* error) {
return SqliteConnectionInit(connection, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection,
struct AdbcError* error) {
return SqliteConnectionRelease(connection, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementBind(struct AdbcStatement* statement,
struct ArrowArray* values, struct
ArrowSchema* schema,
struct AdbcError* error) {
return SqliteStatementBind(statement, values, schema, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement* statement,
struct ArrowArrayStream* stream,
struct AdbcError* error) {
return SqliteStatementBindStream(statement, stream, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementExecute(struct AdbcStatement* statement,
struct AdbcError* error) {
return SqliteStatementExecute(statement, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementGetPartitionDesc(struct AdbcStatement* statement,
uint8_t* partition_desc,
struct AdbcError* error) {
return SqliteStatementGetPartitionDesc(statement, partition_desc, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementGetPartitionDescSize(struct AdbcStatement*
statement,
size_t* length,
struct AdbcError* error) {
return SqliteStatementGetPartitionDescSize(statement, length, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementGetStream(struct AdbcStatement* statement,
struct ArrowArrayStream* out,
struct AdbcError* error) {
return SqliteStatementGetStream(statement, out, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementNew(struct AdbcConnection* connection,
struct AdbcStatement* statement,
struct AdbcError* error) {
return SqliteStatementNew(connection, statement, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement* statement,
struct AdbcError* error) {
return SqliteStatementPrepare(statement, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementRelease(struct AdbcStatement* statement,
struct AdbcError* error) {
return SqliteStatementRelease(statement, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const
char* key,
const char* value, struct AdbcError*
error) {
return SqliteStatementSetOption(statement, key, value, error);
}
-ADBC_DRIVER_EXPORT
AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement* statement,
const char* query, struct AdbcError*
error) {
return SqliteStatementSetSqlQuery(statement, query, error);
}
extern "C" {
-ARROW_EXPORT
+ADBC_EXPORT
AdbcStatusCode AdbcSqliteDriverInit(size_t count, struct AdbcDriver* driver,
size_t* initialized, struct AdbcError*
error) {
if (count < ADBC_VERSION_0_0_1) return ADBC_STATUS_NOT_IMPLEMENTED;
diff --git a/drivers/util.h b/drivers/util.h
index da998a0..1ac8408 100644
--- a/drivers/util.h
+++ b/drivers/util.h
@@ -21,13 +21,6 @@
#include "arrow/result.h"
#include "arrow/util/string_view.h"
-// TODO: dllimport/dllexport for Windows. Should that go in adbc.h instead?
-#ifdef __linux__
-#define ADBC_DRIVER_EXPORT
-#else
-#define ADBC_DRIVER_EXPORT
-#endif // ifdef __linux__
-
#define ADBC_RETURN_NOT_OK(expr) \
do { \
auto _s = (expr); \