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