LCOV - code coverage report
Current view: top level - apps - gdalalg_materialize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 149 160 93.1 %
Date: 2026-05-13 23:47:50 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          47 : GDALMaterializeRasterAlgorithm::GDALMaterializeRasterAlgorithm()
      29             :     : GDALMaterializeStepAlgorithm<GDALRasterPipelineStepAlgorithm,
      30          47 :                                    GDAL_OF_RASTER>(HELP_URL)
      31             : {
      32          47 :     AddRasterHiddenInputDatasetArg();
      33             : 
      34             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
      35             :                         /* positionalAndRequired = */ false,
      36          47 :                         _("Materialized dataset name"))
      37          47 :         .SetDatasetInputFlags(GADV_NAME);
      38             : 
      39          47 :     AddOutputFormatArg(&m_format)
      40             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      41             :                          {GDAL_DCAP_RASTER, GDAL_DCAP_CREATECOPY,
      42         282 :                           GDAL_DCAP_OPEN, GDAL_DMD_EXTENSIONS})
      43         188 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM", "COG"})
      44          94 :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS, {"VRT"});
      45             : 
      46          47 :     AddCreationOptionsArg(&m_creationOptions);
      47          47 :     AddOverwriteArg(&m_overwrite);
      48          47 : }
      49             : 
      50             : /************************************************************************/
      51             : /*              GDALMaterializeRasterAlgorithm::RunStep()               */
      52             : /************************************************************************/
      53             : 
      54           6 : bool GDALMaterializeRasterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
      55             : {
      56           6 :     auto pfnProgress = ctxt.m_pfnProgress;
      57           6 :     auto pProgressData = ctxt.m_pProgressData;
      58             : 
      59           6 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      60           6 :     CPLAssert(poSrcDS);
      61           6 :     CPLAssert(!m_outputDataset.GetDatasetRef());
      62             : 
      63           6 :     if (m_format.empty())
      64           3 :         m_format = "GTiff";
      65             : 
      66           6 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
      67           6 :     if (!poDrv)
      68             :     {
      69           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Driver %s does not exist",
      70             :                     m_format.c_str());
      71           0 :         return false;
      72             :     }
      73             : 
      74          12 :     std::string filename = m_outputDataset.GetName();
      75             :     const bool autoDeleteFile =
      76           6 :         filename.empty() && !EQUAL(m_format.c_str(), "MEM");
      77           6 :     if (autoDeleteFile)
      78             :     {
      79           4 :         filename = CPLGenerateTempFilenameSafe(nullptr);
      80             : 
      81           4 :         const char *pszExt = poDrv->GetMetadataItem(GDAL_DMD_EXTENSIONS);
      82           4 :         if (pszExt)
      83             :         {
      84           4 :             filename += '.';
      85           4 :             filename += CPLStringList(CSLTokenizeString(pszExt))[0];
      86             :         }
      87             :     }
      88             : 
      89          12 :     CPLStringList aosOptions(m_creationOptions);
      90           6 :     if (EQUAL(m_format.c_str(), "GTiff"))
      91             :     {
      92           3 :         if (aosOptions.FetchNameValue("TILED") == nullptr)
      93             :         {
      94           3 :             aosOptions.SetNameValue("TILED", "YES");
      95             :         }
      96           3 :         if (aosOptions.FetchNameValue("COPY_SRC_OVERVIEWS") == nullptr)
      97             :         {
      98           3 :             aosOptions.SetNameValue("COPY_SRC_OVERVIEWS", "YES");
      99             :         }
     100           3 :         if (aosOptions.FetchNameValue("COMPRESS") == nullptr)
     101             :         {
     102             :             const char *pszCOList =
     103           3 :                 poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     104             :             aosOptions.SetNameValue(
     105             :                 "COMPRESS",
     106           3 :                 pszCOList && strstr(pszCOList, "ZSTD") ? "ZSTD" : "DEFLATE");
     107             :         }
     108             :     }
     109             : 
     110           6 :     if (autoDeleteFile)
     111             :     {
     112           4 :         aosOptions.SetNameValue("@SUPPRESS_ASAP", "YES");
     113             :     }
     114             : 
     115             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     116           6 :         poDrv->CreateCopy(filename.c_str(), poSrcDS, false, aosOptions.List(),
     117           6 :                           pfnProgress, pProgressData));
     118           6 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     119           6 :     if (poOutDS)
     120             :     {
     121           6 :         if (poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     122             :         {
     123           0 :             ok = poOutDS->Close() == CE_None;
     124           0 :             poOutDS.reset();
     125           0 :             if (ok)
     126             :             {
     127           0 :                 const char *const apszAllowedDrivers[] = {m_format.c_str(),
     128           0 :                                                           nullptr};
     129           0 :                 poOutDS.reset(GDALDataset::Open(
     130             :                     filename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
     131             :                     apszAllowedDrivers));
     132           0 :                 ok = poOutDS != nullptr;
     133             :             }
     134             :         }
     135           6 :         if (ok)
     136             :         {
     137           6 :             if (autoDeleteFile)
     138             :             {
     139             : #if !defined(_WIN32)
     140           4 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     141             :                 {
     142           4 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     143           4 :                     poDrv->Delete(poOutDS.get(),
     144           8 :                                   CPLStringList(poOutDS->GetFileList()).List());
     145             :                 }
     146             : #endif
     147           4 :                 poOutDS->MarkSuppressOnClose();
     148             :             }
     149             : 
     150           6 :             m_outputDataset.Set(std::move(poOutDS));
     151             :         }
     152             :     }
     153           6 :     return ok;
     154             : }
     155             : 
     156             : /************************************************************************/
     157             : /*                   GDALMaterializeVectorAlgorithm()                   */
     158             : /************************************************************************/
     159             : 
     160          45 : GDALMaterializeVectorAlgorithm::GDALMaterializeVectorAlgorithm()
     161             :     : GDALMaterializeStepAlgorithm<GDALVectorPipelineStepAlgorithm,
     162          45 :                                    GDAL_OF_VECTOR>(HELP_URL)
     163             : {
     164          45 :     AddVectorHiddenInputDatasetArg();
     165             : 
     166             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
     167             :                         /* positionalAndRequired = */ false,
     168          45 :                         _("Materialized dataset name"))
     169          45 :         .SetDatasetInputFlags(GADV_NAME);
     170             : 
     171          45 :     AddOutputFormatArg(&m_format)
     172             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
     173             :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE, GDAL_DCAP_OPEN,
     174         270 :                           GDAL_DMD_EXTENSIONS})
     175         135 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM"})
     176             :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS,
     177         225 :                          {"MBTiles", "MVT", "PMTiles", "JP2ECW"});
     178             : 
     179          45 :     AddCreationOptionsArg(&m_creationOptions);
     180          45 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
     181          45 :     AddOverwriteArg(&m_overwrite);
     182          45 : }
     183             : 
     184             : /************************************************************************/
     185             : /*              GDALMaterializeVectorAlgorithm::RunStep()               */
     186             : /************************************************************************/
     187             : 
     188           9 : bool GDALMaterializeVectorAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     189             : {
     190           9 :     auto pfnProgress = ctxt.m_pfnProgress;
     191           9 :     auto pProgressData = ctxt.m_pProgressData;
     192             : 
     193           9 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     194           9 :     CPLAssert(poSrcDS);
     195           9 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     196             : 
     197           9 :     if (m_format.empty())
     198             :     {
     199           4 :         bool bSeveralGeomFields = false;
     200           8 :         for (const auto *poLayer : poSrcDS->GetLayers())
     201             :         {
     202           4 :             if (!bSeveralGeomFields)
     203           4 :                 bSeveralGeomFields =
     204           4 :                     poLayer->GetLayerDefn()->GetGeomFieldCount() > 1;
     205           7 :             if (!bSeveralGeomFields &&
     206           3 :                 poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
     207             :             {
     208           7 :                 for (const auto *poFieldDefn :
     209          17 :                      poLayer->GetLayerDefn()->GetFields())
     210             :                 {
     211           7 :                     const auto eType = poFieldDefn->GetType();
     212           7 :                     if (eType == OFTStringList || eType == OFTIntegerList ||
     213           6 :                         eType == OFTRealList || eType == OFTInteger64List)
     214             :                     {
     215           1 :                         bSeveralGeomFields = true;
     216             :                     }
     217             :                 }
     218             :             }
     219             :         }
     220           4 :         m_format = bSeveralGeomFields ? "SQLite" : "GPKG";
     221             :     }
     222             : 
     223           9 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
     224           9 :     if (!poDrv)
     225             :     {
     226           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Driver %s does not exist",
     227             :                     m_format.c_str());
     228           0 :         return false;
     229             :     }
     230             : 
     231          18 :     std::string filename = m_outputDataset.GetName();
     232             :     const bool autoDeleteFile =
     233           9 :         filename.empty() && !EQUAL(m_format.c_str(), "MEM");
     234           9 :     if (autoDeleteFile)
     235             :     {
     236           8 :         filename = CPLGenerateTempFilenameSafe(nullptr);
     237             : 
     238           8 :         const char *pszExt = poDrv->GetMetadataItem(GDAL_DMD_EXTENSIONS);
     239           8 :         if (pszExt)
     240             :         {
     241           8 :             filename += '.';
     242           8 :             filename += CPLStringList(CSLTokenizeString(pszExt))[0];
     243             :         }
     244             :     }
     245             : 
     246          18 :     CPLStringList aosOptions;
     247           9 :     aosOptions.AddString("--invoked-from-gdal-algorithm");
     248           9 :     if (!m_overwrite)
     249             :     {
     250           9 :         aosOptions.AddString("--no-overwrite");
     251             :     }
     252             : 
     253           9 :     aosOptions.AddString("-of");
     254           9 :     aosOptions.AddString(m_format.c_str());
     255          10 :     for (const auto &co : m_creationOptions)
     256             :     {
     257           1 :         aosOptions.AddString("-dsco");
     258           1 :         aosOptions.AddString(co.c_str());
     259             :     }
     260          18 :     CPLStringList aosReopenOpenOptions;
     261           9 :     if (EQUAL(m_format.c_str(), "SQLite"))
     262             :     {
     263             :         const char *pszCOList =
     264           3 :             poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     265           6 :         if (pszCOList && strstr(pszCOList, "SPATIALITE") &&
     266           6 :             CPLStringList(m_creationOptions).FetchNameValue("SPATIALITE") ==
     267             :                 nullptr)
     268             :         {
     269           2 :             aosOptions.AddString("-dsco");
     270           2 :             aosOptions.AddString("SPATIALITE=YES");
     271             :         }
     272           3 :         aosReopenOpenOptions.AddString("LIST_ALL_TABLES=YES");
     273             :     }
     274          10 :     for (const auto &co : m_layerCreationOptions)
     275             :     {
     276           1 :         aosOptions.AddString("-lco");
     277           1 :         aosOptions.AddString(co.c_str());
     278             :     }
     279           9 :     if (pfnProgress && pfnProgress != GDALDummyProgress)
     280             :     {
     281           1 :         aosOptions.AddString("-progress");
     282             :     }
     283             : 
     284           9 :     if (autoDeleteFile)
     285             :     {
     286           8 :         aosOptions.AddString("-dsco");
     287           8 :         aosOptions.AddString("@SUPPRESS_ASAP=YES");
     288             :     }
     289             : 
     290             :     GDALVectorTranslateOptions *psOptions =
     291           9 :         GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr);
     292           9 :     GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress,
     293             :                                           pProgressData);
     294             : 
     295           9 :     GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
     296             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     297             :         GDALDataset::FromHandle(GDALVectorTranslate(
     298           9 :             filename.c_str(), nullptr, 1, &hSrcDS, psOptions, nullptr)));
     299           9 :     GDALVectorTranslateOptionsFree(psOptions);
     300             : 
     301           9 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     302           9 :     if (poOutDS)
     303             :     {
     304           9 :         if (poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     305             :         {
     306           2 :             ok = poOutDS->Close() == CE_None;
     307           2 :             poOutDS.reset();
     308           2 :             if (ok)
     309             :             {
     310           2 :                 const char *const apszAllowedDrivers[] = {m_format.c_str(),
     311           2 :                                                           nullptr};
     312           2 :                 poOutDS.reset(GDALDataset::Open(
     313             :                     filename.c_str(), GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR,
     314           2 :                     apszAllowedDrivers, aosReopenOpenOptions.List()));
     315           2 :                 ok = poOutDS != nullptr;
     316             :             }
     317             :         }
     318           9 :         if (ok)
     319             :         {
     320           9 :             if (autoDeleteFile)
     321             :             {
     322             : #if !defined(_WIN32)
     323           8 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     324             :                 {
     325           7 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     326           7 :                     poDrv->Delete(poOutDS.get(),
     327          14 :                                   CPLStringList(poOutDS->GetFileList()).List());
     328             :                 }
     329             : #endif
     330           8 :                 poOutDS->MarkSuppressOnClose();
     331             :             }
     332             : 
     333           9 :             m_outputDataset.Set(std::move(poOutDS));
     334             :         }
     335             :     }
     336           9 :     return ok;
     337             : }
     338             : 
     339             : //! @endcond

Generated by: LCOV version 1.14