Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "vector pipeline" subcommand
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_vector_pipeline.h"
14 : #include "gdalalg_materialize.h"
15 : #include "gdalalg_vector_read.h"
16 : #include "gdalalg_vector_buffer.h"
17 : #include "gdalalg_vector_change_field_type.h"
18 : #include "gdalalg_vector_check_coverage.h"
19 : #include "gdalalg_vector_check_geometry.h"
20 : #include "gdalalg_vector_clean_coverage.h"
21 : #include "gdalalg_vector_clip.h"
22 : #include "gdalalg_vector_concat.h"
23 : #include "gdalalg_vector_edit.h"
24 : #include "gdalalg_vector_explode_collections.h"
25 : #include "gdalalg_vector_filter.h"
26 : #include "gdalalg_vector_geom.h"
27 : #include "gdalalg_vector_info.h"
28 : #include "gdalalg_vector_make_valid.h"
29 : #include "gdalalg_vector_partition.h"
30 : #include "gdalalg_vector_reproject.h"
31 : #include "gdalalg_vector_segmentize.h"
32 : #include "gdalalg_vector_select.h"
33 : #include "gdalalg_vector_set_geom_type.h"
34 : #include "gdalalg_vector_simplify.h"
35 : #include "gdalalg_vector_simplify_coverage.h"
36 : #include "gdalalg_vector_sql.h"
37 : #include "gdalalg_vector_swap_xy.h"
38 : #include "gdalalg_vector_write.h"
39 : #include "gdalalg_tee.h"
40 :
41 : #include "../frmts/mem/memdataset.h"
42 :
43 : #include "cpl_conv.h"
44 : #include "cpl_string.h"
45 :
46 : #include <algorithm>
47 : #include <cassert>
48 :
49 : //! @cond Doxygen_Suppress
50 :
51 : #ifndef _
52 : #define _(x) (x)
53 : #endif
54 :
55 : GDALVectorAlgorithmStepRegistry::~GDALVectorAlgorithmStepRegistry() = default;
56 :
57 : /************************************************************************/
58 : /* GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm() */
59 : /************************************************************************/
60 :
61 1917 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
62 : const std::string &name, const std::string &description,
63 1917 : const std::string &helpURL, bool standaloneStep)
64 : : GDALVectorPipelineStepAlgorithm(
65 : name, description, helpURL,
66 1917 : ConstructorOptions().SetStandaloneStep(standaloneStep))
67 : {
68 1917 : }
69 :
70 : /************************************************************************/
71 : /* GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm() */
72 : /************************************************************************/
73 :
74 2374 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
75 : const std::string &name, const std::string &description,
76 2374 : const std::string &helpURL, const ConstructorOptions &options)
77 2374 : : GDALPipelineStepAlgorithm(name, description, helpURL, options)
78 : {
79 2374 : if (m_standaloneStep)
80 : {
81 415 : m_supportsStreamedOutput = true;
82 :
83 415 : if (m_constructorOptions.addDefaultArguments)
84 : {
85 314 : AddVectorInputArgs(false);
86 314 : AddProgressArg();
87 314 : AddVectorOutputArgs(false, false);
88 : }
89 : }
90 2374 : }
91 :
92 : GDALVectorPipelineStepAlgorithm::~GDALVectorPipelineStepAlgorithm() = default;
93 :
94 : /************************************************************************/
95 : /* GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm() */
96 : /************************************************************************/
97 :
98 94 : GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()
99 : : GDALAbstractPipelineAlgorithm(
100 : NAME, DESCRIPTION, HELP_URL,
101 94 : ConstructorOptions().SetInputDatasetMaxCount(INT_MAX))
102 : {
103 94 : m_supportsStreamedOutput = true;
104 :
105 94 : AddVectorInputArgs(/* hiddenForCLI = */ true);
106 94 : AddProgressArg();
107 188 : AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
108 94 : .SetHiddenForCLI()
109 94 : .SetPositional();
110 94 : AddVectorOutputArgs(/* hiddenForCLI = */ true,
111 : /* shortNameOutputLayerAllowed=*/false);
112 :
113 94 : AddOutputStringArg(&m_output).SetHiddenForCLI();
114 94 : AddStdoutArg(&m_stdout);
115 :
116 94 : RegisterAlgorithms(m_stepRegistry, false);
117 94 : }
118 :
119 : /************************************************************************/
120 : /* GDALVectorPipelineAlgorithm::RegisterAlgorithms() */
121 : /************************************************************************/
122 :
123 : /* static */
124 275 : void GDALVectorPipelineAlgorithm::RegisterAlgorithms(
125 : GDALVectorAlgorithmStepRegistry ®istry, bool forMixedPipeline)
126 : {
127 275 : GDALAlgorithmRegistry::AlgInfo algInfo;
128 :
129 : const auto addSuffixIfNeeded =
130 2750 : [forMixedPipeline](const char *name) -> std::string
131 : {
132 4560 : return forMixedPipeline ? std::string(name).append(VECTOR_SUFFIX)
133 7310 : : std::string(name);
134 275 : };
135 :
136 275 : registry.Register<GDALVectorReadAlgorithm>(
137 550 : addSuffixIfNeeded(GDALVectorReadAlgorithm::NAME));
138 :
139 275 : registry.Register<GDALVectorWriteAlgorithm>(
140 550 : addSuffixIfNeeded(GDALVectorWriteAlgorithm::NAME));
141 :
142 275 : registry.Register<GDALVectorInfoAlgorithm>(
143 550 : addSuffixIfNeeded(GDALVectorInfoAlgorithm::NAME));
144 :
145 275 : registry.Register<GDALVectorBufferAlgorithm>();
146 275 : registry.Register<GDALVectorChangeFieldTypeAlgorithm>(
147 550 : addSuffixIfNeeded(GDALVectorChangeFieldTypeAlgorithm::NAME));
148 275 : registry.Register<GDALVectorCheckCoverageAlgorithm>();
149 275 : registry.Register<GDALVectorCheckGeometryAlgorithm>();
150 275 : registry.Register<GDALVectorConcatAlgorithm>();
151 275 : registry.Register<GDALVectorCleanCoverageAlgorithm>();
152 :
153 275 : registry.Register<GDALVectorClipAlgorithm>(
154 550 : addSuffixIfNeeded(GDALVectorClipAlgorithm::NAME));
155 :
156 275 : registry.Register<GDALVectorEditAlgorithm>(
157 550 : addSuffixIfNeeded(GDALVectorEditAlgorithm::NAME));
158 :
159 275 : registry.Register<GDALVectorExplodeCollectionsAlgorithm>();
160 :
161 275 : registry.Register<GDALMaterializeVectorAlgorithm>(
162 550 : addSuffixIfNeeded(GDALMaterializeVectorAlgorithm::NAME));
163 :
164 275 : registry.Register<GDALVectorReprojectAlgorithm>(
165 550 : addSuffixIfNeeded(GDALVectorReprojectAlgorithm::NAME));
166 :
167 275 : registry.Register<GDALVectorFilterAlgorithm>();
168 275 : registry.Register<GDALVectorGeomAlgorithm>();
169 275 : registry.Register<GDALVectorMakeValidAlgorithm>();
170 275 : registry.Register<GDALVectorPartitionAlgorithm>();
171 275 : registry.Register<GDALVectorSegmentizeAlgorithm>();
172 :
173 275 : registry.Register<GDALVectorSelectAlgorithm>(
174 550 : addSuffixIfNeeded(GDALVectorSelectAlgorithm::NAME));
175 :
176 275 : registry.Register<GDALVectorSetGeomTypeAlgorithm>();
177 275 : registry.Register<GDALVectorSimplifyAlgorithm>();
178 275 : registry.Register<GDALVectorSimplifyCoverageAlgorithm>();
179 275 : registry.Register<GDALVectorSQLAlgorithm>();
180 275 : registry.Register<GDALVectorSwapXYAlgorithm>();
181 :
182 275 : registry.Register<GDALTeeVectorAlgorithm>(
183 550 : addSuffixIfNeeded(GDALTeeVectorAlgorithm::NAME));
184 275 : }
185 :
186 : /************************************************************************/
187 : /* GDALVectorPipelineAlgorithm::GetUsageForCLI() */
188 : /************************************************************************/
189 :
190 8 : std::string GDALVectorPipelineAlgorithm::GetUsageForCLI(
191 : bool shortUsage, const UsageOptions &usageOptions) const
192 : {
193 8 : UsageOptions stepUsageOptions;
194 8 : stepUsageOptions.isPipelineStep = true;
195 :
196 8 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
197 : {
198 4 : auto alg = GetStepAlg(m_helpDocCategory);
199 2 : if (alg)
200 : {
201 2 : alg->SetCallPath({m_helpDocCategory});
202 1 : alg->GetArg("help-doc")->Set(true);
203 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
204 : }
205 : else
206 : {
207 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
208 : m_helpDocCategory.c_str());
209 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
210 1 : m_helpDocCategory.c_str());
211 : }
212 : }
213 :
214 6 : UsageOptions usageOptionsMain(usageOptions);
215 6 : usageOptionsMain.isPipelineMain = true;
216 : std::string ret =
217 12 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
218 6 : if (shortUsage)
219 2 : return ret;
220 :
221 : ret += "\n<PIPELINE> is of the form: read|concat [READ-OPTIONS] "
222 4 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write|info [WRITE-OPTIONS]\n";
223 :
224 4 : if (m_helpDocCategory == "main")
225 : {
226 1 : return ret;
227 : }
228 :
229 3 : ret += '\n';
230 3 : ret += "Example: 'gdal vector pipeline --progress ! read in.gpkg ! \\\n";
231 3 : ret += " reproject --dst-crs=EPSG:32632 ! ";
232 3 : ret += "write out.gpkg --overwrite'\n";
233 3 : ret += '\n';
234 3 : ret += "Potential steps are:\n";
235 :
236 81 : for (const std::string &name : m_stepRegistry.GetNames())
237 : {
238 156 : auto alg = GetStepAlg(name);
239 78 : assert(alg);
240 78 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
241 78 : stepUsageOptions.maxOptLen =
242 78 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
243 : }
244 :
245 : {
246 3 : const auto name = GDALVectorReadAlgorithm::NAME;
247 3 : ret += '\n';
248 6 : auto alg = GetStepAlg(name);
249 6 : alg->SetCallPath({name});
250 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
251 : }
252 81 : for (const std::string &name : m_stepRegistry.GetNames())
253 : {
254 156 : auto alg = GetStepAlg(name);
255 78 : assert(alg);
256 84 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
257 84 : !alg->IsHidden() && name != GDALVectorReadAlgorithm::NAME)
258 : {
259 3 : ret += '\n';
260 6 : alg->SetCallPath({name});
261 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
262 : }
263 : }
264 81 : for (const std::string &name : m_stepRegistry.GetNames())
265 : {
266 156 : auto alg = GetStepAlg(name);
267 78 : assert(alg);
268 78 : if (alg->CanBeMiddleStep() && !alg->IsHidden())
269 : {
270 60 : ret += '\n';
271 120 : alg->SetCallPath({name});
272 60 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
273 : }
274 : }
275 81 : for (const std::string &name : m_stepRegistry.GetNames())
276 : {
277 156 : auto alg = GetStepAlg(name);
278 78 : assert(alg);
279 90 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
280 90 : !alg->IsHidden() && name != GDALVectorWriteAlgorithm::NAME)
281 : {
282 6 : ret += '\n';
283 12 : alg->SetCallPath({name});
284 6 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
285 : }
286 : }
287 : {
288 3 : const auto name = GDALVectorWriteAlgorithm::NAME;
289 3 : ret += '\n';
290 6 : auto alg = GetStepAlg(name);
291 6 : alg->SetCallPath({name});
292 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
293 : }
294 :
295 3 : ret += GetUsageForCLIEnd();
296 :
297 3 : return ret;
298 : }
299 :
300 : /************************************************************************/
301 : /* GDALVectorPipelineOutputLayer */
302 : /************************************************************************/
303 :
304 : /************************************************************************/
305 : /* GDALVectorPipelineOutputLayer() */
306 : /************************************************************************/
307 :
308 162 : GDALVectorPipelineOutputLayer::GDALVectorPipelineOutputLayer(OGRLayer &srcLayer)
309 162 : : m_srcLayer(srcLayer)
310 : {
311 162 : }
312 :
313 : /************************************************************************/
314 : /* ~GDALVectorPipelineOutputLayer() */
315 : /************************************************************************/
316 :
317 : GDALVectorPipelineOutputLayer::~GDALVectorPipelineOutputLayer() = default;
318 :
319 : /************************************************************************/
320 : /* GDALVectorPipelineOutputLayer::ResetReading() */
321 : /************************************************************************/
322 :
323 563 : void GDALVectorPipelineOutputLayer::ResetReading()
324 : {
325 563 : m_srcLayer.ResetReading();
326 563 : m_pendingFeatures.clear();
327 563 : m_idxInPendingFeatures = 0;
328 563 : }
329 :
330 : /************************************************************************/
331 : /* GDALVectorPipelineOutputLayer::GetNextRawFeature() */
332 : /************************************************************************/
333 :
334 2024 : OGRFeature *GDALVectorPipelineOutputLayer::GetNextRawFeature()
335 : {
336 2024 : if (m_idxInPendingFeatures < m_pendingFeatures.size())
337 : {
338 : OGRFeature *poFeature =
339 14 : m_pendingFeatures[m_idxInPendingFeatures].release();
340 14 : ++m_idxInPendingFeatures;
341 14 : return poFeature;
342 : }
343 2010 : m_pendingFeatures.clear();
344 2010 : m_idxInPendingFeatures = 0;
345 : while (true)
346 : {
347 : auto poSrcFeature =
348 2019 : std::unique_ptr<OGRFeature>(m_srcLayer.GetNextFeature());
349 2019 : if (!poSrcFeature)
350 255 : return nullptr;
351 1764 : TranslateFeature(std::move(poSrcFeature), m_pendingFeatures);
352 1764 : if (!m_pendingFeatures.empty())
353 1755 : break;
354 9 : }
355 1755 : OGRFeature *poFeature = m_pendingFeatures[0].release();
356 1755 : m_idxInPendingFeatures = 1;
357 1755 : return poFeature;
358 : }
359 :
360 : /************************************************************************/
361 : /* GDALVectorPipelineOutputDataset */
362 : /************************************************************************/
363 :
364 : /************************************************************************/
365 : /* GDALVectorPipelineOutputDataset() */
366 : /************************************************************************/
367 :
368 153 : GDALVectorPipelineOutputDataset::GDALVectorPipelineOutputDataset(
369 153 : GDALDataset &srcDS)
370 153 : : m_srcDS(srcDS)
371 : {
372 153 : SetDescription(m_srcDS.GetDescription());
373 153 : SetMetadata(m_srcDS.GetMetadata());
374 153 : }
375 :
376 : /************************************************************************/
377 : /* GDALVectorPipelineOutputDataset::AddLayer() */
378 : /************************************************************************/
379 :
380 164 : void GDALVectorPipelineOutputDataset::AddLayer(
381 : OGRLayer &oSrcLayer,
382 : std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer)
383 : {
384 164 : m_layersToDestroy.push_back(std::move(poNewLayer));
385 : OGRLayerWithTranslateFeature *poNewLayerRaw =
386 164 : m_layersToDestroy.back().get();
387 164 : m_layers.push_back(poNewLayerRaw);
388 164 : m_mapSrcLayerToNewLayer[&oSrcLayer] = poNewLayerRaw;
389 164 : }
390 :
391 : /************************************************************************/
392 : /* GDALVectorPipelineOutputDataset::GetLayerCount() */
393 : /************************************************************************/
394 :
395 522 : int GDALVectorPipelineOutputDataset::GetLayerCount() const
396 : {
397 522 : return static_cast<int>(m_layers.size());
398 : }
399 :
400 : /************************************************************************/
401 : /* GDALVectorPipelineOutputDataset::GetLayer() */
402 : /************************************************************************/
403 :
404 246 : OGRLayer *GDALVectorPipelineOutputDataset::GetLayer(int idx) const
405 : {
406 246 : return idx >= 0 && idx < GetLayerCount() ? m_layers[idx] : nullptr;
407 : }
408 :
409 : /************************************************************************/
410 : /* GDALVectorPipelineOutputDataset::TestCapability() */
411 : /************************************************************************/
412 :
413 110 : int GDALVectorPipelineOutputDataset::TestCapability(const char *pszCap) const
414 : {
415 110 : if (EQUAL(pszCap, ODsCRandomLayerRead) ||
416 31 : EQUAL(pszCap, ODsCMeasuredGeometries) || EQUAL(pszCap, ODsCZGeometries))
417 : {
418 94 : return m_srcDS.TestCapability(pszCap);
419 : }
420 16 : return false;
421 : }
422 :
423 : /************************************************************************/
424 : /* GDALVectorPipelineOutputDataset::ResetReading() */
425 : /************************************************************************/
426 :
427 3 : void GDALVectorPipelineOutputDataset::ResetReading()
428 : {
429 3 : m_srcDS.ResetReading();
430 3 : m_pendingFeatures.clear();
431 3 : m_idxInPendingFeatures = 0;
432 3 : }
433 :
434 : /************************************************************************/
435 : /* GDALVectorPipelineOutputDataset::GetNextFeature() */
436 : /************************************************************************/
437 :
438 23 : OGRFeature *GDALVectorPipelineOutputDataset::GetNextFeature(
439 : OGRLayer **ppoBelongingLayer, double *pdfProgressPct,
440 : GDALProgressFunc pfnProgress, void *pProgressData)
441 : {
442 23 : if (m_idxInPendingFeatures < m_pendingFeatures.size())
443 : {
444 : OGRFeature *poFeature =
445 3 : m_pendingFeatures[m_idxInPendingFeatures].release();
446 3 : if (ppoBelongingLayer)
447 3 : *ppoBelongingLayer = m_belongingLayer;
448 3 : ++m_idxInPendingFeatures;
449 3 : return poFeature;
450 : }
451 :
452 20 : m_pendingFeatures.clear();
453 20 : m_idxInPendingFeatures = 0;
454 :
455 : while (true)
456 : {
457 20 : OGRLayer *poSrcBelongingLayer = nullptr;
458 20 : auto poSrcFeature = std::unique_ptr<OGRFeature>(m_srcDS.GetNextFeature(
459 20 : &poSrcBelongingLayer, pdfProgressPct, pfnProgress, pProgressData));
460 20 : if (!poSrcFeature)
461 3 : return nullptr;
462 17 : auto iterToDstLayer = m_mapSrcLayerToNewLayer.find(poSrcBelongingLayer);
463 17 : if (iterToDstLayer != m_mapSrcLayerToNewLayer.end())
464 : {
465 17 : m_belongingLayer = iterToDstLayer->second;
466 17 : m_belongingLayer->TranslateFeature(std::move(poSrcFeature),
467 17 : m_pendingFeatures);
468 17 : if (!m_pendingFeatures.empty())
469 17 : break;
470 : }
471 0 : }
472 17 : OGRFeature *poFeature = m_pendingFeatures[0].release();
473 17 : if (ppoBelongingLayer)
474 17 : *ppoBelongingLayer = m_belongingLayer;
475 17 : m_idxInPendingFeatures = 1;
476 17 : return poFeature;
477 : }
478 :
479 : /************************************************************************/
480 : /* GDALVectorPipelinePassthroughLayer::GetLayerDefn() */
481 : /************************************************************************/
482 :
483 33 : const OGRFeatureDefn *GDALVectorPipelinePassthroughLayer::GetLayerDefn() const
484 : {
485 33 : return m_srcLayer.GetLayerDefn();
486 : }
487 :
488 : /************************************************************************/
489 : /* GDALVectorNonStreamingAlgorithmDataset() */
490 : /************************************************************************/
491 :
492 30 : GDALVectorNonStreamingAlgorithmDataset::GDALVectorNonStreamingAlgorithmDataset()
493 30 : : m_ds(MEMDataset::Create("", 0, 0, 0, GDT_Unknown, nullptr))
494 : {
495 30 : }
496 :
497 : /************************************************************************/
498 : /* ~GDALVectorNonStreamingAlgorithmDataset() */
499 : /************************************************************************/
500 :
501 : GDALVectorNonStreamingAlgorithmDataset::
502 : ~GDALVectorNonStreamingAlgorithmDataset() = default;
503 :
504 : /************************************************************************/
505 : /* GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer() */
506 : /************************************************************************/
507 :
508 26 : bool GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer(
509 : OGRLayer &srcLayer, OGRFeatureDefn &dstDefn)
510 : {
511 26 : CPLStringList aosOptions;
512 26 : if (srcLayer.TestCapability(OLCStringsAsUTF8))
513 : {
514 1 : aosOptions.AddNameValue("ADVERTIZE_UTF8", "TRUE");
515 : }
516 :
517 26 : OGRMemLayer *poDstLayer = m_ds->CreateLayer(dstDefn, aosOptions.List());
518 26 : m_layers.push_back(poDstLayer);
519 :
520 26 : const bool bRet = Process(srcLayer, *poDstLayer);
521 26 : poDstLayer->SetUpdatable(false);
522 52 : return bRet;
523 : }
524 :
525 20 : bool GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer(
526 : OGRLayer &srcLayer)
527 : {
528 20 : return AddProcessedLayer(srcLayer, *srcLayer.GetLayerDefn());
529 : }
530 :
531 : /************************************************************************/
532 : /* GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer() */
533 : /************************************************************************/
534 :
535 6 : void GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer(
536 : OGRLayer &oLayer)
537 : {
538 6 : m_passthrough_layers.push_back(
539 12 : std::make_unique<GDALVectorPipelinePassthroughLayer>(oLayer));
540 6 : m_layers.push_back(m_passthrough_layers.back().get());
541 6 : }
542 :
543 : /************************************************************************/
544 : /* GDALVectorNonStreamingAlgorithmDataset::GetLayerCount() */
545 : /************************************************************************/
546 :
547 74 : int GDALVectorNonStreamingAlgorithmDataset::GetLayerCount() const
548 : {
549 74 : return static_cast<int>(m_layers.size());
550 : }
551 :
552 : /************************************************************************/
553 : /* GDALVectorNonStreamingAlgorithmDataset::GetLayer() */
554 : /************************************************************************/
555 :
556 73 : OGRLayer *GDALVectorNonStreamingAlgorithmDataset::GetLayer(int idx) const
557 : {
558 73 : if (idx < 0 || idx >= static_cast<int>(m_layers.size()))
559 : {
560 4 : return nullptr;
561 : }
562 69 : return m_layers[idx];
563 : }
564 :
565 : /************************************************************************/
566 : /* GDALVectorNonStreamingAlgorithmDataset::TestCapability() */
567 : /************************************************************************/
568 :
569 18 : int GDALVectorNonStreamingAlgorithmDataset::TestCapability(
570 : const char *pszCap) const
571 : {
572 18 : if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer))
573 : {
574 4 : return false;
575 : }
576 :
577 14 : return m_ds->TestCapability(pszCap);
578 : }
579 :
580 : //! @endcond
|