LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/adbc - ogradbcdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 40 324 12.3 %
Date: 2025-07-11 10:11:13 Functions: 5 9 55.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Arrow Database Connectivity driver
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  * Copyright (c) 2024, Dewey Dunnington <dewey@voltrondata.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogr_adbc.h"
      15             : #include "ogradbcdrivercore.h"
      16             : #include "memdataset.h"
      17             : #include "ogr_p.h"
      18             : #include "cpl_error.h"
      19             : #include "cpl_json.h"
      20             : #include "gdal_adbc.h"
      21             : 
      22             : #if defined(OGR_ADBC_HAS_DRIVER_MANAGER)
      23             : #include <arrow-adbc/adbc_driver_manager.h>
      24             : #endif
      25             : 
      26             : #define OGR_ADBC_VERSION ADBC_VERSION_1_1_0
      27             : static_assert(sizeof(AdbcDriver) == ADBC_DRIVER_1_1_0_SIZE);
      28             : 
      29             : namespace
      30             : {
      31             : 
      32             : #if !defined(OGR_ADBC_HAS_DRIVER_MANAGER)
      33           0 : AdbcStatusCode OGRDuckDBLoadDriver(const char *driver_name, void *driver,
      34             :                                    struct AdbcError *error)
      35             : {
      36           0 :     void *load_handle = CPLGetSymbol(driver_name, "duckdb_adbc_init");
      37           0 :     if (!load_handle)
      38             :     {
      39           0 :         return ADBC_STATUS_INTERNAL;
      40             :     }
      41             : 
      42           0 :     AdbcDriverInitFunc init_func =
      43             :         reinterpret_cast<AdbcDriverInitFunc>(load_handle);
      44           0 :     return init_func(OGR_ADBC_VERSION, driver, error);
      45             : }
      46             : #endif
      47             : 
      48           1 : AdbcStatusCode OGRADBCLoadDriver(const char *driver_name,
      49             :                                  const char *entrypoint, void *driver,
      50             :                                  struct AdbcError *error)
      51             : {
      52             :     GDALAdbcLoadDriverFunc load_driver_override =
      53           1 :         GDALGetAdbcLoadDriverOverride();
      54           1 :     if (load_driver_override)
      55             :     {
      56           0 :         return load_driver_override(driver_name, entrypoint, OGR_ADBC_VERSION,
      57           0 :                                     driver, error);
      58             :     }
      59             :     else
      60             :     {
      61             : #if defined(OGR_ADBC_HAS_DRIVER_MANAGER)
      62             :         return AdbcLoadDriver(driver_name, entrypoint, OGR_ADBC_VERSION, driver,
      63             :                               error);
      64             : #else
      65             :         // If the driver is for DuckDB, use a minimal loading function, which
      66             :         // doesn't rely on the ADBC driver manager.
      67           1 :         if (strstr(driver_name, "duckdb"))
      68             :         {
      69           0 :             return OGRDuckDBLoadDriver(driver_name, driver, error);
      70             :         }
      71           1 :         return ADBC_STATUS_NOT_IMPLEMENTED;
      72             : #endif
      73             :     }
      74             : }
      75             : 
      76             : }  // namespace
      77             : 
      78             : // Helper to wrap driver callbacks
      79             : #define ADBC_CALL(func, ...) m_driver.func(__VA_ARGS__)
      80             : 
      81             : /************************************************************************/
      82             : /*                           ~OGRADBCDataset()                          */
      83             : /************************************************************************/
      84             : 
      85           2 : OGRADBCDataset::~OGRADBCDataset()
      86             : {
      87             :     // Layers must be closed before the connection
      88           1 :     m_apoLayers.clear();
      89           1 :     OGRADBCError error;
      90           1 :     if (m_connection)
      91           0 :         ADBC_CALL(ConnectionRelease, m_connection.get(), error);
      92           1 :     error.clear();
      93           1 :     if (m_driver.release)
      94             :     {
      95           0 :         ADBC_CALL(DatabaseRelease, &m_database, error);
      96           0 :         m_driver.release(&m_driver, error);
      97             :     }
      98           2 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                           CreateLayer()                              */
     102             : /************************************************************************/
     103             : 
     104             : std::unique_ptr<OGRADBCLayer>
     105           0 : OGRADBCDataset::CreateLayer(const char *pszStatement, const char *pszLayerName,
     106             :                             bool bInternalUse)
     107             : {
     108             : 
     109           0 :     OGRADBCError error;
     110             : 
     111           0 :     CPLString osStatement(pszStatement);
     112           0 :     if (!m_osParquetFilename.empty())
     113             :     {
     114           0 :         const char *pszSrcLayerName = m_apoLayers.size() == 1
     115           0 :                                           ? m_apoLayers[0]->GetDescription()
     116           0 :                                           : pszLayerName;
     117             :         // Substitute the OGR layer name with the DuckDB expected filename,
     118             :         // single-quoted
     119             :         const std::string osFrom =
     120           0 :             std::string(" FROM ").append(pszSrcLayerName);
     121           0 :         const auto nPos = osStatement.ifind(osFrom);
     122           0 :         if (nPos != std::string::npos)
     123             :         {
     124             :             osStatement =
     125           0 :                 osStatement.substr(0, nPos)
     126           0 :                     .append(" FROM '")
     127           0 :                     .append(OGRDuplicateCharacter(m_osParquetFilename, '\''))
     128           0 :                     .append("'")
     129           0 :                     .append(osStatement.substr(nPos + osFrom.size()));
     130             :         }
     131             :         else
     132             :         {
     133             :             const std::string osFrom2 =
     134           0 :                 std::string(" FROM \"")
     135           0 :                     .append(OGRDuplicateCharacter(pszSrcLayerName, '"'))
     136           0 :                     .append("\"");
     137           0 :             const auto nPos2 = osStatement.ifind(osFrom2);
     138           0 :             if (nPos2 != std::string::npos)
     139             :             {
     140             :                 osStatement =
     141           0 :                     osStatement.substr(0, nPos2)
     142           0 :                         .append(" FROM '")
     143             :                         .append(
     144           0 :                             OGRDuplicateCharacter(m_osParquetFilename, '\''))
     145           0 :                         .append("'")
     146           0 :                         .append(osStatement.substr(nPos2 + osFrom2.size()));
     147             :             }
     148             :         }
     149             :     }
     150             : 
     151           0 :     auto statement = std::make_unique<AdbcStatement>();
     152           0 :     if (ADBC_CALL(StatementNew, m_connection.get(), statement.get(), error) !=
     153             :         ADBC_STATUS_OK)
     154             :     {
     155           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcStatementNew() failed: %s",
     156             :                  error.message());
     157           0 :         return nullptr;
     158             :     }
     159             : 
     160           0 :     if (ADBC_CALL(StatementSetSqlQuery, statement.get(), osStatement.c_str(),
     161           0 :                   error) != ADBC_STATUS_OK)
     162             :     {
     163           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     164             :                  "AdbcStatementSetSqlQuery() failed: %s", error.message());
     165           0 :         error.clear();
     166           0 :         ADBC_CALL(StatementRelease, statement.get(), error);
     167           0 :         return nullptr;
     168             :     }
     169             : 
     170           0 :     auto stream = std::make_unique<OGRArrowArrayStream>();
     171           0 :     int64_t rows_affected = -1;
     172           0 :     if (ADBC_CALL(StatementExecuteQuery, statement.get(), stream->get(),
     173           0 :                   &rows_affected, error) != ADBC_STATUS_OK)
     174             :     {
     175           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     176             :                  "AdbcStatementExecuteQuery() failed: %s", error.message());
     177           0 :         error.clear();
     178           0 :         ADBC_CALL(StatementRelease, statement.get(), error);
     179           0 :         return nullptr;
     180             :     }
     181             : 
     182           0 :     ArrowSchema schema = {};
     183           0 :     if (stream->get_schema(&schema) != 0)
     184             :     {
     185           0 :         CPLError(CE_Failure, CPLE_AppDefined, "get_schema() failed");
     186           0 :         ADBC_CALL(StatementRelease, statement.get(), error);
     187           0 :         return nullptr;
     188             :     }
     189             : 
     190             :     return std::make_unique<OGRADBCLayer>(
     191           0 :         this, pszLayerName, osStatement.c_str(), std::move(statement),
     192           0 :         std::move(stream), &schema, bInternalUse);
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                             ExecuteSQL()                             */
     197             : /************************************************************************/
     198             : 
     199           0 : OGRLayer *OGRADBCDataset::ExecuteSQL(const char *pszStatement,
     200             :                                      OGRGeometry *poSpatialFilter,
     201             :                                      const char *pszDialect)
     202             : {
     203           0 :     if (pszDialect && pszDialect[0] != 0 && !EQUAL(pszDialect, "NATIVE"))
     204             :     {
     205           0 :         return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter,
     206           0 :                                        pszDialect);
     207             :     }
     208             : 
     209           0 :     auto poLayer = CreateLayer(pszStatement, "RESULTSET", false);
     210           0 :     if (poLayer && poSpatialFilter)
     211             :     {
     212           0 :         if (poLayer->GetGeomType() == wkbNone)
     213           0 :             return nullptr;
     214           0 :         poLayer->SetSpatialFilter(poSpatialFilter);
     215             :     }
     216           0 :     return poLayer.release();
     217             : }
     218             : 
     219             : /************************************************************************/
     220             : /*                       IsParquetExtension()                           */
     221             : /************************************************************************/
     222             : 
     223           1 : static bool IsParquetExtension(const char *pszStr)
     224             : {
     225           1 :     const std::string osExt = CPLGetExtensionSafe(pszStr);
     226           2 :     return EQUAL(osExt.c_str(), "parquet") || EQUAL(osExt.c_str(), "parq");
     227             : }
     228             : 
     229             : /************************************************************************/
     230             : /*                                Open()                                */
     231             : /************************************************************************/
     232             : 
     233           1 : bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo)
     234             : {
     235           1 :     OGRADBCError error;
     236             : 
     237           1 :     const char *pszFilename = poOpenInfo->pszFilename;
     238           1 :     std::unique_ptr<GDALOpenInfo> poTmpOpenInfo;
     239           1 :     if (STARTS_WITH(pszFilename, "ADBC:"))
     240             :     {
     241           1 :         pszFilename += strlen("ADBC:");
     242             :         poTmpOpenInfo =
     243           1 :             std::make_unique<GDALOpenInfo>(pszFilename, GA_ReadOnly);
     244           1 :         poTmpOpenInfo->papszOpenOptions = poOpenInfo->papszOpenOptions;
     245           1 :         poOpenInfo = poTmpOpenInfo.get();
     246             :     }
     247             :     const char *pszADBCDriverName =
     248           1 :         CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ADBC_DRIVER");
     249           1 :     m_bIsDuckDBDataset = OGRADBCDriverIsDuckDB(poOpenInfo);
     250             :     const bool bIsSQLite3 =
     251           2 :         (pszADBCDriverName && EQUAL(pszADBCDriverName, "adbc_driver_sqlite")) ||
     252           1 :         OGRADBCDriverIsSQLite3(poOpenInfo);
     253             :     bool bIsParquet =
     254           1 :         OGRADBCDriverIsParquet(poOpenInfo) || IsParquetExtension(pszFilename);
     255           1 :     const char *pszSQL = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "SQL");
     256           1 :     if (!bIsParquet && pszSQL)
     257             :     {
     258           0 :         CPLString osSQL(pszSQL);
     259           0 :         auto iPos = osSQL.find("FROM '");
     260           0 :         if (iPos != std::string::npos)
     261             :         {
     262           0 :             iPos += strlen("FROM '");
     263           0 :             const auto iPos2 = osSQL.find("'", iPos);
     264           0 :             if (iPos2 != std::string::npos)
     265             :             {
     266           0 :                 std::string osFilename = osSQL.substr(iPos, iPos2 - iPos);
     267           0 :                 if (IsParquetExtension(osFilename.c_str()))
     268             :                 {
     269           0 :                     m_osParquetFilename = std::move(osFilename);
     270           0 :                     bIsParquet = true;
     271             :                 }
     272             :             }
     273             :         }
     274             :     }
     275           1 :     const bool bIsPostgreSQL = STARTS_WITH(pszFilename, "postgresql://");
     276             : 
     277           1 :     if (!pszADBCDriverName)
     278             :     {
     279           0 :         if (m_bIsDuckDBDataset || bIsParquet)
     280             :         {
     281           0 :             pszADBCDriverName =
     282             : #ifdef _WIN32
     283             :                 "duckdb.dll"
     284             : #elif defined(__MACH__) && defined(__APPLE__)
     285             :                 "libduckdb.dylib"
     286             : #else
     287             :                 "libduckdb.so"
     288             : #endif
     289             :                 ;
     290             :         }
     291           0 :         else if (bIsPostgreSQL)
     292           0 :             pszADBCDriverName = "adbc_driver_postgresql";
     293           0 :         else if (bIsSQLite3)
     294             :         {
     295           0 :             pszADBCDriverName = "adbc_driver_sqlite";
     296             :         }
     297             :         else
     298             :         {
     299           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     300             :                      "Open option ADBC_DRIVER must be specified");
     301           0 :             return false;
     302             :         }
     303             :     }
     304             : 
     305           1 :     m_bIsDuckDBDriver =
     306           2 :         m_bIsDuckDBDataset || bIsParquet ||
     307           1 :         (pszADBCDriverName && strstr(pszADBCDriverName, "duckdb"));
     308             : 
     309             :     // Load the driver
     310           1 :     if (m_bIsDuckDBDriver)
     311             :     {
     312           0 :         if (OGRADBCLoadDriver(pszADBCDriverName, "duckdb_adbc_init", &m_driver,
     313           0 :                               error) != ADBC_STATUS_OK)
     314             :         {
     315           0 :             CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s",
     316             :                      error.message());
     317           0 :             return false;
     318             :         }
     319             :     }
     320             :     else
     321             :     {
     322           1 :         if (OGRADBCLoadDriver(pszADBCDriverName, nullptr, &m_driver, error) !=
     323             :             ADBC_STATUS_OK)
     324             :         {
     325           1 :             CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s",
     326             :                      error.message());
     327           1 :             return false;
     328             :         }
     329             :     }
     330             : 
     331             :     // Allocate the database
     332           0 :     if (ADBC_CALL(DatabaseNew, &m_database, error) != ADBC_STATUS_OK)
     333             :     {
     334           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseNew() failed: %s",
     335             :                  error.message());
     336           0 :         return false;
     337             :     }
     338             : 
     339             :     // Set options
     340           0 :     if (m_bIsDuckDBDriver)
     341             :     {
     342           0 :         if (ADBC_CALL(DatabaseSetOption, &m_database, "path",
     343             :                       bIsParquet ? ":memory:" : pszFilename,
     344           0 :                       error) != ADBC_STATUS_OK)
     345             :         {
     346           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     347             :                      "AdbcDatabaseSetOption() failed: %s", error.message());
     348           0 :             return false;
     349             :         }
     350             :     }
     351           0 :     else if (pszFilename[0])
     352             :     {
     353           0 :         if (ADBC_CALL(DatabaseSetOption, &m_database, "uri", pszFilename,
     354           0 :                       error) != ADBC_STATUS_OK)
     355             :         {
     356           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     357             :                      "AdbcDatabaseSetOption() failed: %s", error.message());
     358           0 :             return false;
     359             :         }
     360             :     }
     361             : 
     362           0 :     for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(
     363           0 :              static_cast<CSLConstList>(poOpenInfo->papszOpenOptions)))
     364             :     {
     365           0 :         if (STARTS_WITH_CI(pszKey, "ADBC_OPTION_"))
     366             :         {
     367           0 :             if (ADBC_CALL(DatabaseSetOption, &m_database,
     368             :                           pszKey + strlen("ADBC_OPTION_"), pszValue,
     369           0 :                           error) != ADBC_STATUS_OK)
     370             :             {
     371           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     372             :                          "AdbcDatabaseSetOption() failed: %s", error.message());
     373           0 :                 return false;
     374             :             }
     375             :         }
     376             :     }
     377             : 
     378           0 :     if (ADBC_CALL(DatabaseInit, &m_database, error) != ADBC_STATUS_OK)
     379             :     {
     380           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseInit() failed: %s",
     381             :                  error.message());
     382           0 :         return false;
     383             :     }
     384             : 
     385           0 :     m_connection = std::make_unique<AdbcConnection>();
     386           0 :     if (ADBC_CALL(ConnectionNew, m_connection.get(), error) != ADBC_STATUS_OK)
     387             :     {
     388           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionNew() failed: %s",
     389             :                  error.message());
     390           0 :         return false;
     391             :     }
     392             : 
     393           0 :     if (ADBC_CALL(ConnectionInit, m_connection.get(), &m_database, error) !=
     394             :         ADBC_STATUS_OK)
     395             :     {
     396           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionInit() failed: %s",
     397             :                  error.message());
     398           0 :         return false;
     399             :     }
     400             : 
     401           0 :     char **papszPreludeStatements = CSLFetchNameValueMultiple(
     402           0 :         poOpenInfo->papszOpenOptions, "PRELUDE_STATEMENTS");
     403           0 :     for (const char *pszStatement :
     404           0 :          cpl::Iterate(CSLConstList(papszPreludeStatements)))
     405             :     {
     406           0 :         CreateInternalLayer(pszStatement);
     407             :     }
     408           0 :     CSLDestroy(papszPreludeStatements);
     409           0 :     if (m_bIsDuckDBDriver && CPLTestBool(CPLGetConfigOption(
     410             :                                  "OGR_ADBC_AUTO_LOAD_DUCKDB_SPATIAL", "ON")))
     411             :     {
     412             :         auto poTmpLayer =
     413             :             CreateInternalLayer("SELECT 1 FROM duckdb_extensions() WHERE "
     414           0 :                                 "extension_name='spatial' AND loaded = false");
     415           0 :         if (poTmpLayer && std::unique_ptr<OGRFeature>(
     416           0 :                               poTmpLayer->GetNextFeature()) != nullptr)
     417             :         {
     418           0 :             CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     419           0 :             CreateInternalLayer("LOAD spatial");
     420             :         }
     421             : 
     422             :         poTmpLayer =
     423           0 :             CreateInternalLayer("SELECT 1 FROM duckdb_extensions() WHERE "
     424           0 :                                 "extension_name='spatial' AND loaded = true");
     425           0 :         m_bSpatialLoaded =
     426           0 :             poTmpLayer && std::unique_ptr<OGRFeature>(
     427           0 :                               poTmpLayer->GetNextFeature()) != nullptr;
     428             :     }
     429             : 
     430           0 :     std::string osLayerName = "RESULTSET";
     431           0 :     std::string osSQL;
     432           0 :     bool bIsParquetLayer = false;
     433           0 :     if (bIsParquet)
     434             :     {
     435           0 :         if (m_osParquetFilename.empty())
     436           0 :             m_osParquetFilename = pszFilename;
     437           0 :         osLayerName = CPLGetBasenameSafe(m_osParquetFilename.c_str());
     438           0 :         if (osLayerName == "*")
     439           0 :             osLayerName = CPLGetBasenameSafe(
     440           0 :                 CPLGetDirnameSafe(m_osParquetFilename.c_str()).c_str());
     441           0 :         if (!pszSQL)
     442             :         {
     443             :             osSQL =
     444             :                 CPLSPrintf("SELECT * FROM read_parquet('%s')",
     445           0 :                            OGRDuplicateCharacter(pszFilename, '\'').c_str());
     446           0 :             pszSQL = osSQL.c_str();
     447           0 :             bIsParquetLayer = true;
     448             :         }
     449             :     }
     450             : 
     451           0 :     if (pszSQL)
     452             :     {
     453           0 :         if (pszSQL[0])
     454             :         {
     455           0 :             std::unique_ptr<OGRADBCLayer> poLayer;
     456           0 :             if ((bIsParquet || m_bIsDuckDBDataset) && m_bSpatialLoaded)
     457             :             {
     458           0 :                 std::string osErrorMsg;
     459             :                 {
     460           0 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     461           0 :                     poLayer = CreateLayer(pszSQL, osLayerName.c_str(), false);
     462           0 :                     if (!poLayer)
     463           0 :                         osErrorMsg = CPLGetLastErrorMsg();
     464             :                 }
     465           0 :                 if (!poLayer)
     466             :                 {
     467           0 :                     CPLDebug("ADBC",
     468             :                              "Connecting with 'LOAD spatial' did not work "
     469             :                              "(%s). Retrying without it",
     470             :                              osErrorMsg.c_str());
     471           0 :                     ADBC_CALL(ConnectionRelease, m_connection.get(), error);
     472           0 :                     m_connection.reset();
     473             : 
     474           0 :                     ADBC_CALL(DatabaseRelease, &m_database, error);
     475           0 :                     memset(&m_database, 0, sizeof(m_database));
     476             : 
     477           0 :                     if (ADBC_CALL(DatabaseNew, &m_database, error) !=
     478             :                         ADBC_STATUS_OK)
     479             :                     {
     480           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     481             :                                  "AdbcDatabaseNew() failed: %s",
     482             :                                  error.message());
     483           0 :                         return false;
     484             :                     }
     485           0 :                     if (ADBC_CALL(DatabaseSetOption, &m_database, "path",
     486           0 :                                   ":memory:", error) != ADBC_STATUS_OK)
     487             :                     {
     488           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     489             :                                  "AdbcDatabaseSetOption() failed: %s",
     490             :                                  error.message());
     491           0 :                         return false;
     492             :                     }
     493             : 
     494           0 :                     if (ADBC_CALL(DatabaseInit, &m_database, error) !=
     495             :                         ADBC_STATUS_OK)
     496             :                     {
     497           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     498             :                                  "AdbcDatabaseInit() failed: %s",
     499             :                                  error.message());
     500           0 :                         return false;
     501             :                     }
     502             : 
     503           0 :                     m_connection = std::make_unique<AdbcConnection>();
     504           0 :                     if (ADBC_CALL(ConnectionNew, m_connection.get(), error) !=
     505             :                         ADBC_STATUS_OK)
     506             :                     {
     507           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     508             :                                  "AdbcConnectionNew() failed: %s",
     509             :                                  error.message());
     510           0 :                         return false;
     511             :                     }
     512             : 
     513           0 :                     if (ADBC_CALL(ConnectionInit, m_connection.get(),
     514           0 :                                   &m_database, error) != ADBC_STATUS_OK)
     515             :                     {
     516           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     517             :                                  "AdbcConnectionInit() failed: %s",
     518             :                                  error.message());
     519           0 :                         return false;
     520             :                     }
     521             :                 }
     522             :             }
     523           0 :             if (!poLayer)
     524             :             {
     525           0 :                 poLayer = CreateLayer(pszSQL, osLayerName.c_str(), false);
     526           0 :                 if (!poLayer)
     527           0 :                     return false;
     528             :             }
     529             : 
     530           0 :             poLayer->m_bIsParquetLayer = bIsParquetLayer;
     531           0 :             m_apoLayers.emplace_back(std::move(poLayer));
     532             :         }
     533             :     }
     534           0 :     else if (m_bIsDuckDBDataset || bIsSQLite3)
     535             :     {
     536             :         auto poLayerList = CreateInternalLayer(
     537           0 :             "SELECT name FROM sqlite_master WHERE type IN ('table', 'view')");
     538           0 :         if (!poLayerList || poLayerList->GetLayerDefn()->GetFieldCount() != 1)
     539             :         {
     540           0 :             return false;
     541             :         }
     542             : 
     543           0 :         for (const auto &poFeature : poLayerList.get())
     544             :         {
     545           0 :             const char *pszLayerName = poFeature->GetFieldAsString(0);
     546           0 :             if (bIsSQLite3 && EQUAL(pszLayerName, "SpatialIndex"))
     547           0 :                 continue;
     548             :             const std::string osStatement =
     549             :                 CPLSPrintf("SELECT * FROM \"%s\"",
     550           0 :                            OGRDuplicateCharacter(pszLayerName, '"').c_str());
     551           0 :             CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
     552             :             auto poLayer =
     553           0 :                 CreateLayer(osStatement.c_str(), pszLayerName, false);
     554           0 :             if (poLayer)
     555             :             {
     556           0 :                 m_apoLayers.emplace_back(std::move(poLayer));
     557             :             }
     558           0 :         }
     559             :     }
     560           0 :     else if (bIsPostgreSQL)
     561             :     {
     562             :         auto poLayerList = CreateInternalLayer(
     563             :             "SELECT n.nspname, c.relname FROM pg_class c "
     564             :             "JOIN pg_namespace n ON c.relnamespace = n.oid "
     565             :             "AND c.relkind in ('r','v','m','f') "
     566             :             "AND n.nspname NOT IN ('pg_catalog', 'information_schema') "
     567           0 :             "ORDER BY c.oid");
     568           0 :         if (!poLayerList || poLayerList->GetLayerDefn()->GetFieldCount() != 2)
     569             :         {
     570           0 :             return false;
     571             :         }
     572             : 
     573           0 :         for (const auto &poFeature : poLayerList.get())
     574             :         {
     575           0 :             const char *pszNamespace = poFeature->GetFieldAsString(0);
     576           0 :             const char *pszTableName = poFeature->GetFieldAsString(1);
     577             :             const std::string osStatement =
     578             :                 CPLSPrintf("SELECT * FROM \"%s\".\"%s\"",
     579           0 :                            OGRDuplicateCharacter(pszNamespace, '"').c_str(),
     580           0 :                            OGRDuplicateCharacter(pszTableName, '"').c_str());
     581             : 
     582           0 :             CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
     583             :             auto poLayer = CreateLayer(
     584             :                 osStatement.c_str(),
     585           0 :                 CPLSPrintf("%s.%s", pszNamespace, pszTableName), false);
     586           0 :             if (poLayer)
     587             :             {
     588           0 :                 m_apoLayers.emplace_back(std::move(poLayer));
     589             :             }
     590             :         }
     591             :     }
     592             : 
     593           0 :     return true;
     594             : }
     595             : 
     596             : /************************************************************************/
     597             : /*                         GetLayerByName()                             */
     598             : /************************************************************************/
     599             : 
     600           0 : OGRLayer *OGRADBCDataset::GetLayerByName(const char *pszName)
     601             : {
     602           0 :     OGRLayer *poLayer = GDALDataset::GetLayerByName(pszName);
     603           0 :     if (poLayer || !EQUAL(pszName, "table_list"))
     604           0 :         return poLayer;
     605             : 
     606           0 :     OGRADBCError error;
     607           0 :     auto objectsStream = std::make_unique<OGRArrowArrayStream>();
     608           0 :     ADBC_CALL(ConnectionGetObjects, m_connection.get(),
     609             :               ADBC_OBJECT_DEPTH_TABLES,
     610             :               /* catalog = */ nullptr,
     611             :               /* db_schema = */ nullptr,
     612             :               /* table_name = */ nullptr,
     613             :               /* table_type = */ nullptr,
     614             :               /* column_name = */ nullptr, objectsStream->get(), error);
     615             : 
     616           0 :     ArrowSchema schema = {};
     617           0 :     if (objectsStream->get_schema(&schema) != 0)
     618             :     {
     619           0 :         CPLError(CE_Failure, CPLE_AppDefined, "get_schema() failed");
     620           0 :         return nullptr;
     621             :     }
     622             : 
     623           0 :     auto statement = std::make_unique<AdbcStatement>();
     624           0 :     OGRADBCLayer tmpLayer(this, "", "", std::move(statement),
     625           0 :                           std::move(objectsStream), &schema,
     626           0 :                           /* bInternalUse = */ true);
     627           0 :     const auto tmpLayerDefn = tmpLayer.GetLayerDefn();
     628           0 :     if (tmpLayerDefn->GetFieldIndex("catalog_name") < 0 ||
     629           0 :         tmpLayerDefn->GetFieldIndex("catalog_db_schemas") < 0)
     630             :     {
     631           0 :         return nullptr;
     632             :     }
     633             : 
     634             :     auto poTableListLayer =
     635           0 :         std::make_unique<OGRMemLayer>("table_list", nullptr, wkbNone);
     636             :     {
     637           0 :         OGRFieldDefn oField("catalog_name", OFTString);
     638           0 :         poTableListLayer->CreateField(&oField);
     639             :     }
     640             :     {
     641           0 :         OGRFieldDefn oField("schema_name", OFTString);
     642           0 :         poTableListLayer->CreateField(&oField);
     643             :     }
     644             :     {
     645           0 :         OGRFieldDefn oField("table_name", OFTString);
     646           0 :         poTableListLayer->CreateField(&oField);
     647             :     }
     648             :     {
     649           0 :         OGRFieldDefn oField("table_type", OFTString);
     650           0 :         poTableListLayer->CreateField(&oField);
     651             :     }
     652             : 
     653           0 :     for (const auto &poFeature : tmpLayer)
     654             :     {
     655             :         const char *pszCatalogName =
     656           0 :             poFeature->GetFieldAsString("catalog_name");
     657             :         const char *pszCatalogDBSchemas =
     658           0 :             poFeature->GetFieldAsString("catalog_db_schemas");
     659           0 :         if (pszCatalogDBSchemas)
     660             :         {
     661           0 :             CPLJSONDocument oDoc;
     662           0 :             if (oDoc.LoadMemory(pszCatalogDBSchemas))
     663             :             {
     664           0 :                 auto oRoot = oDoc.GetRoot();
     665           0 :                 if (oRoot.GetType() == CPLJSONObject::Type::Array)
     666             :                 {
     667           0 :                     for (const auto &oSchema : oRoot.ToArray())
     668             :                     {
     669           0 :                         if (oSchema.GetType() == CPLJSONObject::Type::Object)
     670             :                         {
     671             :                             const std::string osSchemaName =
     672           0 :                                 oSchema.GetString("schema_name");
     673             :                             const auto oTables =
     674           0 :                                 oSchema.GetArray("db_schema_tables");
     675           0 :                             if (oTables.IsValid())
     676             :                             {
     677           0 :                                 for (const auto &oTable : oTables)
     678             :                                 {
     679           0 :                                     if (oTable.GetType() ==
     680             :                                         CPLJSONObject::Type::Object)
     681             :                                     {
     682             :                                         const std::string osTableName =
     683           0 :                                             oTable.GetString("table_name");
     684             :                                         const std::string osTableType =
     685           0 :                                             oTable.GetString("table_type");
     686           0 :                                         if (!osTableName.empty() &&
     687           0 :                                             osTableType != "index" &&
     688           0 :                                             osTableType != "trigger")
     689             :                                         {
     690             :                                             OGRFeature oFeat(
     691             :                                                 poTableListLayer
     692           0 :                                                     ->GetLayerDefn());
     693           0 :                                             if (pszCatalogName)
     694           0 :                                                 oFeat.SetField("catalog_name",
     695             :                                                                pszCatalogName);
     696           0 :                                             if (oSchema.GetObj("schema_name")
     697           0 :                                                     .IsValid())
     698           0 :                                                 oFeat.SetField(
     699             :                                                     "schema_name",
     700             :                                                     osSchemaName.c_str());
     701           0 :                                             oFeat.SetField("table_name",
     702             :                                                            osTableName.c_str());
     703           0 :                                             if (oTable.GetObj("table_type")
     704           0 :                                                     .IsValid())
     705           0 :                                                 oFeat.SetField(
     706             :                                                     "table_type",
     707             :                                                     osTableType.c_str());
     708           0 :                                             CPL_IGNORE_RET_VAL(
     709           0 :                                                 poTableListLayer->CreateFeature(
     710             :                                                     &oFeat));
     711             :                                         }
     712             :                                     }
     713             :                                 }
     714             :                             }
     715             :                         }
     716             :                     }
     717             :                 }
     718             :             }
     719             :         }
     720             :     }
     721             : 
     722           0 :     m_apoLayers.emplace_back(std::move(poTableListLayer));
     723           0 :     return m_apoLayers.back().get();
     724             : }
     725             : 
     726             : #undef ADBC_CALL

Generated by: LCOV version 1.14