LCOV - code coverage report
Current view: top level - apps - gdalalg_materialize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 176 180 97.8 %
Date: 2026-06-03 12:46:18 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "materialize" pipeline step
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_materialize.h"
      14             : #include "gdal_utils.h"
      15             : #include "gdal_priv.h"
      16             : #include "ogrsf_frmts.h"
      17             : 
      18             : //! @cond Doxygen_Suppress
      19             : 
      20             : #ifndef _
      21             : #define _(x) (x)
      22             : #endif
      23             : 
      24             : /************************************************************************/
      25             : /*                   GDALMaterializeRasterAlgorithm()                   */
      26             : /************************************************************************/
      27             : 
      28          60 : GDALMaterializeRasterAlgorithm::GDALMaterializeRasterAlgorithm()
      29             :     : GDALMaterializeStepAlgorithm<GDALRasterPipelineStepAlgorithm,
      30          60 :                                    GDAL_OF_RASTER>(HELP_URL)
      31             : {
      32          60 :     AddRasterHiddenInputDatasetArg();
      33             : 
      34             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
      35             :                         /* positionalAndRequired = */ false,
      36          60 :                         _("Materialized dataset name"))
      37          60 :         .SetDatasetInputFlags(GADV_NAME);
      38             : 
      39          60 :     AddOutputFormatArg(&m_format)
      40             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      41             :                          {GDAL_DCAP_RASTER, GDAL_DCAP_CREATECOPY,
      42         360 :                           GDAL_DCAP_OPEN, GDAL_DMD_EXTENSIONS})
      43         240 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM", "COG"})
      44         120 :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS, {"VRT"});
      45             : 
      46          60 :     AddCreationOptionsArg(&m_creationOptions);
      47          60 :     AddOverwriteArg(&m_overwrite);
      48             : 
      49             :     AddArg(ARG_NAME_REOPEN_AND_DO_NOT_EARLY_DELETE, 0,
      50             :            _("Reopen after materialization and do not early deleted"),
      51         120 :            &m_reopenAndDoNotEarlyDelete)
      52          60 :         .SetHidden();
      53          60 : }
      54             : 
      55             : /************************************************************************/
      56             : /*              GDALMaterializeRasterAlgorithm::RunStep()               */
      57             : /************************************************************************/
      58             : 
      59          18 : bool GDALMaterializeRasterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
      60             : {
      61          18 :     auto pfnProgress = ctxt.m_pfnProgress;
      62          18 :     auto pProgressData = ctxt.m_pProgressData;
      63             : 
      64          18 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      65          18 :     CPLAssert(poSrcDS);
      66          18 :     CPLAssert(!m_outputDataset.GetDatasetRef());
      67             : 
      68          36 :     std::string filename = m_outputDataset.GetName();
      69          18 :     if (m_format.empty())
      70             :     {
      71           7 :         if (filename.empty())
      72             :         {
      73           3 :             m_format = "GTiff";
      74             :         }
      75             :         else
      76             :         {
      77             :             const auto aosFormats =
      78             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
      79             :                     filename.c_str(), GDAL_OF_RASTER,
      80             :                     /* bSingleMatch = */ true,
      81           4 :                     /* bWarn = */ true));
      82           4 :             if (aosFormats.size() != 1)
      83             :             {
      84           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
      85             :                             "Cannot guess driver for %s", filename.c_str());
      86           1 :                 return false;
      87             :             }
      88           3 :             m_format = aosFormats[0];
      89             :         }
      90             :     }
      91             : 
      92          17 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
      93          17 :     if (!poDrv)
      94             :     {
      95           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Driver %s does not exist",
      96             :                     m_format.c_str());
      97           0 :         return false;
      98             :     }
      99             : 
     100          15 :     const bool autoDeleteFile = !m_reopenAndDoNotEarlyDelete &&
     101          32 :                                 filename.empty() &&
     102           5 :                                 !EQUAL(m_format.c_str(), "MEM");
     103          17 :     if (filename.empty() && !EQUAL(m_format.c_str(), "MEM"))
     104             :     {
     105           5 :         filename = CPLGenerateTempFilenameSafe(nullptr);
     106             : 
     107           5 :         const char *pszExt = poDrv->GetMetadataItem(GDAL_DMD_EXTENSIONS);
     108           5 :         if (pszExt)
     109             :         {
     110           5 :             filename += '.';
     111           5 :             filename += CPLStringList(CSLTokenizeString(pszExt))[0];
     112             :         }
     113             :     }
     114             : 
     115          34 :     CPLStringList aosOptions(m_creationOptions);
     116          17 :     if (EQUAL(m_format.c_str(), "GTiff"))
     117             :     {
     118          12 :         if (aosOptions.FetchNameValue("TILED") == nullptr)
     119             :         {
     120          12 :             aosOptions.SetNameValue("TILED", "YES");
     121             :         }
     122          12 :         if (aosOptions.FetchNameValue("COPY_SRC_OVERVIEWS") == nullptr)
     123             :         {
     124           5 :             aosOptions.SetNameValue("COPY_SRC_OVERVIEWS", "YES");
     125             :         }
     126          12 :         if (aosOptions.FetchNameValue("COMPRESS") == nullptr)
     127             :         {
     128             :             const char *pszCOList =
     129          12 :                 poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     130             :             aosOptions.SetNameValue(
     131             :                 "COMPRESS",
     132          12 :                 pszCOList && strstr(pszCOList, "ZSTD") ? "ZSTD" : "DEFLATE");
     133             :         }
     134             :     }
     135             : 
     136          17 :     if (autoDeleteFile)
     137             :     {
     138           4 :         aosOptions.SetNameValue("@SUPPRESS_ASAP", "YES");
     139             :     }
     140             : 
     141             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     142          17 :         poDrv->CreateCopy(filename.c_str(), poSrcDS, false, aosOptions.List(),
     143          17 :                           pfnProgress, pProgressData));
     144          17 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     145          17 :     if (poOutDS)
     146             :     {
     147          32 :         if (m_reopenAndDoNotEarlyDelete ||
     148          15 :             poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     149             :         {
     150           2 :             ok = poOutDS->Close() == CE_None;
     151           2 :             poOutDS.reset();
     152           2 :             if (ok)
     153             :             {
     154           2 :                 const char *const apszAllowedDrivers[] = {m_format.c_str(),
     155           2 :                                                           nullptr};
     156           2 :                 poOutDS.reset(GDALDataset::Open(
     157             :                     filename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
     158             :                     apszAllowedDrivers));
     159           2 :                 ok = poOutDS != nullptr;
     160             :             }
     161             :         }
     162          17 :         if (ok)
     163             :         {
     164          17 :             if (autoDeleteFile)
     165             :             {
     166             : #if !defined(_WIN32)
     167           4 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     168             :                 {
     169           4 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     170           4 :                     poDrv->Delete(poOutDS.get(),
     171           8 :                                   CPLStringList(poOutDS->GetFileList()).List());
     172             :                 }
     173             : #endif
     174           4 :                 poOutDS->MarkSuppressOnClose();
     175             :             }
     176             : 
     177          17 :             m_outputDataset.Set(std::move(poOutDS));
     178             :         }
     179             :     }
     180          17 :     return ok;
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                   GDALMaterializeVectorAlgorithm()                   */
     185             : /************************************************************************/
     186             : 
     187          56 : GDALMaterializeVectorAlgorithm::GDALMaterializeVectorAlgorithm()
     188             :     : GDALMaterializeStepAlgorithm<GDALVectorPipelineStepAlgorithm,
     189          56 :                                    GDAL_OF_VECTOR>(HELP_URL)
     190             : {
     191          56 :     AddVectorHiddenInputDatasetArg();
     192             : 
     193             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
     194             :                         /* positionalAndRequired = */ false,
     195          56 :                         _("Materialized dataset name"))
     196          56 :         .SetDatasetInputFlags(GADV_NAME);
     197             : 
     198          56 :     AddOutputFormatArg(&m_format)
     199             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
     200             :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE, GDAL_DCAP_OPEN,
     201         336 :                           GDAL_DMD_EXTENSIONS})
     202         168 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM"})
     203             :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS,
     204         280 :                          {"MBTiles", "MVT", "PMTiles", "JP2ECW"});
     205             : 
     206          56 :     AddCreationOptionsArg(&m_creationOptions);
     207          56 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
     208          56 :     AddOverwriteArg(&m_overwrite);
     209          56 : }
     210             : 
     211             : /************************************************************************/
     212             : /*              GDALMaterializeVectorAlgorithm::RunStep()               */
     213             : /************************************************************************/
     214             : 
     215          18 : bool GDALMaterializeVectorAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     216             : {
     217          18 :     auto pfnProgress = ctxt.m_pfnProgress;
     218          18 :     auto pProgressData = ctxt.m_pProgressData;
     219             : 
     220          18 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     221          18 :     CPLAssert(poSrcDS);
     222          18 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     223             : 
     224          36 :     std::string filename = m_outputDataset.GetName();
     225          18 :     if (m_format.empty())
     226             :     {
     227           8 :         if (filename.empty())
     228             :         {
     229           4 :             bool bSeveralGeomFields = false;
     230           8 :             for (const auto *poLayer : poSrcDS->GetLayers())
     231             :             {
     232           4 :                 if (!bSeveralGeomFields)
     233           4 :                     bSeveralGeomFields =
     234           4 :                         poLayer->GetLayerDefn()->GetGeomFieldCount() > 1;
     235           7 :                 if (!bSeveralGeomFields &&
     236           3 :                     poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
     237             :                 {
     238           7 :                     for (const auto *poFieldDefn :
     239          17 :                          poLayer->GetLayerDefn()->GetFields())
     240             :                     {
     241           7 :                         const auto eType = poFieldDefn->GetType();
     242           7 :                         if (eType == OFTStringList || eType == OFTIntegerList ||
     243           6 :                             eType == OFTRealList || eType == OFTInteger64List)
     244             :                         {
     245           1 :                             bSeveralGeomFields = true;
     246             :                         }
     247             :                     }
     248             :                 }
     249             :             }
     250           4 :             m_format = bSeveralGeomFields ? "SQLite" : "GPKG";
     251             :         }
     252             :         else
     253             :         {
     254             :             const auto aosFormats =
     255             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
     256             :                     filename.c_str(), GDAL_OF_VECTOR,
     257             :                     /* bSingleMatch = */ true,
     258           4 :                     /* bWarn = */ true));
     259           4 :             if (aosFormats.size() != 1)
     260             :             {
     261           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     262             :                             "Cannot guess driver for %s", filename.c_str());
     263           1 :                 return false;
     264             :             }
     265           3 :             m_format = aosFormats[0];
     266             :         }
     267             :     }
     268             : 
     269          17 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
     270          17 :     if (!poDrv)
     271             :     {
     272           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Driver %s does not exist",
     273             :                     m_format.c_str());
     274           0 :         return false;
     275             :     }
     276             : 
     277          17 :     const bool autoDeleteFile = !m_reopenAndDoNotEarlyDelete &&
     278          34 :                                 filename.empty() &&
     279           9 :                                 !EQUAL(m_format.c_str(), "MEM");
     280          17 :     if (filename.empty() && !EQUAL(m_format.c_str(), "MEM"))
     281             :     {
     282           8 :         filename = CPLGenerateTempFilenameSafe(nullptr);
     283             : 
     284           8 :         const char *pszExt = poDrv->GetMetadataItem(GDAL_DMD_EXTENSIONS);
     285           8 :         if (pszExt)
     286             :         {
     287           8 :             filename += '.';
     288           8 :             filename += CPLStringList(CSLTokenizeString(pszExt))[0];
     289             :         }
     290             :     }
     291             : 
     292          34 :     CPLStringList aosOptions;
     293          17 :     aosOptions.AddString("--invoked-from-gdal-algorithm");
     294          17 :     if (!m_overwrite)
     295             :     {
     296          17 :         aosOptions.AddString("--no-overwrite");
     297             :     }
     298             : 
     299          17 :     aosOptions.AddString("-of");
     300          17 :     aosOptions.AddString(m_format.c_str());
     301          18 :     for (const auto &co : m_creationOptions)
     302             :     {
     303           1 :         aosOptions.AddString("-dsco");
     304           1 :         aosOptions.AddString(co.c_str());
     305             :     }
     306          34 :     CPLStringList aosReopenOpenOptions;
     307          17 :     if (EQUAL(m_format.c_str(), "SQLite"))
     308             :     {
     309             :         const char *pszCOList =
     310           3 :             poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     311           6 :         if (pszCOList && strstr(pszCOList, "SPATIALITE") &&
     312           6 :             CPLStringList(m_creationOptions).FetchNameValue("SPATIALITE") ==
     313             :                 nullptr)
     314             :         {
     315           2 :             aosOptions.AddString("-dsco");
     316           2 :             aosOptions.AddString("SPATIALITE=YES");
     317             :         }
     318           3 :         aosReopenOpenOptions.AddString("LIST_ALL_TABLES=YES");
     319             :     }
     320          18 :     for (const auto &co : m_layerCreationOptions)
     321             :     {
     322           1 :         aosOptions.AddString("-lco");
     323           1 :         aosOptions.AddString(co.c_str());
     324             :     }
     325          17 :     if (pfnProgress && pfnProgress != GDALDummyProgress)
     326             :     {
     327           1 :         aosOptions.AddString("-progress");
     328             :     }
     329             : 
     330          17 :     if (autoDeleteFile)
     331             :     {
     332           8 :         aosOptions.AddString("-dsco");
     333           8 :         aosOptions.AddString("@SUPPRESS_ASAP=YES");
     334             :     }
     335             : 
     336             :     GDALVectorTranslateOptions *psOptions =
     337          17 :         GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr);
     338          17 :     GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress,
     339             :                                           pProgressData);
     340             : 
     341          17 :     GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
     342             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     343             :         GDALDataset::FromHandle(GDALVectorTranslate(
     344          17 :             filename.c_str(), nullptr, 1, &hSrcDS, psOptions, nullptr)));
     345          17 :     GDALVectorTranslateOptionsFree(psOptions);
     346             : 
     347          17 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     348          17 :     if (poOutDS)
     349             :     {
     350          34 :         if (m_reopenAndDoNotEarlyDelete ||
     351          17 :             poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     352             :         {
     353           2 :             ok = poOutDS->Close() == CE_None;
     354           2 :             poOutDS.reset();
     355           2 :             if (ok)
     356             :             {
     357           2 :                 const char *const apszAllowedDrivers[] = {m_format.c_str(),
     358           2 :                                                           nullptr};
     359           2 :                 poOutDS.reset(GDALDataset::Open(
     360             :                     filename.c_str(), GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR,
     361           2 :                     apszAllowedDrivers, aosReopenOpenOptions.List()));
     362           2 :                 ok = poOutDS != nullptr;
     363             :             }
     364             :         }
     365          17 :         if (ok)
     366             :         {
     367          17 :             if (autoDeleteFile)
     368             :             {
     369             : #if !defined(_WIN32)
     370           8 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     371             :                 {
     372           7 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     373           7 :                     poDrv->Delete(poOutDS.get(),
     374          14 :                                   CPLStringList(poOutDS->GetFileList()).List());
     375             :                 }
     376             : #endif
     377           8 :                 poOutDS->MarkSuppressOnClose();
     378             :             }
     379             : 
     380          17 :             m_outputDataset.Set(std::move(poOutDS));
     381             :         }
     382             :     }
     383          17 :     return ok;
     384             : }
     385             : 
     386             : //! @endcond

Generated by: LCOV version 1.14