Coverage Report

Created: 2026-09-14 06:50

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
0
#define GEOMTYPE_UNCHANGED -2
83
84
#define COORD_DIM_UNCHANGED -1
85
0
#define COORD_DIM_LAYER_DIM -2
86
0
#define COORD_DIM_XYM -3
87
88
0
#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
0
        {
459
0
            if (dfX < m_dfLeftX)
460
0
            {
461
0
                m_dfLeftX = dfX;
462
0
                m_dfLeftY = dfY;
463
0
                m_dfLeftZ = dfZ;
464
0
            }
465
0
            if (dfX > m_dfRightX)
466
0
            {
467
0
                m_dfRightX = dfX;
468
0
                m_dfRightY = dfY;
469
0
                m_dfRightZ = dfZ;
470
0
            }
471
0
            if (dfY < m_dfBottomY)
472
0
            {
473
0
                m_dfBottomX = dfX;
474
0
                m_dfBottomY = dfY;
475
0
                m_dfBottomZ = dfZ;
476
0
            }
477
0
            if (dfY > m_dfTopY)
478
0
            {
479
0
                m_dfTopX = dfX;
480
0
                m_dfTopY = dfY;
481
0
                m_dfTopZ = 0;
482
0
            }
483
0
        }
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
0
{
658
0
    auto poDS = std::unique_ptr<GDALDataset>(
659
0
        GDALDataset::Open(osDS.c_str(), GDAL_OF_VECTOR));
660
0
    if (poDS == nullptr)
661
0
        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
0
{
1469
0
    if (poSpatialFilter == nullptr)
1470
0
        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
0
{
2206
0
    if (!poODS->GetDriver()->GetMetadataItem(GDAL_DCAP_CREATE_RELATIONSHIP))
2207
0
        return;
2208
2209
0
    const auto aosRelationshipNames = poDS->GetRelationshipNames();
2210
0
    if (aosRelationshipNames.empty())
2211
0
        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
0
{
2315
0
    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
0
    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
0
    GDALDatasetH hSrcDS = pahSrcDS[0];
2334
0
    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
0
    auto psOptions =
2344
0
        psOptionsIn ? std::make_unique<GDALVectorTranslateOptions>(*psOptionsIn)
2345
0
                    : std::make_unique<GDALVectorTranslateOptions>();
2346
2347
0
    bool bAppend = false;
2348
0
    bool bUpdate = false;
2349
0
    bool bOverwrite = false;
2350
2351
0
    if (psOptions->eAccessMode == ACCESS_UPDATE)
2352
0
    {
2353
0
        bUpdate = true;
2354
0
    }
2355
0
    else if (psOptions->eAccessMode == ACCESS_APPEND)
2356
0
    {
2357
0
        bAppend = true;
2358
0
        bUpdate = true;
2359
0
    }
2360
0
    else if (psOptions->eAccessMode == ACCESS_OVERWRITE)
2361
0
    {
2362
0
        bOverwrite = true;
2363
0
        bUpdate = true;
2364
0
    }
2365
0
    else if (hDstDS != nullptr)
2366
0
    {
2367
0
        bUpdate = true;
2368
0
    }
2369
2370
0
    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
0
    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
0
    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
0
    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
0
    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
0
    if (!psOptions->osSourceSRSDef.empty() &&
2419
0
        psOptions->osOutputSRSDef.empty() && psOptions->osSpatSRSDef.empty())
2420
0
    {
2421
0
        CPLError(CE_Failure, CPLE_IllegalArg,
2422
0
                 "if -s_srs is specified, -t_srs and/or -spat_srs must also be "
2423
0
                 "specified.");
2424
0
        if (pbUsageError)
2425
0
            *pbUsageError = TRUE;
2426
0
        return nullptr;
2427
0
    }
2428
2429
    /* -------------------------------------------------------------------- */
2430
    /*      Parse spatial filter SRS if needed.                             */
2431
    /* -------------------------------------------------------------------- */
2432
0
    OGRSpatialReferenceRefCountedPtr poSpatSRS;
2433
0
    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
0
    if (!psOptions->poClipSrc && !psOptions->osClipSrcDS.empty())
2456
0
    {
2457
0
        psOptions->poClipSrc =
2458
0
            LoadGeometry(psOptions->osClipSrcDS, psOptions->osClipSrcSQL,
2459
0
                         psOptions->osClipSrcLayer, psOptions->osClipSrcWhere,
2460
0
                         psOptions->bMakeValid);
2461
0
        if (psOptions->poClipSrc == nullptr)
2462
0
        {
2463
0
            CPLError(CE_Failure, CPLE_IllegalArg,
2464
0
                     "cannot load source clip geometry");
2465
0
            return nullptr;
2466
0
        }
2467
0
    }
2468
0
    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
0
    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
0
    std::string osReason;
2488
0
    if (psOptions->poClipSrc && !psOptions->poClipSrc->IsValid(&osReason))
2489
0
    {
2490
0
        if (!psOptions->bMakeValid)
2491
0
        {
2492
0
            CPLError(
2493
0
                CE_Failure, CPLE_IllegalArg,
2494
0
                "-clipsrc geometry is invalid (%s). You can try to make it "
2495
0
                "valid with -makevalid, but the results of the operation "
2496
0
                "should be manually inspected.",
2497
0
                osReason.c_str());
2498
0
            return nullptr;
2499
0
        }
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
0
    if (!psOptions->osClipDstDS.empty())
2519
0
    {
2520
0
        psOptions->poClipDst =
2521
0
            LoadGeometry(psOptions->osClipDstDS, psOptions->osClipDstSQL,
2522
0
                         psOptions->osClipDstLayer, psOptions->osClipDstWhere,
2523
0
                         psOptions->bMakeValid);
2524
0
        if (psOptions->poClipDst == nullptr)
2525
0
        {
2526
0
            CPLError(CE_Failure, CPLE_IllegalArg,
2527
0
                     "cannot load dest clip geometry");
2528
0
            return nullptr;
2529
0
        }
2530
0
    }
2531
2532
0
    if (psOptions->poClipDst && !psOptions->poClipDst->IsValid(&osReason))
2533
0
    {
2534
0
        if (!psOptions->bMakeValid)
2535
0
        {
2536
0
            CPLError(
2537
0
                CE_Failure, CPLE_IllegalArg,
2538
0
                "-clipdst geometry is invalid (%s). You can try to make it "
2539
0
                "valid with -makevalid, but the results of the operation "
2540
0
                "should be manually inspected.",
2541
0
                osReason.c_str());
2542
0
            return nullptr;
2543
0
        }
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
0
    GDALDataset *poDS = GDALDataset::FromHandle(hSrcDS);
2563
0
    GDALDataset *poODS = nullptr;
2564
0
    GDALDriver *poDriver = nullptr;
2565
0
    CPLString osDestFilename;
2566
2567
0
    if (hDstDS)
2568
0
    {
2569
0
        poODS = GDALDataset::FromHandle(hDstDS);
2570
0
        osDestFilename = poODS->GetDescription();
2571
0
    }
2572
0
    else
2573
0
    {
2574
0
        osDestFilename = pszDest;
2575
0
    }
2576
2577
    /* Various tests to avoid overwriting the source layer(s) */
2578
    /* or to avoid appending a layer to itself */
2579
0
    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
0
    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
0
    std::vector<std::string> aoDrivers;
2636
0
    if (poODS == nullptr && psOptions->osFormat.empty())
2637
0
    {
2638
0
        const auto nErrorCount = CPLGetErrorCounter();
2639
0
        aoDrivers = CPLStringList(GDALGetOutputDriversForDatasetName(
2640
0
            pszDest, GDAL_OF_VECTOR, /* bSingleMatch = */ true,
2641
0
            /* bWarn = */ true));
2642
0
        if (!bUpdate && aoDrivers.size() == 1)
2643
0
        {
2644
0
            GDALDriverH hDriver = GDALGetDriverByName(aoDrivers[0].c_str());
2645
0
            const char *pszPrefix = GDALGetMetadataItem(
2646
0
                hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);
2647
0
            if (pszPrefix && STARTS_WITH_CI(pszDest, pszPrefix))
2648
0
            {
2649
0
                bUpdate = true;
2650
0
            }
2651
0
        }
2652
0
        else if (aoDrivers.empty() && CPLGetErrorCounter() > nErrorCount &&
2653
0
                 CPLGetLastErrorType() == CE_Failure)
2654
0
        {
2655
0
            return nullptr;
2656
0
        }
2657
0
    }
2658
2659
0
    if (bUpdate && poODS == nullptr)
2660
0
    {
2661
0
        poODS = GDALDataset::Open(
2662
0
            osDestFilename, GDAL_OF_UPDATE | GDAL_OF_VECTOR, nullptr,
2663
0
            psOptions->aosDestOpenOptions.List(), nullptr);
2664
2665
0
        if (poODS == nullptr)
2666
0
        {
2667
0
            if (bOverwrite || bAppend)
2668
0
            {
2669
0
                poODS = GDALDataset::Open(
2670
0
                    osDestFilename, GDAL_OF_VECTOR, nullptr,
2671
0
                    psOptions->aosDestOpenOptions.List(), nullptr);
2672
0
                if (poODS == nullptr)
2673
0
                {
2674
                    /* OK the datasource doesn't exist at all */
2675
0
                    bUpdate = false;
2676
0
                }
2677
0
                else
2678
0
                {
2679
0
                    poDriver = poODS->GetDriver();
2680
0
                    GDALClose(poODS);
2681
0
                    poODS = nullptr;
2682
0
                }
2683
0
            }
2684
2685
0
            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
0
        }
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
0
    }
2701
2702
0
    if (poODS)
2703
0
        poDriver = poODS->GetDriver();
2704
2705
    /* -------------------------------------------------------------------- */
2706
    /*      Find the output driver.                                         */
2707
    /* -------------------------------------------------------------------- */
2708
0
    bool bNewDataSource = false;
2709
0
    if (!bUpdate)
2710
0
    {
2711
0
        GDALDriverManager *poDM = GetGDALDriverManager();
2712
2713
0
        if (psOptions->bNoOverwrite && !EQUAL(pszDest, ""))
2714
0
        {
2715
0
            const char *pszType = "";
2716
0
            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
0
        }
2725
2726
0
        if (psOptions->osFormat.empty())
2727
0
        {
2728
0
            if (aoDrivers.empty())
2729
0
            {
2730
0
                if (CPLGetExtensionSafe(pszDest).empty() &&
2731
0
                    !psOptions->bInvokedFromGdalAlgorithm)
2732
0
                {
2733
0
                    psOptions->osFormat = "ESRI Shapefile";
2734
0
                }
2735
0
                else
2736
0
                {
2737
0
                    CPLError(CE_Failure, CPLE_AppDefined,
2738
0
                             "Cannot guess driver for %s", pszDest);
2739
0
                    return nullptr;
2740
0
                }
2741
0
            }
2742
0
            else
2743
0
            {
2744
0
                psOptions->osFormat = aoDrivers[0];
2745
0
            }
2746
0
            CPLDebug("GDAL", "Using %s driver", psOptions->osFormat.c_str());
2747
0
        }
2748
2749
0
        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
0
        if (EQUAL(osOGRCompatFormat, "GMT") ||
2756
0
            EQUAL(osOGRCompatFormat, "VRT") ||
2757
0
            EQUAL(osOGRCompatFormat, "SDTS") || EQUAL(osOGRCompatFormat, "PDS"))
2758
0
        {
2759
0
            osOGRCompatFormat = "OGR_" + osOGRCompatFormat;
2760
0
        }
2761
0
        poDriver = poDM->GetDriverByName(osOGRCompatFormat);
2762
0
        if (poDriver == nullptr)
2763
0
        {
2764
0
            CPLError(CE_Failure, CPLE_AppDefined, "Unable to find driver `%s'.",
2765
0
                     psOptions->osFormat.c_str());
2766
0
            return nullptr;
2767
0
        }
2768
2769
0
        CSLConstList papszDriverMD = poDriver->GetMetadata();
2770
0
        if (!CPLTestBool(
2771
0
                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
0
        if (poDriver->CanVectorTranslateFrom(
2780
0
                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
0
        if (!CPLTestBool(
2788
0
                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
0
        if (!psOptions->aosDestOpenOptions.empty())
2805
0
        {
2806
0
            CPLError(CE_Warning, CPLE_AppDefined,
2807
0
                     "-doo ignored when creating the output datasource.");
2808
0
        }
2809
2810
0
        const bool bSingleLayer =
2811
0
            (!psOptions->osSQLStatement.empty() ||
2812
0
             psOptions->aosLayers.size() == 1 ||
2813
0
             (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1));
2814
2815
0
        bool bOutputDirectory =
2816
0
            !bSingleLayer && CPLGetExtensionSafe(osDestFilename).empty() &&
2817
0
            poDriver->GetMetadataItem(
2818
0
                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
0
        VSIStatBufL sStat;
2830
0
        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
2831
0
            !bSingleLayer && psOptions->osNewLayerName.empty() &&
2832
0
            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
0
        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
0
        CPLStringList aosDSCO(psOptions->aosDSCO);
2857
2858
0
        if (!aosDSCO.FetchNameValue("SINGLE_LAYER"))
2859
0
        {
2860
            // Informs the target driver (e.g. JSONFG) if a single layer
2861
            // will be created
2862
0
            const char *pszCOList =
2863
0
                poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
2864
0
            if (bSingleLayer && pszCOList && strstr(pszCOList, "SINGLE_LAYER"))
2865
0
            {
2866
0
                aosDSCO.SetNameValue("SINGLE_LAYER", "YES");
2867
0
            }
2868
0
        }
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
0
        if (EQUAL(poDriver->GetDescription(), "CSV") &&
2874
0
            !aosDSCO.FetchNameValue("GEOMETRY") &&
2875
0
            EQUAL(psOptions->aosLCO.FetchNameValueDef("GEOMETRY", ""),
2876
0
                  "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
0
        poODS = poDriver->Create(osDestFilename, 0, 0, 0, GDT_Unknown,
2887
0
                                 aosDSCO.List());
2888
0
        if (poODS == nullptr)
2889
0
        {
2890
0
            CPLError(CE_Failure, CPLE_AppDefined,
2891
0
                     "%s driver failed to create %s",
2892
0
                     psOptions->osFormat.c_str(), osDestFilename.c_str());
2893
0
            return nullptr;
2894
0
        }
2895
0
        bNewDataSource = true;
2896
2897
0
        if (psOptions->bCopyMD)
2898
0
        {
2899
0
            const CPLStringList aosDomains(poDS->GetMetadataDomainList());
2900
0
            for (const char *pszMD : aosDomains)
2901
0
            {
2902
0
                if (CSLConstList papszMD = poDS->GetMetadata(pszMD))
2903
0
                    poODS->SetMetadata(papszMD, pszMD);
2904
0
            }
2905
0
        }
2906
0
        for (const auto &[pszKey, pszValue] :
2907
0
             cpl::IterateNameValue(psOptions->aosMetadataOptions))
2908
0
        {
2909
0
            poODS->SetMetadataItem(pszKey, pszValue);
2910
0
        }
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
0
        if (!psOptions->osNewLayerName.empty() &&
2916
0
            EQUAL(psOptions->osFormat.c_str(), "GeoJSON"))
2917
0
        {
2918
0
            psOptions->aosLCO.SetNameValue("@NAME",
2919
0
                                           psOptions->osNewLayerName.c_str());
2920
0
        }
2921
0
    }
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
0
    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
0
    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
0
    const bool bRandomLayerReading = poDS->TestCapability(ODsCRandomLayerRead);
2964
0
    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
0
    if (psOptions->nLayerTransaction < 0)
2974
0
    {
2975
0
        if (bRandomLayerReading)
2976
0
            psOptions->nLayerTransaction = FALSE;
2977
0
        else
2978
0
            psOptions->nLayerTransaction =
2979
0
                !poODS->TestCapability(ODsCTransactions);
2980
0
    }
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
0
    OGRSpatialReferenceRefCountedPtr poOutputSRS;
2990
0
    if (!psOptions->osOutputSRSDef.empty())
2991
0
    {
2992
0
        poOutputSRS = OGRSpatialReferenceRefCountedPtr::makeInstance();
2993
0
        poOutputSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2994
0
        if (poOutputSRS->SetFromUserInput(psOptions->osOutputSRSDef.c_str()) !=
2995
0
            OGRERR_NONE)
2996
0
        {
2997
0
            CPLError(CE_Failure, CPLE_AppDefined,
2998
0
                     "Failed to process SRS definition: %s",
2999
0
                     psOptions->osOutputSRSDef.c_str());
3000
0
            return nullptr;
3001
0
        }
3002
0
        poOutputSRS->SetCoordinateEpoch(psOptions->dfOutputCoordinateEpoch);
3003
0
    }
3004
3005
    /* -------------------------------------------------------------------- */
3006
    /*      Parse the source SRS definition if possible.                    */
3007
    /* -------------------------------------------------------------------- */
3008
0
    OGRSpatialReference oSourceSRS;
3009
0
    OGRSpatialReference *poSourceSRS = nullptr;
3010
0
    if (!psOptions->osSourceSRSDef.empty())
3011
0
    {
3012
0
        oSourceSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
3013
0
        if (oSourceSRS.SetFromUserInput(psOptions->osSourceSRSDef.c_str()) !=
3014
0
            OGRERR_NONE)
3015
0
        {
3016
0
            CPLError(CE_Failure, CPLE_AppDefined,
3017
0
                     "Failed to process SRS definition: %s",
3018
0
                     psOptions->osSourceSRSDef.c_str());
3019
0
            return nullptr;
3020
0
        }
3021
0
        oSourceSRS.SetCoordinateEpoch(psOptions->dfSourceCoordinateEpoch);
3022
0
        poSourceSRS = &oSourceSRS;
3023
0
    }
3024
3025
    /* -------------------------------------------------------------------- */
3026
    /*      Create a transformation object from the source to               */
3027
    /*      destination coordinate system.                                  */
3028
    /* -------------------------------------------------------------------- */
3029
0
    std::unique_ptr<GCPCoordTransformation> poGCPCoordTrans;
3030
0
    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
0
    SetupTargetLayer oSetup;
3046
0
    oSetup.m_poSrcDS = poDS;
3047
0
    oSetup.m_poDstDS = poODS;
3048
0
    oSetup.m_papszLCO = psOptions->aosLCO.List();
3049
0
    oSetup.m_poOutputSRS = poOutputSRS.get();
3050
0
    oSetup.m_bTransform = psOptions->bTransform;
3051
0
    oSetup.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
3052
0
    oSetup.m_poUserSourceSRS = poSourceSRS;
3053
0
    oSetup.m_bSelFieldsSet = psOptions->bSelFieldsSet;
3054
0
    oSetup.m_papszSelFields = psOptions->aosSelFields.List();
3055
0
    oSetup.m_bAppend = bAppend;
3056
0
    oSetup.m_bAddMissingFields = psOptions->bAddMissingFields;
3057
0
    oSetup.m_eGType = psOptions->eGType;
3058
0
    oSetup.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
3059
0
    oSetup.m_nCoordDim = psOptions->nCoordDim;
3060
0
    oSetup.m_bOverwrite = bOverwrite;
3061
0
    oSetup.m_papszFieldTypesToString = psOptions->aosFieldTypesToString.List();
3062
0
    oSetup.m_papszMapFieldType = psOptions->aosMapFieldType.List();
3063
0
    oSetup.m_bUnsetFieldWidth = psOptions->bUnsetFieldWidth;
3064
0
    oSetup.m_bExplodeCollections = psOptions->bExplodeCollections;
3065
0
    oSetup.m_pszZField =
3066
0
        psOptions->osZField.empty() ? nullptr : psOptions->osZField.c_str();
3067
0
    oSetup.m_papszFieldMap = psOptions->aosFieldMap.List();
3068
0
    oSetup.m_pszWHERE =
3069
0
        psOptions->osWHERE.empty() ? nullptr : psOptions->osWHERE.c_str();
3070
0
    oSetup.m_bExactFieldNameMatch = psOptions->bExactFieldNameMatch;
3071
0
    oSetup.m_bQuiet = psOptions->bQuiet;
3072
0
    oSetup.m_bForceNullable = psOptions->bForceNullable;
3073
0
    oSetup.m_bResolveDomains = psOptions->bResolveDomains;
3074
0
    oSetup.m_bUnsetDefault = psOptions->bUnsetDefault;
3075
0
    oSetup.m_bUnsetFid = psOptions->bUnsetFid;
3076
0
    oSetup.m_bPreserveFID = psOptions->bPreserveFID;
3077
0
    oSetup.m_bCopyMD = psOptions->bCopyMD;
3078
0
    oSetup.m_bNativeData = psOptions->bNativeData;
3079
0
    oSetup.m_bNewDataSource = bNewDataSource;
3080
0
    oSetup.m_pszCTPipeline = psOptions->osCTPipeline.empty()
3081
0
                                 ? nullptr
3082
0
                                 : psOptions->osCTPipeline.c_str();
3083
0
    oSetup.m_aosCTOptions = psOptions->aosCTOptions;
3084
3085
0
    LayerTranslator oTranslator;
3086
0
    oTranslator.m_poSrcDS = poDS;
3087
0
    oTranslator.m_poODS = poODS;
3088
0
    oTranslator.m_bTransform = psOptions->bTransform;
3089
0
    oTranslator.m_bWrapDateline = psOptions->bWrapDateline;
3090
0
    oTranslator.m_osDateLineOffset =
3091
0
        CPLOPrintf("%g", psOptions->dfDateLineOffset);
3092
0
    oTranslator.m_poOutputSRS = poOutputSRS.get();
3093
0
    oTranslator.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
3094
0
    oTranslator.m_poUserSourceSRS = poSourceSRS;
3095
0
    oTranslator.m_poGCPCoordTrans = poGCPCoordTrans.get();
3096
0
    oTranslator.m_eGType = psOptions->eGType;
3097
0
    oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
3098
0
    oTranslator.m_bMakeValid = psOptions->bMakeValid;
3099
0
    oTranslator.m_bSkipInvalidGeom = psOptions->bSkipInvalidGeom;
3100
0
    oTranslator.m_nCoordDim = psOptions->nCoordDim;
3101
0
    oTranslator.m_eGeomOp = psOptions->eGeomOp;
3102
0
    oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam;
3103
    // Do not emit warning if the user specified directly the clip source geom
3104
0
    if (psOptions->osClipSrcDS.empty())
3105
0
        oTranslator.m_bWarnedClipSrcSRS = true;
3106
0
    oTranslator.m_poClipSrcOri = psOptions->poClipSrc.get();
3107
    // Do not emit warning if the user specified directly the clip dest geom
3108
0
    if (psOptions->osClipDstDS.empty())
3109
0
        oTranslator.m_bWarnedClipDstSRS = true;
3110
0
    oTranslator.m_poClipDstOri = psOptions->poClipDst.get();
3111
0
    oTranslator.m_bExplodeCollections = psOptions->bExplodeCollections;
3112
0
    oTranslator.m_bNativeData = psOptions->bNativeData;
3113
0
    oTranslator.m_nLimit = psOptions->nLimit;
3114
3115
0
    if (psOptions->nGroupTransactions)
3116
0
    {
3117
0
        if (!psOptions->nLayerTransaction)
3118
0
            poODS->StartTransaction(psOptions->bForceTransaction);
3119
0
    }
3120
3121
0
    GIntBig nTotalEventsDone = 0;
3122
3123
    /* -------------------------------------------------------------------- */
3124
    /*      Special case for -sql clause.  No source layers required.       */
3125
    /* -------------------------------------------------------------------- */
3126
0
    int nRetCode = 0;
3127
3128
0
    if (!psOptions->osSQLStatement.empty())
3129
0
    {
3130
        /* Special case: if output=input, then we must likely destroy the */
3131
        /* old table before to avoid transaction issues. */
3132
0
        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
0
        if (!psOptions->osWHERE.empty())
3138
0
            CPLError(CE_Warning, CPLE_AppDefined,
3139
0
                     "-where clause ignored in combination with -sql.");
3140
0
        if (psOptions->aosLayers.size() > 0)
3141
0
            CPLError(CE_Warning, CPLE_AppDefined,
3142
0
                     "layer names ignored in combination with -sql.");
3143
3144
0
        OGRLayer *poResultSet = poDS->ExecuteSQL(
3145
0
            psOptions->osSQLStatement.c_str(),
3146
0
            (!psOptions->bGeomFieldSet) ? psOptions->poSpatialFilter.get()
3147
0
                                        : nullptr,
3148
0
            psOptions->osDialect.empty() ? nullptr
3149
0
                                         : psOptions->osDialect.c_str());
3150
3151
0
        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
0
        else
3258
0
        {
3259
0
            if (CPLGetLastErrorNo() != 0)
3260
0
                nRetCode = 1;
3261
0
        }
3262
0
    }
3263
3264
    /* -------------------------------------------------------------------- */
3265
    /*      Special case for layer interleaving mode.                       */
3266
    /* -------------------------------------------------------------------- */
3267
0
    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
0
    else
3530
0
    {
3531
0
        std::vector<OGRLayer *> apoLayers;
3532
3533
        /* --------------------------------------------------------------------
3534
         */
3535
        /*      Process each data source layer. */
3536
        /* --------------------------------------------------------------------
3537
         */
3538
0
        if (psOptions->aosLayers.empty())
3539
0
        {
3540
0
            const int nLayerCount = poDS->GetLayerCount();
3541
3542
0
            for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3543
0
            {
3544
0
                OGRLayer *poLayer = poDS->GetLayer(iLayer);
3545
3546
0
                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
0
                if (!poDS->IsLayerPrivate(iLayer))
3553
0
                {
3554
0
                    apoLayers.push_back(poLayer);
3555
0
                }
3556
0
            }
3557
0
        }
3558
        /* --------------------------------------------------------------------
3559
         */
3560
        /*      Process specified data source layers. */
3561
        /* --------------------------------------------------------------------
3562
         */
3563
0
        else
3564
0
        {
3565
3566
0
            for (int iLayer = 0; psOptions->aosLayers[iLayer] != nullptr;
3567
0
                 iLayer++)
3568
0
            {
3569
0
                OGRLayer *poLayer =
3570
0
                    poDS->GetLayerByName(psOptions->aosLayers[iLayer]);
3571
3572
0
                if (poLayer == nullptr)
3573
0
                {
3574
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3575
0
                             "Couldn't fetch requested layer '%s'!",
3576
0
                             psOptions->aosLayers[iLayer]);
3577
0
                    if (!psOptions->bSkipFailures)
3578
0
                    {
3579
0
                        return nullptr;
3580
0
                    }
3581
0
                }
3582
3583
0
                apoLayers.emplace_back(poLayer);
3584
0
            }
3585
0
        }
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
0
        VSIStatBufL sStat;
3595
0
        const int nLayerCount = static_cast<int>(apoLayers.size());
3596
0
        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3597
0
            nLayerCount == 1 && psOptions->osNewLayerName.empty() &&
3598
0
            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
0
        std::vector<GIntBig> anLayerCountFeatures(nLayerCount);
3607
0
        GIntBig nCountLayersFeatures = 0;
3608
0
        GIntBig nAccCountFeatures = 0;
3609
3610
        /* First pass to apply filters and count all features if necessary */
3611
0
        for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3612
0
        {
3613
0
            OGRLayer *poLayer = apoLayers[iLayer];
3614
0
            if (poLayer == nullptr)
3615
0
                continue;
3616
3617
0
            if (!psOptions->osWHERE.empty())
3618
0
            {
3619
0
                if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=
3620
0
                    OGRERR_NONE)
3621
0
                {
3622
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3623
0
                             "SetAttributeFilter(%s) on layer '%s' failed.",
3624
0
                             psOptions->osWHERE.c_str(), poLayer->GetName());
3625
0
                    if (!psOptions->bSkipFailures)
3626
0
                    {
3627
0
                        return nullptr;
3628
0
                    }
3629
0
                }
3630
0
            }
3631
3632
0
            ApplySpatialFilter(
3633
0
                poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3634
0
                psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3635
0
                                         : nullptr,
3636
0
                poSourceSRS);
3637
3638
0
            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
0
        }
3672
3673
        /* Second pass to do the real job */
3674
0
        for (int iLayer = 0; iLayer < nLayerCount && nRetCode == 0; iLayer++)
3675
0
        {
3676
0
            OGRLayer *poLayer = apoLayers[iLayer];
3677
0
            if (poLayer == nullptr)
3678
0
                continue;
3679
3680
0
            std::unique_ptr<OGRLayer> poLayerToFree;
3681
0
            OGRLayer *poPassedLayer = poLayer;
3682
0
            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
0
            GDALProgressFunc pfnProgress = nullptr;
3713
0
            std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
3714
0
                pProgressArg(nullptr, GDALDestroyScaledProgress);
3715
3716
0
            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
0
            auto psInfo = oSetup.Setup(poPassedLayer,
3737
0
                                       psOptions->osNewLayerName.empty()
3738
0
                                           ? nullptr
3739
0
                                           : psOptions->osNewLayerName.c_str(),
3740
0
                                       psOptions.get(), nTotalEventsDone);
3741
3742
0
            poPassedLayer->ResetReading();
3743
3744
0
            if ((psInfo == nullptr ||
3745
0
                 !oTranslator.Translate(nullptr, psInfo.get(),
3746
0
                                        anLayerCountFeatures[iLayer], nullptr,
3747
0
                                        nTotalEventsDone, pfnProgress,
3748
0
                                        pProgressArg.get(), psOptions.get())) &&
3749
0
                !psOptions->bSkipFailures)
3750
0
            {
3751
0
                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
0
                else
3759
0
                {
3760
0
                    CPLError(
3761
0
                        CE_Failure, CPLE_AppDefined,
3762
0
                        "Terminating translation prematurely after failed\n"
3763
0
                        "translation of layer %s (use -skipfailures to skip "
3764
0
                        "errors)",
3765
0
                        poLayer->GetName());
3766
0
                }
3767
3768
0
                nRetCode = 1;
3769
0
            }
3770
3771
0
            if (psInfo)
3772
0
                psInfo->CheckSameCoordinateOperation();
3773
0
        }
3774
0
    }
3775
3776
0
    CopyRelationships(poODS, poDS);
3777
3778
    /* -------------------------------------------------------------------- */
3779
    /*      Process DS style table                                          */
3780
    /* -------------------------------------------------------------------- */
3781
3782
0
    poODS->SetStyleTable(poDS->GetStyleTable());
3783
3784
0
    if (psOptions->nGroupTransactions)
3785
0
    {
3786
0
        if (!psOptions->nLayerTransaction)
3787
0
        {
3788
0
            if (nRetCode != 0 && !psOptions->bSkipFailures)
3789
0
                poODS->RollbackTransaction();
3790
0
            else
3791
0
            {
3792
0
                OGRErr eRet = poODS->CommitTransaction();
3793
0
                if (eRet != OGRERR_NONE && eRet != OGRERR_UNSUPPORTED_OPERATION)
3794
0
                {
3795
0
                    nRetCode = 1;
3796
0
                }
3797
0
            }
3798
0
        }
3799
0
    }
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
0
    if (poODS->FlushCache() != CE_None)
3805
0
        nRetCode = 1;
3806
3807
0
    if (nRetCode == 0)
3808
0
    {
3809
0
        if (hDstDS)
3810
0
            return hDstDS;
3811
0
        else
3812
0
            return GDALDataset::ToHandle(poODSUniquePtr.release());
3813
0
    }
3814
3815
0
    return nullptr;
3816
0
}
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
0
{
3857
0
    if (nCoordDim == 2 && eGType != wkbNone)
3858
0
        return wkbFlatten(eGType);
3859
0
    else if (nCoordDim == 3 && eGType != wkbNone)
3860
0
        return wkbSetZ(wkbFlatten(eGType));
3861
0
    else if (nCoordDim == COORD_DIM_XYM && eGType != wkbNone)
3862
0
        return wkbSetM(wkbFlatten(eGType));
3863
0
    else if (nCoordDim == 4 && eGType != wkbNone)
3864
0
        return OGR_GT_SetModifier(static_cast<OGRwkbGeometryType>(eGType), TRUE,
3865
0
                                  TRUE);
3866
0
    else
3867
0
        return eGType;
3868
0
}
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
0
{
3881
0
    if (pbErrorOccurred)
3882
0
        *pbErrorOccurred = false;
3883
0
    if (pbOverwriteActuallyDone)
3884
0
        *pbOverwriteActuallyDone = false;
3885
0
    if (pbAddOverwriteLCO)
3886
0
        *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
0
    CPLPushErrorHandler(CPLQuietErrorHandler);
3893
0
    OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
3894
0
    CPLPopErrorHandler();
3895
0
    CPLErrorReset();
3896
3897
0
    int iLayer = -1;
3898
0
    if (poDstLayer != nullptr)
3899
0
    {
3900
0
        const int nLayerCount = poDstDS->GetLayerCount();
3901
0
        for (iLayer = 0; iLayer < nLayerCount; iLayer++)
3902
0
        {
3903
0
            OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
3904
0
            if (poLayer == poDstLayer)
3905
0
                break;
3906
0
        }
3907
3908
0
        if (iLayer == nLayerCount)
3909
            /* should not happen with an ideal driver */
3910
0
            poDstLayer = nullptr;
3911
0
    }
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
0
    if (poDstLayer != nullptr && bOverwrite)
3919
0
    {
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
0
        if (poDstDS->GetDriver()->GetMetadataItem(
3924
0
                GDAL_DS_LAYER_CREATIONOPTIONLIST) != nullptr &&
3925
0
            strstr(poDstDS->GetDriver()->GetMetadataItem(
3926
0
                       GDAL_DS_LAYER_CREATIONOPTIONLIST),
3927
0
                   "CARTODBFY") != nullptr)
3928
0
        {
3929
0
            if (pbAddOverwriteLCO)
3930
0
                *pbAddOverwriteLCO = true;
3931
0
            if (pbOverwriteActuallyDone)
3932
0
                *pbOverwriteActuallyDone = true;
3933
0
        }
3934
0
        else if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
3935
0
        {
3936
0
            CPLError(CE_Failure, CPLE_AppDefined,
3937
0
                     "DeleteLayer() failed when overwrite requested.");
3938
0
            if (pbErrorOccurred)
3939
0
                *pbErrorOccurred = true;
3940
0
        }
3941
0
        else
3942
0
        {
3943
0
            if (pbOverwriteActuallyDone)
3944
0
                *pbOverwriteActuallyDone = true;
3945
0
        }
3946
0
        poDstLayer = nullptr;
3947
0
    }
3948
3949
0
    return poDstLayer;
3950
0
}
3951
3952
/************************************************************************/
3953
/*                            ConvertType()                             */
3954
/************************************************************************/
3955
3956
static OGRwkbGeometryType ConvertType(GeomTypeConversion eGeomTypeConversion,
3957
                                      OGRwkbGeometryType eGType)
3958
0
{
3959
0
    OGRwkbGeometryType eRetType = eGType;
3960
3961
0
    if (eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
3962
0
        eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3963
0
    {
3964
0
        eRetType = OGR_GT_GetLinear(eRetType);
3965
0
    }
3966
3967
0
    if (eGeomTypeConversion == GTC_PROMOTE_TO_MULTI ||
3968
0
        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
0
    if (eGeomTypeConversion == GTC_CONVERT_TO_CURVE)
3982
0
        eRetType = OGR_GT_GetCurve(eRetType);
3983
3984
0
    return eRetType;
3985
0
}
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
0
{
3998
0
    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
0
    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
0
    if (bUnsetFieldWidth)
4048
0
    {
4049
0
        oFieldDefn.SetWidth(0);
4050
0
        oFieldDefn.SetPrecision(0);
4051
0
    }
4052
0
    if (bForceNullable)
4053
0
        oFieldDefn.SetNullable(TRUE);
4054
0
    if (bUnsetDefault)
4055
0
        oFieldDefn.SetDefault(nullptr);
4056
4057
0
    const auto poDstDriver = poDstDS->GetDriver();
4058
0
    const char *pszCreationFieldDataTypes =
4059
0
        poDstDriver
4060
0
            ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES)
4061
0
            : nullptr;
4062
0
    const char *pszCreationFieldDataSubtypes =
4063
0
        poDstDriver
4064
0
            ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES)
4065
0
            : nullptr;
4066
0
    if (pszCreationFieldDataTypes &&
4067
0
        strstr(pszCreationFieldDataTypes,
4068
0
               OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == nullptr)
4069
0
    {
4070
0
        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
0
        else if (oFieldDefn.GetType() == OFTInteger64)
4093
0
        {
4094
0
            if (!bQuiet)
4095
0
            {
4096
0
                CPLError(
4097
0
                    CE_Warning, CPLE_AppDefined,
4098
0
                    "The output driver does not seem to natively support %s "
4099
0
                    "type for field %s. Converting it to Real instead. "
4100
0
                    "-mapFieldType can be used to control field type "
4101
0
                    "conversion.",
4102
0
                    OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4103
0
                    oFieldDefn.GetNameRef());
4104
0
            }
4105
0
            oFieldDefn.SetType(OFTReal);
4106
0
        }
4107
0
        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
0
        else if (!bQuiet)
4114
0
        {
4115
0
            CPLError(
4116
0
                CE_Warning, CPLE_AppDefined,
4117
0
                "The output driver does not natively support %s type for "
4118
0
                "field %s. Misconversion can happen. "
4119
0
                "-mapFieldType can be used to control field type conversion.",
4120
0
                OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4121
0
                oFieldDefn.GetNameRef());
4122
0
        }
4123
0
    }
4124
0
    else if (!pszCreationFieldDataTypes)
4125
0
    {
4126
        // All drivers supporting OFTInteger64 should advertise it theoretically
4127
0
        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
0
    }
4143
0
}
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
0
{
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
0
    bool bUseWriteArrowBatch = false;
4261
0
    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
0
         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
0
    return bUseWriteArrowBatch;
4451
0
}
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
0
{
4511
0
    int eGType = m_eGType;
4512
0
    bool bPreserveFID = m_bPreserveFID;
4513
0
    bool bAppend = m_bAppend;
4514
4515
0
    if (pszNewLayerName == nullptr)
4516
0
        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
0
    const auto errorCount{CPLGetErrorCounter()};
4525
0
    const OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
4526
0
    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
0
    std::vector<int> anRequestedGeomFields;
4537
0
    const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
4538
0
    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
0
    const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
4582
0
    if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
4583
0
    {
4584
0
        if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())
4585
0
            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
0
    }
4593
4594
0
    int iSrcZField = -1;
4595
0
    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
0
    bool bErrorOccurred;
4611
0
    bool bOverwriteActuallyDone;
4612
0
    bool bAddOverwriteLCO;
4613
0
    OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(
4614
0
        m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,
4615
0
        &bOverwriteActuallyDone, &bAddOverwriteLCO);
4616
0
    const bool bJustCreatedLayer = (poDstLayer == nullptr);
4617
0
    if (bErrorOccurred)
4618
0
        return nullptr;
4619
4620
    /* -------------------------------------------------------------------- */
4621
    /*      If the layer does not exist, then create it.                    */
4622
    /* -------------------------------------------------------------------- */
4623
0
    if (poDstLayer == nullptr)
4624
0
    {
4625
0
        if (!m_poDstDS->TestCapability(ODsCCreateLayer))
4626
0
        {
4627
0
            CPLError(
4628
0
                CE_Failure, CPLE_AppDefined,
4629
0
                "Layer '%s' does not already exist in the output dataset, and "
4630
0
                "cannot be created by the output driver.",
4631
0
                pszNewLayerName);
4632
0
            return nullptr;
4633
0
        }
4634
4635
0
        bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);
4636
0
        if (!bForceGType)
4637
0
        {
4638
0
            if (anRequestedGeomFields.empty())
4639
0
            {
4640
0
                eGType = poSrcFDefn->GetGeomType();
4641
0
            }
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
0
            const bool bHasZ = wkbHasZ(static_cast<OGRwkbGeometryType>(eGType));
4653
0
            eGType = ConvertType(m_eGeomTypeConversion,
4654
0
                                 static_cast<OGRwkbGeometryType>(eGType));
4655
4656
0
            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
0
            if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))
4679
0
                eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));
4680
0
        }
4681
4682
0
        eGType = ForceCoordDimension(eGType, m_nCoordDim);
4683
4684
0
        CPLErrorReset();
4685
4686
0
        CPLStringList aosLCOTemp(CSLDuplicate(m_papszLCO));
4687
0
        const char *pszDestCreationOptions =
4688
0
            m_poDstDS->GetDriver()->GetMetadataItem(
4689
0
                GDAL_DS_LAYER_CREATIONOPTIONLIST);
4690
4691
0
        int eGCreateLayerType = eGType;
4692
0
        if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4693
0
            m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4694
0
        {
4695
0
            eGCreateLayerType = wkbNone;
4696
0
        }
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
0
        else if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4707
0
                 nSrcGeomFieldCount == 1 &&
4708
0
                 m_poDstDS->TestCapability(
4709
0
                     ODsCCreateGeomFieldAfterCreateLayer) &&
4710
0
                 ((!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
0
                  (poSrcLayer->GetGeometryColumn() != nullptr &&
4718
0
                   CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&
4719
0
                   !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&
4720
0
                   (pszDestCreationOptions == nullptr ||
4721
0
                    strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==
4722
0
                        nullptr ||
4723
0
                    strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&
4724
0
                   poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <
4725
0
                       0)))
4726
0
        {
4727
0
            anRequestedGeomFields.push_back(0);
4728
0
            eGCreateLayerType = wkbNone;
4729
0
        }
4730
0
        else if (anRequestedGeomFields.size() == 1 &&
4731
0
                 m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4732
0
        {
4733
0
            eGCreateLayerType = wkbNone;
4734
0
        }
4735
4736
0
        OGRGeomCoordinatePrecision oCoordPrec;
4737
0
        std::string osGeomFieldName;
4738
0
        bool bGeomFieldNullable = true;
4739
4740
0
        {
4741
0
            int iSrcGeomField = -1;
4742
0
            if (anRequestedGeomFields.empty() &&
4743
0
                (nSrcGeomFieldCount == 1 ||
4744
0
                 (!m_poDstDS->TestCapability(
4745
0
                      ODsCCreateGeomFieldAfterCreateLayer) &&
4746
0
                  nSrcGeomFieldCount > 1)))
4747
0
            {
4748
0
                iSrcGeomField = 0;
4749
0
            }
4750
0
            else if (anRequestedGeomFields.size() == 1)
4751
0
            {
4752
0
                iSrcGeomField = anRequestedGeomFields[0];
4753
0
            }
4754
4755
0
            if (iSrcGeomField >= 0)
4756
0
            {
4757
0
                const auto poSrcGeomFieldDefn =
4758
0
                    poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);
4759
0
                if (!psOptions->bUnsetCoordPrecision)
4760
0
                {
4761
0
                    oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()
4762
0
                                     .ConvertToOtherSRS(
4763
0
                                         poSrcGeomFieldDefn->GetSpatialRef(),
4764
0
                                         poOutputSRS);
4765
0
                }
4766
4767
0
                bGeomFieldNullable =
4768
0
                    CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());
4769
4770
0
                const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();
4771
0
                if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&
4772
0
                    poSrcFDefn->GetFieldIndex(pszGFldName) < 0)
4773
0
                {
4774
0
                    osGeomFieldName = pszGFldName;
4775
4776
                    // Use source geometry field name as much as possible
4777
0
                    if (eGType != wkbNone && pszDestCreationOptions &&
4778
0
                        strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=
4779
0
                            nullptr &&
4780
0
                        CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==
4781
0
                            nullptr)
4782
0
                    {
4783
0
                        aosLCOTemp.SetNameValue("GEOMETRY_NAME", pszGFldName);
4784
0
                    }
4785
0
                }
4786
0
            }
4787
0
        }
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
0
        if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4794
0
            nSrcGeomFieldCount >= 1 &&
4795
0
            !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
0
        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
0
        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
0
        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
0
        CSLConstList papszMeasures = poSrcLayer->GetMetadata("MEASURES");
4903
0
        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
0
        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
0
        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
0
        if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&
4941
0
            !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
0
        else if (!bPreserveFID && !m_bUnsetFid && !bAppend && poSrcDriver &&
4967
0
                 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
0
        else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&
4980
0
                 CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4981
0
        {
4982
0
            int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid");
4983
0
            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
0
        }
4993
4994
        // For a MapInfo -> MapInfo translation, preserve the layer bounds.
4995
0
        if (m_poSrcDS->GetDriver() == m_poDstDS->GetDriver() &&
4996
0
            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
0
        if (bAddOverwriteLCO)
5011
0
        {
5012
0
            aosLCOTemp.SetNameValue("OVERWRITE", "ON");
5013
0
            CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON");
5014
0
        }
5015
5016
0
        if (m_bNativeData &&
5017
0
            poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") !=
5018
0
                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
0
        if (pszDestCreationOptions &&
5038
0
            strstr(pszDestCreationOptions,
5039
0
                   "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&
5040
0
            CSLFetchNameValue(m_papszLCO,
5041
0
                              "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)
5042
0
        {
5043
0
            const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
5044
0
            const int nIdxShapeArea =
5045
0
                poSrcLayerDefn->GetFieldIndex("Shape_Area");
5046
0
            const int nIdxShapeLength =
5047
0
                poSrcLayerDefn->GetFieldIndex("Shape_Length");
5048
0
            if ((nIdxShapeArea >= 0 &&
5049
0
                 poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=
5050
0
                     nullptr &&
5051
0
                 EQUAL(
5052
0
                     poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),
5053
0
                     "FILEGEODATABASE_SHAPE_AREA") &&
5054
0
                 (m_papszSelFields == nullptr ||
5055
0
                  CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||
5056
0
                (nIdxShapeLength >= 0 &&
5057
0
                 poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=
5058
0
                     nullptr &&
5059
0
                 EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)
5060
0
                           ->GetDefault(),
5061
0
                       "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
0
        }
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
0
        if (poSrcDriver && pszDestCreationOptions &&
5078
0
            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
0
        OGRGeomFieldDefn oGeomFieldDefn(
5089
0
            osGeomFieldName.c_str(),
5090
0
            static_cast<OGRwkbGeometryType>(eGCreateLayerType));
5091
0
        oGeomFieldDefn.SetSpatialRef(poOutputSRS);
5092
0
        oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);
5093
0
        oGeomFieldDefn.SetNullable(bGeomFieldNullable);
5094
0
        poDstLayer = m_poDstDS->CreateLayer(
5095
0
            pszNewLayerName,
5096
0
            eGCreateLayerType == wkbNone ? nullptr : &oGeomFieldDefn,
5097
0
            aosLCOTemp.List());
5098
5099
0
        if (poDstLayer == nullptr)
5100
0
        {
5101
0
            return nullptr;
5102
0
        }
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
0
        if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&
5107
            // MapInfo is somewhat lossy regarding SRS, so do not warn
5108
0
            !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))
5109
0
        {
5110
0
            auto poCreatedSRS = poDstLayer->GetSpatialRef();
5111
0
            if (poCreatedSRS != nullptr)
5112
0
            {
5113
0
                const char *const apszOptions[] = {
5114
0
                    "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
5115
0
                    "CRITERION=EQUIVALENT", nullptr};
5116
0
                if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))
5117
0
                {
5118
0
                    const char *pszTargetSRSName = m_poOutputSRS->GetName();
5119
0
                    const char *pszCreatedSRSName = poCreatedSRS->GetName();
5120
0
                    CPLError(CE_Warning, CPLE_AppDefined,
5121
0
                             "Target SRS %s not taken into account as target "
5122
0
                             "driver likely implements on-the-fly reprojection "
5123
0
                             "to %s",
5124
0
                             pszTargetSRSName ? pszTargetSRSName : "",
5125
0
                             pszCreatedSRSName ? pszCreatedSRSName : "");
5126
0
                }
5127
0
            }
5128
0
        }
5129
5130
0
        if (m_bCopyMD)
5131
0
        {
5132
0
            const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());
5133
0
            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
0
        }
5160
5161
0
        if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
5162
0
            m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
5163
0
        {
5164
0
            for (int i = 0; i < nSrcGeomFieldCount; i++)
5165
0
            {
5166
0
                anRequestedGeomFields.push_back(i);
5167
0
            }
5168
0
        }
5169
5170
0
        if (anRequestedGeomFields.size() > 1 ||
5171
0
            (anRequestedGeomFields.size() == 1 &&
5172
0
             m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))
5173
0
        {
5174
0
            for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());
5175
0
                 i++)
5176
0
            {
5177
0
                const int iSrcGeomField = anRequestedGeomFields[i];
5178
0
                OGRGeomFieldDefn oGFldDefn(
5179
0
                    poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));
5180
0
                if (m_poOutputSRS != nullptr)
5181
0
                {
5182
0
                    auto poOutputSRSClone =
5183
0
                        OGRSpatialReferenceRefCountedPtr::makeClone(
5184
0
                            m_poOutputSRS);
5185
0
                    oGFldDefn.SetSpatialRef(poOutputSRSClone.get());
5186
0
                }
5187
0
                if (bForceGType)
5188
0
                {
5189
0
                    oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5190
0
                }
5191
0
                else
5192
0
                {
5193
0
                    eGType = oGFldDefn.GetType();
5194
0
                    eGType =
5195
0
                        ConvertType(m_eGeomTypeConversion,
5196
0
                                    static_cast<OGRwkbGeometryType>(eGType));
5197
0
                    eGType = ForceCoordDimension(eGType, m_nCoordDim);
5198
0
                    oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5199
0
                }
5200
0
                if (m_bForceNullable)
5201
0
                    oGFldDefn.SetNullable(TRUE);
5202
0
                poDstLayer->CreateGeomField(&oGFldDefn);
5203
0
            }
5204
0
        }
5205
5206
0
        bAppend = false;
5207
0
    }
5208
5209
    /* -------------------------------------------------------------------- */
5210
    /*      Otherwise we will append to it, if append was requested.        */
5211
    /* -------------------------------------------------------------------- */
5212
0
    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
0
    else
5231
0
    {
5232
0
        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
0
    }
5240
5241
    /* -------------------------------------------------------------------- */
5242
    /*      Process Layer style table                                       */
5243
    /* -------------------------------------------------------------------- */
5244
5245
0
    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
0
    const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
5253
0
    int iSrcFIDField = -1;
5254
5255
    // Initialize the index-to-index map to -1's
5256
0
    std::vector<int> anMap(nSrcFieldCount, -1);
5257
5258
0
    std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;
5259
5260
    /* Determine if NUMERIC field width narrowing is allowed */
5261
0
    auto poSrcDriver = m_poSrcDS->GetDriver();
5262
0
    const char *pszSrcWidthIncludesDecimalSeparator{
5263
0
        poSrcDriver ? poSrcDriver->GetMetadataItem(
5264
0
                          "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")
5265
0
                    : nullptr};
5266
0
    const bool bSrcWidthIncludesDecimalSeparator{
5267
0
        pszSrcWidthIncludesDecimalSeparator &&
5268
0
        EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};
5269
0
    const char *pszDstWidthIncludesDecimalSeparator{
5270
0
        m_poDstDS->GetDriver()->GetMetadataItem(
5271
0
            "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
5272
0
    const bool bDstWidthIncludesDecimalSeparator{
5273
0
        pszDstWidthIncludesDecimalSeparator &&
5274
0
        EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};
5275
0
    const char *pszSrcWidthIncludesMinusSign{
5276
0
        poSrcDriver ? poSrcDriver->GetMetadataItem(
5277
0
                          "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")
5278
0
                    : nullptr};
5279
0
    const bool bSrcWidthIncludesMinusSign{
5280
0
        pszSrcWidthIncludesMinusSign &&
5281
0
        EQUAL(pszSrcWidthIncludesMinusSign, "YES")};
5282
0
    const char *pszDstWidthIncludesMinusSign{
5283
0
        m_poDstDS->GetDriver()->GetMetadataItem(
5284
0
            "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
5285
0
    const bool bDstWidthIncludesMinusSign{
5286
0
        pszDstWidthIncludesMinusSign &&
5287
0
        EQUAL(pszDstWidthIncludesMinusSign, "YES")};
5288
5289
    // Calculate width delta
5290
0
    int iChangeWidthBy{0};
5291
5292
0
    if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)
5293
0
    {
5294
0
        iChangeWidthBy--;
5295
0
    }
5296
0
    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
0
    if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)
5304
0
    {
5305
0
        iChangeWidthBy++;
5306
0
    }
5307
5308
0
    OGRArrowArrayStream streamSrc;
5309
5310
0
    const bool bUseWriteArrowBatch =
5311
0
        !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "OCI") &&
5312
0
        CanUseWriteArrowBatch(poSrcLayer, poDstLayer, bJustCreatedLayer,
5313
0
                              psOptions, bPreserveFID, streamSrc);
5314
5315
    /* Caution : at the time of writing, the MapInfo driver */
5316
    /* returns NULL until a field has been added */
5317
0
    OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
5318
5319
0
    if (bUseWriteArrowBatch)
5320
0
    {
5321
        // Fields created above
5322
0
    }
5323
0
    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
0
    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
0
    else if (!bAppend || m_bAddMissingFields)
5421
0
    {
5422
0
        int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5423
5424
0
        const bool caseInsensitive =
5425
0
            !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");
5426
0
        const auto formatName = [caseInsensitive](const char *name)
5427
0
        {
5428
0
            if (caseInsensitive)
5429
0
            {
5430
0
                return CPLString(name).toupper();
5431
0
            }
5432
0
            else
5433
0
            {
5434
0
                return CPLString(name);
5435
0
            }
5436
0
        };
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
0
        std::map<CPLString, int> oMapPreExistingFields;
5443
0
        std::unordered_set<std::string> oSetDstFieldNames;
5444
0
        for (int iField = 0; iField < nDstFieldCount; iField++)
5445
0
        {
5446
0
            const char *pszFieldName =
5447
0
                poDstFDefn->GetFieldDefn(iField)->GetNameRef();
5448
0
            CPLString osUpperFieldName(formatName(pszFieldName));
5449
0
            oSetDstFieldNames.insert(osUpperFieldName);
5450
0
            if (oMapPreExistingFields.find(osUpperFieldName) ==
5451
0
                oMapPreExistingFields.end())
5452
0
                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
0
        }
5459
5460
0
        const char *pszFIDColumn = poDstLayer->GetFIDColumn();
5461
5462
0
        std::vector<int> anSrcFieldIndices;
5463
0
        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
0
        else
5477
0
        {
5478
0
            for (int iField = 0; iField < nSrcFieldCount; iField++)
5479
0
            {
5480
0
                anSrcFieldIndices.push_back(iField);
5481
0
            }
5482
0
        }
5483
5484
0
        std::unordered_set<std::string> oSetSrcFieldNames;
5485
0
        for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)
5486
0
        {
5487
0
            oSetSrcFieldNames.insert(
5488
0
                formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));
5489
0
        }
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
0
        std::map<std::string, int> oMapFieldNameToLastSuffix;
5500
5501
0
        for (size_t i = 0; i < anSrcFieldIndices.size(); i++)
5502
0
        {
5503
0
            const int iField = anSrcFieldIndices[i];
5504
0
            const OGRFieldDefn *poSrcFieldDefn =
5505
0
                poSrcFDefn->GetFieldDefn(iField);
5506
0
            OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5507
5508
            // Avoid creating a field with the same name as the FID column
5509
0
            if (pszFIDColumn != nullptr &&
5510
0
                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
0
            DoFieldTypeConversion(
5519
0
                m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5520
0
                m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5521
0
                m_bForceNullable, m_bUnsetDefault);
5522
5523
0
            if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5524
0
                oFieldDefn.GetWidth() != 0)
5525
0
            {
5526
0
                oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5527
0
            }
5528
5529
            /* The field may have been already created at layer creation */
5530
0
            {
5531
0
                const auto oIter = oMapPreExistingFields.find(
5532
0
                    formatName(oFieldDefn.GetNameRef()));
5533
0
                if (oIter != oMapPreExistingFields.end())
5534
0
                {
5535
0
                    anMap[iField] = oIter->second;
5536
0
                    continue;
5537
0
                }
5538
0
            }
5539
5540
0
            bool bHasRenamed = false;
5541
            /* In case the field name already exists in the target layer, */
5542
            /* build a unique field name */
5543
0
            if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=
5544
0
                oSetDstFieldNames.end())
5545
0
            {
5546
0
                const CPLString osTmpNameRaddixUC(
5547
0
                    formatName(oFieldDefn.GetNameRef()));
5548
0
                int nTry = 1;
5549
0
                const auto oIter =
5550
0
                    oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);
5551
0
                if (oIter != oMapFieldNameToLastSuffix.end())
5552
0
                    nTry = oIter->second;
5553
0
                CPLString osTmpNameUC = osTmpNameRaddixUC;
5554
0
                osTmpNameUC.reserve(osTmpNameUC.size() + 10);
5555
0
                while (true)
5556
0
                {
5557
0
                    ++nTry;
5558
0
                    char szTry[32];
5559
0
                    snprintf(szTry, sizeof(szTry), "%d", nTry);
5560
0
                    osTmpNameUC.replace(osTmpNameRaddixUC.size(),
5561
0
                                        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
0
                    if (oSetDstFieldNames.find(osTmpNameUC) ==
5567
0
                            oSetDstFieldNames.end() &&
5568
0
                        oSetSrcFieldNames.find(osTmpNameUC) ==
5569
0
                            oSetSrcFieldNames.end())
5570
0
                    {
5571
0
                        bHasRenamed = true;
5572
0
                        oFieldDefn.SetName(
5573
0
                            (CPLString(oFieldDefn.GetNameRef()) + szTry)
5574
0
                                .c_str());
5575
0
                        oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;
5576
0
                        break;
5577
0
                    }
5578
0
                }
5579
0
            }
5580
5581
            // Create field domain in output dataset if not already existing.
5582
0
            const std::string osDomainName(oFieldDefn.GetDomainName());
5583
0
            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
0
            if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5618
0
            {
5619
                /* now that we've created a field, GetLayerDefn() won't return
5620
                 * NULL */
5621
0
                if (poDstFDefn == nullptr)
5622
0
                    poDstFDefn = poDstLayer->GetLayerDefn();
5623
5624
                /* Sanity check : if it fails, the driver is buggy */
5625
0
                if (poDstFDefn != nullptr &&
5626
0
                    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
0
                else
5634
0
                {
5635
0
                    if (poDstFDefn != nullptr)
5636
0
                    {
5637
0
                        const char *pszNewFieldName =
5638
0
                            poDstFDefn->GetFieldDefn(nDstFieldCount)
5639
0
                                ->GetNameRef();
5640
0
                        if (bHasRenamed)
5641
0
                        {
5642
0
                            CPLError(CE_Warning, CPLE_AppDefined,
5643
0
                                     "Field '%s' already exists. Renaming it "
5644
0
                                     "as '%s'",
5645
0
                                     poSrcFieldDefn->GetNameRef(),
5646
0
                                     pszNewFieldName);
5647
0
                        }
5648
0
                        oSetDstFieldNames.insert(formatName(pszNewFieldName));
5649
0
                    }
5650
5651
0
                    anMap[iField] = nDstFieldCount;
5652
0
                    nDstFieldCount++;
5653
0
                }
5654
0
            }
5655
0
            else if (!psOptions->bSkipFailures)
5656
0
                return nullptr;
5657
5658
0
            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
0
        }
5680
0
    }
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
0
    if (bOverwriteActuallyDone && !bAddOverwriteLCO &&
5730
0
        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
0
    auto psInfo = std::make_unique<TargetLayerInfo>();
5749
0
    psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;
5750
0
    psInfo->m_nFeaturesRead = 0;
5751
0
    psInfo->m_bPerFeatureCT = false;
5752
0
    psInfo->m_poSrcLayer = poSrcLayer;
5753
0
    psInfo->m_poDstLayer = poDstLayer;
5754
0
    psInfo->m_aoReprojectionInfo.resize(
5755
0
        poDstLayer->GetLayerDefn()->GetGeomFieldCount());
5756
0
    psInfo->m_anMap = std::move(anMap);
5757
0
    psInfo->m_iSrcZField = iSrcZField;
5758
0
    psInfo->m_iSrcFIDField = iSrcFIDField;
5759
0
    if (anRequestedGeomFields.size() == 1)
5760
0
        psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];
5761
0
    else
5762
0
        psInfo->m_iRequestedSrcGeomField = -1;
5763
0
    psInfo->m_bPreserveFID = bPreserveFID;
5764
0
    psInfo->m_pszCTPipeline = m_pszCTPipeline;
5765
0
    psInfo->m_aosCTOptions = m_aosCTOptions;
5766
0
    psInfo->m_oMapResolved = std::move(oMapResolved);
5767
0
    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
0
    psInfo->m_bCanAvoidSetFrom = false;
5785
0
    if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)
5786
0
    {
5787
0
        psInfo->m_bCanAvoidSetFrom = true;
5788
0
        const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5789
0
        if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||
5790
0
            nSrcGeomFieldCount != nDstGeomFieldCount)
5791
0
        {
5792
0
            psInfo->m_bCanAvoidSetFrom = false;
5793
0
        }
5794
0
        else
5795
0
        {
5796
0
            for (int i = 0; i < nSrcFieldCount; ++i)
5797
0
            {
5798
0
                auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);
5799
0
                auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);
5800
0
                if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||
5801
0
                    psInfo->m_anMap[i] != i)
5802
0
                {
5803
0
                    psInfo->m_bCanAvoidSetFrom = false;
5804
0
                    break;
5805
0
                }
5806
0
            }
5807
0
            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
0
        }
5822
0
    }
5823
5824
0
    psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()
5825
0
                                  ? nullptr
5826
0
                                  : psOptions->osSpatSRSDef.c_str();
5827
0
    psInfo->m_hSpatialFilter =
5828
0
        OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());
5829
0
    psInfo->m_pszGeomField =
5830
0
        psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;
5831
5832
0
    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
0
    psInfo->m_bSupportCurves = poDstLayer->TestCapability(OLCCurveGeometries);
5844
0
    psInfo->m_bSupportZ = poDstLayer->TestCapability(OLCZGeometries);
5845
0
    psInfo->m_bSupportM = poDstLayer->TestCapability(OLCMeasuredGeometries);
5846
5847
0
    psInfo->m_sArrowArrayStream = std::move(streamSrc);
5848
5849
0
    return psInfo;
5850
0
}
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
0
{
5863
0
    OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5864
0
    const int nDstGeomFieldCount =
5865
0
        poDstLayer->GetLayerDefn()->GetGeomFieldCount();
5866
0
    for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
5867
0
    {
5868
        /* --------------------------------------------------------------------
5869
         */
5870
        /*      Setup coordinate transformation if we need it. */
5871
        /* --------------------------------------------------------------------
5872
         */
5873
0
        const OGRSpatialReference *poSourceSRS = nullptr;
5874
0
        OGRCoordinateTransformation *poCT = nullptr;
5875
0
        char **papszTransformOptions = nullptr;
5876
5877
0
        int iSrcGeomField;
5878
0
        auto poDstGeomFieldDefn =
5879
0
            poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
5880
0
        if (psInfo->m_iRequestedSrcGeomField >= 0)
5881
0
        {
5882
0
            iSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5883
0
        }
5884
0
        else
5885
0
        {
5886
0
            iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
5887
0
                poDstGeomFieldDefn->GetNameRef());
5888
0
            if (iSrcGeomField < 0)
5889
0
            {
5890
0
                if (nDstGeomFieldCount == 1 &&
5891
0
                    poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
5892
0
                {
5893
0
                    iSrcGeomField = 0;
5894
0
                }
5895
0
                else
5896
0
                {
5897
0
                    continue;
5898
0
                }
5899
0
            }
5900
0
        }
5901
5902
0
        if (psInfo->m_nFeaturesRead == 0)
5903
0
        {
5904
0
            poSourceSRS = poUserSourceSRS;
5905
0
            if (poSourceSRS == nullptr)
5906
0
            {
5907
0
                if (iSrcGeomField > 0)
5908
0
                    poSourceSRS = poSrcLayer->GetLayerDefn()
5909
0
                                      ->GetGeomFieldDefn(iSrcGeomField)
5910
0
                                      ->GetSpatialRef();
5911
0
                else
5912
0
                    poSourceSRS = poSrcLayer->GetSpatialRef();
5913
0
            }
5914
0
        }
5915
0
        if (poSourceSRS == nullptr)
5916
0
        {
5917
0
            if (poFeature == nullptr)
5918
0
            {
5919
0
                if (bVerboseError)
5920
0
                {
5921
0
                    CPLError(CE_Failure, CPLE_AppDefined,
5922
0
                             "Non-null feature expected to set transformation");
5923
0
                }
5924
0
                return false;
5925
0
            }
5926
0
            OGRGeometry *poSrcGeometry =
5927
0
                poFeature->GetGeomFieldRef(iSrcGeomField);
5928
0
            if (poSrcGeometry)
5929
0
                poSourceSRS = poSrcGeometry->getSpatialReference();
5930
0
            psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);
5931
0
        }
5932
5933
0
        if (bTransform)
5934
0
        {
5935
0
            if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)
5936
0
            {
5937
0
                CPLError(CE_Failure, CPLE_AppDefined,
5938
0
                         "Can't transform coordinates, source layer has no\n"
5939
0
                         "coordinate system.  Use -s_srs to set one.");
5940
5941
0
                return false;
5942
0
            }
5943
5944
0
            if (psInfo->m_pszCTPipeline == nullptr)
5945
0
            {
5946
0
                CPLAssert(nullptr != poSourceSRS);
5947
0
                CPLAssert(nullptr != poOutputSRS);
5948
0
            }
5949
5950
0
            if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)
5951
0
            {
5952
0
                const auto &supportedSRSList =
5953
0
                    poSrcLayer->GetSupportedSRSList(iGeom);
5954
0
                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
0
            }
6002
6003
0
            if (!bTransform)
6004
0
            {
6005
                // do nothing
6006
0
            }
6007
0
            else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&
6008
0
                     psInfo->m_aoReprojectionInfo[iGeom]
6009
0
                             .m_poCT->GetSourceCS() == poSourceSRS)
6010
0
            {
6011
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6012
0
            }
6013
0
            else
6014
0
            {
6015
0
                OGRCoordinateTransformationOptions options;
6016
0
                if (psInfo->m_pszCTPipeline)
6017
0
                {
6018
0
                    options.SetCoordinateOperation(psInfo->m_pszCTPipeline,
6019
0
                                                   false);
6020
0
                }
6021
6022
0
                bool bWarnAboutDifferentCoordinateOperations =
6023
0
                    poGCPCoordTrans == nullptr &&
6024
0
                    !(poSourceSRS && poSourceSRS->IsGeocentric());
6025
6026
0
                for (const auto &[key, value] :
6027
0
                     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
0
                auto poNewCT = std::unique_ptr<OGRCoordinateTransformation>(
6051
0
                    OGRCreateCoordinateTransformation(poSourceSRS, poOutputSRS,
6052
0
                                                      options));
6053
0
                if (poNewCT == nullptr)
6054
0
                {
6055
0
                    char *pszWKT = nullptr;
6056
6057
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6058
0
                             "Failed to create coordinate transformation "
6059
0
                             "between the\n"
6060
0
                             "following coordinate systems.  This may be "
6061
0
                             "because they\n"
6062
0
                             "are not transformable.");
6063
6064
0
                    if (poSourceSRS)
6065
0
                    {
6066
0
                        poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
6067
0
                        CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
6068
0
                                 pszWKT);
6069
0
                        CPLFree(pszWKT);
6070
0
                    }
6071
6072
0
                    if (poOutputSRS)
6073
0
                    {
6074
0
                        poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
6075
0
                        CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
6076
0
                                 pszWKT);
6077
0
                        CPLFree(pszWKT);
6078
0
                    }
6079
6080
0
                    return false;
6081
0
                }
6082
0
                if (poGCPCoordTrans)
6083
0
                {
6084
0
                    poNewCT = std::make_unique<CompositeCT>(poGCPCoordTrans,
6085
0
                                                            std::move(poNewCT));
6086
0
                }
6087
0
                else
6088
0
                {
6089
0
                    psInfo->m_aoReprojectionInfo[iGeom]
6090
0
                        .m_bWarnAboutDifferentCoordinateOperations =
6091
0
                        bWarnAboutDifferentCoordinateOperations;
6092
0
                }
6093
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT = std::move(poNewCT);
6094
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6095
0
                psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =
6096
0
                    !(poGCPCoordTrans == nullptr && poSourceSRS &&
6097
0
                      poSourceSRS->IsGeographic() && poOutputSRS &&
6098
0
                      poOutputSRS->IsGeographic());
6099
0
            }
6100
0
        }
6101
0
        else
6102
0
        {
6103
0
            const char *const apszOptions[] = {
6104
0
                "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
6105
0
                "CRITERION=EQUIVALENT", nullptr};
6106
0
            auto poDstGeomFieldDefnSpatialRef =
6107
0
                poDstGeomFieldDefn->GetSpatialRef();
6108
0
            if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&
6109
0
                poSourceSRS->GetDataAxisToSRSAxisMapping() !=
6110
0
                    poDstGeomFieldDefnSpatialRef
6111
0
                        ->GetDataAxisToSRSAxisMapping() &&
6112
0
                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
0
            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
0
        }
6130
6131
0
        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
0
    }
6171
0
    return true;
6172
0
}
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
0
{
6509
0
    if (psInfo->m_bUseWriteArrowBatch)
6510
0
    {
6511
0
        return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,
6512
0
                              pfnProgress, pProgressArg, psOptions);
6513
0
    }
6514
6515
0
    const int eGType = m_eGType;
6516
0
    const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
6517
6518
0
    OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;
6519
0
    OGRLayer *poDstLayer = psInfo->m_poDstLayer;
6520
0
    const int *const panMap = psInfo->m_anMap.data();
6521
0
    const int iSrcZField = psInfo->m_iSrcZField;
6522
0
    const bool bPreserveFID = psInfo->m_bPreserveFID;
6523
0
    const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
6524
0
    const auto poDstFDefn = poDstLayer->GetLayerDefn();
6525
0
    const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
6526
0
    const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
6527
0
    const bool bExplodeCollections =
6528
0
        m_bExplodeCollections && nDstGeomFieldCount <= 1;
6529
0
    const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;
6530
6531
0
    if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
6532
0
    {
6533
0
        if (nSrcGeomFieldCount == 1)
6534
0
        {
6535
0
            poOutputSRS = poSrcLayer->GetSpatialRef();
6536
0
        }
6537
0
        else if (iRequestedSrcGeomField > 0)
6538
0
        {
6539
0
            poOutputSRS = poSrcLayer->GetLayerDefn()
6540
0
                              ->GetGeomFieldDefn(iRequestedSrcGeomField)
6541
0
                              ->GetSpatialRef();
6542
0
        }
6543
0
    }
6544
6545
    /* -------------------------------------------------------------------- */
6546
    /*      Transfer features.                                              */
6547
    /* -------------------------------------------------------------------- */
6548
0
    if (psOptions->nGroupTransactions)
6549
0
    {
6550
0
        if (psOptions->nLayerTransaction)
6551
0
        {
6552
0
            if (poDstLayer->StartTransaction() == OGRERR_FAILURE)
6553
0
            {
6554
0
                return false;
6555
0
            }
6556
0
        }
6557
0
    }
6558
6559
0
    std::unique_ptr<OGRFeature> poFeature;
6560
0
    auto poDstFeature = std::make_unique<OGRFeature>(poDstFDefn);
6561
0
    int nFeaturesInTransaction = 0;
6562
0
    GIntBig nCount = 0; /* written + failed */
6563
0
    GIntBig nFeaturesWritten = 0;
6564
0
    bool bRunSetPrecisionEvaluated = false;
6565
0
    bool bRunSetPrecision = false;
6566
6567
0
    bool bRet = true;
6568
0
    CPLErrorReset();
6569
6570
0
    bool bSetupCTOK = false;
6571
0
    if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&
6572
0
        !psInfo->m_bPerFeatureCT)
6573
0
    {
6574
0
        bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6575
0
                             m_osDateLineOffset, m_poUserSourceSRS, nullptr,
6576
0
                             poOutputSRS, m_poGCPCoordTrans, false);
6577
0
    }
6578
6579
0
    const bool bSingleIteration = poFeatureIn != nullptr;
6580
0
    while (true)
6581
0
    {
6582
0
        if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)
6583
0
        {
6584
0
            break;
6585
0
        }
6586
6587
0
        if (poFeatureIn != nullptr)
6588
0
            poFeature = std::move(poFeatureIn);
6589
0
        else if (psOptions->nFIDToFetch != OGRNullFID)
6590
0
            poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));
6591
0
        else
6592
0
            poFeature.reset(poSrcLayer->GetNextFeature());
6593
6594
0
        if (poFeature == nullptr)
6595
0
        {
6596
0
            if (CPLGetLastErrorType() == CE_Failure)
6597
0
            {
6598
0
                bRet = false;
6599
0
            }
6600
0
            break;
6601
0
        }
6602
6603
0
        if (!bSetupCTOK &&
6604
0
            (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))
6605
0
        {
6606
0
            if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6607
0
                         m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),
6608
0
                         poOutputSRS, m_poGCPCoordTrans, true))
6609
0
            {
6610
0
                return false;
6611
0
            }
6612
0
        }
6613
6614
0
        psInfo->m_nFeaturesRead++;
6615
6616
0
        int nIters = 1;
6617
0
        std::unique_ptr<OGRGeometryCollection> poCollToExplode;
6618
0
        int iGeomCollToExplode = -1;
6619
0
        OGRGeometry *poSrcGeometry = nullptr;
6620
0
        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
0
        const GIntBig nSrcFID = poFeature->GetFID();
6649
0
        GIntBig nDesiredFID = OGRNullFID;
6650
0
        if (bPreserveFID)
6651
0
            nDesiredFID = nSrcFID;
6652
0
        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
0
        for (int iPart = 0; iPart < nIters; iPart++)
6658
0
        {
6659
0
            if (psOptions->nLayerTransaction &&
6660
0
                ++nFeaturesInTransaction == psOptions->nGroupTransactions)
6661
0
            {
6662
0
                if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||
6663
0
                    poDstLayer->StartTransaction() == OGRERR_FAILURE)
6664
0
                {
6665
0
                    return false;
6666
0
                }
6667
0
                nFeaturesInTransaction = 0;
6668
0
            }
6669
0
            else if (!psOptions->nLayerTransaction &&
6670
0
                     psOptions->nGroupTransactions > 0 &&
6671
0
                     ++nTotalEventsDone >= psOptions->nGroupTransactions)
6672
0
            {
6673
0
                if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||
6674
0
                    m_poODS->StartTransaction(psOptions->bForceTransaction) ==
6675
0
                        OGRERR_FAILURE)
6676
0
                {
6677
0
                    return false;
6678
0
                }
6679
0
                nTotalEventsDone = 0;
6680
0
            }
6681
6682
0
            CPLErrorReset();
6683
0
            if (psInfo->m_bCanAvoidSetFrom)
6684
0
            {
6685
0
                poDstFeature = std::move(poFeature);
6686
                // From now on, poFeature is null !
6687
0
                poDstFeature->SetFDefnUnsafe(poDstFDefn);
6688
0
                poDstFeature->SetFID(nDesiredFID);
6689
0
            }
6690
0
            else
6691
0
            {
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
0
                std::unique_ptr<OGRGeometry> poStolenGeometry;
6697
0
                if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&
6698
0
                    (nDstGeomFieldCount == 1 ||
6699
0
                     (nDstGeomFieldCount == 0 && m_poClipSrcOri)))
6700
0
                {
6701
0
                    poStolenGeometry.reset(poFeature->StealGeometry());
6702
0
                }
6703
0
                else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)
6704
0
                {
6705
0
                    poStolenGeometry.reset(
6706
0
                        poFeature->StealGeometry(iRequestedSrcGeomField));
6707
0
                }
6708
6709
0
                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
0
                poDstFeature->Reset();
6733
6734
0
                if (poDstFeature->SetFrom(
6735
0
                        poFeature.get(), panMap, /* bForgiving = */ TRUE,
6736
0
                        /* bUseISO8601ForDateTimeAsString = */ true) !=
6737
0
                    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
0
                if (poStolenGeometry)
6760
0
                {
6761
0
                    poDstFeature->SetGeometryDirectly(
6762
0
                        poStolenGeometry.release());
6763
0
                }
6764
6765
0
                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
0
                if (nDesiredFID != OGRNullFID)
6788
0
                    poDstFeature->SetFID(nDesiredFID);
6789
0
            }
6790
6791
0
            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
0
            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
0
            if (!m_bNativeData)
6853
0
            {
6854
0
                poDstFeature->SetNativeData(nullptr);
6855
0
                poDstFeature->SetNativeMediaType(nullptr);
6856
0
            }
6857
6858
0
            for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
6859
0
            {
6860
0
                std::unique_ptr<OGRGeometry> poDstGeometry;
6861
6862
0
                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
0
                else
6906
0
                {
6907
0
                    poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));
6908
0
                }
6909
0
                if (poDstGeometry == nullptr)
6910
0
                    continue;
6911
6912
                // poFeature hasn't been moved if iSrcZField != -1
6913
                // cppcheck-suppress accessMoved
6914
0
                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
0
                if (m_nCoordDim == 2 || m_nCoordDim == 3)
6923
0
                {
6924
0
                    poDstGeometry->setCoordinateDimension(m_nCoordDim);
6925
0
                }
6926
0
                else if (m_nCoordDim == 4)
6927
0
                {
6928
0
                    poDstGeometry->set3D(TRUE);
6929
0
                    poDstGeometry->setMeasured(TRUE);
6930
0
                }
6931
0
                else if (m_nCoordDim == COORD_DIM_XYM)
6932
0
                {
6933
0
                    poDstGeometry->set3D(FALSE);
6934
0
                    poDstGeometry->setMeasured(TRUE);
6935
0
                }
6936
0
                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
0
                if (m_eGeomOp == GEOMOP_SEGMENTIZE)
6947
0
                {
6948
0
                    if (m_dfGeomOpParam > 0)
6949
0
                        poDstGeometry->segmentize(m_dfGeomOpParam);
6950
0
                }
6951
0
                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
0
                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
0
                OGRCoordinateTransformation *const poCT =
7018
0
                    psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
7019
0
                char **const papszTransformOptions =
7020
0
                    psInfo->m_aoReprojectionInfo[iGeom]
7021
0
                        .m_aosTransformOptions.List();
7022
0
                const bool bReprojCanInvalidateValidity =
7023
0
                    psInfo->m_aoReprojectionInfo[iGeom]
7024
0
                        .m_bCanInvalidateValidity;
7025
7026
0
                if (poCT != nullptr || papszTransformOptions != nullptr)
7027
0
                {
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
0
                    if (bReprojCanInvalidateValidity &&
7034
0
                        (!psInfo->m_bSupportCurves ||
7035
0
                         m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
7036
0
                         m_eGeomTypeConversion ==
7037
0
                             GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))
7038
0
                    {
7039
0
                        if (poDstGeometry->hasCurveGeometry(TRUE))
7040
0
                        {
7041
0
                            OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
7042
0
                                poDstGeometry->getGeometryType());
7043
0
                            poDstGeometry = OGRGeometryFactory::forceTo(
7044
0
                                std::move(poDstGeometry), eTargetType);
7045
0
                        }
7046
0
                    }
7047
0
                    else if (bReprojCanInvalidateValidity &&
7048
0
                             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
0
                    if (psInfo->m_aoReprojectionInfo[iGeom]
7060
0
                            .m_bWarnAboutDifferentCoordinateOperations)
7061
0
                    {
7062
0
                        struct Visitor : public OGRDefaultConstGeometryVisitor
7063
0
                        {
7064
0
                            TargetLayerInfo::ReprojectionInfo &m_info;
7065
7066
0
                            explicit Visitor(
7067
0
                                TargetLayerInfo::ReprojectionInfo &info)
7068
0
                                : m_info(info)
7069
0
                            {
7070
0
                            }
7071
7072
0
                            using OGRDefaultConstGeometryVisitor::visit;
7073
7074
0
                            void visit(const OGRPoint *point) override
7075
0
                            {
7076
0
                                m_info.UpdateExtremePoints(point->getX(),
7077
0
                                                           point->getY(),
7078
0
                                                           point->getZ());
7079
0
                            }
7080
0
                        };
7081
7082
0
                        Visitor oVisit(psInfo->m_aoReprojectionInfo[iGeom]);
7083
0
                        poDstGeometry->accept(&oVisit);
7084
0
                    }
7085
7086
0
                    for (int iIter = 0; iIter < 2; ++iIter)
7087
0
                    {
7088
0
                        auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(
7089
0
                            OGRGeometryFactory::transformWithOptions(
7090
0
                                poDstGeometry.get(), poCT,
7091
0
                                papszTransformOptions,
7092
0
                                m_transformWithOptionsCache));
7093
0
                        if (poReprojectedGeom == nullptr)
7094
0
                        {
7095
0
                            if (psOptions->nGroupTransactions)
7096
0
                            {
7097
0
                                if (psOptions->nLayerTransaction)
7098
0
                                {
7099
0
                                    if (poDstLayer->CommitTransaction() !=
7100
0
                                            OGRERR_NONE &&
7101
0
                                        !psOptions->bSkipFailures)
7102
0
                                    {
7103
0
                                        return false;
7104
0
                                    }
7105
0
                                }
7106
0
                            }
7107
7108
0
                            CPLError(CE_Failure, CPLE_AppDefined,
7109
0
                                     "Failed to reproject feature " CPL_FRMT_GIB
7110
0
                                     " (geometry probably out of source or "
7111
0
                                     "destination SRS).",
7112
0
                                     nSrcFID);
7113
0
                            if (!psOptions->bSkipFailures)
7114
0
                            {
7115
0
                                return false;
7116
0
                            }
7117
0
                        }
7118
7119
                        // Check if a curve geometry is no longer valid after
7120
                        // reprojection
7121
0
                        const auto eType = poDstGeometry->getGeometryType();
7122
0
                        const auto eFlatType = wkbFlatten(eType);
7123
7124
0
                        std::string osReason;
7125
0
                        if (iIter == 0 && bReprojCanInvalidateValidity &&
7126
0
                            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
0
                        else
7159
0
                        {
7160
0
                            poDstGeometry = std::move(poReprojectedGeom);
7161
0
                            break;
7162
0
                        }
7163
0
                    }
7164
0
                }
7165
0
                else if (poOutputSRS != nullptr)
7166
0
                {
7167
0
                    poDstGeometry->assignSpatialReference(poOutputSRS);
7168
0
                }
7169
7170
0
                if (poDstGeometry != nullptr)
7171
0
                {
7172
0
                    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
0
                    if (psOptions->dfXYRes !=
7231
0
                            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
0
                    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
0
                    if (m_bSkipInvalidGeom && !poDstGeometry->IsValid())
7277
0
                        goto end_loop;
7278
7279
0
                    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
0
                    else if (eGType != GEOMTYPE_UNCHANGED)
7289
0
                    {
7290
0
                        poDstGeometry = OGRGeometryFactory::forceTo(
7291
0
                            std::move(poDstGeometry),
7292
0
                            static_cast<OGRwkbGeometryType>(eGType));
7293
0
                    }
7294
0
                }
7295
7296
0
                if (poDstGeometry && !psOptions->bQuiet)
7297
0
                {
7298
0
                    if (!psInfo->m_bHasWarnedAboutCurves &&
7299
0
                        !psInfo->m_bSupportCurves &&
7300
0
                        OGR_GT_IsNonLinear(poDstGeometry->getGeometryType()))
7301
0
                    {
7302
0
                        CPLError(CE_Warning, CPLE_AppDefined,
7303
0
                                 "Attempt to write curve geometries to layer "
7304
0
                                 "%s that does not support them. They will be "
7305
0
                                 "linearized",
7306
0
                                 poDstLayer->GetDescription());
7307
0
                        psInfo->m_bHasWarnedAboutCurves = true;
7308
0
                    }
7309
0
                    if (!psInfo->m_bHasWarnedAboutZ && !psInfo->m_bSupportZ &&
7310
0
                        OGR_GT_HasZ(poDstGeometry->getGeometryType()))
7311
0
                    {
7312
0
                        CPLError(CE_Warning, CPLE_AppDefined,
7313
0
                                 "Attempt to write Z geometries to layer %s "
7314
0
                                 "that does not support them. Z component will "
7315
0
                                 "be discarded",
7316
0
                                 poDstLayer->GetDescription());
7317
0
                        psInfo->m_bHasWarnedAboutZ = true;
7318
0
                    }
7319
0
                    if (!psInfo->m_bHasWarnedAboutM && !psInfo->m_bSupportM &&
7320
0
                        OGR_GT_HasM(poDstGeometry->getGeometryType()))
7321
0
                    {
7322
0
                        CPLError(CE_Warning, CPLE_AppDefined,
7323
0
                                 "Attempt to write M geometries to layer %s "
7324
0
                                 "that does not support them. M component will "
7325
0
                                 "be discarded",
7326
0
                                 poDstLayer->GetDescription());
7327
0
                        psInfo->m_bHasWarnedAboutM = true;
7328
0
                    }
7329
0
                }
7330
7331
0
                poDstFeature->SetGeomField(iGeom, std::move(poDstGeometry));
7332
0
            }
7333
7334
0
            CPLErrorReset();
7335
0
            if ((psOptions->bUpsert
7336
0
                     ? poDstLayer->UpsertFeature(poDstFeature.get())
7337
0
                     : poDstLayer->CreateFeature(poDstFeature.get())) ==
7338
0
                OGRERR_NONE)
7339
0
            {
7340
0
                nFeaturesWritten++;
7341
0
                if (nDesiredFID != OGRNullFID &&
7342
0
                    poDstFeature->GetFID() != nDesiredFID)
7343
0
                {
7344
0
                    CPLError(CE_Warning, CPLE_AppDefined,
7345
0
                             "Feature id " CPL_FRMT_GIB " not preserved",
7346
0
                             nDesiredFID);
7347
0
                }
7348
0
            }
7349
0
            else if (!psOptions->bSkipFailures)
7350
0
            {
7351
0
                if (psOptions->nGroupTransactions)
7352
0
                {
7353
0
                    if (psOptions->nLayerTransaction)
7354
0
                        poDstLayer->RollbackTransaction();
7355
0
                }
7356
7357
0
                CPLError(CE_Failure, CPLE_AppDefined,
7358
0
                         "Unable to write feature " CPL_FRMT_GIB
7359
0
                         " from layer %s.",
7360
0
                         nSrcFID, poSrcLayer->GetName());
7361
7362
0
                return false;
7363
0
            }
7364
0
            else
7365
0
            {
7366
0
                CPLDebug("GDALVectorTranslate",
7367
0
                         "Unable to write feature " CPL_FRMT_GIB
7368
0
                         " into layer %s.",
7369
0
                         nSrcFID, poSrcLayer->GetName());
7370
0
                if (psOptions->nGroupTransactions)
7371
0
                {
7372
0
                    if (psOptions->nLayerTransaction)
7373
0
                    {
7374
0
                        poDstLayer->RollbackTransaction();
7375
0
                        CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());
7376
0
                    }
7377
0
                    else
7378
0
                    {
7379
0
                        m_poODS->RollbackTransaction();
7380
0
                        m_poODS->StartTransaction(psOptions->bForceTransaction);
7381
0
                    }
7382
0
                }
7383
0
            }
7384
7385
0
        end_loop:;  // nothing
7386
0
        }
7387
7388
        /* Report progress */
7389
0
        nCount++;
7390
0
        bool bGoOn = true;
7391
0
        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
0
        if (!bGoOn)
7399
0
        {
7400
0
            bRet = false;
7401
0
            break;
7402
0
        }
7403
7404
0
        if (pnReadFeatureCount)
7405
0
            *pnReadFeatureCount = nCount;
7406
7407
0
        if (psOptions->nFIDToFetch != OGRNullFID)
7408
0
            break;
7409
0
        if (bSingleIteration)
7410
0
            break;
7411
0
    }
7412
7413
0
    if (psOptions->nGroupTransactions)
7414
0
    {
7415
0
        if (psOptions->nLayerTransaction)
7416
0
        {
7417
0
            if (poDstLayer->CommitTransaction() != OGRERR_NONE)
7418
0
                bRet = false;
7419
0
        }
7420
0
    }
7421
7422
0
    if (!bSingleIteration)
7423
0
    {
7424
0
        CPLDebug("GDALVectorTranslate",
7425
0
                 CPL_FRMT_GIB " features written in layer '%s'",
7426
0
                 nFeaturesWritten, poDstLayer->GetName());
7427
0
    }
7428
7429
0
    return bRet;
7430
0
}
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
0
{
7553
0
    for (auto &info : m_aoReprojectionInfo)
7554
0
    {
7555
0
        if (info.m_bWarnAboutDifferentCoordinateOperations &&
7556
0
            info.m_dfLeftX <= info.m_dfRightX)
7557
0
        {
7558
            // Start recording if different coordinate operations are
7559
            // going to be used
7560
0
            OGRProjCTDifferentOperationsStart(info.m_poCT.get());
7561
7562
0
            {
7563
0
                CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
7564
0
                {
7565
0
                    double dfX = info.m_dfLeftX;
7566
0
                    double dfY = info.m_dfLeftY;
7567
0
                    double dfZ = info.m_dfLeftZ;
7568
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7569
0
                }
7570
7571
0
                {
7572
0
                    double dfX = info.m_dfRightX;
7573
0
                    double dfY = info.m_dfRightY;
7574
0
                    double dfZ = info.m_dfRightZ;
7575
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7576
0
                }
7577
7578
0
                {
7579
0
                    double dfX = info.m_dfTopX;
7580
0
                    double dfY = info.m_dfTopY;
7581
0
                    double dfZ = info.m_dfTopZ;
7582
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7583
0
                }
7584
7585
0
                {
7586
0
                    double dfX = info.m_dfBottomX;
7587
0
                    double dfY = info.m_dfBottomY;
7588
0
                    double dfZ = info.m_dfBottomZ;
7589
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7590
0
                }
7591
0
            }
7592
7593
0
            if (OGRProjCTDifferentOperationsUsed(info.m_poCT.get()))
7594
0
            {
7595
0
                CPLError(
7596
0
                    CE_Warning, CPLE_AppDefined,
7597
0
                    "Several coordinate operations have been used to transform "
7598
0
                    "layer %s. Artifacts may appear. You may consider "
7599
0
                    "using the -ct_opt ALLOW_BALLPARK=NO and/or "
7600
0
                    "-ct_opt ONLY_BEST=YES warping options, or specify "
7601
0
                    "a particular coordinate operation with -ct. "
7602
0
                    "This warning can be silenced with "
7603
0
                    "-ct_opt WARN_ABOUT_DIFFERENT_COORD_OP=NO.",
7604
0
                    m_poSrcLayer->GetName());
7605
0
            }
7606
7607
            // Stop recording
7608
0
            OGRProjCTDifferentOperationsStop(info.m_poCT.get());
7609
0
        }
7610
0
    }
7611
0
}
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
0
{
7622
0
    auto argParser = std::make_unique<GDALArgumentParser>(
7623
0
        "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);
7624
7625
0
    argParser->add_description(
7626
0
        _("Converts simple features data between file formats."));
7627
7628
0
    argParser->add_epilog(
7629
0
        _("For more details, consult https://gdal.org/programs/ogr2ogr.html"));
7630
7631
0
    argParser->add_output_format_argument(psOptions->osFormat);
7632
7633
0
    argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);
7634
7635
0
    argParser->add_layer_creation_options_argument(psOptions->aosLCO);
7636
7637
0
    argParser->add_usage_newline();
7638
7639
0
    {
7640
0
        auto &group = argParser->add_mutually_exclusive_group();
7641
0
        group.add_argument("-append")
7642
0
            .flag()
7643
0
            .action([psOptions](const std::string &)
7644
0
                    { psOptions->eAccessMode = ACCESS_APPEND; })
7645
0
            .help(_("Append to existing layer instead of creating new."));
7646
7647
0
        group.add_argument("-upsert")
7648
0
            .flag()
7649
0
            .action(
7650
0
                [psOptions](const std::string &)
7651
0
                {
7652
0
                    psOptions->eAccessMode = ACCESS_APPEND;
7653
0
                    psOptions->bUpsert = true;
7654
0
                })
7655
0
            .help(_("Variant of -append where the UpsertFeature() operation is "
7656
0
                    "used to insert or update features."));
7657
7658
0
        group.add_argument("-overwrite")
7659
0
            .flag()
7660
0
            .action([psOptions](const std::string &)
7661
0
                    { psOptions->eAccessMode = ACCESS_OVERWRITE; })
7662
0
            .help(_("Delete the output layer and recreate it empty."));
7663
0
    }
7664
7665
0
    argParser->add_argument("-update")
7666
0
        .flag()
7667
0
        .action(
7668
0
            [psOptions](const std::string &)
7669
0
            {
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
0
        .help(_("Open existing output datasource in update mode rather than "
7676
0
                "trying to create a new one."));
7677
7678
0
    argParser->add_argument("-sql")
7679
0
        .metavar("<statement>|@<filename>")
7680
0
        .action(
7681
0
            [psOptions](const std::string &s)
7682
0
            {
7683
0
                GByte *pabyRet = nullptr;
7684
0
                if (!s.empty() && s.front() == '@' &&
7685
0
                    VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7686
0
                                  10 * 1024 * 1024))
7687
0
                {
7688
0
                    GDALRemoveBOM(pabyRet);
7689
0
                    char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);
7690
0
                    psOptions->osSQLStatement =
7691
0
                        CPLRemoveSQLComments(pszSQLStatement);
7692
0
                    VSIFree(pszSQLStatement);
7693
0
                }
7694
0
                else
7695
0
                {
7696
0
                    psOptions->osSQLStatement = s;
7697
0
                }
7698
0
            })
7699
0
        .help(_("SQL statement to execute."));
7700
7701
0
    argParser->add_argument("-dialect")
7702
0
        .metavar("<dialect>")
7703
0
        .store_into(psOptions->osDialect)
7704
0
        .help(_("SQL dialect."));
7705
7706
0
    argParser->add_argument("-spat")
7707
0
        .metavar("<xmin> <ymin> <xmax> <ymax>")
7708
0
        .nargs(4)
7709
0
        .scan<'g', double>()
7710
0
        .help(_("Spatial query extents, in the SRS of the source layer(s) (or "
7711
0
                "the one specified with -spat_srs."));
7712
7713
0
    argParser->add_argument("-where")
7714
0
        .metavar("<restricted_where>|@<filename>")
7715
0
        .action(
7716
0
            [psOptions](const std::string &s)
7717
0
            {
7718
0
                GByte *pabyRet = nullptr;
7719
0
                if (!s.empty() && s.front() == '@' &&
7720
0
                    VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7721
0
                                  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
0
                else
7729
0
                {
7730
0
                    psOptions->osWHERE = s;
7731
0
                }
7732
0
            })
7733
0
        .help(_("Attribute query (like SQL WHERE)."));
7734
7735
0
    argParser->add_argument("-select")
7736
0
        .metavar("<field_list>")
7737
0
        .action(
7738
0
            [psOptions](const std::string &s)
7739
0
            {
7740
0
                psOptions->bSelFieldsSet = true;
7741
0
                psOptions->aosSelFields =
7742
0
                    CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);
7743
0
            })
7744
0
        .help(_("Comma-delimited list of fields from input layer to copy to "
7745
0
                "the new layer."));
7746
7747
0
    argParser->add_argument("-nln")
7748
0
        .metavar("<name>")
7749
0
        .store_into(psOptions->osNewLayerName)
7750
0
        .help(_("Assign an alternate name to the new layer."));
7751
7752
0
    argParser->add_argument("-nlt")
7753
0
        .metavar("<type>")
7754
0
        .append()
7755
0
        .action(
7756
0
            [psOptions](const std::string &osGeomNameIn)
7757
0
            {
7758
0
                bool bIs3D = false;
7759
0
                std::string osGeomName(osGeomNameIn);
7760
0
                if (osGeomName.size() > 3 &&
7761
0
                    STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,
7762
0
                                   "25D"))
7763
0
                {
7764
0
                    bIs3D = true;
7765
0
                    osGeomName.resize(osGeomName.size() - 3);
7766
0
                }
7767
0
                else if (osGeomName.size() > 1 &&
7768
0
                         STARTS_WITH_CI(
7769
0
                             osGeomName.c_str() + osGeomName.size() - 1, "Z"))
7770
0
                {
7771
0
                    bIs3D = true;
7772
0
                    osGeomName.pop_back();
7773
0
                }
7774
0
                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
0
                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
0
                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
0
                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
0
                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
0
                else
7829
0
                {
7830
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7831
0
                    {
7832
0
                        throw std::invalid_argument(
7833
0
                            "Unsupported combination of -nlt arguments.");
7834
0
                    }
7835
0
                    psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());
7836
0
                    if (psOptions->eGType == wkbUnknown)
7837
0
                    {
7838
0
                        throw std::invalid_argument(
7839
0
                            CPLSPrintf("-nlt %s: type not recognised.",
7840
0
                                       osGeomName.c_str()));
7841
0
                    }
7842
0
                }
7843
0
                if (psOptions->eGType != GEOMTYPE_UNCHANGED &&
7844
0
                    psOptions->eGType != wkbNone && bIs3D)
7845
0
                    psOptions->eGType = wkbSetZ(
7846
0
                        static_cast<OGRwkbGeometryType>(psOptions->eGType));
7847
0
            })
7848
0
        .help(_("Define the geometry type for the created layer."));
7849
7850
0
    argParser->add_argument("-s_srs")
7851
0
        .metavar("<srs_def>")
7852
0
        .store_into(psOptions->osSourceSRSDef)
7853
0
        .help(_("Set/override source SRS."));
7854
7855
0
    {
7856
0
        auto &group = argParser->add_mutually_exclusive_group();
7857
0
        group.add_argument("-a_srs")
7858
0
            .metavar("<srs_def>")
7859
0
            .action(
7860
0
                [psOptions](const std::string &osOutputSRSDef)
7861
0
                {
7862
0
                    psOptions->osOutputSRSDef = osOutputSRSDef;
7863
0
                    if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||
7864
0
                        EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))
7865
0
                    {
7866
0
                        psOptions->osOutputSRSDef.clear();
7867
0
                        psOptions->bNullifyOutputSRS = true;
7868
0
                    }
7869
0
                })
7870
0
            .help(_("Assign an output SRS, but without reprojecting."));
7871
7872
0
        group.add_argument("-t_srs")
7873
0
            .metavar("<srs_def>")
7874
0
            .action(
7875
0
                [psOptions](const std::string &osOutputSRSDef)
7876
0
                {
7877
0
                    psOptions->osOutputSRSDef = osOutputSRSDef;
7878
0
                    psOptions->bTransform = true;
7879
0
                })
7880
0
            .help(_("Reproject/transform to this SRS on output, and assign it "
7881
0
                    "as output SRS."));
7882
0
    }
7883
7884
    ///////////////////////////////////////////////////////////////////////
7885
0
    argParser->add_group("Field related options");
7886
7887
0
    argParser->add_argument("-addfields")
7888
0
        .flag()
7889
0
        .action(
7890
0
            [psOptions](const std::string &)
7891
0
            {
7892
0
                psOptions->bAddMissingFields = true;
7893
0
                psOptions->eAccessMode = ACCESS_APPEND;
7894
0
            })
7895
0
        .help(_("Same as append, but add also any new fields."));
7896
7897
0
    argParser->add_argument("-relaxedFieldNameMatch")
7898
0
        .flag()
7899
0
        .action([psOptions](const std::string &)
7900
0
                { psOptions->bExactFieldNameMatch = false; })
7901
0
        .help(_("Do field name matching between source and existing target "
7902
0
                "layer in a more relaxed way."));
7903
7904
0
    argParser->add_argument("-fieldTypeToString")
7905
0
        .metavar("All|<type1>[,<type2>]...")
7906
0
        .action(
7907
0
            [psOptions](const std::string &s)
7908
0
            {
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
0
        .help(_("Converts any field of the specified type to a field of type "
7934
0
                "string in the destination layer."));
7935
7936
0
    argParser->add_argument("-mapFieldType")
7937
0
        .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...")
7938
0
        .action(
7939
0
            [psOptions](const std::string &s)
7940
0
            {
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
0
        .help(_("Converts any field of the specified type to another type."));
7963
7964
0
    argParser->add_argument("-fieldmap")
7965
0
        .metavar("<field_1>[,<field_2>]...")
7966
0
        .action(
7967
0
            [psOptions](const std::string &s)
7968
0
            {
7969
0
                psOptions->aosFieldMap =
7970
0
                    CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);
7971
0
            })
7972
0
        .help(_("Specifies the list of field indexes to be copied from the "
7973
0
                "source to the destination."));
7974
7975
0
    argParser->add_argument("-splitlistfields")
7976
0
        .store_into(psOptions->bSplitListFields)
7977
0
        .help(_("Split fields of type list type into as many fields of scalar "
7978
0
                "type as necessary."));
7979
7980
0
    argParser->add_argument("-maxsubfields")
7981
0
        .metavar("<n>")
7982
0
        .scan<'i', int>()
7983
0
        .action(
7984
0
            [psOptions](const std::string &s)
7985
0
            {
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
0
        .help(_("To be combined with -splitlistfields to limit the number of "
7993
0
                "subfields created for each split field."));
7994
7995
0
    argParser->add_argument("-emptyStrAsNull")
7996
0
        .store_into(psOptions->bEmptyStrAsNull)
7997
0
        .help(_("Treat empty string values as null."));
7998
7999
0
    argParser->add_argument("-forceNullable")
8000
0
        .store_into(psOptions->bForceNullable)
8001
0
        .help(_("Do not propagate not-nullable constraints to target layer if "
8002
0
                "they exist in source layer."));
8003
8004
0
    argParser->add_argument("-unsetFieldWidth")
8005
0
        .store_into(psOptions->bUnsetFieldWidth)
8006
0
        .help(_("Set field width and precision to 0."));
8007
8008
0
    argParser->add_argument("-unsetDefault")
8009
0
        .store_into(psOptions->bUnsetDefault)
8010
0
        .help(_("Do not propagate default field values to target layer if they "
8011
0
                "exist in source layer."));
8012
8013
0
    argParser->add_argument("-resolveDomains")
8014
0
        .store_into(psOptions->bResolveDomains)
8015
0
        .help(_("Cause any selected field that is linked to a coded field "
8016
0
                "domain will be accompanied by an additional field."));
8017
8018
0
    argParser->add_argument("-dateTimeTo")
8019
0
        .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>")
8020
0
        .action(
8021
0
            [psOptions](const std::string &s)
8022
0
            {
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
0
        .help(_("Converts date time values from the timezone specified in the "
8066
0
                "source value to the target timezone."));
8067
8068
0
    argParser->add_argument("-noNativeData")
8069
0
        .flag()
8070
0
        .action([psOptions](const std::string &)
8071
0
                { psOptions->bNativeData = false; })
8072
0
        .help(_("Disable copying of native data."));
8073
8074
    ///////////////////////////////////////////////////////////////////////
8075
0
    argParser->add_group("Advanced geometry and SRS related options");
8076
8077
0
    argParser->add_argument("-dim")
8078
0
        .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM")
8079
0
        .action(
8080
0
            [psOptions](const std::string &osDim)
8081
0
            {
8082
0
                if (EQUAL(osDim.c_str(), "layer_dim"))
8083
0
                    psOptions->nCoordDim = COORD_DIM_LAYER_DIM;
8084
0
                else if (EQUAL(osDim.c_str(), "XY") ||
8085
0
                         EQUAL(osDim.c_str(), "2"))
8086
0
                    psOptions->nCoordDim = 2;
8087
0
                else if (EQUAL(osDim.c_str(), "XYZ") ||
8088
0
                         EQUAL(osDim.c_str(), "3"))
8089
0
                    psOptions->nCoordDim = 3;
8090
0
                else if (EQUAL(osDim.c_str(), "XYM"))
8091
0
                    psOptions->nCoordDim = COORD_DIM_XYM;
8092
0
                else if (EQUAL(osDim.c_str(), "XYZM"))
8093
0
                    psOptions->nCoordDim = 4;
8094
0
                else
8095
0
                {
8096
0
                    throw std::invalid_argument(CPLSPrintf(
8097
0
                        "-dim %s: value not handled.", osDim.c_str()));
8098
0
                }
8099
0
            })
8100
0
        .help(_("Force the coordinate dimension."));
8101
8102
0
    argParser->add_argument("-s_coord_epoch")
8103
0
        .metavar("<epoch>")
8104
0
        .store_into(psOptions->dfSourceCoordinateEpoch)
8105
0
        .help(_("Assign a coordinate epoch, linked with the source SRS."));
8106
8107
0
    argParser->add_argument("-a_coord_epoch")
8108
0
        .metavar("<epoch>")
8109
0
        .store_into(psOptions->dfOutputCoordinateEpoch)
8110
0
        .help(_("Assign a coordinate epoch, linked with the output SRS when "
8111
0
                "-a_srs is used."));
8112
8113
0
    argParser->add_argument("-t_coord_epoch")
8114
0
        .metavar("<epoch>")
8115
0
        .store_into(psOptions->dfOutputCoordinateEpoch)
8116
0
        .help(_("Assign a coordinate epoch, linked with the output SRS when "
8117
0
                "-t_srs is used."));
8118
8119
0
    argParser->add_argument("-ct")
8120
0
        .metavar("<pipeline_def>")
8121
0
        .action(
8122
0
            [psOptions](const std::string &s)
8123
0
            {
8124
0
                psOptions->osCTPipeline = s;
8125
0
                psOptions->bTransform = true;
8126
0
            })
8127
0
        .help(_("Override the default transformation from the source to the "
8128
0
                "target CRS."));
8129
8130
0
    argParser->add_argument("-ct_opt")
8131
0
        .metavar("<NAME>=<VALUE>")
8132
0
        .append()
8133
0
        .action([psOptions](const std::string &s)
8134
0
                { psOptions->aosCTOptions.AddString(s.c_str()); })
8135
0
        .help(_("Coordinate transform option(s)."));
8136
8137
0
    argParser->add_argument("-spat_srs")
8138
0
        .metavar("<srs_def>")
8139
0
        .store_into(psOptions->osSpatSRSDef)
8140
0
        .help(_("Override spatial filter SRS."));
8141
8142
0
    argParser->add_argument("-geomfield")
8143
0
        .metavar("<name>")
8144
0
        .action(
8145
0
            [psOptions](const std::string &s)
8146
0
            {
8147
0
                psOptions->osGeomField = s;
8148
0
                psOptions->bGeomFieldSet = true;
8149
0
            })
8150
0
        .help(_("Name of the geometry field on which the spatial filter "
8151
0
                "operates on."));
8152
8153
0
    argParser->add_argument("-segmentize")
8154
0
        .metavar("<max_dist>")
8155
0
        .store_into(psOptions->dfGeomOpParam)
8156
0
        .action([psOptions](const std::string &)
8157
0
                { psOptions->eGeomOp = GEOMOP_SEGMENTIZE; })
8158
0
        .help(_("Maximum distance between 2 nodes."));
8159
8160
0
    argParser->add_argument("-simplify")
8161
0
        .metavar("<tolerance>")
8162
0
        .store_into(psOptions->dfGeomOpParam)
8163
0
        .action([psOptions](const std::string &)
8164
0
                { psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY; })
8165
0
        .help(_("Distance tolerance for simplification."));
8166
8167
0
    argParser->add_argument("-makevalid")
8168
0
        .flag()
8169
0
        .action(
8170
0
            [psOptions](const std::string &)
8171
0
            {
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
0
        .help(_("Fix geometries to be valid regarding the rules of the Simple "
8180
0
                "Features specification."));
8181
8182
0
    argParser->add_argument("-skipinvalid")
8183
0
        .flag()
8184
0
        .action(
8185
0
            [psOptions](const std::string &)
8186
0
            {
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
0
        .help(_("Whether to skip features with invalid geometries regarding the"
8195
0
                "rules of the Simple Features specification."));
8196
8197
0
    argParser->add_argument("-wrapdateline")
8198
0
        .store_into(psOptions->bWrapDateline)
8199
0
        .help(_("Split geometries crossing the dateline meridian."));
8200
8201
0
    argParser->add_argument("-datelineoffset")
8202
0
        .metavar("<val_in_degree>")
8203
0
        .default_value(psOptions->dfDateLineOffset)
8204
0
        .store_into(psOptions->dfDateLineOffset)
8205
0
        .help(_("Offset from dateline in degrees."));
8206
8207
0
    auto &clipsrcArg =
8208
0
        argParser->add_argument("-clipsrc")
8209
0
            .metavar(
8210
0
                "[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
8211
0
            .help(_("Clip geometries (in source SRS)."));
8212
0
    if (nCountClipSrc > 1)
8213
0
        clipsrcArg.nargs(nCountClipSrc);
8214
8215
0
    argParser->add_argument("-clipsrcsql")
8216
0
        .metavar("<sql_statement>")
8217
0
        .store_into(psOptions->osClipSrcSQL)
8218
0
        .help(_("Select desired geometries from the source clip datasource "
8219
0
                "using an SQL query."));
8220
8221
0
    argParser->add_argument("-clipsrclayer")
8222
0
        .metavar("<layername>")
8223
0
        .store_into(psOptions->osClipSrcLayer)
8224
0
        .help(_("Select the named layer from the source clip datasource."));
8225
8226
0
    argParser->add_argument("-clipsrcwhere")
8227
0
        .metavar("<expression>")
8228
0
        .store_into(psOptions->osClipSrcWhere)
8229
0
        .help(_("Restrict desired geometries from the source clip layer based "
8230
0
                "on an attribute query."));
8231
8232
0
    auto &clipdstArg =
8233
0
        argParser->add_argument("-clipdst")
8234
0
            .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>")
8235
0
            .help(_("Clip geometries (in target SRS)."));
8236
0
    if (nCountClipDst > 1)
8237
0
        clipdstArg.nargs(nCountClipDst);
8238
8239
0
    argParser->add_argument("-clipdstsql")
8240
0
        .metavar("<sql_statement>")
8241
0
        .store_into(psOptions->osClipDstSQL)
8242
0
        .help(_("Select desired geometries from the destination clip "
8243
0
                "datasource using an SQL query."));
8244
8245
0
    argParser->add_argument("-clipdstlayer")
8246
0
        .metavar("<layername>")
8247
0
        .store_into(psOptions->osClipDstLayer)
8248
0
        .help(
8249
0
            _("Select the named layer from the destination clip datasource."));
8250
8251
0
    argParser->add_argument("-clipdstwhere")
8252
0
        .metavar("<expression>")
8253
0
        .store_into(psOptions->osClipDstWhere)
8254
0
        .help(_("Restrict desired geometries from the destination clip layer "
8255
0
                "based on an attribute query."));
8256
8257
0
    argParser->add_argument("-explodecollections")
8258
0
        .store_into(psOptions->bExplodeCollections)
8259
0
        .help(_("Produce one feature for each geometry in any kind of geometry "
8260
0
                "collection in the source file."));
8261
8262
0
    argParser->add_argument("-zfield")
8263
0
        .metavar("<name>")
8264
0
        .store_into(psOptions->osZField)
8265
0
        .help(_("Uses the specified field to fill the Z coordinate of "
8266
0
                "geometries."));
8267
8268
0
    argParser->add_argument("-gcp")
8269
0
        .metavar(
8270
0
            "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")
8271
0
        .nargs(4, 5)
8272
0
        .append()
8273
0
        .scan<'g', double>()
8274
0
        .help(_("Add the indicated ground control point."));
8275
8276
0
    argParser->add_argument("-tps")
8277
0
        .flag()
8278
0
        .action([psOptions](const std::string &)
8279
0
                { psOptions->nTransformOrder = -1; })
8280
0
        .help(_("Force use of thin plate spline transformer based on available "
8281
0
                "GCPs."));
8282
8283
0
    argParser->add_argument("-order")
8284
0
        .metavar("1|2|3")
8285
0
        .store_into(psOptions->nTransformOrder)
8286
0
        .help(_("Order of polynomial used for warping."));
8287
8288
0
    argParser->add_argument("-xyRes")
8289
0
        .metavar("<val>[ m|mm|deg]")
8290
0
        .action(
8291
0
            [psOptions](const std::string &s)
8292
0
            {
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
0
        .help(_("Set/override the geometry X/Y coordinate resolution."));
8315
8316
0
    argParser->add_argument("-zRes")
8317
0
        .metavar("<val>[ m|mm]")
8318
0
        .action(
8319
0
            [psOptions](const std::string &s)
8320
0
            {
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
0
        .help(_("Set/override the geometry Z coordinate resolution."));
8343
8344
0
    argParser->add_argument("-mRes")
8345
0
        .metavar("<val>")
8346
0
        .store_into(psOptions->dfMRes)
8347
0
        .help(_("Set/override the geometry M coordinate resolution."));
8348
8349
0
    argParser->add_argument("-unsetCoordPrecision")
8350
0
        .store_into(psOptions->bUnsetCoordPrecision)
8351
0
        .help(_("Prevent the geometry coordinate resolution from being set on "
8352
0
                "target layer(s)."));
8353
8354
    ///////////////////////////////////////////////////////////////////////
8355
0
    argParser->add_group("Other options");
8356
8357
0
    argParser->add_quiet_argument(&psOptions->bQuiet);
8358
8359
0
    argParser->add_argument("-progress")
8360
0
        .store_into(psOptions->bDisplayProgress)
8361
0
        .help(_("Display progress on terminal. Only works if input layers have "
8362
0
                "the 'fast feature count' capability."));
8363
8364
0
    argParser->add_input_format_argument(
8365
0
        psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers
8366
0
                           : nullptr);
8367
8368
0
    argParser->add_open_options_argument(
8369
0
        psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);
8370
8371
0
    argParser->add_argument("-doo")
8372
0
        .metavar("<NAME>=<VALUE>")
8373
0
        .append()
8374
0
        .action([psOptions](const std::string &s)
8375
0
                { psOptions->aosDestOpenOptions.AddString(s.c_str()); })
8376
0
        .help(_("Open option(s) for output dataset."));
8377
8378
0
    argParser->add_usage_newline();
8379
8380
0
    argParser->add_argument("-fid")
8381
0
        .metavar("<FID>")
8382
0
        .store_into(psOptions->nFIDToFetch)
8383
0
        .help(_("If provided, only the feature with the specified feature id "
8384
0
                "will be processed."));
8385
8386
0
    argParser->add_argument("-preserve_fid")
8387
0
        .store_into(psOptions->bPreserveFID)
8388
0
        .help(_("Use the FID of the source features instead of letting the "
8389
0
                "output driver automatically assign a new one."));
8390
8391
0
    argParser->add_argument("-unsetFid")
8392
0
        .store_into(psOptions->bUnsetFid)
8393
0
        .help(_("Prevent the name of the source FID column and source feature "
8394
0
                "IDs from being reused."));
8395
8396
0
    {
8397
0
        auto &group = argParser->add_mutually_exclusive_group();
8398
0
        group.add_argument("-skip", "-skipfailures")
8399
0
            .flag()
8400
0
            .action(
8401
0
                [psOptions](const std::string &)
8402
0
                {
8403
0
                    psOptions->bSkipFailures = true;
8404
0
                    psOptions->nGroupTransactions = 1; /* #2409 */
8405
0
                })
8406
0
            .help(_("Continue after a failure, skipping the failed feature."));
8407
8408
0
        auto &arg = group.add_argument("-gt")
8409
0
                        .metavar("<n>|unlimited")
8410
0
                        .action(
8411
0
                            [psOptions](const std::string &s)
8412
0
                            {
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
0
                        .help(_("Group <n> features per transaction "));
8425
8426
0
        argParser->add_hidden_alias_for(arg, "tg");
8427
0
    }
8428
8429
0
    argParser->add_argument("-limit")
8430
0
        .metavar("<nb_features>")
8431
0
        .store_into(psOptions->nLimit)
8432
0
        .help(_("Limit the number of features per layer."));
8433
8434
0
    argParser->add_argument("-ds_transaction")
8435
0
        .flag()
8436
0
        .action(
8437
0
            [psOptions](const std::string &)
8438
0
            {
8439
0
                psOptions->nLayerTransaction = FALSE;
8440
0
                psOptions->bForceTransaction = true;
8441
0
            })
8442
0
        .help(_("Force the use of a dataset level transaction."));
8443
8444
    /* Undocumented. Just a provision. Default behavior should be OK */
8445
0
    argParser->add_argument("-lyr_transaction")
8446
0
        .flag()
8447
0
        .hidden()
8448
0
        .action([psOptions](const std::string &)
8449
0
                { psOptions->nLayerTransaction = TRUE; })
8450
0
        .help(_("Force the use of a layer level transaction."));
8451
8452
0
    argParser->add_metadata_item_options_argument(
8453
0
        psOptions->aosMetadataOptions);
8454
8455
0
    argParser->add_argument("-nomd")
8456
0
        .flag()
8457
0
        .action([psOptions](const std::string &)
8458
0
                { psOptions->bCopyMD = false; })
8459
0
        .help(_("Disable copying of metadata from source dataset and layers "
8460
0
                "into target dataset and layers."));
8461
8462
    // Undocumented option used by gdal vector convert
8463
0
    argParser->add_argument("--no-overwrite")
8464
0
        .store_into(psOptions->bNoOverwrite)
8465
0
        .hidden();
8466
8467
    // Undocumented option used by gdal vector * algorithms
8468
0
    argParser->add_argument("--invoked-from-gdal-algorithm")
8469
0
        .store_into(psOptions->bInvokedFromGdalAlgorithm)
8470
0
        .hidden();
8471
8472
0
    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
0
    argParser->add_argument("layer")
8486
0
        .remaining()
8487
0
        .metavar("<layer_name>")
8488
0
        .help(_("Layer name"));
8489
0
    return argParser;
8490
0
}
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
0
{
8524
0
    if (i + nExtraArg >= nArgc)
8525
0
    {
8526
0
        CPLError(CE_Failure, CPLE_IllegalArg,
8527
0
                 "%s option requires %d argument%s", papszArgv[i], nExtraArg,
8528
0
                 nExtraArg == 1 ? "" : "s");
8529
0
        return false;
8530
0
    }
8531
0
    return true;
8532
0
}
8533
#endif
8534
8535
#define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \
8536
0
    if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc))         \
8537
0
    {                                                                          \
8538
0
        return nullptr;                                                        \
8539
0
    }
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
0
{
8564
0
    auto psOptions = std::make_unique<GDALVectorTranslateOptions>();
8565
8566
0
    try
8567
0
    {
8568
        // Pre-processing for custom syntax that ArgumentParser does not support
8569
8570
0
        CPLStringList aosArgv;
8571
0
        const int nArgc = CSLCount(papszArgv);
8572
0
        int nCountClipSrc = 0;
8573
0
        int nCountClipDst = 0;
8574
0
        for (int i = 0;
8575
0
             i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
8576
0
        {
8577
0
            if (EQUAL(papszArgv[i], "-gcp"))
8578
0
            {
8579
                // repeated argument of varying size: not handled by argparse.
8580
8581
0
                CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
8582
0
                char *endptr = nullptr;
8583
                /* -gcp pixel line easting northing [elev] */
8584
8585
0
                psOptions->asGCPs.resize(psOptions->asGCPs.size() + 1);
8586
0
                auto &sGCP = psOptions->asGCPs.back();
8587
8588
0
                const auto oPixel = cpl::strict_parse<double>(papszArgv[++i]);
8589
0
                const auto oLine = cpl::strict_parse<double>(papszArgv[++i]);
8590
0
                const auto oX = cpl::strict_parse<double>(papszArgv[++i]);
8591
0
                const auto oY = cpl::strict_parse<double>(papszArgv[++i]);
8592
8593
0
                if (!oPixel.has_value() || !oLine.has_value() ||
8594
0
                    !oX.has_value() || !oY.has_value())
8595
0
                {
8596
0
                    CPLError(CE_Failure, CPLE_IllegalArg, "Invalid -gcp value");
8597
0
                    return nullptr;
8598
0
                }
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
0
            else if (EQUAL(papszArgv[i], "-clipsrc"))
8620
0
            {
8621
0
                if (nCountClipSrc)
8622
0
                {
8623
0
                    CPLError(CE_Failure, CPLE_AppDefined,
8624
0
                             "Duplicate argument %s", papszArgv[i]);
8625
0
                    return nullptr;
8626
0
                }
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
0
                nCountClipSrc = 1;
8631
0
                CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8632
0
                if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8633
0
                    i + 4 < nArgc)
8634
0
                {
8635
0
                    nCountClipSrc = 4;
8636
0
                }
8637
8638
0
                for (int j = 0; j < 1 + nCountClipSrc; ++j)
8639
0
                {
8640
0
                    aosArgv.AddString(papszArgv[i]);
8641
0
                    ++i;
8642
0
                }
8643
0
                --i;
8644
0
            }
8645
8646
0
            else if (EQUAL(papszArgv[i], "-clipdst"))
8647
0
            {
8648
0
                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
0
                nCountClipDst = 1;
8658
0
                CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8659
0
                if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8660
0
                    i + 4 < nArgc)
8661
0
                {
8662
0
                    nCountClipDst = 4;
8663
0
                }
8664
8665
0
                for (int j = 0; j < 1 + nCountClipDst; ++j)
8666
0
                {
8667
0
                    aosArgv.AddString(papszArgv[i]);
8668
0
                    ++i;
8669
0
                }
8670
0
                --i;
8671
0
            }
8672
8673
0
            else
8674
0
            {
8675
0
                aosArgv.AddString(papszArgv[i]);
8676
0
            }
8677
0
        }
8678
8679
0
        auto argParser = GDALVectorTranslateOptionsGetParser(
8680
0
            psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);
8681
8682
        // Collect non-positional arguments for VectorTranslateFrom() case
8683
0
        psOptions->aosArguments =
8684
0
            argParser->get_non_positional_arguments(aosArgv);
8685
8686
0
        argParser->parse_args_without_binary_name(aosArgv.List());
8687
8688
0
        if (psOptionsForBinary)
8689
0
            psOptionsForBinary->bQuiet = psOptions->bQuiet;
8690
8691
0
        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
0
        if (auto oClipSrc =
8704
0
                argParser->present<std::vector<std::string>>("-clipsrc"))
8705
0
        {
8706
0
            const std::string &osVal = (*oClipSrc)[0];
8707
8708
0
            psOptions->poClipSrc.reset();
8709
0
            psOptions->osClipSrcDS.clear();
8710
8711
0
            VSIStatBufL sStat;
8712
0
            psOptions->bClipSrc = true;
8713
0
            if (oClipSrc->size() == 4)
8714
0
            {
8715
0
                const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
8716
0
                const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
8717
0
                const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
8718
0
                const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
8719
8720
0
                OGRLinearRing oRing;
8721
8722
0
                oRing.addPoint(dfMinX, dfMinY);
8723
0
                oRing.addPoint(dfMinX, dfMaxY);
8724
0
                oRing.addPoint(dfMaxX, dfMaxY);
8725
0
                oRing.addPoint(dfMaxX, dfMinY);
8726
0
                oRing.addPoint(dfMinX, dfMinY);
8727
8728
0
                auto poPoly = std::make_shared<OGRPolygon>();
8729
0
                psOptions->poClipSrc = poPoly;
8730
0
                poPoly->addRing(&oRing);
8731
0
            }
8732
0
            else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8733
0
                      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
0
            else if (EQUAL(osVal.c_str(), "spat_extent"))
8748
0
            {
8749
                // Nothing to do
8750
0
            }
8751
0
            else
8752
0
            {
8753
0
                psOptions->osClipSrcDS = osVal;
8754
0
            }
8755
0
        }
8756
8757
0
        if (auto oClipDst =
8758
0
                argParser->present<std::vector<std::string>>("-clipdst"))
8759
0
        {
8760
0
            const std::string &osVal = (*oClipDst)[0];
8761
8762
0
            psOptions->poClipDst.reset();
8763
0
            psOptions->osClipDstDS.clear();
8764
8765
0
            VSIStatBufL sStat;
8766
0
            if (oClipDst->size() == 4)
8767
0
            {
8768
0
                const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());
8769
0
                const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());
8770
0
                const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());
8771
0
                const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());
8772
8773
0
                auto poPoly = std::make_shared<OGRPolygon>(dfMinX, dfMinY,
8774
0
                                                           dfMaxX, dfMaxY);
8775
0
                psOptions->poClipDst = poPoly;
8776
0
            }
8777
0
            else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8778
0
                      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
0
            else
8793
0
            {
8794
0
                psOptions->osClipDstDS = osVal;
8795
0
            }
8796
0
        }
8797
8798
0
        auto layers = argParser->present<std::vector<std::string>>("layer");
8799
0
        if (layers)
8800
0
        {
8801
0
            for (const auto &layer : *layers)
8802
0
            {
8803
0
                psOptions->aosLayers.AddString(layer.c_str());
8804
0
            }
8805
0
        }
8806
0
        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
0
        return psOptions.release();
8832
0
    }
8833
0
    catch (const std::exception &err)
8834
0
    {
8835
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
8836
0
        if (psOptionsForBinary)
8837
0
            psOptionsForBinary->bShowUsageIfError = true;
8838
0
        return nullptr;
8839
0
    }
8840
0
}
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
0
{
8855
0
    delete psOptions;
8856
0
}
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