LCOV - code coverage report
Current view: top level - apps - gdalalg_materialize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 146 157 93.0 %
Date: 2026-02-21 16:21:44 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          44 : GDALMaterializeVectorAlgorithm::GDALMaterializeVectorAlgorithm()
     161             :     : GDALMaterializeStepAlgorithm<GDALVectorPipelineStepAlgorithm,
     162          44 :                                    GDAL_OF_VECTOR>(HELP_URL)
     163             : {
     164          44 :     AddVectorHiddenInputDatasetArg();
     165             : 
     166             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
     167             :                         /* positionalAndRequired = */ false,
     168          44 :                         _("Materialized dataset name"))
     169          44 :         .SetDatasetInputFlags(GADV_NAME);
     170             : 
     171          44 :     AddOutputFormatArg(&m_format)
     172             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
     173             :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE, GDAL_DCAP_OPEN,
     174         264 :                           GDAL_DMD_EXTENSIONS})
     175         132 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM"})
     176             :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS,
     177         220 :                          {"MBTiles", "MVT", "PMTiles", "JP2ECW"});
     178             : 
     179          44 :     AddCreationOptionsArg(&m_creationOptions);
     180          44 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
     181          44 :     AddOverwriteArg(&m_overwrite);
     182          44 : }
     183             : 
     184             : /************************************************************************/
     185             : /*              GDALMaterializeVectorAlgorithm::RunStep()               */
     186             : /************************************************************************/
     187             : 
     188           8 : bool GDALMaterializeVectorAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     189             : {
     190           8 :     auto pfnProgress = ctxt.m_pfnProgress;
     191           8 :     auto pProgressData = ctxt.m_pProgressData;
     192             : 
     193           8 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     194           8 :     CPLAssert(poSrcDS);
     195           8 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     196             : 
     197           8 :     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           8 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
     224           8 :     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          16 :     std::string filename = m_outputDataset.GetName();
     232             :     const bool autoDeleteFile =
     233           8 :         filename.empty() && !EQUAL(m_format.c_str(), "MEM");
     234           8 :     if (autoDeleteFile)
     235             :     {
     236           7 :         filename = CPLGenerateTempFilenameSafe(nullptr);
     237             : 
     238           7 :         const char *pszExt = poDrv->GetMetadataItem(GDAL_DMD_EXTENSIONS);
     239           7 :         if (pszExt)
     240             :         {
     241           7 :             filename += '.';
     242           7 :             filename += CPLStringList(CSLTokenizeString(pszExt))[0];
     243             :         }
     244             :     }
     245             : 
     246          16 :     CPLStringList aosOptions;
     247           8 :     aosOptions.AddString("--invoked-from-gdal-algorithm");
     248           8 :     if (!m_overwrite)
     249             :     {
     250           8 :         aosOptions.AddString("--no-overwrite");
     251             :     }
     252             : 
     253           8 :     aosOptions.AddString("-of");
     254           8 :     aosOptions.AddString(m_format.c_str());
     255           9 :     for (const auto &co : m_creationOptions)
     256             :     {
     257           1 :         aosOptions.AddString("-dsco");
     258           1 :         aosOptions.AddString(co.c_str());
     259             :     }
     260           8 :     if (EQUAL(m_format.c_str(), "SQLite"))
     261             :     {
     262             :         const char *pszCOList =
     263           2 :             poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     264           4 :         if (pszCOList && strstr(pszCOList, "SPATIALITE") &&
     265           4 :             CPLStringList(m_creationOptions).FetchNameValue("SPATIALITE") ==
     266             :                 nullptr)
     267             :         {
     268           1 :             aosOptions.AddString("-dsco");
     269           1 :             aosOptions.AddString("SPATIALITE=YES");
     270             :         }
     271             :     }
     272           9 :     for (const auto &co : m_layerCreationOptions)
     273             :     {
     274           1 :         aosOptions.AddString("-lco");
     275           1 :         aosOptions.AddString(co.c_str());
     276             :     }
     277           8 :     if (pfnProgress && pfnProgress != GDALDummyProgress)
     278             :     {
     279           1 :         aosOptions.AddString("-progress");
     280             :     }
     281             : 
     282           8 :     if (autoDeleteFile)
     283             :     {
     284           7 :         aosOptions.AddString("-dsco");
     285           7 :         aosOptions.AddString("@SUPPRESS_ASAP=YES");
     286             :     }
     287             : 
     288             :     GDALVectorTranslateOptions *psOptions =
     289           8 :         GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr);
     290           8 :     GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress,
     291             :                                           pProgressData);
     292             : 
     293           8 :     GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
     294             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     295             :         GDALDataset::FromHandle(GDALVectorTranslate(
     296           8 :             filename.c_str(), nullptr, 1, &hSrcDS, psOptions, nullptr)));
     297           8 :     GDALVectorTranslateOptionsFree(psOptions);
     298             : 
     299           8 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     300           8 :     if (poOutDS)
     301             :     {
     302           8 :         if (poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     303             :         {
     304           2 :             ok = poOutDS->Close() == CE_None;
     305           2 :             poOutDS.reset();
     306           2 :             if (ok)
     307             :             {
     308           2 :                 const char *const apszAllowedDrivers[] = {m_format.c_str(),
     309           2 :                                                           nullptr};
     310           2 :                 poOutDS.reset(GDALDataset::Open(
     311             :                     filename.c_str(), GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR,
     312             :                     apszAllowedDrivers));
     313           2 :                 ok = poOutDS != nullptr;
     314             :             }
     315             :         }
     316           8 :         if (ok)
     317             :         {
     318           8 :             if (autoDeleteFile)
     319             :             {
     320             : #if !defined(_WIN32)
     321           7 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     322             :                 {
     323           6 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     324           6 :                     poDrv->Delete(poOutDS.get(),
     325          12 :                                   CPLStringList(poOutDS->GetFileList()).List());
     326             :                 }
     327             : #endif
     328           7 :                 poOutDS->MarkSuppressOnClose();
     329             :             }
     330             : 
     331           8 :             m_outputDataset.Set(std::move(poOutDS));
     332             :         }
     333             :     }
     334           8 :     return ok;
     335             : }
     336             : 
     337             : //! @endcond

Generated by: LCOV version 1.14