From 8d86043696960632c662345c3dff7066367eb651 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 16 Oct 2024 10:19:15 +0200 Subject: [PATCH] Add GDALSetAdbcDriverInitFunc() and use it in OGR ADBC driver --- doc/source/api/vector_c_api.rst | 3 ++ doc/source/drivers/vector/adbc.rst | 10 ++++ gcore/CMakeLists.txt | 2 + gcore/gdal_adbc.cpp | 62 +++++++++++++++++++++++++ gcore/gdal_adbc.h | 41 ++++++++++++++++ ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp | 30 ++++++++++-- 6 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 gcore/gdal_adbc.cpp create mode 100644 gcore/gdal_adbc.h 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..078a64e00da8 100644 --- a/doc/source/drivers/vector/adbc.rst +++ b/doc/source/drivers/vector/adbc.rst @@ -80,6 +80,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 entrypoint +------------------------ + +A custom driver entrypoint can be specified by applications by calling +:cpp:func:`GDALSetAdbcDriverInitFunc` (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 specifying the ADBC driver for all calls in the +same thread. Setting both the init function and the ``ADBC_DRIVER`` open +option is not supported. + Examples -------- diff --git a/gcore/CMakeLists.txt b/gcore/CMakeLists.txt index a61970e9e1f5..dd2a81842638 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 @@ -194,6 +195,7 @@ target_public_header( gdalgeorefpamdataset.h gdal_mdreader.h gdalsubdatasetinfo.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..2c74afef233e --- /dev/null +++ b/gcore/gdal_adbc.cpp @@ -0,0 +1,62 @@ +/****************************************************************************** + * Name: gdal_adbc.h + * Project: GDAL Core + * Purpose: GDAL Core ADBC related declarations. + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (c) 2024, Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#include "cpl_port.h" + +// Very minimal extract of adbc.h +#define ADBC + +CPL_C_START + +typedef uint8_t AdbcStatusCode; +struct AdbcError; +typedef AdbcStatusCode (*AdbcDriverInitFunc)(int version, void *driver, + struct AdbcError *error); + +CPL_C_END + +#include "gdal_adbc.h" + +//! Thread local ADBC driver initialization function +static thread_local AdbcDriverInitFunc tlAdbcDriverInitFunc = nullptr; + +/************************************************************************/ +/* GDALSetAdbcDriverInitFunc() */ +/************************************************************************/ + +/** Sets the ADBC driver initialization function that should be used during + * the next calls to the OGR ADBC driver. + * + * This is a thread-local setting. + * + * When set, it is honored by the OGR ADBC driver to pass the specified + * initialization function as the argument of + * AdbcDriverManagerDatabaseSetInitFunc() + * + * Setting it to NULL resets to the the default behaviour of the ADBC driver, + * which is to honor the ADBC_DRIVER open option. + */ +void GDALSetAdbcDriverInitFunc(AdbcDriverInitFunc init_func) +{ + tlAdbcDriverInitFunc = init_func; +} + +/************************************************************************/ +/* GDALGetAdbcDriverInitFunc() */ +/************************************************************************/ + +/** Gets the ADBC driver initialization function for the current thread. + */ +AdbcDriverInitFunc GDALGetAdbcDriverInitFunc() +{ + return tlAdbcDriverInitFunc; +} diff --git a/gcore/gdal_adbc.h b/gcore/gdal_adbc.h new file mode 100644 index 000000000000..c1f336be63c7 --- /dev/null +++ b/gcore/gdal_adbc.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * Name: gdal_adbc.h + * Project: GDAL Core + * Purpose: GDAL Core ADBC related declarations. + * Author: Even Rouault + * + ****************************************************************************** + * Copyright (c) 2024, Even Rouault + * + * 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) + * + * This header can only be used if the ADBC macro is defined, indicating that + * the abdc.h header has already been included before. + * + * \since GDAL 3.11 + */ + +#include "cpl_port.h" + +#ifdef ADBC + +CPL_C_START + +void CPL_DLL GDALSetAdbcDriverInitFunc(AdbcDriverInitFunc init_func); + +AdbcDriverInitFunc CPL_DLL GDALGetAdbcDriverInitFunc(void); + +CPL_C_END + +#endif + +#endif diff --git a/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp b/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp index 8410f395ea45..a9cfc1e73d59 100644 --- a/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp +++ b/ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp @@ -15,6 +15,7 @@ #include "ogr_mem.h" #include "ogr_p.h" #include "cpl_json.h" +#include "gdal_adbc.h" /************************************************************************/ /* ~OGRADBCDataset() */ @@ -182,7 +183,28 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) const bool bIsParquet = OGRADBCDriverIsParquet(poOpenInfo) || EQUAL(CPLGetExtension(pszFilename), "parquet"); const bool bIsPostgreSQL = STARTS_WITH(pszFilename, "postgresql://"); - if (!pszADBCDriverName) + + AdbcDriverInitFunc pfnDriverInitFunc = GDALGetAdbcDriverInitFunc(); + if (pfnDriverInitFunc && pszADBCDriverName) + { + CPLError(CE_Failure, CPLE_NotSupported, + "Both a AdbcDriverInitFunc and ADBC_DRIVER open option are " + "defined. This is not supported"); + return false; + } + + if (pfnDriverInitFunc) + { + if (AdbcDriverManagerDatabaseSetInitFunc(&m_database, pfnDriverInitFunc, + error) != ADBC_STATUS_OK) + { + CPLError(CE_Failure, CPLE_AppDefined, + "AdbcDriverManagerDatabaseSetInitFunc() failed: %s", + error.message()); + return false; + } + } + else if (!pszADBCDriverName) { if (bIsDuckDB || bIsParquet) { @@ -210,7 +232,8 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) } } - if (AdbcDatabaseSetOption(&m_database, "driver", pszADBCDriverName, + if (pszADBCDriverName && + AdbcDatabaseSetOption(&m_database, "driver", pszADBCDriverName, error) != ADBC_STATUS_OK) { CPLError(CE_Failure, CPLE_AppDefined, @@ -218,7 +241,8 @@ bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo) return false; } - if (bIsDuckDB || bIsParquet || strstr(pszADBCDriverName, "duckdb")) + if (pszADBCDriverName && + (bIsDuckDB || bIsParquet || strstr(pszADBCDriverName, "duckdb"))) { if (AdbcDatabaseSetOption(&m_database, "entrypoint", "duckdb_adbc_init", error) != ADBC_STATUS_OK)