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-01-18 12:42:00 Functions: 0 7 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 "ogr_mem.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             : /*                                Open()                                */
     199             : /************************************************************************/
     200             : 
     201           0 : bool OGRADBCDataset::Open(const GDALOpenInfo *poOpenInfo)
     202             : {
     203           0 :     OGRADBCError error;
     204             : 
     205           0 :     const char *pszFilename = poOpenInfo->pszFilename;
     206           0 :     std::unique_ptr<GDALOpenInfo> poTmpOpenInfo;
     207           0 :     if (STARTS_WITH(pszFilename, "ADBC:"))
     208             :     {
     209           0 :         pszFilename += strlen("ADBC:");
     210             :         poTmpOpenInfo =
     211           0 :             std::make_unique<GDALOpenInfo>(pszFilename, GA_ReadOnly);
     212           0 :         poTmpOpenInfo->papszOpenOptions = poOpenInfo->papszOpenOptions;
     213           0 :         poOpenInfo = poTmpOpenInfo.get();
     214             :     }
     215             :     const char *pszADBCDriverName =
     216           0 :         CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ADBC_DRIVER");
     217           0 :     m_bIsDuckDBDataset = OGRADBCDriverIsDuckDB(poOpenInfo);
     218             :     const bool bIsSQLite3 =
     219           0 :         (pszADBCDriverName && EQUAL(pszADBCDriverName, "adbc_driver_sqlite")) ||
     220           0 :         OGRADBCDriverIsSQLite3(poOpenInfo);
     221             :     bool bIsParquet =
     222           0 :         OGRADBCDriverIsParquet(poOpenInfo) ||
     223           0 :         EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "parquet");
     224           0 :     const char *pszSQL = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "SQL");
     225           0 :     if (!bIsParquet && pszSQL)
     226             :     {
     227           0 :         CPLString osSQL(pszSQL);
     228           0 :         auto iPos = osSQL.find("FROM '");
     229           0 :         if (iPos != std::string::npos)
     230             :         {
     231           0 :             iPos += strlen("FROM '");
     232           0 :             const auto iPos2 = osSQL.find("'", iPos);
     233           0 :             if (iPos2 != std::string::npos)
     234             :             {
     235           0 :                 const std::string osFilename = osSQL.substr(iPos, iPos2 - iPos);
     236           0 :                 if (EQUAL(CPLGetExtensionSafe(osFilename.c_str()).c_str(),
     237             :                           "parquet"))
     238             :                 {
     239           0 :                     m_osParquetFilename = osFilename;
     240           0 :                     bIsParquet = true;
     241             :                 }
     242             :             }
     243             :         }
     244             :     }
     245           0 :     const bool bIsPostgreSQL = STARTS_WITH(pszFilename, "postgresql://");
     246             : 
     247           0 :     if (!pszADBCDriverName)
     248             :     {
     249           0 :         if (m_bIsDuckDBDataset || bIsParquet)
     250             :         {
     251           0 :             pszADBCDriverName =
     252             : #ifdef _WIN32
     253             :                 "duckdb.dll"
     254             : #elif defined(__MACH__) && defined(__APPLE__)
     255             :                 "libduckdb.dylib"
     256             : #else
     257             :                 "libduckdb.so"
     258             : #endif
     259             :                 ;
     260             :         }
     261           0 :         else if (bIsPostgreSQL)
     262           0 :             pszADBCDriverName = "adbc_driver_postgresql";
     263           0 :         else if (bIsSQLite3)
     264             :         {
     265           0 :             pszADBCDriverName = "adbc_driver_sqlite";
     266             :         }
     267             :         else
     268             :         {
     269           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     270             :                      "Open option ADBC_DRIVER must be specified");
     271           0 :             return false;
     272             :         }
     273             :     }
     274             : 
     275           0 :     m_bIsDuckDBDriver =
     276           0 :         m_bIsDuckDBDataset || bIsParquet ||
     277           0 :         (pszADBCDriverName && strstr(pszADBCDriverName, "duckdb"));
     278             : 
     279             :     // Load the driver
     280           0 :     if (m_bIsDuckDBDriver)
     281             :     {
     282           0 :         if (OGRADBCLoadDriver(pszADBCDriverName, "duckdb_adbc_init", &m_driver,
     283           0 :                               error) != ADBC_STATUS_OK)
     284             :         {
     285           0 :             CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s",
     286             :                      error.message());
     287           0 :             return false;
     288             :         }
     289             :     }
     290             :     else
     291             :     {
     292           0 :         if (OGRADBCLoadDriver(pszADBCDriverName, nullptr, &m_driver, error) !=
     293             :             ADBC_STATUS_OK)
     294             :         {
     295           0 :             CPLError(CE_Failure, CPLE_AppDefined, "AdbcLoadDriver() failed: %s",
     296             :                      error.message());
     297           0 :             return false;
     298             :         }
     299             :     }
     300             : 
     301             :     // Allocate the database
     302           0 :     if (ADBC_CALL(DatabaseNew, &m_database, error) != ADBC_STATUS_OK)
     303             :     {
     304           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseNew() failed: %s",
     305             :                  error.message());
     306           0 :         return false;
     307             :     }
     308             : 
     309             :     // Set options
     310           0 :     if (m_bIsDuckDBDriver)
     311             :     {
     312           0 :         if (ADBC_CALL(DatabaseSetOption, &m_database, "path",
     313             :                       bIsParquet ? ":memory:" : pszFilename,
     314           0 :                       error) != ADBC_STATUS_OK)
     315             :         {
     316           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     317             :                      "AdbcDatabaseSetOption() failed: %s", error.message());
     318           0 :             return false;
     319             :         }
     320             :     }
     321           0 :     else if (pszFilename[0])
     322             :     {
     323           0 :         if (ADBC_CALL(DatabaseSetOption, &m_database, "uri", pszFilename,
     324           0 :                       error) != ADBC_STATUS_OK)
     325             :         {
     326           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     327             :                      "AdbcDatabaseSetOption() failed: %s", error.message());
     328           0 :             return false;
     329             :         }
     330             :     }
     331             : 
     332           0 :     for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(
     333           0 :              static_cast<CSLConstList>(poOpenInfo->papszOpenOptions)))
     334             :     {
     335           0 :         if (STARTS_WITH_CI(pszKey, "ADBC_OPTION_"))
     336             :         {
     337           0 :             if (ADBC_CALL(DatabaseSetOption, &m_database,
     338             :                           pszKey + strlen("ADBC_OPTION_"), pszValue,
     339           0 :                           error) != ADBC_STATUS_OK)
     340             :             {
     341           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     342             :                          "AdbcDatabaseSetOption() failed: %s", error.message());
     343           0 :                 return false;
     344             :             }
     345             :         }
     346             :     }
     347             : 
     348           0 :     if (ADBC_CALL(DatabaseInit, &m_database, error) != ADBC_STATUS_OK)
     349             :     {
     350           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcDatabaseInit() failed: %s",
     351             :                  error.message());
     352           0 :         return false;
     353             :     }
     354             : 
     355           0 :     m_connection = std::make_unique<AdbcConnection>();
     356           0 :     if (ADBC_CALL(ConnectionNew, m_connection.get(), error) != ADBC_STATUS_OK)
     357             :     {
     358           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionNew() failed: %s",
     359             :                  error.message());
     360           0 :         return false;
     361             :     }
     362             : 
     363           0 :     if (ADBC_CALL(ConnectionInit, m_connection.get(), &m_database, error) !=
     364             :         ADBC_STATUS_OK)
     365             :     {
     366           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AdbcConnectionInit() failed: %s",
     367             :                  error.message());
     368           0 :         return false;
     369             :     }
     370             : 
     371           0 :     char **papszPreludeStatements = CSLFetchNameValueMultiple(
     372           0 :         poOpenInfo->papszOpenOptions, "PRELUDE_STATEMENTS");
     373           0 :     for (const char *pszStatement :
     374           0 :          cpl::Iterate(CSLConstList(papszPreludeStatements)))
     375             :     {
     376           0 :         CreateInternalLayer(pszStatement);
     377             :     }
     378           0 :     CSLDestroy(papszPreludeStatements);
     379           0 :     if (m_bIsDuckDBDriver && CPLTestBool(CPLGetConfigOption(
     380             :                                  "OGR_ADBC_AUTO_LOAD_DUCKDB_SPATIAL", "ON")))
     381             :     {
     382             :         auto poTmpLayer =
     383             :             CreateInternalLayer("SELECT 1 FROM duckdb_extensions() WHERE "
     384           0 :                                 "extension_name='spatial' AND loaded = false");
     385           0 :         if (poTmpLayer && std::unique_ptr<OGRFeature>(
     386           0 :                               poTmpLayer->GetNextFeature()) != nullptr)
     387             :         {
     388           0 :             CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     389           0 :             CreateInternalLayer("LOAD spatial");
     390             :         }
     391             : 
     392             :         poTmpLayer =
     393           0 :             CreateInternalLayer("SELECT 1 FROM duckdb_extensions() WHERE "
     394           0 :                                 "extension_name='spatial' AND loaded = true");
     395           0 :         m_bSpatialLoaded =
     396           0 :             poTmpLayer && std::unique_ptr<OGRFeature>(
     397           0 :                               poTmpLayer->GetNextFeature()) != nullptr;
     398             :     }
     399             : 
     400           0 :     std::string osLayerName = "RESULTSET";
     401           0 :     std::string osSQL;
     402           0 :     bool bIsParquetLayer = false;
     403           0 :     if (bIsParquet)
     404             :     {
     405           0 :         if (m_osParquetFilename.empty())
     406           0 :             m_osParquetFilename = pszFilename;
     407           0 :         osLayerName = CPLGetBasenameSafe(m_osParquetFilename.c_str());
     408           0 :         if (osLayerName == "*")
     409           0 :             osLayerName = CPLGetBasenameSafe(
     410           0 :                 CPLGetDirnameSafe(m_osParquetFilename.c_str()).c_str());
     411           0 :         if (!pszSQL)
     412             :         {
     413             :             osSQL =
     414             :                 CPLSPrintf("SELECT * FROM '%s'",
     415           0 :                            OGRDuplicateCharacter(pszFilename, '\'').c_str());
     416           0 :             pszSQL = osSQL.c_str();
     417           0 :             bIsParquetLayer = true;
     418             :         }
     419             :     }
     420             : 
     421           0 :     if (pszSQL)
     422             :     {
     423           0 :         if (pszSQL[0])
     424             :         {
     425           0 :             std::unique_ptr<OGRADBCLayer> poLayer;
     426           0 :             if ((bIsParquet || m_bIsDuckDBDataset) && m_bSpatialLoaded)
     427             :             {
     428           0 :                 std::string osErrorMsg;
     429             :                 {
     430           0 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     431           0 :                     poLayer = CreateLayer(pszSQL, osLayerName.c_str(), false);
     432           0 :                     if (!poLayer)
     433           0 :                         osErrorMsg = CPLGetLastErrorMsg();
     434             :                 }
     435           0 :                 if (!poLayer)
     436             :                 {
     437           0 :                     CPLDebug("ADBC",
     438             :                              "Connecting with 'LOAD spatial' did not work "
     439             :                              "(%s). Retrying without it",
     440             :                              osErrorMsg.c_str());
     441           0 :                     ADBC_CALL(ConnectionRelease, m_connection.get(), error);
     442           0 :                     m_connection.reset();
     443             : 
     444           0 :                     ADBC_CALL(DatabaseRelease, &m_database, error);
     445           0 :                     memset(&m_database, 0, sizeof(m_database));
     446             : 
     447           0 :                     if (ADBC_CALL(DatabaseNew, &m_database, error) !=
     448             :                         ADBC_STATUS_OK)
     449             :                     {
     450           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     451             :                                  "AdbcDatabaseNew() failed: %s",
     452             :                                  error.message());
     453           0 :                         return false;
     454             :                     }
     455           0 :                     if (ADBC_CALL(DatabaseSetOption, &m_database, "path",
     456           0 :                                   ":memory:", error) != ADBC_STATUS_OK)
     457             :                     {
     458           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     459             :                                  "AdbcDatabaseSetOption() failed: %s",
     460             :                                  error.message());
     461           0 :                         return false;
     462             :                     }
     463             : 
     464           0 :                     if (ADBC_CALL(DatabaseInit, &m_database, error) !=
     465             :                         ADBC_STATUS_OK)
     466             :                     {
     467           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     468             :                                  "AdbcDatabaseInit() failed: %s",
     469             :                                  error.message());
     470           0 :                         return false;
     471             :                     }
     472             : 
     473           0 :                     m_connection = std::make_unique<AdbcConnection>();
     474           0 :                     if (ADBC_CALL(ConnectionNew, m_connection.get(), error) !=
     475             :                         ADBC_STATUS_OK)
     476             :                     {
     477           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     478             :                                  "AdbcConnectionNew() failed: %s",
     479             :                                  error.message());
     480           0 :                         return false;
     481             :                     }
     482             : 
     483           0 :                     if (ADBC_CALL(ConnectionInit, m_connection.get(),
     484           0 :                                   &m_database, error) != ADBC_STATUS_OK)
     485             :                     {
     486           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     487             :                                  "AdbcConnectionInit() failed: %s",
     488             :                                  error.message());
     489           0 :                         return false;
     490             :                     }
     491             :                 }
     492             :             }
     493           0 :             if (!poLayer)
     494             :             {
     495           0 :                 poLayer = CreateLayer(pszSQL, osLayerName.c_str(), false);
     496           0 :                 if (!poLayer)
     497           0 :                     return false;
     498             :             }
     499             : 
     500           0 :             poLayer->m_bIsParquetLayer = bIsParquetLayer;
     501           0 :             m_apoLayers.emplace_back(std::move(poLayer));
     502             :         }
     503             :     }
     504           0 :     else if (m_bIsDuckDBDataset || bIsSQLite3)
     505             :     {
     506             :         auto poLayerList = CreateInternalLayer(
     507           0 :             "SELECT name FROM sqlite_master WHERE type IN ('table', 'view')");
     508           0 :         if (!poLayerList || poLayerList->GetLayerDefn()->GetFieldCount() != 1)
     509             :         {
     510           0 :             return false;
     511             :         }
     512             : 
     513           0 :         for (const auto &poFeature : poLayerList.get())
     514             :         {
     515           0 :             const char *pszLayerName = poFeature->GetFieldAsString(0);
     516           0 :             if (bIsSQLite3 && EQUAL(pszLayerName, "SpatialIndex"))
     517           0 :                 continue;
     518             :             const std::string osStatement =
     519             :                 CPLSPrintf("SELECT * FROM \"%s\"",
     520           0 :                            OGRDuplicateCharacter(pszLayerName, '"').c_str());
     521           0 :             CPLTurnFailureIntoWarning(true);
     522             :             auto poLayer =
     523           0 :                 CreateLayer(osStatement.c_str(), pszLayerName, false);
     524           0 :             CPLTurnFailureIntoWarning(false);
     525           0 :             if (poLayer)
     526             :             {
     527           0 :                 m_apoLayers.emplace_back(std::move(poLayer));
     528             :             }
     529           0 :         }
     530             :     }
     531           0 :     else if (bIsPostgreSQL)
     532             :     {
     533             :         auto poLayerList = CreateInternalLayer(
     534             :             "SELECT n.nspname, c.relname FROM pg_class c "
     535             :             "JOIN pg_namespace n ON c.relnamespace = n.oid "
     536             :             "AND c.relkind in ('r','v','m','f') "
     537             :             "AND n.nspname NOT IN ('pg_catalog', 'information_schema') "
     538           0 :             "ORDER BY c.oid");
     539           0 :         if (!poLayerList || poLayerList->GetLayerDefn()->GetFieldCount() != 2)
     540             :         {
     541           0 :             return false;
     542             :         }
     543             : 
     544           0 :         for (const auto &poFeature : poLayerList.get())
     545             :         {
     546           0 :             const char *pszNamespace = poFeature->GetFieldAsString(0);
     547           0 :             const char *pszTableName = poFeature->GetFieldAsString(1);
     548             :             const std::string osStatement =
     549             :                 CPLSPrintf("SELECT * FROM \"%s\".\"%s\"",
     550           0 :                            OGRDuplicateCharacter(pszNamespace, '"').c_str(),
     551           0 :                            OGRDuplicateCharacter(pszTableName, '"').c_str());
     552             : 
     553           0 :             CPLTurnFailureIntoWarning(true);
     554             :             auto poLayer = CreateLayer(
     555             :                 osStatement.c_str(),
     556           0 :                 CPLSPrintf("%s.%s", pszNamespace, pszTableName), false);
     557           0 :             CPLTurnFailureIntoWarning(false);
     558           0 :             if (poLayer)
     559             :             {
     560           0 :                 m_apoLayers.emplace_back(std::move(poLayer));
     561             :             }
     562             :         }
     563             :     }
     564             : 
     565           0 :     return true;
     566             : }
     567             : 
     568             : /************************************************************************/
     569             : /*                         GetLayerByName()                             */
     570             : /************************************************************************/
     571             : 
     572           0 : OGRLayer *OGRADBCDataset::GetLayerByName(const char *pszName)
     573             : {
     574           0 :     OGRLayer *poLayer = GDALDataset::GetLayerByName(pszName);
     575           0 :     if (poLayer || !EQUAL(pszName, "table_list"))
     576           0 :         return poLayer;
     577             : 
     578           0 :     OGRADBCError error;
     579           0 :     auto objectsStream = std::make_unique<OGRArrowArrayStream>();
     580           0 :     ADBC_CALL(ConnectionGetObjects, m_connection.get(),
     581             :               ADBC_OBJECT_DEPTH_TABLES,
     582             :               /* catalog = */ nullptr,
     583             :               /* db_schema = */ nullptr,
     584             :               /* table_name = */ nullptr,
     585             :               /* table_type = */ nullptr,
     586             :               /* column_name = */ nullptr, objectsStream->get(), error);
     587             : 
     588           0 :     ArrowSchema schema = {};
     589           0 :     if (objectsStream->get_schema(&schema) != 0)
     590             :     {
     591           0 :         CPLError(CE_Failure, CPLE_AppDefined, "get_schema() failed");
     592           0 :         return nullptr;
     593             :     }
     594             : 
     595           0 :     auto statement = std::make_unique<AdbcStatement>();
     596           0 :     OGRADBCLayer tmpLayer(this, "", "", std::move(statement),
     597           0 :                           std::move(objectsStream), &schema,
     598           0 :                           /* bInternalUse = */ true);
     599           0 :     const auto tmpLayerDefn = tmpLayer.GetLayerDefn();
     600           0 :     if (tmpLayerDefn->GetFieldIndex("catalog_name") < 0 ||
     601           0 :         tmpLayerDefn->GetFieldIndex("catalog_db_schemas") < 0)
     602             :     {
     603           0 :         return nullptr;
     604             :     }
     605             : 
     606             :     auto poTableListLayer =
     607           0 :         std::make_unique<OGRMemLayer>("table_list", nullptr, wkbNone);
     608             :     {
     609           0 :         OGRFieldDefn oField("catalog_name", OFTString);
     610           0 :         poTableListLayer->CreateField(&oField);
     611             :     }
     612             :     {
     613           0 :         OGRFieldDefn oField("schema_name", OFTString);
     614           0 :         poTableListLayer->CreateField(&oField);
     615             :     }
     616             :     {
     617           0 :         OGRFieldDefn oField("table_name", OFTString);
     618           0 :         poTableListLayer->CreateField(&oField);
     619             :     }
     620             :     {
     621           0 :         OGRFieldDefn oField("table_type", OFTString);
     622           0 :         poTableListLayer->CreateField(&oField);
     623             :     }
     624             : 
     625           0 :     for (const auto &poFeature : tmpLayer)
     626             :     {
     627             :         const char *pszCatalogName =
     628           0 :             poFeature->GetFieldAsString("catalog_name");
     629             :         const char *pszCatalogDBSchemas =
     630           0 :             poFeature->GetFieldAsString("catalog_db_schemas");
     631           0 :         if (pszCatalogDBSchemas)
     632             :         {
     633           0 :             CPLJSONDocument oDoc;
     634           0 :             if (oDoc.LoadMemory(pszCatalogDBSchemas))
     635             :             {
     636           0 :                 auto oRoot = oDoc.GetRoot();
     637           0 :                 if (oRoot.GetType() == CPLJSONObject::Type::Array)
     638             :                 {
     639           0 :                     for (const auto &oSchema : oRoot.ToArray())
     640             :                     {
     641           0 :                         if (oSchema.GetType() == CPLJSONObject::Type::Object)
     642             :                         {
     643             :                             const std::string osSchemaName =
     644           0 :                                 oSchema.GetString("schema_name");
     645             :                             const auto oTables =
     646           0 :                                 oSchema.GetArray("db_schema_tables");
     647           0 :                             if (oTables.IsValid())
     648             :                             {
     649           0 :                                 for (const auto &oTable : oTables)
     650             :                                 {
     651           0 :                                     if (oTable.GetType() ==
     652             :                                         CPLJSONObject::Type::Object)
     653             :                                     {
     654             :                                         const std::string osTableName =
     655           0 :                                             oTable.GetString("table_name");
     656             :                                         const std::string osTableType =
     657           0 :                                             oTable.GetString("table_type");
     658           0 :                                         if (!osTableName.empty() &&
     659           0 :                                             osTableType != "index" &&
     660           0 :                                             osTableType != "trigger")
     661             :                                         {
     662             :                                             OGRFeature oFeat(
     663             :                                                 poTableListLayer
     664           0 :                                                     ->GetLayerDefn());
     665           0 :                                             if (pszCatalogName)
     666           0 :                                                 oFeat.SetField("catalog_name",
     667             :                                                                pszCatalogName);
     668           0 :                                             if (oSchema.GetObj("schema_name")
     669           0 :                                                     .IsValid())
     670           0 :                                                 oFeat.SetField(
     671             :                                                     "schema_name",
     672             :                                                     osSchemaName.c_str());
     673           0 :                                             oFeat.SetField("table_name",
     674             :                                                            osTableName.c_str());
     675           0 :                                             if (oTable.GetObj("table_type")
     676           0 :                                                     .IsValid())
     677           0 :                                                 oFeat.SetField(
     678             :                                                     "table_type",
     679             :                                                     osTableType.c_str());
     680           0 :                                             CPL_IGNORE_RET_VAL(
     681           0 :                                                 poTableListLayer->CreateFeature(
     682             :                                                     &oFeat));
     683             :                                         }
     684             :                                     }
     685             :                                 }
     686             :                             }
     687             :                         }
     688             :                     }
     689             :                 }
     690             :             }
     691             :         }
     692             :     }
     693             : 
     694           0 :     m_apoLayers.emplace_back(std::move(poTableListLayer));
     695           0 :     return m_apoLayers.back().get();
     696             : }
     697             : 
     698             : #undef ADBC_CALL

Generated by: LCOV version 1.14