diff --git a/go/adbc/drivermgr/adbc_driver_manager.cc b/go/adbc/drivermgr/adbc_driver_manager.cc deleted file mode 100644 index 93bc787915..0000000000 --- a/go/adbc/drivermgr/adbc_driver_manager.cc +++ /dev/null @@ -1,2795 +0,0 @@ -// 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. - -#if defined(_WIN32) -#define NOMINMAX -#include // Must come first - -#ifndef NTDDI_VERSION -#define NTDDI_VERSION 0x0A00000C // For SHGetKnownFolderPath in ShlObj_core.h in ShlObj.h -#endif - -#include -#include -#include -#include // _wcsnicmp -#include -#include -#else -#include -#endif // defined(_WIN32) - -#include -#include "arrow-adbc/adbc.h" -#include "arrow-adbc/adbc_driver_manager.h" -#include "current_arch.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::string_literals; // NOLINT [build/namespaces] - -ADBC_EXPORT -std::vector InternalAdbcParsePath(const std::string_view path); -ADBC_EXPORT -std::filesystem::path InternalAdbcUserConfigDir(); -#if !defined(_WIN32) -ADBC_EXPORT -std::filesystem::path InternalAdbcSystemConfigDir(); -#endif // !defined(_WIN32) - -struct ParseDriverUriResult { - std::string_view driver; - std::optional uri; -}; - -ADBC_EXPORT -std::optional InternalAdbcParseDriverUri(std::string_view str); - -namespace { - -/// \brief Where a search path came from (for error reporting) -enum class SearchPathSource { - kEnv, - kUser, - kRegistry, - kSystem, - kAdditional, - kConda, - kUnset, - kDoesNotExist, - kDisabledAtCompileTime, - kDisabledAtRunTime, - kOtherError, -}; - -using SearchPaths = std::vector>; - -void AddSearchPathsToError(const SearchPaths& search_paths, std::string& error_message) { - if (!search_paths.empty()) { - error_message += "\nAlso searched these paths for manifests:"; - for (const auto& [source, path] : search_paths) { - error_message += "\n\t"; - switch (source) { - case SearchPathSource::kEnv: - error_message += "ADBC_DRIVER_PATH: "; - break; - case SearchPathSource::kUser: - error_message += "user config dir: "; - break; - case SearchPathSource::kRegistry: - error_message += "Registry: "; - break; - case SearchPathSource::kSystem: - error_message += "system config dir: "; - break; - case SearchPathSource::kAdditional: - error_message += "additional search path: "; - break; - case SearchPathSource::kConda: - error_message += "Conda prefix: "; - break; - case SearchPathSource::kUnset: - error_message += "not set: "; - break; - case SearchPathSource::kDoesNotExist: - error_message += "does not exist: "; - break; - case SearchPathSource::kDisabledAtCompileTime: - error_message += "not enabled at build time: "; - break; - case SearchPathSource::kDisabledAtRunTime: - error_message += "not enabled at run time: "; - break; - case SearchPathSource::kOtherError: - // Don't add any prefix - break; - } - error_message += path.string(); - } - } -} - -// Platform-specific helpers - -#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(&message), /*nSize=*/0, /*Arguments=*/nullptr); - - (*buffer) += '('; - (*buffer) += std::to_string(rc); - (*buffer) += ") "; - (*buffer) += reinterpret_cast(message); - LocalFree(message); -} - -#endif // defined(_WIN32) - -// Error handling - -void ReleaseError(struct AdbcError* error) { - if (error) { - if (error->message) delete[] error->message; - error->message = nullptr; - error->release = nullptr; - } -} - -void SetError(struct AdbcError* error, const std::string& message) { - static const std::string kPrefix = "[Driver Manager] "; - - if (!error) return; - if (error->release) error->release(error); - - // Prepend a string to identify driver manager errors - error->message = new char[kPrefix.size() + message.size() + 1]; - kPrefix.copy(error->message, kPrefix.size()); - message.copy(error->message + kPrefix.size(), message.size()); - error->message[kPrefix.size() + message.size()] = '\0'; - error->release = ReleaseError; -} - -void AppendError(struct AdbcError* error, const std::string& message) { - if (!error) return; - if (!error->release || !error->message) { - SetError(error, message); - return; - } - - size_t original_length = std::strlen(error->message); - size_t combined_length = original_length + 1 + message.size() + 1; - char* new_message = new char[combined_length]; - std::ignore = std::snprintf(new_message, combined_length, "%s\n%s", error->message, - message.c_str()); - - error->release(error); - error->message = new_message; - error->release = ReleaseError; -} - -// Copies src_error into error and releases src_error -void SetError(struct AdbcError* error, struct AdbcError* src_error) { - if (!error) return; - if (error->release) error->release(error); - - if (src_error->message) { - size_t message_size = strlen(src_error->message); - error->message = new char[message_size]; - std::memcpy(error->message, src_error->message, message_size); - error->message[message_size] = '\0'; - } else { - error->message = nullptr; - } - - error->release = ReleaseError; - if (src_error->release) { - src_error->release(src_error); - } -} - -struct OwnedError { - struct AdbcError error = ADBC_ERROR_INIT; - - ~OwnedError() { - if (error.release) { - error.release(&error); - } - } -}; - -#ifdef _WIN32 -using char_type = wchar_t; - -std::string Utf8Encode(const std::wstring& wstr) { - if (wstr.empty()) return std::string(); - int size_needed = WideCharToMultiByte( - CP_UTF8, 0, wstr.data(), static_cast(wstr.size()), NULL, 0, NULL, NULL); - std::string str_to(size_needed, 0); - WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.size()), - str_to.data(), size_needed, NULL, NULL); - return str_to; -} - -std::wstring Utf8Decode(const std::string& str) { - if (str.empty()) return std::wstring(); - int size_needed = - MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), NULL, 0); - std::wstring wstr_to(size_needed, 0); - MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), - wstr_to.data(), size_needed); - return wstr_to; -} - -#else -using char_type = char; -#endif // _WIN32 - -/// \brief The location and entrypoint of a resolved driver. -struct DriverInfo { - std::string manifest_file; - int64_t manifest_version = 0; - std::string driver_name; - std::filesystem::path lib_path; - std::string entrypoint; - - std::string version; - std::string source; -}; - -#ifdef _WIN32 -class RegistryKey { - public: - RegistryKey(HKEY root, const std::wstring_view subkey) noexcept - : root_(root), key_(nullptr) { - status_ = RegOpenKeyExW(root_, subkey.data(), 0, KEY_READ, &key_); - } - - ~RegistryKey() { - if (is_open() && key_ != nullptr) { - RegCloseKey(key_); - key_ = nullptr; - status_ = ERROR_REGISTRY_IO_FAILED; - } - } - - HKEY key() const { return key_; } - bool is_open() const { return status_ == ERROR_SUCCESS; } - LSTATUS status() const { return status_; } - - std::wstring GetString(const std::wstring& name, std::wstring default_value) { - if (!is_open()) return default_value; - - DWORD type = REG_SZ; - DWORD size = 0; - auto result = RegQueryValueExW(key_, name.data(), nullptr, &type, nullptr, &size); - if (result != ERROR_SUCCESS) return default_value; - if (type != REG_SZ) return default_value; - - std::wstring value(size, '\0'); - result = RegQueryValueExW(key_, name.data(), nullptr, &type, - reinterpret_cast(value.data()), &size); - if (result != ERROR_SUCCESS) return default_value; - return value; - } - - int32_t GetInt(const std::wstring& name, const int32_t default_value) { - if (!is_open()) return default_value; - - DWORD dwValue; - DWORD dataSize = sizeof(dwValue); - DWORD valueType; - auto result = RegQueryValueExW(key_, name.data(), nullptr, &valueType, - (LPBYTE)&dwValue, &dataSize); - if (result != ERROR_SUCCESS) return default_value; - if (valueType != REG_DWORD) return default_value; - return static_cast(dwValue); - } - - private: - HKEY root_; - HKEY key_; - LSTATUS status_; -}; - -AdbcStatusCode LoadDriverFromRegistry(HKEY root, const std::wstring& driver_name, - DriverInfo& info, struct AdbcError* error) { - // N.B. start all error messages with the subkey so that the calling code - // can prepend the name of 'root' to the error message (easier than trying - // to invoke win32 API to get the name of the HKEY) - static const LPCWSTR kAdbcDriverRegistry = L"SOFTWARE\\ADBC\\Drivers"; - RegistryKey drivers_key(root, kAdbcDriverRegistry); - if (!drivers_key.is_open()) { - std::string error_message = "SOFTWARE\\ADBC\\DRIVERS not found"s; - SetError(error, std::move(error_message)); - return ADBC_STATUS_NOT_FOUND; - } - - RegistryKey dkey(drivers_key.key(), driver_name); - if (!dkey.is_open()) { - std::string error_message = "SOFTWARE\\ADBC\\DRIVERS has no entry for driver \""s; - error_message += Utf8Encode(driver_name); - error_message += "\""s; - SetError(error, std::move(error_message)); - return ADBC_STATUS_NOT_FOUND; - } - - info.driver_name = Utf8Encode(dkey.GetString(L"name", L"")); - info.manifest_version = int64_t(dkey.GetInt(L"manifest_version", 1)); - if (info.manifest_version != 1) { - SetError(error, "Driver manifest version '" + std::to_string(info.manifest_version) + - "' is not supported by this driver manager."); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - info.entrypoint = Utf8Encode(dkey.GetString(L"entrypoint", L"")); - info.version = Utf8Encode(dkey.GetString(L"version", L"")); - info.source = Utf8Encode(dkey.GetString(L"source", L"")); - info.lib_path = std::filesystem::path(dkey.GetString(L"driver", L"")); - if (info.lib_path.empty()) { - std::string error_message = "SOFTWARE\\ADBC\\DRIVERS\\"s; - error_message += Utf8Encode(driver_name); - error_message += " has no driver path"s; - SetError(error, std::move(error_message)); - return ADBC_STATUS_NOT_FOUND; - } - return ADBC_STATUS_OK; -} -#endif // _WIN32 - -/// \return ADBC_STATUS_NOT_FOUND if the manifest does not contain a driver -/// path for this platform, ADBC_STATUS_INVALID_ARGUMENT if the manifest -/// could not be parsed, ADBC_STATUS_OK otherwise (`info` will be populated) -AdbcStatusCode LoadDriverManifest(const std::filesystem::path& driver_manifest, - DriverInfo& info, struct AdbcError* error) { - toml::table config; - try { - config = toml::parse_file(driver_manifest.native()); - } catch (const toml::parse_error& err) { - // Despite the name, this exception covers IO errors too. Hence, we can't - // differentiate between bad syntax and other I/O error. - std::string message = "Could not open manifest. "; - message += err.what(); - message += ". Manifest: "; - message += driver_manifest.string(); - SetError(error, std::move(message)); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - info.manifest_file = driver_manifest.string(); - info.driver_name = config["name"].value_or(""s); - info.manifest_version = config["manifest_version"].value_or(int64_t(1)); - if (info.manifest_version != 1) { - SetError(error, "Driver manifest version '" + std::to_string(info.manifest_version) + - "' is not supported by this driver manager."); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - info.entrypoint = config.at_path("Driver.entrypoint").value_or(""s); - info.version = config["version"].value_or(""s); - info.source = config["source"].value_or(""s); - - auto entrypoint = config.at_path("Driver.entrypoint"); - if (entrypoint) { - if (auto* ep = entrypoint.as_string()) { - info.entrypoint = ep->get(); - } else { - SetError(error, "Driver entrypoint not a string in manifest '"s + - driver_manifest.string() + "'"s); - return ADBC_STATUS_INVALID_ARGUMENT; - } - } - - auto driver = config.at_path("Driver.shared"); - if (toml::table* platforms = driver.as_table()) { - auto view = platforms->at_path(adbc::CurrentArch()); - if (!view) { - std::string message = "Driver path not found in manifest '"; - message += driver_manifest.string(); - message += "' for current architecture '"; - message += adbc::CurrentArch(); - message += "'. Architectures found:"; - for (const auto& [key, val] : *platforms) { - message += " "; - message += key; - } - SetError(error, std::move(message)); - return ADBC_STATUS_NOT_FOUND; - } else if (auto* path = view.as_string()) { - if (path->get().empty()) { - std::string message = "Driver path is an empty string in manifest '"; - message += driver_manifest.string(); - message += "' for current architecture '"; - message += adbc::CurrentArch(); - message += "'"; - SetError(error, std::move(message)); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - info.lib_path = path->get(); - return ADBC_STATUS_OK; - } - std::string message = "Driver path not found in manifest '"; - message += driver_manifest.string(); - message += "' for current architecture '"; - message += adbc::CurrentArch(); - message += "'. Value was not a string"; - SetError(error, std::move(message)); - return ADBC_STATUS_INVALID_ARGUMENT; - } else if (auto* path = driver.as_string()) { - info.lib_path = path->get(); - if (info.lib_path.empty()) { - SetError(error, "Driver path is an empty string in manifest '"s + - driver_manifest.string() + "'"s); - return ADBC_STATUS_INVALID_ARGUMENT; - } - return ADBC_STATUS_OK; - } - SetError(error, "Driver path not defined in manifest '"s + driver_manifest.string() + - "'. `Driver.shared` must be a string or table"s); - return ADBC_STATUS_INVALID_ARGUMENT; -} - -SearchPaths GetEnvPaths(const char_type* env_var) { -#ifdef _WIN32 - DWORD required_size = GetEnvironmentVariableW(env_var, NULL, 0); - if (required_size == 0) { - return {}; - } - - std::wstring path_var; - path_var.resize(required_size); - DWORD actual_size = GetEnvironmentVariableW(env_var, path_var.data(), required_size); - // Remove null terminator - path_var.resize(actual_size); - auto path = Utf8Encode(path_var); -#else - const char* path_var = std::getenv(env_var); - if (!path_var) { - return {}; - } - std::string path(path_var); -#endif // _WIN32 - SearchPaths paths; - for (auto parsed_path : InternalAdbcParsePath(path)) { - paths.emplace_back(SearchPathSource::kEnv, parsed_path); - } - return paths; -} - -#ifdef _WIN32 -static const wchar_t* kAdbcDriverPath = L"ADBC_DRIVER_PATH"; -#else -static const char* kAdbcDriverPath = "ADBC_DRIVER_PATH"; -#endif // _WIN32 - -SearchPaths GetSearchPaths(const AdbcLoadFlags levels) { - SearchPaths paths; - if (levels & ADBC_LOAD_FLAG_SEARCH_ENV) { - // Check the ADBC_DRIVER_PATH environment variable - paths = GetEnvPaths(kAdbcDriverPath); - } - - if (levels & ADBC_LOAD_FLAG_SEARCH_USER) { - // Check the user configuration directory - std::filesystem::path user_config_dir = InternalAdbcUserConfigDir(); - if (!user_config_dir.empty() && std::filesystem::exists(user_config_dir)) { - paths.emplace_back(SearchPathSource::kUser, std::move(user_config_dir)); - } else { - paths.emplace_back(SearchPathSource::kDoesNotExist, std::move(user_config_dir)); - } - } - - if (levels & ADBC_LOAD_FLAG_SEARCH_SYSTEM) { - // System level behavior for Windows is to search the registry keys so we - // only need to check for macOS and fall back to Unix-like behavior as long - // as we're not on Windows -#if !defined(_WIN32) - const std::filesystem::path system_config_dir = InternalAdbcSystemConfigDir(); - if (std::filesystem::exists(system_config_dir)) { - paths.emplace_back(SearchPathSource::kSystem, std::move(system_config_dir)); - } else { - paths.emplace_back(SearchPathSource::kDoesNotExist, std::move(system_config_dir)); - } -#endif // !defined(_WIN32) - } - - return paths; -} - -bool HasExtension(const std::filesystem::path& path, const std::string& ext) { -#ifdef _WIN32 - auto wext = Utf8Decode(ext); - auto path_ext = path.extension().native(); - return path_ext.size() == wext.size() && - _wcsnicmp(path_ext.data(), wext.data(), wext.size()) == 0; -#else - return path.extension() == ext; -#endif // _WIN32 -} - -/// A driver DLL. -struct ManagedLibrary { - ManagedLibrary() : handle(nullptr) {} - ManagedLibrary(ManagedLibrary&& other) : handle(other.handle) { - other.handle = nullptr; - } - ManagedLibrary(const ManagedLibrary&) = delete; - ManagedLibrary& operator=(const ManagedLibrary&) = delete; - ManagedLibrary& operator=(ManagedLibrary&& other) noexcept { - this->handle = other.handle; - other.handle = nullptr; - return *this; - } - - ~ManagedLibrary() { Release(); } - - void Release() { - // TODO(apache/arrow-adbc#204): causes tests to segfault. Need to - // refcount the driver DLL; also, errors may retain a reference to - // release() from the DLL - how to handle this? It's unlikely we can - // actually do this - in general shared libraries are not safe to unload. - } - - /// \brief Resolve the driver name to a concrete location. - AdbcStatusCode GetDriverInfo( - const std::string_view driver_name, const AdbcLoadFlags load_options, - const std::vector& additional_search_paths, DriverInfo& info, - struct AdbcError* error) { - if (driver_name.empty()) { - SetError(error, "Driver name is empty"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - // First try to treat the given driver name as a path to a manifest or shared library - std::filesystem::path driver_path(driver_name); - const bool allow_relative_paths = load_options & ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS; - if (driver_path.has_extension()) { - if (driver_path.is_relative() && !allow_relative_paths) { - SetError(error, "Driver path is relative and relative paths are not allowed"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - if (HasExtension(driver_path, ".toml")) { - // if the extension is .toml, attempt to load the manifest - // erroring if we fail - - auto status = LoadDriverManifest(driver_path, info, error); - if (status == ADBC_STATUS_OK) { - return Load(info.lib_path.c_str(), {}, error); - } - return status; - } - - // if the extension is not .toml, then just try to load the provided - // path as if it was an absolute path to a driver library - info.lib_path = driver_path; - return Load(driver_path.c_str(), {}, error); - } - - if (driver_path.is_absolute()) { - // if we have an absolute path without an extension, first see if there's a - // toml file with the same name. - driver_path.replace_extension(".toml"); - if (std::filesystem::exists(driver_path)) { - auto status = LoadDriverManifest(driver_path, info, error); - if (status == ADBC_STATUS_OK) { - return Load(info.lib_path.c_str(), {}, error); - } - } - - driver_path.replace_extension(""); - // otherwise just try to load the provided path as if it was an absolute path - info.lib_path = driver_path; - return Load(driver_path.c_str(), {}, error); - } - - if (driver_path.has_extension()) { - if (driver_path.is_relative() && !allow_relative_paths) { - SetError(error, "Driver path is relative and relative paths are not allowed"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - -#if defined(_WIN32) - static const std::string kPlatformLibrarySuffix = ".dll"; -#elif defined(__APPLE__) - static const std::string kPlatformLibrarySuffix = ".dylib"; -#else - static const std::string kPlatformLibrarySuffix = ".so"; -#endif // defined(_WIN32) - if (HasExtension(driver_path, kPlatformLibrarySuffix)) { - info.lib_path = driver_path; - return Load(driver_path.c_str(), {}, error); - } - - SetError(error, "Driver name has unrecognized extension: " + - driver_path.extension().string()); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - // not an absolute path, no extension. Let's search the configured paths - // based on the options - // FindDriver will set info.lib_path - // XXX(lidavidm): the control flow in this call chain is excessively - // convoluted and it's hard to determine if DriverInfo is fully - // initialized or not in all non-error paths - return FindDriver(driver_path, load_options, additional_search_paths, info, error); - } - - /// \return ADBC_STATUS_NOT_FOUND if the driver shared library could not be - /// found (via dlopen) or if a manifest was found but did not contain a - /// path for the current platform, ADBC_STATUS_INVALID_ARGUMENT if a - /// manifest was found but could not be parsed, ADBC_STATUS_OK otherwise - /// - /// May modify search_paths to add error info - AdbcStatusCode SearchPathsForDriver(const std::filesystem::path& driver_path, - SearchPaths& search_paths, DriverInfo& info, - struct AdbcError* error) { - SearchPaths extra_debug_info; - for (const auto& [source, search_path] : search_paths) { - if (source == SearchPathSource::kRegistry || source == SearchPathSource::kUnset || - source == SearchPathSource::kDoesNotExist || - source == SearchPathSource::kDisabledAtCompileTime || - source == SearchPathSource::kDisabledAtRunTime || - source == SearchPathSource::kOtherError) { - continue; - } - std::filesystem::path full_path = search_path / driver_path; - - // check for toml first, then dll - full_path.replace_extension(".toml"); - if (std::filesystem::exists(full_path)) { - OwnedError intermediate_error; - - auto status = LoadDriverManifest(full_path, info, &intermediate_error.error); - if (status == ADBC_STATUS_OK) { - // Don't pass attempted_paths here; we'll generate the error at a higher level - status = Load(info.lib_path.c_str(), {}, &intermediate_error.error); - if (status == ADBC_STATUS_OK) { - return status; - } - std::string message = "found "; - message += full_path.string(); - if (intermediate_error.error.message) { - message += " but: "; - message += intermediate_error.error.message; - } else { - message += " could not load the driver it specified"; - } - extra_debug_info.emplace_back(SearchPathSource::kOtherError, - std::move(message)); - search_paths.insert(search_paths.end(), extra_debug_info.begin(), - extra_debug_info.end()); - return status; - } else if (status == ADBC_STATUS_INVALID_ARGUMENT) { - // The manifest was invalid. Don't ignore that! - search_paths.insert(search_paths.end(), extra_debug_info.begin(), - extra_debug_info.end()); - if (intermediate_error.error.message) { - std::string error_message = intermediate_error.error.message; - AddSearchPathsToError(search_paths, error_message); - SetError(error, std::move(error_message)); - } - return status; - } - // Should be NOT_FOUND otherwise - std::string message = "found "; - message += full_path.string(); - if (intermediate_error.error.message) { - message += " but: "; - message += intermediate_error.error.message; - } else { - message += " which did not define a driver for this platform"; - } - - extra_debug_info.emplace_back(SearchPathSource::kOtherError, std::move(message)); - } - - // remove the .toml extension; Load will add the DLL/SO/DYLIB suffix - full_path.replace_extension(""); - // Don't pass error here - it'll be suppressed anyways - auto status = Load(full_path.c_str(), {}, nullptr); - if (status == ADBC_STATUS_OK) { - info.lib_path = full_path; - return status; - } - } - - search_paths.insert(search_paths.end(), extra_debug_info.begin(), - extra_debug_info.end()); - return ADBC_STATUS_NOT_FOUND; - } - - AdbcStatusCode FindDriver( - const std::filesystem::path& driver_path, const AdbcLoadFlags load_options, - const std::vector& additional_search_paths, DriverInfo& info, - struct AdbcError* error) { - if (driver_path.empty()) { - SetError(error, "Driver path is empty"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - SearchPaths search_paths; - { - // First search the paths in the env var `ADBC_DRIVER_PATH`. - // Then search the runtime application-defined additional search paths. - search_paths = GetSearchPaths(load_options & ADBC_LOAD_FLAG_SEARCH_ENV); - if (!(load_options & ADBC_LOAD_FLAG_SEARCH_ENV)) { - search_paths.emplace_back(SearchPathSource::kDisabledAtRunTime, - "ADBC_DRIVER_PATH (enable ADBC_LOAD_FLAG_SEARCH_ENV)"); - } else if (search_paths.empty()) { - search_paths.emplace_back(SearchPathSource::kUnset, "ADBC_DRIVER_PATH"); - } - for (const auto& path : additional_search_paths) { - search_paths.emplace_back(SearchPathSource::kAdditional, path); - } - -#if ADBC_CONDA_BUILD - // Then, if this is a conda build, search in the conda environment if - // it is activated. - if (load_options & ADBC_LOAD_FLAG_SEARCH_ENV) { -#ifdef _WIN32 - const wchar_t* conda_name = L"CONDA_PREFIX"; -#else - const char* conda_name = "CONDA_PREFIX"; -#endif // _WIN32 - auto venv = GetEnvPaths(conda_name); - if (!venv.empty()) { - for (const auto& [_, venv_path] : venv) { - search_paths.emplace_back(SearchPathSource::kConda, - venv_path / "etc" / "adbc" / "drivers"); - } - } - } else { - search_paths.emplace_back(SearchPathSource::kDisabledAtRunTime, - "Conda prefix (enable ADBC_LOAD_FLAG_SEARCH_ENV)"); - } -#else - if (load_options & ADBC_LOAD_FLAG_SEARCH_ENV) { - search_paths.emplace_back(SearchPathSource::kDisabledAtCompileTime, - "Conda prefix"); - } -#endif // ADBC_CONDA_BUILD - - auto status = SearchPathsForDriver(driver_path, search_paths, info, error); - if (status != ADBC_STATUS_NOT_FOUND) { - // If NOT_FOUND, then keep searching; if OK or INVALID_ARGUMENT, stop - return status; - } - } - - // We searched environment paths and additional search paths (if they - // exist), so now search the rest. -#ifdef _WIN32 - // On Windows, check registry keys, not just search paths. - if (load_options & ADBC_LOAD_FLAG_SEARCH_USER) { - // Check the user registry for the driver. - auto status = - LoadDriverFromRegistry(HKEY_CURRENT_USER, driver_path.native(), info, error); - if (status == ADBC_STATUS_OK) { - return Load(info.lib_path.c_str(), {}, error); - } - if (error && error->message) { - std::string message = "HKEY_CURRENT_USER\\"s; - message += error->message; - search_paths.emplace_back(SearchPathSource::kRegistry, std::move(message)); - } else { - search_paths.emplace_back(SearchPathSource::kRegistry, - "not found in HKEY_CURRENT_USER"); - } - - auto user_paths = GetSearchPaths(ADBC_LOAD_FLAG_SEARCH_USER); - status = SearchPathsForDriver(driver_path, user_paths, info, error); - if (status != ADBC_STATUS_NOT_FOUND) { - return status; - } - search_paths.insert(search_paths.end(), user_paths.begin(), user_paths.end()); - } else { - search_paths.emplace_back(SearchPathSource::kDisabledAtRunTime, - "HKEY_CURRENT_USER (enable ADBC_LOAD_FLAG_SEARCH_USER)"); - } - - if (load_options & ADBC_LOAD_FLAG_SEARCH_SYSTEM) { - // Check the system registry for the driver. - auto status = - LoadDriverFromRegistry(HKEY_LOCAL_MACHINE, driver_path.native(), info, error); - if (status == ADBC_STATUS_OK) { - return Load(info.lib_path.c_str(), {}, error); - } - if (error && error->message) { - std::string message = "HKEY_LOCAL_MACHINE\\"s; - message += error->message; - search_paths.emplace_back(SearchPathSource::kRegistry, std::move(message)); - } else { - search_paths.emplace_back(SearchPathSource::kRegistry, - "not found in HKEY_LOCAL_MACHINE"); - } - - auto system_paths = GetSearchPaths(ADBC_LOAD_FLAG_SEARCH_SYSTEM); - status = SearchPathsForDriver(driver_path, system_paths, info, error); - if (status != ADBC_STATUS_NOT_FOUND) { - return status; - } - search_paths.insert(search_paths.end(), system_paths.begin(), system_paths.end()); - } else { - search_paths.emplace_back( - SearchPathSource::kDisabledAtRunTime, - "HKEY_LOCAL_MACHINE (enable ADBC_LOAD_FLAG_SEARCH_SYSTEM)"); - } - - info.lib_path = driver_path; - return Load(driver_path.c_str(), search_paths, error); -#else - // Otherwise, search the configured paths. - SearchPaths more_search_paths = - GetSearchPaths(load_options & ~ADBC_LOAD_FLAG_SEARCH_ENV); - auto status = SearchPathsForDriver(driver_path, more_search_paths, info, error); - if (status == ADBC_STATUS_NOT_FOUND) { - if (!(load_options & ADBC_LOAD_FLAG_SEARCH_USER)) { - std::filesystem::path user_config_dir = InternalAdbcUserConfigDir(); - std::string message = "user config dir "; - message += user_config_dir.string(); - message += " (enable ADBC_LOAD_FLAG_SEARCH_USER)"; - more_search_paths.emplace_back(SearchPathSource::kDisabledAtRunTime, - std::move(message)); - } - // Windows searches registry keys, so this only applies to other OSes -#if !defined(_WIN32) - if (!(load_options & ADBC_LOAD_FLAG_SEARCH_SYSTEM)) { - std::filesystem::path system_config_dir = InternalAdbcSystemConfigDir(); - std::string message = "system config dir "; - message += system_config_dir.string(); - message += " (enable ADBC_LOAD_FLAG_SEARCH_SYSTEM)"; - more_search_paths.emplace_back(SearchPathSource::kDisabledAtRunTime, - std::move(message)); - } -#endif // !defined(_WIN32) - - // If we reach here, we didn't find the driver in any of the paths - // so let's just attempt to load it as default behavior. - search_paths.insert(search_paths.end(), more_search_paths.begin(), - more_search_paths.end()); - info.lib_path = driver_path; - return Load(driver_path.c_str(), search_paths, error); - } - return status; -#endif // _WIN32 - } - - /// \return ADBC_STATUS_NOT_FOUND if the driver shared library could not be - /// found, ADBC_STATUS_OK otherwise - AdbcStatusCode Load(const char_type* library, const SearchPaths& attempted_paths, - struct AdbcError* error) { - std::string error_message; -#if defined(_WIN32) - HMODULE handle = LoadLibraryExW(library, NULL, 0); - if (!handle) { - error_message += Utf8Encode(library); - error_message += ": LoadLibraryExW() failed: "; - GetWinError(&error_message); - - std::wstring full_driver_name = library; - full_driver_name += L".dll"; - handle = LoadLibraryExW(full_driver_name.c_str(), NULL, 0); - if (!handle) { - error_message += '\n'; - error_message += Utf8Encode(full_driver_name); - error_message += ": LoadLibraryExW() failed: "; - GetWinError(&error_message); - } - } - if (!handle) { - AddSearchPathsToError(attempted_paths, error_message); - SetError(error, error_message); - return ADBC_STATUS_NOT_FOUND; - } else { - this->handle = handle; - } -#else - static const std::string kPlatformLibraryPrefix = "lib"; -#if defined(__APPLE__) - static const std::string kPlatformLibrarySuffix = ".dylib"; -#else - static const std::string kPlatformLibrarySuffix = ".so"; -#endif // defined(__APPLE__) - - void* handle = dlopen(library, 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 = library; - - 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 += library; - 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) { - this->handle = handle; - } else { - AddSearchPathsToError(attempted_paths, error_message); - SetError(error, error_message); - return ADBC_STATUS_NOT_FOUND; - } -#endif // defined(_WIN32) - return ADBC_STATUS_OK; - } - - AdbcStatusCode Lookup(const char* name, void** func, struct AdbcError* error) { -#if defined(_WIN32) - void* load_handle = reinterpret_cast(GetProcAddress(handle, name)); - if (!load_handle) { - std::string message = "GetProcAddress("; - message += name; - message += ") failed: "; - GetWinError(&message); - AppendError(error, message); - return ADBC_STATUS_INTERNAL; - } -#else - void* load_handle = dlsym(handle, name); - if (!load_handle) { - std::string message = "dlsym("; - message += name; - message += ") failed: "; - message += dlerror(); - AppendError(error, message); - return ADBC_STATUS_INTERNAL; - } -#endif // defined(_WIN32) - *func = load_handle; - return ADBC_STATUS_OK; - } - -#if defined(_WIN32) - // The loaded DLL - HMODULE handle; -#else - void* handle; -#endif // defined(_WIN32) -}; - -/// Hold the driver DLL and the driver release callback in the driver struct. -struct ManagerDriverState { - // The original release callback - AdbcStatusCode (*driver_release)(struct AdbcDriver* driver, struct AdbcError* error); - - ManagedLibrary handle; -}; - -/// 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(driver->private_manager); - - if (state->driver_release) { - status = state->driver_release(driver, error); - } - state->handle.Release(); - - driver->private_manager = nullptr; - delete state; - return status; -} - -// ArrowArrayStream wrapper to support AdbcErrorFromArrayStream - -struct ErrorArrayStream { - struct ArrowArrayStream stream; - struct AdbcDriver* private_driver; -}; - -void ErrorArrayStreamRelease(struct ArrowArrayStream* stream) { - if (stream->release != ErrorArrayStreamRelease || !stream->private_data) return; - - auto* private_data = reinterpret_cast(stream->private_data); - private_data->stream.release(&private_data->stream); - delete private_data; - std::memset(stream, 0, sizeof(*stream)); -} - -const char* ErrorArrayStreamGetLastError(struct ArrowArrayStream* stream) { - if (stream->release != ErrorArrayStreamRelease || !stream->private_data) return nullptr; - auto* private_data = reinterpret_cast(stream->private_data); - return private_data->stream.get_last_error(&private_data->stream); -} - -int ErrorArrayStreamGetNext(struct ArrowArrayStream* stream, struct ArrowArray* array) { - if (stream->release != ErrorArrayStreamRelease || !stream->private_data) return EINVAL; - auto* private_data = reinterpret_cast(stream->private_data); - return private_data->stream.get_next(&private_data->stream, array); -} - -int ErrorArrayStreamGetSchema(struct ArrowArrayStream* stream, - struct ArrowSchema* schema) { - if (stream->release != ErrorArrayStreamRelease || !stream->private_data) return EINVAL; - auto* private_data = reinterpret_cast(stream->private_data); - return private_data->stream.get_schema(&private_data->stream, schema); -} - -// Default stubs - -int ErrorGetDetailCount(const struct AdbcError* error) { return 0; } - -struct AdbcErrorDetail ErrorGetDetail(const struct AdbcError* error, int index) { - return {nullptr, nullptr, 0}; -} - -const struct AdbcError* ErrorFromArrayStream(struct ArrowArrayStream* stream, - AdbcStatusCode* status) { - return nullptr; -} - -void ErrorArrayStreamInit(struct ArrowArrayStream* out, - struct AdbcDriver* private_driver) { - if (!out || !out->release || - // Don't bother wrapping if driver didn't claim support - private_driver->ErrorFromArrayStream == ErrorFromArrayStream) { - return; - } - struct ErrorArrayStream* private_data = new ErrorArrayStream; - private_data->stream = *out; - private_data->private_driver = private_driver; - out->get_last_error = ErrorArrayStreamGetLastError; - out->get_next = ErrorArrayStreamGetNext; - out->get_schema = ErrorArrayStreamGetSchema; - out->release = ErrorArrayStreamRelease; - out->private_data = private_data; -} - -AdbcStatusCode DatabaseGetOption(struct AdbcDatabase* database, const char* key, - char* value, size_t* length, struct AdbcError* error) { - SetError(error, "AdbcDatabaseGetOption not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode DatabaseGetOptionBytes(struct AdbcDatabase* database, const char* key, - uint8_t* value, size_t* length, - struct AdbcError* error) { - SetError(error, "AdbcDatabaseGetOptionBytes not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode DatabaseGetOptionInt(struct AdbcDatabase* database, const char* key, - int64_t* value, struct AdbcError* error) { - SetError(error, "AdbcDatabaseGetOptionInt not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode DatabaseGetOptionDouble(struct AdbcDatabase* database, const char* key, - double* value, struct AdbcError* error) { - SetError(error, "AdbcDatabaseGetOptionDouble not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode DatabaseSetOption(struct AdbcDatabase* database, const char* key, - const char* value, struct AdbcError* error) { - SetError(error, "AdbcDatabaseSetOption not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode DatabaseSetOptionBytes(struct AdbcDatabase* database, const char* key, - const uint8_t* value, size_t length, - struct AdbcError* error) { - SetError(error, "AdbcDatabaseSetOptionBytes not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode DatabaseSetOptionInt(struct AdbcDatabase* database, const char* key, - int64_t value, struct AdbcError* error) { - SetError(error, "AdbcDatabaseSetOptionInt not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode DatabaseSetOptionDouble(struct AdbcDatabase* database, const char* key, - double value, struct AdbcError* error) { - SetError(error, "AdbcDatabaseSetOptionDouble not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionCancel(struct AdbcConnection* connection, - struct AdbcError* error) { - SetError(error, "AdbcConnectionCancel not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionCommit(struct AdbcConnection*, struct AdbcError* error) { - SetError(error, "AdbcConnectionCommit not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionGetInfo(struct AdbcConnection* connection, - const uint32_t* info_codes, size_t info_codes_length, - struct ArrowArrayStream* out, struct AdbcError* error) { - SetError(error, "AdbcConnectionGetInfo not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionGetObjects(struct AdbcConnection*, int, const char*, const char*, - const char*, const char**, const char*, - struct ArrowArrayStream*, struct AdbcError* error) { - SetError(error, "AdbcConnectionGetObjects not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionGetOption(struct AdbcConnection* connection, const char* key, - char* value, size_t* length, struct AdbcError* error) { - SetError(error, "AdbcConnectionGetOption not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode ConnectionGetOptionBytes(struct AdbcConnection* connection, - const char* key, uint8_t* value, size_t* length, - struct AdbcError* error) { - SetError(error, "AdbcConnectionGetOptionBytes not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode ConnectionGetOptionInt(struct AdbcConnection* connection, const char* key, - int64_t* value, struct AdbcError* error) { - SetError(error, "AdbcConnectionGetOptionInt not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode ConnectionGetOptionDouble(struct AdbcConnection* connection, - const char* key, double* value, - struct AdbcError* error) { - SetError(error, "AdbcConnectionGetOptionDouble not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode ConnectionGetStatistics(struct AdbcConnection*, const char*, const char*, - const char*, char, struct ArrowArrayStream*, - struct AdbcError* error) { - SetError(error, "AdbcConnectionGetStatistics not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionGetStatisticNames(struct AdbcConnection*, - struct ArrowArrayStream*, - struct AdbcError* error) { - SetError(error, "AdbcConnectionGetStatisticNames not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionGetTableSchema(struct AdbcConnection*, const char*, const char*, - const char*, struct ArrowSchema*, - struct AdbcError* error) { - SetError(error, "AdbcConnectionGetTableSchema not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionGetTableTypes(struct AdbcConnection*, struct ArrowArrayStream*, - struct AdbcError* error) { - SetError(error, "AdbcConnectionGetTableTypes not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionReadPartition(struct AdbcConnection* connection, - const uint8_t* serialized_partition, - size_t serialized_length, - struct ArrowArrayStream* out, - struct AdbcError* error) { - SetError(error, "AdbcConnectionReadPartition not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionRollback(struct AdbcConnection*, struct AdbcError* error) { - SetError(error, "AdbcConnectionRollback not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionSetOption(struct AdbcConnection*, const char*, const char*, - struct AdbcError* error) { - SetError(error, "AdbcConnectionSetOption not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionSetOptionBytes(struct AdbcConnection*, const char*, - const uint8_t*, size_t, struct AdbcError* error) { - SetError(error, "AdbcConnectionSetOptionBytes not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionSetOptionInt(struct AdbcConnection* connection, const char* key, - int64_t value, struct AdbcError* error) { - SetError(error, "AdbcConnectionSetOptionInt not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode ConnectionSetOptionDouble(struct AdbcConnection* connection, - const char* key, double value, - struct AdbcError* error) { - SetError(error, "AdbcConnectionSetOptionDouble not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementBind(struct AdbcStatement*, struct ArrowArray*, - struct ArrowSchema*, struct AdbcError* error) { - SetError(error, "AdbcStatementBind not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementBindStream(struct AdbcStatement*, struct ArrowArrayStream*, - struct AdbcError* error) { - SetError(error, "AdbcStatementBindStream not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementCancel(struct AdbcStatement* statement, struct AdbcError* error) { - SetError(error, "AdbcStatementCancel not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementExecutePartitions(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcPartitions* partitions, - int64_t* rows_affected, - struct AdbcError* error) { - SetError(error, "AdbcStatementExecutePartitions not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementExecuteSchema(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcError* error) { - SetError(error, "AdbcStatementExecuteSchema not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementGetOption(struct AdbcStatement* statement, const char* key, - char* value, size_t* length, struct AdbcError* error) { - SetError(error, "AdbcStatementGetOption not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode StatementGetOptionBytes(struct AdbcStatement* statement, const char* key, - uint8_t* value, size_t* length, - struct AdbcError* error) { - SetError(error, "AdbcStatementGetOptionBytes not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode StatementGetOptionInt(struct AdbcStatement* statement, const char* key, - int64_t* value, struct AdbcError* error) { - SetError(error, "AdbcStatementGetOptionInt not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode StatementGetOptionDouble(struct AdbcStatement* statement, const char* key, - double* value, struct AdbcError* error) { - SetError(error, "AdbcStatementGetOptionDouble not implemented"); - return ADBC_STATUS_NOT_FOUND; -} - -AdbcStatusCode StatementGetParameterSchema(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcError* error) { - SetError(error, "AdbcStatementGetParameterSchema not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementPrepare(struct AdbcStatement*, struct AdbcError* error) { - SetError(error, "AdbcStatementPrepare not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementSetOption(struct AdbcStatement*, const char*, const char*, - struct AdbcError* error) { - SetError(error, "AdbcStatementSetOption not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementSetOptionBytes(struct AdbcStatement*, const char*, const uint8_t*, - size_t, struct AdbcError* error) { - SetError(error, "AdbcStatementSetOptionBytes not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementSetOptionInt(struct AdbcStatement* statement, const char* key, - int64_t value, struct AdbcError* error) { - SetError(error, "AdbcStatementSetOptionInt not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementSetOptionDouble(struct AdbcStatement* statement, const char* key, - double value, struct AdbcError* error) { - SetError(error, "AdbcStatementSetOptionDouble not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementSetSqlQuery(struct AdbcStatement*, const char*, - struct AdbcError* error) { - SetError(error, "AdbcStatementSetSqlQuery not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -AdbcStatusCode StatementSetSubstraitPlan(struct AdbcStatement*, const uint8_t*, size_t, - struct AdbcError* error) { - SetError(error, "AdbcStatementSetSubstraitPlan not implemented"); - return ADBC_STATUS_NOT_IMPLEMENTED; -} - -/// Temporary state while the database is being configured. -struct TempDatabase { - std::unordered_map options; - std::unordered_map bytes_options; - std::unordered_map int_options; - std::unordered_map double_options; - std::string driver; - std::string entrypoint; - AdbcDriverInitFunc init_func = nullptr; - AdbcLoadFlags load_flags = ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS; - std::string additional_search_path_list; -}; - -/// Temporary state while the database is being configured. -struct TempConnection { - std::unordered_map options; - std::unordered_map bytes_options; - std::unordered_map int_options; - std::unordered_map double_options; -}; - -static const char kDefaultEntrypoint[] = "AdbcDriverInit"; -} // namespace - -// Other helpers (intentionally not in an anonymous namespace so they can be tested) -ADBC_EXPORT -std::filesystem::path InternalAdbcUserConfigDir() { - std::filesystem::path config_dir; -#if defined(_WIN32) - // SHGetFolderPath is just an alias to SHGetKnownFolderPath since Vista - // so let's just call the updated function. - PWSTR path = nullptr; - auto hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path); - if (!SUCCEEDED(hres)) { - return config_dir; - } - - std::wstring wpath(path); - std::filesystem::path dir(std::move(wpath)); - if (!dir.empty()) { - config_dir = std::filesystem::path(dir); - config_dir /= "ADBC/Drivers"; - } -#elif defined(__APPLE__) - auto dir = std::getenv("HOME"); - if (dir) { - config_dir = std::filesystem::path(dir); - config_dir /= "Library/Application Support/ADBC/Drivers"; - } -#elif defined(__linux__) - auto dir = std::getenv("XDG_CONFIG_HOME"); - if (!dir) { - dir = std::getenv("HOME"); - if (dir) { - config_dir = std::filesystem::path(dir) /= ".config"; - } - } else { - config_dir = std::filesystem::path(dir); - } - - if (!config_dir.empty()) { - config_dir = config_dir / "adbc" / "drivers"; - } -#endif // defined(_WIN32) - - return config_dir; -} - -#if !defined(_WIN32) -std::filesystem::path InternalAdbcSystemConfigDir() { -#if defined(__APPLE__) - return std::filesystem::path("/Library/Application Support/ADBC/Drivers"); -#else - return std::filesystem::path("/etc/adbc/drivers"); -#endif // defined(__APPLE__) -} -#endif // !defined(_WIN32) - -std::vector InternalAdbcParsePath(const std::string_view path) { - std::vector result; - if (path.empty()) { - return result; - } - -#ifdef _WIN32 - constexpr char delimiter = ';'; - - // pulling the logic from Go's filepath.SplitList function - // where windows checks for quoted/escaped sections while splitting - // but unix doesn't. - // see - // https://cs.opensource.google/go/go/+/refs/tags/go1.24.3:src/path/filepath/path_windows.go - bool in_quotes = false; - size_t start = 0; - for (size_t i = 0; i < path.size(); ++i) { - if (path[i] == '"') { - in_quotes = !in_quotes; - } else if (path[i] == delimiter && !in_quotes) { - result.emplace_back(path.substr(start, i - start)); - start = i + 1; - } - } - result.emplace_back(path.substr(start)); -#else - constexpr char delimiter = ':'; - - size_t start = 0; - size_t end = 0; - while ((end = path.find(delimiter, start)) != std::string::npos) { - result.emplace_back(path.substr(start, end - start)); - start = end + 1; - } - result.emplace_back(path.substr(start)); -#endif // _WIN32 - - // remove empty paths - result.erase(std::remove_if(result.begin(), result.end(), - [](const auto& p) { return p.empty(); }), - result.end()); - return result; -} - -ADBC_EXPORT -std::string InternalAdbcDriverManagerDefaultEntrypoint(const std::string& driver) { - /// - libadbc_driver_sqlite.so.2.0.0 -> AdbcDriverSqliteInit - /// - adbc_driver_sqlite.dll -> AdbcDriverSqliteInit - /// - proprietary_driver.dll -> AdbcProprietaryDriverInit - - // N.B.(https://github.com/apache/arrow-adbc/issues/3680): sanity checks - assert(!driver.empty()); - - // Potential path -> filename - // Treat both \ and / as directory separators on all platforms for simplicity - std::string filename; - { - size_t pos = driver.find_last_of("/\\"); - if (pos != std::string::npos) { - filename = driver.substr(pos + 1); - } else { - filename = driver; - } - } - - // Remove all extensions - { - size_t pos = filename.find('.'); - if (pos != std::string::npos) { - filename = filename.substr(0, pos); - } - } - - // Remove lib prefix - // https://stackoverflow.com/q/1878001/262727 - if (filename.rfind("lib", 0) == 0) { - filename = filename.substr(3); - } - - // Split on underscores, hyphens - // Capitalize and join - std::string entrypoint; - entrypoint.reserve(filename.size()); - size_t pos = 0; - while (pos < filename.size()) { - size_t prev = pos; - pos = filename.find_first_of("-_", pos); - // if pos == npos this is the entire filename - std::string token = filename.substr(prev, pos - prev); - // capitalize first letter - token[0] = static_cast(std::toupper(static_cast(token[0]))); - - entrypoint += token; - - if (pos != std::string::npos) { - pos++; - } - } - - if (entrypoint.rfind("Adbc", 0) != 0) { - entrypoint = "Adbc" + entrypoint; - } - entrypoint += "Init"; - - return entrypoint; -} - -ADBC_EXPORT -std::optional InternalAdbcParseDriverUri(std::string_view str) { - std::string::size_type pos = str.find(":"); - if (pos == std::string::npos) { - return std::nullopt; - } - - std::string_view d = str.substr(0, pos); - if (str.size() <= pos + 1) { - return ParseDriverUriResult{d, std::nullopt}; - } - -#ifdef _WIN32 - if (std::filesystem::exists(std::filesystem::path(str))) { - // No scheme, just a path - return ParseDriverUriResult{str, std::nullopt}; - } -#endif - - if (str[pos + 1] == '/') { // scheme is also driver - return ParseDriverUriResult{d, str}; - } - - // driver:scheme:..... - return ParseDriverUriResult{d, str.substr(pos + 1)}; -} - -// Direct implementations of API methods - -int AdbcErrorGetDetailCount(const struct AdbcError* error) { - if (error->vendor_code == ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA && error->private_data && - error->private_driver && error->private_driver->ErrorGetDetailCount) { - return error->private_driver->ErrorGetDetailCount(error); - } - return 0; -} - -struct AdbcErrorDetail AdbcErrorGetDetail(const struct AdbcError* error, int index) { - if (error->vendor_code == ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA && error->private_data && - error->private_driver && error->private_driver->ErrorGetDetail) { - return error->private_driver->ErrorGetDetail(error, index); - } - return {nullptr, nullptr, 0}; -} - -const struct AdbcError* AdbcErrorFromArrayStream(struct ArrowArrayStream* stream, - AdbcStatusCode* status) { - if (!stream->private_data || stream->release != ErrorArrayStreamRelease) { - return nullptr; - } - auto* private_data = reinterpret_cast(stream->private_data); - auto* error = - private_data->private_driver->ErrorFromArrayStream(&private_data->stream, status); - if (error) { - const_cast(error)->private_driver = private_data->private_driver; - } - return error; -} - -#define INIT_ERROR(ERROR, SOURCE) \ - if ((ERROR) != nullptr && \ - (ERROR)->vendor_code == ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA) { \ - (ERROR)->private_driver = (SOURCE)->private_driver; \ - } - -#define WRAP_STREAM(EXPR, OUT, SOURCE) \ - if (!(OUT)) { \ - /* Happens for ExecuteQuery where out is optional */ \ - return EXPR; \ - } \ - AdbcStatusCode status_code = EXPR; \ - ErrorArrayStreamInit(OUT, (SOURCE)->private_driver); \ - return status_code; - -AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct AdbcError* error) { - // Allocate a temporary structure to store options pre-Init - database->private_data = new TempDatabase(); - database->private_driver = nullptr; - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDatabaseGetOption(struct AdbcDatabase* database, const char* key, - char* value, size_t* length, - struct AdbcError* error) { - if (database->private_driver) { - INIT_ERROR(error, database); - return database->private_driver->DatabaseGetOption(database, key, value, length, - error); - } - const auto* args = reinterpret_cast(database->private_data); - const std::string* result = nullptr; - if (std::strcmp(key, "driver") == 0) { - result = &args->driver; - } else if (std::strcmp(key, "entrypoint") == 0) { - result = &args->entrypoint; - } else { - const auto it = args->options.find(key); - if (it == args->options.end()) { - SetError(error, std::string("Option not found: ") + key); - return ADBC_STATUS_NOT_FOUND; - } - result = &it->second; - } - - if (*length >= result->size() + 1) { - // Enough space - std::memcpy(value, result->c_str(), result->size() + 1); - } - *length = result->size() + 1; - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDatabaseGetOptionBytes(struct AdbcDatabase* database, const char* key, - uint8_t* value, size_t* length, - struct AdbcError* error) { - if (database->private_driver) { - INIT_ERROR(error, database); - return database->private_driver->DatabaseGetOptionBytes(database, key, value, length, - error); - } - const auto* args = reinterpret_cast(database->private_data); - const auto it = args->bytes_options.find(key); - if (it == args->options.end()) { - SetError(error, std::string("Option not found: ") + key); - return ADBC_STATUS_NOT_FOUND; - } - const std::string& result = it->second; - - if (*length >= result.size()) { - // Enough space - std::memcpy(value, result.c_str(), result.size()); - } - *length = result.size(); - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDatabaseGetOptionInt(struct AdbcDatabase* database, const char* key, - int64_t* value, struct AdbcError* error) { - if (database->private_driver) { - INIT_ERROR(error, database); - 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()) { - SetError(error, std::string("Option not found: ") + key); - 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) { - INIT_ERROR(error, database); - 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()) { - SetError(error, std::string("Option not found: ") + key); - 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) { - INIT_ERROR(error, database); - return database->private_driver->DatabaseSetOption(database, key, value, error); - } - - TempDatabase* args = reinterpret_cast(database->private_data); - if (std::strcmp(key, "driver") == 0) { - args->driver = value; - } else if (std::strcmp(key, "entrypoint") == 0) { - args->entrypoint = value; - } else { - args->options[key] = value; - } - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDatabaseSetOptionBytes(struct AdbcDatabase* database, const char* key, - const uint8_t* value, size_t length, - struct AdbcError* error) { - if (database->private_driver) { - INIT_ERROR(error, database); - return database->private_driver->DatabaseSetOptionBytes(database, key, value, length, - error); - } - - TempDatabase* args = reinterpret_cast(database->private_data); - args->bytes_options[key] = std::string(reinterpret_cast(value), length); - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDatabaseSetOptionInt(struct AdbcDatabase* database, const char* key, - int64_t value, struct AdbcError* error) { - if (database->private_driver) { - INIT_ERROR(error, database); - 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) { - INIT_ERROR(error, database); - 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 AdbcDriverManagerDatabaseSetLoadFlags(struct AdbcDatabase* database, - AdbcLoadFlags flags, - struct AdbcError* error) { - if (database->private_driver) { - SetError(error, "Cannot SetLoadFlags after AdbcDatabaseInit"); - return ADBC_STATUS_INVALID_STATE; - } - - TempDatabase* args = reinterpret_cast(database->private_data); - args->load_flags = flags; - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDriverManagerDatabaseSetAdditionalSearchPathList( - struct AdbcDatabase* database, const char* path_list, struct AdbcError* error) { - if (database->private_driver) { - SetError(error, "Cannot SetAdditionalSearchPathList after AdbcDatabaseInit"); - return ADBC_STATUS_INVALID_STATE; - } - - TempDatabase* args = reinterpret_cast(database->private_data); - if (path_list) { - args->additional_search_path_list.assign(path_list); - } else { - args->additional_search_path_list.clear(); - } - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDriverManagerDatabaseSetInitFunc(struct AdbcDatabase* database, - AdbcDriverInitFunc init_func, - struct AdbcError* error) { - if (database->private_driver) { - SetError(error, "Cannot SetInitFunc after AdbcDatabaseInit"); - return ADBC_STATUS_INVALID_STATE; - } - - TempDatabase* args = reinterpret_cast(database->private_data); - args->init_func = init_func; - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcDatabaseInit(struct AdbcDatabase* database, struct AdbcError* error) { - if (!database->private_data) { - SetError(error, "Must call AdbcDatabaseNew before AdbcDatabaseInit"); - return ADBC_STATUS_INVALID_STATE; - } - TempDatabase* args = reinterpret_cast(database->private_data); - if (!args->init_func) { - const auto uri = args->options.find("uri"); - if (args->driver.empty() && uri != args->options.end()) { - std::string owned_uri = uri->second; - auto result = InternalAdbcParseDriverUri(owned_uri); - if (result && result->uri) { - args->driver = std::string{result->driver}; - args->options["uri"] = std::string{*result->uri}; - } - } else if (!args->driver.empty() && uri == args->options.end()) { - std::string owned_driver = args->driver; - auto result = InternalAdbcParseDriverUri(owned_driver); - if (result) { - args->driver = std::string{result->driver}; - if (result->uri) { - args->options["uri"] = std::string{*result->uri}; - } - } - } - - if (args->driver.empty()) { - SetError(error, - "Must provide 'driver' parameter (or encode driver in 'uri' parameter)"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - } - - database->private_driver = new AdbcDriver; - std::memset(database->private_driver, 0, sizeof(AdbcDriver)); - AdbcStatusCode status; - // So we don't confuse a driver into thinking it's initialized already - database->private_data = nullptr; - if (args->init_func) { - status = AdbcLoadDriverFromInitFunc(args->init_func, ADBC_VERSION_1_1_0, - database->private_driver, error); - } else if (!args->entrypoint.empty()) { - status = AdbcFindLoadDriver(args->driver.c_str(), args->entrypoint.c_str(), - ADBC_VERSION_1_1_0, args->load_flags, - args->additional_search_path_list.data(), - database->private_driver, error); - } else { - status = AdbcFindLoadDriver( - args->driver.c_str(), nullptr, ADBC_VERSION_1_1_0, args->load_flags, - args->additional_search_path_list.data(), database->private_driver, error); - } - - if (status != ADBC_STATUS_OK) { - // Restore private_data so it will be released by AdbcDatabaseRelease - database->private_data = args; - if (database->private_driver->release) { - database->private_driver->release(database->private_driver, error); - } - delete database->private_driver; - database->private_driver = nullptr; - return status; - } - - // Errors that occur during AdbcDatabaseXXX() refer to the driver via - // the private_driver member; however, after we return we have released - // the driver and inspecting the error might segfault. Here, we scope - // the driver-produced error to this function and make a copy if necessary. - OwnedError driver_error; - - status = database->private_driver->DatabaseNew(database, &driver_error.error); - if (status != ADBC_STATUS_OK) { - if (database->private_driver->release) { - SetError(error, &driver_error.error); - database->private_driver->release(database->private_driver, nullptr); - } - delete database->private_driver; - database->private_driver = nullptr; - return status; - } - auto options = std::move(args->options); - auto bytes_options = std::move(args->bytes_options); - auto int_options = std::move(args->int_options); - auto double_options = std::move(args->double_options); - delete args; - - INIT_ERROR(error, database); - for (const auto& option : options) { - status = database->private_driver->DatabaseSetOption( - database, option.first.c_str(), option.second.c_str(), &driver_error.error); - if (status != ADBC_STATUS_OK) break; - } - for (const auto& option : bytes_options) { - status = database->private_driver->DatabaseSetOptionBytes( - database, option.first.c_str(), - reinterpret_cast(option.second.data()), option.second.size(), - &driver_error.error); - if (status != ADBC_STATUS_OK) break; - } - for (const auto& option : int_options) { - status = database->private_driver->DatabaseSetOptionInt( - database, option.first.c_str(), option.second, &driver_error.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, &driver_error.error); - if (status != ADBC_STATUS_OK) break; - } - - if (status != ADBC_STATUS_OK) { - // Release the database - std::ignore = database->private_driver->DatabaseRelease(database, nullptr); - if (database->private_driver->release) { - SetError(error, &driver_error.error); - database->private_driver->release(database->private_driver, nullptr); - } - 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; - } - - return database->private_driver->DatabaseInit(database, error); -} - -AdbcStatusCode AdbcDatabaseRelease(struct AdbcDatabase* database, - struct AdbcError* error) { - if (!database->private_driver) { - if (database->private_data) { - TempDatabase* args = reinterpret_cast(database->private_data); - delete args; - database->private_data = nullptr; - return ADBC_STATUS_OK; - } - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, database); - 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; - database->private_data = nullptr; - database->private_driver = nullptr; - return status; -} - -AdbcStatusCode AdbcConnectionCancel(struct AdbcConnection* connection, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionCancel: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionCancel(connection, error); -} - -AdbcStatusCode AdbcConnectionCommit(struct AdbcConnection* connection, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionCommit: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionCommit(connection, error); -} - -AdbcStatusCode AdbcConnectionGetInfo(struct AdbcConnection* connection, - const uint32_t* info_codes, size_t info_codes_length, - struct ArrowArrayStream* out, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionGetInfo: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - WRAP_STREAM(connection->private_driver->ConnectionGetInfo( - connection, info_codes, info_codes_length, out, error), - out, connection); -} - -AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection* connection, int depth, - const char* catalog, const char* db_schema, - const char* table_name, const char** table_types, - const char* column_name, - struct ArrowArrayStream* stream, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionGetObjects: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - WRAP_STREAM(connection->private_driver->ConnectionGetObjects( - connection, depth, catalog, db_schema, table_name, table_types, - column_name, stream, error), - stream, connection); -} - -AdbcStatusCode AdbcConnectionGetOption(struct AdbcConnection* connection, const char* key, - char* value, size_t* length, - struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "AdbcConnectionGetOption: must call 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; - } - if (*length >= it->second.size() + 1) { - std::memcpy(value, it->second.c_str(), it->second.size() + 1); - } - *length = it->second.size() + 1; - return ADBC_STATUS_OK; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionGetOption(connection, key, value, length, - error); -} - -AdbcStatusCode AdbcConnectionGetOptionBytes(struct AdbcConnection* connection, - const char* key, uint8_t* value, - size_t* length, struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "AdbcConnectionGetOption: must call 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->bytes_options.find(key); - if (it == args->options.end()) { - return ADBC_STATUS_NOT_FOUND; - } - if (*length >= it->second.size() + 1) { - std::memcpy(value, it->second.data(), it->second.size() + 1); - } - *length = it->second.size() + 1; - return ADBC_STATUS_OK; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionGetOptionBytes(connection, key, value, - length, error); -} - -AdbcStatusCode AdbcConnectionGetOptionInt(struct AdbcConnection* connection, - const char* key, int64_t* value, - struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "AdbcConnectionGetOption: must call 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; - } - INIT_ERROR(error, connection); - 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 call 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; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionGetOptionDouble(connection, key, value, - error); -} - -AdbcStatusCode AdbcConnectionGetStatistics(struct AdbcConnection* connection, - const char* catalog, const char* db_schema, - const char* table_name, char approximate, - struct ArrowArrayStream* out, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionGetStatistics: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - WRAP_STREAM( - connection->private_driver->ConnectionGetStatistics( - connection, catalog, db_schema, table_name, approximate == 1, out, error), - out, connection); -} - -AdbcStatusCode AdbcConnectionGetStatisticNames(struct AdbcConnection* connection, - struct ArrowArrayStream* out, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionGetStatisticNames: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - WRAP_STREAM( - connection->private_driver->ConnectionGetStatisticNames(connection, out, error), - out, connection); -} - -AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection* connection, - const char* catalog, const char* db_schema, - const char* table_name, - struct ArrowSchema* schema, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionGetTableSchema: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionGetTableSchema( - connection, catalog, db_schema, table_name, schema, error); -} - -AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection* connection, - struct ArrowArrayStream* stream, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionGetTableTypes: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - WRAP_STREAM( - connection->private_driver->ConnectionGetTableTypes(connection, stream, error), - stream, connection); -} - -AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection, - struct AdbcDatabase* database, - struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "Must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } else if (!database->private_driver) { - SetError(error, "Database is not initialized"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - TempConnection* args = reinterpret_cast(connection->private_data); - connection->private_data = nullptr; - std::unordered_map options = std::move(args->options); - std::unordered_map bytes_options = - std::move(args->bytes_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); - if (status != ADBC_STATUS_OK) return status; - connection->private_driver = database->private_driver; - - for (const auto& option : options) { - status = database->private_driver->ConnectionSetOption( - connection, option.first.c_str(), option.second.c_str(), error); - if (status != ADBC_STATUS_OK) return status; - } - for (const auto& option : bytes_options) { - status = database->private_driver->ConnectionSetOptionBytes( - connection, option.first.c_str(), - reinterpret_cast(option.second.data()), option.second.size(), - 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; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionInit(connection, database, error); -} - -AdbcStatusCode AdbcConnectionNew(struct AdbcConnection* connection, - struct AdbcError* error) { - // Allocate a temporary structure to store options pre-Init, because - // we don't get access to the database (and hence the driver - // function table) until then - connection->private_data = new TempConnection; - connection->private_driver = nullptr; - return ADBC_STATUS_OK; -} - -AdbcStatusCode AdbcConnectionReadPartition(struct AdbcConnection* connection, - const uint8_t* serialized_partition, - size_t serialized_length, - struct ArrowArrayStream* out, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionReadPartition: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - WRAP_STREAM(connection->private_driver->ConnectionReadPartition( - connection, serialized_partition, serialized_length, out, error), - out, connection); -} - -AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection, - struct AdbcError* error) { - if (!connection->private_driver) { - if (connection->private_data) { - TempConnection* args = reinterpret_cast(connection->private_data); - delete args; - connection->private_data = nullptr; - return ADBC_STATUS_OK; - } - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - auto status = connection->private_driver->ConnectionRelease(connection, error); - connection->private_driver = nullptr; - return status; -} - -AdbcStatusCode AdbcConnectionRollback(struct AdbcConnection* connection, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcConnectionRollback: must call AdbcConnectionNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionRollback(connection, error); -} - -AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection, const char* key, - const char* value, struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "AdbcConnectionSetOption: must call 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->options[key] = value; - return ADBC_STATUS_OK; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionSetOption(connection, key, value, error); -} - -AdbcStatusCode AdbcConnectionSetOptionBytes(struct AdbcConnection* connection, - const char* key, const uint8_t* value, - size_t length, struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "AdbcConnectionSetOptionInt: must call 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->bytes_options[key] = std::string(reinterpret_cast(value), length); - return ADBC_STATUS_OK; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionSetOptionBytes(connection, key, value, - length, error); -} - -AdbcStatusCode AdbcConnectionSetOptionInt(struct AdbcConnection* connection, - const char* key, int64_t value, - struct AdbcError* error) { - if (!connection->private_data) { - SetError(error, "AdbcConnectionSetOptionInt: must call 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; - } - INIT_ERROR(error, connection); - 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 call 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; - } - INIT_ERROR(error, connection); - return connection->private_driver->ConnectionSetOptionDouble(connection, key, value, - error); -} - -AdbcStatusCode AdbcStatementBind(struct AdbcStatement* statement, - struct ArrowArray* values, struct ArrowSchema* schema, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementBind: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementBind(statement, values, schema, error); -} - -AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement* statement, - struct ArrowArrayStream* stream, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementBindStream: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementBindStream(statement, stream, error); -} - -AdbcStatusCode AdbcStatementCancel(struct AdbcStatement* statement, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementCancel: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementCancel(statement, error); -} - -// XXX: cpplint gets confused here if declared as 'struct ArrowSchema* schema' -AdbcStatusCode AdbcStatementExecutePartitions(struct AdbcStatement* statement, - ArrowSchema* schema, - struct AdbcPartitions* partitions, - int64_t* rows_affected, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementExecutePartitions: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementExecutePartitions( - statement, schema, partitions, rows_affected, error); -} - -AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, - struct ArrowArrayStream* out, - int64_t* rows_affected, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementExecuteQuery: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - WRAP_STREAM(statement->private_driver->StatementExecuteQuery(statement, out, - rows_affected, error), - out, statement); -} - -AdbcStatusCode AdbcStatementExecuteSchema(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementExecuteSchema: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementExecuteSchema(statement, schema, error); -} - -AdbcStatusCode AdbcStatementGetOption(struct AdbcStatement* statement, const char* key, - char* value, size_t* length, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementGetOption: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementGetOption(statement, key, value, length, - error); -} - -AdbcStatusCode AdbcStatementGetOptionBytes(struct AdbcStatement* statement, - const char* key, uint8_t* value, - size_t* length, struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementGetOptionBytes: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementGetOptionBytes(statement, key, value, length, - error); -} - -AdbcStatusCode AdbcStatementGetOptionInt(struct AdbcStatement* statement, const char* key, - int64_t* value, struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementGetOptionInt: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - 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) { - SetError(error, "AdbcStatementGetOptionDouble: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementGetOptionDouble(statement, key, value, - error); -} - -AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementGetParameterSchema: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementGetParameterSchema(statement, schema, error); -} - -AdbcStatusCode AdbcStatementNew(struct AdbcConnection* connection, - struct AdbcStatement* statement, - struct AdbcError* error) { - if (!connection->private_driver) { - SetError(error, "AdbcStatementNew: must call AdbcConnectionInit first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, connection); - auto status = connection->private_driver->StatementNew(connection, statement, error); - statement->private_driver = connection->private_driver; - return status; -} - -AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement* statement, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementPrepare: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementPrepare(statement, error); -} - -AdbcStatusCode AdbcStatementRelease(struct AdbcStatement* statement, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementRelease: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - auto status = statement->private_driver->StatementRelease(statement, error); - statement->private_driver = nullptr; - return status; -} - -AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const char* key, - const char* value, struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementSetOption: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementSetOption(statement, key, value, error); -} - -AdbcStatusCode AdbcStatementSetOptionBytes(struct AdbcStatement* statement, - const char* key, const uint8_t* value, - size_t length, struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementSetOptionBytes: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementSetOptionBytes(statement, key, value, length, - error); -} - -AdbcStatusCode AdbcStatementSetOptionInt(struct AdbcStatement* statement, const char* key, - int64_t value, struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementSetOptionInt: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - 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) { - SetError(error, "AdbcStatementSetOptionDouble: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementSetOptionDouble(statement, key, value, - error); -} - -AdbcStatusCode AdbcStatementSetSqlQuery(struct AdbcStatement* statement, - const char* query, struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementSetSqlQuery: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementSetSqlQuery(statement, query, error); -} - -AdbcStatusCode AdbcStatementSetSubstraitPlan(struct AdbcStatement* statement, - const uint8_t* plan, size_t length, - struct AdbcError* error) { - if (!statement->private_driver) { - SetError(error, "AdbcStatementSetSubstraitPlan: must call AdbcStatementNew first"); - return ADBC_STATUS_INVALID_STATE; - } - INIT_ERROR(error, statement); - return statement->private_driver->StatementSetSubstraitPlan(statement, plan, length, - error); -} - -const char* AdbcStatusCodeMessage(AdbcStatusCode code) { -#define CASE(CONSTANT) \ - case ADBC_STATUS_##CONSTANT: \ - return #CONSTANT; - - switch (code) { - CASE(OK); - CASE(UNKNOWN); - CASE(NOT_IMPLEMENTED); - CASE(NOT_FOUND); - CASE(ALREADY_EXISTS); - CASE(INVALID_ARGUMENT); - CASE(INVALID_STATE); - CASE(INVALID_DATA); - CASE(INTEGRITY); - CASE(INTERNAL); - CASE(IO); - CASE(CANCELLED); - CASE(TIMEOUT); - CASE(UNAUTHENTICATED); - CASE(UNAUTHORIZED); - default: - return "(invalid code)"; - } -#undef CASE -} - -AdbcStatusCode AdbcFindLoadDriver(const char* driver_name, const char* entrypoint, - const int version, const AdbcLoadFlags load_options, - const char* additional_search_path_list, - void* raw_driver, struct AdbcError* error) { - AdbcDriverInitFunc init_func = nullptr; - std::string error_message; - - switch (version) { - case ADBC_VERSION_1_0_0: - case ADBC_VERSION_1_1_0: - break; - default: - SetError(error, "Only ADBC 1.0.0 and 1.1.0 are supported"); - return ADBC_STATUS_NOT_IMPLEMENTED; - } - - if (!raw_driver) { - SetError(error, "Driver pointer is null"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - if (!driver_name) { - SetError(error, "Driver name is null"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - ManagedLibrary library; - DriverInfo info; - if (entrypoint) { - info.entrypoint = entrypoint; - } - - std::vector additional_paths; - if (additional_search_path_list) { - additional_paths = InternalAdbcParsePath(additional_search_path_list); - } - - auto* driver = reinterpret_cast(raw_driver); - - AdbcStatusCode status = - library.GetDriverInfo(driver_name, load_options, additional_paths, info, error); - if (status != ADBC_STATUS_OK) { - driver->release = nullptr; - return status; - } - - void* load_handle = nullptr; - if (!info.entrypoint.empty()) { - status = library.Lookup(info.entrypoint.c_str(), &load_handle, error); - } else { - auto name = InternalAdbcDriverManagerDefaultEntrypoint(info.lib_path.string()); - assert(!name.empty()); - status = library.Lookup(name.c_str(), &load_handle, error); - if (status != ADBC_STATUS_OK) { - status = library.Lookup(kDefaultEntrypoint, &load_handle, error); - } - } - - if (status != ADBC_STATUS_OK) { - library.Release(); - return status; - } - init_func = reinterpret_cast(load_handle); - - status = AdbcLoadDriverFromInitFunc(init_func, version, driver, error); - if (status == ADBC_STATUS_OK) { - ManagerDriverState* state = new ManagerDriverState; - state->driver_release = driver->release; - state->handle = std::move(library); - driver->release = &ReleaseDriver; - driver->private_manager = state; - } else { - library.Release(); - } - return status; -} - -AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, - int version, void* raw_driver, struct AdbcError* error) { - // maintain old behavior of allowing relative paths (because dlopen allows it) - // but don't enable searching for manifests by default. It will need to be explicitly - // enabled by calling AdbcFindLoadDriver directly. - return AdbcFindLoadDriver(driver_name, entrypoint, version, - ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS, nullptr, raw_driver, - error); -} - -AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int version, - void* raw_driver, struct AdbcError* error) { - constexpr std::array kSupportedVersions = { - ADBC_VERSION_1_1_0, - ADBC_VERSION_1_0_0, - }; - - if (!raw_driver) { - SetError(error, "Must provide non-NULL raw_driver"); - return ADBC_STATUS_INVALID_ARGUMENT; - } - - switch (version) { - case ADBC_VERSION_1_0_0: - case ADBC_VERSION_1_1_0: - break; - default: - SetError(error, "Only ADBC 1.0.0 and 1.1.0 are supported"); - return ADBC_STATUS_NOT_IMPLEMENTED; - } - -#define FILL_DEFAULT(DRIVER, STUB) \ - if (!DRIVER->STUB) { \ - DRIVER->STUB = &STUB; \ - } -#define CHECK_REQUIRED(DRIVER, STUB) \ - if (!DRIVER->STUB) { \ - SetError(error, "Driver does not implement required function Adbc" #STUB); \ - return ADBC_STATUS_INTERNAL; \ - } - - // Starting from the passed version, try each (older) version in - // succession with the underlying driver until we find one that's - // accepted. - AdbcStatusCode result = ADBC_STATUS_NOT_IMPLEMENTED; - for (const int try_version : kSupportedVersions) { - if (try_version > version) continue; - result = init_func(try_version, raw_driver, error); - if (result != ADBC_STATUS_NOT_IMPLEMENTED) break; - } - if (result != ADBC_STATUS_OK) { - return result; - } - - if (version >= ADBC_VERSION_1_0_0) { - auto* driver = reinterpret_cast(raw_driver); - CHECK_REQUIRED(driver, DatabaseNew); - CHECK_REQUIRED(driver, DatabaseInit); - CHECK_REQUIRED(driver, DatabaseRelease); - FILL_DEFAULT(driver, DatabaseSetOption); - - CHECK_REQUIRED(driver, ConnectionNew); - CHECK_REQUIRED(driver, ConnectionInit); - CHECK_REQUIRED(driver, ConnectionRelease); - FILL_DEFAULT(driver, ConnectionCommit); - FILL_DEFAULT(driver, ConnectionGetInfo); - FILL_DEFAULT(driver, ConnectionGetObjects); - FILL_DEFAULT(driver, ConnectionGetTableSchema); - FILL_DEFAULT(driver, ConnectionGetTableTypes); - FILL_DEFAULT(driver, ConnectionReadPartition); - FILL_DEFAULT(driver, ConnectionRollback); - FILL_DEFAULT(driver, ConnectionSetOption); - - FILL_DEFAULT(driver, StatementExecutePartitions); - CHECK_REQUIRED(driver, StatementExecuteQuery); - CHECK_REQUIRED(driver, StatementNew); - CHECK_REQUIRED(driver, StatementRelease); - FILL_DEFAULT(driver, StatementBind); - FILL_DEFAULT(driver, StatementBindStream); - FILL_DEFAULT(driver, StatementGetParameterSchema); - FILL_DEFAULT(driver, StatementPrepare); - FILL_DEFAULT(driver, StatementSetOption); - FILL_DEFAULT(driver, StatementSetSqlQuery); - FILL_DEFAULT(driver, StatementSetSubstraitPlan); - } - if (version >= ADBC_VERSION_1_1_0) { - auto* driver = reinterpret_cast(raw_driver); - FILL_DEFAULT(driver, ErrorGetDetailCount); - FILL_DEFAULT(driver, ErrorGetDetail); - FILL_DEFAULT(driver, ErrorFromArrayStream); - - FILL_DEFAULT(driver, DatabaseGetOption); - FILL_DEFAULT(driver, DatabaseGetOptionBytes); - FILL_DEFAULT(driver, DatabaseGetOptionDouble); - FILL_DEFAULT(driver, DatabaseGetOptionInt); - FILL_DEFAULT(driver, DatabaseSetOptionBytes); - FILL_DEFAULT(driver, DatabaseSetOptionDouble); - FILL_DEFAULT(driver, DatabaseSetOptionInt); - - FILL_DEFAULT(driver, ConnectionCancel); - FILL_DEFAULT(driver, ConnectionGetOption); - FILL_DEFAULT(driver, ConnectionGetOptionBytes); - FILL_DEFAULT(driver, ConnectionGetOptionDouble); - FILL_DEFAULT(driver, ConnectionGetOptionInt); - FILL_DEFAULT(driver, ConnectionGetStatistics); - FILL_DEFAULT(driver, ConnectionGetStatisticNames); - FILL_DEFAULT(driver, ConnectionSetOptionBytes); - FILL_DEFAULT(driver, ConnectionSetOptionDouble); - FILL_DEFAULT(driver, ConnectionSetOptionInt); - - FILL_DEFAULT(driver, StatementCancel); - FILL_DEFAULT(driver, StatementExecuteSchema); - FILL_DEFAULT(driver, StatementGetOption); - FILL_DEFAULT(driver, StatementGetOptionBytes); - FILL_DEFAULT(driver, StatementGetOptionDouble); - FILL_DEFAULT(driver, StatementGetOptionInt); - FILL_DEFAULT(driver, StatementSetOptionBytes); - FILL_DEFAULT(driver, StatementSetOptionDouble); - FILL_DEFAULT(driver, StatementSetOptionInt); - } - - return ADBC_STATUS_OK; - -#undef FILL_DEFAULT -#undef CHECK_REQUIRED -} diff --git a/go/adbc/drivermgr/arrow-adbc/adbc.h b/go/adbc/drivermgr/arrow-adbc/adbc.h deleted file mode 100644 index a55f645ed7..0000000000 --- a/go/adbc/drivermgr/arrow-adbc/adbc.h +++ /dev/null @@ -1,2408 +0,0 @@ -// 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. - -/// \file arrow-adbc/adbc.h ADBC: Arrow Database connectivity -/// -/// An Arrow-based interface between applications and database -/// drivers. ADBC aims to provide a vendor-independent API for SQL -/// and Substrait-based database access that is targeted at -/// analytics/OLAP use cases. -/// -/// This API is intended to be implemented directly by drivers and -/// used directly by client applications. To assist portability -/// between different vendors, a "driver manager" library is also -/// provided, which implements this same API, but dynamically loads -/// drivers internally and forwards calls appropriately. -/// -/// ADBC uses structs with free functions that operate on those -/// structs to model objects. -/// -/// In general, objects allow serialized access from multiple threads, -/// but not concurrent access. Specific implementations may permit -/// multiple threads. -/// -/// \version 1.1.0 - -#pragma once - -#include -#include - -/// \defgroup Arrow C Data Interface -/// Definitions for the C Data Interface/C Stream Interface. -/// -/// See https://arrow.apache.org/docs/format/CDataInterface.html -/// -/// @{ - -//! @cond Doxygen_Suppress - -#ifdef __cplusplus -extern "C" { -#endif - -// Extra guard for versions of Arrow without the canonical guard -#ifndef ARROW_FLAG_DICTIONARY_ORDERED - -#ifndef ARROW_C_DATA_INTERFACE -#define ARROW_C_DATA_INTERFACE - -#define ARROW_FLAG_DICTIONARY_ORDERED 1 -#define ARROW_FLAG_NULLABLE 2 -#define ARROW_FLAG_MAP_KEYS_SORTED 4 - -struct ArrowSchema { - // Array type description - const char* format; - const char* name; - const char* metadata; - int64_t flags; - int64_t n_children; - struct ArrowSchema** children; - struct ArrowSchema* dictionary; - - // Release callback - void (*release)(struct ArrowSchema*); - // Opaque producer-specific data - void* private_data; -}; - -struct ArrowArray { - // Array data description - int64_t length; - int64_t null_count; - int64_t offset; - int64_t n_buffers; - int64_t n_children; - const void** buffers; - struct ArrowArray** children; - struct ArrowArray* dictionary; - - // Release callback - void (*release)(struct ArrowArray*); - // Opaque producer-specific data - void* private_data; -}; - -#endif // ARROW_C_DATA_INTERFACE - -#ifndef ARROW_C_STREAM_INTERFACE -#define ARROW_C_STREAM_INTERFACE - -struct ArrowArrayStream { - // Callback to get the stream type - // (will be the same for all arrays in the stream). - // - // Return value: 0 if successful, an `errno`-compatible error code otherwise. - // - // If successful, the ArrowSchema must be released independently from the stream. - int (*get_schema)(struct ArrowArrayStream*, struct ArrowSchema* out); - - // Callback to get the next array - // (if no error and the array is released, the stream has ended) - // - // Return value: 0 if successful, an `errno`-compatible error code otherwise. - // - // If successful, the ArrowArray must be released independently from the stream. - int (*get_next)(struct ArrowArrayStream*, struct ArrowArray* out); - - // Callback to get optional detailed error information. - // This must only be called if the last stream operation failed - // with a non-0 return code. - // - // Return value: pointer to a null-terminated character array describing - // the last error, or NULL if no description is available. - // - // The returned pointer is only valid until the next operation on this stream - // (including release). - const char* (*get_last_error)(struct ArrowArrayStream*); - - // Release callback: release the stream's own resources. - // Note that arrays returned by `get_next` must be individually released. - void (*release)(struct ArrowArrayStream*); - - // Opaque producer-specific data - void* private_data; -}; - -#endif // ARROW_C_STREAM_INTERFACE -#endif // ARROW_FLAG_DICTIONARY_ORDERED - -//! @endcond - -/// @} - -#ifndef ADBC -#define ADBC - -// Storage class macros for Windows -// Allow overriding/aliasing with application-defined macros -#if !defined(ADBC_EXPORT) -#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) -#endif // !defined(ADBC_EXPORT) - -/// \defgroup adbc-error-handling Error Handling -/// ADBC uses integer error codes to signal errors. To provide more -/// detail about errors, functions may also return an AdbcError via an -/// optional out parameter, which can be inspected. If provided, it is -/// the responsibility of the caller to zero-initialize the AdbcError -/// value. -/// -/// @{ - -/// \brief Error codes for operations that may fail. -typedef uint8_t AdbcStatusCode; - -/// \brief No error. -#define ADBC_STATUS_OK 0 - -/// \brief An unknown error occurred. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_UNKNOWN 1 - -/// \brief The operation is not implemented or supported. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_NOT_IMPLEMENTED 2 - -/// \brief A requested resource was not found. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_NOT_FOUND 3 - -/// \brief A requested resource already exists. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_ALREADY_EXISTS 4 - -/// \brief The arguments are invalid, likely a programming error. -/// -/// For instance, they may be of the wrong format, or out of range. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_INVALID_ARGUMENT 5 - -/// \brief The preconditions for the operation are not met, likely a -/// programming error. -/// -/// For instance, the object may be uninitialized, or may have not -/// been fully configured. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_INVALID_STATE 6 - -/// \brief Invalid data was processed (not a programming error). -/// -/// For instance, a division by zero may have occurred during query -/// execution. -/// -/// May indicate a database-side error only. -#define ADBC_STATUS_INVALID_DATA 7 - -/// \brief The database's integrity was affected. -/// -/// For instance, a foreign key check may have failed, or a uniqueness -/// constraint may have been violated. -/// -/// May indicate a database-side error only. -#define ADBC_STATUS_INTEGRITY 8 - -/// \brief An error internal to the driver or database occurred. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_INTERNAL 9 - -/// \brief An I/O error occurred. -/// -/// For instance, a remote service may be unavailable. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_IO 10 - -/// \brief The operation was cancelled, not due to a timeout. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_CANCELLED 11 - -/// \brief The operation was cancelled due to a timeout. -/// -/// May indicate a driver-side or database-side error. -#define ADBC_STATUS_TIMEOUT 12 - -/// \brief Authentication failed. -/// -/// May indicate a database-side error only. -#define ADBC_STATUS_UNAUTHENTICATED 13 - -/// \brief The client is not authorized to perform the given operation. -/// -/// May indicate a database-side error only. -#define ADBC_STATUS_UNAUTHORIZED 14 - -/// \brief Inform the driver/driver manager that we are using the extended -/// AdbcError struct from ADBC 1.1.0. -/// -/// See the AdbcError documentation for usage. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA INT32_MIN - -/// \brief A detailed error message for an operation. -/// -/// The caller must zero-initialize this struct (clarified in ADBC 1.1.0). -/// -/// The structure was extended in ADBC 1.1.0. Drivers and clients using ADBC -/// 1.0.0 will not have the private_data or private_driver fields. Drivers -/// should read/write these fields if and only if vendor_code is equal to -/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA. Clients are required to initialize -/// this struct to avoid the possibility of uninitialized values confusing the -/// driver. -struct ADBC_EXPORT AdbcError { - /// \brief The error message. - char* message; - - /// \brief A vendor-specific error code, if applicable. - int32_t vendor_code; - - /// \brief A SQLSTATE error code, if provided, as defined by the - /// SQL:2003 standard. If not set, it should be set to - /// "\0\0\0\0\0". - char sqlstate[5]; - - /// \brief Release the contained error. - /// - /// Unlike other structures, this is an embedded callback to make it - /// easier for the driver manager and driver to cooperate. - void (*release)(struct AdbcError* error); - - /// \brief Opaque implementation-defined state. - /// - /// This field may not be used unless vendor_code is - /// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA. If present, this field is NULLPTR - /// iff the error is uninitialized/freed. - /// - /// \since ADBC API revision 1.1.0 - void* private_data; - - /// \brief The associated driver (used by the driver manager to help - /// track state). - /// - /// This field may not be used unless vendor_code is - /// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA. - /// - /// \since ADBC API revision 1.1.0 - struct AdbcDriver* private_driver; -}; - -#ifdef __cplusplus -/// \brief A helper to initialize the full AdbcError structure. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_ERROR_INIT \ - (AdbcError{nullptr, \ - ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA, \ - {0, 0, 0, 0, 0}, \ - nullptr, \ - nullptr, \ - nullptr}) -#else -/// \brief A helper to initialize the full AdbcError structure. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_ERROR_INIT \ - ((struct AdbcError){ \ - NULL, ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA, {0, 0, 0, 0, 0}, NULL, NULL, NULL}) -#endif - -/// \brief The size of the AdbcError structure in ADBC 1.0.0. -/// -/// Drivers written for ADBC 1.1.0 and later should never touch more than this -/// portion of an AdbcDriver struct when vendor_code is not -/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_ERROR_1_0_0_SIZE (offsetof(struct AdbcError, private_data)) - -/// \brief The size of the AdbcError structure in ADBC 1.1.0. -/// -/// Drivers written for ADBC 1.1.0 and later should never touch more than this -/// portion of an AdbcDriver struct when vendor_code is -/// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_ERROR_1_1_0_SIZE (sizeof(struct AdbcError)) - -/// \brief Extra key-value metadata for an error. -/// -/// The fields here are owned by the driver and should not be freed. The -/// fields here are invalidated when the release callback in AdbcError is -/// called. -/// -/// \since ADBC API revision 1.1.0 -struct ADBC_EXPORT AdbcErrorDetail { - /// \brief The metadata key. - const char* key; - /// \brief The binary metadata value. - const uint8_t* value; - /// \brief The length of the metadata value. - size_t value_length; -}; - -/// \brief Get the number of metadata values available in an error. -/// -/// \since ADBC API revision 1.1.0 -ADBC_EXPORT -int AdbcErrorGetDetailCount(const struct AdbcError* error); - -/// \brief Get a metadata value in an error by index. -/// -/// If index is invalid, returns an AdbcErrorDetail initialized with NULL/0 -/// fields. -/// -/// \since ADBC API revision 1.1.0 -ADBC_EXPORT -struct AdbcErrorDetail AdbcErrorGetDetail(const struct AdbcError* error, int index); - -/// \brief Get an ADBC error from an ArrowArrayStream created by a driver. -/// -/// This allows retrieving error details and other metadata that would -/// normally be suppressed by the Arrow C Stream Interface. -/// -/// The caller MUST NOT release the error; it is managed by the release -/// callback in the stream itself. -/// -/// \param[in] stream The stream to query. -/// \param[out] status The ADBC status code, or ADBC_STATUS_OK if there is no -/// error. Not written to if the stream does not contain an ADBC error or -/// if the pointer is NULL. -/// \return NULL if not supported. -/// \since ADBC API revision 1.1.0 -ADBC_EXPORT -const struct AdbcError* AdbcErrorFromArrayStream(struct ArrowArrayStream* stream, - AdbcStatusCode* status); - -/// @} - -/// \defgroup adbc-constants Constants -/// @{ - -/// \brief ADBC revision 1.0.0. -/// -/// When passed to an AdbcDriverInitFunc(), the driver parameter must -/// point to an AdbcDriver. -#define ADBC_VERSION_1_0_0 1000000 - -/// \brief ADBC revision 1.1.0. -/// -/// When passed to an AdbcDriverInitFunc(), the driver parameter must -/// point to an AdbcDriver. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_VERSION_1_1_0 1001000 - -/// \brief Canonical option value for enabling an option. -/// -/// For use as the value in SetOption calls. -#define ADBC_OPTION_VALUE_ENABLED "true" - -/// \brief Canonical option value for disabling an option. -/// -/// For use as the value in SetOption calls. -#define ADBC_OPTION_VALUE_DISABLED "false" - -/// \brief Canonical option name for URIs. -/// -/// Should be used as the expected option name to specify a URI for -/// any ADBC driver. -/// -/// The type is char*. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_OPTION_URI "uri" - -/// \brief Canonical option name for usernames. -/// -/// Should be used as the expected option name to specify a username -/// to a driver for authentication. -/// -/// The type is char*. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_OPTION_USERNAME "username" - -/// \brief Canonical option name for passwords. -/// -/// Should be used as the expected option name to specify a password -/// for authentication to a driver. -/// -/// The type is char*. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_OPTION_PASSWORD "password" - -/// \brief The database vendor/product name (e.g. the server name). -/// (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_NAME 0 - -/// \brief The database vendor/product version (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_VERSION 1 - -/// \brief The database vendor/product Arrow library version (type: -/// utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_ARROW_VERSION 2 - -/// \brief Indicates whether SQL queries are supported (type: bool). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_SQL 3 - -/// \brief Indicates whether Substrait queries are supported (type: bool). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_SUBSTRAIT 4 - -/// \brief The minimum supported Substrait version, or null if -/// Substrait is not supported (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_SUBSTRAIT_MIN_VERSION 5 - -/// \brief The maximum supported Substrait version, or null if -/// Substrait is not supported (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_VENDOR_SUBSTRAIT_MAX_VERSION 6 - -/// \brief The driver name (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_DRIVER_NAME 100 - -/// \brief The driver version (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_DRIVER_VERSION 101 - -/// \brief The driver Arrow library version (type: utf8). -/// -/// \see AdbcConnectionGetInfo -#define ADBC_INFO_DRIVER_ARROW_VERSION 102 - -/// \brief The driver ADBC API version (type: int64). -/// -/// The value should be one of the ADBC_VERSION constants. -/// -/// \since ADBC API revision 1.1.0 -/// \see AdbcConnectionGetInfo -/// \see ADBC_VERSION_1_0_0 -/// \see ADBC_VERSION_1_1_0 -#define ADBC_INFO_DRIVER_ADBC_VERSION 103 - -/// \brief Return metadata on catalogs, schemas, tables, and columns. -/// -/// \see AdbcConnectionGetObjects -#define ADBC_OBJECT_DEPTH_ALL 0 - -/// \brief Return metadata on catalogs only. -/// -/// \see AdbcConnectionGetObjects -#define ADBC_OBJECT_DEPTH_CATALOGS 1 - -/// \brief Return metadata on catalogs and schemas. -/// -/// \see AdbcConnectionGetObjects -#define ADBC_OBJECT_DEPTH_DB_SCHEMAS 2 - -/// \brief Return metadata on catalogs, schemas, and tables. -/// -/// \see AdbcConnectionGetObjects -#define ADBC_OBJECT_DEPTH_TABLES 3 - -/// \brief Return metadata on catalogs, schemas, tables, and columns. -/// -/// \see AdbcConnectionGetObjects -#define ADBC_OBJECT_DEPTH_COLUMNS ADBC_OBJECT_DEPTH_ALL - -/// \defgroup adbc-table-statistics ADBC Statistic Types -/// Standard statistic names for AdbcConnectionGetStatistics. -/// @{ - -/// \brief The dictionary-encoded name of the average byte width statistic. -#define ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_KEY 0 - -/// \brief The average byte width statistic. The average size in bytes of a -/// row in the column. Value type is float64. -/// -/// For example, this is roughly the average length of a string for a string -/// column. -#define ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_NAME "adbc.statistic.byte_width" - -/// \brief The dictionary-encoded name of the distinct value count statistic. -#define ADBC_STATISTIC_DISTINCT_COUNT_KEY 1 - -/// \brief The distinct value count (NDV) statistic. The number of distinct -/// values in the column. Value type is int64 (when not approximate) or -/// float64 (when approximate). -#define ADBC_STATISTIC_DISTINCT_COUNT_NAME "adbc.statistic.distinct_count" - -/// \brief The dictionary-encoded name of the max byte width statistic. -#define ADBC_STATISTIC_MAX_BYTE_WIDTH_KEY 2 - -/// \brief The max byte width statistic. The maximum size in bytes of a row -/// in the column. Value type is int64 (when not approximate) or float64 -/// (when approximate). -/// -/// For example, this is the maximum length of a string for a string column. -#define ADBC_STATISTIC_MAX_BYTE_WIDTH_NAME "adbc.statistic.max_byte_width" - -/// \brief The dictionary-encoded name of the max value statistic. -#define ADBC_STATISTIC_MAX_VALUE_KEY 3 - -/// \brief The max value statistic. Value type is column-dependent. -#define ADBC_STATISTIC_MAX_VALUE_NAME "adbc.statistic.max_value" - -/// \brief The dictionary-encoded name of the min value statistic. -#define ADBC_STATISTIC_MIN_VALUE_KEY 4 - -/// \brief The min value statistic. Value type is column-dependent. -#define ADBC_STATISTIC_MIN_VALUE_NAME "adbc.statistic.min_value" - -/// \brief The dictionary-encoded name of the null count statistic. -#define ADBC_STATISTIC_NULL_COUNT_KEY 5 - -/// \brief The null count statistic. The number of values that are null in -/// the column. Value type is int64 (when not approximate) or float64 -/// (when approximate). -#define ADBC_STATISTIC_NULL_COUNT_NAME "adbc.statistic.null_count" - -/// \brief The dictionary-encoded name of the row count statistic. -#define ADBC_STATISTIC_ROW_COUNT_KEY 6 - -/// \brief The row count statistic. The number of rows in the column or -/// table. Value type is int64 (when not approximate) or float64 (when -/// approximate). -#define ADBC_STATISTIC_ROW_COUNT_NAME "adbc.statistic.row_count" -/// @} - -/// \brief The name of the canonical option for whether autocommit is -/// enabled. -/// -/// The type is char*. -/// -/// \see AdbcConnectionSetOption -#define ADBC_CONNECTION_OPTION_AUTOCOMMIT "adbc.connection.autocommit" - -/// \brief The name of the canonical option for whether the current -/// connection should be restricted to being read-only. -/// -/// The type is char*. -/// -/// \see AdbcConnectionSetOption -#define ADBC_CONNECTION_OPTION_READ_ONLY "adbc.connection.readonly" - -/// \brief The name of the canonical option for the current catalog. -/// -/// The type is char*. -/// -/// \see AdbcConnectionGetOption -/// \see AdbcConnectionSetOption -/// \since ADBC API revision 1.1.0 -#define ADBC_CONNECTION_OPTION_CURRENT_CATALOG "adbc.connection.catalog" - -/// \brief The name of the canonical option for the current schema. -/// -/// The type is char*. -/// -/// \see AdbcConnectionGetOption -/// \see AdbcConnectionSetOption -/// \since ADBC API revision 1.1.0 -#define ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA "adbc.connection.db_schema" - -/// \brief The name of the canonical option for making query execution -/// nonblocking. -/// -/// When enabled, AdbcStatementExecutePartitions will return -/// partitions as soon as they are available, instead of returning -/// them all at the end. When there are no more to return, it will -/// return an empty set of partitions. AdbcStatementExecuteQuery and -/// AdbcStatementExecuteSchema are not affected. -/// -/// The default is ADBC_OPTION_VALUE_DISABLED. -/// -/// The type is char*. -/// -/// \see AdbcStatementSetOption -/// \since ADBC API revision 1.1.0 -#define ADBC_STATEMENT_OPTION_INCREMENTAL "adbc.statement.exec.incremental" - -/// \brief The name of the option for getting the progress of a query. -/// -/// The value is not necessarily in any particular range or have any -/// particular units. (For example, it might be a percentage, bytes of data, -/// rows of data, number of workers, etc.) The max value can be retrieved via -/// ADBC_STATEMENT_OPTION_MAX_PROGRESS. This represents the progress of -/// execution, not of consumption (i.e., it is independent of how much of the -/// result set has been read by the client via ArrowArrayStream.get_next().) -/// -/// The type is double. -/// -/// \see AdbcStatementGetOptionDouble -/// \since ADBC API revision 1.1.0 -#define ADBC_STATEMENT_OPTION_PROGRESS "adbc.statement.exec.progress" - -/// \brief The name of the option for getting the maximum progress of a query. -/// -/// This is the value of ADBC_STATEMENT_OPTION_PROGRESS for a completed query. -/// If not supported, or if the value is nonpositive, then the maximum is not -/// known. (For instance, the query may be fully streaming and the driver -/// does not know when the result set will end.) -/// -/// The type is double. -/// -/// \see AdbcStatementGetOptionDouble -/// \since ADBC API revision 1.1.0 -#define ADBC_STATEMENT_OPTION_MAX_PROGRESS "adbc.statement.exec.max_progress" - -/// \brief The name of the canonical option for setting the isolation -/// level of a transaction. -/// -/// Should only be used in conjunction with autocommit disabled and -/// AdbcConnectionCommit / AdbcConnectionRollback. If the desired -/// isolation level is not supported by a driver, it should return an -/// appropriate error. -/// -/// The type is char*. -/// -/// \see AdbcConnectionSetOption -#define ADBC_CONNECTION_OPTION_ISOLATION_LEVEL \ - "adbc.connection.transaction.isolation_level" - -/// \brief Use database or driver default isolation level -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_DEFAULT \ - "adbc.connection.transaction.isolation.default" - -/// \brief The lowest isolation level. Dirty reads are allowed, so one -/// transaction may see not-yet-committed changes made by others. -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_READ_UNCOMMITTED \ - "adbc.connection.transaction.isolation.read_uncommitted" - -/// \brief Lock-based concurrency control keeps write locks until the -/// end of the transaction, but read locks are released as soon as a -/// SELECT is performed. Non-repeatable reads can occur in this -/// isolation level. -/// -/// More simply put, Read Committed is an isolation level that guarantees -/// that any data read is committed at the moment it is read. It simply -/// restricts the reader from seeing any intermediate, uncommitted, -/// 'dirty' reads. It makes no promise whatsoever that if the transaction -/// re-issues the read, it will find the same data; data is free to change -/// after it is read. -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_READ_COMMITTED \ - "adbc.connection.transaction.isolation.read_committed" - -/// \brief Lock-based concurrency control keeps read AND write locks -/// (acquired on selection data) until the end of the transaction. -/// -/// However, range-locks are not managed, so phantom reads can occur. -/// Write skew is possible at this isolation level in some systems. -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_REPEATABLE_READ \ - "adbc.connection.transaction.isolation.repeatable_read" - -/// \brief This isolation guarantees that all reads in the transaction -/// will see a consistent snapshot of the database and the transaction -/// should only successfully commit if no updates conflict with any -/// concurrent updates made since that snapshot. -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_SNAPSHOT \ - "adbc.connection.transaction.isolation.snapshot" - -/// \brief Serializability requires read and write locks to be released -/// only at the end of the transaction. This includes acquiring range- -/// locks when a select query uses a ranged WHERE clause to avoid -/// phantom reads. -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_SERIALIZABLE \ - "adbc.connection.transaction.isolation.serializable" - -/// \brief The central distinction between serializability and linearizability -/// is that serializability is a global property; a property of an entire -/// history of operations and transactions. Linearizability is a local -/// property; a property of a single operation/transaction. -/// -/// Linearizability can be viewed as a special case of strict serializability -/// where transactions are restricted to consist of a single operation applied -/// to a single object. -/// -/// \see AdbcConnectionSetOption -#define ADBC_OPTION_ISOLATION_LEVEL_LINEARIZABLE \ - "adbc.connection.transaction.isolation.linearizable" - -/// \defgroup adbc-statement-ingestion Bulk Data Ingestion -/// While it is possible to insert data via prepared statements, it can -/// be more efficient to explicitly perform a bulk insert. For -/// compatible drivers, this can be accomplished by setting up and -/// executing a statement. Instead of setting a SQL query or Substrait -/// plan, bind the source data via AdbcStatementBind, and set the name -/// of the table to be created via AdbcStatementSetOption and the -/// options below. Then, call AdbcStatementExecute with a NULL for -/// the out parameter (to indicate you do not expect a result set). -/// -/// @{ - -/// \brief The name of the target table for a bulk insert. -/// -/// The driver should attempt to create the table if it does not -/// exist. If the table exists but has a different schema, -/// ADBC_STATUS_ALREADY_EXISTS should be raised. Else, data should be -/// appended to the target table. -/// -/// The type is char*. -#define ADBC_INGEST_OPTION_TARGET_TABLE "adbc.ingest.target_table" - -/// \brief Whether to create (the default) or append. -/// -/// The type is char*. -#define ADBC_INGEST_OPTION_MODE "adbc.ingest.mode" - -/// \brief Create the table and insert data; error if the table exists. -#define ADBC_INGEST_OPTION_MODE_CREATE "adbc.ingest.mode.create" - -/// \brief Do not create the table, and insert data; error if the -/// table does not exist (ADBC_STATUS_NOT_FOUND) or does not match -/// the schema of the data to append (ADBC_STATUS_ALREADY_EXISTS). -#define ADBC_INGEST_OPTION_MODE_APPEND "adbc.ingest.mode.append" - -/// \brief Create the table and insert data; drop the original table -/// if it already exists. -/// \since ADBC API revision 1.1.0 -#define ADBC_INGEST_OPTION_MODE_REPLACE "adbc.ingest.mode.replace" - -/// \brief Insert data; create the table if it does not exist, or -/// error if the table exists, but the schema does not match the -/// schema of the data to append (ADBC_STATUS_ALREADY_EXISTS). -/// \since ADBC API revision 1.1.0 -#define ADBC_INGEST_OPTION_MODE_CREATE_APPEND "adbc.ingest.mode.create_append" - -/// \brief The catalog of the table for bulk insert. -/// -/// The type is char*. -#define ADBC_INGEST_OPTION_TARGET_CATALOG "adbc.ingest.target_catalog" - -/// \brief The schema of the table for bulk insert. -/// -/// The type is char*. -#define ADBC_INGEST_OPTION_TARGET_DB_SCHEMA "adbc.ingest.target_db_schema" - -/// \brief Use a temporary table for ingestion. -/// -/// The value should be ADBC_OPTION_VALUE_ENABLED or -/// ADBC_OPTION_VALUE_DISABLED (the default). -/// -/// This is not supported with ADBC_INGEST_OPTION_TARGET_CATALOG and -/// ADBC_INGEST_OPTION_TARGET_DB_SCHEMA. -/// -/// The type is char*. -#define ADBC_INGEST_OPTION_TEMPORARY "adbc.ingest.temporary" - -/// @} - -/// @} - -/// \defgroup adbc-database Database Initialization -/// Clients first initialize a database, then create a connection -/// (below). This gives the implementation a place to initialize and -/// own any common connection state. For example, in-memory databases -/// can place ownership of the actual database in this object. -/// @{ - -/// \brief An instance of a database. -/// -/// Must be kept alive as long as any connections exist. -struct ADBC_EXPORT AdbcDatabase { - /// \brief Opaque implementation-defined state. - /// This field is NULLPTR iff the connection is uninitialized/freed. - void* private_data; - /// \brief The associated driver (used by the driver manager to help - /// track state). - struct AdbcDriver* private_driver; -}; - -/// @} - -/// \defgroup adbc-connection Connection Establishment -/// Functions for creating, using, and releasing database connections. -/// @{ - -/// \brief An active database connection. -/// -/// Provides methods for query execution, managing prepared -/// statements, using transactions, and so on. -/// -/// Connections are not required to be thread-safe, but they can be -/// used from multiple threads so long as clients take care to -/// serialize accesses to a connection. -struct ADBC_EXPORT AdbcConnection { - /// \brief Opaque implementation-defined state. - /// This field is NULLPTR iff the connection is uninitialized/freed. - void* private_data; - /// \brief The associated driver (used by the driver manager to help - /// track state). - struct AdbcDriver* private_driver; -}; - -/// @} - -/// \defgroup adbc-statement Managing Statements -/// Applications should first initialize a statement with -/// AdbcStatementNew. Then, the statement should be configured with -/// functions like AdbcStatementSetSqlQuery and -/// AdbcStatementSetOption. Finally, the statement can be executed -/// with AdbcStatementExecuteQuery (or call AdbcStatementPrepare first -/// to turn it into a prepared statement instead). -/// @{ - -/// \brief A container for all state needed to execute a database -/// query, such as the query itself, parameters for prepared -/// statements, driver parameters, etc. -/// -/// Statements may represent queries or prepared statements. -/// -/// Statements may be used multiple times and can be reconfigured -/// (e.g. they can be reused to execute multiple different queries). -/// However, executing a statement (and changing certain other state) -/// will invalidate result sets obtained prior to that execution. -/// -/// Multiple statements may be created from a single connection. -/// However, the driver may block or error if they are used -/// concurrently (whether from a single thread or multiple threads). -/// -/// Statements are not required to be thread-safe, but they can be -/// used from multiple threads so long as clients take care to -/// serialize accesses to a statement. -struct ADBC_EXPORT AdbcStatement { - /// \brief Opaque implementation-defined state. - /// This field is NULLPTR iff the connection is uninitialized/freed. - void* private_data; - - /// \brief The associated driver (used by the driver manager to help - /// track state). - struct AdbcDriver* private_driver; -}; - -/// \defgroup adbc-statement-partition Partitioned Results -/// Some backends may internally partition the results. These -/// partitions are exposed to clients who may wish to integrate them -/// with a threaded or distributed execution model, where partitions -/// can be divided among threads or machines and fetched in parallel. -/// -/// To use partitioning, execute the statement with -/// AdbcStatementExecutePartitions to get the partition descriptors. -/// Call AdbcConnectionReadPartition to turn the individual -/// descriptors into ArrowArrayStream instances. This may be done on -/// a different connection than the one the partition was created -/// with, or even in a different process on another machine. -/// -/// Drivers are not required to support partitioning. -/// -/// @{ - -/// \brief The partitions of a distributed/partitioned result set. -struct AdbcPartitions { - /// \brief The number of partitions. - size_t num_partitions; - - /// \brief The partitions of the result set, where each entry (up to - /// num_partitions entries) is an opaque identifier that can be - /// passed to AdbcConnectionReadPartition. - const uint8_t** partitions; - - /// \brief The length of each corresponding entry in partitions. - const size_t* partition_lengths; - - /// \brief Opaque implementation-defined state. - /// This field is NULLPTR iff the connection is uninitialized/freed. - void* private_data; - - /// \brief Release the contained partitions. - /// - /// Unlike other structures, this is an embedded callback to make it - /// easier for the driver manager and driver to cooperate. - void (*release)(struct AdbcPartitions* partitions); -}; - -/// @} - -/// @} - -/// \defgroup adbc-driver Driver Initialization -/// -/// These functions are intended to help support integration between a -/// driver and the driver manager. -/// @{ - -/// \brief An instance of an initialized database driver. -/// -/// This provides a common interface for vendor-specific driver -/// initialization routines. Drivers should populate this struct, and -/// applications can call ADBC functions through this struct, without -/// worrying about multiple definitions of the same symbol. -struct ADBC_EXPORT AdbcDriver { - /// \brief Opaque driver-defined state. - /// This field is NULL if the driver is uninitialized/freed (but - /// it need not have a value even if the driver is initialized). - void* private_data; - /// \brief Opaque driver manager-defined state. - /// This field is NULL if the driver is uninitialized/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. - /// - /// 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 (*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*, const 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*); - - /// \defgroup adbc-1.1.0 ADBC API Revision 1.1.0 - /// - /// Functions added in ADBC 1.1.0. For backwards compatibility, - /// these members must not be accessed unless the version passed to - /// the AdbcDriverInitFunc is greater than or equal to - /// ADBC_VERSION_1_1_0. - /// - /// For a 1.0.0 driver being loaded by a 1.1.0 driver manager: the - /// 1.1.0 manager will allocate the new, expanded AdbcDriver struct - /// and attempt to have the driver initialize it with - /// ADBC_VERSION_1_1_0. This must return an error, after which the - /// driver will try again with ADBC_VERSION_1_0_0. The driver must - /// not access the new fields, which will carry undefined values. - /// - /// For a 1.1.0 driver being loaded by a 1.0.0 driver manager: the - /// 1.0.0 manager will allocate the old AdbcDriver struct and - /// attempt to have the driver initialize it with - /// ADBC_VERSION_1_0_0. The driver must not access the new fields, - /// and should initialize the old fields. - /// - /// @{ - - int (*ErrorGetDetailCount)(const struct AdbcError* error); - struct AdbcErrorDetail (*ErrorGetDetail)(const struct AdbcError* error, int index); - const struct AdbcError* (*ErrorFromArrayStream)(struct ArrowArrayStream* stream, - AdbcStatusCode* status); - - AdbcStatusCode (*DatabaseGetOption)(struct AdbcDatabase*, const char*, char*, size_t*, - struct AdbcError*); - AdbcStatusCode (*DatabaseGetOptionBytes)(struct AdbcDatabase*, const char*, uint8_t*, - size_t*, struct AdbcError*); - AdbcStatusCode (*DatabaseGetOptionDouble)(struct AdbcDatabase*, const char*, double*, - struct AdbcError*); - AdbcStatusCode (*DatabaseGetOptionInt)(struct AdbcDatabase*, const char*, int64_t*, - struct AdbcError*); - AdbcStatusCode (*DatabaseSetOptionBytes)(struct AdbcDatabase*, const char*, - const uint8_t*, size_t, struct AdbcError*); - AdbcStatusCode (*DatabaseSetOptionDouble)(struct AdbcDatabase*, const char*, double, - struct AdbcError*); - AdbcStatusCode (*DatabaseSetOptionInt)(struct AdbcDatabase*, const char*, int64_t, - struct AdbcError*); - - AdbcStatusCode (*ConnectionCancel)(struct AdbcConnection*, struct AdbcError*); - AdbcStatusCode (*ConnectionGetOption)(struct AdbcConnection*, const char*, char*, - size_t*, struct AdbcError*); - AdbcStatusCode (*ConnectionGetOptionBytes)(struct AdbcConnection*, const char*, - uint8_t*, size_t*, struct AdbcError*); - AdbcStatusCode (*ConnectionGetOptionDouble)(struct AdbcConnection*, const char*, - double*, struct AdbcError*); - AdbcStatusCode (*ConnectionGetOptionInt)(struct AdbcConnection*, const char*, int64_t*, - struct AdbcError*); - AdbcStatusCode (*ConnectionGetStatistics)(struct AdbcConnection*, const char*, - const char*, const char*, char, - struct ArrowArrayStream*, struct AdbcError*); - AdbcStatusCode (*ConnectionGetStatisticNames)(struct AdbcConnection*, - struct ArrowArrayStream*, - struct AdbcError*); - AdbcStatusCode (*ConnectionSetOptionBytes)(struct AdbcConnection*, const char*, - const uint8_t*, size_t, struct AdbcError*); - AdbcStatusCode (*ConnectionSetOptionDouble)(struct AdbcConnection*, const char*, double, - struct AdbcError*); - AdbcStatusCode (*ConnectionSetOptionInt)(struct AdbcConnection*, const char*, int64_t, - struct AdbcError*); - - AdbcStatusCode (*StatementCancel)(struct AdbcStatement*, struct AdbcError*); - AdbcStatusCode (*StatementExecuteSchema)(struct AdbcStatement*, struct ArrowSchema*, - struct AdbcError*); - AdbcStatusCode (*StatementGetOption)(struct AdbcStatement*, const char*, char*, size_t*, - struct AdbcError*); - AdbcStatusCode (*StatementGetOptionBytes)(struct AdbcStatement*, const char*, uint8_t*, - size_t*, struct AdbcError*); - AdbcStatusCode (*StatementGetOptionDouble)(struct AdbcStatement*, const char*, double*, - struct AdbcError*); - AdbcStatusCode (*StatementGetOptionInt)(struct AdbcStatement*, const char*, int64_t*, - struct AdbcError*); - AdbcStatusCode (*StatementSetOptionBytes)(struct AdbcStatement*, const char*, - const uint8_t*, size_t, struct AdbcError*); - AdbcStatusCode (*StatementSetOptionDouble)(struct AdbcStatement*, const char*, double, - struct AdbcError*); - AdbcStatusCode (*StatementSetOptionInt)(struct AdbcStatement*, const char*, int64_t, - struct AdbcError*); - - /// @} -}; - -/// \brief The size of the AdbcDriver structure in ADBC 1.0.0. -/// Drivers written for ADBC 1.1.0 and later should never touch more -/// than this portion of an AdbcDriver struct when given -/// ADBC_VERSION_1_0_0. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_DRIVER_1_0_0_SIZE (offsetof(struct AdbcDriver, ErrorGetDetailCount)) - -/// \brief The size of the AdbcDriver structure in ADBC 1.1.0. -/// Drivers written for ADBC 1.1.0 and later should never touch more -/// than this portion of an AdbcDriver struct when given -/// ADBC_VERSION_1_1_0. -/// -/// \since ADBC API revision 1.1.0 -#define ADBC_DRIVER_1_1_0_SIZE (sizeof(struct AdbcDriver)) - -/// @} - -/// \addtogroup adbc-database -/// @{ - -/// \brief Allocate a new (but uninitialized) database. -/// -/// Callers pass in a zero-initialized AdbcDatabase. -/// -/// Drivers should allocate their internal data structure and set the private_data -/// field to point to the newly allocated struct. This struct should be released -/// when AdbcDatabaseRelease is called. -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct AdbcError* error); - -/// \brief Get a string option of the database. -/// -/// This must always be thread-safe (other operations are not), though -/// given the semantics here, it is not recommended to call GetOption -/// concurrently with itself. -/// -/// length must be provided and must be the size of the buffer pointed -/// to by value. If there is sufficient space, the driver will copy -/// the option value (including the null terminator) to buffer and set -/// length to the size of the actual value. If the buffer is too -/// small, no data will be written and length will be set to the -/// required length. -/// -/// In other words: -/// -/// - If output length <= input length, value will contain a value -/// with length bytes. -/// - If output length > input length, nothing has been written to -/// value. -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[in,out] length The length of value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseGetOption(struct AdbcDatabase* database, const char* key, - char* value, size_t* length, - struct AdbcError* error); - -/// \brief Get a bytestring option of the database. -/// -/// This must always be thread-safe (other operations are not), though -/// given the semantics here, it is not recommended to call -/// GetOptionBytes concurrently with itself. -/// -/// length must be provided and must be the size of the buffer pointed -/// to by value. If there is sufficient space, the driver will copy -/// the option value to buffer and set length to the size of the -/// actual value. If the buffer is too small, no data will be written -/// and length will be set to the required length. -/// -/// In other words: -/// -/// - If output length <= input length, value will contain a value -/// with length bytes. -/// - If output length > input length, nothing has been written to -/// value. -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[in,out] length The option value length. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseGetOptionBytes(struct AdbcDatabase* database, const char* key, - uint8_t* value, size_t* length, - struct AdbcError* error); - -/// \brief Get a double option of the database. -/// -/// This must always be thread-safe (other operations are not). -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the double -/// representation of an integer option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseGetOptionDouble(struct AdbcDatabase* database, const char* key, - double* value, struct AdbcError* error); - -/// \brief Get an integer option of the database. -/// -/// This must always be thread-safe (other operations are not). -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the integer -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseGetOptionInt(struct AdbcDatabase* database, const char* key, - int64_t* value, struct AdbcError* error); - -/// \brief Set a char* option. -/// -/// Options may be set before AdbcDatabaseInit. Some drivers may -/// support setting options after initialization as well. -/// -/// \param[in] database The database. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const char* key, - const char* value, struct AdbcError* error); - -/// \brief Set a bytestring option on a database. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[in] length The option value length. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseSetOptionBytes(struct AdbcDatabase* database, const char* key, - const uint8_t* value, size_t length, - struct AdbcError* error); - -/// \brief Set a double option on a database. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseSetOptionDouble(struct AdbcDatabase* database, const char* key, - double value, struct AdbcError* error); - -/// \brief Set an integer option on a database. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] database The database. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcDatabaseSetOptionInt(struct AdbcDatabase* database, const char* key, - int64_t value, struct AdbcError* error); - -/// \brief Finish setting options and initialize the database. -/// -/// Some drivers 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); - -/// @} - -/// \addtogroup adbc-connection -/// @{ - -/// \brief Allocate a new (but uninitialized) connection. -/// -/// Callers pass in a zero-initialized AdbcConnection. -/// -/// Drivers should allocate their internal data structure and set the private_data -/// field to point to the newly allocated struct. This struct should be released -/// when AdbcConnectionRelease is called. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionNew(struct AdbcConnection* connection, - struct AdbcError* error); - -/// \brief Set a char* option. -/// -/// Options may be set before AdbcConnectionInit. Some drivers may -/// support setting options after initialization as well. -/// -/// \param[in] connection The database connection. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection, const char* key, - const char* value, struct AdbcError* error); - -/// \brief Set a bytestring option on a connection. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The connection. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[in] length The option value length. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcConnectionSetOptionBytes(struct AdbcConnection* connection, - const char* key, const uint8_t* value, - size_t length, struct AdbcError* error); - -/// \brief Set an integer option. -/// -/// Options may be set before AdbcConnectionInit. Some drivers may -/// support setting options after initialization as well. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcConnectionSetOptionInt(struct AdbcConnection* connection, - const char* key, int64_t value, - struct AdbcError* error); - -/// \brief Set a double option. -/// -/// Options may be set before AdbcConnectionInit. Some drivers may -/// support setting options after initialization as well. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcConnectionSetOptionDouble(struct AdbcConnection* connection, - const char* key, double value, - struct AdbcError* error); - -/// \brief Finish setting options and initialize the connection. -/// -/// Some drivers may support setting options after initialization -/// as well. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionInit(struct AdbcConnection* connection, - struct AdbcDatabase* database, struct AdbcError* error); - -/// \brief Destroy this 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); - -/// \brief Cancel the in-progress operation on a connection. -/// -/// This can be called during AdbcConnectionGetObjects (or similar), -/// or while consuming an ArrowArrayStream returned from such. -/// Calling this function should make the other functions return -/// ADBC_STATUS_CANCELLED (from ADBC functions) or ECANCELED (from -/// methods of ArrowArrayStream). (It is not guaranteed to, for -/// instance, the result set may be buffered in memory already.) -/// -/// This must always be thread-safe (other operations are not). It is -/// not necessarily signal-safe. -/// -/// \since ADBC API revision 1.1.0 -/// -/// \param[in] connection The connection to cancel. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// -/// \return ADBC_STATUS_INVALID_STATE if there is no operation to cancel. -/// \return ADBC_STATUS_UNKNOWN if the operation could not be cancelled. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionCancel(struct AdbcConnection* connection, - struct AdbcError* error); - -/// \defgroup adbc-connection-metadata Metadata -/// Functions for retrieving metadata about the database. -/// -/// Generally, these functions return an ArrowArrayStream that can be -/// consumed to get the metadata as Arrow data. The returned metadata -/// has an expected schema given in the function docstring. Schema -/// fields are nullable unless otherwise marked. While no -/// AdbcStatement is used in these functions, the result set may count -/// as an active statement to the driver for the purposes of -/// concurrency management (e.g. if the driver has a limit on -/// concurrent active statements and it must execute a SQL query -/// internally in order to implement the metadata function). -/// -/// This AdbcConnection must outlive the returned ArrowArrayStream. -/// -/// Some functions accept "search pattern" arguments, which are -/// strings that can contain the special character "%" to match zero -/// or more characters, or "_" to match exactly one character. (See -/// the documentation of DatabaseMetaData in JDBC or "Pattern Value -/// Arguments" in the ODBC documentation.) Escaping is not currently -/// supported. -/// -/// @{ - -/// \brief Get metadata about the database/driver. -/// -/// The result is an Arrow dataset with the following schema: -/// -/// Field Name | Field Type -/// ----------------------------|------------------------ -/// info_name | uint32 not null -/// info_value | INFO_SCHEMA -/// -/// INFO_SCHEMA is a dense union with members: -/// -/// Field Name (Type Code) | Field Type -/// ----------------------------|------------------------ -/// string_value (0) | utf8 -/// bool_value (1) | bool -/// int64_value (2) | int64 -/// int32_bitmask (3) | int32 -/// string_list (4) | list -/// int32_to_int32_list_map (5) | map> -/// -/// Each metadatum is identified by an integer code. The recognized -/// codes are defined as constants. Codes [0, 10_000) are reserved -/// for ADBC usage. Drivers/vendors will ignore requests for -/// unrecognized codes (the row will be omitted from the result). -/// -/// Since ADBC 1.1.0: the range [500, 1_000) is reserved for "XDBC" -/// information, which is the same metadata provided by the same info -/// code range in the Arrow Flight SQL GetSqlInfo RPC. -/// -/// \param[in] connection The connection to query. -/// \param[in] info_codes A list of metadata codes to fetch, or NULL -/// to fetch all. -/// \param[in] info_codes_length The length of the info_codes -/// parameter. Ignored if info_codes is NULL. -/// \param[out] out The result set. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetInfo(struct AdbcConnection* connection, - const uint32_t* info_codes, size_t info_codes_length, - struct ArrowArrayStream* out, - struct AdbcError* error); - -/// \brief Get a hierarchical view of all catalogs, database schemas, -/// tables, and columns. -/// -/// The result is an Arrow dataset with the following schema: -/// -/// | Field Name | Field Type | -/// |--------------------------|-------------------------| -/// | catalog_name | utf8 | -/// | catalog_db_schemas | list | -/// -/// DB_SCHEMA_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | -/// |--------------------------|-------------------------| -/// | db_schema_name | utf8 | -/// | db_schema_tables | list | -/// -/// TABLE_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | -/// |--------------------------|-------------------------| -/// | table_name | utf8 not null | -/// | table_type | utf8 not null | -/// | table_columns | list | -/// | table_constraints | list | -/// -/// COLUMN_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | Comments | -/// |--------------------------|-------------------------|----------| -/// | column_name | utf8 not null | | -/// | ordinal_position | int32 | (1) | -/// | remarks | utf8 | (2) | -/// | xdbc_data_type | int16 | (3) | -/// | xdbc_type_name | utf8 | (3) | -/// | xdbc_column_size | int32 | (3) | -/// | xdbc_decimal_digits | int16 | (3) | -/// | xdbc_num_prec_radix | int16 | (3) | -/// | xdbc_nullable | int16 | (3) | -/// | xdbc_column_def | utf8 | (3) | -/// | xdbc_sql_data_type | int16 | (3) | -/// | xdbc_datetime_sub | int16 | (3) | -/// | xdbc_char_octet_length | int32 | (3) | -/// | xdbc_is_nullable | utf8 | (3) | -/// | xdbc_scope_catalog | utf8 | (3) | -/// | xdbc_scope_schema | utf8 | (3) | -/// | xdbc_scope_table | utf8 | (3) | -/// | xdbc_is_autoincrement | bool | (3) | -/// | xdbc_is_generatedcolumn | bool | (3) | -/// -/// 1. The column's ordinal position in the table (starting from 1). -/// 2. Database-specific description of the column. -/// 3. Optional value. Should be null if not supported by the driver. -/// xdbc_ values are meant to provide JDBC/ODBC-compatible metadata -/// in an agnostic manner. -/// -/// CONSTRAINT_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | Comments | -/// |--------------------------|-------------------------|----------| -/// | constraint_name | utf8 | | -/// | constraint_type | utf8 not null | (1) | -/// | constraint_column_names | list not null | (2) | -/// | constraint_column_usage | list | (3) | -/// -/// 1. One of 'CHECK', 'FOREIGN KEY', 'PRIMARY KEY', or 'UNIQUE'. -/// 2. The columns on the current table that are constrained, in -/// order. -/// 3. For FOREIGN KEY only, the referenced table and columns. -/// -/// USAGE_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | -/// |--------------------------|-------------------------| -/// | fk_catalog | utf8 | -/// | fk_db_schema | utf8 | -/// | fk_table | utf8 not null | -/// | fk_column_name | utf8 not null | -/// -/// This AdbcConnection must outlive the returned ArrowArrayStream. -/// -/// \param[in] connection The database connection. -/// \param[in] depth The level of nesting to display. If 0, display -/// all levels. If 1, display only catalogs (i.e. catalog_schemas -/// will be null). If 2, display only catalogs and schemas -/// (i.e. db_schema_tables will be null), and so on. -/// \param[in] catalog Only show tables in the given catalog. If NULL, -/// do not filter by catalog. If an empty string, only show tables -/// without a catalog. May be a search pattern (see section -/// documentation). -/// \param[in] db_schema Only show tables in the given database schema. If -/// NULL, do not filter by database schema. If an empty string, only show -/// tables without a database schema. May be a search pattern (see section -/// documentation). -/// \param[in] table_name Only show tables with the given name. If NULL, do not -/// filter by name. May be a search pattern (see section documentation). -/// \param[in] table_type Only show tables matching one of the given table -/// types. If NULL, show tables of any type. Valid table types can be fetched -/// from GetTableTypes. Terminate the list with a NULL entry. -/// \param[in] column_name Only show columns with the given name. If -/// NULL, do not filter by name. May be a search pattern (see -/// section documentation). -/// \param[out] out The result set. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection* connection, int depth, - const char* catalog, const char* db_schema, - const char* table_name, const char** table_type, - const char* column_name, - struct ArrowArrayStream* out, - struct AdbcError* error); - -/// \brief Get a string option of the connection. -/// -/// This must always be thread-safe (other operations are not), though -/// given the semantics here, it is not recommended to call GetOption -/// concurrently with itself. -/// -/// length must be provided and must be the size of the buffer pointed -/// to by value. If there is sufficient space, the driver will copy -/// the option value (including the null terminator) to buffer and set -/// length to the size of the actual value. If the buffer is too -/// small, no data will be written and length will be set to the -/// required length. -/// -/// In other words: -/// -/// - If output length <= input length, value will contain a value -/// with length bytes. -/// - If output length > input length, nothing has been written to -/// value. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[in,out] length The length of value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetOption(struct AdbcConnection* connection, const char* key, - char* value, size_t* length, - struct AdbcError* error); - -/// \brief Get a bytestring option of the connection. -/// -/// This must always be thread-safe (other operations are not), though -/// given the semantics here, it is not recommended to call -/// GetOptionBytes concurrently with itself. -/// -/// length must be provided and must be the size of the buffer pointed -/// to by value. If there is sufficient space, the driver will copy -/// the option value to buffer and set length to the size of the -/// actual value. If the buffer is too small, no data will be written -/// and length will be set to the required length. -/// -/// In other words: -/// -/// - If output length <= input length, value will contain a value -/// with length bytes. -/// - If output length > input length, nothing has been written to -/// value. -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The connection. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[in,out] length The option value length. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetOptionBytes(struct AdbcConnection* connection, - const char* key, uint8_t* value, - size_t* length, struct AdbcError* error); - -/// \brief Get an integer option of the connection. -/// -/// This must always be thread-safe (other operations are not). -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetOptionInt(struct AdbcConnection* connection, - const char* key, int64_t* value, - struct AdbcError* error); - -/// \brief Get a double option of the connection. -/// -/// This must always be thread-safe (other operations are not). -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetOptionDouble(struct AdbcConnection* connection, - const char* key, double* value, - struct AdbcError* error); - -/// \brief Get statistics about the data distribution of table(s). -/// -/// The result is an Arrow dataset with the following schema: -/// -/// | Field Name | Field Type | -/// |--------------------------|----------------------------------| -/// | catalog_name | utf8 | -/// | catalog_db_schemas | list not null | -/// -/// DB_SCHEMA_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | -/// |--------------------------|----------------------------------| -/// | db_schema_name | utf8 | -/// | db_schema_statistics | list not null | -/// -/// STATISTICS_SCHEMA is a Struct with fields: -/// -/// | Field Name | Field Type | Comments | -/// |--------------------------|----------------------------------| -------- | -/// | table_name | utf8 not null | | -/// | column_name | utf8 | (1) | -/// | statistic_key | int16 not null | (2) | -/// | statistic_value | VALUE_SCHEMA not null | | -/// | statistic_is_approximate | bool not null | (3) | -/// -/// 1. If null, then the statistic applies to the entire table. -/// 2. A dictionary-encoded statistic name (although we do not use the Arrow -/// dictionary type). Values in [0, 1024) are reserved for ADBC. Other -/// values are for implementation-specific statistics. For the definitions -/// of predefined statistic types, see \ref adbc-table-statistics. To get -/// driver-specific statistic names, use AdbcConnectionGetStatisticNames. -/// 3. If true, then the value is approximate or best-effort. -/// -/// VALUE_SCHEMA is a dense union with members: -/// -/// | Field Name | Field Type | -/// |--------------------------|----------------------------------| -/// | int64 | int64 | -/// | uint64 | uint64 | -/// | float64 | float64 | -/// | binary | binary | -/// -/// This AdbcConnection must outlive the returned ArrowArrayStream. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[in] catalog The catalog (or nullptr). May be a search -/// pattern (see section documentation). -/// \param[in] db_schema The database schema (or nullptr). May be a -/// search pattern (see section documentation). -/// \param[in] table_name The table name (or nullptr). May be a -/// search pattern (see section documentation). -/// \param[in] approximate If zero, request exact values of -/// statistics, else allow for best-effort, approximate, or cached -/// values. The database may return approximate values regardless, -/// as indicated in the result. Requesting exact values may be -/// expensive or unsupported. -/// \param[out] out The result set. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetStatistics(struct AdbcConnection* connection, - const char* catalog, const char* db_schema, - const char* table_name, char approximate, - struct ArrowArrayStream* out, - struct AdbcError* error); - -/// \brief Get the names of statistics specific to this driver. -/// -/// The result is an Arrow dataset with the following schema: -/// -/// Field Name | Field Type -/// ---------------|---------------- -/// statistic_name | utf8 not null -/// statistic_key | int16 not null -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] connection The database connection. -/// \param[out] out The result set. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetStatisticNames(struct AdbcConnection* connection, - struct ArrowArrayStream* out, - struct AdbcError* error); - -/// \brief Get the Arrow schema of a table. -/// -/// \param[in] connection The database connection. -/// \param[in] catalog The catalog (or nullptr if not applicable). -/// \param[in] db_schema The database schema (or nullptr if not applicable). -/// \param[in] table_name The table name. -/// \param[out] schema The table schema. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection* connection, - const char* catalog, const char* db_schema, - const char* table_name, - struct ArrowSchema* schema, - struct AdbcError* error); - -/// \brief Get a list of table types in the database. -/// -/// The result is an Arrow dataset with the following schema: -/// -/// Field Name | Field Type -/// ---------------|-------------- -/// table_type | utf8 not null -/// -/// This AdbcConnection must outlive the returned ArrowArrayStream. -/// -/// \param[in] connection The database connection. -/// \param[out] out The result set. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection* connection, - struct ArrowArrayStream* out, - struct AdbcError* error); - -/// @} - -/// \defgroup adbc-connection-partition Partitioned Results -/// Some databases may internally partition the results. These -/// partitions are exposed to clients who may wish to integrate them -/// with a threaded or distributed execution model, where partitions -/// can be divided among threads or machines for processing. -/// -/// Drivers are not required to support partitioning. -/// -/// Partitions are not ordered. If the result set is sorted, -/// implementations should return a single partition. -/// -/// @{ - -/// \brief Construct a statement for a partition of a query. The -/// results can then be read independently. -/// -/// A partition can be retrieved from AdbcPartitions. -/// -/// This AdbcConnection must outlive the returned ArrowArrayStream. -/// -/// \param[in] connection The connection to use. This does not have -/// to be the same connection that the partition was created on. -/// \param[in] serialized_partition The partition descriptor. -/// \param[in] serialized_length The partition descriptor length. -/// \param[out] out The result set. -/// \param[out] error Error details, if an error occurs. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionReadPartition(struct AdbcConnection* connection, - const uint8_t* serialized_partition, - size_t serialized_length, - struct ArrowArrayStream* out, - struct AdbcError* error); - -/// @} - -/// \defgroup adbc-connection-transaction Transaction Semantics -/// -/// Connections start out in auto-commit mode by default (if -/// applicable for the given vendor). Use AdbcConnectionSetOption and -/// ADBC_CONNECTION_OPTION_AUTO_COMMIT to change this. -/// -/// @{ - -/// \brief Commit any pending transactions. Only used if autocommit is -/// disabled. -/// -/// Behavior is undefined if this is mixed with SQL transaction -/// statements. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionCommit(struct AdbcConnection* connection, - struct AdbcError* error); - -/// \brief Roll back any pending transactions. Only used if autocommit -/// is disabled. -/// -/// Behavior is undefined if this is mixed with SQL transaction -/// statements. -ADBC_EXPORT -AdbcStatusCode AdbcConnectionRollback(struct AdbcConnection* connection, - struct AdbcError* error); - -/// @} - -/// @} - -/// \addtogroup adbc-statement -/// @{ - -/// \brief Create a new statement for a given connection. -/// -/// Callers pass in a zero-initialized AdbcStatement. -/// -/// Drivers should allocate their internal data structure and set the private_data -/// field to point to the newly allocated struct. This struct should be released -/// when AdbcStatementRelease is called. -ADBC_EXPORT -AdbcStatusCode AdbcStatementNew(struct AdbcConnection* connection, - struct AdbcStatement* statement, struct AdbcError* error); - -/// \brief Destroy a statement. -/// \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 and get the results. -/// -/// This invalidates any prior result sets. This AdbcStatement must -/// outlive the returned ArrowArrayStream. -/// -/// Since ADBC 1.1.0: releasing the returned ArrowArrayStream without -/// consuming it fully is equivalent to calling AdbcStatementCancel. -/// -/// \param[in] statement The statement to execute. -/// \param[out] out The results. Pass NULL if the client does not -/// expect a result set. -/// \param[out] rows_affected The number of rows affected if known, -/// else -1. Pass NULL if the client does not want this information. -/// \param[out] error An optional location to return an error -/// message if necessary. -ADBC_EXPORT -AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, - struct ArrowArrayStream* out, - int64_t* rows_affected, struct AdbcError* error); - -/// \brief Get the schema of the result set of a query without -/// executing it. -/// -/// This invalidates any prior result sets. -/// -/// Depending on the driver, this may require first executing -/// AdbcStatementPrepare. -/// -/// \since ADBC API revision 1.1.0 -/// -/// \param[in] statement The statement to execute. -/// \param[out] schema The result schema. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver does not support this. -ADBC_EXPORT -AdbcStatusCode AdbcStatementExecuteSchema(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcError* error); - -/// \brief Turn this statement into a prepared statement to be -/// executed multiple times. -/// -/// This invalidates any prior result sets. -ADBC_EXPORT -AdbcStatusCode AdbcStatementPrepare(struct AdbcStatement* statement, - struct AdbcError* error); - -/// \defgroup adbc-statement-sql SQL Semantics -/// Functions for executing SQL queries, or querying SQL-related -/// metadata. Drivers are not required to support both SQL and -/// Substrait semantics. If they do, it may be via converting -/// between representations internally. -/// @{ - -/// \brief Set the SQL query to execute. -/// -/// The query can then be executed with AdbcStatementExecute. For -/// queries expected to be executed repeatedly, AdbcStatementPrepare -/// the statement first. -/// -/// \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); - -/// @} - -/// \defgroup adbc-statement-substrait Substrait Semantics -/// Functions for executing Substrait plans, or querying -/// Substrait-related metadata. Drivers are not required to support -/// both SQL and Substrait semantics. If they do, it may be via -/// converting between representations internally. -/// @{ - -/// \brief Set the Substrait plan to execute. -/// -/// The query can then be executed with AdbcStatementExecute. For -/// queries expected to be executed repeatedly, AdbcStatementPrepare -/// the statement first. -/// -/// \param[in] statement The 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); - -/// @} - -/// \brief Bind Arrow data. This can be used for bulk inserts or -/// prepared statements. -/// -/// \param[in] statement The statement to bind to. -/// \param[in] values The values to bind. The driver will call the -/// release callback itself, although it may not do this until the -/// statement is released. -/// \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); - -/// \brief Bind Arrow data. This can be used for bulk inserts or -/// prepared statements. -/// \param[in] statement The statement to bind to. -/// \param[in] stream The values to bind. The driver will call the -/// release callback itself, although it may not do this until the -/// 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* stream, - struct AdbcError* error); - -/// \brief Cancel execution of an in-progress query. -/// -/// This can be called during AdbcStatementExecuteQuery (or similar), -/// or while consuming an ArrowArrayStream returned from such. -/// Calling this function should make the other functions return -/// ADBC_STATUS_CANCELLED (from ADBC functions) or ECANCELED (from -/// methods of ArrowArrayStream). (It is not guaranteed to, for -/// instance, the result set may be buffered in memory already.) -/// -/// This must always be thread-safe (other operations are not). It is -/// not necessarily signal-safe. -/// -/// \since ADBC API revision 1.1.0 -/// -/// \param[in] statement The statement to cancel. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// -/// \return ADBC_STATUS_INVALID_STATE if there is no query to cancel. -/// \return ADBC_STATUS_UNKNOWN if the query could not be cancelled. -ADBC_EXPORT -AdbcStatusCode AdbcStatementCancel(struct AdbcStatement* statement, - struct AdbcError* error); - -/// \brief Get a string option of the statement. -/// -/// This must always be thread-safe (other operations are not), though -/// given the semantics here, it is not recommended to call GetOption -/// concurrently with itself. -/// -/// length must be provided and must be the size of the buffer pointed -/// to by value. If there is sufficient space, the driver will copy -/// the option value (including the null terminator) to buffer and set -/// length to the size of the actual value. If the buffer is too -/// small, no data will be written and length will be set to the -/// required length. -/// -/// In other words: -/// -/// - If output length <= input length, value will contain a value -/// with length bytes. -/// - If output length > input length, nothing has been written to -/// value. -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[in,out] length The length of value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcStatementGetOption(struct AdbcStatement* statement, const char* key, - char* value, size_t* length, - struct AdbcError* error); - -/// \brief Get a bytestring option of the statement. -/// -/// This must always be thread-safe (other operations are not), though -/// given the semantics here, it is not recommended to call -/// GetOptionBytes concurrently with itself. -/// -/// length must be provided and must be the size of the buffer pointed -/// to by value. If there is sufficient space, the driver will copy -/// the option value to buffer and set length to the size of the -/// actual value. If the buffer is too small, no data will be written -/// and length will be set to the required length. -/// -/// In other words: -/// -/// - If output length <= input length, value will contain a value -/// with length bytes. -/// - If output length > input length, nothing has been written to -/// value. -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[in,out] length The option value length. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcStatementGetOptionBytes(struct AdbcStatement* statement, - const char* key, uint8_t* value, - size_t* length, struct AdbcError* error); - -/// \brief Get an integer option of the statement. -/// -/// This must always be thread-safe (other operations are not). -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcStatementGetOptionInt(struct AdbcStatement* statement, const char* key, - int64_t* value, struct AdbcError* error); - -/// \brief Get a double option of the statement. -/// -/// This must always be thread-safe (other operations are not). -/// -/// For standard options, drivers must always support getting the -/// option value (if they support getting option values at all) via -/// the type specified in the option. (For example, an option set via -/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers -/// may also support getting a converted option value via other -/// getters if needed. (For example, getting the string -/// representation of a double option.) -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to get. -/// \param[out] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcStatementGetOptionDouble(struct AdbcStatement* statement, - const char* key, double* value, - struct AdbcError* error); - -/// \brief Get the schema for bound parameters. -/// -/// This retrieves an Arrow schema describing the number, names, and -/// types of the parameters in a parameterized statement. The fields -/// of the schema should be in order of the ordinal position of the -/// parameters; named parameters should appear only once. -/// -/// If the parameter does not have a name, or the name cannot be -/// determined, the name of the corresponding field in the schema will -/// be an empty string. If the type cannot be determined, the type of -/// the corresponding field will be NA (NullType). -/// -/// This should be called after AdbcStatementPrepare. -/// -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the schema cannot be determined. -ADBC_EXPORT -AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcError* error); - -/// \brief Set a string option on a statement. -/// \param[in] statement The statement. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized. -ADBC_EXPORT -AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const char* key, - const char* value, struct AdbcError* error); - -/// \brief Set a bytestring option on a statement. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[in] length The option value length. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcStatementSetOptionBytes(struct AdbcStatement* statement, - const char* key, const uint8_t* value, - size_t length, struct AdbcError* error); - -/// \brief Set an integer option on a statement. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcStatementSetOptionInt(struct AdbcStatement* statement, const char* key, - int64_t value, struct AdbcError* error); - -/// \brief Set a double option on a statement. -/// -/// \since ADBC API revision 1.1.0 -/// \param[in] statement The statement. -/// \param[in] key The option to set. -/// \param[in] value The option value. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized -ADBC_EXPORT -AdbcStatusCode AdbcStatementSetOptionDouble(struct AdbcStatement* statement, - const char* key, double value, - struct AdbcError* error); - -/// \addtogroup adbc-statement-partition -/// @{ - -/// \brief Execute a statement and get the results as a partitioned -/// result set. -/// -/// \param[in] statement The statement to execute. -/// \param[out] schema The schema of the result set. -/// \param[out] partitions The result partitions. -/// \param[out] rows_affected The number of rows affected if known, -/// else -1. Pass NULL if the client does not want this information. -/// \param[out] error An optional location to return an error -/// message if necessary. -/// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver does not support -/// partitioned results -ADBC_EXPORT -AdbcStatusCode AdbcStatementExecutePartitions(struct AdbcStatement* statement, - struct ArrowSchema* schema, - struct AdbcPartitions* partitions, - int64_t* rows_affected, - struct AdbcError* error); - -/// @} - -/// @} - -/// \addtogroup adbc-driver -/// @{ - -/// \brief Common entry point for drivers via the driver manager -/// (which uses dlopen(3)/LoadLibrary). The driver manager is told -/// to load a library and call a function of this type to load the -/// driver. -/// -/// Although drivers may choose any name for this function, the -/// recommended name is "AdbcDriverInit", or a name derived from the -/// name of the driver's shared library as follows: remove the 'lib' -/// prefix (on Unix systems) and all file extensions, then PascalCase -/// the driver name, append Init, and prepend Adbc (if not already -/// there). For example: -/// -/// - libadbc_driver_sqlite.so.2.0.0 -> AdbcDriverSqliteInit -/// - adbc_driver_sqlite.dll -> AdbcDriverSqliteInit -/// - proprietary_driver.dll -> AdbcProprietaryDriverInit -/// -/// \param[in] version The ADBC revision to attempt to initialize (see -/// ADBC_VERSION_1_0_0). -/// \param[out] driver The table of function pointers to -/// initialize. Should be a pointer to the appropriate struct for -/// the given version (see the documentation for the version). -/// \param[out] error An optional location to return an error message -/// if necessary. -/// \return ADBC_STATUS_OK if the driver was initialized, or -/// ADBC_STATUS_NOT_IMPLEMENTED if the version is not supported. In -/// that case, clients may retry with a different version. -typedef AdbcStatusCode (*AdbcDriverInitFunc)(int version, void* driver, - struct AdbcError* error); - -/// @} - -#endif // ADBC - -#ifdef __cplusplus -} -#endif diff --git a/go/adbc/drivermgr/arrow-adbc/adbc_driver_manager.h b/go/adbc/drivermgr/arrow-adbc/adbc_driver_manager.h deleted file mode 100644 index cf968ffdb4..0000000000 --- a/go/adbc/drivermgr/arrow-adbc/adbc_driver_manager.h +++ /dev/null @@ -1,182 +0,0 @@ -// 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. - -/// \file arrow-adbc/adbc_driver_manager.h ADBC Driver Manager -/// -/// A helper library to dynamically load and use multiple ADBC drivers in the -/// same process. - -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ADBC_DRIVER_MANAGER_H -#define ADBC_DRIVER_MANAGER_H - -typedef uint32_t AdbcLoadFlags; - -#define ADBC_LOAD_FLAG_SEARCH_ENV 1 -#define ADBC_LOAD_FLAG_SEARCH_USER 2 -#define ADBC_LOAD_FLAG_SEARCH_SYSTEM 4 -#define ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS 8 - -#define ADBC_LOAD_FLAG_DEFAULT \ - (ADBC_LOAD_FLAG_SEARCH_ENV | ADBC_LOAD_FLAG_SEARCH_USER | \ - ADBC_LOAD_FLAG_SEARCH_SYSTEM | ADBC_LOAD_FLAG_ALLOW_RELATIVE_PATHS) - -/// \brief Common entry point for drivers via the driver manager. -/// -/// The driver manager can fill in default implementations of some -/// ADBC functions for drivers. Drivers must implement a minimum level -/// of functionality for this to be possible, however, and some -/// functions must be implemented by the driver. -/// -/// \param[in] driver_name An identifier for the driver (e.g. a path to a -/// shared library on Linux). -/// \param[in] entrypoint An identifier for the entrypoint (e.g. the symbol to -/// call for AdbcDriverInitFunc on Linux). If not provided, search for an -/// entrypoint based on the driver name. -/// \param[in] version The ADBC revision to attempt to initialize. -/// \param[out] driver The table of function pointers to initialize. -/// \param[out] error An optional location to return an error message -/// if necessary. -ADBC_EXPORT -AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, - int version, void* driver, struct AdbcError* error); - -/// \brief Common entry point to search for and load a driver or manifest. -/// -/// The driver manager can fill in default implementations of some ADBC functions -/// for drivers. Drivers must implement a minimum level of functionality for this -/// to be possible, however, and some functions must be implemented by the driver. -/// -/// This function is different from AdbcLoadDriver in that it also accepts the name -/// of a driver manifest file, and allows specifying options to control what -/// directories it will search through. The behavior is as follows: -/// -/// If the passed in driver_name is an absolute path: -/// - If the path has a `.toml` extension, it will attempt to parse the manifest and load -/// the driver specified within it. Erroring if this fails. -/// - If the path has an extension other than `.toml`, it will attempt to load the path as -/// a shared library. Erroring if this fails. -/// -/// If the passed in driver_name does not have an extension and is not an absolute path: -/// - The load_options parameter will control whether the driver manager will search the -/// environment variable ADBC_DRIVER_PATH and (if built or installed with conda) the -/// conda environment, the user-level configuration, and/or the system-level -/// configuration for either a manifest file or a shared library. -/// - For each path to be searched, it will first look for /.toml. If -/// that file exists, it will attempt to parse the manifest and load the driver -/// specified within it, erroring if this fails. -/// - If the manifest file does not exist, it will then look for -/// /. -/// where is one of the following: `.so`, `.dll`, `.dylib`. If it can load -/// that shared library, then success is returned. Otherwise it moves to the next -/// directory until the search is either successful, or all directories have been -/// searched. -/// -/// \param[in] driver_name An identifier for the driver (e.g. a path to a -/// shared library on Linux or the basename of a manifest file). -/// \param[in] entrypoint An identifier for the entrypoint (e.g. the symbol to -/// call for AdbcDriverInitFunc on Linux). If not provided, search for an -/// entrypoint based on the driver name. -/// \param[in] version The ADBC revision to attempt to initialize. -/// \param[in] load_options bit mask of AdbcLoadFlags to control the directories searched -/// \param[in] additional_search_path_list A list of additional paths to search for -/// delimited by the OS specific path list separator. -/// \param[out] driver The table of function pointers to initialize -/// \param[out] error An optional location to return an error message -ADBC_EXPORT -AdbcStatusCode AdbcFindLoadDriver(const char* driver_name, const char* entrypoint, - const int version, const AdbcLoadFlags load_options, - const char* additional_search_path_list, void* driver, - struct AdbcError* error); - -/// \brief Common entry point for drivers via the driver manager. -/// -/// The driver manager can fill in default implementations of some -/// ADBC functions for drivers. Drivers must implement a minimum level -/// of functionality for this to be possible, however, and some -/// functions must be implemented by the driver. -/// -/// \param[in] init_func The entrypoint to call. -/// \param[in] version The ADBC revision to attempt to initialize. -/// \param[out] driver The table of function pointers to initialize. -/// \param[out] error An optional location to return an error message -/// if necessary. -ADBC_EXPORT -AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int version, - void* driver, struct AdbcError* error); - -/// \brief Set the AdbcDriverInitFunc to use. -/// -/// This is an extension to the ADBC API. The driver manager shims -/// the AdbcDatabase* functions to allow you to specify the -/// driver/entrypoint dynamically. This function lets you set the -/// entrypoint explicitly, for applications that can dynamically -/// load drivers on their own. -ADBC_EXPORT -AdbcStatusCode AdbcDriverManagerDatabaseSetInitFunc(struct AdbcDatabase* database, - AdbcDriverInitFunc init_func, - struct AdbcError* error); - -/// \brief Set the load flags for the driver manager. -/// -/// This is an extension to the ADBC API. The driver manager shims -/// the AdbcDatabase* functions to allow you to specify the -/// driver/entrypoint dynamically. This function lets you set the -/// load flags explicitly, for applications that can dynamically -/// load drivers on their own. -/// -/// If this function isn't called, the default load flags are just to -/// allow relative paths, disallowing the lookups of manifests. -ADBC_EXPORT -AdbcStatusCode AdbcDriverManagerDatabaseSetLoadFlags(struct AdbcDatabase* database, - AdbcLoadFlags flags, - struct AdbcError* error); - -/// \brief Set an additional manifest search path list for the driver manager. -/// -/// This is an extension to the ADBC API. The driver manager shims -/// the AdbcDatabase* functions to allow you to specify the -/// driver/entrypoint dynamically. This function lets you explicitly -/// set a path list at runtime for additional paths to search when -/// looking for a driver manifest. While users can add additional -/// paths via the ADBC_DRIVER_PATH environment variable, this allows -/// an application to specify search paths at runtime which are not tied -/// to the load flags. -/// -/// Calling this function with NULL as the `path_list` will clear any -/// previously set additional search paths. -ADBC_EXPORT -AdbcStatusCode AdbcDriverManagerDatabaseSetAdditionalSearchPathList( - struct AdbcDatabase* database, const char* path_list, 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 - -#ifdef __cplusplus -} -#endif diff --git a/go/adbc/drivermgr/current_arch.h b/go/adbc/drivermgr/current_arch.h deleted file mode 100644 index fc7167c205..0000000000 --- a/go/adbc/drivermgr/current_arch.h +++ /dev/null @@ -1,139 +0,0 @@ -// 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. - -#pragma once - -#include - -#if defined(_WIN32) -#define ADBC_LITTLE_ENDIAN 1 -#else -#if defined(__APPLE__) || defined(__FreeBSD__) -#include -#elif defined(sun) || defined(__sun) -#include -#elif !defined(_AIX) -#include -#endif -#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) -#define ADBC_LITTLE_ENDIAN 1 -#else -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define ADBC_LITTLE_ENDIAN 1 -#else -#define ADBC_LITTLE_ENDIAN 0 -#endif -#endif -#endif - -namespace adbc { - -const std::string& CurrentArch() { -#if defined(_WIN32) - static const std::string platform = "windows"; -#elif defined(__APPLE__) - static const std::string platform = "macos"; -#elif defined(__FreeBSD__) - static const std::string platform = "freebsd"; -#elif defined(__OpenBSD__) - static const std::string platform = "openbsd"; -#elif defined(__linux__) - static const std::string platform = "linux"; -#else - static const std::string platform = "unknown"; -#endif - -#if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64) - static const std::string arch = "amd64"; -#elif defined(__aarch64__) || defined(_M_ARM64) || defined(__ARM_ARCH_ISA_A64) -#ifdef ADBC_LITTLE_ENDIAN - static const std::string arch = "arm64"; -#else - static const std::string arch = "arm64be"; -#endif -#elif defined(__i386__) || defined(_M_IX86) || defined(_M_X86) - static const std::string arch = "x86"; -#elif defined(__arm__) || defined(_M_ARM) -#ifdef ADBC_LITTLE_ENDIAN - static const std::string arch = "arm"; -#else - static const std::string arch = "armbe"; -#endif -#elif defined(__riscv) || defined(_M_RISCV) -#if defined(__riscv_xlen) && __riscv_xlen == 64 - static const std::string arch = "riscv64"; -#else - static const std::string arch = "riscv"; -#endif -#elif defined(__ppc64__) || defined(__powerpc64__) -#ifdef ADBC_LITTLE_ENDIAN - static const std::string arch = "powerpc64le"; -#else - static const std::string arch = "powerpc64"; -#endif -#elif defined(__powerpc__) || defined(__ppc__) || defined(_M_PPC) - static const std::string arch = "powerpc"; -#elif defined(__s390x__) || defined(_M_S390) - static const std::string arch = "s390x"; -#elif defined(__sparc__) || defined(__sparc) -#if defined(_LP64) || defined(__LP64__) - static const std::string arch = "sparc64"; -#else - static const std::string arch = "sparc"; -#endif -#elif defined(__wasm32__) - static const std::string arch = "wasm32"; -#elif defined(__wasm64__) - static const std::string arch = "wasm64"; -#else - static const std::string arch = "unknown"; -#endif - -// musl doesn't actually define any preprocessor macro for itself -// but apparently it doesn't define __USE_GNU inside of features.h -// while gcc DOES define that. -// see https://stackoverflow.com/questions/58177815/how-to-actually-detect-musl-libc -#if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) -#else -#if !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#include // NOLINT [build/include] -#ifndef __USE_GNU -#define __MUSL__ -#endif -#undef _GNU_SOURCE /* don't contaminate other includes unnecessarily */ -#else -#include // NOLINT [build/include] -#ifndef __USE_GNU -#define __MUSL__ -#endif -#endif -#endif - -#if defined(__MINGW32__) || defined(__MINGW64__) - static const std::string target = "_mingw"; -#elif defined(__MUSL__) - static const std::string target = "_musl"; -#else - static const std::string target = ""; -#endif - - static const std::string result = platform + "_" + arch + target; - return result; -} - -} // namespace adbc diff --git a/go/adbc/drivermgr/functions.go b/go/adbc/drivermgr/functions.go new file mode 100644 index 0000000000..c13dba0719 --- /dev/null +++ b/go/adbc/drivermgr/functions.go @@ -0,0 +1,186 @@ +// 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. + +package drivermgr + +import "github.com/ebitengine/purego" + +// Database functions (ADBC 1.0.0) +var ( + adbcDatabaseNew func(*AdbcDatabase, *AdbcError) AdbcStatusCode + adbcDatabaseInit func(*AdbcDatabase, *AdbcError) AdbcStatusCode + adbcDatabaseRelease func(*AdbcDatabase, *AdbcError) AdbcStatusCode + adbcDatabaseSetOption func(*AdbcDatabase, *byte, *byte, *AdbcError) AdbcStatusCode +) + +// Database functions (ADBC 1.1.0) +var ( + adbcDatabaseGetOption func(*AdbcDatabase, *byte, *byte, *uintptr, *AdbcError) AdbcStatusCode + adbcDatabaseGetOptionBytes func(*AdbcDatabase, *byte, *byte, *uintptr, *AdbcError) AdbcStatusCode + adbcDatabaseGetOptionDouble func(*AdbcDatabase, *byte, *float64, *AdbcError) AdbcStatusCode + adbcDatabaseGetOptionInt func(*AdbcDatabase, *byte, *int64, *AdbcError) AdbcStatusCode + adbcDatabaseSetOptionBytes func(*AdbcDatabase, *byte, *byte, uintptr, *AdbcError) AdbcStatusCode + adbcDatabaseSetOptionDouble func(*AdbcDatabase, *byte, float64, *AdbcError) AdbcStatusCode + adbcDatabaseSetOptionInt func(*AdbcDatabase, *byte, int64, *AdbcError) AdbcStatusCode +) + +// Driver Manager specific functions +var ( + adbcDriverManagerDatabaseSetLoadFlags func(*AdbcDatabase, AdbcLoadFlags, *AdbcError) AdbcStatusCode +) + +// Connection functions (ADBC 1.0.0) +var ( + adbcConnectionNew func(*AdbcConnection, *AdbcError) AdbcStatusCode + adbcConnectionInit func(*AdbcConnection, *AdbcDatabase, *AdbcError) AdbcStatusCode + adbcConnectionRelease func(*AdbcConnection, *AdbcError) AdbcStatusCode + adbcConnectionSetOption func(*AdbcConnection, *byte, *byte, *AdbcError) AdbcStatusCode + adbcConnectionGetInfo func(*AdbcConnection, *uint32, uintptr, *ArrowArrayStream, *AdbcError) AdbcStatusCode + adbcConnectionGetObjects func(*AdbcConnection, int32, *byte, *byte, *byte, **byte, *byte, *ArrowArrayStream, *AdbcError) AdbcStatusCode + adbcConnectionGetTableSchema func(*AdbcConnection, *byte, *byte, *byte, *ArrowSchema, *AdbcError) AdbcStatusCode + adbcConnectionGetTableTypes func(*AdbcConnection, *ArrowArrayStream, *AdbcError) AdbcStatusCode + adbcConnectionCommit func(*AdbcConnection, *AdbcError) AdbcStatusCode + adbcConnectionRollback func(*AdbcConnection, *AdbcError) AdbcStatusCode + adbcConnectionReadPartition func(*AdbcConnection, *byte, uintptr, *ArrowArrayStream, *AdbcError) AdbcStatusCode +) + +// Connection functions (ADBC 1.1.0) +var ( + adbcConnectionCancel func(*AdbcConnection, *AdbcError) AdbcStatusCode + adbcConnectionGetOption func(*AdbcConnection, *byte, *byte, *uintptr, *AdbcError) AdbcStatusCode + adbcConnectionGetOptionBytes func(*AdbcConnection, *byte, *byte, *uintptr, *AdbcError) AdbcStatusCode + adbcConnectionGetOptionDouble func(*AdbcConnection, *byte, *float64, *AdbcError) AdbcStatusCode + adbcConnectionGetOptionInt func(*AdbcConnection, *byte, *int64, *AdbcError) AdbcStatusCode + adbcConnectionGetStatistics func(*AdbcConnection, *byte, *byte, *byte, byte, *ArrowArrayStream, *AdbcError) AdbcStatusCode + adbcConnectionGetStatisticNames func(*AdbcConnection, *ArrowArrayStream, *AdbcError) AdbcStatusCode + adbcConnectionSetOptionBytes func(*AdbcConnection, *byte, *byte, uintptr, *AdbcError) AdbcStatusCode + adbcConnectionSetOptionDouble func(*AdbcConnection, *byte, float64, *AdbcError) AdbcStatusCode + adbcConnectionSetOptionInt func(*AdbcConnection, *byte, int64, *AdbcError) AdbcStatusCode +) + +// Statement functions (ADBC 1.0.0) +var ( + adbcStatementNew func(*AdbcConnection, *AdbcStatement, *AdbcError) AdbcStatusCode + adbcStatementRelease func(*AdbcStatement, *AdbcError) AdbcStatusCode + adbcStatementSetOption func(*AdbcStatement, *byte, *byte, *AdbcError) AdbcStatusCode + adbcStatementSetSqlQuery func(*AdbcStatement, *byte, *AdbcError) AdbcStatusCode + adbcStatementSetSubstraitPlan func(*AdbcStatement, *byte, uintptr, *AdbcError) AdbcStatusCode + adbcStatementPrepare func(*AdbcStatement, *AdbcError) AdbcStatusCode + adbcStatementExecuteQuery func(*AdbcStatement, *ArrowArrayStream, *int64, *AdbcError) AdbcStatusCode + adbcStatementExecutePartitions func(*AdbcStatement, *ArrowSchema, *AdbcPartitions, *int64, *AdbcError) AdbcStatusCode + adbcStatementBind func(*AdbcStatement, *ArrowArray, *ArrowSchema, *AdbcError) AdbcStatusCode + adbcStatementBindStream func(*AdbcStatement, *ArrowArrayStream, *AdbcError) AdbcStatusCode + adbcStatementGetParameterSchema func(*AdbcStatement, *ArrowSchema, *AdbcError) AdbcStatusCode +) + +// Statement functions (ADBC 1.1.0) +var ( + adbcStatementCancel func(*AdbcStatement, *AdbcError) AdbcStatusCode + adbcStatementExecuteSchema func(*AdbcStatement, *ArrowSchema, *AdbcError) AdbcStatusCode + adbcStatementGetOption func(*AdbcStatement, *byte, *byte, *uintptr, *AdbcError) AdbcStatusCode + adbcStatementGetOptionBytes func(*AdbcStatement, *byte, *byte, *uintptr, *AdbcError) AdbcStatusCode + adbcStatementGetOptionDouble func(*AdbcStatement, *byte, *float64, *AdbcError) AdbcStatusCode + adbcStatementGetOptionInt func(*AdbcStatement, *byte, *int64, *AdbcError) AdbcStatusCode + adbcStatementSetOptionBytes func(*AdbcStatement, *byte, *byte, uintptr, *AdbcError) AdbcStatusCode + adbcStatementSetOptionDouble func(*AdbcStatement, *byte, float64, *AdbcError) AdbcStatusCode + adbcStatementSetOptionInt func(*AdbcStatement, *byte, int64, *AdbcError) AdbcStatusCode +) + +// Error functions (ADBC 1.1.0) +var ( + adbcErrorGetDetailCount func(*AdbcError) int32 + adbcErrorGetDetail func(*AdbcError, int32) AdbcErrorDetail + adbcErrorFromArrayStream func(*ArrowArrayStream, *AdbcStatusCode) *AdbcError +) + +// registerFunctions registers all ADBC function bindings with purego. +// This is called once during library loading. +func registerFunctions(lib uintptr) error { + // Database functions (ADBC 1.0.0) + purego.RegisterLibFunc(&adbcDatabaseNew, lib, "AdbcDatabaseNew") + purego.RegisterLibFunc(&adbcDatabaseInit, lib, "AdbcDatabaseInit") + purego.RegisterLibFunc(&adbcDatabaseRelease, lib, "AdbcDatabaseRelease") + purego.RegisterLibFunc(&adbcDatabaseSetOption, lib, "AdbcDatabaseSetOption") + + // Database functions (ADBC 1.1.0) + purego.RegisterLibFunc(&adbcDatabaseGetOption, lib, "AdbcDatabaseGetOption") + purego.RegisterLibFunc(&adbcDatabaseGetOptionBytes, lib, "AdbcDatabaseGetOptionBytes") + purego.RegisterLibFunc(&adbcDatabaseGetOptionDouble, lib, "AdbcDatabaseGetOptionDouble") + purego.RegisterLibFunc(&adbcDatabaseGetOptionInt, lib, "AdbcDatabaseGetOptionInt") + purego.RegisterLibFunc(&adbcDatabaseSetOptionBytes, lib, "AdbcDatabaseSetOptionBytes") + purego.RegisterLibFunc(&adbcDatabaseSetOptionDouble, lib, "AdbcDatabaseSetOptionDouble") + purego.RegisterLibFunc(&adbcDatabaseSetOptionInt, lib, "AdbcDatabaseSetOptionInt") + + // Driver Manager extensions + purego.RegisterLibFunc(&adbcDriverManagerDatabaseSetLoadFlags, lib, "AdbcDriverManagerDatabaseSetLoadFlags") + + // Connection functions (ADBC 1.0.0) + purego.RegisterLibFunc(&adbcConnectionNew, lib, "AdbcConnectionNew") + purego.RegisterLibFunc(&adbcConnectionInit, lib, "AdbcConnectionInit") + purego.RegisterLibFunc(&adbcConnectionRelease, lib, "AdbcConnectionRelease") + purego.RegisterLibFunc(&adbcConnectionSetOption, lib, "AdbcConnectionSetOption") + purego.RegisterLibFunc(&adbcConnectionGetInfo, lib, "AdbcConnectionGetInfo") + purego.RegisterLibFunc(&adbcConnectionGetObjects, lib, "AdbcConnectionGetObjects") + purego.RegisterLibFunc(&adbcConnectionGetTableSchema, lib, "AdbcConnectionGetTableSchema") + purego.RegisterLibFunc(&adbcConnectionGetTableTypes, lib, "AdbcConnectionGetTableTypes") + purego.RegisterLibFunc(&adbcConnectionCommit, lib, "AdbcConnectionCommit") + purego.RegisterLibFunc(&adbcConnectionRollback, lib, "AdbcConnectionRollback") + purego.RegisterLibFunc(&adbcConnectionReadPartition, lib, "AdbcConnectionReadPartition") + + // Connection functions (ADBC 1.1.0) + purego.RegisterLibFunc(&adbcConnectionCancel, lib, "AdbcConnectionCancel") + purego.RegisterLibFunc(&adbcConnectionGetOption, lib, "AdbcConnectionGetOption") + purego.RegisterLibFunc(&adbcConnectionGetOptionBytes, lib, "AdbcConnectionGetOptionBytes") + purego.RegisterLibFunc(&adbcConnectionGetOptionDouble, lib, "AdbcConnectionGetOptionDouble") + purego.RegisterLibFunc(&adbcConnectionGetOptionInt, lib, "AdbcConnectionGetOptionInt") + purego.RegisterLibFunc(&adbcConnectionGetStatistics, lib, "AdbcConnectionGetStatistics") + purego.RegisterLibFunc(&adbcConnectionGetStatisticNames, lib, "AdbcConnectionGetStatisticNames") + purego.RegisterLibFunc(&adbcConnectionSetOptionBytes, lib, "AdbcConnectionSetOptionBytes") + purego.RegisterLibFunc(&adbcConnectionSetOptionDouble, lib, "AdbcConnectionSetOptionDouble") + purego.RegisterLibFunc(&adbcConnectionSetOptionInt, lib, "AdbcConnectionSetOptionInt") + + // Statement functions (ADBC 1.0.0) + purego.RegisterLibFunc(&adbcStatementNew, lib, "AdbcStatementNew") + purego.RegisterLibFunc(&adbcStatementRelease, lib, "AdbcStatementRelease") + purego.RegisterLibFunc(&adbcStatementSetOption, lib, "AdbcStatementSetOption") + purego.RegisterLibFunc(&adbcStatementSetSqlQuery, lib, "AdbcStatementSetSqlQuery") + purego.RegisterLibFunc(&adbcStatementSetSubstraitPlan, lib, "AdbcStatementSetSubstraitPlan") + purego.RegisterLibFunc(&adbcStatementPrepare, lib, "AdbcStatementPrepare") + purego.RegisterLibFunc(&adbcStatementExecuteQuery, lib, "AdbcStatementExecuteQuery") + purego.RegisterLibFunc(&adbcStatementExecutePartitions, lib, "AdbcStatementExecutePartitions") + purego.RegisterLibFunc(&adbcStatementBind, lib, "AdbcStatementBind") + purego.RegisterLibFunc(&adbcStatementBindStream, lib, "AdbcStatementBindStream") + purego.RegisterLibFunc(&adbcStatementGetParameterSchema, lib, "AdbcStatementGetParameterSchema") + + // Statement functions (ADBC 1.1.0) + purego.RegisterLibFunc(&adbcStatementCancel, lib, "AdbcStatementCancel") + purego.RegisterLibFunc(&adbcStatementExecuteSchema, lib, "AdbcStatementExecuteSchema") + purego.RegisterLibFunc(&adbcStatementGetOption, lib, "AdbcStatementGetOption") + purego.RegisterLibFunc(&adbcStatementGetOptionBytes, lib, "AdbcStatementGetOptionBytes") + purego.RegisterLibFunc(&adbcStatementGetOptionDouble, lib, "AdbcStatementGetOptionDouble") + purego.RegisterLibFunc(&adbcStatementGetOptionInt, lib, "AdbcStatementGetOptionInt") + purego.RegisterLibFunc(&adbcStatementSetOptionBytes, lib, "AdbcStatementSetOptionBytes") + purego.RegisterLibFunc(&adbcStatementSetOptionDouble, lib, "AdbcStatementSetOptionDouble") + purego.RegisterLibFunc(&adbcStatementSetOptionInt, lib, "AdbcStatementSetOptionInt") + + // Error functions (ADBC 1.1.0) + purego.RegisterLibFunc(&adbcErrorGetDetailCount, lib, "AdbcErrorGetDetailCount") + purego.RegisterLibFunc(&adbcErrorGetDetail, lib, "AdbcErrorGetDetail") + purego.RegisterLibFunc(&adbcErrorFromArrayStream, lib, "AdbcErrorFromArrayStream") + + return nil +} diff --git a/go/adbc/drivermgr/helpers.go b/go/adbc/drivermgr/helpers.go new file mode 100644 index 0000000000..8a37e899c0 --- /dev/null +++ b/go/adbc/drivermgr/helpers.go @@ -0,0 +1,116 @@ +// 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. + +package drivermgr + +import ( + "unsafe" + + "github.com/apache/arrow-adbc/go/adbc" + "github.com/ebitengine/purego" +) + +// goString converts a null-terminated C string to Go string. +func goString(cstr *byte) string { + if cstr == nil { + return "" + } + var length int + for ptr := cstr; *ptr != 0; ptr = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + 1)) { + length++ + } + return string(unsafe.Slice(cstr, length)) +} + +// cString converts a Go string to a null-terminated byte slice. +// The caller is responsible for keeping the returned slice alive. +func cString(s string) *byte { + if s == "" { + return nil + } + b := make([]byte, len(s)+1) + copy(b, s) + b[len(s)] = 0 + return &b[0] +} + +// cStringFree is a no-op since Go manages memory, but kept for clarity. +func cStringFree(_ *byte) { + // Go GC handles this +} + +// toAdbcError converts a C AdbcError to a Go adbc.Error. +func toAdbcError(code AdbcStatusCode, e *AdbcError) error { + if e == nil || e.Release == 0 { + return adbc.Error{ + Code: adbc.Status(code), + Msg: "[drivermgr] unknown error", + } + } + + err := adbc.Error{ + Code: adbc.Status(code), + VendorCode: e.VendorCode, + Msg: goString(e.Message), + } + copy(err.SqlState[:], e.SqlState[:]) + + // Call release callback if present + if e.Release != 0 { + releaseErr(e) + } + + return err +} + +// releaseErr calls the error's release callback via purego. +func releaseErr(e *AdbcError) { + if e.Release == 0 { + return + } + // Call the release function pointer + purego.SyscallN(e.Release, uintptr(unsafe.Pointer(e))) + e.Release = 0 +} + +// allocArrowArray allocates a zeroed ArrowArray. +func allocArrowArray() *ArrowArray { + arr := new(ArrowArray) + *arr = ArrowArray{} // zero initialize + return arr +} + +// allocArrowSchema allocates a zeroed ArrowSchema. +func allocArrowSchema() *ArrowSchema { + schema := new(ArrowSchema) + *schema = ArrowSchema{} // zero initialize + return schema +} + +// allocArrowArrayStream allocates a zeroed ArrowArrayStream. +func allocArrowArrayStream() *ArrowArrayStream { + stream := new(ArrowArrayStream) + *stream = ArrowArrayStream{} // zero initialize + return stream +} + +// allocAdbcError allocates a zeroed AdbcError. +func allocAdbcError() *AdbcError { + e := new(AdbcError) + *e = AdbcError{} // zero initialize + return e +} diff --git a/go/adbc/drivermgr/library.go b/go/adbc/drivermgr/library.go new file mode 100644 index 0000000000..45ec66243e --- /dev/null +++ b/go/adbc/drivermgr/library.go @@ -0,0 +1,68 @@ +// 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. + +package drivermgr + +import ( + "fmt" + "os" + "runtime" + "sync" +) + +var ( + driverManagerLib uintptr + loadOnce sync.Once + loadErr error +) + +// loadDriverManagerLibrary loads the ADBC driver manager shared library. +// It uses sync.Once to ensure the library is only loaded once per process. +// The library path can be overridden via the ADBC_DRIVER_MANAGER_LIB environment variable. +func loadDriverManagerLibrary() (uintptr, error) { + loadOnce.Do(func() { + var libName string + switch runtime.GOOS { + case "darwin": + libName = "libadbc_driver_manager.dylib" + case "linux": + libName = "libadbc_driver_manager.so" + case "windows": + libName = "adbc_driver_manager.dll" + default: + loadErr = fmt.Errorf("unsupported OS: %s", runtime.GOOS) + return + } + + // Allow override via environment variable + if override := os.Getenv("ADBC_DRIVER_MANAGER_LIB"); override != "" { + libName = override + } + + var lib uintptr + lib, loadErr = loadLibrary(libName) + if loadErr != nil { + loadErr = fmt.Errorf("failed to load ADBC driver manager library %q: %w. You can specify the exact path with env var ADBC_DRIVER_MANAGER_LIB", libName, loadErr) + return + } + + driverManagerLib = lib + loadErr = registerFunctions(lib) + }) + + return driverManagerLib, loadErr +} diff --git a/go/adbc/drivermgr/library_unix.go b/go/adbc/drivermgr/library_unix.go new file mode 100644 index 0000000000..43b5e8810f --- /dev/null +++ b/go/adbc/drivermgr/library_unix.go @@ -0,0 +1,27 @@ +// 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. + +//go:build !windows + +package drivermgr + +import "github.com/ebitengine/purego" + +// loadLibrary loads a shared library on Unix-like systems (Linux, macOS, FreeBSD) +func loadLibrary(path string) (uintptr, error) { + return purego.Dlopen(path, purego.RTLD_NOW|purego.RTLD_GLOBAL) +} diff --git a/go/adbc/drivermgr/library_windows.go b/go/adbc/drivermgr/library_windows.go new file mode 100644 index 0000000000..7fa63bf1dd --- /dev/null +++ b/go/adbc/drivermgr/library_windows.go @@ -0,0 +1,31 @@ +// 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. + +//go:build windows + +package drivermgr + +import "syscall" + +// loadLibrary loads a DLL on Windows +func loadLibrary(path string) (uintptr, error) { + handle, err := syscall.LoadLibrary(path) + if err != nil { + return 0, err + } + return uintptr(handle), nil +} diff --git a/go/adbc/drivermgr/types.go b/go/adbc/drivermgr/types.go new file mode 100644 index 0000000000..57b15e7809 --- /dev/null +++ b/go/adbc/drivermgr/types.go @@ -0,0 +1,140 @@ +// 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. + +package drivermgr + +// C-compatible struct definitions for ADBC types. +// These structs must match the C memory layout exactly (same field order, sizes, alignment). + +// Arrow C Data Interface types (from adbc.h) + +// ArrowSchema matches the C ArrowSchema struct layout. +type ArrowSchema struct { + Format *byte // const char* + Name *byte // const char* + Metadata *byte // const char* + Flags int64 // int64_t + NChildren int64 // int64_t + Children **ArrowSchema // struct ArrowSchema** + Dictionary *ArrowSchema // struct ArrowSchema* + Release uintptr // void (*release)(struct ArrowSchema*) + PrivateData uintptr // void* +} + +// ArrowArray matches the C ArrowArray struct layout. +type ArrowArray struct { + Length int64 // int64_t + NullCount int64 // int64_t + Offset int64 // int64_t + NBuffers int64 // int64_t + NChildren int64 // int64_t + Buffers *uintptr // const void** + Children **ArrowArray // struct ArrowArray** + Dictionary *ArrowArray // struct ArrowArray* + Release uintptr // void (*release)(struct ArrowArray*) + PrivateData uintptr // void* +} + +// ArrowArrayStream matches the C ArrowArrayStream struct layout. +type ArrowArrayStream struct { + GetSchema uintptr // int (*get_schema)(struct ArrowArrayStream*, struct ArrowSchema* out) + GetNext uintptr // int (*get_next)(struct ArrowArrayStream*, struct ArrowArray* out) + GetLastError uintptr // const char* (*get_last_error)(struct ArrowArrayStream*) + Release uintptr // void (*release)(struct ArrowArrayStream*) + PrivateData uintptr // void* +} + +// ADBC types (from adbc.h) + +// AdbcError matches the C AdbcError struct layout (ADBC 1.1.0). +type AdbcError struct { + Message *byte // char* + VendorCode int32 // int32_t + SqlState [5]byte // char[5] + _ [3]byte // padding to align Release to pointer boundary + Release uintptr // void (*release)(struct AdbcError*) + PrivateData uintptr // void* (ADBC 1.1.0) + PrivateDriver uintptr // struct AdbcDriver* (ADBC 1.1.0) +} + +// AdbcDatabase matches the C AdbcDatabase struct layout. +type AdbcDatabase struct { + PrivateData uintptr // void* + PrivateDriver uintptr // struct AdbcDriver* +} + +// AdbcConnection matches the C AdbcConnection struct layout. +type AdbcConnection struct { + PrivateData uintptr // void* + PrivateDriver uintptr // struct AdbcDriver* +} + +// AdbcStatement matches the C AdbcStatement struct layout. +type AdbcStatement struct { + PrivateData uintptr // void* + PrivateDriver uintptr // struct AdbcDriver* +} + +// AdbcPartitions matches the C AdbcPartitions struct layout. +type AdbcPartitions struct { + NumPartitions uintptr // size_t + Partitions **byte // const uint8_t** + PartitionLengths *uintptr // const size_t* + PrivateData uintptr // void* + Release uintptr // void (*release)(struct AdbcPartitions*) +} + +// AdbcErrorDetail for extended error info (ADBC 1.1.0). +type AdbcErrorDetail struct { + Key *byte // const char* + Value *byte // const uint8_t* + ValueLength uintptr // size_t +} + +// AdbcStatusCode represents ADBC status codes. +type AdbcStatusCode uint8 + +// Status codes matching ADBC_STATUS_* constants. +const ( + StatusOK AdbcStatusCode = 0 + StatusUnknown AdbcStatusCode = 1 + StatusNotImplemented AdbcStatusCode = 2 + StatusNotFound AdbcStatusCode = 3 + StatusAlreadyExists AdbcStatusCode = 4 + StatusInvalidArgument AdbcStatusCode = 5 + StatusInvalidState AdbcStatusCode = 6 + StatusInvalidData AdbcStatusCode = 7 + StatusIntegrity AdbcStatusCode = 8 + StatusInternal AdbcStatusCode = 9 + StatusIO AdbcStatusCode = 10 + StatusCancelled AdbcStatusCode = 11 + StatusTimeout AdbcStatusCode = 12 + StatusUnauthenticated AdbcStatusCode = 13 + StatusUnauthorized AdbcStatusCode = 14 +) + +// AdbcLoadFlags for driver manager (from adbc_driver_manager.h). +type AdbcLoadFlags uint32 + +// Load flag constants matching ADBC_LOAD_FLAG_* constants. +const ( + LoadFlagSearchEnv AdbcLoadFlags = 1 + LoadFlagSearchUser AdbcLoadFlags = 2 + LoadFlagSearchSystem AdbcLoadFlags = 4 + LoadFlagAllowRelativePaths AdbcLoadFlags = 8 + LoadFlagDefault AdbcLoadFlags = LoadFlagSearchEnv | LoadFlagSearchUser | LoadFlagSearchSystem | LoadFlagAllowRelativePaths +) diff --git a/go/adbc/drivermgr/vendored/toml++/toml.hpp b/go/adbc/drivermgr/vendored/toml++/toml.hpp deleted file mode 100644 index cc188fb72c..0000000000 --- a/go/adbc/drivermgr/vendored/toml++/toml.hpp +++ /dev/null @@ -1,17748 +0,0 @@ -//---------------------------------------------------------------------------------------------------------------------- -// -// toml++ v3.4.0 -// https://github.com/marzer/tomlplusplus -// SPDX-License-Identifier: MIT -// -//---------------------------------------------------------------------------------------------------------------------- -// -// - THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY - -// -// If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this -// file was assembled from a number of smaller files by a python script, and code contributions should not be made -// against it directly. You should instead make your changes in the relevant source file(s). The file names of the files -// that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file. -// -//---------------------------------------------------------------------------------------------------------------------- -// -// TOML Language Specifications: -// latest: https://github.com/toml-lang/toml/blob/master/README.md -// v1.0.0: https://toml.io/en/v1.0.0 -// v0.5.0: https://toml.io/en/v0.5.0 -// changelog: https://github.com/toml-lang/toml/blob/master/CHANGELOG.md -// -//---------------------------------------------------------------------------------------------------------------------- -// -// MIT License -// -// Copyright (c) Mark Gillard -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -// Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//---------------------------------------------------------------------------------------------------------------------- -#ifndef TOMLPLUSPLUS_HPP -#define TOMLPLUSPLUS_HPP - -#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3 -#define TOMLPLUSPLUS_H // guard name used in the legacy toml.h - -//******** impl/preprocessor.hpp ************************************************************************************* - -#ifndef __cplusplus -#error toml++ is a C++ library. -#endif - -#ifndef TOML_CPP -#ifdef _MSVC_LANG -#if _MSVC_LANG > __cplusplus -#define TOML_CPP _MSVC_LANG -#endif -#endif -#ifndef TOML_CPP -#define TOML_CPP __cplusplus -#endif -#if TOML_CPP >= 202900L -#undef TOML_CPP -#define TOML_CPP 29 -#elif TOML_CPP >= 202600L -#undef TOML_CPP -#define TOML_CPP 26 -#elif TOML_CPP >= 202302L -#undef TOML_CPP -#define TOML_CPP 23 -#elif TOML_CPP >= 202002L -#undef TOML_CPP -#define TOML_CPP 20 -#elif TOML_CPP >= 201703L -#undef TOML_CPP -#define TOML_CPP 17 -#elif TOML_CPP >= 201402L -#undef TOML_CPP -#define TOML_CPP 14 -#elif TOML_CPP >= 201103L -#undef TOML_CPP -#define TOML_CPP 11 -#else -#undef TOML_CPP -#define TOML_CPP 0 -#endif -#endif - -#if !TOML_CPP -#error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml -#elif TOML_CPP < 17 -#error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11 -#endif - -#ifndef TOML_MAKE_VERSION -#define TOML_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + ((patch))) -#endif - -#ifndef TOML_INTELLISENSE -#ifdef __INTELLISENSE__ -#define TOML_INTELLISENSE 1 -#else -#define TOML_INTELLISENSE 0 -#endif -#endif - -#ifndef TOML_DOXYGEN -#if defined(DOXYGEN) || defined(__DOXYGEN) || defined(__DOXYGEN__) || defined(__doxygen__) || defined(__POXY__) \ - || defined(__poxy__) -#define TOML_DOXYGEN 1 -#else -#define TOML_DOXYGEN 0 -#endif -#endif - -#ifndef TOML_CLANG -#ifdef __clang__ -#define TOML_CLANG __clang_major__ -#else -#define TOML_CLANG 0 -#endif - -// special handling for apple clang; see: -// - https://github.com/marzer/tomlplusplus/issues/189 -// - https://en.wikipedia.org/wiki/Xcode -// - -// https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time -#if TOML_CLANG && defined(__apple_build_version__) -#undef TOML_CLANG -#define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) -#if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0) -#define TOML_CLANG 16 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0) -#define TOML_CLANG 15 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0) -#define TOML_CLANG 14 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6) -#define TOML_CLANG 13 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0) -#define TOML_CLANG 12 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5) -#define TOML_CLANG 11 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0) -#define TOML_CLANG 10 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3) -#define TOML_CLANG 9 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0) -#define TOML_CLANG 8 -#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1) -#define TOML_CLANG 7 -#else -#define TOML_CLANG 6 // not strictly correct but doesn't matter below this -#endif -#undef TOML_CLANG_VERSION -#endif -#endif - -#ifndef TOML_ICC -#ifdef __INTEL_COMPILER -#define TOML_ICC __INTEL_COMPILER -#ifdef __ICL -#define TOML_ICC_CL TOML_ICC -#else -#define TOML_ICC_CL 0 -#endif -#else -#define TOML_ICC 0 -#define TOML_ICC_CL 0 -#endif -#endif - -#ifndef TOML_MSVC_LIKE -#ifdef _MSC_VER -#define TOML_MSVC_LIKE _MSC_VER -#else -#define TOML_MSVC_LIKE 0 -#endif -#endif - -#ifndef TOML_MSVC -#if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC -#define TOML_MSVC TOML_MSVC_LIKE -#else -#define TOML_MSVC 0 -#endif -#endif - -#ifndef TOML_GCC_LIKE -#ifdef __GNUC__ -#define TOML_GCC_LIKE __GNUC__ -#else -#define TOML_GCC_LIKE 0 -#endif -#endif - -#ifndef TOML_GCC -#if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC -#define TOML_GCC TOML_GCC_LIKE -#else -#define TOML_GCC 0 -#endif -#endif - -#ifndef TOML_CUDA -#if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__) -#define TOML_CUDA 1 -#else -#define TOML_CUDA 0 -#endif -#endif - -#ifndef TOML_ARCH_ITANIUM -#if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) -#define TOML_ARCH_ITANIUM 1 -#define TOML_ARCH_BITNESS 64 -#else -#define TOML_ARCH_ITANIUM 0 -#endif -#endif - -#ifndef TOML_ARCH_AMD64 -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) -#define TOML_ARCH_AMD64 1 -#define TOML_ARCH_BITNESS 64 -#else -#define TOML_ARCH_AMD64 0 -#endif -#endif - -#ifndef TOML_ARCH_X86 -#if defined(__i386__) || defined(_M_IX86) -#define TOML_ARCH_X86 1 -#define TOML_ARCH_BITNESS 32 -#else -#define TOML_ARCH_X86 0 -#endif -#endif - -#ifndef TOML_ARCH_ARM -#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \ - || defined(_M_ARM64EC) -#define TOML_ARCH_ARM32 0 -#define TOML_ARCH_ARM64 1 -#define TOML_ARCH_ARM 1 -#define TOML_ARCH_BITNESS 64 -#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE) -#define TOML_ARCH_ARM32 1 -#define TOML_ARCH_ARM64 0 -#define TOML_ARCH_ARM 1 -#define TOML_ARCH_BITNESS 32 -#else -#define TOML_ARCH_ARM32 0 -#define TOML_ARCH_ARM64 0 -#define TOML_ARCH_ARM 0 -#endif -#endif - -#ifndef TOML_ARCH_BITNESS -#define TOML_ARCH_BITNESS 0 -#endif - -#ifndef TOML_ARCH_X64 -#if TOML_ARCH_BITNESS == 64 -#define TOML_ARCH_X64 1 -#else -#define TOML_ARCH_X64 0 -#endif -#endif - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) -#define TOML_WINDOWS 1 -#else -#define TOML_WINDOWS 0 -#endif - -#ifdef __unix__ -#define TOML_UNIX 1 -#else -#define TOML_UNIX 0 -#endif - -#ifdef __linux__ -#define TOML_LINUX 1 -#else -#define TOML_LINUX 0 -#endif - -// TOML_HAS_INCLUDE -#ifndef TOML_HAS_INCLUDE -#ifdef __has_include -#define TOML_HAS_INCLUDE(header) __has_include(header) -#else -#define TOML_HAS_INCLUDE(header) 0 -#endif -#endif - -// TOML_HAS_BUILTIN -#ifndef TOML_HAS_BUILTIN -#ifdef __has_builtin -#define TOML_HAS_BUILTIN(name) __has_builtin(name) -#else -#define TOML_HAS_BUILTIN(name) 0 -#endif -#endif - -// TOML_HAS_FEATURE -#ifndef TOML_HAS_FEATURE -#ifdef __has_feature -#define TOML_HAS_FEATURE(name) __has_feature(name) -#else -#define TOML_HAS_FEATURE(name) 0 -#endif -#endif - -// TOML_HAS_ATTR -#ifndef TOML_HAS_ATTR -#ifdef __has_attribute -#define TOML_HAS_ATTR(attr) __has_attribute(attr) -#else -#define TOML_HAS_ATTR(attr) 0 -#endif -#endif - -// TOML_HAS_CPP_ATTR -#ifndef TOML_HAS_CPP_ATTR -#ifdef __has_cpp_attribute -#define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr) -#else -#define TOML_HAS_CPP_ATTR(attr) 0 -#endif -#endif - -// TOML_ATTR (gnu attributes) -#ifndef TOML_ATTR -#if TOML_CLANG || TOML_GCC_LIKE -#define TOML_ATTR(...) __attribute__((__VA_ARGS__)) -#else -#define TOML_ATTR(...) -#endif -#endif - -// TOML_DECLSPEC (msvc attributes) -#ifndef TOML_DECLSPEC -#if TOML_MSVC_LIKE -#define TOML_DECLSPEC(...) __declspec(__VA_ARGS__) -#else -#define TOML_DECLSPEC(...) -#endif -#endif - -// TOML_COMPILER_HAS_EXCEPTIONS -#ifndef TOML_COMPILER_HAS_EXCEPTIONS -#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions) -#define TOML_COMPILER_HAS_EXCEPTIONS 1 -#else -#define TOML_COMPILER_HAS_EXCEPTIONS 0 -#endif -#endif - -// TOML_COMPILER_HAS_RTTI -#ifndef TOML_COMPILER_HAS_RTTI -#if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti) -#define TOML_COMPILER_HAS_RTTI 1 -#else -#define TOML_COMPILER_HAS_RTTI 0 -#endif -#endif - -// TOML_CONCAT -#define TOML_CONCAT_1(x, y) x##y -#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y) - -// TOML_MAKE_STRING -#define TOML_MAKE_STRING_1(s) #s -#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s) - -// TOML_PRAGMA_XXXX (compiler-specific pragmas) -#if TOML_CLANG -#define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl)) -#else -#define TOML_PRAGMA_CLANG(decl) -#endif -#if TOML_CLANG >= 8 -#define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl) -#else -#define TOML_PRAGMA_CLANG_GE_8(decl) -#endif -#if TOML_CLANG >= 9 -#define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl) -#else -#define TOML_PRAGMA_CLANG_GE_9(decl) -#endif -#if TOML_CLANG >= 10 -#define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl) -#else -#define TOML_PRAGMA_CLANG_GE_10(decl) -#endif -#if TOML_CLANG >= 11 -#define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl) -#else -#define TOML_PRAGMA_CLANG_GE_11(decl) -#endif -#if TOML_GCC -#define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl)) -#else -#define TOML_PRAGMA_GCC(decl) -#endif -#if TOML_MSVC -#define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__) -#else -#define TOML_PRAGMA_MSVC(...) -#endif -#if TOML_ICC -#define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__) -#else -#define TOML_PRAGMA_ICC(...) -#endif - -// TOML_ALWAYS_INLINE -#ifdef _MSC_VER -#define TOML_ALWAYS_INLINE __forceinline -#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__) -#define TOML_ALWAYS_INLINE \ - TOML_ATTR(__always_inline__) \ - inline -#else -#define TOML_ALWAYS_INLINE inline -#endif - -// TOML_NEVER_INLINE -#ifdef _MSC_VER -#define TOML_NEVER_INLINE TOML_DECLSPEC(noinline) -#elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555 -#define TOML_NEVER_INLINE TOML_ATTR(noinline) -#else -#if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__) -#define TOML_NEVER_INLINE TOML_ATTR(__noinline__) -#endif -#endif -#ifndef TOML_NEVER_INLINE -#define TOML_NEVER_INLINE -#endif - -// MSVC attributes -#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable) -#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases) - -// TOML_TRIVIAL_ABI -#if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__) -#define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__) -#else -#define TOML_TRIVIAL_ABI -#endif - -// TOML_NODISCARD -#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603 -#define TOML_NODISCARD [[nodiscard]] -#elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__) -#define TOML_NODISCARD TOML_ATTR(__warn_unused_result__) -#else -#define TOML_NODISCARD -#endif - -// TOML_NODISCARD_CTOR -#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907 -#define TOML_NODISCARD_CTOR [[nodiscard]] -#else -#define TOML_NODISCARD_CTOR -#endif - -// pure + const -#ifndef TOML_PURE -#ifdef NDEBUG -#define TOML_PURE \ - TOML_DECLSPEC(noalias) \ - TOML_ATTR(pure) -#else -#define TOML_PURE -#endif -#endif -#ifndef TOML_CONST -#ifdef NDEBUG -#define TOML_CONST \ - TOML_DECLSPEC(noalias) \ - TOML_ATTR(const) -#else -#define TOML_CONST -#endif -#endif -#ifndef TOML_INLINE_GETTER -#define TOML_INLINE_GETTER \ - TOML_NODISCARD \ - TOML_ALWAYS_INLINE -#endif -#ifndef TOML_PURE_GETTER -#define TOML_PURE_GETTER \ - TOML_NODISCARD \ - TOML_PURE -#endif -#ifndef TOML_PURE_INLINE_GETTER -#define TOML_PURE_INLINE_GETTER \ - TOML_NODISCARD \ - TOML_ALWAYS_INLINE \ - TOML_PURE -#endif -#ifndef TOML_CONST_GETTER -#define TOML_CONST_GETTER \ - TOML_NODISCARD \ - TOML_CONST -#endif -#ifndef TOML_CONST_INLINE_GETTER -#define TOML_CONST_INLINE_GETTER \ - TOML_NODISCARD \ - TOML_ALWAYS_INLINE \ - TOML_CONST -#endif - -// TOML_ASSUME -#ifdef _MSC_VER -#define TOML_ASSUME(expr) __assume(expr) -#elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume) -#define TOML_ASSUME(expr) __builtin_assume(expr) -#elif TOML_HAS_CPP_ATTR(assume) >= 202207 -#define TOML_ASSUME(expr) [[assume(expr)]] -#elif TOML_HAS_ATTR(__assume__) -#define TOML_ASSUME(expr) __attribute__((__assume__(expr))) -#else -#define TOML_ASSUME(expr) static_cast(0) -#endif - -// TOML_UNREACHABLE -#ifdef _MSC_VER -#define TOML_UNREACHABLE __assume(0) -#elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable) -#define TOML_UNREACHABLE __builtin_unreachable() -#else -#define TOML_UNREACHABLE static_cast(0) -#endif - -// TOML_LIKELY -#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803 -#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]] -#define TOML_LIKELY_CASE [[likely]] -#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) -#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1)) -#else -#define TOML_LIKELY(...) (__VA_ARGS__) -#endif -#ifndef TOML_LIKELY_CASE -#define TOML_LIKELY_CASE -#endif - -// TOML_UNLIKELY -#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803 -#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]] -#define TOML_UNLIKELY_CASE [[unlikely]] -#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) -#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0)) -#else -#define TOML_UNLIKELY(...) (__VA_ARGS__) -#endif -#ifndef TOML_UNLIKELY_CASE -#define TOML_UNLIKELY_CASE -#endif - -// TOML_FLAGS_ENUM -#if TOML_CLANG || TOML_HAS_ATTR(flag_enum) -#define TOML_FLAGS_ENUM __attribute__((flag_enum)) -#else -#define TOML_FLAGS_ENUM -#endif - -// TOML_OPEN_ENUM + TOML_CLOSED_ENUM -#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility) -#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open))) -#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed))) -#else -#define TOML_OPEN_ENUM -#define TOML_CLOSED_ENUM -#endif - -// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM -#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM -#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM - -// TOML_MAKE_FLAGS -#define TOML_MAKE_FLAGS_2(T, op, linkage) \ - TOML_CONST_INLINE_GETTER \ - linkage constexpr T operator op(T lhs, T rhs) noexcept \ - { \ - using under = std::underlying_type_t; \ - return static_cast(static_cast(lhs) op static_cast(rhs)); \ - } \ - \ - linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept \ - { \ - return lhs = (lhs op rhs); \ - } \ - \ - static_assert(true) -#define TOML_MAKE_FLAGS_1(T, linkage) \ - static_assert(std::is_enum_v); \ - \ - TOML_MAKE_FLAGS_2(T, &, linkage); \ - TOML_MAKE_FLAGS_2(T, |, linkage); \ - TOML_MAKE_FLAGS_2(T, ^, linkage); \ - \ - TOML_CONST_INLINE_GETTER \ - linkage constexpr T operator~(T val) noexcept \ - { \ - using under = std::underlying_type_t; \ - return static_cast(~static_cast(val)); \ - } \ - \ - TOML_CONST_INLINE_GETTER \ - linkage constexpr bool operator!(T val) noexcept \ - { \ - using under = std::underlying_type_t; \ - return !static_cast(val); \ - } \ - \ - static_assert(true) -#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, ) - -#define TOML_UNUSED(...) static_cast(__VA_ARGS__) - -#define TOML_DELETE_DEFAULTS(T) \ - T(const T&) = delete; \ - T(T&&) = delete; \ - T& operator=(const T&) = delete; \ - T& operator=(T&&) = delete - -#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \ - __VA_ARGS__ TOML_NODISCARD \ - friend bool operator==(RHS rhs, LHS lhs) noexcept \ - { \ - return lhs == rhs; \ - } \ - __VA_ARGS__ TOML_NODISCARD \ - friend bool operator!=(LHS lhs, RHS rhs) noexcept \ - { \ - return !(lhs == rhs); \ - } \ - __VA_ARGS__ TOML_NODISCARD \ - friend bool operator!=(RHS rhs, LHS lhs) noexcept \ - { \ - return !(lhs == rhs); \ - } \ - static_assert(true) - -#define TOML_EVAL_BOOL_1(T, F) T -#define TOML_EVAL_BOOL_0(T, F) F - -#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL) -#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__ -#endif - -// COMPILER-SPECIFIC WARNING MANAGEMENT - -#if TOML_CLANG - -#define TOML_PUSH_WARNINGS \ - TOML_PRAGMA_CLANG(diagnostic push) \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option") \ - static_assert(true) - -#define TOML_DISABLE_SWITCH_WARNINGS \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch") \ - static_assert(true) - -#define TOML_DISABLE_ARITHMETIC_WARNINGS \ - TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wimplicit-int-float-conversion") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow") \ - static_assert(true) - -#define TOML_DISABLE_SPAM_WARNINGS \ - TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted") \ - TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported") \ - TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant") \ - TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers") \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded") \ - static_assert(true) - -#define TOML_POP_WARNINGS \ - TOML_PRAGMA_CLANG(diagnostic pop) \ - static_assert(true) - -#define TOML_DISABLE_WARNINGS \ - TOML_PRAGMA_CLANG(diagnostic push) \ - TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything") \ - static_assert(true, "") - -#define TOML_ENABLE_WARNINGS \ - TOML_PRAGMA_CLANG(diagnostic pop) \ - static_assert(true) - -#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1 - -#elif TOML_MSVC - -#define TOML_PUSH_WARNINGS \ - __pragma(warning(push)) \ - static_assert(true) - -#if TOML_HAS_INCLUDE() -#pragma warning(push, 0) -#include -#pragma warning(pop) -#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \ - __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) \ - static_assert(true) -#else -#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) -#endif - -#define TOML_DISABLE_SWITCH_WARNINGS \ - __pragma(warning(disable : 4061)) \ - __pragma(warning(disable : 4062)) \ - __pragma(warning(disable : 4063)) \ - __pragma(warning(disable : 5262)) /* switch-case implicit fallthrough (false-positive) */ \ - __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */ \ - static_assert(true) - -#define TOML_DISABLE_SPAM_WARNINGS \ - __pragma(warning(disable : 4127)) /* conditional expr is constant */ \ - __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */ \ - __pragma(warning(disable : 4348)) \ - __pragma(warning(disable : 4464)) /* relative include path contains '..' */ \ - __pragma(warning(disable : 4505)) /* unreferenced local function removed */ \ - __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */ \ - __pragma(warning(disable : 4582)) /* constructor is not implicitly called */ \ - __pragma(warning(disable : 4619)) /* there is no warning number 'XXXX' */ \ - __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */ \ - __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */ \ - __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */ \ - __pragma(warning(disable : 4710)) /* function not inlined */ \ - __pragma(warning(disable : 4711)) /* function selected for automatic expansion */ \ - __pragma(warning(disable : 4820)) /* N bytes padding added */ \ - __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */ \ - __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted */ \ - __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted */ \ - __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */ \ - __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */ \ - __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */ \ - __pragma(warning(disable : 26451)) \ - __pragma(warning(disable : 26490)) \ - __pragma(warning(disable : 26495)) \ - __pragma(warning(disable : 26812)) \ - __pragma(warning(disable : 26819)) \ - static_assert(true) - -#define TOML_DISABLE_ARITHMETIC_WARNINGS \ - __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */ \ - __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */ \ - __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */ \ - static_assert(true) - -#define TOML_POP_WARNINGS \ - __pragma(warning(pop)) \ - static_assert(true) - -#define TOML_DISABLE_WARNINGS \ - __pragma(warning(push, 0)) \ - __pragma(warning(disable : 4348)) \ - __pragma(warning(disable : 4668)) \ - __pragma(warning(disable : 5105)) \ - __pragma(warning(disable : 5264)) \ - TOML_DISABLE_CODE_ANALYSIS_WARNINGS; \ - TOML_DISABLE_SWITCH_WARNINGS; \ - TOML_DISABLE_SPAM_WARNINGS; \ - TOML_DISABLE_ARITHMETIC_WARNINGS; \ - static_assert(true) - -#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS - -#elif TOML_ICC - -#define TOML_PUSH_WARNINGS \ - __pragma(warning(push)) \ - static_assert(true) - -#define TOML_DISABLE_SPAM_WARNINGS \ - __pragma(warning(disable : 82)) /* storage class is not first */ \ - __pragma(warning(disable : 111)) /* statement unreachable (false-positive) */ \ - __pragma(warning(disable : 869)) /* unreferenced parameter */ \ - __pragma(warning(disable : 1011)) /* missing return (false-positive) */ \ - __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */ \ - static_assert(true) - -#define TOML_POP_WARNINGS \ - __pragma(warning(pop)) \ - static_assert(true) - -#define TOML_DISABLE_WARNINGS \ - __pragma(warning(push, 0)) \ - TOML_DISABLE_SPAM_WARNINGS - -#define TOML_ENABLE_WARNINGS \ - __pragma(warning(pop)) \ - static_assert(true) - -#elif TOML_GCC - -#define TOML_PUSH_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic push) \ - static_assert(true) - -#define TOML_DISABLE_SWITCH_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default") \ - static_assert(true) - -#define TOML_DISABLE_ARITHMETIC_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ - static_assert(true) - -#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure") \ - static_assert(true) - -#define TOML_DISABLE_SPAM_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches") \ - static_assert(true) - -#define TOML_POP_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic pop) \ - static_assert(true) - -#define TOML_DISABLE_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic push) \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wall") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wextra") \ - TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic") \ - TOML_DISABLE_SWITCH_WARNINGS; \ - TOML_DISABLE_ARITHMETIC_WARNINGS; \ - TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \ - TOML_DISABLE_SPAM_WARNINGS; \ - static_assert(true) - -#define TOML_ENABLE_WARNINGS \ - TOML_PRAGMA_GCC(diagnostic pop) \ - static_assert(true) - -#endif - -#ifndef TOML_PUSH_WARNINGS -#define TOML_PUSH_WARNINGS static_assert(true) -#endif -#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS -#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) -#endif -#ifndef TOML_DISABLE_SWITCH_WARNINGS -#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true) -#endif -#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS -#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true) -#endif -#ifndef TOML_DISABLE_SPAM_WARNINGS -#define TOML_DISABLE_SPAM_WARNINGS static_assert(true) -#endif -#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS -#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true) -#endif -#ifndef TOML_POP_WARNINGS -#define TOML_POP_WARNINGS static_assert(true) -#endif -#ifndef TOML_DISABLE_WARNINGS -#define TOML_DISABLE_WARNINGS static_assert(true) -#endif -#ifndef TOML_ENABLE_WARNINGS -#define TOML_ENABLE_WARNINGS static_assert(true) -#endif -#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES -#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0 -#endif - -#ifdef TOML_CONFIG_HEADER -#include TOML_CONFIG_HEADER -#endif - -// is the library being built as a shared lib/dll using meson and friends? -#ifndef TOML_SHARED_LIB -#define TOML_SHARED_LIB 0 -#endif - -// header-only mode -#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0 -#define TOML_HEADER_ONLY TOML_ALL_INLINE -#endif -#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE -#undef TOML_HEADER_ONLY -#define TOML_HEADER_ONLY 1 -#endif -#if TOML_DOXYGEN || TOML_SHARED_LIB -#undef TOML_HEADER_ONLY -#define TOML_HEADER_ONLY 0 -#endif - -// internal implementation switch -#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY -#undef TOML_IMPLEMENTATION -#define TOML_IMPLEMENTATION 1 -#else -#define TOML_IMPLEMENTATION 0 -#endif - -// dll/shared lib function exports (legacy - TOML_API was the old name for this setting) -#if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && !defined(TOML_EXPORTED_STATIC_FUNCTION) \ - && !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && defined(TOML_API) -#define TOML_EXPORTED_MEMBER_FUNCTION TOML_API -#define TOML_EXPORTED_STATIC_FUNCTION TOML_API -#define TOML_EXPORTED_FREE_FUNCTION TOML_API -#endif - -// dll/shared lib exports -#if TOML_SHARED_LIB -#undef TOML_API -#undef TOML_EXPORTED_CLASS -#undef TOML_EXPORTED_MEMBER_FUNCTION -#undef TOML_EXPORTED_STATIC_FUNCTION -#undef TOML_EXPORTED_FREE_FUNCTION -#if TOML_WINDOWS -#if TOML_IMPLEMENTATION -#define TOML_EXPORTED_CLASS __declspec(dllexport) -#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport) -#else -#define TOML_EXPORTED_CLASS __declspec(dllimport) -#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport) -#endif -#ifndef TOML_CALLCONV -#define TOML_CALLCONV __cdecl -#endif -#elif defined(__GNUC__) && __GNUC__ >= 4 -#define TOML_EXPORTED_CLASS __attribute__((visibility("default"))) -#define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default"))) -#define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default"))) -#define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default"))) -#endif -#endif -#ifndef TOML_EXPORTED_CLASS -#define TOML_EXPORTED_CLASS -#endif -#ifndef TOML_EXPORTED_MEMBER_FUNCTION -#define TOML_EXPORTED_MEMBER_FUNCTION -#endif -#ifndef TOML_EXPORTED_STATIC_FUNCTION -#define TOML_EXPORTED_STATIC_FUNCTION -#endif -#ifndef TOML_EXPORTED_FREE_FUNCTION -#define TOML_EXPORTED_FREE_FUNCTION -#endif - -// experimental language features -#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES - // pre-3.0 -#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES -#endif -#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE -#undef TOML_ENABLE_UNRELEASED_FEATURES -#define TOML_ENABLE_UNRELEASED_FEATURES 1 -#endif -#ifndef TOML_ENABLE_UNRELEASED_FEATURES -#define TOML_ENABLE_UNRELEASED_FEATURES 0 -#endif - -// parser -#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0 -#define TOML_ENABLE_PARSER TOML_PARSER -#endif -#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE -#undef TOML_ENABLE_PARSER -#define TOML_ENABLE_PARSER 1 -#endif - -// formatters -#if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE -#undef TOML_ENABLE_FORMATTERS -#define TOML_ENABLE_FORMATTERS 1 -#endif - -// SIMD -#if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE -#undef TOML_ENABLE_SIMD -#define TOML_ENABLE_SIMD 1 -#endif - -// windows compat -#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0 -#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT -#endif -#if !defined(TOML_ENABLE_WINDOWS_COMPAT) || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) \ - || TOML_INTELLISENSE -#undef TOML_ENABLE_WINDOWS_COMPAT -#define TOML_ENABLE_WINDOWS_COMPAT 1 -#endif - -#if !TOML_WINDOWS -#undef TOML_ENABLE_WINDOWS_COMPAT -#define TOML_ENABLE_WINDOWS_COMPAT 0 -#endif - -#ifndef TOML_INCLUDE_WINDOWS_H -#define TOML_INCLUDE_WINDOWS_H 0 -#endif - -// custom optional -#ifdef TOML_OPTIONAL_TYPE -#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1 -#else -#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0 -#endif - -// exceptions (library use) -#if TOML_COMPILER_HAS_EXCEPTIONS -#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS) -#undef TOML_EXCEPTIONS -#define TOML_EXCEPTIONS 1 -#endif -#else -#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS -#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler. -#endif -#undef TOML_EXCEPTIONS -#define TOML_EXCEPTIONS 0 -#endif - -// calling convention for static/free/friend functions -#ifndef TOML_CALLCONV -#define TOML_CALLCONV -#endif - -#ifndef TOML_UNDEF_MACROS -#define TOML_UNDEF_MACROS 1 -#endif - -#ifndef TOML_MAX_NESTED_VALUES -#define TOML_MAX_NESTED_VALUES 256 -// this refers to the depth of nested values, e.g. inline tables and arrays. -// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... -#endif - -#ifdef TOML_CHAR_8_STRINGS -#if TOML_CHAR_8_STRINGS -#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly. -#endif -#endif - -#ifdef TOML_LARGE_FILES -#if !TOML_LARGE_FILES -#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0. -#endif -#endif - -#ifndef TOML_LIFETIME_HOOKS -#define TOML_LIFETIME_HOOKS 0 -#endif - -#ifdef NDEBUG -#undef TOML_ASSERT -#define TOML_ASSERT(expr) static_assert(true) -#endif -#ifndef TOML_ASSERT -#ifndef assert -TOML_DISABLE_WARNINGS; -#include -TOML_ENABLE_WARNINGS; -#endif -#define TOML_ASSERT(expr) assert(expr) -#endif -#ifdef NDEBUG -#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr) -#else -#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr) -#endif - -#ifndef TOML_ENABLE_FLOAT16 -#define TOML_ENABLE_FLOAT16 0 -#endif - -#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)) -// not supported by any version of GCC or Clang as of 26/11/2020 -// not supported by any version of ICC on Linux as of 11/01/2021 -#define TOML_FLOAT_CHARCONV 0 -#endif -#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__)) -// causes link errors on emscripten -// causes Mac OS SDK version errors on some versions of Apple Clang -#define TOML_INT_CHARCONV 0 -#endif -#ifndef TOML_INT_CHARCONV -#define TOML_INT_CHARCONV 1 -#endif -#ifndef TOML_FLOAT_CHARCONV -#define TOML_FLOAT_CHARCONV 1 -#endif -#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE() -#undef TOML_INT_CHARCONV -#undef TOML_FLOAT_CHARCONV -#define TOML_INT_CHARCONV 0 -#define TOML_FLOAT_CHARCONV 0 -#endif - -#if defined(__cpp_concepts) && __cpp_concepts >= 201907 -#define TOML_REQUIRES(...) requires(__VA_ARGS__) -#else -#define TOML_REQUIRES(...) -#endif -#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0 -#define TOML_CONSTRAINED_TEMPLATE(condition, ...) \ - template <__VA_ARGS__ TOML_ENABLE_IF(condition)> \ - TOML_REQUIRES(condition) -#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__) - -#if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && defined(__LDBL_MANT_DIG__) \ - && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__ -#define TOML_FLOAT128 __float128 -#endif - -#ifdef __SIZEOF_INT128__ -#define TOML_INT128 __int128_t -#define TOML_UINT128 __uint128_t -#endif - -// clang-format off - -//******** impl/version.hpp ****************************************************************************************** - -#define TOML_LIB_MAJOR 3 -#define TOML_LIB_MINOR 4 -#define TOML_LIB_PATCH 0 - -#define TOML_LANG_MAJOR 1 -#define TOML_LANG_MINOR 0 -#define TOML_LANG_PATCH 0 - -//******** impl/preprocessor.hpp ************************************************************************************* - -#define TOML_LIB_SINGLE_HEADER 1 - -#if TOML_ENABLE_UNRELEASED_FEATURES - #define TOML_LANG_EFFECTIVE_VERSION \ - TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1) -#else - #define TOML_LANG_EFFECTIVE_VERSION \ - TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) -#endif - -#define TOML_LANG_HIGHER_THAN(major, minor, patch) \ - (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch)) - -#define TOML_LANG_AT_LEAST(major, minor, patch) \ - (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch)) - -#define TOML_LANG_UNRELEASED \ - TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) - -#ifndef TOML_ABI_NAMESPACES - #if TOML_DOXYGEN - #define TOML_ABI_NAMESPACES 0 - #else - #define TOML_ABI_NAMESPACES 1 - #endif -#endif -#if TOML_ABI_NAMESPACES - #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR) - #define TOML_NAMESPACE_END } static_assert(true) - #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR) - #define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true) - #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F)) - #define TOML_ABI_NAMESPACE_END } static_assert(true) -#else - #define TOML_NAMESPACE_START namespace toml - #define TOML_NAMESPACE_END static_assert(true) - #define TOML_NAMESPACE toml - #define TOML_ABI_NAMESPACE_START(...) static_assert(true) - #define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true) - #define TOML_ABI_NAMESPACE_END static_assert(true) -#endif -#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl -#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END -#if TOML_HEADER_ONLY - #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START - #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END - #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl - #define TOML_EXTERNAL_LINKAGE inline - #define TOML_INTERNAL_LINKAGE inline -#else - #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \ - using namespace toml; \ - namespace - #define TOML_ANON_NAMESPACE_END static_assert(true) - #define TOML_ANON_NAMESPACE - #define TOML_EXTERNAL_LINKAGE - #define TOML_INTERNAL_LINKAGE static -#endif - -// clang-format on - -// clang-format off - -#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES - - #define TOML_SA_NEWLINE " " - #define TOML_SA_LIST_SEP ", " - #define TOML_SA_LIST_BEG " (" - #define TOML_SA_LIST_END ")" - #define TOML_SA_LIST_NEW " " - #define TOML_SA_LIST_NXT ", " - -#else - - #define TOML_SA_NEWLINE "\n| " - #define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - " - #define TOML_SA_LIST_BEG TOML_SA_LIST_SEP - #define TOML_SA_LIST_END - #define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE - #define TOML_SA_LIST_NXT TOML_SA_LIST_NEW - -#endif - -#define TOML_SA_NATIVE_VALUE_TYPE_LIST \ - TOML_SA_LIST_BEG "std::string" \ - TOML_SA_LIST_SEP "int64_t" \ - TOML_SA_LIST_SEP "double" \ - TOML_SA_LIST_SEP "bool" \ - TOML_SA_LIST_SEP "toml::date" \ - TOML_SA_LIST_SEP "toml::time" \ - TOML_SA_LIST_SEP "toml::date_time" \ - TOML_SA_LIST_END - -#define TOML_SA_NODE_TYPE_LIST \ - TOML_SA_LIST_BEG "toml::table" \ - TOML_SA_LIST_SEP "toml::array" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_SEP "toml::value" \ - TOML_SA_LIST_END - -#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \ - TOML_SA_LIST_NEW "A native TOML value type" \ - TOML_SA_NATIVE_VALUE_TYPE_LIST \ - \ - TOML_SA_LIST_NXT "A TOML node type" \ - TOML_SA_NODE_TYPE_LIST - -// clang-format on - -TOML_PUSH_WARNINGS; -TOML_DISABLE_SPAM_WARNINGS; -TOML_DISABLE_SWITCH_WARNINGS; -TOML_DISABLE_SUGGEST_ATTR_WARNINGS; - -// misc warning false-positives -#if TOML_MSVC -#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch -#if TOML_SHARED_LIB -#pragma warning(disable : 4251) // dll exports for std lib types -#endif -#elif TOML_CLANG -TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene") -#if TOML_CLANG >= 12 -TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions") -#endif -#if TOML_CLANG == 13 -TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier") -#endif -#endif - -//******** impl/std_new.hpp ****************************************************************************************** - -TOML_DISABLE_WARNINGS; -#include -TOML_ENABLE_WARNINGS; - -#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914 -#define TOML_LAUNDER(x) __builtin_launder(x) -#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 -#define TOML_LAUNDER(x) std::launder(x) -#else -#define TOML_LAUNDER(x) x -#endif - -//******** impl/std_string.hpp *************************************************************************************** - -TOML_DISABLE_WARNINGS; -#include -#include -TOML_ENABLE_WARNINGS; - -#if TOML_DOXYGEN \ - || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \ - && __cpp_lib_char8_t >= 201907) -#define TOML_HAS_CHAR8 1 -#else -#define TOML_HAS_CHAR8 0 -#endif - -namespace toml // non-abi namespace; this is not an error -{ - using namespace std::string_literals; - using namespace std::string_view_literals; -} - -#if TOML_ENABLE_WINDOWS_COMPAT - -TOML_IMPL_NAMESPACE_START -{ - TOML_NODISCARD - TOML_EXPORTED_FREE_FUNCTION - std::string narrow(std::wstring_view); - - TOML_NODISCARD - TOML_EXPORTED_FREE_FUNCTION - std::wstring widen(std::string_view); - -#if TOML_HAS_CHAR8 - - TOML_NODISCARD - TOML_EXPORTED_FREE_FUNCTION - std::wstring widen(std::u8string_view); - -#endif -} -TOML_IMPL_NAMESPACE_END; - -#endif // TOML_ENABLE_WINDOWS_COMPAT - -//******** impl/std_optional.hpp ************************************************************************************* - -TOML_DISABLE_WARNINGS; -#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE -#include -#endif -TOML_ENABLE_WARNINGS; - -TOML_NAMESPACE_START -{ -#if TOML_HAS_CUSTOM_OPTIONAL_TYPE - - template - using optional = TOML_OPTIONAL_TYPE; - -#else - - template - using optional = std::optional; - -#endif -} -TOML_NAMESPACE_END; - -//******** impl/forward_declarations.hpp ***************************************************************************** - -TOML_DISABLE_WARNINGS; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -TOML_ENABLE_WARNINGS; -TOML_PUSH_WARNINGS; -#ifdef _MSC_VER -#ifndef __clang__ -#pragma inline_recursion(on) -#endif -#pragma push_macro("min") -#pragma push_macro("max") -#undef min -#undef max -#endif - -#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS -#define TOML_ENV_MESSAGE \ - "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \ - "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \ - "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \ - "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \ - "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. " \ - "Thanks!" - -static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE); -#ifdef FLT_RADIX -static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE); -#endif -static_assert('A' == 65, TOML_ENV_MESSAGE); -static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE); -static_assert(std::numeric_limits::is_iec559, TOML_ENV_MESSAGE); -static_assert(std::numeric_limits::digits == 53, TOML_ENV_MESSAGE); -static_assert(std::numeric_limits::digits10 == 15, TOML_ENV_MESSAGE); -static_assert(std::numeric_limits::radix == 2, TOML_ENV_MESSAGE); - -#undef TOML_ENV_MESSAGE -#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS - -// undocumented forward declarations are hidden from doxygen because they fuck it up =/ - -namespace toml // non-abi namespace; this is not an error -{ - using ::std::size_t; - using ::std::intptr_t; - using ::std::uintptr_t; - using ::std::ptrdiff_t; - using ::std::nullptr_t; - using ::std::int8_t; - using ::std::int16_t; - using ::std::int32_t; - using ::std::int64_t; - using ::std::uint8_t; - using ::std::uint16_t; - using ::std::uint32_t; - using ::std::uint64_t; - using ::std::uint_least32_t; - using ::std::uint_least64_t; -} - -TOML_NAMESPACE_START -{ - struct date; - struct time; - struct time_offset; - - TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt); - struct date_time; - TOML_ABI_NAMESPACE_END; - - struct source_position; - struct source_region; - - class node; - template - class node_view; - - class key; - class array; - class table; - template - class value; - - class path; - - class toml_formatter; - class json_formatter; - class yaml_formatter; - - TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex); -#if TOML_EXCEPTIONS - using parse_result = table; -#else - class parse_result; -#endif - TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS -} -TOML_NAMESPACE_END; - -TOML_IMPL_NAMESPACE_START -{ - using node_ptr = std::unique_ptr; - - TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex); - class parser; - TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS - - // clang-format off - - inline constexpr std::string_view control_char_escapes[] = - { - "\\u0000"sv, - "\\u0001"sv, - "\\u0002"sv, - "\\u0003"sv, - "\\u0004"sv, - "\\u0005"sv, - "\\u0006"sv, - "\\u0007"sv, - "\\b"sv, - "\\t"sv, - "\\n"sv, - "\\u000B"sv, - "\\f"sv, - "\\r"sv, - "\\u000E"sv, - "\\u000F"sv, - "\\u0010"sv, - "\\u0011"sv, - "\\u0012"sv, - "\\u0013"sv, - "\\u0014"sv, - "\\u0015"sv, - "\\u0016"sv, - "\\u0017"sv, - "\\u0018"sv, - "\\u0019"sv, - "\\u001A"sv, - "\\u001B"sv, - "\\u001C"sv, - "\\u001D"sv, - "\\u001E"sv, - "\\u001F"sv, - }; - - inline constexpr std::string_view node_type_friendly_names[] = - { - "none"sv, - "table"sv, - "array"sv, - "string"sv, - "integer"sv, - "floating-point"sv, - "boolean"sv, - "date"sv, - "time"sv, - "date-time"sv - }; - - // clang-format on -} -TOML_IMPL_NAMESPACE_END; - -#if TOML_ABI_NAMESPACES -#if TOML_EXCEPTIONS -#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser -#else -#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser -#endif -#else -#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser -#endif - -namespace toml -{ -} - -TOML_NAMESPACE_START // abi namespace -{ - inline namespace literals - { - } - - enum class TOML_CLOSED_ENUM node_type : uint8_t - { - none, - table, - array, - string, - integer, - floating_point, - boolean, - date, - time, - date_time - }; - - template - inline std::basic_ostream& operator<<(std::basic_ostream& lhs, node_type rhs) - { - const auto str = impl::node_type_friendly_names[static_cast>(rhs)]; - using str_char_t = decltype(str)::value_type; - if constexpr (std::is_same_v) - return lhs << str; - else - { - if constexpr (sizeof(Char) == sizeof(str_char_t)) - return lhs << std::basic_string_view{ reinterpret_cast(str.data()), str.length() }; - else - return lhs << str.data(); - } - } - - enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error - { - none, - format_as_binary = 1, - format_as_octal = 2, - format_as_hexadecimal = 3, - }; - TOML_MAKE_FLAGS(value_flags); - - inline constexpr value_flags preserve_source_value_flags = - POXY_IMPLEMENTATION_DETAIL(value_flags{ static_cast>(-1) }); - - enum class TOML_CLOSED_FLAGS_ENUM format_flags : uint64_t - { - none, - quote_dates_and_times = (1ull << 0), - quote_infinities_and_nans = (1ull << 1), - allow_literal_strings = (1ull << 2), - allow_multi_line_strings = (1ull << 3), - allow_real_tabs_in_strings = (1ull << 4), - allow_unicode_strings = (1ull << 5), - allow_binary_integers = (1ull << 6), - allow_octal_integers = (1ull << 7), - allow_hexadecimal_integers = (1ull << 8), - indent_sub_tables = (1ull << 9), - indent_array_elements = (1ull << 10), - indentation = indent_sub_tables | indent_array_elements, - relaxed_float_precision = (1ull << 11), - terse_key_value_pairs = (1ull << 12), - }; - TOML_MAKE_FLAGS(format_flags); - - template - struct TOML_TRIVIAL_ABI inserter - { - static_assert(std::is_reference_v); - - T value; - }; - template - inserter(T&&) -> inserter; - template - inserter(T&) -> inserter; - - using default_formatter = toml_formatter; -} -TOML_NAMESPACE_END; - -TOML_IMPL_NAMESPACE_START -{ - template - using remove_cvref = std::remove_cv_t>; - - template - using common_signed_type = std::common_type_t...>; - - template - inline constexpr bool is_one_of = (false || ... || std::is_same_v); - - template - inline constexpr bool all_integral = (std::is_integral_v && ...); - - template - inline constexpr bool is_cvref = std::is_reference_v || std::is_const_v || std::is_volatile_v; - - template - inline constexpr bool is_wide_string = - is_one_of, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>; - - template - inline constexpr bool value_retrieval_is_nothrow = !std::is_same_v, std::string> -#if TOML_HAS_CHAR8 - && !std::is_same_v, std::u8string> -#endif - - && !is_wide_string; - - template - struct copy_ref_; - template - using copy_ref = typename copy_ref_::type; - - template - struct copy_ref_ - { - using type = Dest; - }; - - template - struct copy_ref_ - { - using type = std::add_lvalue_reference_t; - }; - - template - struct copy_ref_ - { - using type = std::add_rvalue_reference_t; - }; - - template - struct copy_cv_; - template - using copy_cv = typename copy_cv_::type; - - template - struct copy_cv_ - { - using type = Dest; - }; - - template - struct copy_cv_ - { - using type = std::add_const_t; - }; - - template - struct copy_cv_ - { - using type = std::add_volatile_t; - }; - - template - struct copy_cv_ - { - using type = std::add_cv_t; - }; - - template - using copy_cvref = - copy_ref, std::remove_reference_t>, Dest>, Src>; - - template - inline constexpr bool always_false = false; - - template - inline constexpr bool first_is_same = false; - template - inline constexpr bool first_is_same = true; - - template > - struct underlying_type_ - { - using type = std::underlying_type_t; - }; - template - struct underlying_type_ - { - using type = T; - }; - template - using underlying_type = typename underlying_type_::type; - - // general value traits - // (as they relate to their equivalent native TOML type) - struct default_value_traits - { - using native_type = void; - static constexpr bool is_native = false; - static constexpr bool is_losslessly_convertible_to_native = false; - static constexpr bool can_represent_native = false; - static constexpr bool can_partially_represent_native = false; - static constexpr auto type = node_type::none; - }; - - template - struct value_traits; - - template > - struct value_traits_base_selector - { - static_assert(!is_cvref); - - using type = default_value_traits; - }; - template - struct value_traits_base_selector - { - static_assert(!is_cvref); - - using type = value_traits>; - }; - - template - struct value_traits : value_traits_base_selector::type - {}; - template - struct value_traits : value_traits - {}; - template - struct value_traits : value_traits - {}; - template - struct value_traits : value_traits - {}; - template - struct value_traits : value_traits - {}; - template - struct value_traits : value_traits - {}; - - // integer value_traits specializations - standard types - template - struct integer_limits - { - static constexpr T min = T{ (std::numeric_limits>::min)() }; - static constexpr T max = T{ (std::numeric_limits>::max)() }; - }; - template - struct integer_traits_base : integer_limits - { - using native_type = int64_t; - static constexpr bool is_native = std::is_same_v, native_type>; - static constexpr bool is_signed = static_cast>(-1) < underlying_type{}; - static constexpr auto type = node_type::integer; - static constexpr bool can_partially_represent_native = true; - }; - template - struct unsigned_integer_traits : integer_traits_base - { - static constexpr bool is_losslessly_convertible_to_native = - integer_limits>::max <= 9223372036854775807ULL; - static constexpr bool can_represent_native = false; - }; - template - struct signed_integer_traits : integer_traits_base - { - using native_type = int64_t; - static constexpr bool is_losslessly_convertible_to_native = - integer_limits>::min >= (-9223372036854775807LL - 1LL) - && integer_limits>::max <= 9223372036854775807LL; - static constexpr bool can_represent_native = - integer_limits>::min <= (-9223372036854775807LL - 1LL) - && integer_limits>::max >= 9223372036854775807LL; - }; - template ::is_signed> - struct integer_traits : signed_integer_traits - {}; - template - struct integer_traits : unsigned_integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; - static_assert(value_traits::is_native); - static_assert(value_traits::is_signed); - static_assert(value_traits::is_losslessly_convertible_to_native); - static_assert(value_traits::can_represent_native); - static_assert(value_traits::can_partially_represent_native); - - // integer value_traits specializations - non-standard types -#ifdef TOML_INT128 - template <> - struct integer_limits - { - static constexpr TOML_INT128 max = - static_cast((TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1); - static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 }; - }; - template <> - struct integer_limits - { - static constexpr TOML_UINT128 min = TOML_UINT128{}; - static constexpr TOML_UINT128 max = (2u * static_cast(integer_limits::max)) + 1u; - }; - template <> - struct value_traits : integer_traits - {}; - template <> - struct value_traits : integer_traits - {}; -#endif -#ifdef TOML_SMALL_INT_TYPE - template <> - struct value_traits : signed_integer_traits - {}; -#endif - - // floating-point traits base - template - struct float_traits_base - { - static constexpr auto type = node_type::floating_point; - using native_type = double; - static constexpr bool is_native = std::is_same_v; - static constexpr bool is_signed = true; - - static constexpr int bits = static_cast(sizeof(T) * CHAR_BIT); - static constexpr int digits = MantissaDigits; - static constexpr int digits10 = DecimalDigits; - - static constexpr bool is_losslessly_convertible_to_native = bits <= 64 // - && digits <= 53 // DBL_MANT_DIG - && digits10 <= 15; // DBL_DIG - - static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG - && digits10 >= 15; // DBL_DIG - - static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0; - }; - template - struct float_traits : float_traits_base::digits, std::numeric_limits::digits10> - {}; -#if TOML_ENABLE_FLOAT16 - template <> - struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__> - {}; -#endif -#ifdef TOML_FLOAT128 - template <> - struct float_traits : float_traits_base - {}; -#endif - - // floating-point traits - template <> - struct value_traits : float_traits - {}; - template <> - struct value_traits : float_traits - {}; - template <> - struct value_traits : float_traits - {}; -#if TOML_ENABLE_FLOAT16 - template <> - struct value_traits<_Float16> : float_traits<_Float16> - {}; -#endif -#ifdef TOML_FLOAT128 - template <> - struct value_traits : float_traits - {}; -#endif -#ifdef TOML_SMALL_FLOAT_TYPE - template <> - struct value_traits : float_traits - {}; -#endif - static_assert(value_traits::is_native); - static_assert(value_traits::is_losslessly_convertible_to_native); - static_assert(value_traits::can_represent_native); - static_assert(value_traits::can_partially_represent_native); - - // string value_traits specializations - char-based strings - template - struct string_traits - { - using native_type = std::string; - static constexpr bool is_native = std::is_same_v; - static constexpr bool is_losslessly_convertible_to_native = true; - static constexpr bool can_represent_native = - !std::is_array_v && (!std::is_pointer_v || std::is_const_v>); - static constexpr bool can_partially_represent_native = can_represent_native; - static constexpr auto type = node_type::string; - }; - template <> - struct value_traits : string_traits - {}; - template <> - struct value_traits : string_traits - {}; - template <> - struct value_traits : string_traits - {}; - template - struct value_traits : string_traits - {}; - template <> - struct value_traits : string_traits - {}; - template - struct value_traits : string_traits - {}; - - // string value_traits specializations - char8_t-based strings -#if TOML_HAS_CHAR8 - template <> - struct value_traits : string_traits - {}; - template <> - struct value_traits : string_traits - {}; - template <> - struct value_traits : string_traits - {}; - template - struct value_traits : string_traits - {}; - template <> - struct value_traits : string_traits - {}; - template - struct value_traits : string_traits - {}; -#endif - - // string value_traits specializations - wchar_t-based strings on Windows -#if TOML_ENABLE_WINDOWS_COMPAT - template - struct wstring_traits - { - using native_type = std::string; - static constexpr bool is_native = false; - static constexpr bool is_losslessly_convertible_to_native = true; // narrow - static constexpr bool can_represent_native = std::is_same_v; // widen - static constexpr bool can_partially_represent_native = can_represent_native; - static constexpr auto type = node_type::string; - }; - template <> - struct value_traits : wstring_traits - {}; - template <> - struct value_traits : wstring_traits - {}; - template <> - struct value_traits : wstring_traits - {}; - template - struct value_traits : wstring_traits - {}; - template <> - struct value_traits : wstring_traits - {}; - template - struct value_traits : wstring_traits - {}; -#endif - - // other 'native' value_traits specializations - template - struct native_value_traits - { - using native_type = T; - static constexpr bool is_native = true; - static constexpr bool is_losslessly_convertible_to_native = true; - static constexpr bool can_represent_native = true; - static constexpr bool can_partially_represent_native = true; - static constexpr auto type = NodeType; - }; - template <> - struct value_traits : native_value_traits - {}; - template <> - struct value_traits : native_value_traits - {}; - template <> - struct value_traits