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