diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index e9de701fc9d7..7d3561b01a0b 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -77,6 +77,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:update, v:virtual-I/O s:subda PMTiles -vector- (rw+v): ProtoMap Tiles (*.pmtiles) JSONFG -vector- (rw+v): OGC Features and Geometries JSON (*.json) MiraMonVector -vector- (rw+v): MiraMon Vectors (.pol, .arc, .pnt) (*.pol, *.arc, *.pnt) + ADBC -vector- (ro): Arrow Database Connectivity TIGER -vector- (rov): U.S. Census TIGER/Line AVCBin -vector- (rov): Arc/Info Binary Coverage AVCE00 -vector- (rov): Arc/Info E00 (ASCII) Coverage (*.e00) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b7f88f67772b..2fb810e2ea38 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -57,6 +57,7 @@ repos: frmts/grib/degrib/degrib| frmts/grib/degrib/g2clib| port/utf8.h| + ogr/ogrsf_frmts/adbc/ogr_adbc_internal.h| ogr/ogrsf_frmts/cad/libopencad/| ogr/ogrsf_frmts/geojson/libjson/| ogr/ogrsf_frmts/flatgeobuf/flatbuffers/| diff --git a/autotest/ogr/ogr_adbc.py b/autotest/ogr/ogr_adbc.py index 5148ada0702e..edaf0e937140 100755 --- a/autotest/ogr/ogr_adbc.py +++ b/autotest/ogr/ogr_adbc.py @@ -17,7 +17,19 @@ from osgeo import gdal, ogr -pytestmark = pytest.mark.require_driver("ADBC") + +def _has_adbc_driver_manager(): + drv = gdal.GetDriverByName("ADBC") + return drv and drv.GetMetadataItem("HAS_ADBC_DRIVER_MANAGER") + + +pytestmark = [ + pytest.mark.require_driver("ADBC"), + pytest.mark.skipif( + not _has_adbc_driver_manager(), + reason="ADBC driver built without AdbcDriverManager", + ), +] ############################################################################### diff --git a/doc/source/api/vector_c_api.rst b/doc/source/api/vector_c_api.rst index ea70e352227c..65dc4074b266 100644 --- a/doc/source/api/vector_c_api.rst +++ b/doc/source/api/vector_c_api.rst @@ -14,3 +14,6 @@ ogr_core.h and ogr_api.h: Vector C API .. doxygenfile:: ogr_api.h :project: api + +.. doxygenfile:: gdal_adbc.h + :project: api diff --git a/doc/source/drivers/vector/adbc.rst b/doc/source/drivers/vector/adbc.rst index 4287995608db..e8a3659d2715 100644 --- a/doc/source/drivers/vector/adbc.rst +++ b/doc/source/drivers/vector/adbc.rst @@ -7,11 +7,19 @@ ADBC -- Arrow Database Connectivity .. shortname:: ADBC -.. build_dependencies:: adbc-driver-manager +ADBC is a set of APIs and libraries for Arrow-native access to database. -ADBC is a set of APIs and libraries for Arrow-native access to database. This -driver uses the ``adbc-driver-manager`` library to connect to available ADBC -drivers, and expose content as classic OGR features, or as a ArrowArrayStream. +This driver has 2 modes: + +- either it has been built against the ``adbc-driver-manager`` library. In that + case, it can directly be used to connect to available ADBC drivers, and expose + content as classic OGR features, or as a ArrowArrayStream. + In that mode the driver metadata exposes the ``HAS_ADBC_DRIVER_MANAGER`` + metadata item. +- or it has not, in which case applications embedding GDAL must use + :cpp:func:`GDALSetAdbcLoadDriverOverride` as detailed in a below paragraph. + Note that use of that function can also be done even if the driver has been built + against the ``adbc-driver-manager`` library. Consult the `installation instruction `__ for the various ADBC drivers. At time of writing, there are drivers for @@ -80,6 +88,16 @@ It returns for each table a OGR feature with the following fields (some potentially unset or with an empty string): ``catalog_name``, ``schema_name``, ``table_name``, ``table_type``. +Custom driver entry point +------------------------- + +A custom driver entry point can be specified by applications by calling +:cpp:func:`GDALSetAdbcLoadDriverOverride` (defined in header :file:`gdal_adbc.h`) +before using the driver. The specified init function will be used by the +GDAL ADBC driver as a way of locating and loading the ADBC driver if GDAL was +not built with ADBC Driver Manager support or if an embedding application has +an updated or augmented collection of drivers available. + Examples -------- diff --git a/gcore/CMakeLists.txt b/gcore/CMakeLists.txt index a4699856b6fb..98c7fde1993a 100644 --- a/gcore/CMakeLists.txt +++ b/gcore/CMakeLists.txt @@ -1,6 +1,7 @@ # CMake4GDAL project is distributed under MIT license. See accompanying file LICENSE.txt. add_library( gcore OBJECT + gdal_adbc.cpp gdalopeninfo.cpp gdaldriver.cpp gdaldrivermanager.cpp @@ -195,6 +196,7 @@ target_public_header( gdal_mdreader.h gdalsubdatasetinfo.h gdal_typetraits.h + gdal_adbc.h ) set(GDAL_DATA_FILES diff --git a/gcore/gdal_adbc.cpp b/gcore/gdal_adbc.cpp new file mode 100644 index 000000000000..16c46103bdf3 --- /dev/null +++ b/gcore/gdal_adbc.cpp @@ -0,0 +1,49 @@ +/****************************************************************************** + * Name: gdal_adbc.h + * Project: GDAL Core + * Purpose: GDAL Core ADBC related declarations. + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (c) 2024, Even Rouault + * Copyright (c) 2024, Dewey Dunnington + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#include "cpl_port.h" +#include "gdal_adbc.h" + +//! ADBC driver initialization function +static GDALAdbcLoadDriverFunc GDALAdbcLoadDriver = nullptr; + +/************************************************************************/ +/* GDALSetAdbcLoadDriverOverride() */ +/************************************************************************/ + +/** When set, it is used by the OGR ADBC driver to populate AdbcDriver + * callbacks. This provides an embedding application the opportunity to + * locate an up-to-date version of a driver or to bundle a driver not + * available at the system level. + * + * Setting it to NULL resets to the the default behavior of the ADBC driver, + * which is use AdbcLoadDriver() from arrow-adbc/adbc_driver_manager.h or + * to error if the OGR ADBC driver was not built against a system driver + * manager. + */ +void GDALSetAdbcLoadDriverOverride(GDALAdbcLoadDriverFunc init_func) +{ + GDALAdbcLoadDriver = init_func; +} + +/************************************************************************/ +/* GDALGetAdbcLoadDriverOverride() */ +/************************************************************************/ + +/** Gets the ADBC driver load function. This will be NULL if an explicit + * override was not specified. + */ +GDALAdbcLoadDriverFunc GDALGetAdbcLoadDriverOverride() +{ + return GDALAdbcLoadDriver; +} diff --git a/gcore/gdal_adbc.h b/gcore/gdal_adbc.h new file mode 100644 index 000000000000..3132e370afad --- /dev/null +++ b/gcore/gdal_adbc.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * Name: gdal_adbc.h + * Project: GDAL Core + * Purpose: GDAL Core ADBC related declarations. + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (c) 2024, Even Rouault + * Copyright (c) 2024, Dewey Dunnington + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#ifndef GDAL_ADBC_H_INCLUDED +#define GDAL_ADBC_H_INCLUDED + +/** + * \file gdal_adbc.h + * + * C GDAL entry points for Arrow Database Connectivity (ADBC) + * + * These functions provide an opportunity to override the mechanism + * that locates and loads ADBC drivers, or provide one if GDAL was + * not built with ADBC driver manager support. + * + * \since GDAL 3.11 + */ + +#include "cpl_port.h" + +#include + +CPL_C_START + +/** Type of a callback function to load a ADBC driver. */ +typedef uint8_t (*GDALAdbcLoadDriverFunc)(const char *driver_name, + const char *entrypoint, int version, + void *driver, void *error); + +void CPL_DLL GDALSetAdbcLoadDriverOverride(GDALAdbcLoadDriverFunc init_func); + +GDALAdbcLoadDriverFunc CPL_DLL GDALGetAdbcLoadDriverOverride(void); + +CPL_C_END + +#endif diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index ac7feb80f52c..d9337012cae0 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -84,6 +84,7 @@ ogr_optional_driver(jml JML) ogr_optional_driver(vdv "VDV-451/VDV-452/INTREST Data Format") ogr_optional_driver(flatgeobuf FlatGeobuf) ogr_optional_driver(mapml MapML) +ogr_optional_driver(adbc ADBC) if( NOT WORDS_BIGENDIAN ) ogr_optional_driver(miramon "MiraMonVector") @@ -113,7 +114,6 @@ ogr_dependent_driver(oapif "OGC API Features service" "GDAL_USE_CURL") ogr_dependent_driver(ngw "NextGIS Web" "GDAL_USE_CURL") ogr_dependent_driver(elastic "ElasticSearch" "GDAL_USE_CURL") ogr_dependent_driver(xodr OpenDRIVE "GDAL_USE_OPENDRIVE;GDAL_USE_GEOS") -ogr_dependent_driver(adbc ADBC "GDAL_USE_ADBCDRIVERMANAGER") ogr_dependent_driver(idrisi IDRISI "GDAL_ENABLE_DRIVER_IDRISI") diff --git a/ogr/ogrsf_frmts/adbc/CMakeLists.txt b/ogr/ogrsf_frmts/adbc/CMakeLists.txt index 5f12eb1d4afe..fd60b66fcd44 100644 --- a/ogr/ogrsf_frmts/adbc/CMakeLists.txt +++ b/ogr/ogrsf_frmts/adbc/CMakeLists.txt @@ -10,6 +10,10 @@ add_gdal_driver( NO_SHARED_SYMBOL_WITH_CORE STRONG_CXX_WFLAGS) +if(TARGET ogr_ADBC_core AND GDAL_USE_ADBCDRIVERMANAGER AND TARGET AdbcDriverManager::adbc_driver_manager_shared) + target_compile_definitions(ogr_ADBC_core PRIVATE OGR_ADBC_HAS_DRIVER_MANAGER) +endif() + if(NOT TARGET ogr_ADBC) return() endif() @@ -17,4 +21,8 @@ endif() gdal_standard_includes(ogr_ADBC) target_include_directories(ogr_ADBC PRIVATE $ $) -gdal_target_link_libraries(ogr_ADBC PRIVATE AdbcDriverManager::adbc_driver_manager_shared) + +if (GDAL_USE_ADBCDRIVERMANAGER AND TARGET AdbcDriverManager::adbc_driver_manager_shared) + gdal_target_link_libraries(ogr_ADBC PRIVATE AdbcDriverManager::adbc_driver_manager_shared) + target_compile_definitions(ogr_ADBC PRIVATE OGR_ADBC_HAS_DRIVER_MANAGER) +endif() diff --git a/ogr/ogrsf_frmts/adbc/ogr_adbc.h b/ogr/ogrsf_frmts/adbc/ogr_adbc.h index 03ea21a1f378..d1d8e0662060 100644 --- a/ogr/ogrsf_frmts/adbc/ogr_adbc.h +++ b/ogr/ogrsf_frmts/adbc/ogr_adbc.h @@ -17,7 +17,7 @@ #include "ogrsf_frmts.h" #include "ogrlayerarrow.h" -#include +#include "ogr_adbc_internal.h" /************************************************************************/ /* OGRArrowArrayToOGRFeatureAdapterLayer */ @@ -138,6 +138,7 @@ class OGRADBCDataset final : public GDALDataset { friend class OGRADBCLayer; + AdbcDriver m_driver{}; AdbcDatabase m_database{}; std::unique_ptr m_connection{}; std::vector> m_apoLayers{}; @@ -175,12 +176,9 @@ class OGRADBCDataset final : public GDALDataset struct OGRADBCError { - AdbcError error{}; + AdbcError error{ADBC_ERROR_INIT}; - inline OGRADBCError() - { - memset(&error, 0, sizeof(error)); - } + inline OGRADBCError() = default; inline ~OGRADBCError() { diff --git a/ogr/ogrsf_frmts/adbc/ogr_adbc_internal.h b/ogr/ogrsf_frmts/adbc/ogr_adbc_internal.h new file mode 100644 index 000000000000..b965672e6f48 --- /dev/null +++ b/ogr/ogrsf_frmts/adbc/ogr_adbc_internal.h @@ -0,0 +1,2356 @@ +// 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 unintialized/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 unintialized/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 unintialized/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 unintialized/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 unintialized/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 unintialized/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 unintialized/freed (but + /// it need not have a value even if the driver is initialized). + void* private_manager; + + /// \brief Release the driver and perform any cleanup. + /// + /// 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/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp b/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp index 8410f395ea45..8a03d9f0abb1 100644 --- a/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp +++ b/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp @@ -6,6 +6,7 @@ * ****************************************************************************** * Copyright (c) 2024, Even Rouault + * Copyright (c) 2024, Dewey Dunnington * * SPDX-License-Identifier: MIT ****************************************************************************/ @@ -15,6 +16,44 @@ #include "ogr_mem.h" #include "ogr_p.h" #include "cpl_json.h" +#include "gdal_adbc.h" + +#if defined(OGR_ADBC_HAS_DRIVER_MANAGER) +#include +#endif + +#define OGR_ADBC_VERSION ADBC_VERSION_1_1_0 +static_assert(sizeof(AdbcDriver) == ADBC_DRIVER_1_1_0_SIZE); + +namespace +{ + +AdbcStatusCode OGRADBCLoadDriver(const char *driver_name, + const char *entrypoint, void *driver, + struct AdbcError *error) +{ + GDALAdbcLoadDriverFunc load_driver_override = + GDALGetAdbcLoadDriverOverride(); + if (load_driver_override) + { + return load_driver_override(driver_name, entrypoint, OGR_ADBC_VERSION, + driver, error); + } + else + { +#if defined(OGR_ADBC_HAS_DRIVER_MANAGER) + return AdbcLoadDriver(driver_name, entrypoint, OGR_ADBC_VERSION, driver, + error); +#else + return ADBC_STATUS_NOT_IMPLEMENTED; +#endif + } +} + +} // namespace + +// Helper to wrap driver callbacks +#define ADBC_CALL(func, ...) m_driver.func(__VA_ARGS__) /************************************************************************/ /* ~OGRADBCDataset() */ @@ -26,9 +65,13 @@ OGRADBCDataset::~OGRADBCDataset() m_apoLayers.clear(); OGRADBCError error; if (m_connection) - AdbcConnectionRelease(m_connection.get(), error); + ADBC_CALL(ConnectionRelease, m_connection.get(), error); error.clear(); - AdbcDatabaseRelease(&m_database, error); + if (m_driver.release) + { + ADBC_CALL(DatabaseRelease, &m_database, error); + m_driver.release(&m_driver, error); + } } /************************************************************************/ @@ -82,7 +125,7 @@ OGRADBCDataset::CreateLayer(const char *pszStatement, const char *pszLayerName) } auto statement = std::make_unique(); - if (AdbcStatementNew(m_connection.get(), statement.get(), error) != + if (ADBC_CALL(StatementNew, m_connection.get(), statement.get(), error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcStatementNew() failed: %s", @@ -90,25 +133,25 @@ OGRADBCDataset::CreateLayer(const char *pszStatement, const char *pszLayerName) return nullptr; } - if (AdbcStatementSetSqlQuery(statement.get(), osStatement.c_str(), error) != - ADBC_STATUS_OK) + if (ADBC_CALL(StatementSetSqlQuery, statement.get(), osStatement.c_str(), + error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcStatementSetSqlQuery() failed: %s", error.message()); error.clear(); - AdbcStatementRelease(statement.get(), error); + ADBC_CALL(StatementRelease, statement.get(), error); return nullptr; } auto stream = std::make_unique(); int64_t rows_affected = -1; - if (AdbcStatementExecuteQuery(statement.get(), stream->get(), - &rows_affected, error) != ADBC_STATUS_OK) + if (ADBC_CALL(StatementExecuteQuery, statement.get(), stream->get(), + &rows_affected, error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcStatementExecuteQuery() failed: %s", error.message()); error.clear(); - AdbcStatementRelease(statement.get(), error); + ADBC_CALL(StatementRelease, statement.get(), error); return nullptr; } @@ -116,7 +159,7 @@ OGRADBCDataset::CreateLayer(const char *pszStatement, const char *pszLayerName) if (stream->get_schema(&schema) != 0) { CPLError(CE_Failure, CPLE_AppDefined, "get_schema() failed"); - AdbcStatementRelease(statement.get(), error); + ADBC_CALL(StatementRelease, statement.get(), error); return nullptr; } @@ -156,13 +199,6 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) { OGRADBCError error; - if (AdbcDatabaseNew(&m_database, error) != ADBC_STATUS_OK) - { - CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseNew() failed: %s", - error.message()); - return false; - } - const char *pszFilename = poOpenInfo->pszFilename; std::unique_ptr poTmpOpenInfo; if (STARTS_WITH(pszFilename, "ADBC:")) @@ -182,6 +218,7 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) const bool bIsParquet = OGRADBCDriverIsParquet(poOpenInfo) || EQUAL(CPLGetExtension(pszFilename), "parquet"); const bool bIsPostgreSQL = STARTS_WITH(pszFilename, "postgresql://"); + if (!pszADBCDriverName) { if (bIsDuckDB || bIsParquet) @@ -210,26 +247,44 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) } } - if (AdbcDatabaseSetOption(&m_database, "driver", pszADBCDriverName, - error) != ADBC_STATUS_OK) + // Load the driver + if (pszADBCDriverName && + (bIsDuckDB || bIsParquet || strstr(pszADBCDriverName, "duckdb"))) { - CPLError(CE_Failure, CPLE_AppDefined, - "AdbcDatabaseSetOption() failed: %s", error.message()); - return false; + if (OGRADBCLoadDriver(pszADBCDriverName, "duckdb_adbc_init", &m_driver, + error) != ADBC_STATUS_OK) + { + CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s", + error.message()); + return false; + } } - - if (bIsDuckDB || bIsParquet || strstr(pszADBCDriverName, "duckdb")) + else { - if (AdbcDatabaseSetOption(&m_database, "entrypoint", "duckdb_adbc_init", - error) != ADBC_STATUS_OK) + if (OGRADBCLoadDriver(pszADBCDriverName, nullptr, &m_driver, error) != + ADBC_STATUS_OK) { - CPLError(CE_Failure, CPLE_AppDefined, - "AdbcDatabaseSetOption() failed: %s", error.message()); + CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s", + error.message()); return false; } - if (AdbcDatabaseSetOption(&m_database, "path", - bIsParquet ? ":memory:" : pszFilename, - error) != ADBC_STATUS_OK) + } + + // Allocate the database + if (ADBC_CALL(DatabaseNew, &m_database, error) != ADBC_STATUS_OK) + { + CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseNew() failed: %s", + error.message()); + return false; + } + + // Set options + if (pszADBCDriverName && + (bIsDuckDB || bIsParquet || strstr(pszADBCDriverName, "duckdb"))) + { + if (ADBC_CALL(DatabaseSetOption, &m_database, "path", + bIsParquet ? ":memory:" : pszFilename, + error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseSetOption() failed: %s", error.message()); @@ -238,8 +293,8 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) } else if (pszFilename[0]) { - if (AdbcDatabaseSetOption(&m_database, "uri", pszFilename, error) != - ADBC_STATUS_OK) + if (ADBC_CALL(DatabaseSetOption, &m_database, "uri", pszFilename, + error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseSetOption() failed: %s", error.message()); @@ -252,9 +307,9 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) { if (STARTS_WITH_CI(pszKey, "ADBC_OPTION_")) { - if (AdbcDatabaseSetOption(&m_database, - pszKey + strlen("ADBC_OPTION_"), pszValue, - error) != ADBC_STATUS_OK) + if (ADBC_CALL(DatabaseSetOption, &m_database, + pszKey + strlen("ADBC_OPTION_"), pszValue, + error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseSetOption() failed: %s", error.message()); @@ -263,7 +318,7 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) } } - if (AdbcDatabaseInit(&m_database, error) != ADBC_STATUS_OK) + if (ADBC_CALL(DatabaseInit, &m_database, error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseInit() failed: %s", error.message()); @@ -271,14 +326,14 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) } m_connection = std::make_unique(); - if (AdbcConnectionNew(m_connection.get(), error) != ADBC_STATUS_OK) + if (ADBC_CALL(ConnectionNew, m_connection.get(), error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionNew() failed: %s", error.message()); return false; } - if (AdbcConnectionInit(m_connection.get(), &m_database, error) != + if (ADBC_CALL(ConnectionInit, m_connection.get(), &m_database, error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionInit() failed: %s", @@ -394,13 +449,13 @@ OGRLayer *OGRADBCDataset::GetLayerByName(const char *pszName) OGRADBCError error; auto objectsStream = std::make_unique(); - AdbcConnectionGetObjects(m_connection.get(), ADBC_OBJECT_DEPTH_TABLES, - /* catalog = */ nullptr, - /* db_schema = */ nullptr, - /* table_name = */ nullptr, - /* table_type = */ nullptr, - /* column_name = */ nullptr, objectsStream->get(), - error); + ADBC_CALL(ConnectionGetObjects, m_connection.get(), + ADBC_OBJECT_DEPTH_TABLES, + /* catalog = */ nullptr, + /* db_schema = */ nullptr, + /* table_name = */ nullptr, + /* table_type = */ nullptr, + /* column_name = */ nullptr, objectsStream->get(), error); ArrowSchema schema = {}; if (objectsStream->get_schema(&schema) != 0) @@ -510,3 +565,5 @@ OGRLayer *OGRADBCDataset::GetLayerByName(const char *pszName) m_apoLayers.emplace_back(std::move(poTableListLayer)); return m_apoLayers.back().get(); } + +#undef ADBC_CALL diff --git a/ogr/ogrsf_frmts/adbc/ogradbcdrivercore.cpp b/ogr/ogrsf_frmts/adbc/ogradbcdrivercore.cpp index 3be24128f199..f9e5a295aefa 100644 --- a/ogr/ogrsf_frmts/adbc/ogradbcdrivercore.cpp +++ b/ogr/ogrsf_frmts/adbc/ogradbcdrivercore.cpp @@ -12,6 +12,7 @@ #include "ogrsf_frmts.h" #include "ogradbcdrivercore.h" +#include "gdal_adbc.h" /************************************************************************/ /* IsDuckDB() */ @@ -55,12 +56,15 @@ bool OGRADBCDriverIsParquet(const GDALOpenInfo *poOpenInfo) int OGRADBCDriverIdentify(GDALOpenInfo *poOpenInfo) { - return (STARTS_WITH(poOpenInfo->pszFilename, "ADBC:") || - OGRADBCDriverIsDuckDB(poOpenInfo) || - OGRADBCDriverIsSQLite3(poOpenInfo) || - OGRADBCDriverIsParquet(poOpenInfo)) && - !STARTS_WITH(poOpenInfo->pszFilename, "/vsi") && - !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "mbtiles"); + return STARTS_WITH(poOpenInfo->pszFilename, "ADBC:") || + ((OGRADBCDriverIsDuckDB(poOpenInfo) || + OGRADBCDriverIsSQLite3(poOpenInfo) || + OGRADBCDriverIsParquet(poOpenInfo)) +#ifndef OGR_ADBC_HAS_DRIVER_MANAGER + && GDALGetAdbcLoadDriverOverride() != nullptr +#endif + && !STARTS_WITH(poOpenInfo->pszFilename, "/vsi") && + !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "mbtiles")); } /************************************************************************/ @@ -88,6 +92,9 @@ void OGRADBCDriverSetCommonMetadata(GDALDriver *poDriver) ""); poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "NATIVE OGRSQL SQLITE"); +#ifdef OGR_ADBC_HAS_DRIVER_MANAGER + poDriver->SetMetadataItem("HAS_ADBC_DRIVER_MANAGER", "YES"); +#endif poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); poDriver->pfnIdentify = OGRADBCDriverIdentify; diff --git a/ogr/ogrsf_frmts/adbc/ogradbclayer.cpp b/ogr/ogrsf_frmts/adbc/ogradbclayer.cpp index 3667c2ed5184..02a7b45d7c2e 100644 --- a/ogr/ogrsf_frmts/adbc/ogradbclayer.cpp +++ b/ogr/ogrsf_frmts/adbc/ogradbclayer.cpp @@ -6,6 +6,7 @@ * ****************************************************************************** * Copyright (c) 2024, Even Rouault + * Copyright (c) 2024, Dewey Dunnington * * SPDX-License-Identifier: MIT ****************************************************************************/ @@ -13,6 +14,8 @@ #include "ogr_adbc.h" #include "ogr_p.h" +#define ADBC_CALL(func, ...) m_poDS->m_driver.func(__VA_ARGS__) + /************************************************************************/ /* OGRADBCLayer() */ /************************************************************************/ @@ -45,7 +48,7 @@ OGRADBCLayer::~OGRADBCLayer() { OGRADBCError error; if (m_statement) - AdbcStatementRelease(m_statement.get(), error); + ADBC_CALL(StatementRelease, m_statement.get(), error); if (m_schema.release) m_schema.release(&m_schema); } @@ -173,8 +176,8 @@ bool OGRADBCLayer::GetArrowStreamInternal(struct ArrowArrayStream *out_stream) { OGRADBCError error; int64_t rows_affected = -1; - if (AdbcStatementExecuteQuery(m_statement.get(), out_stream, &rows_affected, - error) != ADBC_STATUS_OK) + if (ADBC_CALL(StatementExecuteQuery, m_statement.get(), out_stream, + &rows_affected, error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, "AdbcStatementExecuteQuery() failed: %s", error.message()); @@ -254,3 +257,5 @@ GIntBig OGRADBCLayer::GetFeatureCountParquet() return -1; } + +#undef ADBC_CALL