Coverage Report

Created: 2026-09-26 08:22

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