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