LCOV - code coverage report
Current view: top level - apps - gdalalg_materialize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 179 183 97.8 %
Date: 2026-06-23 16:35:19 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          61 : GDALMaterializeRasterAlgorithm::GDALMaterializeRasterAlgorithm()
      29             :     : GDALMaterializeStepAlgorithm<GDALRasterPipelineStepAlgorithm,
      30          61 :                                    GDAL_OF_RASTER>(HELP_URL)
      31             : {
      32          61 :     AddRasterHiddenInputDatasetArg();
      33             : 
      34             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
      35             :                         /* positionalAndRequired = */ false,
      36          61 :                         _("Materialized dataset name"))
      37          61 :         .SetDatasetInputFlags(GADV_NAME);
      38             : 
      39          61 :     AddOutputFormatArg(&m_format)
      40             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      41             :                          {GDAL_DCAP_RASTER, GDAL_DCAP_CREATECOPY,
      42         366 :                           GDAL_DCAP_OPEN, GDAL_DMD_EXTENSIONS})
      43         244 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM", "COG"})
      44         122 :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS, {"VRT"});
      45             : 
      46          61 :     AddCreationOptionsArg(&m_creationOptions);
      47          61 :     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         122 :            &m_reopenAndDoNotEarlyDelete)
      52          61 :         .SetHidden();
      53          61 : }
      54             : 
      55             : /************************************************************************/
      56             : /*              GDALMaterializeRasterAlgorithm::RunStep()               */
      57             : /************************************************************************/
      58             : 
      59          19 : bool GDALMaterializeRasterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
      60             : {
      61          19 :     auto pfnProgress = ctxt.m_pfnProgress;
      62          19 :     auto pProgressData = ctxt.m_pProgressData;
      63             : 
      64          19 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      65          19 :     CPLAssert(poSrcDS);
      66          19 :     CPLAssert(!m_outputDataset.GetDatasetRef());
      67             : 
      68          38 :     std::string filename = m_outputDataset.GetName();
      69          19 :     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          18 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
      93          18 :     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          33 :                                 filename.empty() &&
     102           5 :                                 !EQUAL(m_format.c_str(), "MEM");
     103          18 :     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          36 :     CPLStringList aosOptions(m_creationOptions);
     116          18 :     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          18 :     if (autoDeleteFile)
     137             :     {
     138           4 :         aosOptions.SetNameValue("@SUPPRESS_ASAP", "YES");
     139             :     }
     140             : 
     141             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     142          18 :         poDrv->CreateCopy(filename.c_str(), poSrcDS, false, aosOptions.List(),
     143          18 :                           pfnProgress, pProgressData));
     144          18 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     145          18 :     if (poOutDS)
     146             :     {
     147          33 :         if (m_reopenAndDoNotEarlyDelete ||
     148          15 :             poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     149             :         {
     150           3 :             ok = poOutDS->Close() == CE_None;
     151           3 :             poOutDS.reset();
     152           3 :             if (ok)
     153             :             {
     154           6 :                 std::string reopenFormat = m_format;
     155           3 :                 if (m_format == "COG")
     156           1 :                     reopenFormat = "GTiff";
     157           3 :                 const char *const apszAllowedDrivers[] = {reopenFormat.c_str(),
     158           3 :                                                           nullptr};
     159           3 :                 poOutDS.reset(GDALDataset::Open(
     160             :                     filename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
     161             :                     apszAllowedDrivers));
     162           3 :                 ok = poOutDS != nullptr;
     163             :             }
     164             :         }
     165          18 :         if (ok)
     166             :         {
     167          18 :             if (autoDeleteFile)
     168             :             {
     169             : #if !defined(_WIN32)
     170           4 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     171             :                 {
     172           4 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     173           4 :                     poDrv->Delete(poOutDS.get(),
     174           8 :                                   CPLStringList(poOutDS->GetFileList()).List());
     175             :                 }
     176             : #endif
     177           4 :                 poOutDS->MarkSuppressOnClose();
     178             :             }
     179             : 
     180          18 :             m_outputDataset.Set(std::move(poOutDS));
     181             :         }
     182             :     }
     183          18 :     return ok;
     184             : }
     185             : 
     186             : /************************************************************************/
     187             : /*                   GDALMaterializeVectorAlgorithm()                   */
     188             : /************************************************************************/
     189             : 
     190          56 : GDALMaterializeVectorAlgorithm::GDALMaterializeVectorAlgorithm()
     191             :     : GDALMaterializeStepAlgorithm<GDALVectorPipelineStepAlgorithm,
     192          56 :                                    GDAL_OF_VECTOR>(HELP_URL)
     193             : {
     194          56 :     AddVectorHiddenInputDatasetArg();
     195             : 
     196             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
     197             :                         /* positionalAndRequired = */ false,
     198          56 :                         _("Materialized dataset name"))
     199          56 :         .SetDatasetInputFlags(GADV_NAME);
     200             : 
     201          56 :     AddOutputFormatArg(&m_format)
     202             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
     203             :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE, GDAL_DCAP_OPEN,
     204         336 :                           GDAL_DMD_EXTENSIONS})
     205         168 :         .AddMetadataItem(GAAMDI_ALLOWED_FORMATS, {"MEM"})
     206             :         .AddMetadataItem(GAAMDI_EXCLUDED_FORMATS,
     207         280 :                          {"MBTiles", "MVT", "PMTiles", "JP2ECW"});
     208             : 
     209          56 :     AddCreationOptionsArg(&m_creationOptions);
     210          56 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
     211          56 :     AddOverwriteArg(&m_overwrite);
     212          56 : }
     213             : 
     214             : /************************************************************************/
     215             : /*              GDALMaterializeVectorAlgorithm::RunStep()               */
     216             : /************************************************************************/
     217             : 
     218          18 : bool GDALMaterializeVectorAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     219             : {
     220          18 :     auto pfnProgress = ctxt.m_pfnProgress;
     221          18 :     auto pProgressData = ctxt.m_pProgressData;
     222             : 
     223          18 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     224          18 :     CPLAssert(poSrcDS);
     225          18 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     226             : 
     227          36 :     std::string filename = m_outputDataset.GetName();
     228          18 :     if (m_format.empty())
     229             :     {
     230           8 :         if (filename.empty())
     231             :         {
     232           4 :             bool bSeveralGeomFields = false;
     233           8 :             for (const auto *poLayer : poSrcDS->GetLayers())
     234             :             {
     235           4 :                 if (!bSeveralGeomFields)
     236           4 :                     bSeveralGeomFields =
     237           4 :                         poLayer->GetLayerDefn()->GetGeomFieldCount() > 1;
     238           7 :                 if (!bSeveralGeomFields &&
     239           3 :                     poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
     240             :                 {
     241           7 :                     for (const auto *poFieldDefn :
     242          17 :                          poLayer->GetLayerDefn()->GetFields())
     243             :                     {
     244           7 :                         const auto eType = poFieldDefn->GetType();
     245           7 :                         if (eType == OFTStringList || eType == OFTIntegerList ||
     246           6 :                             eType == OFTRealList || eType == OFTInteger64List)
     247             :                         {
     248           1 :                             bSeveralGeomFields = true;
     249             :                         }
     250             :                     }
     251             :                 }
     252             :             }
     253           4 :             m_format = bSeveralGeomFields ? "SQLite" : "GPKG";
     254             :         }
     255             :         else
     256             :         {
     257             :             const auto aosFormats =
     258             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
     259             :                     filename.c_str(), GDAL_OF_VECTOR,
     260             :                     /* bSingleMatch = */ true,
     261           4 :                     /* bWarn = */ true));
     262           4 :             if (aosFormats.size() != 1)
     263             :             {
     264           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     265             :                             "Cannot guess driver for %s", filename.c_str());
     266           1 :                 return false;
     267             :             }
     268           3 :             m_format = aosFormats[0];
     269             :         }
     270             :     }
     271             : 
     272          17 :     auto poDrv = GetGDALDriverManager()->GetDriverByName(m_format.c_str());
     273          17 :     if (!poDrv)
     274             :     {
     275           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Driver %s does not exist",
     276             :                     m_format.c_str());
     277           0 :         return false;
     278             :     }
     279             : 
     280          17 :     const bool autoDeleteFile = !m_reopenAndDoNotEarlyDelete &&
     281          34 :                                 filename.empty() &&
     282           9 :                                 !EQUAL(m_format.c_str(), "MEM");
     283          17 :     if (filename.empty() && !EQUAL(m_format.c_str(), "MEM"))
     284             :     {
     285           8 :         filename = CPLGenerateTempFilenameSafe(nullptr);
     286             : 
     287           8 :         const char *pszExt = poDrv->GetMetadataItem(GDAL_DMD_EXTENSIONS);
     288           8 :         if (pszExt)
     289             :         {
     290           8 :             filename += '.';
     291           8 :             filename += CPLStringList(CSLTokenizeString(pszExt))[0];
     292             :         }
     293             :     }
     294             : 
     295          34 :     CPLStringList aosOptions;
     296          17 :     aosOptions.AddString("--invoked-from-gdal-algorithm");
     297          17 :     if (!m_overwrite)
     298             :     {
     299          17 :         aosOptions.AddString("--no-overwrite");
     300             :     }
     301             : 
     302          17 :     aosOptions.AddString("-of");
     303          17 :     aosOptions.AddString(m_format.c_str());
     304          18 :     for (const auto &co : m_creationOptions)
     305             :     {
     306           1 :         aosOptions.AddString("-dsco");
     307           1 :         aosOptions.AddString(co.c_str());
     308             :     }
     309          34 :     CPLStringList aosReopenOpenOptions;
     310          17 :     if (EQUAL(m_format.c_str(), "SQLite"))
     311             :     {
     312             :         const char *pszCOList =
     313           3 :             poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     314           6 :         if (pszCOList && strstr(pszCOList, "SPATIALITE") &&
     315           6 :             CPLStringList(m_creationOptions).FetchNameValue("SPATIALITE") ==
     316             :                 nullptr)
     317             :         {
     318           2 :             aosOptions.AddString("-dsco");
     319           2 :             aosOptions.AddString("SPATIALITE=YES");
     320             :         }
     321           3 :         aosReopenOpenOptions.AddString("LIST_ALL_TABLES=YES");
     322             :     }
     323          18 :     for (const auto &co : m_layerCreationOptions)
     324             :     {
     325           1 :         aosOptions.AddString("-lco");
     326           1 :         aosOptions.AddString(co.c_str());
     327             :     }
     328          17 :     if (pfnProgress && pfnProgress != GDALDummyProgress)
     329             :     {
     330           1 :         aosOptions.AddString("-progress");
     331             :     }
     332             : 
     333          17 :     if (autoDeleteFile)
     334             :     {
     335           8 :         aosOptions.AddString("-dsco");
     336           8 :         aosOptions.AddString("@SUPPRESS_ASAP=YES");
     337             :     }
     338             : 
     339             :     GDALVectorTranslateOptions *psOptions =
     340          17 :         GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr);
     341          17 :     GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress,
     342             :                                           pProgressData);
     343             : 
     344          17 :     GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
     345             :     auto poOutDS = std::unique_ptr<GDALDataset>(
     346             :         GDALDataset::FromHandle(GDALVectorTranslate(
     347          17 :             filename.c_str(), nullptr, 1, &hSrcDS, psOptions, nullptr)));
     348          17 :     GDALVectorTranslateOptionsFree(psOptions);
     349             : 
     350          17 :     bool ok = poOutDS != nullptr && poOutDS->FlushCache() == CE_None;
     351          17 :     if (poOutDS)
     352             :     {
     353          34 :         if (m_reopenAndDoNotEarlyDelete ||
     354          17 :             poDrv->GetMetadataItem(GDAL_DCAP_REOPEN_AFTER_WRITE_REQUIRED))
     355             :         {
     356           2 :             ok = poOutDS->Close() == CE_None;
     357           2 :             poOutDS.reset();
     358           2 :             if (ok)
     359             :             {
     360           2 :                 const char *const apszAllowedDrivers[] = {m_format.c_str(),
     361           2 :                                                           nullptr};
     362           2 :                 poOutDS.reset(GDALDataset::Open(
     363             :                     filename.c_str(), GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR,
     364           2 :                     apszAllowedDrivers, aosReopenOpenOptions.List()));
     365           2 :                 ok = poOutDS != nullptr;
     366             :             }
     367             :         }
     368          17 :         if (ok)
     369             :         {
     370          17 :             if (autoDeleteFile)
     371             :             {
     372             : #if !defined(_WIN32)
     373           8 :                 if (poDrv->GetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE))
     374             :                 {
     375           7 :                     CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     376           7 :                     poDrv->Delete(poOutDS.get(),
     377          14 :                                   CPLStringList(poOutDS->GetFileList()).List());
     378             :                 }
     379             : #endif
     380           8 :                 poOutDS->MarkSuppressOnClose();
     381             :             }
     382             : 
     383          17 :             m_outputDataset.Set(std::move(poOutDS));
     384             :         }
     385             :     }
     386          17 :     return ok;
     387             : }
     388             : 
     389             : //! @endcond

Generated by: LCOV version 1.14