Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Simple client for translating between formats.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2008-2015, Even Rouault <even dot rouault at spatialys.com>
10 : * Copyright (c) 2015, Faza Mahamood
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "gdal_utils.h"
33 : #include "gdal_utils_priv.h"
34 : #include "gdalargumentparser.h"
35 :
36 : #include <cassert>
37 : #include <climits>
38 : #include <cstdio>
39 : #include <cstdlib>
40 : #include <cstring>
41 :
42 : #include <algorithm>
43 : #include <limits>
44 : #include <map>
45 : #include <memory>
46 : #include <set>
47 : #include <unordered_set>
48 : #include <string>
49 : #include <utility>
50 : #include <vector>
51 :
52 : #include "commonutils.h"
53 : #include "cpl_conv.h"
54 : #include "cpl_error.h"
55 : #include "cpl_progress.h"
56 : #include "cpl_string.h"
57 : #include "cpl_time.h"
58 : #include "cpl_vsi.h"
59 : #include "gdal.h"
60 : #include "gdal_alg.h"
61 : #include "gdal_alg_priv.h"
62 : #include "gdal_priv.h"
63 : #include "ogr_api.h"
64 : #include "ogr_core.h"
65 : #include "ogr_feature.h"
66 : #include "ogr_featurestyle.h"
67 : #include "ogr_geometry.h"
68 : #include "ogr_p.h"
69 : #include "ogr_recordbatch.h"
70 : #include "ogr_spatialref.h"
71 : #include "ogrlayerdecorator.h"
72 : #include "ogrsf_frmts.h"
73 :
74 : typedef enum
75 : {
76 : GEOMOP_NONE,
77 : GEOMOP_SEGMENTIZE,
78 : GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY,
79 : } GeomOperation;
80 :
81 : typedef enum
82 : {
83 : GTC_DEFAULT,
84 : GTC_PROMOTE_TO_MULTI,
85 : GTC_CONVERT_TO_LINEAR,
86 : GTC_CONVERT_TO_CURVE,
87 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR,
88 : } GeomTypeConversion;
89 :
90 : #define GEOMTYPE_UNCHANGED -2
91 :
92 : #define COORD_DIM_UNCHANGED -1
93 : #define COORD_DIM_LAYER_DIM -2
94 : #define COORD_DIM_XYM -3
95 :
96 : #define TZ_OFFSET_INVALID INT_MIN
97 :
98 : /************************************************************************/
99 : /* CopyableGCPs */
100 : /************************************************************************/
101 :
102 : namespace gdal::ogr2ogr_lib
103 : {
104 : struct CopyableGCPs
105 : {
106 : /*! size of the list pasGCPs */
107 : int nGCPCount = 0;
108 :
109 : /*! list of ground control points to be added */
110 : GDAL_GCP *pasGCPs = nullptr;
111 :
112 702 : CopyableGCPs() = default;
113 :
114 660 : CopyableGCPs(const CopyableGCPs &other)
115 660 : {
116 660 : nGCPCount = other.nGCPCount;
117 660 : if (other.nGCPCount)
118 5 : pasGCPs = GDALDuplicateGCPs(other.nGCPCount, other.pasGCPs);
119 : else
120 655 : pasGCPs = nullptr;
121 660 : }
122 :
123 1357 : ~CopyableGCPs()
124 1357 : {
125 1357 : if (pasGCPs)
126 : {
127 10 : GDALDeinitGCPs(nGCPCount, pasGCPs);
128 10 : CPLFree(pasGCPs);
129 : }
130 1357 : }
131 : };
132 : } // namespace gdal::ogr2ogr_lib
133 :
134 : using namespace gdal::ogr2ogr_lib;
135 :
136 : /************************************************************************/
137 : /* GDALVectorTranslateOptions */
138 : /************************************************************************/
139 :
140 : /** Options for use with GDALVectorTranslate(). GDALVectorTranslateOptions* must
141 : * be allocated and freed with GDALVectorTranslateOptionsNew() and
142 : * GDALVectorTranslateOptionsFree() respectively.
143 : */
144 : struct GDALVectorTranslateOptions
145 : {
146 : // All arguments passed to GDALVectorTranslate() except the positional
147 : // ones (that is dataset names and layer names)
148 : CPLStringList aosArguments{};
149 :
150 : /*! continue after a failure, skipping the failed feature */
151 : bool bSkipFailures = false;
152 :
153 : /*! use layer level transaction. If set to FALSE, then it is interpreted as
154 : * dataset level transaction. */
155 : int nLayerTransaction = -1;
156 :
157 : /*! force the use of particular transaction type based on
158 : * GDALVectorTranslate::nLayerTransaction */
159 : bool bForceTransaction = false;
160 :
161 : /*! group nGroupTransactions features per transaction.
162 : Increase the value for better performance when writing into DBMS drivers
163 : that have transaction support. nGroupTransactions can be set to -1 to
164 : load the data into a single transaction */
165 : int nGroupTransactions = 100 * 1000;
166 :
167 : /*! If provided, only the feature with this feature id will be reported.
168 : Operates exclusive of the spatial or attribute queries. Note: if you want
169 : to select several features based on their feature id, you can also use
170 : the fact the 'fid' is a special field recognized by OGR SQL. So
171 : GDALVectorTranslateOptions::pszWHERE = "fid in (1,3,5)" would select
172 : features 1, 3 and 5. */
173 : GIntBig nFIDToFetch = OGRNullFID;
174 :
175 : /*! allow or suppress progress monitor and other non-error output */
176 : bool bQuiet = false;
177 :
178 : /*! output file format name */
179 : std::string osFormat{};
180 :
181 : /*! list of layers of the source dataset which needs to be selected */
182 : CPLStringList aosLayers{};
183 :
184 : /*! dataset creation option (format specific) */
185 : CPLStringList aosDSCO{};
186 :
187 : /*! layer creation option (format specific) */
188 : CPLStringList aosLCO{};
189 :
190 : /*! access modes */
191 : GDALVectorTranslateAccessMode eAccessMode = ACCESS_CREATION;
192 :
193 : /*! whether to use UpsertFeature() instead of CreateFeature() */
194 : bool bUpsert = false;
195 :
196 : /*! It has the effect of adding, to existing target layers, the new fields
197 : found in source layers. This option is useful when merging files that
198 : have non-strictly identical structures. This might not work for output
199 : formats that don't support adding fields to existing non-empty layers. */
200 : bool bAddMissingFields = false;
201 :
202 : /*! It must be set to true to trigger reprojection, otherwise only SRS
203 : * assignment is done. */
204 : bool bTransform = false;
205 :
206 : /*! output SRS. GDALVectorTranslateOptions::bTransform must be set to true
207 : to trigger reprojection, otherwise only SRS assignment is done. */
208 : std::string osOutputSRSDef{};
209 :
210 : /*! Coordinate epoch of source SRS */
211 : double dfSourceCoordinateEpoch = 0;
212 :
213 : /*! Coordinate epoch of output SRS */
214 : double dfOutputCoordinateEpoch = 0;
215 :
216 : /*! override source SRS */
217 : std::string osSourceSRSDef{};
218 :
219 : /*! PROJ pipeline */
220 : std::string osCTPipeline{};
221 :
222 : bool bNullifyOutputSRS = false;
223 :
224 : /*! If set to false, then field name matching between source and existing
225 : target layer is done in a more relaxed way if the target driver has an
226 : implementation for it. */
227 : bool bExactFieldNameMatch = true;
228 :
229 : /*! an alternate name to the new layer */
230 : std::string osNewLayerName{};
231 :
232 : /*! attribute query (like SQL WHERE) */
233 : std::string osWHERE{};
234 :
235 : /*! name of the geometry field on which the spatial filter operates on. */
236 : std::string osGeomField{};
237 :
238 : /*! whether osGeomField is set (useful for empty strings) */
239 : bool bGeomFieldSet = false;
240 :
241 : /*! whether -select has been specified. This is of course true when
242 : * !aosSelFields.empty(), but this can also be set when an empty string
243 : * has been to disable fields. */
244 : bool bSelFieldsSet = false;
245 :
246 : /*! list of fields from input layer to copy to the new layer.
247 : * Geometry fields can also be specified in the list. */
248 : CPLStringList aosSelFields{};
249 :
250 : /*! SQL statement to execute. The resulting table/layer will be saved to the
251 : * output. */
252 : std::string osSQLStatement{};
253 :
254 : /*! SQL dialect. In some cases can be used to use (unoptimized) OGR SQL
255 : instead of the native SQL of an RDBMS by using "OGRSQL". The "SQLITE"
256 : dialect can also be used with any datasource. */
257 : std::string osDialect{};
258 :
259 : /*! the geometry type for the created layer */
260 : int eGType = GEOMTYPE_UNCHANGED;
261 :
262 : GeomTypeConversion eGeomTypeConversion = GTC_DEFAULT;
263 :
264 : /*! Geometric operation to perform */
265 : GeomOperation eGeomOp = GEOMOP_NONE;
266 :
267 : /*! the parameter to geometric operation */
268 : double dfGeomOpParam = 0;
269 :
270 : /*! Whether to run MakeValid */
271 : bool bMakeValid = false;
272 :
273 : /*! list of field types to convert to a field of type string in the
274 : destination layer. Valid types are: Integer, Integer64, Real, String,
275 : Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList,
276 : StringList. Special value "All" can be used to convert all fields to
277 : strings. This is an alternate way to using the CAST operator of OGR SQL,
278 : that may avoid typing a long SQL query. Note that this does not influence
279 : the field types used by the source driver, and is only an afterwards
280 : conversion. */
281 : CPLStringList aosFieldTypesToString{};
282 :
283 : /*! list of field types and the field type after conversion in the
284 : destination layer.
285 : ("srctype1=dsttype1","srctype2=dsttype2",...).
286 : Valid types are : Integer, Integer64, Real, String, Date, Time,
287 : DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Types
288 : can also include subtype between parenthesis, such as Integer(Boolean),
289 : Real(Float32), ... Special value "All" can be used to convert all fields
290 : to another type. This is an alternate way to using the CAST operator of
291 : OGR SQL, that may avoid typing a long SQL query. This is a generalization
292 : of GDALVectorTranslateOptions::papszFieldTypeToString. Note that this
293 : does not influence the field types used by the source driver, and is only
294 : an afterwards conversion. */
295 : CPLStringList aosMapFieldType{};
296 :
297 : /*! set field width and precision to 0 */
298 : bool bUnsetFieldWidth = false;
299 :
300 : /*! display progress on terminal. Only works if input layers have the "fast
301 : feature count" capability */
302 : bool bDisplayProgress = false;
303 :
304 : /*! split geometries crossing the dateline meridian */
305 : bool bWrapDateline = false;
306 :
307 : /*! offset from dateline in degrees (default long. = +/- 10deg, geometries
308 : within 170deg to -170deg will be split) */
309 : double dfDateLineOffset = 10.0;
310 :
311 : /*! clip geometries when it is set to true */
312 : bool bClipSrc = false;
313 :
314 : std::shared_ptr<OGRGeometry> poClipSrc{};
315 :
316 : /*! clip datasource */
317 : std::string osClipSrcDS{};
318 :
319 : /*! select desired geometries using an SQL query */
320 : std::string osClipSrcSQL{};
321 :
322 : /*! selected named layer from the source clip datasource */
323 : std::string osClipSrcLayer{};
324 :
325 : /*! restrict desired geometries based on attribute query */
326 : std::string osClipSrcWhere{};
327 :
328 : std::shared_ptr<OGRGeometry> poClipDst{};
329 :
330 : /*! destination clip datasource */
331 : std::string osClipDstDS{};
332 :
333 : /*! select desired geometries using an SQL query */
334 : std::string osClipDstSQL{};
335 :
336 : /*! selected named layer from the destination clip datasource */
337 : std::string osClipDstLayer{};
338 :
339 : /*! restrict desired geometries based on attribute query */
340 : std::string osClipDstWhere{};
341 :
342 : /*! split fields of type StringList, RealList or IntegerList into as many
343 : fields of type String, Real or Integer as necessary. */
344 : bool bSplitListFields = false;
345 :
346 : /*! limit the number of subfields created for each split field. */
347 : int nMaxSplitListSubFields = -1;
348 :
349 : /*! produce one feature for each geometry in any kind of geometry collection
350 : in the source file */
351 : bool bExplodeCollections = false;
352 :
353 : /*! uses the specified field to fill the Z coordinates of geometries */
354 : std::string osZField{};
355 :
356 : /*! the list of field indexes to be copied from the source to the
357 : destination. The (n)th value specified in the list is the index of the
358 : field in the target layer definition in which the n(th) field of the
359 : source layer must be copied. Index count starts at zero. There must be
360 : exactly as many values in the list as the count of the fields in the
361 : source layer. We can use the "identity" option to specify that the fields
362 : should be transferred by using the same order. This option should be used
363 : along with the GDALVectorTranslateOptions::eAccessMode = ACCESS_APPEND
364 : option. */
365 : CPLStringList aosFieldMap{};
366 :
367 : /*! force the coordinate dimension to nCoordDim (valid values are 2 or 3).
368 : This affects both the layer geometry type, and feature geometries. */
369 : int nCoordDim = COORD_DIM_UNCHANGED;
370 :
371 : /*! destination dataset open option (format specific), only valid in update
372 : * mode */
373 : CPLStringList aosDestOpenOptions{};
374 :
375 : /*! If set to true, does not propagate not-nullable constraints to target
376 : layer if they exist in source layer */
377 : bool bForceNullable = false;
378 :
379 : /*! If set to true, for each field with a coded field domains, create a
380 : field that contains the description of the coded value. */
381 : bool bResolveDomains = false;
382 :
383 : /*! If set to true, empty string values will be treated as null */
384 : bool bEmptyStrAsNull = false;
385 :
386 : /*! If set to true, does not propagate default field values to target layer
387 : if they exist in source layer */
388 : bool bUnsetDefault = false;
389 :
390 : /*! to prevent the new default behavior that consists in, if the output
391 : driver has a FID layer creation option and we are not in append mode, to
392 : preserve the name of the source FID column and source feature IDs */
393 : bool bUnsetFid = false;
394 :
395 : /*! use the FID of the source features instead of letting the output driver
396 : to automatically assign a new one. If not in append mode, this behavior
397 : becomes the default if the output driver has a FID layer creation option.
398 : In which case the name of the source FID column will be used and source
399 : feature IDs will be attempted to be preserved. This behavior can be
400 : disabled by option GDALVectorTranslateOptions::bUnsetFid */
401 : bool bPreserveFID = false;
402 :
403 : /*! set it to false to disable copying of metadata from source dataset and
404 : layers into target dataset and layers, when supported by output driver.
405 : */
406 : bool bCopyMD = true;
407 :
408 : /*! list of metadata key and value to set on the output dataset, when
409 : supported by output driver.
410 : ("META-TAG1=VALUE1","META-TAG2=VALUE2") */
411 : CPLStringList aosMetadataOptions{};
412 :
413 : /*! override spatial filter SRS */
414 : std::string osSpatSRSDef{};
415 :
416 : /*! list of ground control points to be added */
417 : CopyableGCPs oGCPs{};
418 :
419 : /*! order of polynomial used for warping (1 to 3). The default is to select
420 : a polynomial order based on the number of GCPs */
421 : int nTransformOrder = 0;
422 :
423 : /*! spatial query extents, in the SRS of the source layer(s) (or the one
424 : specified with GDALVectorTranslateOptions::pszSpatSRSDef). Only features
425 : whose geometry intersects the extents will be selected. The geometries
426 : will not be clipped unless GDALVectorTranslateOptions::bClipSrc is true.
427 : */
428 : std::shared_ptr<OGRGeometry> poSpatialFilter;
429 :
430 : /*! the progress function to use */
431 : GDALProgressFunc pfnProgress = nullptr;
432 :
433 : /*! pointer to the progress data variable */
434 : void *pProgressData = nullptr;
435 :
436 : /*! Whether layer and feature native data must be transferred. */
437 : bool bNativeData = true;
438 :
439 : /*! Maximum number of features, or -1 if no limit. */
440 : GIntBig nLimit = -1;
441 :
442 : /*! Wished offset w.r.t UTC of dateTime */
443 : int nTZOffsetInSec = TZ_OFFSET_INVALID;
444 :
445 : /*! Geometry X,Y coordinate resolution */
446 : double dfXYRes = OGRGeomCoordinatePrecision::UNKNOWN;
447 :
448 : /*! Unit of dXYRes. empty string, "m", "mm" or "deg" */
449 : std::string osXYResUnit{};
450 :
451 : /*! Geometry Z coordinate resolution */
452 : double dfZRes = OGRGeomCoordinatePrecision::UNKNOWN;
453 :
454 : /*! Unit of dfZRes. empty string, "m" or "mm" */
455 : std::string osZResUnit{};
456 :
457 : /*! Geometry M coordinate resolution */
458 : double dfMRes = OGRGeomCoordinatePrecision::UNKNOWN;
459 :
460 : /*! Whether to unset geometry coordinate precision */
461 : bool bUnsetCoordPrecision = false;
462 : };
463 :
464 : struct TargetLayerInfo
465 : {
466 : OGRLayer *m_poSrcLayer = nullptr;
467 : GIntBig m_nFeaturesRead = 0;
468 : bool m_bPerFeatureCT = 0;
469 : OGRLayer *m_poDstLayer = nullptr;
470 : bool m_bUseWriteArrowBatch = false;
471 :
472 : struct ReprojectionInfo
473 : {
474 : std::unique_ptr<OGRCoordinateTransformation> m_poCT{};
475 : CPLStringList m_aosTransformOptions{};
476 : bool m_bCanInvalidateValidity = true;
477 : };
478 :
479 : std::vector<ReprojectionInfo> m_aoReprojectionInfo{};
480 :
481 : std::vector<int> m_anMap{};
482 :
483 : struct ResolvedInfo
484 : {
485 : int nSrcField;
486 : const OGRFieldDomain *poDomain;
487 : };
488 :
489 : std::map<int, ResolvedInfo> m_oMapResolved{};
490 : std::map<const OGRFieldDomain *, std::map<std::string, std::string>>
491 : m_oMapDomainToKV{};
492 : int m_iSrcZField = -1;
493 : int m_iSrcFIDField = -1;
494 : int m_iRequestedSrcGeomField = -1;
495 : bool m_bPreserveFID = false;
496 : const char *m_pszCTPipeline = nullptr;
497 : bool m_bCanAvoidSetFrom = false;
498 : const char *m_pszSpatSRSDef = nullptr;
499 : OGRGeometryH m_hSpatialFilter = nullptr;
500 : const char *m_pszGeomField = nullptr;
501 : std::vector<int> m_anDateTimeFieldIdx{};
502 : bool m_bSupportCurves = false;
503 : };
504 :
505 : struct AssociatedLayers
506 : {
507 : OGRLayer *poSrcLayer = nullptr;
508 : std::unique_ptr<TargetLayerInfo> psInfo{};
509 : };
510 :
511 : class SetupTargetLayer
512 : {
513 : bool CanUseWriteArrowBatch(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,
514 : bool bJustCreatedLayer,
515 : const GDALVectorTranslateOptions *psOptions,
516 : bool &bError);
517 :
518 : public:
519 : GDALDataset *m_poSrcDS;
520 : GDALDataset *m_poDstDS;
521 : char **m_papszLCO;
522 : OGRSpatialReference *m_poOutputSRS;
523 : bool m_bTransform = false;
524 : bool m_bNullifyOutputSRS;
525 : bool m_bSelFieldsSet = false;
526 : char **m_papszSelFields;
527 : bool m_bAppend;
528 : bool m_bAddMissingFields;
529 : int m_eGType;
530 : GeomTypeConversion m_eGeomTypeConversion;
531 : int m_nCoordDim;
532 : bool m_bOverwrite;
533 : char **m_papszFieldTypesToString;
534 : char **m_papszMapFieldType;
535 : bool m_bUnsetFieldWidth;
536 : bool m_bExplodeCollections;
537 : const char *m_pszZField;
538 : char **m_papszFieldMap;
539 : const char *m_pszWHERE;
540 : bool m_bExactFieldNameMatch;
541 : bool m_bQuiet;
542 : bool m_bForceNullable;
543 : bool m_bResolveDomains;
544 : bool m_bUnsetDefault;
545 : bool m_bUnsetFid;
546 : bool m_bPreserveFID;
547 : bool m_bCopyMD;
548 : bool m_bNativeData;
549 : bool m_bNewDataSource;
550 : const char *m_pszCTPipeline;
551 :
552 : std::unique_ptr<TargetLayerInfo>
553 : Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
554 : GDALVectorTranslateOptions *psOptions, GIntBig &nTotalEventsDone);
555 : };
556 :
557 : class LayerTranslator
558 : {
559 : static bool TranslateArrow(const TargetLayerInfo *psInfo,
560 : GIntBig nCountLayerFeatures,
561 : GIntBig *pnReadFeatureCount,
562 : GDALProgressFunc pfnProgress, void *pProgressArg,
563 : const GDALVectorTranslateOptions *psOptions);
564 :
565 : public:
566 : GDALDataset *m_poSrcDS = nullptr;
567 : GDALDataset *m_poODS = nullptr;
568 : bool m_bTransform = false;
569 : bool m_bWrapDateline = false;
570 : CPLString m_osDateLineOffset{};
571 : OGRSpatialReference *m_poOutputSRS = nullptr;
572 : bool m_bNullifyOutputSRS = false;
573 : OGRSpatialReference *m_poUserSourceSRS = nullptr;
574 : OGRCoordinateTransformation *m_poGCPCoordTrans = nullptr;
575 : int m_eGType = -1;
576 : GeomTypeConversion m_eGeomTypeConversion = GTC_DEFAULT;
577 : bool m_bMakeValid = false;
578 : int m_nCoordDim = 0;
579 : GeomOperation m_eGeomOp = GEOMOP_NONE;
580 : double m_dfGeomOpParam = 0;
581 : OGRGeometry *m_poClipSrcOri = nullptr;
582 : bool m_bWarnedClipSrcSRS = false;
583 : std::unique_ptr<OGRGeometry> m_poClipSrcReprojectedToSrcSRS;
584 : const OGRSpatialReference *m_poClipSrcReprojectedToSrcSRS_SRS = nullptr;
585 : OGRGeometry *m_poClipDstOri = nullptr;
586 : bool m_bWarnedClipDstSRS = false;
587 : std::unique_ptr<OGRGeometry> m_poClipDstReprojectedToDstSRS;
588 : const OGRSpatialReference *m_poClipDstReprojectedToDstSRS_SRS = nullptr;
589 : bool m_bExplodeCollections = false;
590 : bool m_bNativeData = false;
591 : GIntBig m_nLimit = -1;
592 : OGRGeometryFactory::TransformWithOptionsCache m_transformWithOptionsCache;
593 :
594 : bool Translate(OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,
595 : GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
596 : GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress,
597 : void *pProgressArg,
598 : const GDALVectorTranslateOptions *psOptions);
599 :
600 : private:
601 : const OGRGeometry *GetDstClipGeom(const OGRSpatialReference *poGeomSRS);
602 : const OGRGeometry *GetSrcClipGeom(const OGRSpatialReference *poGeomSRS);
603 : };
604 :
605 : static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
606 : const char *pszNewLayerName,
607 : bool bOverwrite,
608 : bool *pbErrorOccurred,
609 : bool *pbOverwriteActuallyDone,
610 : bool *pbAddOverwriteLCO);
611 :
612 : /************************************************************************/
613 : /* LoadGeometry() */
614 : /************************************************************************/
615 :
616 14 : static std::unique_ptr<OGRGeometry> LoadGeometry(const std::string &osDS,
617 : const std::string &osSQL,
618 : const std::string &osLyr,
619 : const std::string &osWhere)
620 : {
621 : auto poDS = std::unique_ptr<GDALDataset>(
622 28 : GDALDataset::Open(osDS.c_str(), GDAL_OF_VECTOR));
623 14 : if (poDS == nullptr)
624 2 : return nullptr;
625 :
626 12 : OGRLayer *poLyr = nullptr;
627 12 : if (!osSQL.empty())
628 3 : poLyr = poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr);
629 9 : else if (!osLyr.empty())
630 2 : poLyr = poDS->GetLayerByName(osLyr.c_str());
631 : else
632 7 : poLyr = poDS->GetLayer(0);
633 :
634 12 : if (poLyr == nullptr)
635 : {
636 0 : CPLError(CE_Failure, CPLE_AppDefined,
637 : "Failed to identify source layer from datasource.");
638 0 : return nullptr;
639 : }
640 :
641 12 : if (!osWhere.empty())
642 5 : poLyr->SetAttributeFilter(osWhere.c_str());
643 :
644 24 : OGRGeometryCollection oGC;
645 :
646 12 : const auto poSRSSrc = poLyr->GetSpatialRef();
647 12 : if (poSRSSrc)
648 : {
649 2 : auto poSRSClone = poSRSSrc->Clone();
650 2 : oGC.assignSpatialReference(poSRSClone);
651 2 : poSRSClone->Release();
652 : }
653 :
654 24 : for (auto &poFeat : poLyr)
655 : {
656 24 : auto poSrcGeom = std::unique_ptr<OGRGeometry>(poFeat->StealGeometry());
657 12 : if (poSrcGeom)
658 : {
659 : // Only take into account areal geometries.
660 12 : if (poSrcGeom->getDimension() == 2)
661 : {
662 12 : if (!poSrcGeom->IsValid())
663 : {
664 1 : CPLError(CE_Warning, CPLE_AppDefined,
665 : "Geometry of feature " CPL_FRMT_GIB " of %s "
666 : "is invalid. Trying to make it valid",
667 : poFeat->GetFID(), osDS.c_str());
668 : auto poValid =
669 2 : std::unique_ptr<OGRGeometry>(poSrcGeom->MakeValid());
670 1 : if (poValid)
671 : {
672 1 : oGC.addGeometryDirectly(poValid.release());
673 : }
674 : }
675 : else
676 : {
677 11 : oGC.addGeometryDirectly(poSrcGeom.release());
678 : }
679 : }
680 : }
681 : }
682 :
683 12 : if (!osSQL.empty())
684 3 : poDS->ReleaseResultSet(poLyr);
685 :
686 12 : if (oGC.IsEmpty())
687 0 : return nullptr;
688 :
689 12 : return std::unique_ptr<OGRGeometry>(oGC.UnaryUnion());
690 : }
691 :
692 : /************************************************************************/
693 : /* OGRSplitListFieldLayer */
694 : /************************************************************************/
695 :
696 : typedef struct
697 : {
698 : int iSrcIndex;
699 : OGRFieldType eType;
700 : int nMaxOccurrences;
701 : int nWidth;
702 : } ListFieldDesc;
703 :
704 : class OGRSplitListFieldLayer : public OGRLayer
705 : {
706 : OGRLayer *poSrcLayer;
707 : OGRFeatureDefn *poFeatureDefn;
708 : ListFieldDesc *pasListFields;
709 : int nListFieldCount;
710 : int nMaxSplitListSubFields;
711 :
712 : OGRFeature *TranslateFeature(OGRFeature *poSrcFeature);
713 :
714 : public:
715 : OGRSplitListFieldLayer(OGRLayer *poSrcLayer, int nMaxSplitListSubFields);
716 : virtual ~OGRSplitListFieldLayer();
717 :
718 : bool BuildLayerDefn(GDALProgressFunc pfnProgress, void *pProgressArg);
719 :
720 : virtual OGRFeature *GetNextFeature() override;
721 : virtual OGRFeature *GetFeature(GIntBig nFID) override;
722 : virtual OGRFeatureDefn *GetLayerDefn() override;
723 :
724 1 : virtual void ResetReading() override
725 : {
726 1 : poSrcLayer->ResetReading();
727 1 : }
728 :
729 1 : virtual int TestCapability(const char *) override
730 : {
731 1 : return FALSE;
732 : }
733 :
734 0 : virtual GIntBig GetFeatureCount(int bForce = TRUE) override
735 : {
736 0 : return poSrcLayer->GetFeatureCount(bForce);
737 : }
738 :
739 1 : virtual OGRSpatialReference *GetSpatialRef() override
740 : {
741 1 : return poSrcLayer->GetSpatialRef();
742 : }
743 :
744 0 : virtual OGRGeometry *GetSpatialFilter() override
745 : {
746 0 : return poSrcLayer->GetSpatialFilter();
747 : }
748 :
749 1 : virtual OGRStyleTable *GetStyleTable() override
750 : {
751 1 : return poSrcLayer->GetStyleTable();
752 : }
753 :
754 0 : virtual void SetSpatialFilter(OGRGeometry *poGeom) override
755 : {
756 0 : poSrcLayer->SetSpatialFilter(poGeom);
757 0 : }
758 :
759 0 : virtual void SetSpatialFilter(int iGeom, OGRGeometry *poGeom) override
760 : {
761 0 : poSrcLayer->SetSpatialFilter(iGeom, poGeom);
762 0 : }
763 :
764 0 : virtual void SetSpatialFilterRect(double dfMinX, double dfMinY,
765 : double dfMaxX, double dfMaxY) override
766 : {
767 0 : poSrcLayer->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX, dfMaxY);
768 0 : }
769 :
770 0 : virtual void SetSpatialFilterRect(int iGeom, double dfMinX, double dfMinY,
771 : double dfMaxX, double dfMaxY) override
772 : {
773 0 : poSrcLayer->SetSpatialFilterRect(iGeom, dfMinX, dfMinY, dfMaxX, dfMaxY);
774 0 : }
775 :
776 0 : virtual OGRErr SetAttributeFilter(const char *pszFilter) override
777 : {
778 0 : return poSrcLayer->SetAttributeFilter(pszFilter);
779 : }
780 : };
781 :
782 : /************************************************************************/
783 : /* OGRSplitListFieldLayer() */
784 : /************************************************************************/
785 :
786 1 : OGRSplitListFieldLayer::OGRSplitListFieldLayer(OGRLayer *poSrcLayerIn,
787 1 : int nMaxSplitListSubFieldsIn)
788 : : poSrcLayer(poSrcLayerIn), poFeatureDefn(nullptr), pasListFields(nullptr),
789 : nListFieldCount(0),
790 : nMaxSplitListSubFields(
791 1 : nMaxSplitListSubFieldsIn < 0 ? INT_MAX : nMaxSplitListSubFieldsIn)
792 : {
793 1 : }
794 :
795 : /************************************************************************/
796 : /* ~OGRSplitListFieldLayer() */
797 : /************************************************************************/
798 :
799 2 : OGRSplitListFieldLayer::~OGRSplitListFieldLayer()
800 : {
801 1 : if (poFeatureDefn)
802 1 : poFeatureDefn->Release();
803 :
804 1 : CPLFree(pasListFields);
805 2 : }
806 :
807 : /************************************************************************/
808 : /* BuildLayerDefn() */
809 : /************************************************************************/
810 :
811 1 : bool OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
812 : void *pProgressArg)
813 : {
814 1 : CPLAssert(poFeatureDefn == nullptr);
815 :
816 1 : OGRFeatureDefn *poSrcFieldDefn = poSrcLayer->GetLayerDefn();
817 :
818 1 : int nSrcFields = poSrcFieldDefn->GetFieldCount();
819 1 : pasListFields = static_cast<ListFieldDesc *>(
820 1 : CPLCalloc(sizeof(ListFieldDesc), nSrcFields));
821 1 : nListFieldCount = 0;
822 :
823 : /* Establish the list of fields of list type */
824 6 : for (int i = 0; i < nSrcFields; ++i)
825 : {
826 5 : OGRFieldType eType = poSrcFieldDefn->GetFieldDefn(i)->GetType();
827 5 : if (eType == OFTIntegerList || eType == OFTInteger64List ||
828 3 : eType == OFTRealList || eType == OFTStringList)
829 : {
830 3 : pasListFields[nListFieldCount].iSrcIndex = i;
831 3 : pasListFields[nListFieldCount].eType = eType;
832 3 : if (nMaxSplitListSubFields == 1)
833 0 : pasListFields[nListFieldCount].nMaxOccurrences = 1;
834 3 : nListFieldCount++;
835 : }
836 : }
837 :
838 1 : if (nListFieldCount == 0)
839 0 : return false;
840 :
841 : /* No need for full scan if the limit is 1. We just to have to create */
842 : /* one and a single one field */
843 1 : if (nMaxSplitListSubFields != 1)
844 : {
845 1 : poSrcLayer->ResetReading();
846 :
847 : const GIntBig nFeatureCount =
848 1 : poSrcLayer->TestCapability(OLCFastFeatureCount)
849 1 : ? poSrcLayer->GetFeatureCount()
850 1 : : 0;
851 1 : GIntBig nFeatureIndex = 0;
852 :
853 : /* Scan the whole layer to compute the maximum number of */
854 : /* items for each field of list type */
855 2 : for (auto &poSrcFeature : poSrcLayer)
856 : {
857 4 : for (int i = 0; i < nListFieldCount; ++i)
858 : {
859 3 : int nCount = 0;
860 : OGRField *psField =
861 3 : poSrcFeature->GetRawFieldRef(pasListFields[i].iSrcIndex);
862 3 : switch (pasListFields[i].eType)
863 : {
864 1 : case OFTIntegerList:
865 1 : nCount = psField->IntegerList.nCount;
866 1 : break;
867 1 : case OFTRealList:
868 1 : nCount = psField->RealList.nCount;
869 1 : break;
870 1 : case OFTStringList:
871 : {
872 1 : nCount = psField->StringList.nCount;
873 1 : char **paList = psField->StringList.paList;
874 3 : for (int j = 0; j < nCount; j++)
875 : {
876 2 : int nWidth = static_cast<int>(strlen(paList[j]));
877 2 : if (nWidth > pasListFields[i].nWidth)
878 1 : pasListFields[i].nWidth = nWidth;
879 : }
880 1 : break;
881 : }
882 0 : default:
883 : // cppcheck-suppress knownConditionTrueFalse
884 0 : CPLAssert(false);
885 : break;
886 : }
887 3 : if (nCount > pasListFields[i].nMaxOccurrences)
888 : {
889 3 : if (nCount > nMaxSplitListSubFields)
890 0 : nCount = nMaxSplitListSubFields;
891 3 : pasListFields[i].nMaxOccurrences = nCount;
892 : }
893 : }
894 :
895 1 : nFeatureIndex++;
896 1 : if (pfnProgress != nullptr && nFeatureCount != 0)
897 0 : pfnProgress(nFeatureIndex * 1.0 / nFeatureCount, "",
898 : pProgressArg);
899 : }
900 : }
901 :
902 : /* Now let's build the target feature definition */
903 :
904 1 : poFeatureDefn =
905 1 : OGRFeatureDefn::CreateFeatureDefn(poSrcFieldDefn->GetName());
906 1 : poFeatureDefn->Reference();
907 1 : poFeatureDefn->SetGeomType(wkbNone);
908 :
909 1 : for (int i = 0; i < poSrcFieldDefn->GetGeomFieldCount(); ++i)
910 : {
911 0 : poFeatureDefn->AddGeomFieldDefn(poSrcFieldDefn->GetGeomFieldDefn(i));
912 : }
913 :
914 1 : int iListField = 0;
915 6 : for (int i = 0; i < nSrcFields; ++i)
916 : {
917 5 : const OGRFieldType eType = poSrcFieldDefn->GetFieldDefn(i)->GetType();
918 5 : if (eType == OFTIntegerList || eType == OFTInteger64List ||
919 3 : eType == OFTRealList || eType == OFTStringList)
920 : {
921 3 : const int nMaxOccurrences =
922 3 : pasListFields[iListField].nMaxOccurrences;
923 3 : const int nWidth = pasListFields[iListField].nWidth;
924 3 : iListField++;
925 3 : if (nMaxOccurrences == 1)
926 : {
927 : OGRFieldDefn oFieldDefn(
928 0 : poSrcFieldDefn->GetFieldDefn(i)->GetNameRef(),
929 : (eType == OFTIntegerList) ? OFTInteger
930 0 : : (eType == OFTInteger64List) ? OFTInteger64
931 0 : : (eType == OFTRealList) ? OFTReal
932 0 : : OFTString);
933 0 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
934 : }
935 : else
936 : {
937 9 : for (int j = 0; j < nMaxOccurrences; j++)
938 : {
939 12 : CPLString osFieldName;
940 : osFieldName.Printf(
941 6 : "%s%d", poSrcFieldDefn->GetFieldDefn(i)->GetNameRef(),
942 6 : j + 1);
943 : OGRFieldDefn oFieldDefn(
944 : osFieldName.c_str(),
945 : (eType == OFTIntegerList) ? OFTInteger
946 8 : : (eType == OFTInteger64List) ? OFTInteger64
947 4 : : (eType == OFTRealList) ? OFTReal
948 16 : : OFTString);
949 6 : oFieldDefn.SetWidth(nWidth);
950 6 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
951 : }
952 3 : }
953 : }
954 : else
955 : {
956 2 : poFeatureDefn->AddFieldDefn(poSrcFieldDefn->GetFieldDefn(i));
957 : }
958 : }
959 :
960 1 : return true;
961 : }
962 :
963 : /************************************************************************/
964 : /* TranslateFeature() */
965 : /************************************************************************/
966 :
967 2 : OGRFeature *OGRSplitListFieldLayer::TranslateFeature(OGRFeature *poSrcFeature)
968 : {
969 2 : if (poSrcFeature == nullptr)
970 1 : return nullptr;
971 1 : if (poFeatureDefn == nullptr)
972 0 : return poSrcFeature;
973 :
974 1 : OGRFeature *poFeature = OGRFeature::CreateFeature(poFeatureDefn);
975 1 : poFeature->SetFID(poSrcFeature->GetFID());
976 1 : for (int i = 0; i < poFeature->GetGeomFieldCount(); i++)
977 : {
978 0 : poFeature->SetGeomFieldDirectly(i, poSrcFeature->StealGeometry(i));
979 : }
980 1 : poFeature->SetStyleString(poFeature->GetStyleString());
981 :
982 1 : OGRFeatureDefn *poSrcFieldDefn = poSrcLayer->GetLayerDefn();
983 1 : int nSrcFields = poSrcFeature->GetFieldCount();
984 1 : int iDstField = 0;
985 1 : int iListField = 0;
986 :
987 6 : for (int iSrcField = 0; iSrcField < nSrcFields; ++iSrcField)
988 : {
989 : const OGRFieldType eType =
990 5 : poSrcFieldDefn->GetFieldDefn(iSrcField)->GetType();
991 5 : OGRField *psField = poSrcFeature->GetRawFieldRef(iSrcField);
992 5 : switch (eType)
993 : {
994 1 : case OFTIntegerList:
995 : {
996 1 : const int nCount = std::min(nMaxSplitListSubFields,
997 1 : psField->IntegerList.nCount);
998 1 : int *paList = psField->IntegerList.paList;
999 3 : for (int j = 0; j < nCount; ++j)
1000 2 : poFeature->SetField(iDstField + j, paList[j]);
1001 1 : iDstField += pasListFields[iListField].nMaxOccurrences;
1002 1 : iListField++;
1003 1 : break;
1004 : }
1005 0 : case OFTInteger64List:
1006 : {
1007 0 : const int nCount = std::min(nMaxSplitListSubFields,
1008 0 : psField->Integer64List.nCount);
1009 0 : GIntBig *paList = psField->Integer64List.paList;
1010 0 : for (int j = 0; j < nCount; ++j)
1011 0 : poFeature->SetField(iDstField + j, paList[j]);
1012 0 : iDstField += pasListFields[iListField].nMaxOccurrences;
1013 0 : iListField++;
1014 0 : break;
1015 : }
1016 1 : case OFTRealList:
1017 : {
1018 : const int nCount =
1019 1 : std::min(nMaxSplitListSubFields, psField->RealList.nCount);
1020 1 : double *paList = psField->RealList.paList;
1021 3 : for (int j = 0; j < nCount; ++j)
1022 2 : poFeature->SetField(iDstField + j, paList[j]);
1023 1 : iDstField += pasListFields[iListField].nMaxOccurrences;
1024 1 : iListField++;
1025 1 : break;
1026 : }
1027 1 : case OFTStringList:
1028 : {
1029 1 : const int nCount = std::min(nMaxSplitListSubFields,
1030 1 : psField->StringList.nCount);
1031 1 : char **paList = psField->StringList.paList;
1032 3 : for (int j = 0; j < nCount; ++j)
1033 2 : poFeature->SetField(iDstField + j, paList[j]);
1034 1 : iDstField += pasListFields[iListField].nMaxOccurrences;
1035 1 : iListField++;
1036 1 : break;
1037 : }
1038 2 : default:
1039 : {
1040 2 : poFeature->SetField(iDstField, psField);
1041 2 : iDstField++;
1042 2 : break;
1043 : }
1044 : }
1045 : }
1046 :
1047 1 : OGRFeature::DestroyFeature(poSrcFeature);
1048 :
1049 1 : return poFeature;
1050 : }
1051 :
1052 : /************************************************************************/
1053 : /* GetNextFeature() */
1054 : /************************************************************************/
1055 :
1056 2 : OGRFeature *OGRSplitListFieldLayer::GetNextFeature()
1057 : {
1058 2 : return TranslateFeature(poSrcLayer->GetNextFeature());
1059 : }
1060 :
1061 : /************************************************************************/
1062 : /* GetFeature() */
1063 : /************************************************************************/
1064 :
1065 0 : OGRFeature *OGRSplitListFieldLayer::GetFeature(GIntBig nFID)
1066 : {
1067 0 : return TranslateFeature(poSrcLayer->GetFeature(nFID));
1068 : }
1069 :
1070 : /************************************************************************/
1071 : /* GetLayerDefn() */
1072 : /************************************************************************/
1073 :
1074 3 : OGRFeatureDefn *OGRSplitListFieldLayer::GetLayerDefn()
1075 : {
1076 3 : if (poFeatureDefn == nullptr)
1077 0 : return poSrcLayer->GetLayerDefn();
1078 3 : return poFeatureDefn;
1079 : }
1080 :
1081 : /************************************************************************/
1082 : /* GCPCoordTransformation() */
1083 : /* */
1084 : /* Apply GCP Transform to points */
1085 : /************************************************************************/
1086 :
1087 : class GCPCoordTransformation : public OGRCoordinateTransformation
1088 : {
1089 0 : GCPCoordTransformation(const GCPCoordTransformation &other)
1090 0 : : hTransformArg(GDALCloneTransformer(other.hTransformArg)),
1091 0 : bUseTPS(other.bUseTPS), poSRS(other.poSRS)
1092 : {
1093 0 : if (poSRS)
1094 0 : poSRS->Reference();
1095 0 : }
1096 :
1097 : GCPCoordTransformation &operator=(const GCPCoordTransformation &) = delete;
1098 :
1099 : public:
1100 : void *hTransformArg;
1101 : bool bUseTPS;
1102 : OGRSpatialReference *poSRS;
1103 :
1104 5 : GCPCoordTransformation(int nGCPCount, const GDAL_GCP *pasGCPList,
1105 : int nReqOrder, OGRSpatialReference *poSRSIn)
1106 5 : : hTransformArg(nullptr), bUseTPS(nReqOrder < 0), poSRS(poSRSIn)
1107 : {
1108 5 : if (nReqOrder < 0)
1109 : {
1110 1 : hTransformArg =
1111 1 : GDALCreateTPSTransformer(nGCPCount, pasGCPList, FALSE);
1112 : }
1113 : else
1114 : {
1115 4 : hTransformArg = GDALCreateGCPTransformer(nGCPCount, pasGCPList,
1116 : nReqOrder, FALSE);
1117 : }
1118 5 : if (poSRS)
1119 2 : poSRS->Reference();
1120 5 : }
1121 :
1122 0 : OGRCoordinateTransformation *Clone() const override
1123 : {
1124 0 : return new GCPCoordTransformation(*this);
1125 : }
1126 :
1127 5 : bool IsValid() const
1128 : {
1129 5 : return hTransformArg != nullptr;
1130 : }
1131 :
1132 10 : virtual ~GCPCoordTransformation()
1133 5 : {
1134 5 : if (hTransformArg != nullptr)
1135 : {
1136 5 : GDALDestroyTransformer(hTransformArg);
1137 : }
1138 5 : if (poSRS)
1139 2 : poSRS->Dereference();
1140 10 : }
1141 :
1142 10 : virtual const OGRSpatialReference *GetSourceCS() const override
1143 : {
1144 10 : return poSRS;
1145 : }
1146 :
1147 16 : virtual const OGRSpatialReference *GetTargetCS() const override
1148 : {
1149 16 : return poSRS;
1150 : }
1151 :
1152 10 : virtual int Transform(size_t nCount, double *x, double *y, double *z,
1153 : double * /* t */, int *pabSuccess) override
1154 : {
1155 10 : CPLAssert(nCount <=
1156 : static_cast<size_t>(std::numeric_limits<int>::max()));
1157 10 : if (bUseTPS)
1158 2 : return GDALTPSTransform(hTransformArg, FALSE,
1159 : static_cast<int>(nCount), x, y, z,
1160 2 : pabSuccess);
1161 : else
1162 8 : return GDALGCPTransform(hTransformArg, FALSE,
1163 : static_cast<int>(nCount), x, y, z,
1164 8 : pabSuccess);
1165 : }
1166 :
1167 0 : virtual OGRCoordinateTransformation *GetInverse() const override
1168 : {
1169 0 : return nullptr;
1170 : }
1171 : };
1172 :
1173 : /************************************************************************/
1174 : /* CompositeCT */
1175 : /************************************************************************/
1176 :
1177 : class CompositeCT : public OGRCoordinateTransformation
1178 : {
1179 0 : CompositeCT(const CompositeCT &other)
1180 0 : : poCT1(other.poCT1 ? other.poCT1->Clone() : nullptr), bOwnCT1(true),
1181 0 : poCT2(other.poCT2 ? other.poCT2->Clone() : nullptr), bOwnCT2(true)
1182 : {
1183 0 : }
1184 :
1185 : CompositeCT &operator=(const CompositeCT &) = delete;
1186 :
1187 : public:
1188 : OGRCoordinateTransformation *poCT1;
1189 : bool bOwnCT1;
1190 : OGRCoordinateTransformation *poCT2;
1191 : bool bOwnCT2;
1192 :
1193 28 : CompositeCT(OGRCoordinateTransformation *poCT1In, bool bOwnCT1In,
1194 : OGRCoordinateTransformation *poCT2In, bool bOwnCT2In)
1195 28 : : poCT1(poCT1In), bOwnCT1(bOwnCT1In), poCT2(poCT2In), bOwnCT2(bOwnCT2In)
1196 : {
1197 28 : }
1198 :
1199 56 : virtual ~CompositeCT()
1200 28 : {
1201 28 : if (bOwnCT1)
1202 0 : delete poCT1;
1203 28 : if (bOwnCT2)
1204 24 : delete poCT2;
1205 56 : }
1206 :
1207 0 : OGRCoordinateTransformation *Clone() const override
1208 : {
1209 0 : return new CompositeCT(*this);
1210 : }
1211 :
1212 10100 : virtual const OGRSpatialReference *GetSourceCS() const override
1213 : {
1214 20190 : return poCT1 ? poCT1->GetSourceCS()
1215 10090 : : poCT2 ? poCT2->GetSourceCS()
1216 10100 : : nullptr;
1217 : }
1218 :
1219 40386 : virtual const OGRSpatialReference *GetTargetCS() const override
1220 : {
1221 40402 : return poCT2 ? poCT2->GetTargetCS()
1222 16 : : poCT1 ? poCT1->GetTargetCS()
1223 40386 : : nullptr;
1224 : }
1225 :
1226 10057 : virtual bool GetEmitErrors() const override
1227 : {
1228 10057 : if (poCT1)
1229 0 : return poCT1->GetEmitErrors();
1230 10057 : if (poCT2)
1231 10057 : return poCT2->GetEmitErrors();
1232 0 : return true;
1233 : }
1234 :
1235 20114 : virtual void SetEmitErrors(bool bEmitErrors) override
1236 : {
1237 20114 : if (poCT1)
1238 0 : poCT1->SetEmitErrors(bEmitErrors);
1239 20114 : if (poCT2)
1240 20114 : poCT2->SetEmitErrors(bEmitErrors);
1241 20114 : }
1242 :
1243 50434 : virtual int Transform(size_t nCount, double *x, double *y, double *z,
1244 : double *t, int *pabSuccess) override
1245 : {
1246 50434 : int nResult = TRUE;
1247 50434 : if (poCT1)
1248 10 : nResult = poCT1->Transform(nCount, x, y, z, t, pabSuccess);
1249 50434 : if (nResult && poCT2)
1250 50426 : nResult = poCT2->Transform(nCount, x, y, z, t, pabSuccess);
1251 50434 : return nResult;
1252 : }
1253 :
1254 0 : virtual OGRCoordinateTransformation *GetInverse() const override
1255 : {
1256 0 : return nullptr;
1257 : }
1258 : };
1259 :
1260 : /************************************************************************/
1261 : /* AxisMappingCoordinateTransformation */
1262 : /************************************************************************/
1263 :
1264 : class AxisMappingCoordinateTransformation : public OGRCoordinateTransformation
1265 : {
1266 : public:
1267 : bool bSwapXY = false;
1268 :
1269 0 : AxisMappingCoordinateTransformation(const std::vector<int> &mappingIn,
1270 : const std::vector<int> &mappingOut)
1271 0 : {
1272 0 : if (mappingIn.size() >= 2 && mappingIn[0] == 1 && mappingIn[1] == 2 &&
1273 0 : mappingOut.size() >= 2 && mappingOut[0] == 2 && mappingOut[1] == 1)
1274 : {
1275 0 : bSwapXY = true;
1276 : }
1277 0 : else if (mappingIn.size() >= 2 && mappingIn[0] == 2 &&
1278 0 : mappingIn[1] == 1 && mappingOut.size() >= 2 &&
1279 0 : mappingOut[0] == 1 && mappingOut[1] == 2)
1280 : {
1281 0 : bSwapXY = true;
1282 : }
1283 : else
1284 : {
1285 0 : CPLError(CE_Failure, CPLE_NotSupported,
1286 : "Unsupported axis transformation");
1287 : }
1288 0 : }
1289 :
1290 0 : ~AxisMappingCoordinateTransformation() override
1291 0 : {
1292 0 : }
1293 :
1294 0 : virtual OGRCoordinateTransformation *Clone() const override
1295 : {
1296 0 : return new AxisMappingCoordinateTransformation(*this);
1297 : }
1298 :
1299 0 : virtual const OGRSpatialReference *GetSourceCS() const override
1300 : {
1301 0 : return nullptr;
1302 : }
1303 :
1304 0 : virtual const OGRSpatialReference *GetTargetCS() const override
1305 : {
1306 0 : return nullptr;
1307 : }
1308 :
1309 0 : virtual int Transform(size_t nCount, double *x, double *y, double * /*z*/,
1310 : double * /*t*/, int *pabSuccess) override
1311 : {
1312 0 : for (size_t i = 0; i < nCount; i++)
1313 : {
1314 0 : if (pabSuccess)
1315 0 : pabSuccess[i] = true;
1316 0 : if (bSwapXY)
1317 0 : std::swap(x[i], y[i]);
1318 : }
1319 0 : return true;
1320 : }
1321 :
1322 0 : virtual OGRCoordinateTransformation *GetInverse() const override
1323 : {
1324 0 : return nullptr;
1325 : }
1326 : };
1327 :
1328 : /************************************************************************/
1329 : /* ApplySpatialFilter() */
1330 : /************************************************************************/
1331 :
1332 782 : static void ApplySpatialFilter(OGRLayer *poLayer, OGRGeometry *poSpatialFilter,
1333 : const OGRSpatialReference *poSpatSRS,
1334 : const char *pszGeomField,
1335 : const OGRSpatialReference *poSourceSRS)
1336 : {
1337 782 : if (poSpatialFilter == nullptr)
1338 774 : return;
1339 :
1340 8 : OGRGeometry *poSpatialFilterReprojected = nullptr;
1341 8 : if (poSpatSRS)
1342 : {
1343 4 : poSpatialFilterReprojected = poSpatialFilter->clone();
1344 4 : poSpatialFilterReprojected->assignSpatialReference(poSpatSRS);
1345 : const OGRSpatialReference *poSpatialFilterTargetSRS =
1346 4 : poSourceSRS ? poSourceSRS : poLayer->GetSpatialRef();
1347 4 : if (poSpatialFilterTargetSRS)
1348 : {
1349 : // When transforming the spatial filter from its spat_srs to the
1350 : // layer SRS, make sure to densify it sufficiently to avoid issues
1351 4 : constexpr double SEGMENT_DISTANCE_METRE = 10 * 1000;
1352 4 : if (poSpatSRS->IsGeographic())
1353 : {
1354 : const double LENGTH_OF_ONE_DEGREE =
1355 1 : poSpatSRS->GetSemiMajor(nullptr) * M_PI / 180.0;
1356 1 : poSpatialFilterReprojected->segmentize(SEGMENT_DISTANCE_METRE /
1357 1 : LENGTH_OF_ONE_DEGREE);
1358 : }
1359 3 : else if (poSpatSRS->IsProjected())
1360 : {
1361 3 : poSpatialFilterReprojected->segmentize(
1362 : SEGMENT_DISTANCE_METRE /
1363 3 : poSpatSRS->GetLinearUnits(nullptr));
1364 : }
1365 4 : poSpatialFilterReprojected->transformTo(poSpatialFilterTargetSRS);
1366 : }
1367 : else
1368 0 : CPLError(CE_Warning, CPLE_AppDefined,
1369 : "cannot determine layer SRS for %s.",
1370 0 : poLayer->GetDescription());
1371 : }
1372 :
1373 8 : if (pszGeomField != nullptr)
1374 : {
1375 : const int iGeomField =
1376 1 : poLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomField);
1377 1 : if (iGeomField >= 0)
1378 1 : poLayer->SetSpatialFilter(iGeomField,
1379 : poSpatialFilterReprojected
1380 : ? poSpatialFilterReprojected
1381 1 : : poSpatialFilter);
1382 : else
1383 0 : CPLError(CE_Warning, CPLE_AppDefined,
1384 : "Cannot find geometry field %s.", pszGeomField);
1385 : }
1386 : else
1387 : {
1388 7 : poLayer->SetSpatialFilter(poSpatialFilterReprojected
1389 : ? poSpatialFilterReprojected
1390 7 : : poSpatialFilter);
1391 : }
1392 :
1393 8 : delete poSpatialFilterReprojected;
1394 : }
1395 :
1396 : /************************************************************************/
1397 : /* GetFieldType() */
1398 : /************************************************************************/
1399 :
1400 12 : static int GetFieldType(const char *pszArg, int *pnSubFieldType)
1401 : {
1402 12 : *pnSubFieldType = OFSTNone;
1403 12 : const char *pszOpenParenthesis = strchr(pszArg, '(');
1404 12 : const int nLengthBeforeParenthesis =
1405 12 : pszOpenParenthesis ? static_cast<int>(pszOpenParenthesis - pszArg)
1406 11 : : static_cast<int>(strlen(pszArg));
1407 72 : for (int iType = 0; iType <= static_cast<int>(OFTMaxType); iType++)
1408 : {
1409 : const char *pszFieldTypeName =
1410 72 : OGRFieldDefn::GetFieldTypeName(static_cast<OGRFieldType>(iType));
1411 72 : if (EQUALN(pszArg, pszFieldTypeName, nLengthBeforeParenthesis) &&
1412 12 : pszFieldTypeName[nLengthBeforeParenthesis] == '\0')
1413 : {
1414 12 : if (pszOpenParenthesis != nullptr)
1415 : {
1416 1 : *pnSubFieldType = -1;
1417 2 : CPLString osArgSubType = pszOpenParenthesis + 1;
1418 1 : if (!osArgSubType.empty() && osArgSubType.back() == ')')
1419 1 : osArgSubType.resize(osArgSubType.size() - 1);
1420 2 : for (int iSubType = 0;
1421 2 : iSubType <= static_cast<int>(OFSTMaxSubType); iSubType++)
1422 : {
1423 : const char *pszFieldSubTypeName =
1424 2 : OGRFieldDefn::GetFieldSubTypeName(
1425 : static_cast<OGRFieldSubType>(iSubType));
1426 2 : if (EQUAL(pszFieldSubTypeName, osArgSubType))
1427 : {
1428 1 : *pnSubFieldType = iSubType;
1429 1 : break;
1430 : }
1431 : }
1432 : }
1433 12 : return iType;
1434 : }
1435 : }
1436 0 : return -1;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* IsFieldType() */
1441 : /************************************************************************/
1442 :
1443 8 : static bool IsFieldType(const char *pszArg)
1444 : {
1445 : int iSubType;
1446 8 : return GetFieldType(pszArg, &iSubType) >= 0 && iSubType >= 0;
1447 : }
1448 :
1449 : class GDALVectorTranslateWrappedDataset : public GDALDataset
1450 : {
1451 : GDALDataset *m_poBase;
1452 : OGRSpatialReference *m_poOutputSRS;
1453 : bool m_bTransform;
1454 :
1455 : std::vector<OGRLayer *> m_apoLayers;
1456 : std::vector<OGRLayer *> m_apoHiddenLayers;
1457 :
1458 : GDALVectorTranslateWrappedDataset(GDALDataset *poBase,
1459 : OGRSpatialReference *poOutputSRS,
1460 : bool bTransform);
1461 :
1462 : public:
1463 : virtual ~GDALVectorTranslateWrappedDataset();
1464 :
1465 3 : virtual int GetLayerCount() override
1466 : {
1467 3 : return static_cast<int>(m_apoLayers.size());
1468 : }
1469 :
1470 : virtual OGRLayer *GetLayer(int nIdx) override;
1471 : virtual OGRLayer *GetLayerByName(const char *pszName) override;
1472 :
1473 : virtual OGRLayer *ExecuteSQL(const char *pszStatement,
1474 : OGRGeometry *poSpatialFilter,
1475 : const char *pszDialect) override;
1476 : virtual void ReleaseResultSet(OGRLayer *poResultsSet) override;
1477 :
1478 : static GDALVectorTranslateWrappedDataset *
1479 : New(GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform);
1480 : };
1481 :
1482 : class GDALVectorTranslateWrappedLayer : public OGRLayerDecorator
1483 : {
1484 : std::vector<OGRCoordinateTransformation *> m_apoCT;
1485 : OGRFeatureDefn *m_poFDefn;
1486 :
1487 : GDALVectorTranslateWrappedLayer(OGRLayer *poBaseLayer, bool bOwnBaseLayer);
1488 : OGRFeature *TranslateFeature(OGRFeature *poSrcFeat);
1489 :
1490 : public:
1491 : virtual ~GDALVectorTranslateWrappedLayer();
1492 :
1493 379 : virtual OGRFeatureDefn *GetLayerDefn() override
1494 : {
1495 379 : return m_poFDefn;
1496 : }
1497 :
1498 : virtual OGRFeature *GetNextFeature() override;
1499 : virtual OGRFeature *GetFeature(GIntBig nFID) override;
1500 :
1501 : static GDALVectorTranslateWrappedLayer *
1502 : New(OGRLayer *poBaseLayer, bool bOwnBaseLayer,
1503 : OGRSpatialReference *poOutputSRS, bool bTransform);
1504 : };
1505 :
1506 89 : GDALVectorTranslateWrappedLayer::GDALVectorTranslateWrappedLayer(
1507 89 : OGRLayer *poBaseLayer, bool bOwnBaseLayer)
1508 : : OGRLayerDecorator(poBaseLayer, bOwnBaseLayer),
1509 89 : m_apoCT(poBaseLayer->GetLayerDefn()->GetGeomFieldCount(),
1510 89 : static_cast<OGRCoordinateTransformation *>(nullptr)),
1511 178 : m_poFDefn(nullptr)
1512 : {
1513 89 : }
1514 :
1515 : GDALVectorTranslateWrappedLayer *
1516 89 : GDALVectorTranslateWrappedLayer::New(OGRLayer *poBaseLayer, bool bOwnBaseLayer,
1517 : OGRSpatialReference *poOutputSRS,
1518 : bool bTransform)
1519 : {
1520 : GDALVectorTranslateWrappedLayer *poNew =
1521 89 : new GDALVectorTranslateWrappedLayer(poBaseLayer, bOwnBaseLayer);
1522 89 : poNew->m_poFDefn = poBaseLayer->GetLayerDefn()->Clone();
1523 89 : poNew->m_poFDefn->Reference();
1524 89 : if (!poOutputSRS)
1525 0 : return poNew;
1526 :
1527 104 : for (int i = 0; i < poNew->m_poFDefn->GetGeomFieldCount(); i++)
1528 : {
1529 15 : if (bTransform)
1530 : {
1531 0 : const OGRSpatialReference *poSourceSRS = poBaseLayer->GetLayerDefn()
1532 0 : ->GetGeomFieldDefn(i)
1533 0 : ->GetSpatialRef();
1534 0 : if (poSourceSRS == nullptr)
1535 : {
1536 0 : CPLError(CE_Failure, CPLE_AppDefined,
1537 : "Layer %s has no source SRS for geometry field %s",
1538 0 : poBaseLayer->GetName(),
1539 0 : poBaseLayer->GetLayerDefn()
1540 0 : ->GetGeomFieldDefn(i)
1541 : ->GetNameRef());
1542 0 : delete poNew;
1543 0 : return nullptr;
1544 : }
1545 : else
1546 : {
1547 0 : poNew->m_apoCT[i] =
1548 0 : OGRCreateCoordinateTransformation(poSourceSRS, poOutputSRS);
1549 0 : if (poNew->m_apoCT[i] == nullptr)
1550 : {
1551 0 : CPLError(CE_Failure, CPLE_AppDefined,
1552 : "Failed to create coordinate transformation "
1553 : "between the\n"
1554 : "following coordinate systems. This may be "
1555 : "because they\n"
1556 : "are not transformable.");
1557 :
1558 0 : char *pszWKT = nullptr;
1559 0 : poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
1560 0 : CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
1561 : pszWKT);
1562 0 : CPLFree(pszWKT);
1563 :
1564 0 : poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
1565 0 : CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
1566 : pszWKT);
1567 0 : CPLFree(pszWKT);
1568 :
1569 0 : delete poNew;
1570 0 : return nullptr;
1571 : }
1572 : }
1573 : }
1574 15 : poNew->m_poFDefn->GetGeomFieldDefn(i)->SetSpatialRef(poOutputSRS);
1575 : }
1576 :
1577 89 : return poNew;
1578 : }
1579 :
1580 178 : GDALVectorTranslateWrappedLayer::~GDALVectorTranslateWrappedLayer()
1581 : {
1582 89 : if (m_poFDefn)
1583 89 : m_poFDefn->Release();
1584 104 : for (size_t i = 0; i < m_apoCT.size(); ++i)
1585 15 : delete m_apoCT[i];
1586 178 : }
1587 :
1588 661 : OGRFeature *GDALVectorTranslateWrappedLayer::GetNextFeature()
1589 : {
1590 661 : return TranslateFeature(OGRLayerDecorator::GetNextFeature());
1591 : }
1592 :
1593 0 : OGRFeature *GDALVectorTranslateWrappedLayer::GetFeature(GIntBig nFID)
1594 : {
1595 0 : return TranslateFeature(OGRLayerDecorator::GetFeature(nFID));
1596 : }
1597 :
1598 : OGRFeature *
1599 661 : GDALVectorTranslateWrappedLayer::TranslateFeature(OGRFeature *poSrcFeat)
1600 : {
1601 661 : if (poSrcFeat == nullptr)
1602 103 : return nullptr;
1603 558 : OGRFeature *poNewFeat = new OGRFeature(m_poFDefn);
1604 558 : poNewFeat->SetFrom(poSrcFeat);
1605 558 : poNewFeat->SetFID(poSrcFeat->GetFID());
1606 573 : for (int i = 0; i < poNewFeat->GetGeomFieldCount(); i++)
1607 : {
1608 15 : OGRGeometry *poGeom = poNewFeat->GetGeomFieldRef(i);
1609 15 : if (poGeom)
1610 : {
1611 13 : if (m_apoCT[i])
1612 0 : poGeom->transform(m_apoCT[i]);
1613 13 : poGeom->assignSpatialReference(
1614 13 : m_poFDefn->GetGeomFieldDefn(i)->GetSpatialRef());
1615 : }
1616 : }
1617 558 : delete poSrcFeat;
1618 558 : return poNewFeat;
1619 : }
1620 :
1621 3 : GDALVectorTranslateWrappedDataset::GDALVectorTranslateWrappedDataset(
1622 3 : GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform)
1623 3 : : m_poBase(poBase), m_poOutputSRS(poOutputSRS), m_bTransform(bTransform)
1624 : {
1625 3 : SetDescription(poBase->GetDescription());
1626 3 : if (poBase->GetDriver())
1627 : {
1628 3 : poDriver = new GDALDriver();
1629 3 : poDriver->SetDescription(poBase->GetDriver()->GetDescription());
1630 : }
1631 3 : }
1632 :
1633 3 : GDALVectorTranslateWrappedDataset *GDALVectorTranslateWrappedDataset::New(
1634 : GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform)
1635 : {
1636 : GDALVectorTranslateWrappedDataset *poNew =
1637 3 : new GDALVectorTranslateWrappedDataset(poBase, poOutputSRS, bTransform);
1638 70 : for (int i = 0; i < poBase->GetLayerCount(); i++)
1639 : {
1640 67 : OGRLayer *poLayer = GDALVectorTranslateWrappedLayer::New(
1641 67 : poBase->GetLayer(i), false, poOutputSRS, bTransform);
1642 67 : if (poLayer == nullptr)
1643 : {
1644 0 : delete poNew;
1645 0 : return nullptr;
1646 : }
1647 67 : poNew->m_apoLayers.push_back(poLayer);
1648 : }
1649 3 : return poNew;
1650 : }
1651 :
1652 6 : GDALVectorTranslateWrappedDataset::~GDALVectorTranslateWrappedDataset()
1653 : {
1654 3 : delete poDriver;
1655 70 : for (size_t i = 0; i < m_apoLayers.size(); i++)
1656 : {
1657 67 : delete m_apoLayers[i];
1658 : }
1659 3 : for (size_t i = 0; i < m_apoHiddenLayers.size(); i++)
1660 : {
1661 0 : delete m_apoHiddenLayers[i];
1662 : }
1663 6 : }
1664 :
1665 0 : OGRLayer *GDALVectorTranslateWrappedDataset::GetLayer(int i)
1666 : {
1667 0 : if (i < 0 || i >= static_cast<int>(m_apoLayers.size()))
1668 0 : return nullptr;
1669 0 : return m_apoLayers[i];
1670 : }
1671 :
1672 68 : OGRLayer *GDALVectorTranslateWrappedDataset::GetLayerByName(const char *pszName)
1673 : {
1674 1008 : for (size_t i = 0; i < m_apoLayers.size(); i++)
1675 : {
1676 1008 : if (strcmp(m_apoLayers[i]->GetName(), pszName) == 0)
1677 68 : return m_apoLayers[i];
1678 : }
1679 0 : for (size_t i = 0; i < m_apoHiddenLayers.size(); i++)
1680 : {
1681 0 : if (strcmp(m_apoHiddenLayers[i]->GetName(), pszName) == 0)
1682 0 : return m_apoHiddenLayers[i];
1683 : }
1684 0 : for (size_t i = 0; i < m_apoLayers.size(); i++)
1685 : {
1686 0 : if (EQUAL(m_apoLayers[i]->GetName(), pszName))
1687 0 : return m_apoLayers[i];
1688 : }
1689 0 : for (size_t i = 0; i < m_apoHiddenLayers.size(); i++)
1690 : {
1691 0 : if (EQUAL(m_apoHiddenLayers[i]->GetName(), pszName))
1692 0 : return m_apoHiddenLayers[i];
1693 : }
1694 :
1695 0 : OGRLayer *poLayer = m_poBase->GetLayerByName(pszName);
1696 0 : if (poLayer == nullptr)
1697 0 : return nullptr;
1698 0 : poLayer = GDALVectorTranslateWrappedLayer::New(poLayer, false,
1699 0 : m_poOutputSRS, m_bTransform);
1700 0 : if (poLayer == nullptr)
1701 0 : return nullptr;
1702 :
1703 : // Replicate source dataset behavior: if the fact of calling
1704 : // GetLayerByName() on a initially hidden layer makes it visible through
1705 : // GetLayerCount()/GetLayer(), do the same. Otherwise we are going to
1706 : // maintain it hidden as well.
1707 0 : for (int i = 0; i < m_poBase->GetLayerCount(); i++)
1708 : {
1709 0 : if (m_poBase->GetLayer(i) == poLayer)
1710 : {
1711 0 : m_apoLayers.push_back(poLayer);
1712 0 : return poLayer;
1713 : }
1714 : }
1715 0 : m_apoHiddenLayers.push_back(poLayer);
1716 0 : return poLayer;
1717 : }
1718 :
1719 : OGRLayer *
1720 22 : GDALVectorTranslateWrappedDataset::ExecuteSQL(const char *pszStatement,
1721 : OGRGeometry *poSpatialFilter,
1722 : const char *pszDialect)
1723 : {
1724 : OGRLayer *poLayer =
1725 22 : m_poBase->ExecuteSQL(pszStatement, poSpatialFilter, pszDialect);
1726 22 : if (poLayer == nullptr)
1727 0 : return nullptr;
1728 44 : return GDALVectorTranslateWrappedLayer::New(poLayer, true, m_poOutputSRS,
1729 22 : m_bTransform);
1730 : }
1731 :
1732 22 : void GDALVectorTranslateWrappedDataset::ReleaseResultSet(OGRLayer *poResultsSet)
1733 : {
1734 22 : delete poResultsSet;
1735 22 : }
1736 :
1737 : /************************************************************************/
1738 : /* OGR2OGRSpatialReferenceHolder */
1739 : /************************************************************************/
1740 :
1741 : class OGR2OGRSpatialReferenceHolder
1742 : {
1743 : OGRSpatialReference *m_poSRS;
1744 :
1745 : public:
1746 649 : OGR2OGRSpatialReferenceHolder() : m_poSRS(nullptr)
1747 : {
1748 649 : }
1749 :
1750 649 : ~OGR2OGRSpatialReferenceHolder()
1751 649 : {
1752 649 : if (m_poSRS)
1753 134 : m_poSRS->Release();
1754 649 : }
1755 :
1756 134 : void assignNoRefIncrease(OGRSpatialReference *poSRS)
1757 : {
1758 134 : CPLAssert(m_poSRS == nullptr);
1759 134 : m_poSRS = poSRS;
1760 134 : }
1761 :
1762 1663 : OGRSpatialReference *get()
1763 : {
1764 1663 : return m_poSRS;
1765 : }
1766 : };
1767 :
1768 : /************************************************************************/
1769 : /* GDALVectorTranslateCreateCopy() */
1770 : /************************************************************************/
1771 :
1772 : static GDALDataset *
1773 22 : GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest,
1774 : GDALDataset *poDS,
1775 : const GDALVectorTranslateOptions *psOptions)
1776 : {
1777 22 : const char *const szErrorMsg = "%s not supported by this output driver";
1778 :
1779 22 : if (psOptions->bSkipFailures)
1780 : {
1781 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-skipfailures");
1782 0 : return nullptr;
1783 : }
1784 22 : if (psOptions->nLayerTransaction >= 0)
1785 : {
1786 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1787 : "-lyr_transaction or -ds_transaction");
1788 0 : return nullptr;
1789 : }
1790 22 : if (psOptions->nFIDToFetch >= 0)
1791 : {
1792 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-fid");
1793 0 : return nullptr;
1794 : }
1795 22 : if (!psOptions->aosLCO.empty())
1796 : {
1797 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-lco");
1798 0 : return nullptr;
1799 : }
1800 22 : if (psOptions->bAddMissingFields)
1801 : {
1802 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-addfields");
1803 0 : return nullptr;
1804 : }
1805 22 : if (!psOptions->osSourceSRSDef.empty())
1806 : {
1807 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-s_srs");
1808 0 : return nullptr;
1809 : }
1810 22 : if (!psOptions->bExactFieldNameMatch)
1811 : {
1812 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1813 : "-relaxedFieldNameMatch");
1814 0 : return nullptr;
1815 : }
1816 22 : if (!psOptions->osNewLayerName.empty())
1817 : {
1818 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nln");
1819 0 : return nullptr;
1820 : }
1821 22 : if (psOptions->bSelFieldsSet)
1822 : {
1823 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-select");
1824 0 : return nullptr;
1825 : }
1826 22 : if (!psOptions->osSQLStatement.empty())
1827 : {
1828 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-sql");
1829 0 : return nullptr;
1830 : }
1831 22 : if (!psOptions->osDialect.empty())
1832 : {
1833 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-dialect");
1834 0 : return nullptr;
1835 : }
1836 22 : if (psOptions->eGType != GEOMTYPE_UNCHANGED ||
1837 22 : psOptions->eGeomTypeConversion != GTC_DEFAULT)
1838 : {
1839 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nlt");
1840 0 : return nullptr;
1841 : }
1842 22 : if (!psOptions->aosFieldTypesToString.empty())
1843 : {
1844 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1845 : "-fieldTypeToString");
1846 0 : return nullptr;
1847 : }
1848 22 : if (!psOptions->aosMapFieldType.empty())
1849 : {
1850 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-mapFieldType");
1851 0 : return nullptr;
1852 : }
1853 22 : if (psOptions->bUnsetFieldWidth)
1854 : {
1855 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetFieldWidth");
1856 0 : return nullptr;
1857 : }
1858 22 : if (psOptions->bWrapDateline)
1859 : {
1860 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-wrapdateline");
1861 0 : return nullptr;
1862 : }
1863 22 : if (psOptions->bClipSrc)
1864 : {
1865 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrc");
1866 0 : return nullptr;
1867 : }
1868 22 : if (!psOptions->osClipSrcSQL.empty())
1869 : {
1870 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrcsql");
1871 0 : return nullptr;
1872 : }
1873 22 : if (!psOptions->osClipSrcLayer.empty())
1874 : {
1875 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrclayer");
1876 0 : return nullptr;
1877 : }
1878 22 : if (!psOptions->osClipSrcWhere.empty())
1879 : {
1880 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrcwhere");
1881 0 : return nullptr;
1882 : }
1883 22 : if (!psOptions->osClipDstDS.empty() || psOptions->poClipDst)
1884 : {
1885 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdst");
1886 0 : return nullptr;
1887 : }
1888 22 : if (!psOptions->osClipDstSQL.empty())
1889 : {
1890 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstsql");
1891 0 : return nullptr;
1892 : }
1893 22 : if (!psOptions->osClipDstLayer.empty())
1894 : {
1895 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstlayer");
1896 0 : return nullptr;
1897 : }
1898 22 : if (!psOptions->osClipDstWhere.empty())
1899 : {
1900 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstwhere");
1901 0 : return nullptr;
1902 : }
1903 22 : if (psOptions->bSplitListFields)
1904 : {
1905 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-splitlistfields");
1906 0 : return nullptr;
1907 : }
1908 22 : if (psOptions->nMaxSplitListSubFields >= 0)
1909 : {
1910 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-maxsubfields");
1911 0 : return nullptr;
1912 : }
1913 22 : if (psOptions->bExplodeCollections)
1914 : {
1915 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1916 : "-explodecollections");
1917 0 : return nullptr;
1918 : }
1919 22 : if (!psOptions->osZField.empty())
1920 : {
1921 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-zfield");
1922 0 : return nullptr;
1923 : }
1924 22 : if (psOptions->oGCPs.nGCPCount)
1925 : {
1926 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-gcp");
1927 0 : return nullptr;
1928 : }
1929 22 : if (!psOptions->aosFieldMap.empty())
1930 : {
1931 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-fieldmap");
1932 0 : return nullptr;
1933 : }
1934 22 : if (psOptions->bForceNullable)
1935 : {
1936 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-forceNullable");
1937 0 : return nullptr;
1938 : }
1939 22 : if (psOptions->bResolveDomains)
1940 : {
1941 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-forceNullable");
1942 0 : return nullptr;
1943 : }
1944 22 : if (psOptions->bEmptyStrAsNull)
1945 : {
1946 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-emptyStrAsNull");
1947 0 : return nullptr;
1948 : }
1949 22 : if (psOptions->bUnsetDefault)
1950 : {
1951 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetDefault");
1952 0 : return nullptr;
1953 : }
1954 22 : if (psOptions->bUnsetFid)
1955 : {
1956 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetFid");
1957 0 : return nullptr;
1958 : }
1959 22 : if (!psOptions->bCopyMD)
1960 : {
1961 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nomd");
1962 0 : return nullptr;
1963 : }
1964 22 : if (!psOptions->bNativeData)
1965 : {
1966 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-noNativeData");
1967 0 : return nullptr;
1968 : }
1969 22 : if (psOptions->nLimit >= 0)
1970 : {
1971 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-limit");
1972 0 : return nullptr;
1973 : }
1974 22 : if (!psOptions->aosMetadataOptions.empty())
1975 : {
1976 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-mo");
1977 0 : return nullptr;
1978 : }
1979 :
1980 22 : GDALDataset *poWrkSrcDS = poDS;
1981 44 : OGR2OGRSpatialReferenceHolder oOutputSRSHolder;
1982 :
1983 22 : if (!psOptions->osOutputSRSDef.empty())
1984 : {
1985 3 : oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());
1986 3 : oOutputSRSHolder.get()->SetAxisMappingStrategy(
1987 : OAMS_TRADITIONAL_GIS_ORDER);
1988 3 : if (oOutputSRSHolder.get()->SetFromUserInput(
1989 3 : psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)
1990 : {
1991 0 : CPLError(CE_Failure, CPLE_AppDefined,
1992 : "Failed to process SRS definition: %s",
1993 : psOptions->osOutputSRSDef.c_str());
1994 0 : return nullptr;
1995 : }
1996 3 : oOutputSRSHolder.get()->SetCoordinateEpoch(
1997 3 : psOptions->dfOutputCoordinateEpoch);
1998 :
1999 3 : poWrkSrcDS = GDALVectorTranslateWrappedDataset::New(
2000 3 : poDS, oOutputSRSHolder.get(), psOptions->bTransform);
2001 3 : if (poWrkSrcDS == nullptr)
2002 0 : return nullptr;
2003 : }
2004 :
2005 22 : if (!psOptions->osWHERE.empty())
2006 : {
2007 : // Hack for GMLAS driver
2008 0 : if (EQUAL(poDriver->GetDescription(), "GMLAS"))
2009 : {
2010 0 : if (psOptions->aosLayers.empty())
2011 : {
2012 0 : CPLError(CE_Failure, CPLE_NotSupported,
2013 : "-where not supported by this output driver "
2014 : "without explicit layer name(s)");
2015 0 : if (poWrkSrcDS != poDS)
2016 0 : delete poWrkSrcDS;
2017 0 : return nullptr;
2018 : }
2019 : else
2020 : {
2021 0 : for (const char *pszLayer : psOptions->aosLayers)
2022 : {
2023 0 : OGRLayer *poSrcLayer = poDS->GetLayerByName(pszLayer);
2024 0 : if (poSrcLayer != nullptr)
2025 : {
2026 0 : poSrcLayer->SetAttributeFilter(
2027 0 : psOptions->osWHERE.c_str());
2028 : }
2029 : }
2030 : }
2031 : }
2032 : else
2033 : {
2034 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-where");
2035 0 : if (poWrkSrcDS != poDS)
2036 0 : delete poWrkSrcDS;
2037 0 : return nullptr;
2038 : }
2039 : }
2040 :
2041 22 : if (psOptions->poSpatialFilter)
2042 : {
2043 0 : for (int i = 0; i < poWrkSrcDS->GetLayerCount(); ++i)
2044 : {
2045 0 : OGRLayer *poSrcLayer = poWrkSrcDS->GetLayer(i);
2046 0 : if (poSrcLayer &&
2047 0 : poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0 &&
2048 0 : (psOptions->aosLayers.empty() ||
2049 0 : psOptions->aosLayers.FindString(poSrcLayer->GetName()) >= 0))
2050 : {
2051 0 : if (psOptions->bGeomFieldSet)
2052 : {
2053 : const int iGeomField =
2054 0 : poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
2055 0 : psOptions->osGeomField.c_str());
2056 0 : if (iGeomField >= 0)
2057 0 : poSrcLayer->SetSpatialFilter(
2058 0 : iGeomField, psOptions->poSpatialFilter.get());
2059 : else
2060 0 : CPLError(CE_Warning, CPLE_AppDefined,
2061 : "Cannot find geometry field %s in layer %s. "
2062 : "Applying to first geometry field",
2063 : psOptions->osGeomField.c_str(),
2064 0 : poSrcLayer->GetName());
2065 : }
2066 : else
2067 : {
2068 0 : poSrcLayer->SetSpatialFilter(
2069 0 : psOptions->poSpatialFilter.get());
2070 : }
2071 : }
2072 : }
2073 : }
2074 :
2075 44 : CPLStringList aosDSCO(psOptions->aosDSCO);
2076 22 : if (!psOptions->aosLayers.empty())
2077 : {
2078 : // Hack for GMLAS driver
2079 0 : if (EQUAL(poDriver->GetDescription(), "GMLAS"))
2080 : {
2081 0 : CPLString osLayers;
2082 0 : for (const char *pszLayer : psOptions->aosLayers)
2083 : {
2084 0 : if (!osLayers.empty())
2085 0 : osLayers += ",";
2086 0 : osLayers += pszLayer;
2087 : }
2088 0 : aosDSCO.SetNameValue("LAYERS", osLayers);
2089 : }
2090 : else
2091 : {
2092 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
2093 : "Specifying layers");
2094 0 : if (poWrkSrcDS != poDS)
2095 0 : delete poWrkSrcDS;
2096 0 : return nullptr;
2097 : }
2098 : }
2099 :
2100 : // Hack for GMLAS driver (this speed up deletion by avoiding the GML
2101 : // driver to try parsing a pre-existing file). Could be potentially
2102 : // removed if the GML driver implemented fast dataset opening (ie
2103 : // without parsing) and GetFileList()
2104 22 : if (EQUAL(poDriver->GetDescription(), "GMLAS"))
2105 : {
2106 22 : GDALDriverH hIdentifyingDriver = GDALIdentifyDriver(pszDest, nullptr);
2107 23 : if (hIdentifyingDriver != nullptr &&
2108 1 : EQUAL(GDALGetDescription(hIdentifyingDriver), "GML"))
2109 : {
2110 0 : VSIUnlink(pszDest);
2111 0 : VSIUnlink(CPLResetExtension(pszDest, "gfs"));
2112 : }
2113 : }
2114 :
2115 : GDALDataset *poOut =
2116 22 : poDriver->CreateCopy(pszDest, poWrkSrcDS, FALSE, aosDSCO.List(),
2117 22 : psOptions->pfnProgress, psOptions->pProgressData);
2118 :
2119 22 : if (poWrkSrcDS != poDS)
2120 3 : delete poWrkSrcDS;
2121 :
2122 22 : return poOut;
2123 : }
2124 :
2125 : /************************************************************************/
2126 : /* GDALVectorTranslate() */
2127 : /************************************************************************/
2128 : /**
2129 : * Converts vector data between file formats.
2130 : *
2131 : * This is the equivalent of the <a href="/programs/ogr2ogr.html">ogr2ogr</a>
2132 : * utility.
2133 : *
2134 : * GDALVectorTranslateOptions* must be allocated and freed with
2135 : * GDALVectorTranslateOptionsNew() and GDALVectorTranslateOptionsFree()
2136 : * respectively. pszDest and hDstDS cannot be used at the same time.
2137 : *
2138 : * @param pszDest the destination dataset path or NULL.
2139 : * @param hDstDS the destination dataset or NULL.
2140 : * @param nSrcCount the number of input datasets (only 1 supported currently)
2141 : * @param pahSrcDS the list of input datasets.
2142 : * @param psOptionsIn the options struct returned by
2143 : * GDALVectorTranslateOptionsNew() or NULL.
2144 : * @param pbUsageError pointer to a integer output variable to store if any
2145 : * usage error has occurred, or NULL.
2146 : * @return the output dataset (new dataset that must be closed using
2147 : * GDALClose(), or hDstDS is not NULL) or NULL in case of error.
2148 : *
2149 : * @since GDAL 2.1
2150 : */
2151 :
2152 660 : GDALDatasetH GDALVectorTranslate(const char *pszDest, GDALDatasetH hDstDS,
2153 : int nSrcCount, GDALDatasetH *pahSrcDS,
2154 : const GDALVectorTranslateOptions *psOptionsIn,
2155 : int *pbUsageError)
2156 :
2157 : {
2158 660 : if (pszDest == nullptr && hDstDS == nullptr)
2159 : {
2160 0 : CPLError(CE_Failure, CPLE_AppDefined,
2161 : "pszDest == NULL && hDstDS == NULL");
2162 :
2163 0 : if (pbUsageError)
2164 0 : *pbUsageError = TRUE;
2165 0 : return nullptr;
2166 : }
2167 660 : if (nSrcCount != 1)
2168 : {
2169 0 : CPLError(CE_Failure, CPLE_AppDefined, "nSrcCount != 1");
2170 :
2171 0 : if (pbUsageError)
2172 0 : *pbUsageError = TRUE;
2173 0 : return nullptr;
2174 : }
2175 :
2176 660 : GDALDatasetH hSrcDS = pahSrcDS[0];
2177 660 : if (hSrcDS == nullptr)
2178 : {
2179 0 : CPLError(CE_Failure, CPLE_AppDefined, "hSrcDS == NULL");
2180 :
2181 0 : if (pbUsageError)
2182 0 : *pbUsageError = TRUE;
2183 0 : return nullptr;
2184 : }
2185 :
2186 : auto psOptions =
2187 : psOptionsIn ? std::make_unique<GDALVectorTranslateOptions>(*psOptionsIn)
2188 1320 : : std::make_unique<GDALVectorTranslateOptions>();
2189 :
2190 660 : bool bAppend = false;
2191 660 : bool bUpdate = false;
2192 660 : bool bOverwrite = false;
2193 :
2194 660 : if (psOptions->eAccessMode == ACCESS_UPDATE)
2195 : {
2196 5 : bUpdate = true;
2197 : }
2198 655 : else if (psOptions->eAccessMode == ACCESS_APPEND)
2199 : {
2200 32 : bAppend = true;
2201 32 : bUpdate = true;
2202 : }
2203 623 : else if (psOptions->eAccessMode == ACCESS_OVERWRITE)
2204 : {
2205 13 : bOverwrite = true;
2206 13 : bUpdate = true;
2207 : }
2208 610 : else if (hDstDS != nullptr)
2209 : {
2210 5 : bUpdate = true;
2211 : }
2212 :
2213 : const CPLString osDateLineOffset =
2214 1320 : CPLOPrintf("%g", psOptions->dfDateLineOffset);
2215 :
2216 660 : if (psOptions->bPreserveFID && psOptions->bExplodeCollections)
2217 : {
2218 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2219 : "cannot use -preserve_fid and -explodecollections at the same "
2220 : "time.");
2221 1 : if (pbUsageError)
2222 1 : *pbUsageError = TRUE;
2223 1 : return nullptr;
2224 : }
2225 :
2226 659 : if (!psOptions->aosFieldMap.empty() && !bAppend)
2227 : {
2228 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2229 : "if -fieldmap is specified, -append must also be specified");
2230 0 : if (pbUsageError)
2231 0 : *pbUsageError = TRUE;
2232 0 : return nullptr;
2233 : }
2234 :
2235 659 : if (!psOptions->aosFieldMap.empty() && psOptions->bAddMissingFields)
2236 : {
2237 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2238 : "if -addfields is specified, -fieldmap cannot be used.");
2239 0 : if (pbUsageError)
2240 0 : *pbUsageError = TRUE;
2241 0 : return nullptr;
2242 : }
2243 :
2244 659 : if (psOptions->bSelFieldsSet && bAppend && !psOptions->bAddMissingFields)
2245 : {
2246 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2247 : "if -append is specified, -select cannot be used "
2248 : "(use -fieldmap or -sql instead).");
2249 1 : if (pbUsageError)
2250 1 : *pbUsageError = TRUE;
2251 1 : return nullptr;
2252 : }
2253 :
2254 658 : if (!psOptions->aosFieldTypesToString.empty() &&
2255 0 : !psOptions->aosMapFieldType.empty())
2256 : {
2257 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2258 : "-fieldTypeToString and -mapFieldType are exclusive.");
2259 0 : if (pbUsageError)
2260 0 : *pbUsageError = TRUE;
2261 0 : return nullptr;
2262 : }
2263 :
2264 664 : if (!psOptions->osSourceSRSDef.empty() &&
2265 664 : psOptions->osOutputSRSDef.empty() && psOptions->osSpatSRSDef.empty())
2266 : {
2267 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2268 : "if -s_srs is specified, -t_srs and/or -spat_srs must also be "
2269 : "specified.");
2270 0 : if (pbUsageError)
2271 0 : *pbUsageError = TRUE;
2272 0 : return nullptr;
2273 : }
2274 :
2275 : /* -------------------------------------------------------------------- */
2276 : /* Parse spatial filter SRS if needed. */
2277 : /* -------------------------------------------------------------------- */
2278 658 : std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSpatSRS;
2279 658 : if (psOptions->poSpatialFilter && !psOptions->osSpatSRSDef.empty())
2280 : {
2281 4 : if (!psOptions->osSQLStatement.empty())
2282 : {
2283 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2284 : "-spat_srs not compatible with -sql.");
2285 0 : return nullptr;
2286 : }
2287 4 : OGREnvelope sEnvelope;
2288 4 : psOptions->poSpatialFilter->getEnvelope(&sEnvelope);
2289 4 : poSpatSRS.reset(new OGRSpatialReference());
2290 4 : poSpatSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2291 4 : if (poSpatSRS->SetFromUserInput(psOptions->osSpatSRSDef.c_str()) !=
2292 : OGRERR_NONE)
2293 : {
2294 0 : CPLError(CE_Failure, CPLE_AppDefined,
2295 : "Failed to process SRS definition: %s",
2296 0 : psOptions->osSpatSRSDef.c_str());
2297 0 : return nullptr;
2298 : }
2299 : }
2300 :
2301 658 : if (!psOptions->poClipSrc && !psOptions->osClipSrcDS.empty())
2302 : {
2303 8 : psOptions->poClipSrc =
2304 16 : LoadGeometry(psOptions->osClipSrcDS, psOptions->osClipSrcSQL,
2305 16 : psOptions->osClipSrcLayer, psOptions->osClipSrcWhere);
2306 8 : if (psOptions->poClipSrc == nullptr)
2307 : {
2308 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2309 : "cannot load source clip geometry");
2310 1 : return nullptr;
2311 : }
2312 : }
2313 651 : else if (psOptions->bClipSrc && !psOptions->poClipSrc &&
2314 1 : psOptions->poSpatialFilter)
2315 : {
2316 1 : psOptions->poClipSrc.reset(psOptions->poSpatialFilter->clone());
2317 1 : if (poSpatSRS)
2318 : {
2319 0 : psOptions->poClipSrc->assignSpatialReference(poSpatSRS.get());
2320 : }
2321 : }
2322 649 : else if (psOptions->bClipSrc && !psOptions->poClipSrc)
2323 : {
2324 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2325 : "-clipsrc must be used with -spat option or a\n"
2326 : "bounding box, WKT string or datasource must be specified");
2327 0 : if (pbUsageError)
2328 0 : *pbUsageError = TRUE;
2329 0 : return nullptr;
2330 : }
2331 :
2332 657 : if (!psOptions->osClipDstDS.empty())
2333 : {
2334 6 : psOptions->poClipDst =
2335 12 : LoadGeometry(psOptions->osClipDstDS, psOptions->osClipDstSQL,
2336 12 : psOptions->osClipDstLayer, psOptions->osClipDstWhere);
2337 6 : if (psOptions->poClipDst == nullptr)
2338 : {
2339 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2340 : "cannot load dest clip geometry");
2341 1 : return nullptr;
2342 : }
2343 : }
2344 :
2345 656 : GDALDataset *poDS = GDALDataset::FromHandle(hSrcDS);
2346 656 : GDALDataset *poODS = nullptr;
2347 656 : GDALDriver *poDriver = nullptr;
2348 1312 : CPLString osDestFilename;
2349 :
2350 656 : if (hDstDS)
2351 : {
2352 14 : poODS = GDALDataset::FromHandle(hDstDS);
2353 14 : osDestFilename = poODS->GetDescription();
2354 : }
2355 : else
2356 : {
2357 642 : osDestFilename = pszDest;
2358 : }
2359 :
2360 : /* Various tests to avoid overwriting the source layer(s) */
2361 : /* or to avoid appending a layer to itself */
2362 54 : if (bUpdate && strcmp(osDestFilename, poDS->GetDescription()) == 0 &&
2363 710 : !EQUAL(poDS->GetDriverName(), "Memory") && (bOverwrite || bAppend))
2364 : {
2365 1 : bool bError = false;
2366 1 : if (psOptions->osNewLayerName.empty())
2367 0 : bError = true;
2368 1 : else if (psOptions->aosLayers.size() == 1)
2369 1 : bError = strcmp(psOptions->osNewLayerName.c_str(),
2370 1 : psOptions->aosLayers[0]) == 0;
2371 0 : else if (psOptions->osSQLStatement.empty())
2372 0 : bError = true;
2373 1 : if (bError)
2374 : {
2375 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2376 : "-nln name must be specified combined with "
2377 : "a single source layer name,\nor a -sql statement, and "
2378 : "name must be different from an existing layer.");
2379 0 : return nullptr;
2380 : }
2381 : }
2382 750 : else if (!bUpdate && strcmp(osDestFilename, poDS->GetDescription()) == 0 &&
2383 48 : (psOptions->osFormat.empty() ||
2384 47 : !EQUAL(psOptions->osFormat.c_str(), "Memory")))
2385 : {
2386 1 : CPLError(CE_Failure, CPLE_AppDefined,
2387 : "Source and destination datasets must be different "
2388 : "in non-update mode.");
2389 1 : return nullptr;
2390 : }
2391 :
2392 : /* -------------------------------------------------------------------- */
2393 : /* Try opening the output datasource as an existing, writable */
2394 : /* -------------------------------------------------------------------- */
2395 1310 : std::vector<std::string> aoDrivers;
2396 655 : if (poODS == nullptr && psOptions->osFormat.empty())
2397 : {
2398 277 : aoDrivers = GetOutputDriversFor(pszDest, GDAL_OF_VECTOR);
2399 277 : if (!bUpdate && aoDrivers.size() == 1)
2400 : {
2401 235 : GDALDriverH hDriver = GDALGetDriverByName(aoDrivers[0].c_str());
2402 235 : const char *pszPrefix = GDALGetMetadataItem(
2403 : hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);
2404 235 : if (pszPrefix && STARTS_WITH_CI(pszDest, pszPrefix))
2405 : {
2406 2 : bUpdate = true;
2407 : }
2408 : }
2409 : }
2410 :
2411 655 : if (bUpdate && poODS == nullptr)
2412 : {
2413 42 : poODS = GDALDataset::Open(
2414 : osDestFilename, GDAL_OF_UPDATE | GDAL_OF_VECTOR, nullptr,
2415 42 : psOptions->aosDestOpenOptions.List(), nullptr);
2416 :
2417 42 : if (poODS == nullptr)
2418 : {
2419 2 : if (bOverwrite || bAppend)
2420 : {
2421 2 : poODS = GDALDataset::Open(
2422 : osDestFilename, GDAL_OF_VECTOR, nullptr,
2423 2 : psOptions->aosDestOpenOptions.List(), nullptr);
2424 2 : if (poODS == nullptr)
2425 : {
2426 : /* OK the datasource doesn't exist at all */
2427 2 : bUpdate = false;
2428 : }
2429 : else
2430 : {
2431 0 : poDriver = poODS->GetDriver();
2432 0 : GDALClose(poODS);
2433 0 : poODS = nullptr;
2434 : }
2435 : }
2436 :
2437 2 : if (bUpdate)
2438 : {
2439 0 : CPLError(CE_Failure, CPLE_AppDefined,
2440 : "Unable to open existing output datasource `%s'.",
2441 : osDestFilename.c_str());
2442 0 : return nullptr;
2443 : }
2444 : }
2445 40 : else if (psOptions->aosDSCO.size() > 0)
2446 : {
2447 0 : CPLError(CE_Warning, CPLE_AppDefined,
2448 : "Datasource creation options ignored since an existing "
2449 : "datasource\n"
2450 : " being updated.");
2451 : }
2452 : }
2453 :
2454 655 : if (poODS)
2455 54 : poDriver = poODS->GetDriver();
2456 :
2457 : /* -------------------------------------------------------------------- */
2458 : /* Find the output driver. */
2459 : /* -------------------------------------------------------------------- */
2460 655 : bool bNewDataSource = false;
2461 655 : if (!bUpdate)
2462 : {
2463 601 : GDALDriverManager *poDM = GetGDALDriverManager();
2464 :
2465 601 : if (psOptions->osFormat.empty())
2466 : {
2467 247 : if (aoDrivers.empty())
2468 : {
2469 11 : if (EQUAL(CPLGetExtension(pszDest), ""))
2470 : {
2471 10 : psOptions->osFormat = "ESRI Shapefile";
2472 : }
2473 : else
2474 : {
2475 1 : CPLError(CE_Failure, CPLE_AppDefined,
2476 : "Cannot guess driver for %s", pszDest);
2477 28 : return nullptr;
2478 : }
2479 : }
2480 : else
2481 : {
2482 236 : if (aoDrivers.size() > 1)
2483 : {
2484 1 : CPLError(CE_Warning, CPLE_AppDefined,
2485 : "Several drivers matching %s extension. Using %s",
2486 1 : CPLGetExtension(pszDest), aoDrivers[0].c_str());
2487 : }
2488 236 : psOptions->osFormat = aoDrivers[0];
2489 : }
2490 246 : CPLDebug("GDAL", "Using %s driver", psOptions->osFormat.c_str());
2491 : }
2492 :
2493 600 : CPLString osOGRCompatFormat(psOptions->osFormat);
2494 : // Special processing for non-unified drivers that have the same name
2495 : // as GDAL and OGR drivers. GMT should become OGR_GMT.
2496 : // Other candidates could be VRT, SDTS and PDS, but they don't
2497 : // have write capabilities. But do the substitution to get a sensible
2498 : // error message
2499 600 : if (EQUAL(osOGRCompatFormat, "GMT") ||
2500 599 : EQUAL(osOGRCompatFormat, "VRT") ||
2501 1199 : EQUAL(osOGRCompatFormat, "SDTS") || EQUAL(osOGRCompatFormat, "PDS"))
2502 : {
2503 1 : osOGRCompatFormat = "OGR_" + osOGRCompatFormat;
2504 : }
2505 600 : poDriver = poDM->GetDriverByName(osOGRCompatFormat);
2506 600 : if (poDriver == nullptr)
2507 : {
2508 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to find driver `%s'.",
2509 0 : psOptions->osFormat.c_str());
2510 0 : return nullptr;
2511 : }
2512 :
2513 600 : char **papszDriverMD = poDriver->GetMetadata();
2514 600 : if (!CPLTestBool(
2515 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")))
2516 : {
2517 0 : CPLError(CE_Failure, CPLE_AppDefined,
2518 : "%s driver has no vector capabilities.",
2519 0 : psOptions->osFormat.c_str());
2520 0 : return nullptr;
2521 : }
2522 :
2523 600 : if (poDriver->CanVectorTranslateFrom(
2524 600 : pszDest, poDS, psOptions->aosArguments.List(), nullptr))
2525 : {
2526 2 : return poDriver->VectorTranslateFrom(
2527 2 : pszDest, poDS, psOptions->aosArguments.List(),
2528 4 : psOptions->pfnProgress, psOptions->pProgressData);
2529 : }
2530 :
2531 598 : if (!CPLTestBool(
2532 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
2533 : {
2534 22 : if (CPLTestBool(CSLFetchNameValueDef(
2535 : papszDriverMD, GDAL_DCAP_CREATECOPY, "FALSE")))
2536 : {
2537 22 : poODS = GDALVectorTranslateCreateCopy(poDriver, pszDest, poDS,
2538 22 : psOptions.get());
2539 22 : return poODS;
2540 : }
2541 :
2542 0 : CPLError(CE_Failure, CPLE_AppDefined,
2543 : "%s driver does not support data source creation.",
2544 0 : psOptions->osFormat.c_str());
2545 0 : return nullptr;
2546 : }
2547 :
2548 576 : if (!psOptions->aosDestOpenOptions.empty())
2549 : {
2550 0 : CPLError(CE_Warning, CPLE_AppDefined,
2551 : "-doo ignored when creating the output datasource.");
2552 : }
2553 :
2554 : /* --------------------------------------------------------------------
2555 : */
2556 : /* Special case to improve user experience when translating */
2557 : /* a datasource with multiple layers into a shapefile. If the */
2558 : /* user gives a target datasource with .shp and it does not exist,
2559 : */
2560 : /* the shapefile driver will try to create a file, but this is not
2561 : */
2562 : /* appropriate because here we have several layers, so create */
2563 : /* a directory instead. */
2564 : /* --------------------------------------------------------------------
2565 : */
2566 : VSIStatBufL sStat;
2567 646 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
2568 70 : psOptions->osSQLStatement.empty() &&
2569 67 : (psOptions->aosLayers.size() > 1 ||
2570 70 : (psOptions->aosLayers.empty() && poDS->GetLayerCount() > 1)) &&
2571 6 : psOptions->osNewLayerName.empty() &&
2572 647 : EQUAL(CPLGetExtension(osDestFilename), "SHP") &&
2573 1 : VSIStatL(osDestFilename, &sStat) != 0)
2574 : {
2575 1 : if (VSIMkdir(osDestFilename, 0755) != 0)
2576 : {
2577 0 : CPLError(CE_Failure, CPLE_AppDefined,
2578 : "Failed to create directory %s\n"
2579 : "for shapefile datastore.",
2580 : osDestFilename.c_str());
2581 0 : return nullptr;
2582 : }
2583 : }
2584 :
2585 576 : CPLStringList aosDSCO(psOptions->aosDSCO);
2586 :
2587 576 : if (!aosDSCO.FetchNameValue("SINGLE_LAYER"))
2588 : {
2589 : // Informs the target driver (e.g. JSONFG) if a single layer
2590 : // will be created
2591 : const char *pszCOList =
2592 576 : poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
2593 577 : if (pszCOList && strstr(pszCOList, "SINGLE_LAYER") &&
2594 1 : (!psOptions->osSQLStatement.empty() ||
2595 1 : psOptions->aosLayers.size() == 1 ||
2596 1 : (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1)))
2597 : {
2598 1 : aosDSCO.SetNameValue("SINGLE_LAYER", "YES");
2599 : }
2600 : }
2601 :
2602 : /* --------------------------------------------------------------------
2603 : */
2604 : /* Create the output data source. */
2605 : /* --------------------------------------------------------------------
2606 : */
2607 576 : poODS = poDriver->Create(osDestFilename, 0, 0, 0, GDT_Unknown,
2608 576 : aosDSCO.List());
2609 576 : if (poODS == nullptr)
2610 : {
2611 6 : CPLError(CE_Failure, CPLE_AppDefined,
2612 : "%s driver failed to create %s",
2613 3 : psOptions->osFormat.c_str(), osDestFilename.c_str());
2614 3 : return nullptr;
2615 : }
2616 573 : bNewDataSource = true;
2617 :
2618 573 : if (psOptions->bCopyMD)
2619 : {
2620 1138 : const CPLStringList aosDomains(poDS->GetMetadataDomainList());
2621 599 : for (const char *pszMD : aosDomains)
2622 : {
2623 30 : if (char **papszMD = poDS->GetMetadata(pszMD))
2624 7 : poODS->SetMetadata(papszMD, pszMD);
2625 : }
2626 : }
2627 2 : for (const auto &[pszKey, pszValue] :
2628 575 : cpl::IterateNameValue(psOptions->aosMetadataOptions))
2629 : {
2630 1 : poODS->SetMetadataItem(pszKey, pszValue);
2631 : }
2632 :
2633 : // When writing to GeoJSON and using -nln, set the @NAME layer
2634 : // creation option to avoid the GeoJSON driver to potentially reuse
2635 : // the source feature collection name if the input is also GeoJSON.
2636 584 : if (!psOptions->osNewLayerName.empty() &&
2637 11 : EQUAL(psOptions->osFormat.c_str(), "GeoJSON"))
2638 : {
2639 1 : psOptions->aosLCO.SetNameValue("@NAME",
2640 1 : psOptions->osNewLayerName.c_str());
2641 : }
2642 : }
2643 :
2644 : // Some syntaxic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=....
2645 : // source [srclayer] -lco OVERWRITE=YES" work like "ogr2ogr -overwrite
2646 : // PG:dbname=.... source [srclayer]" The former syntax used to work at
2647 : // GDAL 1.1.8 time when it was documented in the PG driver, but was broken
2648 : // starting with GDAL 1.3.2
2649 : // (https://github.com/OSGeo/gdal/commit/29c108a6c9f651dfebae6d1313ba0e707a77c1aa)
2650 : // This could probably be generalized to other drivers that support the
2651 : // OVERWRITE layer creation option, but we'd need to make sure that they
2652 : // just do a DeleteLayer() call. The CARTO driver is an exception regarding
2653 : // that.
2654 641 : if (EQUAL(poODS->GetDriver()->GetDescription(), "PostgreSQL") &&
2655 14 : CPLTestBool(psOptions->aosLCO.FetchNameValueDef("OVERWRITE", "NO")))
2656 : {
2657 0 : if (bAppend)
2658 : {
2659 0 : CPLError(CE_Failure, CPLE_AppDefined,
2660 : "-append and -lco OVERWRITE=YES are mutually exclusive");
2661 0 : if (hDstDS == nullptr)
2662 0 : GDALClose(poODS);
2663 0 : return nullptr;
2664 : }
2665 0 : bOverwrite = true;
2666 : }
2667 :
2668 : /* -------------------------------------------------------------------- */
2669 : /* For random reading */
2670 : /* -------------------------------------------------------------------- */
2671 : const bool bRandomLayerReading =
2672 627 : CPL_TO_BOOL(poDS->TestCapability(ODsCRandomLayerRead));
2673 17 : if (bRandomLayerReading && !poODS->TestCapability(ODsCRandomLayerWrite) &&
2674 644 : psOptions->aosLayers.size() != 1 && psOptions->osSQLStatement.empty() &&
2675 0 : !psOptions->bQuiet)
2676 : {
2677 0 : CPLError(CE_Warning, CPLE_AppDefined,
2678 : "Input datasource uses random layer reading, but "
2679 : "output datasource does not support random layer writing");
2680 : }
2681 :
2682 627 : if (psOptions->nLayerTransaction < 0)
2683 : {
2684 626 : if (bRandomLayerReading)
2685 17 : psOptions->nLayerTransaction = FALSE;
2686 : else
2687 609 : psOptions->nLayerTransaction =
2688 609 : !poODS->TestCapability(ODsCTransactions);
2689 : }
2690 1 : else if (psOptions->nLayerTransaction && bRandomLayerReading)
2691 : {
2692 0 : psOptions->nLayerTransaction = false;
2693 : }
2694 :
2695 : /* -------------------------------------------------------------------- */
2696 : /* Parse the output SRS definition if possible. */
2697 : /* -------------------------------------------------------------------- */
2698 1254 : OGR2OGRSpatialReferenceHolder oOutputSRSHolder;
2699 627 : if (!psOptions->osOutputSRSDef.empty())
2700 : {
2701 131 : oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());
2702 131 : oOutputSRSHolder.get()->SetAxisMappingStrategy(
2703 : OAMS_TRADITIONAL_GIS_ORDER);
2704 262 : if (oOutputSRSHolder.get()->SetFromUserInput(
2705 262 : psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)
2706 : {
2707 0 : CPLError(CE_Failure, CPLE_AppDefined,
2708 : "Failed to process SRS definition: %s",
2709 0 : psOptions->osOutputSRSDef.c_str());
2710 0 : if (hDstDS == nullptr)
2711 0 : GDALClose(poODS);
2712 0 : return nullptr;
2713 : }
2714 262 : oOutputSRSHolder.get()->SetCoordinateEpoch(
2715 131 : psOptions->dfOutputCoordinateEpoch);
2716 : }
2717 :
2718 : /* -------------------------------------------------------------------- */
2719 : /* Parse the source SRS definition if possible. */
2720 : /* -------------------------------------------------------------------- */
2721 1254 : OGRSpatialReference oSourceSRS;
2722 627 : OGRSpatialReference *poSourceSRS = nullptr;
2723 627 : if (!psOptions->osSourceSRSDef.empty())
2724 : {
2725 6 : oSourceSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2726 6 : if (oSourceSRS.SetFromUserInput(psOptions->osSourceSRSDef.c_str()) !=
2727 : OGRERR_NONE)
2728 : {
2729 0 : CPLError(CE_Failure, CPLE_AppDefined,
2730 : "Failed to process SRS definition: %s",
2731 0 : psOptions->osSourceSRSDef.c_str());
2732 0 : if (hDstDS == nullptr)
2733 0 : GDALClose(poODS);
2734 0 : return nullptr;
2735 : }
2736 6 : oSourceSRS.SetCoordinateEpoch(psOptions->dfSourceCoordinateEpoch);
2737 6 : poSourceSRS = &oSourceSRS;
2738 : }
2739 :
2740 : /* -------------------------------------------------------------------- */
2741 : /* Create a transformation object from the source to */
2742 : /* destination coordinate system. */
2743 : /* -------------------------------------------------------------------- */
2744 627 : GCPCoordTransformation *poGCPCoordTrans = nullptr;
2745 627 : if (psOptions->oGCPs.nGCPCount > 0)
2746 : {
2747 5 : poGCPCoordTrans = new GCPCoordTransformation(
2748 5 : psOptions->oGCPs.nGCPCount, psOptions->oGCPs.pasGCPs,
2749 5 : psOptions->nTransformOrder,
2750 5 : poSourceSRS ? poSourceSRS : oOutputSRSHolder.get());
2751 5 : if (!(poGCPCoordTrans->IsValid()))
2752 : {
2753 0 : delete poGCPCoordTrans;
2754 0 : poGCPCoordTrans = nullptr;
2755 : }
2756 : }
2757 :
2758 : /* -------------------------------------------------------------------- */
2759 : /* Create layer setup and transformer objects. */
2760 : /* -------------------------------------------------------------------- */
2761 627 : SetupTargetLayer oSetup;
2762 627 : oSetup.m_poSrcDS = poDS;
2763 627 : oSetup.m_poDstDS = poODS;
2764 627 : oSetup.m_papszLCO = psOptions->aosLCO.List();
2765 627 : oSetup.m_poOutputSRS = oOutputSRSHolder.get();
2766 627 : oSetup.m_bTransform = psOptions->bTransform;
2767 627 : oSetup.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
2768 627 : oSetup.m_bSelFieldsSet = psOptions->bSelFieldsSet;
2769 627 : oSetup.m_papszSelFields = psOptions->aosSelFields.List();
2770 627 : oSetup.m_bAppend = bAppend;
2771 627 : oSetup.m_bAddMissingFields = psOptions->bAddMissingFields;
2772 627 : oSetup.m_eGType = psOptions->eGType;
2773 627 : oSetup.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
2774 627 : oSetup.m_nCoordDim = psOptions->nCoordDim;
2775 627 : oSetup.m_bOverwrite = bOverwrite;
2776 627 : oSetup.m_papszFieldTypesToString = psOptions->aosFieldTypesToString.List();
2777 627 : oSetup.m_papszMapFieldType = psOptions->aosMapFieldType.List();
2778 627 : oSetup.m_bUnsetFieldWidth = psOptions->bUnsetFieldWidth;
2779 627 : oSetup.m_bExplodeCollections = psOptions->bExplodeCollections;
2780 627 : oSetup.m_pszZField =
2781 627 : psOptions->osZField.empty() ? nullptr : psOptions->osZField.c_str();
2782 627 : oSetup.m_papszFieldMap = psOptions->aosFieldMap.List();
2783 627 : oSetup.m_pszWHERE =
2784 627 : psOptions->osWHERE.empty() ? nullptr : psOptions->osWHERE.c_str();
2785 627 : oSetup.m_bExactFieldNameMatch = psOptions->bExactFieldNameMatch;
2786 627 : oSetup.m_bQuiet = psOptions->bQuiet;
2787 627 : oSetup.m_bForceNullable = psOptions->bForceNullable;
2788 627 : oSetup.m_bResolveDomains = psOptions->bResolveDomains;
2789 627 : oSetup.m_bUnsetDefault = psOptions->bUnsetDefault;
2790 627 : oSetup.m_bUnsetFid = psOptions->bUnsetFid;
2791 627 : oSetup.m_bPreserveFID = psOptions->bPreserveFID;
2792 627 : oSetup.m_bCopyMD = psOptions->bCopyMD;
2793 627 : oSetup.m_bNativeData = psOptions->bNativeData;
2794 627 : oSetup.m_bNewDataSource = bNewDataSource;
2795 627 : oSetup.m_pszCTPipeline = psOptions->osCTPipeline.empty()
2796 627 : ? nullptr
2797 3 : : psOptions->osCTPipeline.c_str();
2798 :
2799 1254 : LayerTranslator oTranslator;
2800 627 : oTranslator.m_poSrcDS = poDS;
2801 627 : oTranslator.m_poODS = poODS;
2802 627 : oTranslator.m_bTransform = psOptions->bTransform;
2803 627 : oTranslator.m_bWrapDateline = psOptions->bWrapDateline;
2804 627 : oTranslator.m_osDateLineOffset = osDateLineOffset;
2805 627 : oTranslator.m_poOutputSRS = oOutputSRSHolder.get();
2806 627 : oTranslator.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
2807 627 : oTranslator.m_poUserSourceSRS = poSourceSRS;
2808 627 : oTranslator.m_poGCPCoordTrans = poGCPCoordTrans;
2809 627 : oTranslator.m_eGType = psOptions->eGType;
2810 627 : oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
2811 627 : oTranslator.m_bMakeValid = psOptions->bMakeValid;
2812 627 : oTranslator.m_nCoordDim = psOptions->nCoordDim;
2813 627 : oTranslator.m_eGeomOp = psOptions->eGeomOp;
2814 627 : oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam;
2815 : // Do not emit warning if the user specified directly the clip source geom
2816 627 : if (psOptions->osClipSrcDS.empty())
2817 620 : oTranslator.m_bWarnedClipSrcSRS = true;
2818 627 : oTranslator.m_poClipSrcOri = psOptions->poClipSrc.get();
2819 : // Do not emit warning if the user specified directly the clip dest geom
2820 627 : if (psOptions->osClipDstDS.empty())
2821 622 : oTranslator.m_bWarnedClipDstSRS = true;
2822 627 : oTranslator.m_poClipDstOri = psOptions->poClipDst.get();
2823 627 : oTranslator.m_bExplodeCollections = psOptions->bExplodeCollections;
2824 627 : oTranslator.m_bNativeData = psOptions->bNativeData;
2825 627 : oTranslator.m_nLimit = psOptions->nLimit;
2826 :
2827 627 : if (psOptions->nGroupTransactions)
2828 : {
2829 626 : if (!psOptions->nLayerTransaction)
2830 102 : poODS->StartTransaction(psOptions->bForceTransaction);
2831 : }
2832 :
2833 627 : GIntBig nTotalEventsDone = 0;
2834 :
2835 : /* -------------------------------------------------------------------- */
2836 : /* Special case for -sql clause. No source layers required. */
2837 : /* -------------------------------------------------------------------- */
2838 627 : int nRetCode = 0;
2839 :
2840 627 : if (!psOptions->osSQLStatement.empty())
2841 : {
2842 : /* Special case: if output=input, then we must likely destroy the */
2843 : /* old table before to avoid transaction issues. */
2844 11 : if (poDS == poODS && !psOptions->osNewLayerName.empty() && bOverwrite)
2845 0 : GetLayerAndOverwriteIfNecessary(
2846 0 : poODS, psOptions->osNewLayerName.c_str(), bOverwrite, nullptr,
2847 : nullptr, nullptr);
2848 :
2849 11 : if (!psOptions->osWHERE.empty())
2850 0 : CPLError(CE_Warning, CPLE_AppDefined,
2851 : "-where clause ignored in combination with -sql.");
2852 11 : if (psOptions->aosLayers.size() > 0)
2853 0 : CPLError(CE_Warning, CPLE_AppDefined,
2854 : "layer names ignored in combination with -sql.");
2855 :
2856 22 : OGRLayer *poResultSet = poDS->ExecuteSQL(
2857 11 : psOptions->osSQLStatement.c_str(),
2858 11 : (!psOptions->bGeomFieldSet) ? psOptions->poSpatialFilter.get()
2859 : : nullptr,
2860 11 : psOptions->osDialect.empty() ? nullptr
2861 12 : : psOptions->osDialect.c_str());
2862 :
2863 11 : if (poResultSet != nullptr)
2864 : {
2865 11 : if (psOptions->poSpatialFilter && psOptions->bGeomFieldSet)
2866 : {
2867 0 : int iGeomField = poResultSet->GetLayerDefn()->GetGeomFieldIndex(
2868 0 : psOptions->osGeomField.c_str());
2869 0 : if (iGeomField >= 0)
2870 0 : poResultSet->SetSpatialFilter(
2871 0 : iGeomField, psOptions->poSpatialFilter.get());
2872 : else
2873 0 : CPLError(CE_Warning, CPLE_AppDefined,
2874 : "Cannot find geometry field %s.",
2875 0 : psOptions->osGeomField.c_str());
2876 : }
2877 :
2878 11 : GIntBig nCountLayerFeatures = 0;
2879 11 : GDALProgressFunc pfnProgress = nullptr;
2880 11 : void *pProgressArg = nullptr;
2881 11 : if (psOptions->bDisplayProgress)
2882 : {
2883 1 : if (bRandomLayerReading)
2884 : {
2885 1 : pfnProgress = psOptions->pfnProgress;
2886 1 : pProgressArg = psOptions->pProgressData;
2887 : }
2888 0 : else if (!poResultSet->TestCapability(OLCFastFeatureCount))
2889 : {
2890 0 : CPLError(CE_Warning, CPLE_AppDefined,
2891 : "Progress turned off as fast feature count is not "
2892 : "available.");
2893 0 : psOptions->bDisplayProgress = false;
2894 : }
2895 : else
2896 : {
2897 0 : nCountLayerFeatures = poResultSet->GetFeatureCount();
2898 0 : pfnProgress = psOptions->pfnProgress;
2899 0 : pProgressArg = psOptions->pProgressData;
2900 : }
2901 : }
2902 :
2903 11 : OGRLayer *poPassedLayer = poResultSet;
2904 11 : if (psOptions->bSplitListFields)
2905 : {
2906 : auto poLayer = new OGRSplitListFieldLayer(
2907 0 : poPassedLayer, psOptions->nMaxSplitListSubFields);
2908 0 : poPassedLayer = poLayer;
2909 0 : int nRet = poLayer->BuildLayerDefn(nullptr, nullptr);
2910 0 : if (!nRet)
2911 : {
2912 0 : delete poPassedLayer;
2913 0 : poPassedLayer = poResultSet;
2914 : }
2915 : }
2916 :
2917 : /* --------------------------------------------------------------------
2918 : */
2919 : /* Special case to improve user experience when translating
2920 : * into */
2921 : /* single file shapefile and source has only one layer, and
2922 : * that */
2923 : /* the layer name isn't specified */
2924 : /* --------------------------------------------------------------------
2925 : */
2926 : VSIStatBufL sStat;
2927 14 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
2928 3 : psOptions->osNewLayerName.empty() &&
2929 3 : VSIStatL(osDestFilename, &sStat) == 0 &&
2930 14 : VSI_ISREG(sStat.st_mode) &&
2931 0 : (EQUAL(CPLGetExtension(osDestFilename), "shp") ||
2932 0 : EQUAL(CPLGetExtension(osDestFilename), "shz") ||
2933 0 : EQUAL(CPLGetExtension(osDestFilename), "dbf")))
2934 : {
2935 0 : psOptions->osNewLayerName = CPLGetBasename(osDestFilename);
2936 : }
2937 :
2938 : auto psInfo = oSetup.Setup(poPassedLayer,
2939 11 : psOptions->osNewLayerName.empty()
2940 : ? nullptr
2941 1 : : psOptions->osNewLayerName.c_str(),
2942 34 : psOptions.get(), nTotalEventsDone);
2943 :
2944 11 : poPassedLayer->ResetReading();
2945 :
2946 22 : if (psInfo == nullptr ||
2947 11 : !oTranslator.Translate(nullptr, psInfo.get(),
2948 : nCountLayerFeatures, nullptr,
2949 : nTotalEventsDone, pfnProgress,
2950 11 : pProgressArg, psOptions.get()))
2951 : {
2952 0 : CPLError(CE_Failure, CPLE_AppDefined,
2953 : "Terminating translation prematurely after failed\n"
2954 : "translation from sql statement.");
2955 :
2956 0 : nRetCode = 1;
2957 : }
2958 :
2959 11 : if (poPassedLayer != poResultSet)
2960 0 : delete poPassedLayer;
2961 :
2962 11 : poDS->ReleaseResultSet(poResultSet);
2963 : }
2964 : else
2965 : {
2966 0 : if (CPLGetLastErrorNo() != 0)
2967 0 : nRetCode = 1;
2968 : }
2969 : }
2970 :
2971 : /* -------------------------------------------------------------------- */
2972 : /* Special case for layer interleaving mode. */
2973 : /* -------------------------------------------------------------------- */
2974 616 : else if (bRandomLayerReading)
2975 : {
2976 16 : if (psOptions->bSplitListFields)
2977 : {
2978 0 : CPLError(CE_Failure, CPLE_AppDefined,
2979 : "-splitlistfields not supported in this mode");
2980 0 : if (hDstDS == nullptr)
2981 0 : GDALClose(poODS);
2982 0 : delete poGCPCoordTrans;
2983 0 : return nullptr;
2984 : }
2985 :
2986 : // Make sure to probe all layers in case some are by default invisible
2987 28 : for (const char *pszLayer : psOptions->aosLayers)
2988 : {
2989 12 : OGRLayer *poLayer = poDS->GetLayerByName(pszLayer);
2990 :
2991 12 : if (poLayer == nullptr)
2992 : {
2993 0 : CPLError(CE_Failure, CPLE_AppDefined,
2994 : "Couldn't fetch requested layer %s!", pszLayer);
2995 0 : if (hDstDS == nullptr)
2996 0 : GDALClose(poODS);
2997 0 : delete poGCPCoordTrans;
2998 0 : return nullptr;
2999 : }
3000 : }
3001 :
3002 16 : const int nSrcLayerCount = poDS->GetLayerCount();
3003 16 : std::vector<AssociatedLayers> pasAssocLayers(nSrcLayerCount);
3004 :
3005 : /* --------------------------------------------------------------------
3006 : */
3007 : /* Special case to improve user experience when translating into */
3008 : /* single file shapefile and source has only one layer, and that */
3009 : /* the layer name isn't specified */
3010 : /* --------------------------------------------------------------------
3011 : */
3012 : VSIStatBufL sStat;
3013 16 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3014 5 : (psOptions->aosLayers.size() == 1 || nSrcLayerCount == 1) &&
3015 0 : psOptions->osNewLayerName.empty() &&
3016 21 : VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3017 0 : (EQUAL(CPLGetExtension(osDestFilename), "shp") ||
3018 0 : EQUAL(CPLGetExtension(osDestFilename), "shz") ||
3019 0 : EQUAL(CPLGetExtension(osDestFilename), "dbf")))
3020 : {
3021 0 : psOptions->osNewLayerName = CPLGetBasename(osDestFilename);
3022 : }
3023 :
3024 16 : GDALProgressFunc pfnProgress = nullptr;
3025 16 : void *pProgressArg = nullptr;
3026 16 : if (!psOptions->bQuiet)
3027 : {
3028 16 : pfnProgress = psOptions->pfnProgress;
3029 16 : pProgressArg = psOptions->pProgressData;
3030 : }
3031 :
3032 : /* --------------------------------------------------------------------
3033 : */
3034 : /* If no target layer specified, use all source layers. */
3035 : /* --------------------------------------------------------------------
3036 : */
3037 16 : if (psOptions->aosLayers.empty())
3038 : {
3039 148 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3040 : {
3041 135 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3042 :
3043 135 : if (poLayer == nullptr)
3044 : {
3045 0 : CPLError(CE_Failure, CPLE_AppDefined,
3046 : "Couldn't fetch advertised layer %d!", iLayer);
3047 0 : if (hDstDS == nullptr)
3048 0 : GDALClose(poODS);
3049 0 : delete poGCPCoordTrans;
3050 0 : return nullptr;
3051 : }
3052 :
3053 135 : psOptions->aosLayers.AddString(poLayer->GetName());
3054 : }
3055 : }
3056 : else
3057 : {
3058 3 : const bool bSrcIsOSM = (strcmp(poDS->GetDriverName(), "OSM") == 0);
3059 3 : if (bSrcIsOSM)
3060 : {
3061 6 : CPLString osInterestLayers = "SET interest_layers =";
3062 15 : for (int iLayer = 0; iLayer < psOptions->aosLayers.size();
3063 : iLayer++)
3064 : {
3065 12 : if (iLayer != 0)
3066 9 : osInterestLayers += ",";
3067 12 : osInterestLayers += psOptions->aosLayers[iLayer];
3068 : }
3069 :
3070 3 : poDS->ExecuteSQL(osInterestLayers.c_str(), nullptr, nullptr);
3071 : }
3072 : }
3073 :
3074 : /* --------------------------------------------------------------------
3075 : */
3076 : /* First pass to set filters. */
3077 : /* --------------------------------------------------------------------
3078 : */
3079 16 : std::map<OGRLayer *, int> oMapLayerToIdx;
3080 :
3081 166 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3082 : {
3083 150 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3084 150 : if (poLayer == nullptr)
3085 : {
3086 0 : CPLError(CE_Failure, CPLE_AppDefined,
3087 : "Couldn't fetch advertised layer %d!", iLayer);
3088 0 : if (hDstDS == nullptr)
3089 0 : GDALClose(poODS);
3090 0 : delete poGCPCoordTrans;
3091 0 : return nullptr;
3092 : }
3093 :
3094 150 : pasAssocLayers[iLayer].poSrcLayer = poLayer;
3095 :
3096 150 : if (psOptions->aosLayers.FindString(poLayer->GetName()) >= 0)
3097 : {
3098 147 : if (!psOptions->osWHERE.empty())
3099 : {
3100 0 : if (poLayer->SetAttributeFilter(
3101 0 : psOptions->osWHERE.c_str()) != OGRERR_NONE)
3102 : {
3103 0 : CPLError(CE_Failure, CPLE_AppDefined,
3104 : "SetAttributeFilter(%s) on layer '%s' failed.",
3105 0 : psOptions->osWHERE.c_str(),
3106 0 : poLayer->GetName());
3107 0 : if (!psOptions->bSkipFailures)
3108 : {
3109 0 : if (hDstDS == nullptr)
3110 0 : GDALClose(poODS);
3111 0 : delete poGCPCoordTrans;
3112 0 : return nullptr;
3113 : }
3114 : }
3115 : }
3116 :
3117 294 : ApplySpatialFilter(
3118 147 : poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3119 147 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3120 : : nullptr,
3121 : poSourceSRS);
3122 :
3123 147 : oMapLayerToIdx[poLayer] = iLayer;
3124 : }
3125 : }
3126 :
3127 : /* --------------------------------------------------------------------
3128 : */
3129 : /* Second pass to process features in a interleaved layer mode. */
3130 : /* --------------------------------------------------------------------
3131 : */
3132 16 : bool bTargetLayersHaveBeenCreated = false;
3133 : while (true)
3134 : {
3135 991 : OGRLayer *poFeatureLayer = nullptr;
3136 1982 : OGRFeature *poFeature = poDS->GetNextFeature(
3137 991 : &poFeatureLayer, nullptr, pfnProgress, pProgressArg);
3138 991 : if (poFeature == nullptr)
3139 16 : break;
3140 : std::map<OGRLayer *, int>::const_iterator oIter =
3141 975 : oMapLayerToIdx.find(poFeatureLayer);
3142 975 : if (oIter == oMapLayerToIdx.end())
3143 : {
3144 : // Feature in a layer that is not a layer of interest.
3145 0 : OGRFeature::DestroyFeature(poFeature);
3146 : }
3147 : else
3148 : {
3149 975 : if (!bTargetLayersHaveBeenCreated)
3150 : {
3151 : // We defer target layer creation at the first feature
3152 : // retrieved since getting the layer definition can be
3153 : // costly (case of the GMLAS driver) and thus we'd better
3154 : // taking advantage from the progress callback of
3155 : // GetNextFeature.
3156 15 : bTargetLayersHaveBeenCreated = true;
3157 160 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3158 : {
3159 145 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3160 290 : if (psOptions->aosLayers.FindString(
3161 290 : poLayer->GetName()) < 0)
3162 3 : continue;
3163 :
3164 : auto psInfo = oSetup.Setup(
3165 : poLayer,
3166 142 : psOptions->osNewLayerName.empty()
3167 : ? nullptr
3168 0 : : psOptions->osNewLayerName.c_str(),
3169 284 : psOptions.get(), nTotalEventsDone);
3170 :
3171 142 : if (psInfo == nullptr && !psOptions->bSkipFailures)
3172 : {
3173 0 : if (hDstDS == nullptr)
3174 0 : GDALClose(poODS);
3175 0 : delete poGCPCoordTrans;
3176 0 : OGRFeature::DestroyFeature(poFeature);
3177 0 : return nullptr;
3178 : }
3179 :
3180 142 : pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3181 : }
3182 15 : if (nRetCode)
3183 0 : break;
3184 : }
3185 :
3186 975 : int iLayer = oIter->second;
3187 975 : TargetLayerInfo *psInfo = pasAssocLayers[iLayer].psInfo.get();
3188 1949 : if ((psInfo == nullptr ||
3189 974 : !oTranslator.Translate(poFeature, psInfo, 0, nullptr,
3190 : nTotalEventsDone, nullptr, nullptr,
3191 1950 : psOptions.get())) &&
3192 1 : !psOptions->bSkipFailures)
3193 : {
3194 0 : CPLError(
3195 : CE_Failure, CPLE_AppDefined,
3196 : "Terminating translation prematurely after failed\n"
3197 : "translation of layer %s (use -skipfailures to skip "
3198 : "errors)",
3199 0 : poFeatureLayer->GetName());
3200 :
3201 0 : nRetCode = 1;
3202 0 : break;
3203 : }
3204 975 : if (psInfo == nullptr)
3205 1 : OGRFeature::DestroyFeature(poFeature);
3206 : }
3207 975 : } // while true
3208 :
3209 16 : if (pfnProgress)
3210 : {
3211 0 : pfnProgress(1.0, "", pProgressArg);
3212 : }
3213 :
3214 16 : if (!bTargetLayersHaveBeenCreated)
3215 : {
3216 : // bTargetLayersHaveBeenCreated not used after here.
3217 : // bTargetLayersHaveBeenCreated = true;
3218 6 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3219 : {
3220 5 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3221 5 : if (psOptions->aosLayers.FindString(poLayer->GetName()) < 0)
3222 0 : continue;
3223 :
3224 : auto psInfo =
3225 : oSetup.Setup(poLayer,
3226 5 : psOptions->osNewLayerName.empty()
3227 : ? nullptr
3228 0 : : psOptions->osNewLayerName.c_str(),
3229 10 : psOptions.get(), nTotalEventsDone);
3230 :
3231 5 : if (psInfo == nullptr && !psOptions->bSkipFailures)
3232 : {
3233 0 : if (hDstDS == nullptr)
3234 0 : GDALClose(poODS);
3235 0 : delete poGCPCoordTrans;
3236 0 : return nullptr;
3237 : }
3238 :
3239 5 : pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3240 : }
3241 : }
3242 : }
3243 :
3244 : else
3245 : {
3246 600 : std::vector<OGRLayer *> apoLayers;
3247 :
3248 : /* --------------------------------------------------------------------
3249 : */
3250 : /* Process each data source layer. */
3251 : /* --------------------------------------------------------------------
3252 : */
3253 600 : if (psOptions->aosLayers.empty())
3254 : {
3255 591 : const int nLayerCount = poDS->GetLayerCount();
3256 :
3257 1211 : for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3258 : {
3259 620 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3260 :
3261 620 : if (poLayer == nullptr)
3262 : {
3263 0 : CPLError(CE_Failure, CPLE_AppDefined,
3264 : "Couldn't fetch advertised layer %d!", iLayer);
3265 0 : if (hDstDS == nullptr)
3266 0 : GDALClose(poODS);
3267 0 : delete poGCPCoordTrans;
3268 0 : return nullptr;
3269 : }
3270 620 : if (!poDS->IsLayerPrivate(iLayer))
3271 : {
3272 620 : apoLayers.push_back(poLayer);
3273 : }
3274 : }
3275 : }
3276 : /* --------------------------------------------------------------------
3277 : */
3278 : /* Process specified data source layers. */
3279 : /* --------------------------------------------------------------------
3280 : */
3281 : else
3282 : {
3283 :
3284 24 : for (int iLayer = 0; psOptions->aosLayers[iLayer] != nullptr;
3285 : iLayer++)
3286 : {
3287 : OGRLayer *poLayer =
3288 15 : poDS->GetLayerByName(psOptions->aosLayers[iLayer]);
3289 :
3290 15 : if (poLayer == nullptr)
3291 : {
3292 0 : CPLError(CE_Failure, CPLE_AppDefined,
3293 : "Couldn't fetch requested layer '%s'!",
3294 0 : psOptions->aosLayers[iLayer]);
3295 0 : if (!psOptions->bSkipFailures)
3296 : {
3297 0 : if (hDstDS == nullptr)
3298 0 : GDALClose(poODS);
3299 0 : delete poGCPCoordTrans;
3300 0 : return nullptr;
3301 : }
3302 : }
3303 :
3304 15 : apoLayers.emplace_back(poLayer);
3305 : }
3306 : }
3307 :
3308 : /* --------------------------------------------------------------------
3309 : */
3310 : /* Special case to improve user experience when translating into */
3311 : /* single file shapefile and source has only one layer, and that */
3312 : /* the layer name isn't specified */
3313 : /* --------------------------------------------------------------------
3314 : */
3315 : VSIStatBufL sStat;
3316 600 : const int nLayerCount = static_cast<int>(apoLayers.size());
3317 683 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3318 82 : nLayerCount == 1 && psOptions->osNewLayerName.empty() &&
3319 694 : VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3320 11 : (EQUAL(CPLGetExtension(osDestFilename), "shp") ||
3321 2 : EQUAL(CPLGetExtension(osDestFilename), "shz") ||
3322 1 : EQUAL(CPLGetExtension(osDestFilename), "dbf")))
3323 : {
3324 10 : psOptions->osNewLayerName = CPLGetBasename(osDestFilename);
3325 : }
3326 :
3327 600 : std::vector<GIntBig> anLayerCountFeatures;
3328 600 : anLayerCountFeatures.resize(nLayerCount);
3329 600 : GIntBig nCountLayersFeatures = 0;
3330 600 : GIntBig nAccCountFeatures = 0;
3331 :
3332 : /* First pass to apply filters and count all features if necessary */
3333 1235 : for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3334 : {
3335 635 : OGRLayer *poLayer = apoLayers[iLayer];
3336 635 : if (poLayer == nullptr)
3337 0 : continue;
3338 :
3339 635 : if (!psOptions->osWHERE.empty())
3340 : {
3341 8 : if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=
3342 : OGRERR_NONE)
3343 : {
3344 0 : CPLError(CE_Failure, CPLE_AppDefined,
3345 : "SetAttributeFilter(%s) on layer '%s' failed.",
3346 0 : psOptions->osWHERE.c_str(), poLayer->GetName());
3347 0 : if (!psOptions->bSkipFailures)
3348 : {
3349 0 : if (hDstDS == nullptr)
3350 0 : GDALClose(poODS);
3351 0 : delete poGCPCoordTrans;
3352 0 : return nullptr;
3353 : }
3354 : }
3355 : }
3356 :
3357 1269 : ApplySpatialFilter(
3358 635 : poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3359 635 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3360 : : nullptr,
3361 : poSourceSRS);
3362 :
3363 635 : if (psOptions->bDisplayProgress)
3364 : {
3365 4 : if (!poLayer->TestCapability(OLCFastFeatureCount))
3366 : {
3367 0 : CPLError(CE_Warning, CPLE_NotSupported,
3368 : "Progress turned off as fast feature count is not "
3369 : "available.");
3370 0 : psOptions->bDisplayProgress = false;
3371 : }
3372 : else
3373 : {
3374 4 : anLayerCountFeatures[iLayer] = poLayer->GetFeatureCount();
3375 4 : if (psOptions->nLimit >= 0)
3376 0 : anLayerCountFeatures[iLayer] = std::min(
3377 0 : anLayerCountFeatures[iLayer], psOptions->nLimit);
3378 4 : nCountLayersFeatures += anLayerCountFeatures[iLayer];
3379 : }
3380 : }
3381 : }
3382 :
3383 : /* Second pass to do the real job */
3384 1235 : for (int iLayer = 0; iLayer < nLayerCount && nRetCode == 0; iLayer++)
3385 : {
3386 635 : OGRLayer *poLayer = apoLayers[iLayer];
3387 635 : if (poLayer == nullptr)
3388 0 : continue;
3389 :
3390 635 : GDALProgressFunc pfnProgress = nullptr;
3391 635 : void *pProgressArg = nullptr;
3392 :
3393 635 : OGRLayer *poPassedLayer = poLayer;
3394 635 : if (psOptions->bSplitListFields)
3395 : {
3396 : auto poSLFLayer = new OGRSplitListFieldLayer(
3397 1 : poPassedLayer, psOptions->nMaxSplitListSubFields);
3398 1 : poPassedLayer = poSLFLayer;
3399 :
3400 1 : if (psOptions->bDisplayProgress &&
3401 1 : psOptions->nMaxSplitListSubFields != 1 &&
3402 : nCountLayersFeatures != 0)
3403 : {
3404 0 : pfnProgress = GDALScaledProgress;
3405 0 : pProgressArg = GDALCreateScaledProgress(
3406 : nAccCountFeatures * 1.0 / nCountLayersFeatures,
3407 0 : (nAccCountFeatures + anLayerCountFeatures[iLayer] / 2) *
3408 : 1.0 / nCountLayersFeatures,
3409 0 : psOptions->pfnProgress, psOptions->pProgressData);
3410 : }
3411 : else
3412 : {
3413 1 : pfnProgress = nullptr;
3414 1 : pProgressArg = nullptr;
3415 : }
3416 :
3417 : int nRet =
3418 1 : poSLFLayer->BuildLayerDefn(pfnProgress, pProgressArg);
3419 1 : if (!nRet)
3420 : {
3421 0 : delete poPassedLayer;
3422 0 : poPassedLayer = poLayer;
3423 : }
3424 :
3425 1 : if (psOptions->bDisplayProgress)
3426 0 : GDALDestroyScaledProgress(pProgressArg);
3427 1 : pfnProgress = nullptr;
3428 1 : pProgressArg = nullptr;
3429 : }
3430 :
3431 635 : if (psOptions->bDisplayProgress)
3432 : {
3433 4 : if (nCountLayersFeatures != 0)
3434 : {
3435 4 : pfnProgress = GDALScaledProgress;
3436 4 : GIntBig nStart = 0;
3437 4 : if (poPassedLayer != poLayer &&
3438 0 : psOptions->nMaxSplitListSubFields != 1)
3439 0 : nStart = anLayerCountFeatures[iLayer] / 2;
3440 4 : pProgressArg = GDALCreateScaledProgress(
3441 4 : (nAccCountFeatures + nStart) * 1.0 /
3442 : nCountLayersFeatures,
3443 4 : (nAccCountFeatures + anLayerCountFeatures[iLayer]) *
3444 : 1.0 / nCountLayersFeatures,
3445 4 : psOptions->pfnProgress, psOptions->pProgressData);
3446 : }
3447 : }
3448 :
3449 635 : nAccCountFeatures += anLayerCountFeatures[iLayer];
3450 :
3451 : auto psInfo = oSetup.Setup(poPassedLayer,
3452 635 : psOptions->osNewLayerName.empty()
3453 : ? nullptr
3454 31 : : psOptions->osNewLayerName.c_str(),
3455 1936 : psOptions.get(), nTotalEventsDone);
3456 :
3457 635 : poPassedLayer->ResetReading();
3458 :
3459 635 : if ((psInfo == nullptr ||
3460 633 : !oTranslator.Translate(nullptr, psInfo.get(),
3461 633 : anLayerCountFeatures[iLayer], nullptr,
3462 : nTotalEventsDone, pfnProgress,
3463 1270 : pProgressArg, psOptions.get())) &&
3464 8 : !psOptions->bSkipFailures)
3465 : {
3466 7 : CPLError(CE_Failure, CPLE_AppDefined,
3467 : "Terminating translation prematurely after failed\n"
3468 : "translation of layer %s (use -skipfailures to skip "
3469 : "errors)",
3470 7 : poLayer->GetName());
3471 :
3472 7 : nRetCode = 1;
3473 : }
3474 :
3475 635 : if (poPassedLayer != poLayer)
3476 1 : delete poPassedLayer;
3477 :
3478 635 : if (psOptions->bDisplayProgress)
3479 4 : GDALDestroyScaledProgress(pProgressArg);
3480 : }
3481 : }
3482 : /* -------------------------------------------------------------------- */
3483 : /* Process DS style table */
3484 : /* -------------------------------------------------------------------- */
3485 :
3486 627 : poODS->SetStyleTable(poDS->GetStyleTable());
3487 :
3488 627 : if (psOptions->nGroupTransactions)
3489 : {
3490 626 : if (!psOptions->nLayerTransaction)
3491 : {
3492 102 : if (nRetCode != 0 && !psOptions->bSkipFailures)
3493 6 : poODS->RollbackTransaction();
3494 : else
3495 : {
3496 96 : OGRErr eRet = poODS->CommitTransaction();
3497 96 : if (eRet != OGRERR_NONE && eRet != OGRERR_UNSUPPORTED_OPERATION)
3498 : {
3499 1 : nRetCode = 1;
3500 : }
3501 : }
3502 : }
3503 : }
3504 :
3505 627 : delete poGCPCoordTrans;
3506 :
3507 : // Note: this guarantees that the file can be opened in a consistent state,
3508 : // without requiring to close poODS, only if the driver declares
3509 : // DCAP_FLUSHCACHE_CONSISTENT_STATE
3510 627 : if (poODS->FlushCache() != CE_None)
3511 0 : nRetCode = 1;
3512 :
3513 627 : if (nRetCode == 0)
3514 619 : return GDALDataset::ToHandle(poODS);
3515 :
3516 8 : if (hDstDS == nullptr)
3517 8 : GDALClose(poODS);
3518 8 : return nullptr;
3519 : }
3520 :
3521 : /************************************************************************/
3522 : /* SetZ() */
3523 : /************************************************************************/
3524 :
3525 : namespace
3526 : {
3527 : class SetZVisitor : public OGRDefaultGeometryVisitor
3528 : {
3529 : double m_dfZ;
3530 :
3531 : public:
3532 30 : explicit SetZVisitor(double dfZ) : m_dfZ(dfZ)
3533 : {
3534 30 : }
3535 :
3536 : using OGRDefaultGeometryVisitor::visit;
3537 :
3538 735 : void visit(OGRPoint *poPoint) override
3539 : {
3540 735 : poPoint->setZ(m_dfZ);
3541 735 : }
3542 : };
3543 : } // namespace
3544 :
3545 30 : static void SetZ(OGRGeometry *poGeom, double dfZ)
3546 : {
3547 30 : if (poGeom == nullptr)
3548 0 : return;
3549 60 : SetZVisitor visitor(dfZ);
3550 30 : poGeom->set3D(true);
3551 30 : poGeom->accept(&visitor);
3552 : }
3553 :
3554 : /************************************************************************/
3555 : /* ForceCoordDimension() */
3556 : /************************************************************************/
3557 :
3558 903 : static int ForceCoordDimension(int eGType, int nCoordDim)
3559 : {
3560 903 : if (nCoordDim == 2 && eGType != wkbNone)
3561 3 : return wkbFlatten(eGType);
3562 900 : else if (nCoordDim == 3 && eGType != wkbNone)
3563 3 : return wkbSetZ(wkbFlatten(eGType));
3564 897 : else if (nCoordDim == COORD_DIM_XYM && eGType != wkbNone)
3565 2 : return wkbSetM(wkbFlatten(eGType));
3566 895 : else if (nCoordDim == 4 && eGType != wkbNone)
3567 2 : return OGR_GT_SetModifier(static_cast<OGRwkbGeometryType>(eGType), TRUE,
3568 2 : TRUE);
3569 : else
3570 893 : return eGType;
3571 : }
3572 :
3573 : /************************************************************************/
3574 : /* GetLayerAndOverwriteIfNecessary() */
3575 : /************************************************************************/
3576 :
3577 793 : static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
3578 : const char *pszNewLayerName,
3579 : bool bOverwrite,
3580 : bool *pbErrorOccurred,
3581 : bool *pbOverwriteActuallyDone,
3582 : bool *pbAddOverwriteLCO)
3583 : {
3584 793 : if (pbErrorOccurred)
3585 793 : *pbErrorOccurred = false;
3586 793 : if (pbOverwriteActuallyDone)
3587 793 : *pbOverwriteActuallyDone = false;
3588 793 : if (pbAddOverwriteLCO)
3589 793 : *pbAddOverwriteLCO = false;
3590 :
3591 : /* GetLayerByName() can instantiate layers that would have been */
3592 : /* 'hidden' otherwise, for example, non-spatial tables in a */
3593 : /* PostGIS-enabled database, so this apparently useless command is */
3594 : /* not useless. (#4012) */
3595 793 : CPLPushErrorHandler(CPLQuietErrorHandler);
3596 793 : OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
3597 793 : CPLPopErrorHandler();
3598 793 : CPLErrorReset();
3599 :
3600 793 : int iLayer = -1;
3601 793 : if (poDstLayer != nullptr)
3602 : {
3603 52 : const int nLayerCount = poDstDS->GetLayerCount();
3604 366 : for (iLayer = 0; iLayer < nLayerCount; iLayer++)
3605 : {
3606 366 : OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
3607 366 : if (poLayer == poDstLayer)
3608 52 : break;
3609 : }
3610 :
3611 52 : if (iLayer == nLayerCount)
3612 : /* should not happen with an ideal driver */
3613 0 : poDstLayer = nullptr;
3614 : }
3615 :
3616 : /* -------------------------------------------------------------------- */
3617 : /* If the user requested overwrite, and we have the layer in */
3618 : /* question we need to delete it now so it will get recreated */
3619 : /* (overwritten). */
3620 : /* -------------------------------------------------------------------- */
3621 793 : if (poDstLayer != nullptr && bOverwrite)
3622 : {
3623 : /* When using the CARTO driver we don't want to delete the layer if */
3624 : /* it's going to be recreated. Instead we mark it to be overwritten */
3625 : /* when the new creation is requested */
3626 12 : if (poDstDS->GetDriver()->GetMetadataItem(
3627 24 : GDAL_DS_LAYER_CREATIONOPTIONLIST) != nullptr &&
3628 24 : strstr(poDstDS->GetDriver()->GetMetadataItem(
3629 12 : GDAL_DS_LAYER_CREATIONOPTIONLIST),
3630 : "CARTODBFY") != nullptr)
3631 : {
3632 0 : if (pbAddOverwriteLCO)
3633 0 : *pbAddOverwriteLCO = true;
3634 0 : if (pbOverwriteActuallyDone)
3635 0 : *pbOverwriteActuallyDone = true;
3636 : }
3637 12 : else if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
3638 : {
3639 0 : CPLError(CE_Failure, CPLE_AppDefined,
3640 : "DeleteLayer() failed when overwrite requested.");
3641 0 : if (pbErrorOccurred)
3642 0 : *pbErrorOccurred = true;
3643 : }
3644 : else
3645 : {
3646 12 : if (pbOverwriteActuallyDone)
3647 12 : *pbOverwriteActuallyDone = true;
3648 : }
3649 12 : poDstLayer = nullptr;
3650 : }
3651 :
3652 793 : return poDstLayer;
3653 : }
3654 :
3655 : /************************************************************************/
3656 : /* ConvertType() */
3657 : /************************************************************************/
3658 :
3659 898 : static OGRwkbGeometryType ConvertType(GeomTypeConversion eGeomTypeConversion,
3660 : OGRwkbGeometryType eGType)
3661 : {
3662 898 : OGRwkbGeometryType eRetType = eGType;
3663 :
3664 898 : if (eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
3665 : eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3666 : {
3667 13 : eRetType = OGR_GT_GetLinear(eRetType);
3668 : }
3669 :
3670 898 : if (eGeomTypeConversion == GTC_PROMOTE_TO_MULTI ||
3671 : eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3672 : {
3673 12 : if (eRetType == wkbTriangle || eRetType == wkbTIN ||
3674 : eRetType == wkbPolyhedralSurface)
3675 : {
3676 0 : eRetType = wkbMultiPolygon;
3677 : }
3678 12 : else if (!OGR_GT_IsSubClassOf(eRetType, wkbGeometryCollection))
3679 : {
3680 8 : eRetType = OGR_GT_GetCollection(eRetType);
3681 : }
3682 : }
3683 :
3684 898 : if (eGeomTypeConversion == GTC_CONVERT_TO_CURVE)
3685 2 : eRetType = OGR_GT_GetCurve(eRetType);
3686 :
3687 898 : return eRetType;
3688 : }
3689 :
3690 : /************************************************************************/
3691 : /* DoFieldTypeConversion() */
3692 : /************************************************************************/
3693 :
3694 3139 : static void DoFieldTypeConversion(GDALDataset *poDstDS,
3695 : OGRFieldDefn &oFieldDefn,
3696 : char **papszFieldTypesToString,
3697 : char **papszMapFieldType,
3698 : bool bUnsetFieldWidth, bool bQuiet,
3699 : bool bForceNullable, bool bUnsetDefault)
3700 : {
3701 3139 : if (papszFieldTypesToString != nullptr)
3702 : {
3703 0 : CPLString osLookupString;
3704 : osLookupString.Printf(
3705 : "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3706 0 : OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
3707 :
3708 0 : int iIdx = CSLFindString(papszFieldTypesToString, osLookupString);
3709 0 : if (iIdx < 0)
3710 0 : iIdx = CSLFindString(
3711 : papszFieldTypesToString,
3712 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
3713 0 : if (iIdx < 0)
3714 0 : iIdx = CSLFindString(papszFieldTypesToString, "All");
3715 0 : if (iIdx >= 0)
3716 : {
3717 0 : oFieldDefn.SetSubType(OFSTNone);
3718 0 : oFieldDefn.SetType(OFTString);
3719 : }
3720 : }
3721 3139 : else if (papszMapFieldType != nullptr)
3722 : {
3723 28 : CPLString osLookupString;
3724 : osLookupString.Printf(
3725 : "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3726 14 : OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
3727 :
3728 : const char *pszType =
3729 14 : CSLFetchNameValue(papszMapFieldType, osLookupString);
3730 14 : if (pszType == nullptr)
3731 13 : pszType = CSLFetchNameValue(
3732 : papszMapFieldType,
3733 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
3734 14 : if (pszType == nullptr)
3735 10 : pszType = CSLFetchNameValue(papszMapFieldType, "All");
3736 14 : if (pszType != nullptr)
3737 : {
3738 : int iSubType;
3739 4 : int iType = GetFieldType(pszType, &iSubType);
3740 4 : if (iType >= 0 && iSubType >= 0)
3741 : {
3742 4 : oFieldDefn.SetSubType(OFSTNone);
3743 4 : oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
3744 4 : oFieldDefn.SetSubType(static_cast<OGRFieldSubType>(iSubType));
3745 4 : if (iType == OFTInteger)
3746 1 : oFieldDefn.SetWidth(0);
3747 : }
3748 : }
3749 : }
3750 3139 : if (bUnsetFieldWidth)
3751 : {
3752 6 : oFieldDefn.SetWidth(0);
3753 6 : oFieldDefn.SetPrecision(0);
3754 : }
3755 3139 : if (bForceNullable)
3756 4 : oFieldDefn.SetNullable(TRUE);
3757 3139 : if (bUnsetDefault)
3758 2 : oFieldDefn.SetDefault(nullptr);
3759 :
3760 3139 : const auto poDstDriver = poDstDS->GetDriver();
3761 : const char *pszCreationFieldDataTypes =
3762 : poDstDriver
3763 3139 : ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES)
3764 3139 : : nullptr;
3765 : const char *pszCreationFieldDataSubtypes =
3766 : poDstDriver
3767 3139 : ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES)
3768 3139 : : nullptr;
3769 6169 : if (pszCreationFieldDataTypes &&
3770 3030 : strstr(pszCreationFieldDataTypes,
3771 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == nullptr)
3772 : {
3773 33 : if (pszCreationFieldDataSubtypes &&
3774 64 : (oFieldDefn.GetType() == OFTIntegerList ||
3775 61 : oFieldDefn.GetType() == OFTInteger64List ||
3776 59 : oFieldDefn.GetType() == OFTRealList ||
3777 96 : oFieldDefn.GetType() == OFTStringList) &&
3778 25 : strstr(pszCreationFieldDataSubtypes, "JSON"))
3779 : {
3780 5 : if (!bQuiet)
3781 : {
3782 5 : CPLError(
3783 : CE_Warning, CPLE_AppDefined,
3784 : "The output driver does not seem to natively support %s "
3785 : "type for field %s. Converting it to String(JSON) instead. "
3786 : "-mapFieldType can be used to control field type "
3787 : "conversion.",
3788 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3789 : oFieldDefn.GetNameRef());
3790 : }
3791 5 : oFieldDefn.SetSubType(OFSTNone);
3792 5 : oFieldDefn.SetType(OFTString);
3793 5 : oFieldDefn.SetSubType(OFSTJSON);
3794 : }
3795 29 : else if (oFieldDefn.GetType() == OFTInteger64)
3796 : {
3797 5 : if (!bQuiet)
3798 : {
3799 5 : CPLError(
3800 : CE_Warning, CPLE_AppDefined,
3801 : "The output driver does not seem to natively support %s "
3802 : "type for field %s. Converting it to Real instead. "
3803 : "-mapFieldType can be used to control field type "
3804 : "conversion.",
3805 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3806 : oFieldDefn.GetNameRef());
3807 : }
3808 5 : oFieldDefn.SetType(OFTReal);
3809 : }
3810 24 : else if (!bQuiet)
3811 : {
3812 24 : CPLError(
3813 : CE_Warning, CPLE_AppDefined,
3814 : "The output driver does not natively support %s type for "
3815 : "field %s. Misconversion can happen. "
3816 : "-mapFieldType can be used to control field type conversion.",
3817 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3818 : oFieldDefn.GetNameRef());
3819 : }
3820 : }
3821 3105 : else if (!pszCreationFieldDataTypes)
3822 : {
3823 : // All drivers supporting OFTInteger64 should advertise it theoretically
3824 109 : if (oFieldDefn.GetType() == OFTInteger64)
3825 : {
3826 1 : if (!bQuiet)
3827 : {
3828 1 : CPLError(CE_Warning, CPLE_AppDefined,
3829 : "The output driver does not seem to natively support "
3830 : "%s type "
3831 : "for field %s. Converting it to Real instead. "
3832 : "-mapFieldType can be used to control field type "
3833 : "conversion.",
3834 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3835 : oFieldDefn.GetNameRef());
3836 : }
3837 1 : oFieldDefn.SetType(OFTReal);
3838 : }
3839 : }
3840 3139 : }
3841 :
3842 : /************************************************************************/
3843 : /* SetupTargetLayer::CanUseWriteArrowBatch() */
3844 : /************************************************************************/
3845 :
3846 789 : bool SetupTargetLayer::CanUseWriteArrowBatch(
3847 : OGRLayer *poSrcLayer, OGRLayer *poDstLayer, bool bJustCreatedLayer,
3848 : const GDALVectorTranslateOptions *psOptions, bool &bError)
3849 : {
3850 789 : bError = false;
3851 :
3852 : // Check if we can use the Arrow interface to get and write features
3853 : // as it will be faster if the input driver has a fast
3854 : // implementation of GetArrowStream().
3855 : // We also can only do that only if using ogr2ogr without options that
3856 : // alter features.
3857 : // OGR2OGR_USE_ARROW_API config option is mostly for testing purposes
3858 : // or as a safety belt if things turned bad...
3859 789 : bool bUseWriteArrowBatch = false;
3860 789 : if (((poSrcLayer->TestCapability(OLCFastGetArrowStream) &&
3861 : // As we don't control the input array size when the input or output
3862 : // drivers are Arrow/Parquet (as they don't use the generic
3863 : // implementation), we can't guarantee that ROW_GROUP_SIZE/BATCH_SIZE
3864 : // layer creation options will be honored.
3865 137 : !psOptions->aosLCO.FetchNameValue("ROW_GROUP_SIZE") &&
3866 135 : !psOptions->aosLCO.FetchNameValue("BATCH_SIZE") &&
3867 132 : CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "YES"))) ||
3868 657 : CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "NO"))) &&
3869 136 : !psOptions->bSkipFailures && !psOptions->bTransform &&
3870 134 : !psOptions->poClipSrc && !psOptions->poClipDst &&
3871 128 : psOptions->oGCPs.nGCPCount == 0 && !psOptions->bWrapDateline &&
3872 128 : !m_papszSelFields && !m_bAddMissingFields &&
3873 128 : m_eGType == GEOMTYPE_UNCHANGED && psOptions->eGeomOp == GEOMOP_NONE &&
3874 128 : m_eGeomTypeConversion == GTC_DEFAULT && m_nCoordDim < 0 &&
3875 128 : !m_papszFieldTypesToString && !m_papszMapFieldType &&
3876 128 : !m_bUnsetFieldWidth && !m_bExplodeCollections && !m_pszZField &&
3877 127 : m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains &&
3878 127 : !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID &&
3879 1705 : psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN &&
3880 127 : !psOptions->bMakeValid)
3881 : {
3882 : struct ArrowArrayStream streamSrc;
3883 127 : const char *const apszOptions[] = {"SILENCE_GET_SCHEMA_ERROR=YES",
3884 : nullptr};
3885 127 : if (poSrcLayer->GetArrowStream(&streamSrc, apszOptions))
3886 : {
3887 : struct ArrowSchema schemaSrc;
3888 127 : if (streamSrc.get_schema(&streamSrc, &schemaSrc) == 0)
3889 : {
3890 127 : std::string osErrorMsg;
3891 127 : if (poDstLayer->IsArrowSchemaSupported(&schemaSrc, nullptr,
3892 127 : osErrorMsg))
3893 : {
3894 : const OGRFeatureDefn *poSrcFDefn =
3895 127 : poSrcLayer->GetLayerDefn();
3896 : const OGRFeatureDefn *poDstFDefn =
3897 127 : poDstLayer->GetLayerDefn();
3898 125 : if (bJustCreatedLayer && poDstFDefn &&
3899 377 : poDstFDefn->GetFieldCount() == 0 &&
3900 125 : poDstFDefn->GetGeomFieldCount() ==
3901 125 : poSrcFDefn->GetGeomFieldCount())
3902 : {
3903 : // Create output fields using CreateFieldFromArrowSchema()
3904 970 : for (int i = 0; i < schemaSrc.n_children; ++i)
3905 : {
3906 845 : const char *pszFieldName =
3907 845 : schemaSrc.children[i]->name;
3908 :
3909 : const auto iSrcField =
3910 845 : poSrcFDefn->GetFieldIndex(pszFieldName);
3911 845 : if (iSrcField >= 0)
3912 : {
3913 : const auto poSrcFieldDefn =
3914 701 : poSrcFDefn->GetFieldDefn(iSrcField);
3915 : // Create field domain in output dataset if not already existing.
3916 : const std::string osDomainName(
3917 1402 : poSrcFieldDefn->GetDomainName());
3918 701 : if (!osDomainName.empty())
3919 : {
3920 27 : if (m_poDstDS->TestCapability(
3921 18 : ODsCAddFieldDomain) &&
3922 9 : m_poDstDS->GetFieldDomain(
3923 9 : osDomainName) == nullptr)
3924 : {
3925 : const auto poSrcDomain =
3926 18 : m_poSrcDS->GetFieldDomain(
3927 9 : osDomainName);
3928 9 : if (poSrcDomain)
3929 : {
3930 18 : std::string failureReason;
3931 9 : if (!m_poDstDS->AddFieldDomain(
3932 18 : std::unique_ptr<
3933 : OGRFieldDomain>(
3934 9 : poSrcDomain->Clone()),
3935 9 : failureReason))
3936 : {
3937 0 : CPLDebug("OGR2OGR",
3938 : "Cannot create domain "
3939 : "%s: %s",
3940 : osDomainName.c_str(),
3941 : failureReason.c_str());
3942 : }
3943 : }
3944 : else
3945 : {
3946 0 : CPLDebug("OGR2OGR",
3947 : "Cannot find domain %s in "
3948 : "source dataset",
3949 : osDomainName.c_str());
3950 : }
3951 : }
3952 : }
3953 : }
3954 :
3955 2532 : if (!EQUAL(pszFieldName, "OGC_FID") &&
3956 842 : !EQUAL(pszFieldName, "wkb_geometry") &&
3957 839 : !EQUAL(pszFieldName,
3958 829 : poSrcLayer->GetFIDColumn()) &&
3959 829 : poSrcFDefn->GetGeomFieldIndex(pszFieldName) <
3960 1687 : 0 &&
3961 708 : !poDstLayer->CreateFieldFromArrowSchema(
3962 708 : schemaSrc.children[i], nullptr))
3963 : {
3964 0 : CPLError(CE_Failure, CPLE_AppDefined,
3965 : "Cannot create field %s",
3966 : pszFieldName);
3967 0 : schemaSrc.release(&schemaSrc);
3968 0 : streamSrc.release(&streamSrc);
3969 0 : return false;
3970 : }
3971 : }
3972 125 : bUseWriteArrowBatch = true;
3973 : }
3974 2 : else if (!bJustCreatedLayer)
3975 : {
3976 : // If the layer already exist, get its schema, and
3977 : // check that it looks to be the same as the source
3978 : // one
3979 : struct ArrowArrayStream streamDst;
3980 2 : if (poDstLayer->GetArrowStream(&streamDst, nullptr))
3981 : {
3982 : struct ArrowSchema schemaDst;
3983 2 : if (streamDst.get_schema(&streamDst, &schemaDst) ==
3984 : 0)
3985 : {
3986 2 : if (schemaDst.n_children ==
3987 2 : schemaSrc.n_children)
3988 : {
3989 2 : bUseWriteArrowBatch = true;
3990 : }
3991 2 : schemaDst.release(&schemaDst);
3992 : }
3993 2 : streamDst.release(&streamDst);
3994 : }
3995 : }
3996 127 : if (bUseWriteArrowBatch)
3997 : {
3998 127 : CPLDebug("OGR2OGR", "Using WriteArrowBatch()");
3999 : }
4000 : }
4001 : else
4002 : {
4003 0 : CPLDebug("OGR2OGR",
4004 : "Cannot use WriteArrowBatch() because "
4005 : "input layer schema is not supported by output "
4006 : "layer: %s",
4007 : osErrorMsg.c_str());
4008 : }
4009 127 : schemaSrc.release(&schemaSrc);
4010 : }
4011 127 : streamSrc.release(&streamSrc);
4012 : }
4013 : }
4014 789 : return bUseWriteArrowBatch;
4015 : }
4016 :
4017 : /************************************************************************/
4018 : /* SetupTargetLayer::Setup() */
4019 : /************************************************************************/
4020 :
4021 : std::unique_ptr<TargetLayerInfo>
4022 793 : SetupTargetLayer::Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
4023 : GDALVectorTranslateOptions *psOptions,
4024 : GIntBig &nTotalEventsDone)
4025 : {
4026 793 : int eGType = m_eGType;
4027 793 : bool bPreserveFID = m_bPreserveFID;
4028 793 : bool bAppend = m_bAppend;
4029 :
4030 793 : if (pszNewLayerName == nullptr)
4031 761 : pszNewLayerName = poSrcLayer->GetName();
4032 :
4033 : /* -------------------------------------------------------------------- */
4034 : /* Get other info. */
4035 : /* -------------------------------------------------------------------- */
4036 793 : OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
4037 :
4038 : /* -------------------------------------------------------------------- */
4039 : /* Find requested geometry fields. */
4040 : /* -------------------------------------------------------------------- */
4041 1586 : std::vector<int> anRequestedGeomFields;
4042 793 : const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
4043 793 : if (m_bSelFieldsSet && !bAppend)
4044 : {
4045 40 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4046 : iField++)
4047 : {
4048 25 : int iSrcField = poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4049 25 : if (iSrcField >= 0)
4050 : {
4051 : /* do nothing */
4052 : }
4053 : else
4054 : {
4055 3 : iSrcField =
4056 3 : poSrcFDefn->GetGeomFieldIndex(m_papszSelFields[iField]);
4057 3 : if (iSrcField >= 0)
4058 : {
4059 3 : anRequestedGeomFields.push_back(iSrcField);
4060 : }
4061 : else
4062 : {
4063 0 : CPLError(CE_Failure, CPLE_AppDefined,
4064 : "Field '%s' not found in source layer.",
4065 0 : m_papszSelFields[iField]);
4066 0 : if (!psOptions->bSkipFailures)
4067 0 : return nullptr;
4068 : }
4069 : }
4070 : }
4071 :
4072 16 : if (anRequestedGeomFields.size() > 1 &&
4073 1 : !m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4074 : {
4075 0 : CPLError(CE_Failure, CPLE_AppDefined,
4076 : "Several geometry fields requested, but output "
4077 : "datasource does not support multiple geometry "
4078 : "fields.");
4079 0 : if (!psOptions->bSkipFailures)
4080 0 : return nullptr;
4081 : else
4082 0 : anRequestedGeomFields.resize(0);
4083 : }
4084 : }
4085 :
4086 793 : const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
4087 793 : if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
4088 : {
4089 658 : if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())
4090 656 : poOutputSRS = poSrcLayer->GetSpatialRef();
4091 2 : else if (anRequestedGeomFields.size() == 1)
4092 : {
4093 1 : int iSrcGeomField = anRequestedGeomFields[0];
4094 : poOutputSRS =
4095 1 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetSpatialRef();
4096 : }
4097 : }
4098 :
4099 793 : int iSrcZField = -1;
4100 793 : if (m_pszZField != nullptr)
4101 : {
4102 4 : iSrcZField = poSrcFDefn->GetFieldIndex(m_pszZField);
4103 4 : if (iSrcZField < 0)
4104 : {
4105 1 : CPLError(CE_Warning, CPLE_AppDefined,
4106 : "zfield '%s' does not exist in layer %s", m_pszZField,
4107 1 : poSrcLayer->GetName());
4108 : }
4109 : }
4110 :
4111 : /* -------------------------------------------------------------------- */
4112 : /* Find the layer. */
4113 : /* -------------------------------------------------------------------- */
4114 :
4115 : bool bErrorOccurred;
4116 : bool bOverwriteActuallyDone;
4117 : bool bAddOverwriteLCO;
4118 1586 : OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(
4119 793 : m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,
4120 : &bOverwriteActuallyDone, &bAddOverwriteLCO);
4121 793 : const bool bJustCreatedLayer = (poDstLayer == nullptr);
4122 793 : if (bErrorOccurred)
4123 0 : return nullptr;
4124 :
4125 : /* -------------------------------------------------------------------- */
4126 : /* If the layer does not exist, then create it. */
4127 : /* -------------------------------------------------------------------- */
4128 793 : if (poDstLayer == nullptr)
4129 : {
4130 753 : if (!m_poDstDS->TestCapability(ODsCCreateLayer))
4131 : {
4132 0 : CPLError(
4133 : CE_Failure, CPLE_AppDefined,
4134 : "Layer '%s' does not already exist in the output dataset, and "
4135 : "cannot be created by the output driver.",
4136 : pszNewLayerName);
4137 4 : return nullptr;
4138 : }
4139 :
4140 753 : bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);
4141 753 : if (!bForceGType)
4142 : {
4143 737 : if (anRequestedGeomFields.empty())
4144 : {
4145 735 : eGType = poSrcFDefn->GetGeomType();
4146 : }
4147 2 : else if (anRequestedGeomFields.size() == 1)
4148 : {
4149 1 : int iSrcGeomField = anRequestedGeomFields[0];
4150 1 : eGType = poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetType();
4151 : }
4152 : else
4153 : {
4154 1 : eGType = wkbNone;
4155 : }
4156 :
4157 : bool bHasZ =
4158 737 : CPL_TO_BOOL(wkbHasZ(static_cast<OGRwkbGeometryType>(eGType)));
4159 737 : eGType = ConvertType(m_eGeomTypeConversion,
4160 : static_cast<OGRwkbGeometryType>(eGType));
4161 :
4162 737 : if (m_bExplodeCollections)
4163 : {
4164 3 : const OGRwkbGeometryType eFGType = wkbFlatten(eGType);
4165 3 : if (eFGType == wkbMultiPoint)
4166 : {
4167 1 : eGType = wkbPoint;
4168 : }
4169 2 : else if (eFGType == wkbMultiLineString)
4170 : {
4171 0 : eGType = wkbLineString;
4172 : }
4173 2 : else if (eFGType == wkbMultiPolygon)
4174 : {
4175 0 : eGType = wkbPolygon;
4176 : }
4177 2 : else if (eFGType == wkbGeometryCollection ||
4178 2 : eFGType == wkbMultiCurve || eFGType == wkbMultiSurface)
4179 : {
4180 0 : eGType = wkbUnknown;
4181 : }
4182 : }
4183 :
4184 737 : if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))
4185 108 : eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));
4186 : }
4187 :
4188 753 : eGType = ForceCoordDimension(eGType, m_nCoordDim);
4189 :
4190 753 : CPLErrorReset();
4191 :
4192 753 : char **papszLCOTemp = CSLDuplicate(m_papszLCO);
4193 : const char *pszDestCreationOptions =
4194 753 : m_poDstDS->GetDriver()->GetMetadataItem(
4195 753 : GDAL_DS_LAYER_CREATIONOPTIONLIST);
4196 :
4197 753 : int eGCreateLayerType = eGType;
4198 764 : if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4199 11 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4200 : {
4201 10 : eGCreateLayerType = wkbNone;
4202 : }
4203 : // If the source layer has a single geometry column that is not nullable
4204 : // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it
4205 : // so as to be able to set the not null constraint (if the driver
4206 : // supports it) and that the output driver has no GEOMETRY_NULLABLE
4207 : // layer creation option. Same if the source geometry column has a non
4208 : // empty name that is not overridden, and that the output driver has no
4209 : // GEOMETRY_NAME layer creation option, but no LAUNDER option (if
4210 : // laundering is available, then we might want to launder the geometry
4211 : // column name as well)
4212 590 : else if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4213 588 : nSrcGeomFieldCount == 1 &&
4214 588 : m_poDstDS->TestCapability(
4215 2044 : ODsCCreateGeomFieldAfterCreateLayer) &&
4216 123 : ((!poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4217 2 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") ==
4218 2 : nullptr &&
4219 2 : (pszDestCreationOptions == nullptr ||
4220 2 : strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") !=
4221 0 : nullptr) &&
4222 0 : !m_bForceNullable) ||
4223 123 : (poSrcLayer->GetGeometryColumn() != nullptr &&
4224 123 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&
4225 123 : !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&
4226 24 : (pszDestCreationOptions == nullptr ||
4227 24 : strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==
4228 8 : nullptr ||
4229 8 : strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&
4230 24 : poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <
4231 : 0)))
4232 : {
4233 24 : anRequestedGeomFields.push_back(0);
4234 24 : eGCreateLayerType = wkbNone;
4235 : }
4236 720 : else if (anRequestedGeomFields.size() == 1 &&
4237 1 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4238 : {
4239 0 : eGCreateLayerType = wkbNone;
4240 : }
4241 :
4242 753 : OGRGeomCoordinatePrecision oCoordPrec;
4243 753 : std::string osGeomFieldName;
4244 753 : bool bGeomFieldNullable = true;
4245 :
4246 : {
4247 753 : int iSrcGeomField = -1;
4248 916 : if (anRequestedGeomFields.empty() &&
4249 163 : (nSrcGeomFieldCount == 1 ||
4250 163 : (!m_poDstDS->TestCapability(
4251 196 : ODsCCreateGeomFieldAfterCreateLayer) &&
4252 : nSrcGeomFieldCount > 1)))
4253 : {
4254 565 : iSrcGeomField = 0;
4255 : }
4256 188 : else if (anRequestedGeomFields.size() == 1)
4257 : {
4258 25 : iSrcGeomField = anRequestedGeomFields[0];
4259 : }
4260 :
4261 753 : if (iSrcGeomField >= 0)
4262 : {
4263 : const auto poSrcGeomFieldDefn =
4264 590 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);
4265 590 : if (!psOptions->bUnsetCoordPrecision)
4266 : {
4267 589 : oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()
4268 1178 : .ConvertToOtherSRS(
4269 589 : poSrcGeomFieldDefn->GetSpatialRef(),
4270 589 : poOutputSRS);
4271 : }
4272 :
4273 : bGeomFieldNullable =
4274 590 : CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());
4275 :
4276 590 : const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();
4277 770 : if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&
4278 180 : poSrcFDefn->GetFieldIndex(pszGFldName) < 0)
4279 : {
4280 179 : osGeomFieldName = pszGFldName;
4281 :
4282 : // Use source geometry field name as much as possible
4283 179 : if (eGType != wkbNone && pszDestCreationOptions &&
4284 179 : strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=
4285 358 : nullptr &&
4286 150 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==
4287 : nullptr)
4288 : {
4289 150 : papszLCOTemp = CSLSetNameValue(
4290 : papszLCOTemp, "GEOMETRY_NAME", pszGFldName);
4291 : }
4292 : }
4293 : }
4294 : }
4295 :
4296 : // If the source feature first geometry column is not nullable
4297 : // and that GEOMETRY_NULLABLE creation option is available, use it
4298 : // so as to be able to set the not null constraint (if the driver
4299 : // supports it)
4300 600 : if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4301 575 : nSrcGeomFieldCount >= 1 &&
4302 575 : !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4303 0 : pszDestCreationOptions != nullptr &&
4304 0 : strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") != nullptr &&
4305 1353 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") == nullptr &&
4306 0 : !m_bForceNullable)
4307 : {
4308 0 : bGeomFieldNullable = false;
4309 : papszLCOTemp =
4310 0 : CSLSetNameValue(papszLCOTemp, "GEOMETRY_NULLABLE", "NO");
4311 0 : CPLDebug("GDALVectorTranslate", "Using GEOMETRY_NULLABLE=NO");
4312 : }
4313 :
4314 753 : if (psOptions->dfXYRes != OGRGeomCoordinatePrecision::UNKNOWN)
4315 : {
4316 7 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4317 8 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr &&
4318 1 : !OGRGeometryFactory::haveGEOS())
4319 : {
4320 0 : CPLError(CE_Warning, CPLE_AppDefined,
4321 : "-xyRes specified, but driver does not expose the "
4322 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, "
4323 : "and this build has no GEOS support");
4324 : }
4325 :
4326 7 : oCoordPrec.dfXYResolution = psOptions->dfXYRes;
4327 7 : if (!psOptions->osXYResUnit.empty())
4328 : {
4329 5 : if (!poOutputSRS)
4330 : {
4331 1 : CSLDestroy(papszLCOTemp);
4332 1 : CPLError(CE_Failure, CPLE_AppDefined,
4333 : "Unit suffix for -xyRes cannot be used with an "
4334 : "unknown destination SRS");
4335 1 : return nullptr;
4336 : }
4337 :
4338 4 : if (psOptions->osXYResUnit == "mm")
4339 : {
4340 1 : oCoordPrec.dfXYResolution *= 1e-3;
4341 : }
4342 3 : else if (psOptions->osXYResUnit == "deg")
4343 : {
4344 : double dfFactorDegToMeter =
4345 2 : poOutputSRS->GetSemiMajor(nullptr) * M_PI / 180;
4346 2 : oCoordPrec.dfXYResolution *= dfFactorDegToMeter;
4347 : }
4348 : else
4349 : {
4350 : // Checked at argument parsing time
4351 1 : CPLAssert(psOptions->osXYResUnit == "m");
4352 : }
4353 :
4354 4 : OGRGeomCoordinatePrecision tmp;
4355 4 : tmp.SetFromMeter(poOutputSRS, oCoordPrec.dfXYResolution, 0, 0);
4356 4 : oCoordPrec.dfXYResolution = tmp.dfXYResolution;
4357 : }
4358 : }
4359 :
4360 752 : if (psOptions->dfZRes != OGRGeomCoordinatePrecision::UNKNOWN)
4361 : {
4362 4 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4363 4 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4364 : {
4365 0 : CPLError(CE_Warning, CPLE_AppDefined,
4366 : "-zRes specified, but driver does not expose the "
4367 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4368 : }
4369 :
4370 4 : oCoordPrec.dfZResolution = psOptions->dfZRes;
4371 4 : if (!psOptions->osZResUnit.empty())
4372 : {
4373 3 : if (!poOutputSRS)
4374 : {
4375 1 : CSLDestroy(papszLCOTemp);
4376 1 : CPLError(CE_Failure, CPLE_AppDefined,
4377 : "Unit suffix for -zRes cannot be used with an "
4378 : "unknown destination SRS");
4379 1 : return nullptr;
4380 : }
4381 :
4382 2 : if (psOptions->osZResUnit == "mm")
4383 : {
4384 1 : oCoordPrec.dfZResolution *= 1e-3;
4385 : }
4386 : else
4387 : {
4388 : // Checked at argument parsing time
4389 1 : CPLAssert(psOptions->osZResUnit == "m");
4390 : }
4391 :
4392 2 : OGRGeomCoordinatePrecision tmp;
4393 2 : tmp.SetFromMeter(poOutputSRS, 0, oCoordPrec.dfZResolution, 0);
4394 2 : oCoordPrec.dfZResolution = tmp.dfZResolution;
4395 : }
4396 : }
4397 :
4398 751 : if (psOptions->dfMRes != OGRGeomCoordinatePrecision::UNKNOWN)
4399 : {
4400 3 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4401 3 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4402 : {
4403 0 : CPLError(CE_Warning, CPLE_AppDefined,
4404 : "-mRes specified, but driver does not expose the "
4405 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4406 : }
4407 :
4408 3 : oCoordPrec.dfMResolution = psOptions->dfMRes;
4409 : }
4410 :
4411 : // Force FID column as 64 bit if the source feature has a 64 bit FID,
4412 : // the target driver supports 64 bit FID and the user didn't set it
4413 : // manually.
4414 751 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
4415 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&
4416 1 : pszDestCreationOptions &&
4417 752 : strstr(pszDestCreationOptions, "FID64") != nullptr &&
4418 0 : CSLFetchNameValue(m_papszLCO, "FID64") == nullptr)
4419 : {
4420 0 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID64", "YES");
4421 0 : CPLDebug("GDALVectorTranslate", "Using FID64=YES");
4422 : }
4423 :
4424 : // If output driver supports FID layer creation option, set it with
4425 : // the FID column name of the source layer
4426 749 : if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&
4427 748 : !EQUAL(poSrcLayer->GetFIDColumn(), "") &&
4428 30 : pszDestCreationOptions != nullptr &&
4429 30 : (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4430 1502 : strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4431 26 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4432 : {
4433 26 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID",
4434 26 : poSrcLayer->GetFIDColumn());
4435 26 : if (!psOptions->bExplodeCollections)
4436 : {
4437 25 : CPLDebug("GDALVectorTranslate",
4438 : "Using FID=%s and -preserve_fid",
4439 25 : poSrcLayer->GetFIDColumn());
4440 25 : bPreserveFID = true;
4441 : }
4442 : else
4443 : {
4444 1 : CPLDebug("GDALVectorTranslate",
4445 : "Using FID=%s and disable -preserve_fid because not "
4446 : "compatible with -explodecollection",
4447 1 : poSrcLayer->GetFIDColumn());
4448 1 : bPreserveFID = false;
4449 : }
4450 : }
4451 : // Detect scenario of converting from GPX to a format like GPKG
4452 : // Cf https://github.com/OSGeo/gdal/issues/9225
4453 720 : else if (!bPreserveFID && !m_bUnsetFid && !bAppend &&
4454 717 : m_poSrcDS->GetDriver() &&
4455 717 : EQUAL(m_poSrcDS->GetDriver()->GetDescription(), "GPX") &&
4456 5 : pszDestCreationOptions &&
4457 5 : (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4458 1445 : strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4459 5 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4460 : {
4461 5 : CPLDebug("GDALVectorTranslate",
4462 : "Forcing -preserve_fid because source is GPX and layers "
4463 : "have FID cross references");
4464 5 : bPreserveFID = true;
4465 : }
4466 : // Detect scenario of converting GML2 with fid attribute to GPKG
4467 762 : else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&
4468 42 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4469 : {
4470 42 : int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid");
4471 43 : if (nFieldIdx >= 0 && poSrcLayer->GetLayerDefn()
4472 1 : ->GetFieldDefn(nFieldIdx)
4473 1 : ->GetType() == OFTString)
4474 : {
4475 1 : CPLDebug("GDALVectorTranslate",
4476 : "Source layer has a non-string 'fid' column. Using "
4477 : "FID=gpkg_fid for GeoPackage");
4478 1 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID", "gpkg_fid");
4479 : }
4480 : }
4481 :
4482 : // If bAddOverwriteLCO is ON (set up when overwriting a CARTO layer),
4483 : // set OVERWRITE to YES so the new layer overwrites the old one
4484 751 : if (bAddOverwriteLCO)
4485 : {
4486 0 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "OVERWRITE", "ON");
4487 0 : CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON");
4488 : }
4489 :
4490 2252 : if (m_bNativeData &&
4491 750 : poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") !=
4492 20 : nullptr &&
4493 20 : poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA") !=
4494 20 : nullptr &&
4495 20 : pszDestCreationOptions != nullptr &&
4496 1521 : strstr(pszDestCreationOptions, "NATIVE_DATA") != nullptr &&
4497 20 : strstr(pszDestCreationOptions, "NATIVE_MEDIA_TYPE") != nullptr)
4498 : {
4499 20 : papszLCOTemp = CSLSetNameValue(
4500 : papszLCOTemp, "NATIVE_DATA",
4501 20 : poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA"));
4502 : papszLCOTemp =
4503 20 : CSLSetNameValue(papszLCOTemp, "NATIVE_MEDIA_TYPE",
4504 : poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE",
4505 20 : "NATIVE_DATA"));
4506 20 : CPLDebug("GDALVectorTranslate", "Transferring layer NATIVE_DATA");
4507 : }
4508 :
4509 : // For FileGeodatabase, automatically set
4510 : // CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES creation option if the source
4511 : // layer has a Shape_Area/Shape_Length field
4512 1483 : if (pszDestCreationOptions &&
4513 732 : strstr(pszDestCreationOptions,
4514 1483 : "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&
4515 12 : CSLFetchNameValue(m_papszLCO,
4516 : "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)
4517 : {
4518 12 : const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
4519 : const int nIdxShapeArea =
4520 12 : poSrcLayerDefn->GetFieldIndex("Shape_Area");
4521 : const int nIdxShapeLength =
4522 12 : poSrcLayerDefn->GetFieldIndex("Shape_Length");
4523 14 : if ((nIdxShapeArea >= 0 &&
4524 2 : poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=
4525 2 : nullptr &&
4526 2 : EQUAL(
4527 : poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),
4528 2 : "FILEGEODATABASE_SHAPE_AREA") &&
4529 2 : (m_papszSelFields == nullptr ||
4530 16 : CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||
4531 2 : (nIdxShapeLength >= 0 &&
4532 2 : poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=
4533 2 : nullptr &&
4534 2 : EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)
4535 : ->GetDefault(),
4536 2 : "FILEGEODATABASE_SHAPE_LENGTH") &&
4537 2 : (m_papszSelFields == nullptr ||
4538 0 : CSLFindString(m_papszSelFields, "Shape_Length") >= 0)))
4539 : {
4540 4 : papszLCOTemp = CSLSetNameValue(
4541 : papszLCOTemp, "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS", "YES");
4542 4 : CPLDebug("GDALVectorTranslate",
4543 : "Setting CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES");
4544 : }
4545 : }
4546 :
4547 : OGRGeomFieldDefn oGeomFieldDefn(
4548 : osGeomFieldName.c_str(),
4549 751 : static_cast<OGRwkbGeometryType>(eGCreateLayerType));
4550 751 : oGeomFieldDefn.SetSpatialRef(poOutputSRS);
4551 751 : oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);
4552 751 : oGeomFieldDefn.SetNullable(bGeomFieldNullable);
4553 751 : poDstLayer = m_poDstDS->CreateLayer(pszNewLayerName, &oGeomFieldDefn,
4554 : papszLCOTemp);
4555 751 : CSLDestroy(papszLCOTemp);
4556 :
4557 751 : if (poDstLayer == nullptr)
4558 : {
4559 2 : return nullptr;
4560 : }
4561 :
4562 : // Cf https://github.com/OSGeo/gdal/issues/6859
4563 : // warn if the user requests -t_srs but the driver uses a different SRS.
4564 772 : if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&
4565 : // MapInfo is somewhat lossy regarding SRS, so do not warn
4566 23 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))
4567 : {
4568 23 : auto poCreatedSRS = poDstLayer->GetSpatialRef();
4569 23 : if (poCreatedSRS != nullptr)
4570 : {
4571 18 : const char *const apszOptions[] = {
4572 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
4573 : "CRITERION=EQUIVALENT", nullptr};
4574 18 : if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))
4575 : {
4576 1 : const char *pszTargetSRSName = m_poOutputSRS->GetName();
4577 1 : const char *pszCreatedSRSName = poCreatedSRS->GetName();
4578 1 : CPLError(CE_Warning, CPLE_AppDefined,
4579 : "Target SRS %s not taken into account as target "
4580 : "driver likely implements on-the-fly reprojection "
4581 : "to %s",
4582 : pszTargetSRSName ? pszTargetSRSName : "",
4583 : pszCreatedSRSName ? pszCreatedSRSName : "");
4584 : }
4585 : }
4586 : }
4587 :
4588 749 : if (m_bCopyMD)
4589 : {
4590 1490 : const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());
4591 1078 : for (const char *pszMD : aosDomains)
4592 : {
4593 333 : if (!EQUAL(pszMD, "IMAGE_STRUCTURE") &&
4594 333 : !EQUAL(pszMD, "SUBDATASETS"))
4595 : {
4596 333 : if (char **papszMD = poSrcLayer->GetMetadata(pszMD))
4597 319 : poDstLayer->SetMetadata(papszMD, pszMD);
4598 : }
4599 : }
4600 : }
4601 :
4602 760 : if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4603 11 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4604 : {
4605 135 : for (int i = 0; i < nSrcGeomFieldCount; i++)
4606 : {
4607 125 : anRequestedGeomFields.push_back(i);
4608 : }
4609 : }
4610 :
4611 1512 : if (anRequestedGeomFields.size() > 1 ||
4612 738 : (anRequestedGeomFields.size() == 1 &&
4613 25 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))
4614 : {
4615 186 : for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());
4616 : i++)
4617 : {
4618 151 : const int iSrcGeomField = anRequestedGeomFields[i];
4619 : OGRGeomFieldDefn oGFldDefn(
4620 302 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));
4621 151 : if (m_poOutputSRS != nullptr)
4622 : {
4623 4 : auto poOutputSRSClone = m_poOutputSRS->Clone();
4624 4 : oGFldDefn.SetSpatialRef(poOutputSRSClone);
4625 4 : poOutputSRSClone->Release();
4626 : }
4627 151 : if (bForceGType)
4628 : {
4629 1 : oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
4630 : }
4631 : else
4632 : {
4633 150 : eGType = oGFldDefn.GetType();
4634 150 : eGType =
4635 150 : ConvertType(m_eGeomTypeConversion,
4636 : static_cast<OGRwkbGeometryType>(eGType));
4637 150 : eGType = ForceCoordDimension(eGType, m_nCoordDim);
4638 150 : oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
4639 : }
4640 151 : if (m_bForceNullable)
4641 2 : oGFldDefn.SetNullable(TRUE);
4642 151 : poDstLayer->CreateGeomField(&oGFldDefn);
4643 : }
4644 : }
4645 :
4646 749 : bAppend = false;
4647 : }
4648 :
4649 : /* -------------------------------------------------------------------- */
4650 : /* Otherwise we will append to it, if append was requested. */
4651 : /* -------------------------------------------------------------------- */
4652 40 : else if (!bAppend && !m_bNewDataSource)
4653 : {
4654 0 : CPLError(CE_Failure, CPLE_AppDefined,
4655 : "Layer %s already exists, and -append not specified.\n"
4656 : " Consider using -append, or -overwrite.",
4657 : pszNewLayerName);
4658 0 : return nullptr;
4659 : }
4660 : else
4661 : {
4662 40 : if (CSLCount(m_papszLCO) > 0)
4663 : {
4664 0 : CPLError(
4665 : CE_Warning, CPLE_AppDefined,
4666 : "Layer creation options ignored since an existing layer is\n"
4667 : " being appended to.");
4668 : }
4669 : }
4670 :
4671 : /* -------------------------------------------------------------------- */
4672 : /* Process Layer style table */
4673 : /* -------------------------------------------------------------------- */
4674 :
4675 789 : poDstLayer->SetStyleTable(poSrcLayer->GetStyleTable());
4676 : /* -------------------------------------------------------------------- */
4677 : /* Add fields. Default to copy all field. */
4678 : /* If only a subset of all fields requested, then output only */
4679 : /* the selected fields, and in the order that they were */
4680 : /* selected. */
4681 : /* -------------------------------------------------------------------- */
4682 789 : const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
4683 789 : int iSrcFIDField = -1;
4684 :
4685 : // Initialize the index-to-index map to -1's
4686 1578 : std::vector<int> anMap(nSrcFieldCount, -1);
4687 :
4688 1578 : std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;
4689 :
4690 : /* Determine if NUMERIC field width narrowing is allowed */
4691 : const char *pszSrcWidthIncludesDecimalSeparator{
4692 789 : m_poSrcDS->GetDriver()->GetMetadataItem(
4693 789 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
4694 789 : const bool bSrcWidthIncludesDecimalSeparator{
4695 1012 : pszSrcWidthIncludesDecimalSeparator &&
4696 223 : EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};
4697 : const char *pszDstWidthIncludesDecimalSeparator{
4698 789 : m_poDstDS->GetDriver()->GetMetadataItem(
4699 789 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
4700 789 : const bool bDstWidthIncludesDecimalSeparator{
4701 934 : pszDstWidthIncludesDecimalSeparator &&
4702 145 : EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};
4703 : const char *pszSrcWidthIncludesMinusSign{
4704 789 : m_poSrcDS->GetDriver()->GetMetadataItem(
4705 789 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
4706 789 : const bool bSrcWidthIncludesMinusSign{
4707 1012 : pszSrcWidthIncludesMinusSign &&
4708 223 : EQUAL(pszSrcWidthIncludesMinusSign, "YES")};
4709 : const char *pszDstWidthIncludesMinusSign{
4710 789 : m_poDstDS->GetDriver()->GetMetadataItem(
4711 789 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
4712 789 : const bool bDstWidthIncludesMinusSign{
4713 934 : pszDstWidthIncludesMinusSign &&
4714 145 : EQUAL(pszDstWidthIncludesMinusSign, "YES")};
4715 :
4716 : // Calculate width delta
4717 789 : int iChangeWidthBy{0};
4718 :
4719 789 : if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)
4720 : {
4721 127 : iChangeWidthBy--;
4722 : }
4723 662 : else if (!bSrcWidthIncludesDecimalSeparator &&
4724 : bDstWidthIncludesDecimalSeparator)
4725 : {
4726 49 : iChangeWidthBy++;
4727 : }
4728 :
4729 : // We cannot assume there is no minus sign, we can only inflate here
4730 789 : if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)
4731 : {
4732 49 : iChangeWidthBy++;
4733 : }
4734 :
4735 789 : bool bError = false;
4736 789 : const bool bUseWriteArrowBatch = CanUseWriteArrowBatch(
4737 : poSrcLayer, poDstLayer, bJustCreatedLayer, psOptions, bError);
4738 789 : if (bError)
4739 0 : return nullptr;
4740 :
4741 : /* Caution : at the time of writing, the MapInfo driver */
4742 : /* returns NULL until a field has been added */
4743 789 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
4744 :
4745 789 : if (bUseWriteArrowBatch)
4746 : {
4747 : // Fields created above
4748 : }
4749 662 : else if (m_papszFieldMap && bAppend)
4750 : {
4751 2 : bool bIdentity = false;
4752 :
4753 2 : if (EQUAL(m_papszFieldMap[0], "identity"))
4754 1 : bIdentity = true;
4755 1 : else if (CSLCount(m_papszFieldMap) != nSrcFieldCount)
4756 : {
4757 0 : CPLError(
4758 : CE_Failure, CPLE_AppDefined,
4759 : "Field map should contain the value 'identity' or "
4760 : "the same number of integer values as the source field count.");
4761 0 : return nullptr;
4762 : }
4763 :
4764 32 : for (int iField = 0; iField < nSrcFieldCount; iField++)
4765 : {
4766 30 : anMap[iField] = bIdentity ? iField : atoi(m_papszFieldMap[iField]);
4767 30 : if (anMap[iField] >= poDstFDefn->GetFieldCount())
4768 : {
4769 0 : CPLError(CE_Failure, CPLE_AppDefined,
4770 0 : "Invalid destination field index %d.", anMap[iField]);
4771 0 : return nullptr;
4772 : }
4773 2 : }
4774 : }
4775 660 : else if (m_bSelFieldsSet && !bAppend)
4776 : {
4777 15 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
4778 40 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4779 : iField++)
4780 : {
4781 : const int iSrcField =
4782 25 : poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4783 25 : if (iSrcField >= 0)
4784 : {
4785 : OGRFieldDefn *poSrcFieldDefn =
4786 22 : poSrcFDefn->GetFieldDefn(iSrcField);
4787 44 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
4788 :
4789 22 : DoFieldTypeConversion(
4790 : m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
4791 22 : m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
4792 22 : m_bForceNullable, m_bUnsetDefault);
4793 :
4794 22 : if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
4795 0 : oFieldDefn.GetWidth() != 0)
4796 : {
4797 0 : oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
4798 : }
4799 :
4800 : /* The field may have been already created at layer creation */
4801 : const int iDstField =
4802 : poDstFDefn
4803 22 : ? poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef())
4804 22 : : -1;
4805 22 : if (iDstField >= 0)
4806 : {
4807 0 : anMap[iSrcField] = iDstField;
4808 : }
4809 22 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
4810 : {
4811 : /* now that we've created a field, GetLayerDefn() won't
4812 : * return NULL */
4813 22 : if (poDstFDefn == nullptr)
4814 0 : poDstFDefn = poDstLayer->GetLayerDefn();
4815 :
4816 : /* Sanity check : if it fails, the driver is buggy */
4817 44 : if (poDstFDefn != nullptr &&
4818 22 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
4819 : {
4820 0 : CPLError(CE_Warning, CPLE_AppDefined,
4821 : "The output driver has claimed to have added "
4822 : "the %s field, but it did not!",
4823 : oFieldDefn.GetNameRef());
4824 : }
4825 : else
4826 : {
4827 22 : anMap[iSrcField] = nDstFieldCount;
4828 22 : nDstFieldCount++;
4829 : }
4830 : }
4831 : }
4832 : }
4833 :
4834 : /* --------------------------------------------------------------------
4835 : */
4836 : /* Use SetIgnoredFields() on source layer if available */
4837 : /* --------------------------------------------------------------------
4838 : */
4839 15 : if (poSrcLayer->TestCapability(OLCIgnoreFields))
4840 : {
4841 10 : bool bUseIgnoredFields = true;
4842 10 : char **papszWHEREUsedFields = nullptr;
4843 :
4844 10 : if (m_pszWHERE)
4845 : {
4846 : /* We must not ignore fields used in the -where expression
4847 : * (#4015) */
4848 4 : OGRFeatureQuery oFeatureQuery;
4849 2 : if (oFeatureQuery.Compile(poSrcLayer->GetLayerDefn(),
4850 : m_pszWHERE, FALSE,
4851 2 : nullptr) == OGRERR_NONE)
4852 : {
4853 0 : papszWHEREUsedFields = oFeatureQuery.GetUsedFields();
4854 : }
4855 : else
4856 : {
4857 2 : bUseIgnoredFields = false;
4858 : }
4859 : }
4860 :
4861 10 : char **papszIgnoredFields = nullptr;
4862 :
4863 32 : for (int iSrcField = 0;
4864 32 : bUseIgnoredFields && iSrcField < poSrcFDefn->GetFieldCount();
4865 : iSrcField++)
4866 : {
4867 : const char *pszFieldName =
4868 22 : poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();
4869 22 : bool bFieldRequested = false;
4870 44 : for (int iField = 0;
4871 44 : m_papszSelFields && m_papszSelFields[iField]; iField++)
4872 : {
4873 33 : if (EQUAL(pszFieldName, m_papszSelFields[iField]))
4874 : {
4875 11 : bFieldRequested = true;
4876 11 : break;
4877 : }
4878 : }
4879 22 : bFieldRequested |=
4880 22 : CSLFindString(papszWHEREUsedFields, pszFieldName) >= 0;
4881 22 : bFieldRequested |= (m_pszZField != nullptr &&
4882 0 : EQUAL(pszFieldName, m_pszZField));
4883 :
4884 : /* If source field not requested, add it to ignored files list
4885 : */
4886 22 : if (!bFieldRequested)
4887 : papszIgnoredFields =
4888 11 : CSLAddString(papszIgnoredFields, pszFieldName);
4889 : }
4890 10 : if (bUseIgnoredFields)
4891 8 : poSrcLayer->SetIgnoredFields(
4892 8 : const_cast<const char **>(papszIgnoredFields));
4893 10 : CSLDestroy(papszIgnoredFields);
4894 10 : CSLDestroy(papszWHEREUsedFields);
4895 15 : }
4896 : }
4897 645 : else if (!bAppend || m_bAddMissingFields)
4898 : {
4899 617 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
4900 :
4901 : const bool caseInsensitive =
4902 617 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");
4903 12367 : const auto formatName = [caseInsensitive](const char *name)
4904 : {
4905 12367 : if (caseInsensitive)
4906 : {
4907 24150 : return CPLString(name).toupper();
4908 : }
4909 : else
4910 : {
4911 292 : return CPLString(name);
4912 : }
4913 617 : };
4914 :
4915 : /* Save the map of existing fields, before creating new ones */
4916 : /* This helps when converting a source layer that has duplicated field
4917 : * names */
4918 : /* which is a bad idea */
4919 1234 : std::map<CPLString, int> oMapPreExistingFields;
4920 1234 : std::unordered_set<std::string> oSetDstFieldNames;
4921 762 : for (int iField = 0; iField < nDstFieldCount; iField++)
4922 : {
4923 : const char *pszFieldName =
4924 145 : poDstFDefn->GetFieldDefn(iField)->GetNameRef();
4925 290 : CPLString osUpperFieldName(formatName(pszFieldName));
4926 145 : oSetDstFieldNames.insert(osUpperFieldName);
4927 145 : if (oMapPreExistingFields.find(osUpperFieldName) ==
4928 290 : oMapPreExistingFields.end())
4929 145 : oMapPreExistingFields[osUpperFieldName] = iField;
4930 : /*else
4931 : CPLError(CE_Warning, CPLE_AppDefined,
4932 : "The target layer has already a duplicated field name
4933 : '%s' before " "adding the fields of the source layer",
4934 : pszFieldName); */
4935 : }
4936 :
4937 617 : const char *pszFIDColumn = poDstLayer->GetFIDColumn();
4938 :
4939 1234 : std::vector<int> anSrcFieldIndices;
4940 617 : if (m_bSelFieldsSet)
4941 : {
4942 2 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4943 : iField++)
4944 : {
4945 : const int iSrcField =
4946 1 : poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4947 1 : if (iSrcField >= 0)
4948 : {
4949 1 : anSrcFieldIndices.push_back(iSrcField);
4950 : }
4951 : }
4952 : }
4953 : else
4954 : {
4955 3733 : for (int iField = 0; iField < nSrcFieldCount; iField++)
4956 : {
4957 3117 : anSrcFieldIndices.push_back(iField);
4958 : }
4959 : }
4960 :
4961 1234 : std::unordered_set<std::string> oSetSrcFieldNames;
4962 3736 : for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)
4963 : {
4964 : oSetSrcFieldNames.insert(
4965 3119 : formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));
4966 : }
4967 :
4968 : // For each source field name, memorize the last number suffix to have
4969 : // unique field names in the target. Let's imagine we have a source
4970 : // layer with the field name foo repeated twice After dealing the first
4971 : // field, oMapFieldNameToLastSuffix["foo"] will be 1, so when starting a
4972 : // unique name for the second field, we'll be able to start at 2. This
4973 : // avoids quadratic complexity if a big number of source field names are
4974 : // identical. Like in
4975 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37768
4976 1234 : std::map<std::string, int> oMapFieldNameToLastSuffix;
4977 :
4978 3735 : for (size_t i = 0; i < anSrcFieldIndices.size(); i++)
4979 : {
4980 3118 : const int iField = anSrcFieldIndices[i];
4981 : const OGRFieldDefn *poSrcFieldDefn =
4982 3118 : poSrcFDefn->GetFieldDefn(iField);
4983 3118 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
4984 :
4985 : // Avoid creating a field with the same name as the FID column
4986 6237 : if (pszFIDColumn != nullptr &&
4987 3119 : EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&
4988 1 : (oFieldDefn.GetType() == OFTInteger ||
4989 0 : oFieldDefn.GetType() == OFTInteger64))
4990 : {
4991 1 : iSrcFIDField = iField;
4992 1 : continue;
4993 : }
4994 :
4995 3117 : DoFieldTypeConversion(
4996 : m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
4997 3117 : m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
4998 3117 : m_bForceNullable, m_bUnsetDefault);
4999 :
5000 3252 : if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5001 135 : oFieldDefn.GetWidth() != 0)
5002 : {
5003 95 : oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5004 : }
5005 :
5006 : /* The field may have been already created at layer creation */
5007 : {
5008 : const auto oIter = oMapPreExistingFields.find(
5009 3117 : formatName(oFieldDefn.GetNameRef()));
5010 3117 : if (oIter != oMapPreExistingFields.end())
5011 : {
5012 115 : anMap[iField] = oIter->second;
5013 115 : continue;
5014 : }
5015 : }
5016 :
5017 3002 : bool bHasRenamed = false;
5018 : /* In case the field name already exists in the target layer, */
5019 : /* build a unique field name */
5020 3002 : if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=
5021 6004 : oSetDstFieldNames.end())
5022 : {
5023 : const CPLString osTmpNameRaddixUC(
5024 4 : formatName(oFieldDefn.GetNameRef()));
5025 2 : int nTry = 1;
5026 : const auto oIter =
5027 2 : oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);
5028 2 : if (oIter != oMapFieldNameToLastSuffix.end())
5029 1 : nTry = oIter->second;
5030 2 : CPLString osTmpNameUC = osTmpNameRaddixUC;
5031 2 : osTmpNameUC.reserve(osTmpNameUC.size() + 10);
5032 : while (true)
5033 : {
5034 3 : ++nTry;
5035 : char szTry[32];
5036 3 : snprintf(szTry, sizeof(szTry), "%d", nTry);
5037 : osTmpNameUC.replace(osTmpNameRaddixUC.size(),
5038 3 : std::string::npos, szTry);
5039 :
5040 : /* Check that the proposed name doesn't exist either in the
5041 : * already */
5042 : /* created fields or in the source fields */
5043 3 : if (oSetDstFieldNames.find(osTmpNameUC) ==
5044 9 : oSetDstFieldNames.end() &&
5045 3 : oSetSrcFieldNames.find(osTmpNameUC) ==
5046 6 : oSetSrcFieldNames.end())
5047 : {
5048 2 : bHasRenamed = true;
5049 2 : oFieldDefn.SetName(
5050 4 : (CPLString(oFieldDefn.GetNameRef()) + szTry)
5051 : .c_str());
5052 2 : oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;
5053 2 : break;
5054 : }
5055 1 : }
5056 : }
5057 :
5058 : // Create field domain in output dataset if not already existing.
5059 6004 : const std::string osDomainName(oFieldDefn.GetDomainName());
5060 3002 : if (!osDomainName.empty())
5061 : {
5062 32 : if (m_poDstDS->TestCapability(ODsCAddFieldDomain) &&
5063 16 : m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5064 : {
5065 : const auto poSrcDomain =
5066 16 : m_poSrcDS->GetFieldDomain(osDomainName);
5067 16 : if (poSrcDomain)
5068 : {
5069 28 : std::string failureReason;
5070 14 : if (!m_poDstDS->AddFieldDomain(
5071 28 : std::unique_ptr<OGRFieldDomain>(
5072 14 : poSrcDomain->Clone()),
5073 14 : failureReason))
5074 : {
5075 0 : oFieldDefn.SetDomainName(std::string());
5076 0 : CPLDebug("OGR2OGR", "Cannot create domain %s: %s",
5077 : osDomainName.c_str(),
5078 : failureReason.c_str());
5079 : }
5080 : }
5081 : else
5082 : {
5083 2 : CPLDebug("OGR2OGR",
5084 : "Cannot find domain %s in source dataset",
5085 : osDomainName.c_str());
5086 : }
5087 : }
5088 16 : if (m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5089 : {
5090 2 : oFieldDefn.SetDomainName(std::string());
5091 : }
5092 : }
5093 :
5094 3002 : if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5095 : {
5096 : /* now that we've created a field, GetLayerDefn() won't return
5097 : * NULL */
5098 2982 : if (poDstFDefn == nullptr)
5099 0 : poDstFDefn = poDstLayer->GetLayerDefn();
5100 :
5101 : /* Sanity check : if it fails, the driver is buggy */
5102 5964 : if (poDstFDefn != nullptr &&
5103 2982 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5104 : {
5105 0 : CPLError(CE_Warning, CPLE_AppDefined,
5106 : "The output driver has claimed to have added the "
5107 : "%s field, but it did not!",
5108 : oFieldDefn.GetNameRef());
5109 : }
5110 : else
5111 : {
5112 2982 : if (poDstFDefn != nullptr)
5113 : {
5114 : const char *pszNewFieldName =
5115 2982 : poDstFDefn->GetFieldDefn(nDstFieldCount)
5116 2982 : ->GetNameRef();
5117 2982 : if (bHasRenamed)
5118 : {
5119 2 : CPLError(CE_Warning, CPLE_AppDefined,
5120 : "Field '%s' already exists. Renaming it "
5121 : "as '%s'",
5122 : poSrcFieldDefn->GetNameRef(),
5123 : pszNewFieldName);
5124 : }
5125 2982 : oSetDstFieldNames.insert(formatName(pszNewFieldName));
5126 : }
5127 :
5128 2982 : anMap[iField] = nDstFieldCount;
5129 2982 : nDstFieldCount++;
5130 : }
5131 : }
5132 :
5133 3002 : if (m_bResolveDomains && !osDomainName.empty())
5134 : {
5135 : const auto poSrcDomain =
5136 3 : m_poSrcDS->GetFieldDomain(osDomainName);
5137 3 : if (poSrcDomain && poSrcDomain->GetDomainType() == OFDT_CODED)
5138 : {
5139 : OGRFieldDefn oResolvedField(
5140 : CPLSPrintf("%s_resolved", oFieldDefn.GetNameRef()),
5141 2 : OFTString);
5142 1 : if (poDstLayer->CreateField(&oResolvedField) == OGRERR_NONE)
5143 : {
5144 : TargetLayerInfo::ResolvedInfo resolvedInfo;
5145 1 : resolvedInfo.nSrcField = iField;
5146 1 : resolvedInfo.poDomain = poSrcDomain;
5147 1 : oMapResolved[nDstFieldCount] = resolvedInfo;
5148 1 : nDstFieldCount++;
5149 : }
5150 : }
5151 : }
5152 617 : }
5153 : }
5154 : else
5155 : {
5156 : /* For an existing layer, build the map by fetching the index in the
5157 : * destination */
5158 : /* layer for each source field */
5159 28 : if (poDstFDefn == nullptr)
5160 : {
5161 0 : CPLError(CE_Failure, CPLE_AppDefined, "poDstFDefn == NULL.");
5162 0 : return nullptr;
5163 : }
5164 :
5165 95 : for (int iField = 0; iField < nSrcFieldCount; iField++)
5166 : {
5167 67 : OGRFieldDefn *poSrcFieldDefn = poSrcFDefn->GetFieldDefn(iField);
5168 67 : const int iDstField = poDstLayer->FindFieldIndex(
5169 67 : poSrcFieldDefn->GetNameRef(), m_bExactFieldNameMatch);
5170 67 : if (iDstField >= 0)
5171 64 : anMap[iField] = iDstField;
5172 : else
5173 3 : CPLDebug(
5174 : "GDALVectorTranslate",
5175 : "Skipping field '%s' not found in destination layer '%s'.",
5176 3 : poSrcFieldDefn->GetNameRef(), poDstLayer->GetName());
5177 : }
5178 : }
5179 :
5180 12 : if (bOverwriteActuallyDone && !bAddOverwriteLCO &&
5181 12 : EQUAL(m_poDstDS->GetDriver()->GetDescription(), "PostgreSQL") &&
5182 807 : !psOptions->nLayerTransaction && psOptions->nGroupTransactions > 0 &&
5183 6 : CPLTestBool(CPLGetConfigOption("PG_COMMIT_WHEN_OVERWRITING", "YES")))
5184 : {
5185 6 : CPLDebug("GDALVectorTranslate",
5186 : "Forcing transaction commit as table overwriting occurred");
5187 : // Commit when overwriting as this consumes a lot of PG resources
5188 : // and could result in """out of shared memory.
5189 : // You might need to increase max_locks_per_transaction."""" errors
5190 12 : if (m_poDstDS->CommitTransaction() == OGRERR_FAILURE ||
5191 6 : m_poDstDS->StartTransaction(psOptions->bForceTransaction) ==
5192 : OGRERR_FAILURE)
5193 : {
5194 0 : return nullptr;
5195 : }
5196 6 : nTotalEventsDone = 0;
5197 : }
5198 :
5199 1578 : std::unique_ptr<TargetLayerInfo> psInfo(new TargetLayerInfo);
5200 789 : psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;
5201 789 : psInfo->m_nFeaturesRead = 0;
5202 789 : psInfo->m_bPerFeatureCT = false;
5203 789 : psInfo->m_poSrcLayer = poSrcLayer;
5204 789 : psInfo->m_poDstLayer = poDstLayer;
5205 789 : psInfo->m_aoReprojectionInfo.resize(
5206 789 : poDstLayer->GetLayerDefn()->GetGeomFieldCount());
5207 789 : psInfo->m_anMap = std::move(anMap);
5208 789 : psInfo->m_iSrcZField = iSrcZField;
5209 789 : psInfo->m_iSrcFIDField = iSrcFIDField;
5210 789 : if (anRequestedGeomFields.size() == 1)
5211 25 : psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];
5212 : else
5213 764 : psInfo->m_iRequestedSrcGeomField = -1;
5214 789 : psInfo->m_bPreserveFID = bPreserveFID;
5215 789 : psInfo->m_pszCTPipeline = m_pszCTPipeline;
5216 789 : psInfo->m_oMapResolved = std::move(oMapResolved);
5217 790 : for (const auto &kv : psInfo->m_oMapResolved)
5218 : {
5219 1 : const auto poDomain = kv.second.poDomain;
5220 : const auto poCodedDomain =
5221 1 : cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);
5222 1 : const auto enumeration = poCodedDomain->GetEnumeration();
5223 2 : std::map<std::string, std::string> oMapCodeValue;
5224 4 : for (int i = 0; enumeration[i].pszCode != nullptr; ++i)
5225 : {
5226 6 : oMapCodeValue[enumeration[i].pszCode] =
5227 6 : enumeration[i].pszValue ? enumeration[i].pszValue : "";
5228 : }
5229 1 : psInfo->m_oMapDomainToKV[poDomain] = std::move(oMapCodeValue);
5230 : }
5231 :
5232 : // Detect if we can directly pass the source feature to the CreateFeature()
5233 : // method of the target layer, without doing any copying of field content.
5234 789 : psInfo->m_bCanAvoidSetFrom = false;
5235 789 : if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)
5236 : {
5237 783 : psInfo->m_bCanAvoidSetFrom = true;
5238 783 : const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5239 783 : if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||
5240 : nSrcGeomFieldCount != nDstGeomFieldCount)
5241 : {
5242 152 : psInfo->m_bCanAvoidSetFrom = false;
5243 : }
5244 : else
5245 : {
5246 3386 : for (int i = 0; i < nSrcFieldCount; ++i)
5247 : {
5248 2783 : auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);
5249 2783 : auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);
5250 5553 : if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||
5251 2770 : psInfo->m_anMap[i] != i)
5252 : {
5253 28 : psInfo->m_bCanAvoidSetFrom = false;
5254 28 : break;
5255 : }
5256 : }
5257 631 : if (!psInfo->m_bCanAvoidSetFrom && nSrcGeomFieldCount > 1)
5258 : {
5259 4 : for (int i = 0; i < nSrcGeomFieldCount; ++i)
5260 : {
5261 3 : auto poSrcGeomFieldDefn = poSrcFDefn->GetGeomFieldDefn(i);
5262 3 : auto poDstGeomFieldDefn = poDstFDefn->GetGeomFieldDefn(i);
5263 3 : if (!EQUAL(poSrcGeomFieldDefn->GetNameRef(),
5264 : poDstGeomFieldDefn->GetNameRef()))
5265 : {
5266 1 : psInfo->m_bCanAvoidSetFrom = false;
5267 1 : break;
5268 : }
5269 : }
5270 : }
5271 : }
5272 : }
5273 :
5274 1578 : psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()
5275 789 : ? nullptr
5276 4 : : psOptions->osSpatSRSDef.c_str();
5277 789 : psInfo->m_hSpatialFilter =
5278 789 : OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());
5279 789 : psInfo->m_pszGeomField =
5280 789 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;
5281 :
5282 789 : if (psOptions->nTZOffsetInSec != TZ_OFFSET_INVALID && poDstFDefn)
5283 : {
5284 15 : for (int i = 0; i < poDstFDefn->GetFieldCount(); ++i)
5285 : {
5286 10 : if (poDstFDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
5287 : {
5288 5 : psInfo->m_anDateTimeFieldIdx.push_back(i);
5289 : }
5290 : }
5291 : }
5292 :
5293 789 : psInfo->m_bSupportCurves =
5294 789 : CPL_TO_BOOL(poDstLayer->TestCapability(OLCCurveGeometries));
5295 :
5296 789 : return psInfo;
5297 : }
5298 :
5299 : /************************************************************************/
5300 : /* SetupCT() */
5301 : /************************************************************************/
5302 :
5303 : static bool
5304 628 : SetupCT(TargetLayerInfo *psInfo, OGRLayer *poSrcLayer, bool bTransform,
5305 : bool bWrapDateline, const CPLString &osDateLineOffset,
5306 : const OGRSpatialReference *poUserSourceSRS, OGRFeature *poFeature,
5307 : const OGRSpatialReference *poOutputSRS,
5308 : OGRCoordinateTransformation *poGCPCoordTrans, bool bVerboseError)
5309 : {
5310 628 : OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5311 : const int nDstGeomFieldCount =
5312 628 : poDstLayer->GetLayerDefn()->GetGeomFieldCount();
5313 1216 : for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
5314 : {
5315 : /* --------------------------------------------------------------------
5316 : */
5317 : /* Setup coordinate transformation if we need it. */
5318 : /* --------------------------------------------------------------------
5319 : */
5320 589 : const OGRSpatialReference *poSourceSRS = nullptr;
5321 589 : OGRCoordinateTransformation *poCT = nullptr;
5322 589 : char **papszTransformOptions = nullptr;
5323 :
5324 : int iSrcGeomField;
5325 : auto poDstGeomFieldDefn =
5326 589 : poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
5327 589 : if (psInfo->m_iRequestedSrcGeomField >= 0)
5328 : {
5329 23 : iSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5330 : }
5331 : else
5332 : {
5333 1132 : iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
5334 566 : poDstGeomFieldDefn->GetNameRef());
5335 566 : if (iSrcGeomField < 0)
5336 : {
5337 218 : if (nDstGeomFieldCount == 1 &&
5338 109 : poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
5339 : {
5340 103 : iSrcGeomField = 0;
5341 : }
5342 : else
5343 : {
5344 6 : continue;
5345 : }
5346 : }
5347 : }
5348 :
5349 583 : if (psInfo->m_nFeaturesRead == 0)
5350 : {
5351 582 : poSourceSRS = poUserSourceSRS;
5352 582 : if (poSourceSRS == nullptr)
5353 : {
5354 576 : if (iSrcGeomField > 0)
5355 118 : poSourceSRS = poSrcLayer->GetLayerDefn()
5356 118 : ->GetGeomFieldDefn(iSrcGeomField)
5357 118 : ->GetSpatialRef();
5358 : else
5359 458 : poSourceSRS = poSrcLayer->GetSpatialRef();
5360 : }
5361 : }
5362 583 : if (poSourceSRS == nullptr)
5363 : {
5364 246 : if (poFeature == nullptr)
5365 : {
5366 1 : if (bVerboseError)
5367 : {
5368 0 : CPLError(CE_Failure, CPLE_AppDefined,
5369 : "Non-null feature expected to set transformation");
5370 : }
5371 1 : return false;
5372 : }
5373 : OGRGeometry *poSrcGeometry =
5374 245 : poFeature->GetGeomFieldRef(iSrcGeomField);
5375 245 : if (poSrcGeometry)
5376 204 : poSourceSRS = poSrcGeometry->getSpatialReference();
5377 245 : psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);
5378 : }
5379 :
5380 582 : if (bTransform)
5381 : {
5382 25 : if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)
5383 : {
5384 0 : CPLError(CE_Failure, CPLE_AppDefined,
5385 : "Can't transform coordinates, source layer has no\n"
5386 : "coordinate system. Use -s_srs to set one.");
5387 :
5388 0 : return false;
5389 : }
5390 :
5391 25 : if (psInfo->m_pszCTPipeline == nullptr)
5392 : {
5393 22 : CPLAssert(nullptr != poSourceSRS);
5394 22 : CPLAssert(nullptr != poOutputSRS);
5395 : }
5396 :
5397 25 : if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)
5398 : {
5399 : const auto &supportedSRSList =
5400 23 : poSrcLayer->GetSupportedSRSList(iGeom);
5401 23 : if (!supportedSRSList.empty())
5402 : {
5403 1 : const char *const apszOptions[] = {
5404 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
5405 1 : for (const auto &poSRS : supportedSRSList)
5406 : {
5407 1 : if (poSRS->IsSame(poOutputSRS, apszOptions))
5408 : {
5409 2 : OGRSpatialReference oSourceSRSBackup;
5410 1 : if (poSourceSRS)
5411 1 : oSourceSRSBackup = *poSourceSRS;
5412 1 : if (poSrcLayer->SetActiveSRS(iGeom, poSRS.get()) ==
5413 : OGRERR_NONE)
5414 : {
5415 1 : CPLDebug("ogr2ogr",
5416 : "Switching layer active SRS to %s",
5417 : poSRS->GetName());
5418 :
5419 1 : if (psInfo->m_hSpatialFilter != nullptr &&
5420 0 : ((psInfo->m_iRequestedSrcGeomField < 0 &&
5421 0 : iGeom == 0) ||
5422 : (iGeom ==
5423 0 : psInfo->m_iRequestedSrcGeomField)))
5424 : {
5425 0 : OGRSpatialReference oSpatSRS;
5426 0 : oSpatSRS.SetAxisMappingStrategy(
5427 : OAMS_TRADITIONAL_GIS_ORDER);
5428 0 : if (psInfo->m_pszSpatSRSDef)
5429 0 : oSpatSRS.SetFromUserInput(
5430 : psInfo->m_pszSpatSRSDef);
5431 0 : ApplySpatialFilter(
5432 : poSrcLayer,
5433 : OGRGeometry::FromHandle(
5434 : psInfo->m_hSpatialFilter),
5435 0 : !oSpatSRS.IsEmpty() ? &oSpatSRS
5436 0 : : !oSourceSRSBackup.IsEmpty()
5437 : ? &oSourceSRSBackup
5438 : : nullptr,
5439 : psInfo->m_pszGeomField, poOutputSRS);
5440 : }
5441 :
5442 1 : bTransform = false;
5443 : }
5444 1 : break;
5445 : }
5446 : }
5447 : }
5448 : }
5449 :
5450 25 : if (!bTransform)
5451 : {
5452 : // do nothing
5453 : }
5454 25 : else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&
5455 1 : psInfo->m_aoReprojectionInfo[iGeom]
5456 1 : .m_poCT->GetSourceCS() == poSourceSRS)
5457 : {
5458 0 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5459 : }
5460 : else
5461 : {
5462 24 : OGRCoordinateTransformationOptions options;
5463 24 : if (psInfo->m_pszCTPipeline)
5464 : {
5465 3 : options.SetCoordinateOperation(psInfo->m_pszCTPipeline,
5466 : false);
5467 : }
5468 24 : poCT = OGRCreateCoordinateTransformation(poSourceSRS,
5469 : poOutputSRS, options);
5470 24 : if (poCT == nullptr)
5471 : {
5472 0 : char *pszWKT = nullptr;
5473 :
5474 0 : CPLError(CE_Failure, CPLE_AppDefined,
5475 : "Failed to create coordinate transformation "
5476 : "between the\n"
5477 : "following coordinate systems. This may be "
5478 : "because they\n"
5479 : "are not transformable.");
5480 :
5481 0 : if (poSourceSRS)
5482 : {
5483 0 : poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
5484 0 : CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
5485 : pszWKT);
5486 0 : CPLFree(pszWKT);
5487 : }
5488 :
5489 0 : if (poOutputSRS)
5490 : {
5491 0 : poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
5492 0 : CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
5493 : pszWKT);
5494 0 : CPLFree(pszWKT);
5495 : }
5496 :
5497 0 : return false;
5498 : }
5499 24 : poCT = new CompositeCT(poGCPCoordTrans, false, poCT, true);
5500 24 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(poCT);
5501 24 : psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =
5502 47 : !(poGCPCoordTrans == nullptr && poSourceSRS &&
5503 23 : poSourceSRS->IsGeographic() && poOutputSRS &&
5504 3 : poOutputSRS->IsGeographic());
5505 : }
5506 : }
5507 : else
5508 : {
5509 557 : const char *const apszOptions[] = {
5510 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
5511 : "CRITERION=EQUIVALENT", nullptr};
5512 : auto poDstGeomFieldDefnSpatialRef =
5513 557 : poDstGeomFieldDefn->GetSpatialRef();
5514 314 : if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&
5515 240 : poSourceSRS->GetDataAxisToSRSAxisMapping() !=
5516 : poDstGeomFieldDefnSpatialRef
5517 871 : ->GetDataAxisToSRSAxisMapping() &&
5518 2 : poSourceSRS->IsSame(poDstGeomFieldDefnSpatialRef, apszOptions))
5519 : {
5520 0 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(
5521 : new CompositeCT(
5522 0 : new AxisMappingCoordinateTransformation(
5523 0 : poSourceSRS->GetDataAxisToSRSAxisMapping(),
5524 : poDstGeomFieldDefnSpatialRef
5525 0 : ->GetDataAxisToSRSAxisMapping()),
5526 0 : true, poGCPCoordTrans, false));
5527 0 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5528 : }
5529 557 : else if (poGCPCoordTrans)
5530 : {
5531 8 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(
5532 4 : new CompositeCT(poGCPCoordTrans, false, nullptr, false));
5533 4 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5534 : }
5535 : }
5536 :
5537 582 : if (bWrapDateline)
5538 : {
5539 5 : if (bTransform && poCT != nullptr && poOutputSRS != nullptr &&
5540 1 : poOutputSRS->IsGeographic())
5541 : {
5542 : papszTransformOptions =
5543 1 : CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
5544 1 : if (!osDateLineOffset.empty())
5545 : {
5546 1 : CPLString soOffset("DATELINEOFFSET=");
5547 1 : soOffset += osDateLineOffset;
5548 : papszTransformOptions =
5549 1 : CSLAddString(papszTransformOptions, soOffset);
5550 : }
5551 : }
5552 3 : else if (poSourceSRS != nullptr && poSourceSRS->IsGeographic())
5553 : {
5554 : papszTransformOptions =
5555 3 : CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
5556 3 : if (!osDateLineOffset.empty())
5557 : {
5558 3 : CPLString soOffset("DATELINEOFFSET=");
5559 3 : soOffset += osDateLineOffset;
5560 : papszTransformOptions =
5561 3 : CSLAddString(papszTransformOptions, soOffset);
5562 : }
5563 : }
5564 : else
5565 : {
5566 : static bool bHasWarned = false;
5567 0 : if (!bHasWarned)
5568 0 : CPLError(CE_Failure, CPLE_IllegalArg,
5569 : "-wrapdateline option only works when "
5570 : "reprojecting to a geographic SRS");
5571 0 : bHasWarned = true;
5572 : }
5573 :
5574 4 : psInfo->m_aoReprojectionInfo[iGeom].m_aosTransformOptions.Assign(
5575 4 : papszTransformOptions);
5576 : }
5577 : }
5578 627 : return true;
5579 : }
5580 :
5581 : /************************************************************************/
5582 : /* LayerTranslator::TranslateArrow() */
5583 : /************************************************************************/
5584 :
5585 127 : bool LayerTranslator::TranslateArrow(
5586 : const TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,
5587 : GIntBig *pnReadFeatureCount, GDALProgressFunc pfnProgress,
5588 : void *pProgressArg, const GDALVectorTranslateOptions *psOptions)
5589 : {
5590 : struct ArrowArrayStream stream;
5591 : struct ArrowSchema schema;
5592 254 : CPLStringList aosOptionsGetArrowStream;
5593 254 : CPLStringList aosOptionsWriteArrowBatch;
5594 127 : aosOptionsGetArrowStream.SetNameValue("GEOMETRY_ENCODING", "WKB");
5595 127 : if (!psInfo->m_bPreserveFID)
5596 119 : aosOptionsGetArrowStream.SetNameValue("INCLUDE_FID", "NO");
5597 : else
5598 : {
5599 : aosOptionsWriteArrowBatch.SetNameValue(
5600 8 : "FID", psInfo->m_poSrcLayer->GetFIDColumn());
5601 : aosOptionsWriteArrowBatch.SetNameValue("IF_FID_NOT_PRESERVED",
5602 8 : "WARNING");
5603 : }
5604 127 : if (psOptions->nLimit >= 0)
5605 : {
5606 : aosOptionsGetArrowStream.SetNameValue(
5607 : "MAX_FEATURES_IN_BATCH",
5608 : CPLSPrintf(CPL_FRMT_GIB,
5609 2 : std::min<GIntBig>(psOptions->nLimit,
5610 2 : (psOptions->nGroupTransactions > 0
5611 4 : ? psOptions->nGroupTransactions
5612 2 : : 65536))));
5613 : }
5614 125 : else if (psOptions->nGroupTransactions > 0)
5615 : {
5616 : aosOptionsGetArrowStream.SetNameValue(
5617 : "MAX_FEATURES_IN_BATCH",
5618 125 : CPLSPrintf("%d", psOptions->nGroupTransactions));
5619 : }
5620 127 : if (psInfo->m_poSrcLayer->GetArrowStream(&stream,
5621 127 : aosOptionsGetArrowStream.List()))
5622 : {
5623 127 : if (stream.get_schema(&stream, &schema) != 0)
5624 : {
5625 0 : CPLError(CE_Failure, CPLE_AppDefined, "stream.get_schema() failed");
5626 0 : stream.release(&stream);
5627 0 : return false;
5628 : }
5629 : }
5630 : else
5631 : {
5632 0 : CPLError(CE_Failure, CPLE_AppDefined, "GetArrowStream() failed");
5633 0 : return false;
5634 : }
5635 :
5636 127 : bool bRet = true;
5637 :
5638 127 : GIntBig nCount = 0;
5639 127 : bool bGoOn = true;
5640 254 : while (bGoOn)
5641 : {
5642 : struct ArrowArray array;
5643 : // Acquire source batch
5644 252 : if (stream.get_next(&stream, &array) != 0)
5645 : {
5646 0 : CPLError(CE_Failure, CPLE_AppDefined, "stream.get_next() failed");
5647 0 : bRet = false;
5648 125 : break;
5649 : }
5650 :
5651 252 : if (array.release == nullptr)
5652 : {
5653 : // End of stream
5654 125 : break;
5655 : }
5656 :
5657 : // Limit number of features in batch if needed
5658 127 : if (psOptions->nLimit >= 0 &&
5659 2 : nCount + array.length >= psOptions->nLimit)
5660 : {
5661 2 : const auto nAdjustedLength = psOptions->nLimit - nCount;
5662 14 : for (int i = 0; i < array.n_children; ++i)
5663 : {
5664 12 : if (array.children[i]->length == array.length)
5665 12 : array.children[i]->length = nAdjustedLength;
5666 : }
5667 2 : array.length = nAdjustedLength;
5668 2 : nCount = psOptions->nLimit;
5669 2 : bGoOn = false;
5670 : }
5671 : else
5672 : {
5673 125 : nCount += array.length;
5674 : }
5675 :
5676 : // Write batch to target layer
5677 127 : if (!psInfo->m_poDstLayer->WriteArrowBatch(
5678 127 : &schema, &array, aosOptionsWriteArrowBatch.List()))
5679 : {
5680 0 : CPLError(CE_Failure, CPLE_AppDefined, "WriteArrowBatch() failed");
5681 0 : if (array.release)
5682 0 : array.release(&array);
5683 0 : bRet = false;
5684 0 : break;
5685 : }
5686 :
5687 127 : if (array.release)
5688 15 : array.release(&array);
5689 :
5690 : /* Report progress */
5691 127 : if (pfnProgress)
5692 : {
5693 0 : if (!pfnProgress(nCountLayerFeatures
5694 0 : ? nCount * 1.0 / nCountLayerFeatures
5695 : : 1.0,
5696 : "", pProgressArg))
5697 : {
5698 0 : bGoOn = false;
5699 0 : bRet = false;
5700 : }
5701 : }
5702 :
5703 127 : if (pnReadFeatureCount)
5704 0 : *pnReadFeatureCount = nCount;
5705 : }
5706 :
5707 127 : schema.release(&schema);
5708 :
5709 : // Ugly hack to work around https://github.com/OSGeo/gdal/issues/9497
5710 : // Deleting a RecordBatchReader obtained from arrow::dataset::Scanner.ToRecordBatchReader()
5711 : // is a lengthy operation since all batches are read in its destructors.
5712 : // Here we ask to our custom I/O layer to return in error to short circuit
5713 : // that lengthy operation.
5714 127 : if (auto poDS = psInfo->m_poSrcLayer->GetDataset())
5715 : {
5716 252 : if (poDS->GetLayerCount() == 1 && poDS->GetDriver() &&
5717 126 : EQUAL(poDS->GetDriver()->GetDescription(), "PARQUET"))
5718 : {
5719 6 : bool bStopIO = false;
5720 : const char *pszArrowStopIO =
5721 6 : CPLGetConfigOption("OGR_ARROW_STOP_IO", nullptr);
5722 6 : if (pszArrowStopIO && CPLTestBool(pszArrowStopIO))
5723 : {
5724 0 : bStopIO = true;
5725 : }
5726 6 : else if (!pszArrowStopIO)
5727 : {
5728 12 : std::string osExePath;
5729 6 : osExePath.resize(1024);
5730 6 : if (CPLGetExecPath(osExePath.data(),
5731 12 : static_cast<int>(osExePath.size())))
5732 : {
5733 6 : osExePath.resize(strlen(osExePath.data()));
5734 6 : if (strcmp(CPLGetBasename(osExePath.data()), "ogr2ogr") ==
5735 : 0)
5736 : {
5737 1 : bStopIO = true;
5738 : }
5739 : }
5740 : }
5741 6 : if (bStopIO)
5742 : {
5743 1 : CPLSetConfigOption("OGR_ARROW_STOP_IO", "YES");
5744 1 : CPLDebug("OGR2OGR", "Forcing interruption of Parquet I/O");
5745 : }
5746 : }
5747 : }
5748 :
5749 127 : stream.release(&stream);
5750 127 : return bRet;
5751 : }
5752 :
5753 : /************************************************************************/
5754 : /* LayerTranslator::Translate() */
5755 : /************************************************************************/
5756 :
5757 1618 : bool LayerTranslator::Translate(
5758 : OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,
5759 : GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
5760 : GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress, void *pProgressArg,
5761 : const GDALVectorTranslateOptions *psOptions)
5762 : {
5763 1618 : if (psInfo->m_bUseWriteArrowBatch)
5764 : {
5765 127 : return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,
5766 127 : pfnProgress, pProgressArg, psOptions);
5767 : }
5768 :
5769 1491 : const int eGType = m_eGType;
5770 1491 : const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
5771 :
5772 1491 : OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;
5773 1491 : OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5774 1491 : const int *const panMap = psInfo->m_anMap.data();
5775 1491 : const int iSrcZField = psInfo->m_iSrcZField;
5776 1491 : const bool bPreserveFID = psInfo->m_bPreserveFID;
5777 1491 : const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
5778 1491 : const auto poDstFDefn = poDstLayer->GetLayerDefn();
5779 1491 : const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
5780 1491 : const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5781 1491 : const bool bExplodeCollections =
5782 1491 : m_bExplodeCollections && nDstGeomFieldCount <= 1;
5783 1491 : const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5784 :
5785 1491 : if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
5786 : {
5787 1460 : if (nSrcGeomFieldCount == 1)
5788 : {
5789 463 : poOutputSRS = poSrcLayer->GetSpatialRef();
5790 : }
5791 997 : else if (iRequestedSrcGeomField > 0)
5792 : {
5793 1 : poOutputSRS = poSrcLayer->GetLayerDefn()
5794 1 : ->GetGeomFieldDefn(iRequestedSrcGeomField)
5795 1 : ->GetSpatialRef();
5796 : }
5797 : }
5798 :
5799 : /* -------------------------------------------------------------------- */
5800 : /* Transfer features. */
5801 : /* -------------------------------------------------------------------- */
5802 1491 : if (psOptions->nGroupTransactions)
5803 : {
5804 1490 : if (psOptions->nLayerTransaction)
5805 : {
5806 428 : if (poDstLayer->StartTransaction() == OGRERR_FAILURE)
5807 : {
5808 0 : delete poFeatureIn;
5809 0 : return false;
5810 : }
5811 : }
5812 : }
5813 :
5814 1491 : std::unique_ptr<OGRFeature> poFeature;
5815 2982 : std::unique_ptr<OGRFeature> poDstFeature(new OGRFeature(poDstFDefn));
5816 1491 : int nFeaturesInTransaction = 0;
5817 1491 : GIntBig nCount = 0; /* written + failed */
5818 1491 : GIntBig nFeaturesWritten = 0;
5819 1491 : bool bRunSetPrecisionEvaluated = false;
5820 1491 : bool bRunSetPrecision = false;
5821 :
5822 1491 : bool bRet = true;
5823 1491 : CPLErrorReset();
5824 :
5825 1491 : bool bSetupCTOK = false;
5826 1491 : if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&
5827 24 : !psInfo->m_bPerFeatureCT)
5828 : {
5829 24 : bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
5830 24 : m_osDateLineOffset, m_poUserSourceSRS, nullptr,
5831 : poOutputSRS, m_poGCPCoordTrans, false);
5832 : }
5833 :
5834 : while (true)
5835 : {
5836 15055 : if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)
5837 : {
5838 9 : break;
5839 : }
5840 :
5841 15046 : if (poFeatureIn != nullptr)
5842 974 : poFeature.reset(poFeatureIn);
5843 14072 : else if (psOptions->nFIDToFetch != OGRNullFID)
5844 5 : poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));
5845 : else
5846 14067 : poFeature.reset(poSrcLayer->GetNextFeature());
5847 :
5848 15046 : if (poFeature == nullptr)
5849 : {
5850 498 : if (CPLGetLastErrorType() == CE_Failure)
5851 : {
5852 1 : bRet = false;
5853 : }
5854 498 : break;
5855 : }
5856 :
5857 14548 : if (!bSetupCTOK &&
5858 4459 : (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))
5859 : {
5860 1208 : if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
5861 604 : m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),
5862 : poOutputSRS, m_poGCPCoordTrans, true))
5863 : {
5864 4 : return false;
5865 : }
5866 : }
5867 :
5868 14548 : psInfo->m_nFeaturesRead++;
5869 :
5870 14548 : int nIters = 1;
5871 0 : std::unique_ptr<OGRGeometryCollection> poCollToExplode;
5872 14548 : int iGeomCollToExplode = -1;
5873 14548 : if (bExplodeCollections)
5874 : {
5875 : OGRGeometry *poSrcGeometry;
5876 4 : if (iRequestedSrcGeomField >= 0)
5877 : poSrcGeometry =
5878 0 : poFeature->GetGeomFieldRef(iRequestedSrcGeomField);
5879 : else
5880 4 : poSrcGeometry = poFeature->GetGeometryRef();
5881 8 : if (poSrcGeometry &&
5882 4 : OGR_GT_IsSubClassOf(poSrcGeometry->getGeometryType(),
5883 : wkbGeometryCollection))
5884 : {
5885 : const int nParts =
5886 3 : poSrcGeometry->toGeometryCollection()->getNumGeometries();
5887 3 : if (nParts > 0)
5888 : {
5889 3 : iGeomCollToExplode = iRequestedSrcGeomField >= 0
5890 : ? iRequestedSrcGeomField
5891 : : 0;
5892 3 : poCollToExplode.reset(
5893 : poFeature->StealGeometry(iGeomCollToExplode)
5894 : ->toGeometryCollection());
5895 3 : nIters = nParts;
5896 : }
5897 : }
5898 : }
5899 :
5900 14548 : const GIntBig nSrcFID = poFeature->GetFID();
5901 14548 : GIntBig nDesiredFID = OGRNullFID;
5902 14548 : if (bPreserveFID)
5903 11158 : nDesiredFID = nSrcFID;
5904 3391 : else if (psInfo->m_iSrcFIDField >= 0 &&
5905 1 : poFeature->IsFieldSetAndNotNull(psInfo->m_iSrcFIDField))
5906 : nDesiredFID =
5907 1 : poFeature->GetFieldAsInteger64(psInfo->m_iSrcFIDField);
5908 :
5909 29095 : for (int iPart = 0; iPart < nIters; iPart++)
5910 : {
5911 17755 : if (psOptions->nLayerTransaction &&
5912 3204 : ++nFeaturesInTransaction == psOptions->nGroupTransactions)
5913 : {
5914 0 : if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||
5915 0 : poDstLayer->StartTransaction() == OGRERR_FAILURE)
5916 : {
5917 0 : return false;
5918 : }
5919 0 : nFeaturesInTransaction = 0;
5920 : }
5921 40449 : else if (!psOptions->nLayerTransaction &&
5922 25878 : psOptions->nGroupTransactions > 0 &&
5923 11327 : ++nTotalEventsDone >= psOptions->nGroupTransactions)
5924 : {
5925 40 : if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||
5926 20 : m_poODS->StartTransaction(psOptions->bForceTransaction) ==
5927 : OGRERR_FAILURE)
5928 : {
5929 0 : return false;
5930 : }
5931 20 : nTotalEventsDone = 0;
5932 : }
5933 :
5934 14551 : CPLErrorReset();
5935 14551 : if (psInfo->m_bCanAvoidSetFrom)
5936 : {
5937 14304 : poDstFeature = std::move(poFeature);
5938 : // From now on, poFeature is null !
5939 14304 : poDstFeature->SetFDefnUnsafe(poDstFDefn);
5940 14304 : poDstFeature->SetFID(nDesiredFID);
5941 : }
5942 : else
5943 : {
5944 : /* Optimization to avoid duplicating the source geometry in the
5945 : */
5946 : /* target feature : we steal it from the source feature for
5947 : * now... */
5948 0 : std::unique_ptr<OGRGeometry> poStolenGeometry;
5949 247 : if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&
5950 44 : (nDstGeomFieldCount == 1 ||
5951 44 : (nDstGeomFieldCount == 0 && m_poClipSrcOri)))
5952 : {
5953 172 : poStolenGeometry.reset(poFeature->StealGeometry());
5954 : }
5955 75 : else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)
5956 : {
5957 0 : poStolenGeometry.reset(
5958 : poFeature->StealGeometry(iRequestedSrcGeomField));
5959 : }
5960 :
5961 247 : if (nDstGeomFieldCount == 0 && poStolenGeometry &&
5962 0 : m_poClipSrcOri)
5963 : {
5964 : const OGRGeometry *poClipGeom =
5965 0 : GetSrcClipGeom(poStolenGeometry->getSpatialReference());
5966 :
5967 0 : if (poClipGeom != nullptr &&
5968 0 : !poClipGeom->Intersects(poStolenGeometry.get()))
5969 : {
5970 0 : goto end_loop;
5971 : }
5972 : }
5973 :
5974 247 : poDstFeature->Reset();
5975 247 : if (poDstFeature->SetFrom(poFeature.get(), panMap, TRUE) !=
5976 : OGRERR_NONE)
5977 : {
5978 0 : if (psOptions->nGroupTransactions)
5979 : {
5980 0 : if (psOptions->nLayerTransaction)
5981 : {
5982 0 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
5983 : {
5984 0 : return false;
5985 : }
5986 : }
5987 : }
5988 :
5989 0 : CPLError(CE_Failure, CPLE_AppDefined,
5990 : "Unable to translate feature " CPL_FRMT_GIB
5991 : " from layer %s.",
5992 0 : nSrcFID, poSrcLayer->GetName());
5993 :
5994 0 : return false;
5995 : }
5996 :
5997 : /* ... and now we can attach the stolen geometry */
5998 247 : if (poStolenGeometry)
5999 : {
6000 166 : poDstFeature->SetGeometryDirectly(
6001 : poStolenGeometry.release());
6002 : }
6003 :
6004 247 : if (!psInfo->m_oMapResolved.empty())
6005 : {
6006 4 : for (const auto &kv : psInfo->m_oMapResolved)
6007 : {
6008 2 : const int nDstField = kv.first;
6009 2 : const int nSrcField = kv.second.nSrcField;
6010 2 : if (poFeature->IsFieldSetAndNotNull(nSrcField))
6011 : {
6012 2 : const auto poDomain = kv.second.poDomain;
6013 : const auto &oMapKV =
6014 2 : psInfo->m_oMapDomainToKV[poDomain];
6015 : const auto iter = oMapKV.find(
6016 2 : poFeature->GetFieldAsString(nSrcField));
6017 2 : if (iter != oMapKV.end())
6018 : {
6019 2 : poDstFeature->SetField(nDstField,
6020 1 : iter->second.c_str());
6021 : }
6022 : }
6023 : }
6024 : }
6025 :
6026 247 : if (nDesiredFID != OGRNullFID)
6027 2 : poDstFeature->SetFID(nDesiredFID);
6028 : }
6029 :
6030 14551 : if (psOptions->bEmptyStrAsNull)
6031 : {
6032 2 : for (int i = 0; i < poDstFeature->GetFieldCount(); i++)
6033 : {
6034 1 : if (!poDstFeature->IsFieldSetAndNotNull(i))
6035 0 : continue;
6036 1 : auto fieldDef = poDstFeature->GetFieldDefnRef(i);
6037 1 : if (fieldDef->GetType() != OGRFieldType::OFTString)
6038 0 : continue;
6039 1 : auto str = poDstFeature->GetFieldAsString(i);
6040 1 : if (strcmp(str, "") == 0)
6041 1 : poDstFeature->SetFieldNull(i);
6042 : }
6043 : }
6044 :
6045 14551 : if (!psInfo->m_anDateTimeFieldIdx.empty())
6046 : {
6047 40 : for (int i : psInfo->m_anDateTimeFieldIdx)
6048 : {
6049 20 : if (!poDstFeature->IsFieldSetAndNotNull(i))
6050 11 : continue;
6051 15 : auto psField = poDstFeature->GetRawFieldRef(i);
6052 15 : if (psField->Date.TZFlag == 0 || psField->Date.TZFlag == 1)
6053 5 : continue;
6054 :
6055 10 : const int nTZOffsetInSec =
6056 10 : (psField->Date.TZFlag - 100) * 15 * 60;
6057 10 : if (nTZOffsetInSec == psOptions->nTZOffsetInSec)
6058 1 : continue;
6059 :
6060 : struct tm brokendowntime;
6061 9 : memset(&brokendowntime, 0, sizeof(brokendowntime));
6062 9 : brokendowntime.tm_year = psField->Date.Year - 1900;
6063 9 : brokendowntime.tm_mon = psField->Date.Month - 1;
6064 9 : brokendowntime.tm_mday = psField->Date.Day;
6065 9 : GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
6066 9 : int nSec = psField->Date.Hour * 3600 +
6067 9 : psField->Date.Minute * 60 +
6068 9 : static_cast<int>(psField->Date.Second);
6069 9 : nSec += psOptions->nTZOffsetInSec - nTZOffsetInSec;
6070 9 : nUnixTime += nSec;
6071 9 : CPLUnixTimeToYMDHMS(nUnixTime, &brokendowntime);
6072 :
6073 9 : psField->Date.Year =
6074 9 : static_cast<GInt16>(brokendowntime.tm_year + 1900);
6075 9 : psField->Date.Month =
6076 9 : static_cast<GByte>(brokendowntime.tm_mon + 1);
6077 9 : psField->Date.Day =
6078 9 : static_cast<GByte>(brokendowntime.tm_mday);
6079 9 : psField->Date.Hour =
6080 9 : static_cast<GByte>(brokendowntime.tm_hour);
6081 9 : psField->Date.Minute =
6082 9 : static_cast<GByte>(brokendowntime.tm_min);
6083 9 : psField->Date.Second = static_cast<float>(
6084 9 : brokendowntime.tm_sec + fmod(psField->Date.Second, 1));
6085 9 : psField->Date.TZFlag = static_cast<GByte>(
6086 9 : 100 + psOptions->nTZOffsetInSec / (15 * 60));
6087 : }
6088 : }
6089 :
6090 : /* Erase native data if asked explicitly */
6091 14551 : if (!m_bNativeData)
6092 : {
6093 1 : poDstFeature->SetNativeData(nullptr);
6094 1 : poDstFeature->SetNativeMediaType(nullptr);
6095 : }
6096 :
6097 28068 : for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
6098 : {
6099 0 : std::unique_ptr<OGRGeometry> poDstGeometry;
6100 :
6101 13555 : if (poCollToExplode && iGeom == iGeomCollToExplode)
6102 : {
6103 6 : OGRGeometry *poPart = poCollToExplode->getGeometryRef(0);
6104 6 : poCollToExplode->removeGeometry(0, FALSE);
6105 6 : poDstGeometry.reset(poPart);
6106 : }
6107 : else
6108 : {
6109 13549 : poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));
6110 : }
6111 13555 : if (poDstGeometry == nullptr)
6112 605 : continue;
6113 :
6114 : // poFeature hasn't been moved if iSrcZField != -1
6115 : // cppcheck-suppress accessMoved
6116 12950 : if (iSrcZField != -1 && poFeature != nullptr)
6117 : {
6118 30 : SetZ(poDstGeometry.get(),
6119 : poFeature->GetFieldAsDouble(iSrcZField));
6120 : /* This will correct the coordinate dimension to 3 */
6121 30 : poDstGeometry.reset(poDstGeometry->clone());
6122 : }
6123 :
6124 12950 : if (m_nCoordDim == 2 || m_nCoordDim == 3)
6125 : {
6126 24 : poDstGeometry->setCoordinateDimension(m_nCoordDim);
6127 : }
6128 12926 : else if (m_nCoordDim == 4)
6129 : {
6130 2 : poDstGeometry->set3D(TRUE);
6131 2 : poDstGeometry->setMeasured(TRUE);
6132 : }
6133 12924 : else if (m_nCoordDim == COORD_DIM_XYM)
6134 : {
6135 2 : poDstGeometry->set3D(FALSE);
6136 2 : poDstGeometry->setMeasured(TRUE);
6137 : }
6138 12922 : else if (m_nCoordDim == COORD_DIM_LAYER_DIM)
6139 : {
6140 : const OGRwkbGeometryType eDstLayerGeomType =
6141 2 : poDstLayer->GetLayerDefn()
6142 2 : ->GetGeomFieldDefn(iGeom)
6143 2 : ->GetType();
6144 2 : poDstGeometry->set3D(wkbHasZ(eDstLayerGeomType));
6145 2 : poDstGeometry->setMeasured(wkbHasM(eDstLayerGeomType));
6146 : }
6147 :
6148 12950 : if (m_eGeomOp == GEOMOP_SEGMENTIZE)
6149 : {
6150 20 : if (m_dfGeomOpParam > 0)
6151 20 : poDstGeometry->segmentize(m_dfGeomOpParam);
6152 : }
6153 12930 : else if (m_eGeomOp == GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY)
6154 : {
6155 1 : if (m_dfGeomOpParam > 0)
6156 : {
6157 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6158 : poDstGeometry->SimplifyPreserveTopology(
6159 2 : m_dfGeomOpParam));
6160 1 : if (poNewGeom)
6161 : {
6162 1 : poDstGeometry = std::move(poNewGeom);
6163 : }
6164 : }
6165 : }
6166 :
6167 12950 : if (m_poClipSrcOri)
6168 : {
6169 :
6170 : const OGRGeometry *poClipGeom =
6171 43 : GetSrcClipGeom(poDstGeometry->getSpatialReference());
6172 :
6173 0 : std::unique_ptr<OGRGeometry> poClipped;
6174 43 : if (poClipGeom != nullptr)
6175 : {
6176 43 : OGREnvelope oClipEnv;
6177 43 : OGREnvelope oDstEnv;
6178 :
6179 43 : poClipGeom->getEnvelope(&oClipEnv);
6180 43 : poDstGeometry->getEnvelope(&oDstEnv);
6181 :
6182 43 : if (oClipEnv.Intersects(oDstEnv))
6183 : {
6184 24 : poClipped.reset(
6185 24 : poClipGeom->Intersection(poDstGeometry.get()));
6186 : }
6187 : }
6188 :
6189 43 : if (poClipped == nullptr || poClipped->IsEmpty())
6190 : {
6191 23 : goto end_loop;
6192 : }
6193 :
6194 20 : const int nDim = poDstGeometry->getDimension();
6195 21 : if (poClipped->getDimension() < nDim &&
6196 1 : wkbFlatten(
6197 : poDstFDefn->GetGeomFieldDefn(iGeom)->GetType()) !=
6198 : wkbUnknown)
6199 : {
6200 3 : CPLDebug(
6201 : "OGR2OGR",
6202 : "Discarding feature " CPL_FRMT_GIB " of layer %s, "
6203 : "as its intersection with -clipsrc is a %s "
6204 : "whereas the input is a %s",
6205 1 : nSrcFID, poSrcLayer->GetName(),
6206 1 : OGRToOGCGeomType(poClipped->getGeometryType()),
6207 1 : OGRToOGCGeomType(poDstGeometry->getGeometryType()));
6208 1 : goto end_loop;
6209 : }
6210 :
6211 19 : poDstGeometry = std::move(poClipped);
6212 : }
6213 :
6214 : OGRCoordinateTransformation *const poCT =
6215 12926 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6216 : char **const papszTransformOptions =
6217 12926 : psInfo->m_aoReprojectionInfo[iGeom]
6218 12926 : .m_aosTransformOptions.List();
6219 : const bool bReprojCanInvalidateValidity =
6220 12926 : psInfo->m_aoReprojectionInfo[iGeom]
6221 12926 : .m_bCanInvalidateValidity;
6222 :
6223 12926 : if (poCT != nullptr || papszTransformOptions != nullptr)
6224 : {
6225 : // If we need to change the geometry type to linear, and
6226 : // we have a geometry with curves, then convert it to
6227 : // linear first, to avoid invalidities due to the fact
6228 : // that validity of arc portions isn't always kept while
6229 : // reprojecting and then discretizing.
6230 10101 : if (bReprojCanInvalidateValidity &&
6231 10099 : (!psInfo->m_bSupportCurves ||
6232 10048 : m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
6233 10046 : m_eGeomTypeConversion ==
6234 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))
6235 : {
6236 53 : if (poDstGeometry->hasCurveGeometry(TRUE))
6237 : {
6238 4 : OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
6239 4 : poDstGeometry->getGeometryType());
6240 4 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6241 : poDstGeometry.release(), eTargetType));
6242 53 : }
6243 : }
6244 10046 : else if (bReprojCanInvalidateValidity &&
6245 2 : eGType != GEOMTYPE_UNCHANGED &&
6246 2 : !OGR_GT_IsNonLinear(
6247 20094 : static_cast<OGRwkbGeometryType>(eGType)) &&
6248 2 : poDstGeometry->hasCurveGeometry(TRUE))
6249 : {
6250 2 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6251 : poDstGeometry.release(),
6252 : static_cast<OGRwkbGeometryType>(eGType)));
6253 : }
6254 :
6255 10102 : for (int iIter = 0; iIter < 2; ++iIter)
6256 : {
6257 : auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(
6258 : OGRGeometryFactory::transformWithOptions(
6259 10102 : poDstGeometry.get(), poCT,
6260 : papszTransformOptions,
6261 10102 : m_transformWithOptionsCache));
6262 10102 : if (poReprojectedGeom == nullptr)
6263 : {
6264 0 : if (psOptions->nGroupTransactions)
6265 : {
6266 0 : if (psOptions->nLayerTransaction)
6267 : {
6268 0 : if (poDstLayer->CommitTransaction() !=
6269 0 : OGRERR_NONE &&
6270 0 : !psOptions->bSkipFailures)
6271 : {
6272 0 : return false;
6273 : }
6274 : }
6275 : }
6276 :
6277 0 : CPLError(CE_Failure, CPLE_AppDefined,
6278 : "Failed to reproject feature " CPL_FRMT_GIB
6279 : " (geometry probably out of source or "
6280 : "destination SRS).",
6281 : nSrcFID);
6282 0 : if (!psOptions->bSkipFailures)
6283 : {
6284 0 : return false;
6285 : }
6286 : }
6287 :
6288 : // Check if a curve geometry is no longer valid after
6289 : // reprojection
6290 10102 : const auto eType = poDstGeometry->getGeometryType();
6291 10102 : const auto eFlatType = wkbFlatten(eType);
6292 :
6293 4 : const auto IsValid = [](const OGRGeometry *poGeom)
6294 : {
6295 : CPLErrorHandlerPusher oErrorHandler(
6296 8 : CPLQuietErrorHandler);
6297 8 : return poGeom->IsValid();
6298 : };
6299 :
6300 10101 : if (iIter == 0 && bReprojCanInvalidateValidity &&
6301 10099 : OGRGeometryFactory::haveGEOS() &&
6302 10097 : (eFlatType == wkbCurvePolygon ||
6303 10097 : eFlatType == wkbCompoundCurve ||
6304 10097 : eFlatType == wkbMultiCurve ||
6305 2 : eFlatType == wkbMultiSurface) &&
6306 20205 : poDstGeometry->hasCurveGeometry(TRUE) &&
6307 2 : IsValid(poDstGeometry.get()))
6308 : {
6309 2 : OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
6310 2 : poDstGeometry->getGeometryType());
6311 : auto poDstGeometryTmp =
6312 : std::unique_ptr<OGRGeometry>(
6313 : OGRGeometryFactory::forceTo(
6314 2 : poReprojectedGeom->clone(),
6315 2 : eTargetType));
6316 2 : if (!IsValid(poDstGeometryTmp.get()))
6317 : {
6318 1 : CPLDebug("OGR2OGR",
6319 : "Curve geometry no longer valid after "
6320 : "reprojection: transforming it into "
6321 : "linear one before reprojecting");
6322 1 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6323 : poDstGeometry.release(), eTargetType));
6324 1 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6325 : poDstGeometry.release(), eType));
6326 : }
6327 : else
6328 : {
6329 1 : poDstGeometry = std::move(poReprojectedGeom);
6330 1 : break;
6331 : }
6332 : }
6333 : else
6334 : {
6335 10100 : poDstGeometry = std::move(poReprojectedGeom);
6336 10100 : break;
6337 : }
6338 10101 : }
6339 : }
6340 2825 : else if (poOutputSRS != nullptr)
6341 : {
6342 1780 : poDstGeometry->assignSpatialReference(poOutputSRS);
6343 : }
6344 :
6345 12926 : if (poDstGeometry != nullptr)
6346 : {
6347 12926 : if (m_poClipDstOri)
6348 : {
6349 25 : const OGRGeometry *poClipGeom = GetDstClipGeom(
6350 : poDstGeometry->getSpatialReference());
6351 25 : if (poClipGeom == nullptr)
6352 : {
6353 14 : goto end_loop;
6354 : }
6355 :
6356 0 : std::unique_ptr<OGRGeometry> poClipped;
6357 :
6358 25 : OGREnvelope oClipEnv;
6359 25 : OGREnvelope oDstEnv;
6360 :
6361 25 : poClipGeom->getEnvelope(&oClipEnv);
6362 25 : poDstGeometry->getEnvelope(&oDstEnv);
6363 :
6364 25 : if (oClipEnv.Intersects(oDstEnv))
6365 : {
6366 14 : poClipped.reset(
6367 14 : poClipGeom->Intersection(poDstGeometry.get()));
6368 : }
6369 :
6370 25 : if (poClipped == nullptr || poClipped->IsEmpty())
6371 : {
6372 13 : goto end_loop;
6373 : }
6374 :
6375 12 : const int nDim = poDstGeometry->getDimension();
6376 13 : if (poClipped->getDimension() < nDim &&
6377 1 : wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
6378 : ->GetType()) != wkbUnknown)
6379 : {
6380 3 : CPLDebug(
6381 : "OGR2OGR",
6382 : "Discarding feature " CPL_FRMT_GIB
6383 : " of layer %s, "
6384 : "as its intersection with -clipdst is a %s "
6385 : "whereas the input is a %s",
6386 1 : nSrcFID, poSrcLayer->GetName(),
6387 1 : OGRToOGCGeomType(poClipped->getGeometryType()),
6388 : OGRToOGCGeomType(
6389 1 : poDstGeometry->getGeometryType()));
6390 1 : goto end_loop;
6391 : }
6392 :
6393 11 : poDstGeometry = std::move(poClipped);
6394 : }
6395 :
6396 25824 : if (psOptions->dfXYRes !=
6397 1 : OGRGeomCoordinatePrecision::UNKNOWN &&
6398 12913 : OGRGeometryFactory::haveGEOS() &&
6399 1 : !poDstGeometry->hasCurveGeometry())
6400 : {
6401 : // OGR_APPLY_GEOM_SET_PRECISION default value for
6402 : // OGRLayer::CreateFeature() purposes, but here in the
6403 : // ogr2ogr -xyRes context, we force calling SetPrecision(),
6404 : // unless the user explicitly asks not to do it by
6405 : // setting the config option to NO.
6406 1 : if (!bRunSetPrecisionEvaluated)
6407 : {
6408 1 : bRunSetPrecisionEvaluated = true;
6409 1 : bRunSetPrecision = CPLTestBool(CPLGetConfigOption(
6410 : "OGR_APPLY_GEOM_SET_PRECISION", "YES"));
6411 : }
6412 1 : if (bRunSetPrecision)
6413 : {
6414 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6415 1 : poDstGeometry->SetPrecision(psOptions->dfXYRes,
6416 1 : /* nFlags = */ 0));
6417 1 : if (!poNewGeom)
6418 0 : goto end_loop;
6419 1 : poDstGeometry = std::move(poNewGeom);
6420 : }
6421 : }
6422 :
6423 12912 : if (m_bMakeValid)
6424 : {
6425 : const bool bIsGeomCollection =
6426 3 : wkbFlatten(poDstGeometry->getGeometryType()) ==
6427 3 : wkbGeometryCollection;
6428 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6429 3 : poDstGeometry->MakeValid());
6430 3 : if (!poNewGeom)
6431 0 : goto end_loop;
6432 3 : poDstGeometry = std::move(poNewGeom);
6433 3 : if (!bIsGeomCollection)
6434 : {
6435 2 : poDstGeometry.reset(
6436 : OGRGeometryFactory::
6437 : removeLowerDimensionSubGeoms(
6438 2 : poDstGeometry.get()));
6439 : }
6440 : }
6441 :
6442 12912 : if (m_eGeomTypeConversion != GTC_DEFAULT)
6443 : {
6444 : OGRwkbGeometryType eTargetType =
6445 11 : poDstGeometry->getGeometryType();
6446 : eTargetType =
6447 11 : ConvertType(m_eGeomTypeConversion, eTargetType);
6448 11 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6449 : poDstGeometry.release(), eTargetType));
6450 : }
6451 12901 : else if (eGType != GEOMTYPE_UNCHANGED)
6452 : {
6453 59 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6454 : poDstGeometry.release(),
6455 : static_cast<OGRwkbGeometryType>(eGType)));
6456 : }
6457 : }
6458 :
6459 12912 : poDstFeature->SetGeomFieldDirectly(iGeom,
6460 : poDstGeometry.release());
6461 : }
6462 :
6463 14513 : CPLErrorReset();
6464 29026 : if ((psOptions->bUpsert
6465 14513 : ? poDstLayer->UpsertFeature(poDstFeature.get())
6466 14513 : : poDstLayer->CreateFeature(poDstFeature.get())) ==
6467 : OGRERR_NONE)
6468 : {
6469 14508 : nFeaturesWritten++;
6470 25661 : if (nDesiredFID != OGRNullFID &&
6471 11153 : poDstFeature->GetFID() != nDesiredFID)
6472 : {
6473 0 : CPLError(CE_Warning, CPLE_AppDefined,
6474 : "Feature id " CPL_FRMT_GIB " not preserved",
6475 : nDesiredFID);
6476 : }
6477 : }
6478 5 : else if (!psOptions->bSkipFailures)
6479 : {
6480 4 : if (psOptions->nGroupTransactions)
6481 : {
6482 4 : if (psOptions->nLayerTransaction)
6483 0 : poDstLayer->RollbackTransaction();
6484 : }
6485 :
6486 4 : CPLError(CE_Failure, CPLE_AppDefined,
6487 : "Unable to write feature " CPL_FRMT_GIB
6488 : " from layer %s.",
6489 4 : nSrcFID, poSrcLayer->GetName());
6490 :
6491 4 : return false;
6492 : }
6493 : else
6494 : {
6495 1 : CPLDebug("GDALVectorTranslate",
6496 : "Unable to write feature " CPL_FRMT_GIB
6497 : " into layer %s.",
6498 1 : nSrcFID, poSrcLayer->GetName());
6499 1 : if (psOptions->nGroupTransactions)
6500 : {
6501 1 : if (psOptions->nLayerTransaction)
6502 : {
6503 0 : poDstLayer->RollbackTransaction();
6504 0 : CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());
6505 : }
6506 : else
6507 : {
6508 1 : m_poODS->RollbackTransaction();
6509 1 : m_poODS->StartTransaction(psOptions->bForceTransaction);
6510 : }
6511 : }
6512 : }
6513 :
6514 14547 : end_loop:; // nothing
6515 : }
6516 :
6517 : /* Report progress */
6518 14544 : nCount++;
6519 14544 : bool bGoOn = true;
6520 14544 : if (pfnProgress)
6521 : {
6522 75 : bGoOn = pfnProgress(nCountLayerFeatures
6523 36 : ? nCount * 1.0 / nCountLayerFeatures
6524 : : 1.0,
6525 : "", pProgressArg) != FALSE;
6526 : }
6527 14544 : if (!bGoOn)
6528 : {
6529 1 : bRet = false;
6530 1 : break;
6531 : }
6532 :
6533 14543 : if (pnReadFeatureCount)
6534 0 : *pnReadFeatureCount = nCount;
6535 :
6536 14543 : if (psOptions->nFIDToFetch != OGRNullFID)
6537 5 : break;
6538 14538 : if (poFeatureIn != nullptr)
6539 974 : break;
6540 13564 : }
6541 :
6542 1487 : if (psOptions->nGroupTransactions)
6543 : {
6544 1486 : if (psOptions->nLayerTransaction)
6545 : {
6546 428 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6547 0 : bRet = false;
6548 : }
6549 : }
6550 :
6551 1487 : if (poFeatureIn == nullptr)
6552 : {
6553 513 : CPLDebug("GDALVectorTranslate",
6554 : CPL_FRMT_GIB " features written in layer '%s'",
6555 513 : nFeaturesWritten, poDstLayer->GetName());
6556 : }
6557 :
6558 1487 : return bRet;
6559 : }
6560 :
6561 : /************************************************************************/
6562 : /* LayerTranslator::GetDstClipGeom() */
6563 : /************************************************************************/
6564 :
6565 : const OGRGeometry *
6566 25 : LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS)
6567 : {
6568 25 : if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS)
6569 : {
6570 22 : auto poClipDstSRS = m_poClipDstOri->getSpatialReference();
6571 22 : if (poClipDstSRS && poGeomSRS && !poClipDstSRS->IsSame(poGeomSRS))
6572 : {
6573 : // Transform clip geom to geometry SRS
6574 1 : m_poClipDstReprojectedToDstSRS.reset(m_poClipDstOri->clone());
6575 1 : if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) !=
6576 : OGRERR_NONE)
6577 : {
6578 0 : return nullptr;
6579 : }
6580 1 : m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS;
6581 : }
6582 21 : else if (!poClipDstSRS && poGeomSRS)
6583 : {
6584 21 : if (!m_bWarnedClipDstSRS)
6585 : {
6586 1 : m_bWarnedClipDstSRS = true;
6587 1 : CPLError(CE_Warning, CPLE_AppDefined,
6588 : "Clip destination geometry has no "
6589 : "attached SRS, but the feature's "
6590 : "geometry has one. Assuming clip "
6591 : "destination geometry SRS is the "
6592 : "same as the feature's geometry");
6593 : }
6594 : }
6595 : }
6596 :
6597 25 : return m_poClipDstReprojectedToDstSRS ? m_poClipDstReprojectedToDstSRS.get()
6598 50 : : m_poClipDstOri;
6599 : }
6600 :
6601 : /************************************************************************/
6602 : /* LayerTranslator::GetSrcClipGeom() */
6603 : /************************************************************************/
6604 :
6605 : const OGRGeometry *
6606 43 : LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS)
6607 : {
6608 43 : if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS)
6609 : {
6610 40 : auto poClipSrcSRS = m_poClipSrcOri->getSpatialReference();
6611 40 : if (poClipSrcSRS && poGeomSRS && !poClipSrcSRS->IsSame(poGeomSRS))
6612 : {
6613 : // Transform clip geom to geometry SRS
6614 1 : m_poClipSrcReprojectedToSrcSRS.reset(m_poClipSrcOri->clone());
6615 1 : if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) !=
6616 : OGRERR_NONE)
6617 : {
6618 0 : return nullptr;
6619 : }
6620 1 : m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS;
6621 : }
6622 39 : else if (!poClipSrcSRS && poGeomSRS)
6623 : {
6624 39 : if (!m_bWarnedClipSrcSRS)
6625 : {
6626 3 : m_bWarnedClipSrcSRS = true;
6627 3 : CPLError(CE_Warning, CPLE_AppDefined,
6628 : "Clip source geometry has no attached SRS, "
6629 : "but the feature's geometry has one. "
6630 : "Assuming clip source geometry SRS is the "
6631 : "same as the feature's geometry");
6632 : }
6633 : }
6634 : }
6635 :
6636 43 : return m_poClipSrcReprojectedToSrcSRS ? m_poClipSrcReprojectedToSrcSRS.get()
6637 86 : : m_poClipSrcOri;
6638 : }
6639 :
6640 : /************************************************************************/
6641 : /* GDALVectorTranslateOptionsGetParser() */
6642 : /************************************************************************/
6643 :
6644 698 : static std::unique_ptr<GDALArgumentParser> GDALVectorTranslateOptionsGetParser(
6645 : GDALVectorTranslateOptions *psOptions,
6646 : GDALVectorTranslateOptionsForBinary *psOptionsForBinary, int nCountClipSrc,
6647 : int nCountClipDst)
6648 : {
6649 : auto argParser = std::make_unique<GDALArgumentParser>(
6650 698 : "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);
6651 :
6652 698 : argParser->add_description(
6653 698 : _("Converts simple features data between file formats."));
6654 :
6655 698 : argParser->add_epilog(
6656 698 : _("For more details, consult https://gdal.org/programs/ogr2ogr.html"));
6657 :
6658 698 : argParser->add_output_format_argument(psOptions->osFormat);
6659 :
6660 698 : argParser->add_argument("-dsco")
6661 1396 : .metavar("<NAME>=<VALUE>")
6662 698 : .append()
6663 78 : .action([psOptions](const std::string &s)
6664 776 : { psOptions->aosDSCO.AddString(s.c_str()); })
6665 698 : .help(_("Dataset creation option (format specific)."));
6666 :
6667 698 : argParser->add_layer_creation_options_argument(psOptions->aosLCO);
6668 :
6669 698 : argParser->add_usage_newline();
6670 :
6671 : {
6672 698 : auto &group = argParser->add_mutually_exclusive_group();
6673 698 : group.add_argument("-append")
6674 698 : .flag()
6675 30 : .action([psOptions](const std::string &)
6676 698 : { psOptions->eAccessMode = ACCESS_APPEND; })
6677 698 : .help(_("Append to existing layer instead of creating new."));
6678 :
6679 698 : group.add_argument("-upsert")
6680 698 : .flag()
6681 : .action(
6682 1 : [psOptions](const std::string &)
6683 : {
6684 1 : psOptions->eAccessMode = ACCESS_APPEND;
6685 1 : psOptions->bUpsert = true;
6686 698 : })
6687 : .help(_("Variant of -append where the UpsertFeature() operation is "
6688 698 : "used to insert or update features."));
6689 :
6690 698 : group.add_argument("-overwrite")
6691 698 : .flag()
6692 13 : .action([psOptions](const std::string &)
6693 698 : { psOptions->eAccessMode = ACCESS_OVERWRITE; })
6694 698 : .help(_("Delete the output layer and recreate it empty."));
6695 : }
6696 :
6697 698 : argParser->add_argument("-update")
6698 698 : .flag()
6699 : .action(
6700 22 : [psOptions](const std::string &)
6701 : {
6702 : /* Don't reset -append or -overwrite */
6703 8 : if (psOptions->eAccessMode != ACCESS_APPEND &&
6704 7 : psOptions->eAccessMode != ACCESS_OVERWRITE)
6705 7 : psOptions->eAccessMode = ACCESS_UPDATE;
6706 698 : })
6707 : .help(_("Open existing output datasource in update mode rather than "
6708 698 : "trying to create a new one."));
6709 :
6710 698 : argParser->add_argument("-sql")
6711 1396 : .metavar("<statement>|@<filename>")
6712 : .action(
6713 22 : [psOptions](const std::string &s)
6714 : {
6715 11 : GByte *pabyRet = nullptr;
6716 14 : if (!s.empty() && s.front() == '@' &&
6717 3 : VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
6718 : 1024 * 1024))
6719 : {
6720 3 : GDALRemoveBOM(pabyRet);
6721 3 : char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);
6722 : psOptions->osSQLStatement =
6723 3 : GDALRemoveSQLComments(pszSQLStatement);
6724 3 : VSIFree(pszSQLStatement);
6725 : }
6726 : else
6727 : {
6728 8 : psOptions->osSQLStatement = s;
6729 : }
6730 709 : })
6731 698 : .help(_("SQL statement to execute."));
6732 :
6733 698 : argParser->add_argument("-dialect")
6734 1396 : .metavar("<dialect>")
6735 698 : .store_into(psOptions->osDialect)
6736 698 : .help(_("SQL dialect."));
6737 :
6738 698 : argParser->add_argument("-spat")
6739 1396 : .metavar("<xmin> <ymin> <xmax> <ymax>")
6740 698 : .nargs(4)
6741 698 : .scan<'g', double>()
6742 : .help(_("Spatial query extents, in the SRS of the source layer(s) (or "
6743 698 : "the one specified with -spat_srs."));
6744 :
6745 698 : argParser->add_argument("-where")
6746 1396 : .metavar("<restricted_where>|@<filename>")
6747 : .action(
6748 16 : [psOptions](const std::string &s)
6749 : {
6750 8 : GByte *pabyRet = nullptr;
6751 9 : if (!s.empty() && s.front() == '@' &&
6752 1 : VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
6753 : 1024 * 1024))
6754 : {
6755 1 : GDALRemoveBOM(pabyRet);
6756 1 : char *pszWHERE = reinterpret_cast<char *>(pabyRet);
6757 1 : psOptions->osWHERE = pszWHERE;
6758 1 : VSIFree(pszWHERE);
6759 : }
6760 : else
6761 : {
6762 7 : psOptions->osWHERE = s;
6763 : }
6764 706 : })
6765 698 : .help(_("Attribute query (like SQL WHERE)."));
6766 :
6767 698 : argParser->add_argument("-select")
6768 1396 : .metavar("<field_list>")
6769 : .action(
6770 34 : [psOptions](const std::string &s)
6771 : {
6772 17 : psOptions->bSelFieldsSet = true;
6773 : psOptions->aosSelFields =
6774 17 : CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);
6775 698 : })
6776 : .help(_("Comma-delimited list of fields from input layer to copy to "
6777 698 : "the new layer."));
6778 :
6779 698 : argParser->add_argument("-nln")
6780 1396 : .metavar("<name>")
6781 698 : .store_into(psOptions->osNewLayerName)
6782 698 : .help(_("Assign an alternate name to the new layer."));
6783 :
6784 698 : argParser->add_argument("-nlt")
6785 1396 : .metavar("<type>")
6786 698 : .append()
6787 : .action(
6788 223 : [psOptions](const std::string &osGeomNameIn)
6789 : {
6790 49 : bool bIs3D = false;
6791 98 : std::string osGeomName(osGeomNameIn);
6792 98 : if (osGeomName.size() > 3 &&
6793 49 : STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,
6794 : "25D"))
6795 : {
6796 1 : bIs3D = true;
6797 1 : osGeomName.resize(osGeomName.size() - 3);
6798 : }
6799 96 : else if (osGeomName.size() > 1 &&
6800 48 : STARTS_WITH_CI(
6801 : osGeomName.c_str() + osGeomName.size() - 1, "Z"))
6802 : {
6803 0 : bIs3D = true;
6804 0 : osGeomName.resize(osGeomName.size() - 1);
6805 : }
6806 49 : if (EQUAL(osGeomName.c_str(), "NONE"))
6807 : {
6808 1 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
6809 : {
6810 : throw std::invalid_argument(
6811 0 : "Unsupported combination of -nlt arguments.");
6812 : }
6813 1 : psOptions->eGType = wkbNone;
6814 : }
6815 48 : else if (EQUAL(osGeomName.c_str(), "GEOMETRY"))
6816 : {
6817 4 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
6818 : {
6819 : throw std::invalid_argument(
6820 0 : "Unsupported combination of -nlt arguments.");
6821 : }
6822 4 : psOptions->eGType = wkbUnknown;
6823 : }
6824 44 : else if (EQUAL(osGeomName.c_str(), "PROMOTE_TO_MULTI"))
6825 : {
6826 8 : if (psOptions->eGeomTypeConversion == GTC_CONVERT_TO_LINEAR)
6827 2 : psOptions->eGeomTypeConversion =
6828 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
6829 6 : else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
6830 5 : psOptions->eGeomTypeConversion = GTC_PROMOTE_TO_MULTI;
6831 : else
6832 : {
6833 : throw std::invalid_argument(
6834 1 : "Unsupported combination of -nlt arguments.");
6835 : }
6836 : }
6837 36 : else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_LINEAR"))
6838 : {
6839 12 : if (psOptions->eGeomTypeConversion == GTC_PROMOTE_TO_MULTI)
6840 2 : psOptions->eGeomTypeConversion =
6841 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
6842 10 : else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
6843 9 : psOptions->eGeomTypeConversion = GTC_CONVERT_TO_LINEAR;
6844 : else
6845 : {
6846 : throw std::invalid_argument(
6847 1 : "Unsupported combination of -nlt arguments.");
6848 : }
6849 : }
6850 24 : else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_CURVE"))
6851 : {
6852 7 : if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
6853 5 : psOptions->eGeomTypeConversion = GTC_CONVERT_TO_CURVE;
6854 : else
6855 : {
6856 : throw std::invalid_argument(
6857 2 : "Unsupported combination of -nlt arguments.");
6858 : }
6859 : }
6860 : else
6861 : {
6862 17 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
6863 : {
6864 : throw std::invalid_argument(
6865 3 : "Unsupported combination of -nlt arguments.");
6866 : }
6867 14 : psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());
6868 14 : if (psOptions->eGType == wkbUnknown)
6869 : {
6870 : throw std::invalid_argument(
6871 : CPLSPrintf("-nlt %s: type not recognised.",
6872 0 : osGeomName.c_str()));
6873 : }
6874 : }
6875 42 : if (psOptions->eGType != GEOMTYPE_UNCHANGED &&
6876 23 : psOptions->eGType != wkbNone && bIs3D)
6877 1 : psOptions->eGType = wkbSetZ(
6878 : static_cast<OGRwkbGeometryType>(psOptions->eGType));
6879 740 : })
6880 698 : .help(_("Define the geometry type for the created layer."));
6881 :
6882 698 : argParser->add_argument("-s_srs")
6883 1396 : .metavar("<srs_def>")
6884 698 : .store_into(psOptions->osSourceSRSDef)
6885 698 : .help(_("Set/override source SRS."));
6886 :
6887 : {
6888 698 : auto &group = argParser->add_mutually_exclusive_group();
6889 698 : group.add_argument("-a_srs")
6890 1396 : .metavar("<srs_def>")
6891 : .action(
6892 353 : [psOptions](const std::string &osOutputSRSDef)
6893 : {
6894 115 : psOptions->osOutputSRSDef = osOutputSRSDef;
6895 230 : if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||
6896 115 : EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))
6897 : {
6898 4 : psOptions->osOutputSRSDef.clear();
6899 4 : psOptions->bNullifyOutputSRS = true;
6900 : }
6901 698 : })
6902 698 : .help(_("Assign an output SRS, but without reprojecting."));
6903 :
6904 698 : group.add_argument("-t_srs")
6905 1396 : .metavar("<srs_def>")
6906 : .action(
6907 46 : [psOptions](const std::string &osOutputSRSDef)
6908 : {
6909 23 : psOptions->osOutputSRSDef = osOutputSRSDef;
6910 23 : psOptions->bTransform = true;
6911 698 : })
6912 : .help(_("Reproject/transform to this SRS on output, and assign it "
6913 698 : "as output SRS."));
6914 : }
6915 :
6916 : ///////////////////////////////////////////////////////////////////////
6917 698 : argParser->add_group("Field related options");
6918 :
6919 698 : argParser->add_argument("-addfields")
6920 698 : .flag()
6921 : .action(
6922 2 : [psOptions](const std::string &)
6923 : {
6924 2 : psOptions->bAddMissingFields = true;
6925 2 : psOptions->eAccessMode = ACCESS_APPEND;
6926 698 : })
6927 698 : .help(_("Same as append, but add also any new fields."));
6928 :
6929 698 : argParser->add_argument("-relaxedFieldNameMatch")
6930 698 : .flag()
6931 0 : .action([psOptions](const std::string &)
6932 698 : { psOptions->bExactFieldNameMatch = false; })
6933 : .help(_("Do field name matching between source and existing target "
6934 698 : "layer in a more relaxed way."));
6935 :
6936 698 : argParser->add_argument("-fieldTypeToString")
6937 1396 : .metavar("All|<type1>[,<type2>]...")
6938 : .action(
6939 0 : [psOptions](const std::string &s)
6940 : {
6941 : psOptions->aosFieldTypesToString =
6942 0 : CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
6943 0 : CSLConstList iter = psOptions->aosFieldTypesToString.List();
6944 0 : while (*iter)
6945 : {
6946 0 : if (IsFieldType(*iter))
6947 : {
6948 : /* Do nothing */
6949 : }
6950 0 : else if (EQUAL(*iter, "All"))
6951 : {
6952 0 : psOptions->aosFieldTypesToString.Clear();
6953 0 : psOptions->aosFieldTypesToString.AddString("All");
6954 0 : break;
6955 : }
6956 : else
6957 : {
6958 : throw std::invalid_argument(CPLSPrintf(
6959 : "Unhandled type for fieldTypeToString option : %s",
6960 0 : *iter));
6961 : }
6962 0 : iter++;
6963 : }
6964 698 : })
6965 : .help(_("Converts any field of the specified type to a field of type "
6966 698 : "string in the destination layer."));
6967 :
6968 698 : argParser->add_argument("-mapFieldType")
6969 1396 : .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...")
6970 : .action(
6971 12 : [psOptions](const std::string &s)
6972 : {
6973 : psOptions->aosMapFieldType =
6974 4 : CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
6975 4 : CSLConstList iter = psOptions->aosMapFieldType.List();
6976 8 : while (*iter)
6977 : {
6978 4 : char *pszKey = nullptr;
6979 4 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
6980 4 : if (pszKey && pszValue)
6981 : {
6982 8 : if (!((IsFieldType(pszKey) || EQUAL(pszKey, "All")) &&
6983 4 : IsFieldType(pszValue)))
6984 : {
6985 0 : CPLFree(pszKey);
6986 : throw std::invalid_argument(CPLSPrintf(
6987 0 : "Invalid value for -mapFieldType : %s", *iter));
6988 : }
6989 : }
6990 4 : CPLFree(pszKey);
6991 4 : iter++;
6992 : }
6993 702 : })
6994 698 : .help(_("Converts any field of the specified type to another type."));
6995 :
6996 698 : argParser->add_argument("-fieldmap")
6997 1396 : .metavar("<field_1>[,<field_2>]...")
6998 : .action(
6999 4 : [psOptions](const std::string &s)
7000 : {
7001 : psOptions->aosFieldMap =
7002 2 : CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);
7003 698 : })
7004 : .help(_("Specifies the list of field indexes to be copied from the "
7005 698 : "source to the destination."));
7006 :
7007 698 : argParser->add_argument("-splitlistfields")
7008 698 : .store_into(psOptions->bSplitListFields)
7009 : .help(_("Split fields of type list type into as many fields of scalar "
7010 698 : "type as necessary."));
7011 :
7012 698 : argParser->add_argument("-maxsubfields")
7013 1396 : .metavar("<n>")
7014 698 : .scan<'i', int>()
7015 : .action(
7016 0 : [psOptions](const std::string &s)
7017 : {
7018 0 : const int nVal = atoi(s.c_str());
7019 0 : if (nVal > 0)
7020 : {
7021 0 : psOptions->nMaxSplitListSubFields = nVal;
7022 : }
7023 698 : })
7024 : .help(_("To be combined with -splitlistfields to limit the number of "
7025 698 : "subfields created for each split field."));
7026 :
7027 698 : argParser->add_argument("-emptyStrAsNull")
7028 698 : .store_into(psOptions->bEmptyStrAsNull)
7029 698 : .help(_("Treat empty string values as null."));
7030 :
7031 698 : argParser->add_argument("-forceNullable")
7032 698 : .store_into(psOptions->bForceNullable)
7033 : .help(_("Do not propagate not-nullable constraints to target layer if "
7034 698 : "they exist in source layer."));
7035 :
7036 698 : argParser->add_argument("-unsetFieldWidth")
7037 698 : .store_into(psOptions->bUnsetFieldWidth)
7038 698 : .help(_("Set field width and precision to 0."));
7039 :
7040 698 : argParser->add_argument("-unsetDefault")
7041 698 : .store_into(psOptions->bUnsetDefault)
7042 : .help(_("Do not propagate default field values to target layer if they "
7043 698 : "exist in source layer."));
7044 :
7045 698 : argParser->add_argument("-resolveDomains")
7046 698 : .store_into(psOptions->bResolveDomains)
7047 : .help(_("Cause any selected field that is linked to a coded field "
7048 698 : "domain will be accompanied by an additional field."));
7049 :
7050 698 : argParser->add_argument("-dateTimeTo")
7051 1396 : .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>")
7052 : .action(
7053 33 : [psOptions](const std::string &s)
7054 : {
7055 13 : const char *pszFormat = s.c_str();
7056 13 : if (EQUAL(pszFormat, "UTC"))
7057 : {
7058 1 : psOptions->nTZOffsetInSec = 0;
7059 : }
7060 12 : else if (STARTS_WITH_CI(pszFormat, "UTC") &&
7061 11 : (strlen(pszFormat) == strlen("UTC+HH") ||
7062 9 : strlen(pszFormat) == strlen("UTC+HH:MM")) &&
7063 7 : (pszFormat[3] == '+' || pszFormat[3] == '-'))
7064 : {
7065 6 : const int nHour = atoi(pszFormat + strlen("UTC+"));
7066 6 : if (nHour < 0 || nHour > 14)
7067 : {
7068 1 : throw std::invalid_argument("Invalid UTC hour offset.");
7069 : }
7070 5 : else if (strlen(pszFormat) == strlen("UTC+HH"))
7071 : {
7072 0 : psOptions->nTZOffsetInSec = nHour * 3600;
7073 0 : if (pszFormat[3] == '-')
7074 0 : psOptions->nTZOffsetInSec =
7075 0 : -psOptions->nTZOffsetInSec;
7076 : }
7077 : else // if( strlen(pszFormat) == strlen("UTC+HH:MM") )
7078 : {
7079 5 : const int nMin = atoi(pszFormat + strlen("UTC+HH:"));
7080 5 : if (nMin == 0 || nMin == 15 || nMin == 30 || nMin == 45)
7081 : {
7082 4 : psOptions->nTZOffsetInSec =
7083 4 : nHour * 3600 + nMin * 60;
7084 4 : if (pszFormat[3] == '-')
7085 3 : psOptions->nTZOffsetInSec =
7086 3 : -psOptions->nTZOffsetInSec;
7087 : }
7088 : }
7089 : }
7090 12 : if (psOptions->nTZOffsetInSec == TZ_OFFSET_INVALID)
7091 : {
7092 : throw std::invalid_argument(
7093 : "Value of -dateTimeTo should be UTC, UTC(+|-)HH or "
7094 7 : "UTC(+|-)HH:MM with HH in [0,14] and MM=00,15,30,45");
7095 : }
7096 703 : })
7097 : .help(_("Converts date time values from the timezone specified in the "
7098 698 : "source value to the target timezone."));
7099 :
7100 698 : argParser->add_argument("-noNativeData")
7101 698 : .flag()
7102 1 : .action([psOptions](const std::string &)
7103 698 : { psOptions->bNativeData = false; })
7104 698 : .help(_("Disable copying of native data."));
7105 :
7106 : ///////////////////////////////////////////////////////////////////////
7107 698 : argParser->add_group("Advanced geometry and SRS related options");
7108 :
7109 698 : argParser->add_argument("-dim")
7110 1396 : .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM")
7111 : .action(
7112 24 : [psOptions](const std::string &osDim)
7113 : {
7114 12 : if (EQUAL(osDim.c_str(), "layer_dim"))
7115 2 : psOptions->nCoordDim = COORD_DIM_LAYER_DIM;
7116 18 : else if (EQUAL(osDim.c_str(), "XY") ||
7117 8 : EQUAL(osDim.c_str(), "2"))
7118 3 : psOptions->nCoordDim = 2;
7119 12 : else if (EQUAL(osDim.c_str(), "XYZ") ||
7120 5 : EQUAL(osDim.c_str(), "3"))
7121 3 : psOptions->nCoordDim = 3;
7122 4 : else if (EQUAL(osDim.c_str(), "XYM"))
7123 2 : psOptions->nCoordDim = COORD_DIM_XYM;
7124 2 : else if (EQUAL(osDim.c_str(), "XYZM"))
7125 2 : psOptions->nCoordDim = 4;
7126 : else
7127 : {
7128 : throw std::invalid_argument(CPLSPrintf(
7129 0 : "-dim %s: value not handled.", osDim.c_str()));
7130 : }
7131 710 : })
7132 698 : .help(_("Force the coordinate dimension."));
7133 :
7134 698 : argParser->add_argument("-s_coord_epoch")
7135 1396 : .metavar("<epoch>")
7136 698 : .store_into(psOptions->dfSourceCoordinateEpoch)
7137 698 : .help(_("Assign a coordinate epoch, linked with the source SRS."));
7138 :
7139 698 : argParser->add_argument("-a_coord_epoch")
7140 1396 : .metavar("<epoch>")
7141 698 : .store_into(psOptions->dfOutputCoordinateEpoch)
7142 : .help(_("Assign a coordinate epoch, linked with the output SRS when "
7143 698 : "-a_srs is used."));
7144 :
7145 698 : argParser->add_argument("-t_coord_epoch")
7146 1396 : .metavar("<epoch>")
7147 698 : .store_into(psOptions->dfOutputCoordinateEpoch)
7148 : .help(_("Assign a coordinate epoch, linked with the output SRS when "
7149 698 : "-t_srs is used."));
7150 :
7151 698 : argParser->add_argument("-ct")
7152 1396 : .metavar("<pipeline_def>")
7153 : .action(
7154 6 : [psOptions](const std::string &s)
7155 : {
7156 3 : psOptions->osCTPipeline = s;
7157 3 : psOptions->bTransform = true;
7158 698 : })
7159 : .help(_("Override the default transformation from the source to the "
7160 698 : "target CRS."));
7161 :
7162 698 : argParser->add_argument("-spat_srs")
7163 1396 : .metavar("<srs_def>")
7164 698 : .store_into(psOptions->osSpatSRSDef)
7165 698 : .help(_("Override spatial filter SRS."));
7166 :
7167 698 : argParser->add_argument("-geomfield")
7168 1396 : .metavar("<name>")
7169 : .action(
7170 2 : [psOptions](const std::string &s)
7171 : {
7172 1 : psOptions->osGeomField = s;
7173 1 : psOptions->bGeomFieldSet = true;
7174 698 : })
7175 : .help(_("Name of the geometry field on which the spatial filter "
7176 698 : "operates on."));
7177 :
7178 698 : argParser->add_argument("-segmentize")
7179 1396 : .metavar("<max_dist>")
7180 : .action(
7181 4 : [psOptions](const std::string &s)
7182 : {
7183 2 : psOptions->eGeomOp = GEOMOP_SEGMENTIZE;
7184 2 : psOptions->dfGeomOpParam = CPLAtofM(s.c_str());
7185 698 : })
7186 698 : .help(_("Maximum distance between 2 nodes."));
7187 :
7188 698 : argParser->add_argument("-simplify")
7189 1396 : .metavar("<tolerance>")
7190 : .action(
7191 2 : [psOptions](const std::string &s)
7192 : {
7193 1 : psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY;
7194 1 : psOptions->dfGeomOpParam = CPLAtofM(s.c_str());
7195 698 : })
7196 698 : .help(_("Distance tolerance for simplification."));
7197 :
7198 698 : argParser->add_argument("-makevalid")
7199 698 : .flag()
7200 : .action(
7201 2 : [psOptions](const std::string &)
7202 : {
7203 1 : if (!OGRGeometryFactory::haveGEOS())
7204 : {
7205 : throw std::invalid_argument(
7206 0 : "-makevalid only supported for builds against GEOS");
7207 : }
7208 1 : psOptions->bMakeValid = true;
7209 699 : })
7210 : .help(_("Fix geometries to be valid regarding the rules of the Simple "
7211 698 : "Features specification."));
7212 :
7213 698 : argParser->add_argument("-wrapdateline")
7214 698 : .store_into(psOptions->bWrapDateline)
7215 698 : .help(_("Split geometries crossing the dateline meridian."));
7216 :
7217 698 : argParser->add_argument("-datelineoffset")
7218 1396 : .metavar("<val_in_degree>")
7219 698 : .default_value(psOptions->dfDateLineOffset)
7220 698 : .store_into(psOptions->dfDateLineOffset)
7221 698 : .help(_("Offset from dateline in degrees."));
7222 :
7223 698 : argParser->add_argument("-clipsrc")
7224 698 : .nargs(nCountClipSrc)
7225 1396 : .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
7226 698 : .help(_("Clip geometries (in source SRS)."));
7227 :
7228 698 : argParser->add_argument("-clipsrcsql")
7229 1396 : .metavar("<sql_statement>")
7230 698 : .store_into(psOptions->osClipSrcSQL)
7231 : .help(_("Select desired geometries from the source clip datasource "
7232 698 : "using an SQL query."));
7233 :
7234 698 : argParser->add_argument("-clipsrclayer")
7235 1396 : .metavar("<layername>")
7236 698 : .store_into(psOptions->osClipSrcLayer)
7237 698 : .help(_("Select the named layer from the source clip datasource."));
7238 :
7239 698 : argParser->add_argument("-clipsrcwhere")
7240 1396 : .metavar("<expression>")
7241 698 : .store_into(psOptions->osClipSrcWhere)
7242 : .help(_("Restrict desired geometries from the source clip layer based "
7243 698 : "on an attribute query."));
7244 :
7245 698 : argParser->add_argument("-clipdst")
7246 698 : .nargs(nCountClipDst)
7247 1396 : .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>")
7248 698 : .help(_("Clip geometries (in target SRS)."));
7249 :
7250 698 : argParser->add_argument("-clipdstsql")
7251 1396 : .metavar("<sql_statement>")
7252 698 : .store_into(psOptions->osClipDstSQL)
7253 : .help(_("Select desired geometries from the destination clip "
7254 698 : "datasource using an SQL query."));
7255 :
7256 698 : argParser->add_argument("-clipdstlayer")
7257 1396 : .metavar("<layername>")
7258 698 : .store_into(psOptions->osClipDstLayer)
7259 : .help(
7260 698 : _("Select the named layer from the destination clip datasource."));
7261 :
7262 698 : argParser->add_argument("-clipdstwhere")
7263 1396 : .metavar("<expression>")
7264 698 : .store_into(psOptions->osClipDstWhere)
7265 : .help(_("Restrict desired geometries from the destination clip layer "
7266 698 : "based on an attribute query."));
7267 :
7268 698 : argParser->add_argument("-explodecollections")
7269 698 : .store_into(psOptions->bExplodeCollections)
7270 : .help(_("Produce one feature for each geometry in any kind of geometry "
7271 698 : "collection in the source file."));
7272 :
7273 698 : argParser->add_argument("-zfield")
7274 1396 : .metavar("<name>")
7275 698 : .store_into(psOptions->osZField)
7276 : .help(_("Uses the specified field to fill the Z coordinate of "
7277 698 : "geometries."));
7278 :
7279 698 : argParser->add_argument("-gcp")
7280 : .metavar(
7281 1396 : "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")
7282 698 : .nargs(4, 5)
7283 698 : .append()
7284 698 : .scan<'g', double>()
7285 698 : .help(_("Add the indicated ground control point."));
7286 :
7287 698 : argParser->add_argument("-tps")
7288 698 : .flag()
7289 1 : .action([psOptions](const std::string &)
7290 698 : { psOptions->nTransformOrder = -1; })
7291 : .help(_("Force use of thin plate spline transformer based on available "
7292 698 : "GCPs."));
7293 :
7294 698 : argParser->add_argument("-order")
7295 1396 : .metavar("1|2|3")
7296 698 : .store_into(psOptions->nTransformOrder)
7297 698 : .help(_("Order of polynomial used for warping."));
7298 :
7299 698 : argParser->add_argument("-xyRes")
7300 1396 : .metavar("<val>[ m|mm|deg]")
7301 : .action(
7302 25 : [psOptions](const std::string &s)
7303 : {
7304 9 : const char *pszVal = s.c_str();
7305 :
7306 9 : char *endptr = nullptr;
7307 9 : psOptions->dfXYRes = CPLStrtodM(pszVal, &endptr);
7308 9 : if (!endptr)
7309 : {
7310 : throw std::invalid_argument(
7311 : "Invalid value for -xyRes. Must be of the form "
7312 0 : "{numeric_value}[ ]?[m|mm|deg]?");
7313 : }
7314 9 : if (*endptr == ' ')
7315 6 : ++endptr;
7316 9 : if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
7317 5 : strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
7318 : {
7319 : throw std::invalid_argument(
7320 : "Invalid value for -xyRes. Must be of the form "
7321 2 : "{numeric_value}[ ]?[m|mm|deg]?");
7322 : }
7323 7 : psOptions->osXYResUnit = endptr;
7324 705 : })
7325 698 : .help(_("Set/override the geometry X/Y coordinate resolution."));
7326 :
7327 698 : argParser->add_argument("-zRes")
7328 1396 : .metavar("<val>[ m|mm]")
7329 : .action(
7330 16 : [psOptions](const std::string &s)
7331 : {
7332 6 : const char *pszVal = s.c_str();
7333 :
7334 6 : char *endptr = nullptr;
7335 6 : psOptions->dfZRes = CPLStrtodM(pszVal, &endptr);
7336 6 : if (!endptr)
7337 : {
7338 : throw std::invalid_argument(
7339 : "Invalid value for -zRes. Must be of the form "
7340 0 : "{numeric_value}[ ]?[m|mm]?");
7341 : }
7342 6 : if (*endptr == ' ')
7343 4 : ++endptr;
7344 6 : if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
7345 3 : strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
7346 : {
7347 : throw std::invalid_argument(
7348 : "Invalid value for -zRes. Must be of the form "
7349 2 : "{numeric_value}[ ]?[m|mm]?");
7350 : }
7351 4 : psOptions->osZResUnit = endptr;
7352 702 : })
7353 698 : .help(_("Set/override the geometry Z coordinate resolution."));
7354 :
7355 698 : argParser->add_argument("-mRes")
7356 1396 : .metavar("<val>")
7357 698 : .store_into(psOptions->dfMRes)
7358 698 : .help(_("Set/override the geometry M coordinate resolution."));
7359 :
7360 698 : argParser->add_argument("-unsetCoordPrecision")
7361 698 : .store_into(psOptions->bUnsetCoordPrecision)
7362 : .help(_("Prevent the geometry coordinate resolution from being set on "
7363 698 : "target layer(s)."));
7364 :
7365 : ///////////////////////////////////////////////////////////////////////
7366 698 : argParser->add_group("Other options");
7367 :
7368 698 : argParser->add_quiet_argument(&psOptions->bQuiet);
7369 :
7370 698 : argParser->add_argument("-progress")
7371 698 : .store_into(psOptions->bDisplayProgress)
7372 : .help(_("Display progress on terminal. Only works if input layers have "
7373 698 : "the 'fast feature count' capability."));
7374 :
7375 : argParser->add_input_format_argument(
7376 : psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers
7377 698 : : nullptr);
7378 :
7379 : argParser->add_open_options_argument(
7380 698 : psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);
7381 :
7382 698 : argParser->add_argument("-doo")
7383 1396 : .metavar("<NAME>=<VALUE>")
7384 698 : .append()
7385 0 : .action([psOptions](const std::string &s)
7386 698 : { psOptions->aosDestOpenOptions.AddString(s.c_str()); })
7387 698 : .help(_("Open option(s) for output dataset."));
7388 :
7389 698 : argParser->add_usage_newline();
7390 :
7391 698 : argParser->add_argument("-fid")
7392 1396 : .metavar("<FID>")
7393 698 : .store_into(psOptions->nFIDToFetch)
7394 : .help(_("If provided, only the feature with the specified feature id "
7395 698 : "will be processed."));
7396 :
7397 698 : argParser->add_argument("-preserve_fid")
7398 698 : .store_into(psOptions->bPreserveFID)
7399 : .help(_("Use the FID of the source features instead of letting the "
7400 698 : "output driver automatically assign a new one."));
7401 :
7402 698 : argParser->add_argument("-unsetFid")
7403 698 : .store_into(psOptions->bUnsetFid)
7404 : .help(_("Prevent the name of the source FID column and source feature "
7405 698 : "IDs from being re-used."));
7406 :
7407 : {
7408 698 : auto &group = argParser->add_mutually_exclusive_group();
7409 698 : group.add_argument("-skip", "-skipfailures")
7410 698 : .flag()
7411 : .action(
7412 4 : [psOptions](const std::string &)
7413 : {
7414 4 : psOptions->bSkipFailures = true;
7415 4 : psOptions->nGroupTransactions = 1; /* #2409 */
7416 698 : })
7417 698 : .help(_("Continue after a failure, skipping the failed feature."));
7418 :
7419 698 : auto &arg = group.add_argument("-gt")
7420 1396 : .metavar("<n>|unlimited")
7421 : .action(
7422 8 : [psOptions](const std::string &s)
7423 : {
7424 : /* If skipfailures is already set we should not
7425 : modify nGroupTransactions = 1 #2409 */
7426 4 : if (!psOptions->bSkipFailures)
7427 : {
7428 4 : if (EQUAL(s.c_str(), "unlimited"))
7429 1 : psOptions->nGroupTransactions = -1;
7430 : else
7431 3 : psOptions->nGroupTransactions =
7432 3 : atoi(s.c_str());
7433 : }
7434 698 : })
7435 698 : .help(_("Group <n> features per transaction "));
7436 :
7437 698 : argParser->add_hidden_alias_for(arg, "tg");
7438 : }
7439 :
7440 698 : argParser->add_argument("-limit")
7441 1396 : .metavar("<nb_features>")
7442 698 : .store_into(psOptions->nLimit)
7443 698 : .help(_("Limit the number of features per layer."));
7444 :
7445 698 : argParser->add_argument("-ds_transaction")
7446 698 : .flag()
7447 : .action(
7448 1 : [psOptions](const std::string &)
7449 : {
7450 1 : psOptions->nLayerTransaction = FALSE;
7451 1 : psOptions->bForceTransaction = true;
7452 698 : })
7453 698 : .help(_("Force the use of a dataset level transaction."));
7454 :
7455 : /* Undocumented. Just a provision. Default behavior should be OK */
7456 698 : argParser->add_argument("-lyr_transaction")
7457 698 : .flag()
7458 698 : .hidden()
7459 0 : .action([psOptions](const std::string &)
7460 698 : { psOptions->nLayerTransaction = TRUE; })
7461 698 : .help(_("Force the use of a layer level transaction."));
7462 :
7463 : argParser->add_metadata_item_options_argument(
7464 698 : psOptions->aosMetadataOptions);
7465 :
7466 698 : argParser->add_argument("-nomd")
7467 698 : .flag()
7468 4 : .action([psOptions](const std::string &)
7469 698 : { psOptions->bCopyMD = false; })
7470 : .help(_("Disable copying of metadata from source dataset and layers "
7471 698 : "into target dataset and layers."));
7472 :
7473 698 : if (psOptionsForBinary)
7474 : {
7475 131 : argParser->add_argument("dst_dataset_name")
7476 262 : .metavar("<dst_dataset_name>")
7477 131 : .store_into(psOptionsForBinary->osDestDataSource)
7478 131 : .help(_("Output dataset."));
7479 :
7480 131 : argParser->add_argument("src_dataset_name")
7481 262 : .metavar("<src_dataset_name>")
7482 131 : .store_into(psOptionsForBinary->osDataSource)
7483 131 : .help(_("Input dataset."));
7484 : }
7485 :
7486 698 : argParser->add_argument("layer")
7487 698 : .remaining()
7488 1396 : .metavar("<layer_name>")
7489 698 : .help(_("Layer name"));
7490 698 : return argParser;
7491 : }
7492 :
7493 : /************************************************************************/
7494 : /* GDALVectorTranslateGetParserUsage() */
7495 : /************************************************************************/
7496 :
7497 0 : std::string GDALVectorTranslateGetParserUsage()
7498 : {
7499 : try
7500 : {
7501 0 : GDALVectorTranslateOptions sOptions;
7502 0 : GDALVectorTranslateOptionsForBinary sOptionsForBinary;
7503 : auto argParser = GDALVectorTranslateOptionsGetParser(
7504 0 : &sOptions, &sOptionsForBinary, 1, 1);
7505 0 : return argParser->usage();
7506 : }
7507 0 : catch (const std::exception &err)
7508 : {
7509 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
7510 0 : err.what());
7511 0 : return std::string();
7512 : }
7513 : }
7514 :
7515 : /************************************************************************/
7516 : /* CHECK_HAS_ENOUGH_ADDITIONAL_ARGS() */
7517 : /************************************************************************/
7518 :
7519 : #ifndef CheckHasEnoughAdditionalArgs_defined
7520 : #define CheckHasEnoughAdditionalArgs_defined
7521 :
7522 39 : static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,
7523 : int nExtraArg, int nArgc)
7524 : {
7525 39 : if (i + nExtraArg >= nArgc)
7526 : {
7527 2 : CPLError(CE_Failure, CPLE_IllegalArg,
7528 2 : "%s option requires %d argument%s", papszArgv[i], nExtraArg,
7529 : nExtraArg == 1 ? "" : "s");
7530 2 : return false;
7531 : }
7532 37 : return true;
7533 : }
7534 : #endif
7535 :
7536 : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
7537 : if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc)) \
7538 : { \
7539 : return nullptr; \
7540 : }
7541 :
7542 : /************************************************************************/
7543 : /* GDALVectorTranslateOptionsNew() */
7544 : /************************************************************************/
7545 :
7546 : /**
7547 : * allocates a GDALVectorTranslateOptions struct.
7548 : *
7549 : * @param papszArgv NULL terminated list of options (potentially including
7550 : * filename and open options too), or NULL. The accepted options are the ones of
7551 : * the <a href="/programs/ogr2ogr.html">ogr2ogr</a> utility.
7552 : * @param psOptionsForBinary (output) may be NULL (and should generally be
7553 : * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
7554 : * GDALVectorTranslateOptionsForBinaryNew() prior to
7555 : * this function. Will be filled with potentially present filename, open
7556 : * options,...
7557 : * @return pointer to the allocated GDALVectorTranslateOptions struct. Must be
7558 : * freed with GDALVectorTranslateOptionsFree().
7559 : *
7560 : * @since GDAL 2.1
7561 : */
7562 702 : GDALVectorTranslateOptions *GDALVectorTranslateOptionsNew(
7563 : char **papszArgv, GDALVectorTranslateOptionsForBinary *psOptionsForBinary)
7564 : {
7565 1401 : auto psOptions = std::make_unique<GDALVectorTranslateOptions>();
7566 :
7567 : /* -------------------------------------------------------------------- */
7568 : /* Pre-processing for custom syntax that ArgumentParser does not */
7569 : /* support. */
7570 : /* -------------------------------------------------------------------- */
7571 :
7572 1401 : CPLStringList aosArgv;
7573 702 : const int nArgc = CSLCount(papszArgv);
7574 702 : int nCountClipSrc = 0;
7575 702 : int nCountClipDst = 0;
7576 3384 : for (int i = 0;
7577 3384 : i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
7578 : {
7579 2686 : if (EQUAL(papszArgv[i], "-gcp"))
7580 : {
7581 : // repeated argument of varying size: not handled by argparse.
7582 :
7583 15 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
7584 15 : char *endptr = nullptr;
7585 : /* -gcp pixel line easting northing [elev] */
7586 :
7587 15 : psOptions->oGCPs.nGCPCount++;
7588 30 : psOptions->oGCPs.pasGCPs = static_cast<GDAL_GCP *>(
7589 15 : CPLRealloc(psOptions->oGCPs.pasGCPs,
7590 15 : sizeof(GDAL_GCP) * psOptions->oGCPs.nGCPCount));
7591 15 : GDALInitGCPs(1, psOptions->oGCPs.pasGCPs +
7592 15 : psOptions->oGCPs.nGCPCount - 1);
7593 :
7594 15 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]
7595 15 : .dfGCPPixel = CPLAtof(papszArgv[++i]);
7596 15 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPLine =
7597 15 : CPLAtof(papszArgv[++i]);
7598 15 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPX =
7599 15 : CPLAtof(papszArgv[++i]);
7600 15 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPY =
7601 15 : CPLAtof(papszArgv[++i]);
7602 29 : if (papszArgv[i + 1] != nullptr &&
7603 14 : (CPLStrtod(papszArgv[i + 1], &endptr) != 0.0 ||
7604 14 : papszArgv[i + 1][0] == '0'))
7605 : {
7606 : /* Check that last argument is really a number and not a
7607 : * filename */
7608 : /* looking like a number (see ticket #863) */
7609 0 : if (endptr && *endptr == 0)
7610 0 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]
7611 0 : .dfGCPZ = CPLAtof(papszArgv[++i]);
7612 : }
7613 :
7614 : /* should set id and info? */
7615 : }
7616 :
7617 2671 : else if (EQUAL(papszArgv[i], "-clipsrc"))
7618 : {
7619 15 : if (nCountClipSrc)
7620 : {
7621 1 : CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
7622 1 : papszArgv[i]);
7623 1 : return nullptr;
7624 : }
7625 : // argparse doesn't handle well variable number of values
7626 : // just before the positional arguments, so we have to detect
7627 : // it manually and set the correct number.
7628 14 : nCountClipSrc = 1;
7629 14 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
7630 16 : if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
7631 3 : i + 4 < nArgc)
7632 : {
7633 2 : nCountClipSrc = 4;
7634 : }
7635 :
7636 45 : for (int j = 0; j < 1 + nCountClipSrc; ++j)
7637 : {
7638 32 : aosArgv.AddString(papszArgv[i]);
7639 32 : ++i;
7640 : }
7641 13 : --i;
7642 : }
7643 :
7644 2656 : else if (EQUAL(papszArgv[i], "-clipdst"))
7645 : {
7646 11 : if (nCountClipDst)
7647 : {
7648 1 : CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
7649 1 : papszArgv[i]);
7650 1 : return nullptr;
7651 : }
7652 : // argparse doesn't handle well variable number of values
7653 : // just before the positional arguments, so we have to detect
7654 : // it manually and set the correct number.
7655 10 : nCountClipDst = 1;
7656 10 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
7657 12 : if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
7658 3 : i + 4 < nArgc)
7659 : {
7660 2 : nCountClipDst = 4;
7661 : }
7662 :
7663 33 : for (int j = 0; j < 1 + nCountClipDst; ++j)
7664 : {
7665 24 : aosArgv.AddString(papszArgv[i]);
7666 24 : ++i;
7667 : }
7668 9 : --i;
7669 : }
7670 :
7671 : else
7672 : {
7673 2645 : aosArgv.AddString(papszArgv[i]);
7674 : }
7675 : }
7676 :
7677 : try
7678 : {
7679 : auto argParser = GDALVectorTranslateOptionsGetParser(
7680 1393 : psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);
7681 :
7682 : // Collect non-positional arguments for VectorTranslateFrom() case
7683 697 : psOptions->aosArguments =
7684 1395 : argParser->get_non_positional_arguments(aosArgv);
7685 :
7686 697 : argParser->parse_args_without_binary_name(aosArgv.List());
7687 :
7688 673 : if (psOptionsForBinary)
7689 128 : psOptionsForBinary->bQuiet = psOptions->bQuiet;
7690 :
7691 681 : if (auto oSpat = argParser->present<std::vector<double>>("-spat"))
7692 : {
7693 16 : OGRLinearRing oRing;
7694 8 : const double dfMinX = (*oSpat)[0];
7695 8 : const double dfMinY = (*oSpat)[1];
7696 8 : const double dfMaxX = (*oSpat)[2];
7697 8 : const double dfMaxY = (*oSpat)[3];
7698 :
7699 8 : oRing.addPoint(dfMinX, dfMinY);
7700 8 : oRing.addPoint(dfMinX, dfMaxY);
7701 8 : oRing.addPoint(dfMaxX, dfMaxY);
7702 8 : oRing.addPoint(dfMaxX, dfMinY);
7703 8 : oRing.addPoint(dfMinX, dfMinY);
7704 :
7705 16 : auto poSpatialFilter = std::make_shared<OGRPolygon>();
7706 8 : poSpatialFilter->addRing(&oRing);
7707 8 : psOptions->poSpatialFilter = poSpatialFilter;
7708 : }
7709 :
7710 673 : if (auto oClipSrc =
7711 673 : argParser->present<std::vector<std::string>>("-clipsrc"))
7712 : {
7713 12 : const std::string &osVal = (*oClipSrc)[0];
7714 :
7715 12 : psOptions->poClipSrc.reset();
7716 12 : psOptions->osClipSrcDS.clear();
7717 :
7718 : VSIStatBufL sStat;
7719 12 : psOptions->bClipSrc = true;
7720 12 : if (oClipSrc->size() == 4)
7721 : {
7722 1 : const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
7723 1 : const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
7724 1 : const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
7725 1 : const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
7726 :
7727 2 : OGRLinearRing oRing;
7728 :
7729 1 : oRing.addPoint(dfMinX, dfMinY);
7730 1 : oRing.addPoint(dfMinX, dfMaxY);
7731 1 : oRing.addPoint(dfMaxX, dfMaxY);
7732 1 : oRing.addPoint(dfMaxX, dfMinY);
7733 1 : oRing.addPoint(dfMinX, dfMinY);
7734 :
7735 2 : auto poPoly = std::make_shared<OGRPolygon>();
7736 1 : psOptions->poClipSrc = poPoly;
7737 1 : poPoly->addRing(&oRing);
7738 : }
7739 11 : else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
7740 13 : STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
7741 2 : VSIStatL(osVal.c_str(), &sStat) != 0)
7742 : {
7743 2 : OGRGeometry *poGeom = nullptr;
7744 2 : OGRGeometryFactory::createFromWkt(osVal.c_str(), nullptr,
7745 : &poGeom);
7746 2 : psOptions->poClipSrc.reset(poGeom);
7747 2 : if (psOptions->poClipSrc == nullptr)
7748 : {
7749 0 : CPLError(CE_Failure, CPLE_IllegalArg,
7750 : "Invalid geometry. Must be a valid POLYGON or "
7751 : "MULTIPOLYGON WKT");
7752 0 : return nullptr;
7753 : }
7754 : }
7755 9 : else if (EQUAL(osVal.c_str(), "spat_extent"))
7756 : {
7757 : // Nothing to do
7758 : }
7759 : else
7760 : {
7761 8 : psOptions->osClipSrcDS = osVal;
7762 : }
7763 : }
7764 :
7765 673 : if (auto oClipDst =
7766 673 : argParser->present<std::vector<std::string>>("-clipdst"))
7767 : {
7768 8 : const std::string &osVal = (*oClipDst)[0];
7769 :
7770 8 : psOptions->poClipDst.reset();
7771 8 : psOptions->osClipDstDS.clear();
7772 :
7773 : VSIStatBufL sStat;
7774 8 : if (oClipDst->size() == 4)
7775 : {
7776 1 : const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());
7777 1 : const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());
7778 1 : const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());
7779 1 : const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());
7780 :
7781 2 : OGRLinearRing oRing;
7782 :
7783 1 : oRing.addPoint(dfMinX, dfMinY);
7784 1 : oRing.addPoint(dfMinX, dfMaxY);
7785 1 : oRing.addPoint(dfMaxX, dfMaxY);
7786 1 : oRing.addPoint(dfMaxX, dfMinY);
7787 1 : oRing.addPoint(dfMinX, dfMinY);
7788 :
7789 2 : auto poPoly = std::make_shared<OGRPolygon>();
7790 1 : psOptions->poClipDst = poPoly;
7791 1 : poPoly->addRing(&oRing);
7792 : }
7793 7 : else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
7794 8 : STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
7795 1 : VSIStatL(osVal.c_str(), &sStat) != 0)
7796 : {
7797 1 : OGRGeometry *poGeom = nullptr;
7798 1 : OGRGeometryFactory::createFromWkt(osVal.c_str(), nullptr,
7799 : &poGeom);
7800 1 : psOptions->poClipDst.reset(poGeom);
7801 1 : if (psOptions->poClipDst == nullptr)
7802 : {
7803 0 : CPLError(CE_Failure, CPLE_IllegalArg,
7804 : "Invalid geometry. Must be a valid POLYGON or "
7805 : "MULTIPOLYGON WKT");
7806 0 : return nullptr;
7807 : }
7808 : }
7809 : else
7810 : {
7811 6 : psOptions->osClipDstDS = osVal;
7812 : }
7813 : }
7814 :
7815 1346 : auto layers = argParser->present<std::vector<std::string>>("layer");
7816 673 : if (layers)
7817 : {
7818 45 : for (const auto &layer : *layers)
7819 : {
7820 31 : psOptions->aosLayers.AddString(layer.c_str());
7821 : }
7822 : }
7823 673 : if (psOptionsForBinary)
7824 : {
7825 128 : psOptionsForBinary->eAccessMode = psOptions->eAccessMode;
7826 128 : psOptionsForBinary->osFormat = psOptions->osFormat;
7827 :
7828 128 : if (!(CPLTestBool(
7829 : psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
7830 : "NATIVE_DATA",
7831 : psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
7832 : "@NATIVE_DATA", "TRUE")))))
7833 : {
7834 0 : psOptions->bNativeData = false;
7835 : }
7836 :
7837 128 : if (psOptions->bNativeData &&
7838 127 : psOptionsForBinary->aosOpenOptions.FetchNameValue(
7839 255 : "NATIVE_DATA") == nullptr &&
7840 127 : psOptionsForBinary->aosOpenOptions.FetchNameValue(
7841 : "@NATIVE_DATA") == nullptr)
7842 : {
7843 : psOptionsForBinary->aosOpenOptions.AddString(
7844 127 : "@NATIVE_DATA=YES");
7845 : }
7846 : }
7847 :
7848 673 : return psOptions.release();
7849 : }
7850 22 : catch (const std::exception &err)
7851 : {
7852 22 : CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
7853 22 : return nullptr;
7854 : }
7855 : }
7856 :
7857 : /************************************************************************/
7858 : /* GDALVectorTranslateOptionsFree() */
7859 : /************************************************************************/
7860 :
7861 : /**
7862 : * Frees the GDALVectorTranslateOptions struct.
7863 : *
7864 : * @param psOptions the options struct for GDALVectorTranslate().
7865 : * @since GDAL 2.1
7866 : */
7867 :
7868 671 : void GDALVectorTranslateOptionsFree(GDALVectorTranslateOptions *psOptions)
7869 : {
7870 671 : delete psOptions;
7871 671 : }
7872 :
7873 : /************************************************************************/
7874 : /* GDALVectorTranslateOptionsSetProgress() */
7875 : /************************************************************************/
7876 :
7877 : /**
7878 : * Set a progress function.
7879 : *
7880 : * @param psOptions the options struct for GDALVectorTranslate().
7881 : * @param pfnProgress the progress callback.
7882 : * @param pProgressData the user data for the progress callback.
7883 : *
7884 : * @since GDAL 2.1
7885 : */
7886 :
7887 129 : void GDALVectorTranslateOptionsSetProgress(
7888 : GDALVectorTranslateOptions *psOptions, GDALProgressFunc pfnProgress,
7889 : void *pProgressData)
7890 : {
7891 129 : psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
7892 129 : psOptions->pProgressData = pProgressData;
7893 129 : if (pfnProgress == GDALTermProgress)
7894 127 : psOptions->bQuiet = false;
7895 129 : }
7896 :
7897 : #undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS
|