LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/adbc - ogradbcdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 316 0.0 %
Date: 2025-05-31 00:00:17 Functions: 0 8 0.0 %

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

Generated by: LCOV version 1.14