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
|