Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: "write" step of "vector pipeline"
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_write.h"
14 : #include "cpl_string.h"
15 : #include "gdal_utils.h"
16 : #include "gdal_priv.h"
17 :
18 : #ifndef _
19 : #define _(x) (x)
20 : #endif
21 :
22 : //! @cond Doxygen_Suppress
23 :
24 : /************************************************************************/
25 : /* GDALVectorWriteAlgorithm::GDALVectorWriteAlgorithm() */
26 : /************************************************************************/
27 :
28 753 : GDALVectorWriteAlgorithm::GDALVectorWriteAlgorithm()
29 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
30 0 : ConstructorOptions()
31 753 : .SetStandaloneStep(false)
32 1506 : .SetNoCreateEmptyLayersArgument(true))
33 : {
34 753 : AddVectorOutputArgs(/* hiddenForCLI = */ false,
35 : /* shortNameOutputLayerAllowed=*/true);
36 :
37 : AddArg(GDAL_ARG_NAME_QUIET, 'q',
38 1506 : _("Quiet mode (suppress warning messages)"), &m_quiet)
39 753 : .SetCategory(GAAC_COMMON);
40 753 : }
41 :
42 : /************************************************************************/
43 : /* GDALVectorWriteAlgorithm::RunStep() */
44 : /************************************************************************/
45 :
46 : namespace
47 : {
48 46 : class OGRReadBufferedLayer
49 : : public OGRLayer,
50 : public OGRGetNextFeatureThroughRaw<OGRReadBufferedLayer>
51 : {
52 : public:
53 23 : explicit OGRReadBufferedLayer(OGRLayer &srcLayer)
54 23 : : m_srcLayer(srcLayer), m_poFeature(nullptr)
55 : {
56 23 : m_poFeature.reset(m_srcLayer.GetNextFeature());
57 23 : }
58 :
59 : ~OGRReadBufferedLayer() override;
60 :
61 2 : const char *GetDescription() const override
62 : {
63 2 : return m_srcLayer.GetDescription();
64 : }
65 :
66 27 : GIntBig GetFeatureCount(int bForce) override
67 : {
68 27 : if (m_poAttrQuery == nullptr && m_poFilterGeom == nullptr)
69 : {
70 17 : return m_srcLayer.GetFeatureCount(bForce);
71 : }
72 :
73 10 : return OGRLayer::GetFeatureCount(bForce);
74 : }
75 :
76 327 : const OGRFeatureDefn *GetLayerDefn() const override
77 : {
78 327 : return m_srcLayer.GetLayerDefn();
79 : }
80 :
81 205 : OGRFeature *GetNextRawFeature()
82 : {
83 205 : auto ret = m_poFeature.release();
84 205 : m_poFeature.reset(m_srcLayer.GetNextFeature());
85 205 : return ret;
86 : }
87 :
88 171 : DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGRReadBufferedLayer)
89 :
90 4 : OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
91 : bool bForce) override
92 : {
93 4 : return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
94 : }
95 :
96 0 : OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent,
97 : bool bForce) override
98 : {
99 0 : return m_srcLayer.GetExtent3D(iGeomField, psExtent, bForce);
100 : }
101 :
102 23 : const OGRFeature *PeekNextFeature() const
103 : {
104 23 : return m_poFeature.get();
105 : }
106 :
107 70 : int TestCapability(const char *pszCap) const override
108 : {
109 70 : if (EQUAL(pszCap, OLCFastFeatureCount) ||
110 70 : EQUAL(pszCap, OLCFastGetExtent) ||
111 67 : EQUAL(pszCap, OLCFastGetExtent3D) ||
112 67 : EQUAL(pszCap, OLCZGeometries) ||
113 61 : EQUAL(pszCap, OLCMeasuredGeometries) ||
114 53 : EQUAL(pszCap, OLCCurveGeometries))
115 : {
116 25 : return m_srcLayer.TestCapability(pszCap);
117 : }
118 :
119 45 : return false;
120 : }
121 :
122 168 : void ResetReading() override
123 : {
124 168 : m_srcLayer.ResetReading();
125 168 : m_poFeature.reset(m_srcLayer.GetNextFeature());
126 168 : }
127 :
128 : private:
129 : OGRLayer &m_srcLayer;
130 : std::unique_ptr<OGRFeature> m_poFeature;
131 : };
132 :
133 : OGRReadBufferedLayer::~OGRReadBufferedLayer() = default;
134 :
135 : class GDALReadBufferedDataset final : public GDALDataset
136 : {
137 : public:
138 10 : explicit GDALReadBufferedDataset(GDALDataset &srcDS) : m_srcDS(srcDS)
139 : {
140 10 : m_srcDS.Reference();
141 :
142 33 : for (int i = 0; i < srcDS.GetLayerCount(); i++)
143 : {
144 : auto poLayer =
145 46 : std::make_unique<OGRReadBufferedLayer>(*srcDS.GetLayer(i));
146 23 : if (poLayer->PeekNextFeature())
147 : {
148 14 : m_layers.push_back(std::move(poLayer));
149 : }
150 : }
151 10 : }
152 :
153 : ~GDALReadBufferedDataset() override;
154 :
155 111 : int GetLayerCount() const override
156 : {
157 111 : return static_cast<int>(m_layers.size());
158 : }
159 :
160 54 : const OGRLayer *GetLayer(int nLayer) const override
161 : {
162 54 : if (nLayer < 0 || nLayer >= static_cast<int>(m_layers.size()))
163 : {
164 4 : return nullptr;
165 : }
166 50 : return m_layers[nLayer].get();
167 : }
168 :
169 : private:
170 : GDALDataset &m_srcDS;
171 : std::vector<std::unique_ptr<OGRReadBufferedLayer>> m_layers{};
172 : };
173 :
174 20 : GDALReadBufferedDataset::~GDALReadBufferedDataset()
175 : {
176 10 : m_srcDS.Release();
177 20 : }
178 :
179 : } // namespace
180 :
181 412 : bool GDALVectorWriteAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
182 : {
183 412 : auto pfnProgress = ctxt.m_pfnProgress;
184 412 : auto pProgressData = ctxt.m_pProgressData;
185 412 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
186 412 : CPLAssert(poSrcDS);
187 :
188 412 : std::unique_ptr<GDALDataset> poReadBufferedDataset;
189 :
190 412 : if (m_noCreateEmptyLayers)
191 : {
192 10 : if (poSrcDS->TestCapability(ODsCRandomLayerRead))
193 : {
194 1 : CPLError(
195 : CE_Warning, CPLE_AppDefined,
196 : "Source dataset supports random-layer reading, but this "
197 : "is not compatible with --no-create-empty-layers. Attempting "
198 : "to read features by layer, but this may fail if the "
199 : "source dataset is large.");
200 : }
201 :
202 : poReadBufferedDataset =
203 10 : std::make_unique<GDALReadBufferedDataset>(*poSrcDS);
204 :
205 10 : if (m_format == "stream")
206 : {
207 8 : m_outputDataset.Set(std::move(poReadBufferedDataset));
208 8 : return true;
209 : }
210 :
211 2 : poSrcDS = poReadBufferedDataset.get();
212 : }
213 :
214 404 : if (m_format == "stream")
215 : {
216 176 : m_outputDataset.Set(poSrcDS);
217 176 : return true;
218 : }
219 :
220 456 : CPLStringList aosOptions;
221 228 : aosOptions.AddString("--invoked-from-gdal-algorithm");
222 228 : if (!m_overwrite)
223 : {
224 218 : aosOptions.AddString("--no-overwrite");
225 : }
226 228 : if (m_overwriteLayer)
227 : {
228 5 : aosOptions.AddString("-overwrite");
229 : }
230 228 : if (m_appendLayer)
231 : {
232 5 : aosOptions.AddString("-append");
233 : }
234 228 : if (m_upsert)
235 : {
236 2 : aosOptions.AddString("-upsert");
237 : }
238 228 : if (!m_format.empty())
239 : {
240 138 : aosOptions.AddString("-of");
241 138 : aosOptions.AddString(m_format.c_str());
242 : }
243 231 : for (const auto &co : m_creationOptions)
244 : {
245 3 : aosOptions.AddString("-dsco");
246 3 : aosOptions.AddString(co.c_str());
247 : }
248 232 : for (const auto &co : m_layerCreationOptions)
249 : {
250 4 : aosOptions.AddString("-lco");
251 4 : aosOptions.AddString(co.c_str());
252 : }
253 228 : if (!m_outputLayerName.empty())
254 : {
255 6 : aosOptions.AddString("-nln");
256 6 : aosOptions.AddString(m_outputLayerName.c_str());
257 : }
258 228 : if (pfnProgress && pfnProgress != GDALDummyProgress)
259 : {
260 9 : aosOptions.AddString("-progress");
261 : }
262 228 : if (m_skipErrors)
263 : {
264 2 : aosOptions.AddString("-skipfailures");
265 : }
266 228 : if (m_quiet)
267 : {
268 3 : aosOptions.AddString("-q");
269 : }
270 :
271 228 : GDALDataset *poRetDS = nullptr;
272 : GDALDatasetH hOutDS =
273 228 : GDALDataset::ToHandle(m_outputDataset.GetDatasetRef());
274 : GDALVectorTranslateOptions *psOptions =
275 228 : GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr);
276 228 : if (psOptions)
277 : {
278 228 : GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress,
279 : pProgressData);
280 :
281 228 : GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
282 228 : poRetDS = GDALDataset::FromHandle(
283 228 : GDALVectorTranslate(m_outputDataset.GetName().c_str(), hOutDS, 1,
284 : &hSrcDS, psOptions, nullptr));
285 228 : GDALVectorTranslateOptionsFree(psOptions);
286 : }
287 :
288 228 : if (!poRetDS)
289 : {
290 14 : return false;
291 : }
292 :
293 214 : if (!hOutDS)
294 : {
295 202 : m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
296 : }
297 :
298 214 : return true;
299 : }
300 :
301 : //! @endcond
|