LCOV - code coverage report
Current view: top level - frmts/postgisraster - postgisrasterdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 43 74 58.1 %
Date: 2025-10-01 17:07:58 Functions: 8 11 72.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * File :    PostGISRasterDriver.cpp
       3             :  * Project:  PostGIS Raster driver
       4             :  * Purpose:  Implements PostGIS Raster driver class methods
       5             :  * Author:   Jorge Arevalo, jorge.arevalo@deimos-space.com
       6             :  *
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2010, Jorge Arevalo, jorge.arevalo@deimos-space.com
      10             :  * Copyright (c) 2013, Even Rouault
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ******************************************************************************/
      14             : 
      15             : #include "gdal_frmts.h"
      16             : #include "gdalplugindriverproxy.h"
      17             : 
      18             : #include <stdexcept>
      19             : 
      20             : #include "postgisrasterdrivercore.h"
      21             : 
      22             : #include "gdalsubdatasetinfo.h"
      23             : 
      24             : /************************************************************************/
      25             : /*                     PostGISRasterDriverIdentify()                    */
      26             : /************************************************************************/
      27             : 
      28       57922 : int PostGISRasterDriverIdentify(GDALOpenInfo *poOpenInfo)
      29             : 
      30             : {
      31       57922 :     if (poOpenInfo->pszFilename == nullptr || poOpenInfo->fpL != nullptr ||
      32       54464 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "PG:"))
      33             :     {
      34       57918 :         return FALSE;
      35             :     }
      36             : 
      37             :     // Will avoid a OGR PostgreSQL connection string to be recognized as a
      38             :     // PostgisRaster one and later fail (#6034)
      39           4 :     if (strstr(poOpenInfo->pszFilename, " schemas=") ||
      40           4 :         strstr(poOpenInfo->pszFilename, " SCHEMAS="))
      41             :     {
      42           0 :         return FALSE;
      43             :     }
      44             : 
      45           4 :     return TRUE;
      46             : }
      47             : 
      48             : /**************************************************************
      49             :  * \brief Replace the single quotes by " in the input string
      50             :  *
      51             :  * Needed before tokenize function
      52             :  *************************************************************/
      53           2 : static char *ReplaceSingleQuotes(const char *pszInput, int nLength)
      54             : {
      55             :     int i;
      56           2 :     char *pszOutput = nullptr;
      57             : 
      58           2 :     if (nLength == -1)
      59           2 :         nLength = static_cast<int>(strlen(pszInput));
      60             : 
      61           2 :     pszOutput = static_cast<char *>(CPLCalloc(nLength + 1, sizeof(char)));
      62             : 
      63         106 :     for (i = 0; i < nLength; i++)
      64             :     {
      65         104 :         if (pszInput[i] == '\'')
      66          12 :             pszOutput[i] = '"';
      67             :         else
      68          92 :             pszOutput[i] = pszInput[i];
      69             :     }
      70             : 
      71           2 :     return pszOutput;
      72             : }
      73             : 
      74             : /***********************************************************************
      75             :  * \brief Split connection string into user, password, host, database...
      76             :  *
      77             :  * The parameters separated by spaces are return as a list of strings.
      78             :  * The function accepts all the PostgreSQL recognized parameter keywords.
      79             :  *
      80             :  * The returned list must be freed with CSLDestroy when no longer needed
      81             :  **********************************************************************/
      82           2 : char **PostGISRasterParseConnectionString(const char *pszConnectionString)
      83             : {
      84             : 
      85             :     /* Escape string following SQL scheme */
      86             :     char *pszEscapedConnectionString =
      87           2 :         ReplaceSingleQuotes(pszConnectionString, -1);
      88             : 
      89             :     /* Avoid PG: part */
      90           2 :     char *pszStartPos = strstr(pszEscapedConnectionString, ":") + 1;
      91             : 
      92             :     /* Tokenize */
      93             :     char **papszParams =
      94           2 :         CSLTokenizeString2(pszStartPos, " ", CSLT_HONOURSTRINGS);
      95             : 
      96             :     /* Free */
      97           2 :     CPLFree(pszEscapedConnectionString);
      98             : 
      99           2 :     return papszParams;
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                    PostGISRasterDriverGetSubdatasetInfo()            */
     104             : /************************************************************************/
     105             : 
     106             : struct PostGISRasterDriverSubdatasetInfo final : public GDALSubdatasetInfo
     107             : {
     108             :   public:
     109           0 :     explicit PostGISRasterDriverSubdatasetInfo(const std::string &fileName)
     110           0 :         : GDALSubdatasetInfo(fileName)
     111             :     {
     112           0 :     }
     113             : 
     114             :     // GDALSubdatasetInfo interface
     115             :   private:
     116             :     void parseFileName() override;
     117             : };
     118             : 
     119           0 : void PostGISRasterDriverSubdatasetInfo::parseFileName()
     120             : {
     121           0 :     if (!STARTS_WITH_CI(m_fileName.c_str(), "PG:"))
     122             :     {
     123           0 :         return;
     124             :     }
     125             : 
     126           0 :     char **papszParams = PostGISRasterParseConnectionString(m_fileName.c_str());
     127             : 
     128           0 :     const int nTableIdx = CSLFindName(papszParams, "table");
     129           0 :     if (nTableIdx != -1)
     130             :     {
     131           0 :         size_t nTableStart = m_fileName.find("table=");
     132           0 :         bool bHasQuotes{false};
     133             :         try
     134             :         {
     135           0 :             bHasQuotes = m_fileName.at(nTableStart + 6) == '\'';
     136             :         }
     137           0 :         catch (const std::out_of_range &)
     138             :         {
     139             :             // ignore error
     140             :         }
     141             : 
     142           0 :         m_subdatasetComponent = papszParams[nTableIdx];
     143             : 
     144           0 :         if (bHasQuotes)
     145             :         {
     146           0 :             m_subdatasetComponent.insert(6, "'");
     147           0 :             m_subdatasetComponent.push_back('\'');
     148             :         }
     149             : 
     150           0 :         m_driverPrefixComponent = "PG";
     151             : 
     152           0 :         size_t nPathLength = m_subdatasetComponent.length();
     153           0 :         if (nTableStart != 0)
     154             :         {
     155           0 :             nPathLength++;
     156           0 :             nTableStart--;
     157             :         }
     158             : 
     159           0 :         m_pathComponent = m_fileName;
     160           0 :         m_pathComponent.erase(nTableStart, nPathLength);
     161           0 :         m_pathComponent.erase(0, 3);
     162             :     }
     163             : 
     164           0 :     CSLDestroy(papszParams);
     165             : }
     166             : 
     167             : static GDALSubdatasetInfo *
     168        2687 : PostGISRasterDriverGetSubdatasetInfo(const char *pszFileName)
     169             : {
     170        2687 :     if (STARTS_WITH_CI(pszFileName, "PG:"))
     171             :     {
     172             :         std::unique_ptr<GDALSubdatasetInfo> info =
     173           0 :             std::make_unique<PostGISRasterDriverSubdatasetInfo>(pszFileName);
     174           0 :         if (!info->GetSubdatasetComponent().empty() &&
     175           0 :             !info->GetPathComponent().empty())
     176             :         {
     177           0 :             return info.release();
     178             :         }
     179             :     }
     180        2687 :     return nullptr;
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                PostGISRasterDriverSetCommonMetadata()                */
     185             : /************************************************************************/
     186             : 
     187        1760 : void PostGISRasterDriverSetCommonMetadata(GDALDriver *poDriver)
     188             : {
     189        1760 :     poDriver->SetDescription(DRIVER_NAME);
     190        1760 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     191        1760 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PostGIS Raster driver");
     192        1760 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     193        1760 :     poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "PG:");
     194             : 
     195        1760 :     poDriver->pfnIdentify = PostGISRasterDriverIdentify;
     196        1760 :     poDriver->pfnGetSubdatasetInfoFunc = PostGISRasterDriverGetSubdatasetInfo;
     197             : 
     198        1760 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     199        1760 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     200        1760 : }
     201             : 
     202             : /************************************************************************/
     203             : /*                   DeclareDeferredPostGISRasterPlugin()               */
     204             : /************************************************************************/
     205             : 
     206             : #ifdef PLUGIN_FILENAME
     207        2033 : void DeclareDeferredPostGISRasterPlugin()
     208             : {
     209        2033 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     210             :     {
     211         283 :         return;
     212             :     }
     213        1750 :     auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     214             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     215             :     poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     216             :                               PLUGIN_INSTALLATION_MESSAGE);
     217             : #endif
     218        1750 :     PostGISRasterDriverSetCommonMetadata(poDriver);
     219        1750 :     GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     220             : }
     221             : #endif

Generated by: LCOV version 1.14