Coverage Report

Created: 2026-10-28 07:09

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
    auto poSrcDriver = poSrcDS ? poSrcDS->GetDriver() : nullptr;
4220
0
    auto poDstDriver = poDstDS ? poDstDS->GetDriver() : nullptr;
4221
4222
0
    const auto IsArrowNativeDriver = [](GDALDriver *poDriver)
4223
0
    {
4224
0
        return poDriver && (EQUAL(poDriver->GetDescription(), "ARROW") ||
4225
0
                            EQUAL(poDriver->GetDescription(), "PARQUET") ||
4226
0
                            EQUAL(poDriver->GetDescription(), "ADBC"));
4227
0
    };
4228
4229
0
    if (!IsArrowNativeDriver(poSrcDriver) && !IsArrowNativeDriver(poDstDriver))
4230
0
    {
4231
        // For non-Arrow-native drivers, request DateTime as string, to
4232
        // allow mix of timezones
4233
0
        aosOptionsGetArrowStream.SetNameValue(GAS_OPT_DATETIME_AS_STRING,
4234
0
                                              "YES");
4235
0
    }
4236
4237
0
    return aosOptionsGetArrowStream;
4238
0
}
4239
4240
/************************************************************************/
4241
/*              SetupTargetLayer::CanUseWriteArrowBatch()               */
4242
/************************************************************************/
4243
4244
bool SetupTargetLayer::CanUseWriteArrowBatch(
4245
    OGRLayer *poSrcLayer, OGRLayer *poDstLayer, bool bJustCreatedLayer,
4246
    const GDALVectorTranslateOptions *psOptions, bool bPreserveFID,
4247
    OGRArrowArrayStream &streamSrc)
4248
0
{
4249
    // Check if we can use the Arrow interface to get and write features
4250
    // as it will be faster if the input driver has a fast
4251
    // implementation of GetArrowStream().
4252
    // We also can only do that only if using ogr2ogr without options that
4253
    // alter features.
4254
    // OGR2OGR_USE_ARROW_API config option is mostly for testing purposes
4255
    // or as a safety belt if things turned bad...
4256
0
    bool bUseWriteArrowBatch = false;
4257
0
    if (((poSrcLayer->TestCapability(OLCFastGetArrowStream) &&
4258
          // As we don't control the input array size when the input or output
4259
          // drivers are Arrow/Parquet (as they don't use the generic
4260
          // implementation), we can't guarantee that ROW_GROUP_SIZE/BATCH_SIZE
4261
          // layer creation options will be honored.
4262
0
          !psOptions->aosLCO.FetchNameValue("ROW_GROUP_SIZE") &&
4263
0
          !psOptions->aosLCO.FetchNameValue("BATCH_SIZE") &&
4264
0
          CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "YES"))) ||
4265
0
         CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "NO"))) &&
4266
0
        !psOptions->bUpsert && !psOptions->bSkipFailures &&
4267
0
        !psOptions->poClipSrc && !psOptions->poClipDst &&
4268
0
        psOptions->asGCPs.empty() && !psOptions->bWrapDateline &&
4269
0
        !m_bAddMissingFields && m_eGType == GEOMTYPE_UNCHANGED &&
4270
0
        psOptions->eGeomOp == GEOMOP_NONE &&
4271
0
        m_eGeomTypeConversion == GTC_DEFAULT && m_nCoordDim < 0 &&
4272
0
        !m_papszFieldTypesToString && !m_papszMapFieldType &&
4273
0
        !m_bUnsetFieldWidth && !m_bExplodeCollections && !m_pszZField &&
4274
0
        m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains &&
4275
0
        !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID &&
4276
0
        psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN &&
4277
0
        !psOptions->bMakeValid && !psOptions->bSkipInvalidGeom)
4278
0
    {
4279
0
        if (psOptions->bTransform)
4280
0
        {
4281
            // To simplify implementation for now
4282
0
            if (poSrcLayer->GetLayerDefn()->GetGeomFieldCount() != 1 ||
4283
0
                poDstLayer->GetLayerDefn()->GetGeomFieldCount() != 1)
4284
0
            {
4285
0
                return false;
4286
0
            }
4287
0
            const auto poSrcSRS = m_poUserSourceSRS ? m_poUserSourceSRS
4288
0
                                                    : poSrcLayer->GetLayerDefn()
4289
0
                                                          ->GetGeomFieldDefn(0)
4290
0
                                                          ->GetSpatialRef();
4291
0
            if (!OGRGeometryFactory::isTransformWithOptionsRegularTransform(
4292
0
                    poSrcSRS, m_poOutputSRS, nullptr))
4293
0
            {
4294
0
                return false;
4295
0
            }
4296
0
        }
4297
4298
0
        if (m_bSelFieldsSet)
4299
0
        {
4300
0
            SetIgnoredFields(poSrcLayer);
4301
0
        }
4302
4303
0
        const CPLStringList aosGetArrowStreamOptions(BuildGetArrowStreamOptions(
4304
0
            poSrcLayer, poDstLayer, psOptions, bPreserveFID));
4305
0
        if (poSrcLayer->GetArrowStream(streamSrc.get(),
4306
0
                                       aosGetArrowStreamOptions.List()))
4307
0
        {
4308
0
            struct ArrowSchema schemaSrc;
4309
0
            if (streamSrc.get_schema(&schemaSrc) == 0)
4310
0
            {
4311
0
                if (psOptions->bTransform &&
4312
0
                    GetArrowGeomFieldIndex(&schemaSrc,
4313
0
                                           poSrcLayer->GetGeometryColumn()) < 0)
4314
0
                {
4315
0
                    schemaSrc.release(&schemaSrc);
4316
0
                    streamSrc.clear();
4317
0
                    return false;
4318
0
                }
4319
4320
0
                std::string osErrorMsg;
4321
0
                if (poDstLayer->IsArrowSchemaSupported(&schemaSrc, nullptr,
4322
0
                                                       osErrorMsg))
4323
0
                {
4324
0
                    const OGRFeatureDefn *poSrcFDefn =
4325
0
                        poSrcLayer->GetLayerDefn();
4326
0
                    const OGRFeatureDefn *poDstFDefn =
4327
0
                        poDstLayer->GetLayerDefn();
4328
0
                    if (bJustCreatedLayer && poDstFDefn &&
4329
0
                        poDstFDefn->GetFieldCount() == 0 &&
4330
0
                        poDstFDefn->GetGeomFieldCount() ==
4331
0
                            poSrcFDefn->GetGeomFieldCount())
4332
0
                    {
4333
                        // Create output fields using CreateFieldFromArrowSchema()
4334
0
                        for (int i = 0; i < schemaSrc.n_children; ++i)
4335
0
                        {
4336
0
                            const char *pszFieldName =
4337
0
                                schemaSrc.children[i]->name;
4338
4339
0
                            const auto iSrcField =
4340
0
                                poSrcFDefn->GetFieldIndex(pszFieldName);
4341
0
                            if (iSrcField >= 0)
4342
0
                            {
4343
0
                                const auto poSrcFieldDefn =
4344
0
                                    poSrcFDefn->GetFieldDefn(iSrcField);
4345
                                // Create field domain in output dataset if not already existing.
4346
0
                                const std::string osDomainName(
4347
0
                                    poSrcFieldDefn->GetDomainName());
4348
0
                                if (!osDomainName.empty())
4349
0
                                {
4350
0
                                    if (m_poDstDS->TestCapability(
4351
0
                                            ODsCAddFieldDomain) &&
4352
0
                                        m_poDstDS->GetFieldDomain(
4353
0
                                            osDomainName) == nullptr)
4354
0
                                    {
4355
0
                                        const auto poSrcDomain =
4356
0
                                            m_poSrcDS->GetFieldDomain(
4357
0
                                                osDomainName);
4358
0
                                        if (poSrcDomain)
4359
0
                                        {
4360
0
                                            std::string failureReason;
4361
0
                                            if (!m_poDstDS->AddFieldDomain(
4362
0
                                                    std::unique_ptr<
4363
0
                                                        OGRFieldDomain>(
4364
0
                                                        poSrcDomain->Clone()),
4365
0
                                                    failureReason))
4366
0
                                            {
4367
0
                                                CPLDebug("OGR2OGR",
4368
0
                                                         "Cannot create domain "
4369
0
                                                         "%s: %s",
4370
0
                                                         osDomainName.c_str(),
4371
0
                                                         failureReason.c_str());
4372
0
                                            }
4373
0
                                        }
4374
0
                                        else
4375
0
                                        {
4376
0
                                            CPLDebug("OGR2OGR",
4377
0
                                                     "Cannot find domain %s in "
4378
0
                                                     "source dataset",
4379
0
                                                     osDomainName.c_str());
4380
0
                                        }
4381
0
                                    }
4382
0
                                }
4383
0
                            }
4384
4385
0
                            if (!EQUAL(pszFieldName, "OGC_FID") &&
4386
0
                                !EQUAL(pszFieldName, "wkb_geometry") &&
4387
0
                                !EQUAL(pszFieldName,
4388
0
                                       poSrcLayer->GetFIDColumn()) &&
4389
0
                                poSrcFDefn->GetGeomFieldIndex(pszFieldName) <
4390
0
                                    0 &&
4391
0
                                !poDstLayer->CreateFieldFromArrowSchema(
4392
0
                                    schemaSrc.children[i], nullptr))
4393
0
                            {
4394
0
                                CPLError(CE_Failure, CPLE_AppDefined,
4395
0
                                         "Cannot create field %s",
4396
0
                                         pszFieldName);
4397
0
                                schemaSrc.release(&schemaSrc);
4398
0
                                streamSrc.clear();
4399
0
                                return false;
4400
0
                            }
4401
0
                        }
4402
0
                        bUseWriteArrowBatch = true;
4403
0
                    }
4404
0
                    else if (!bJustCreatedLayer)
4405
0
                    {
4406
                        // If the layer already exist, get its schema, and
4407
                        // check that it looks to be the same as the source
4408
                        // one
4409
0
                        struct ArrowArrayStream streamDst;
4410
0
                        if (poDstLayer->GetArrowStream(
4411
0
                                &streamDst, aosGetArrowStreamOptions.List()))
4412
0
                        {
4413
0
                            struct ArrowSchema schemaDst;
4414
0
                            if (streamDst.get_schema(&streamDst, &schemaDst) ==
4415
0
                                0)
4416
0
                            {
4417
0
                                if (schemaDst.n_children ==
4418
0
                                    schemaSrc.n_children)
4419
0
                                {
4420
0
                                    bUseWriteArrowBatch = true;
4421
0
                                }
4422
0
                                schemaDst.release(&schemaDst);
4423
0
                            }
4424
0
                            streamDst.release(&streamDst);
4425
0
                        }
4426
0
                    }
4427
0
                    if (bUseWriteArrowBatch)
4428
0
                    {
4429
0
                        CPLDebug("OGR2OGR", "Using WriteArrowBatch()");
4430
0
                    }
4431
0
                }
4432
0
                else
4433
0
                {
4434
0
                    CPLDebug("OGR2OGR",
4435
0
                             "Cannot use WriteArrowBatch() because "
4436
0
                             "input layer schema is not supported by output "
4437
0
                             "layer: %s",
4438
0
                             osErrorMsg.c_str());
4439
0
                }
4440
0
                schemaSrc.release(&schemaSrc);
4441
0
            }
4442
0
            if (!bUseWriteArrowBatch)
4443
0
                streamSrc.clear();
4444
0
        }
4445
0
    }
4446
0
    return bUseWriteArrowBatch;
4447
0
}
4448
4449
/************************************************************************/
4450
/*                 SetupTargetLayer::SetIgnoredFields()                 */
4451
/************************************************************************/
4452
4453
void SetupTargetLayer::SetIgnoredFields(OGRLayer *poSrcLayer)
4454
0
{
4455
0
    bool bUseIgnoredFields = true;
4456
0
    CPLStringList aosWHEREUsedFields;
4457
0
    const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
4458
4459
0
    if (m_pszWHERE)
4460
0
    {
4461
        /* We must not ignore fields used in the -where expression
4462
         * (#4015) */
4463
0
        OGRFeatureQuery oFeatureQuery;
4464
0
        if (oFeatureQuery.Compile(poSrcFDefn, m_pszWHERE, FALSE, nullptr) ==
4465
0
            OGRERR_NONE)
4466
0
        {
4467
0
            aosWHEREUsedFields = oFeatureQuery.GetUsedFields();
4468
0
        }
4469
0
        else
4470
0
        {
4471
0
            bUseIgnoredFields = false;
4472
0
        }
4473
0
    }
4474
4475
0
    CPLStringList aosIgnoredFields;
4476
0
    for (int iSrcField = 0;
4477
0
         bUseIgnoredFields && iSrcField < poSrcFDefn->GetFieldCount();
4478
0
         iSrcField++)
4479
0
    {
4480
0
        const char *pszFieldName =
4481
0
            poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();
4482
0
        bool bFieldRequested =
4483
0
            CSLFindString(m_papszSelFields, pszFieldName) >= 0;
4484
0
        bFieldRequested |= aosWHEREUsedFields.FindString(pszFieldName) >= 0;
4485
0
        bFieldRequested |=
4486
0
            (m_pszZField != nullptr && EQUAL(pszFieldName, m_pszZField));
4487
4488
        // If the source field is not requested, add it to the list of ignored
4489
        // fields.
4490
0
        if (!bFieldRequested)
4491
0
            aosIgnoredFields.push_back(pszFieldName);
4492
0
    }
4493
0
    if (bUseIgnoredFields)
4494
0
        poSrcLayer->SetIgnoredFields(
4495
0
            const_cast<const char **>(aosIgnoredFields.List()));
4496
0
}
4497
4498
/************************************************************************/
4499
/*                      SetupTargetLayer::Setup()                       */
4500
/************************************************************************/
4501
4502
std::unique_ptr<TargetLayerInfo>
4503
SetupTargetLayer::Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
4504
                        GDALVectorTranslateOptions *psOptions,
4505
                        GIntBig &nTotalEventsDone)
4506
0
{
4507
0
    int eGType = m_eGType;
4508
0
    bool bPreserveFID = m_bPreserveFID;
4509
0
    bool bAppend = m_bAppend;
4510
4511
0
    if (pszNewLayerName == nullptr)
4512
0
        pszNewLayerName = poSrcLayer->GetName();
4513
4514
    /* -------------------------------------------------------------------- */
4515
    /*      Get other info.                                                 */
4516
    /* -------------------------------------------------------------------- */
4517
4518
    // Capture errors from VRT layers such as WFS
4519
    // (see issue GH # https://github.com/OSGeo/gdal/issues/14826)
4520
0
    const auto errorCount{CPLGetErrorCounter()};
4521
0
    const OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
4522
0
    if (CPLGetErrorCounter() != errorCount)
4523
0
    {
4524
0
        CPLError(CE_Failure, CPLE_AppDefined,
4525
0
                 "Error retrieving the source layer definition");
4526
0
        return nullptr;
4527
0
    }
4528
4529
    /* -------------------------------------------------------------------- */
4530
    /*      Find requested geometry fields.                                 */
4531
    /* -------------------------------------------------------------------- */
4532
0
    std::vector<int> anRequestedGeomFields;
4533
0
    const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
4534
0
    if (m_bSelFieldsSet && !bAppend)
4535
0
    {
4536
0
        for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4537
0
             iField++)
4538
0
        {
4539
0
            int iSrcField = poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4540
0
            if (iSrcField >= 0)
4541
0
            {
4542
                /* do nothing */
4543
0
            }
4544
0
            else
4545
0
            {
4546
0
                iSrcField =
4547
0
                    poSrcFDefn->GetGeomFieldIndex(m_papszSelFields[iField]);
4548
0
                if (iSrcField >= 0)
4549
0
                {
4550
0
                    anRequestedGeomFields.push_back(iSrcField);
4551
0
                }
4552
0
                else
4553
0
                {
4554
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4555
0
                             "Field '%s' not found in source layer.",
4556
0
                             m_papszSelFields[iField]);
4557
0
                    if (!psOptions->bSkipFailures)
4558
0
                        return nullptr;
4559
0
                }
4560
0
            }
4561
0
        }
4562
4563
0
        if (anRequestedGeomFields.size() > 1 &&
4564
0
            !m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4565
0
        {
4566
0
            CPLError(CE_Failure, CPLE_AppDefined,
4567
0
                     "Several geometry fields requested, but output "
4568
0
                     "datasource does not support multiple geometry "
4569
0
                     "fields.");
4570
0
            if (!psOptions->bSkipFailures)
4571
0
                return nullptr;
4572
0
            else
4573
0
                anRequestedGeomFields.resize(0);
4574
0
        }
4575
0
    }
4576
4577
0
    const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
4578
0
    if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
4579
0
    {
4580
0
        if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())
4581
0
            poOutputSRS = poSrcLayer->GetSpatialRef();
4582
0
        else if (anRequestedGeomFields.size() == 1)
4583
0
        {
4584
0
            int iSrcGeomField = anRequestedGeomFields[0];
4585
0
            poOutputSRS =
4586
0
                poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetSpatialRef();
4587
0
        }
4588
0
    }
4589
4590
0
    int iSrcZField = -1;
4591
0
    if (m_pszZField != nullptr)
4592
0
    {
4593
0
        iSrcZField = poSrcFDefn->GetFieldIndex(m_pszZField);
4594
0
        if (iSrcZField < 0)
4595
0
        {
4596
0
            CPLError(CE_Warning, CPLE_AppDefined,
4597
0
                     "zfield '%s' does not exist in layer %s", m_pszZField,
4598
0
                     poSrcLayer->GetName());
4599
0
        }
4600
0
    }
4601
4602
    /* -------------------------------------------------------------------- */
4603
    /*      Find the layer.                                                 */
4604
    /* -------------------------------------------------------------------- */
4605
4606
0
    bool bErrorOccurred;
4607
0
    bool bOverwriteActuallyDone;
4608
0
    bool bAddOverwriteLCO;
4609
0
    OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(
4610
0
        m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,
4611
0
        &bOverwriteActuallyDone, &bAddOverwriteLCO);
4612
0
    const bool bJustCreatedLayer = (poDstLayer == nullptr);
4613
0
    if (bErrorOccurred)
4614
0
        return nullptr;
4615
4616
    /* -------------------------------------------------------------------- */
4617
    /*      If the layer does not exist, then create it.                    */
4618
    /* -------------------------------------------------------------------- */
4619
0
    if (poDstLayer == nullptr)
4620
0
    {
4621
0
        if (!m_poDstDS->TestCapability(ODsCCreateLayer))
4622
0
        {
4623
0
            CPLError(
4624
0
                CE_Failure, CPLE_AppDefined,
4625
0
                "Layer '%s' does not already exist in the output dataset, and "
4626
0
                "cannot be created by the output driver.",
4627
0
                pszNewLayerName);
4628
0
            return nullptr;
4629
0
        }
4630
4631
0
        bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);
4632
0
        if (!bForceGType)
4633
0
        {
4634
0
            if (anRequestedGeomFields.empty())
4635
0
            {
4636
0
                eGType = poSrcFDefn->GetGeomType();
4637
0
            }
4638
0
            else if (anRequestedGeomFields.size() == 1)
4639
0
            {
4640
0
                int iSrcGeomField = anRequestedGeomFields[0];
4641
0
                eGType = poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetType();
4642
0
            }
4643
0
            else
4644
0
            {
4645
0
                eGType = wkbNone;
4646
0
            }
4647
4648
0
            const bool bHasZ = wkbHasZ(static_cast<OGRwkbGeometryType>(eGType));
4649
0
            eGType = ConvertType(m_eGeomTypeConversion,
4650
0
                                 static_cast<OGRwkbGeometryType>(eGType));
4651
4652
0
            if (m_bExplodeCollections)
4653
0
            {
4654
0
                const OGRwkbGeometryType eFGType = wkbFlatten(eGType);
4655
0
                if (eFGType == wkbMultiPoint)
4656
0
                {
4657
0
                    eGType = wkbPoint;
4658
0
                }
4659
0
                else if (eFGType == wkbMultiLineString)
4660
0
                {
4661
0
                    eGType = wkbLineString;
4662
0
                }
4663
0
                else if (eFGType == wkbMultiPolygon)
4664
0
                {
4665
0
                    eGType = wkbPolygon;
4666
0
                }
4667
0
                else if (eFGType == wkbGeometryCollection ||
4668
0
                         eFGType == wkbMultiCurve || eFGType == wkbMultiSurface)
4669
0
                {
4670
0
                    eGType = wkbUnknown;
4671
0
                }
4672
0
            }
4673
4674
0
            if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))
4675
0
                eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));
4676
0
        }
4677
4678
0
        eGType = ForceCoordDimension(eGType, m_nCoordDim);
4679
4680
0
        CPLErrorReset();
4681
4682
0
        CPLStringList aosLCOTemp(CSLDuplicate(m_papszLCO));
4683
0
        const char *pszDestCreationOptions =
4684
0
            m_poDstDS->GetDriver()->GetMetadataItem(
4685
0
                GDAL_DS_LAYER_CREATIONOPTIONLIST);
4686
4687
0
        int eGCreateLayerType = eGType;
4688
0
        if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4689
0
            m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4690
0
        {
4691
0
            eGCreateLayerType = wkbNone;
4692
0
        }
4693
        // If the source layer has a single geometry column that is not nullable
4694
        // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it
4695
        // so as to be able to set the not null constraint (if the driver
4696
        // supports it) and that the output driver has no GEOMETRY_NULLABLE
4697
        // layer creation option. Same if the source geometry column has a non
4698
        // empty name that is not overridden, and that the output driver has no
4699
        // GEOMETRY_NAME layer creation option, but no LAUNDER option (if
4700
        // laundering is available, then we might want to launder the geometry
4701
        // column name as well)
4702
0
        else if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4703
0
                 nSrcGeomFieldCount == 1 &&
4704
0
                 m_poDstDS->TestCapability(
4705
0
                     ODsCCreateGeomFieldAfterCreateLayer) &&
4706
0
                 ((!poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4707
0
                   CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") ==
4708
0
                       nullptr &&
4709
0
                   (pszDestCreationOptions == nullptr ||
4710
0
                    strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") !=
4711
0
                        nullptr) &&
4712
0
                   !m_bForceNullable) ||
4713
0
                  (poSrcLayer->GetGeometryColumn() != nullptr &&
4714
0
                   CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&
4715
0
                   !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&
4716
0
                   (pszDestCreationOptions == nullptr ||
4717
0
                    strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==
4718
0
                        nullptr ||
4719
0
                    strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&
4720
0
                   poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <
4721
0
                       0)))
4722
0
        {
4723
0
            anRequestedGeomFields.push_back(0);
4724
0
            eGCreateLayerType = wkbNone;
4725
0
        }
4726
0
        else if (anRequestedGeomFields.size() == 1 &&
4727
0
                 m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4728
0
        {
4729
0
            eGCreateLayerType = wkbNone;
4730
0
        }
4731
4732
0
        OGRGeomCoordinatePrecision oCoordPrec;
4733
0
        std::string osGeomFieldName;
4734
0
        bool bGeomFieldNullable = true;
4735
4736
0
        {
4737
0
            int iSrcGeomField = -1;
4738
0
            if (anRequestedGeomFields.empty() &&
4739
0
                (nSrcGeomFieldCount == 1 ||
4740
0
                 (!m_poDstDS->TestCapability(
4741
0
                      ODsCCreateGeomFieldAfterCreateLayer) &&
4742
0
                  nSrcGeomFieldCount > 1)))
4743
0
            {
4744
0
                iSrcGeomField = 0;
4745
0
            }
4746
0
            else if (anRequestedGeomFields.size() == 1)
4747
0
            {
4748
0
                iSrcGeomField = anRequestedGeomFields[0];
4749
0
            }
4750
4751
0
            if (iSrcGeomField >= 0)
4752
0
            {
4753
0
                const auto poSrcGeomFieldDefn =
4754
0
                    poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);
4755
0
                if (!psOptions->bUnsetCoordPrecision)
4756
0
                {
4757
0
                    oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()
4758
0
                                     .ConvertToOtherSRS(
4759
0
                                         poSrcGeomFieldDefn->GetSpatialRef(),
4760
0
                                         poOutputSRS);
4761
0
                }
4762
4763
0
                bGeomFieldNullable =
4764
0
                    CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());
4765
4766
0
                const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();
4767
0
                if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&
4768
0
                    poSrcFDefn->GetFieldIndex(pszGFldName) < 0)
4769
0
                {
4770
0
                    osGeomFieldName = pszGFldName;
4771
4772
                    // Use source geometry field name as much as possible
4773
0
                    if (eGType != wkbNone && pszDestCreationOptions &&
4774
0
                        strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=
4775
0
                            nullptr &&
4776
0
                        CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==
4777
0
                            nullptr)
4778
0
                    {
4779
0
                        aosLCOTemp.SetNameValue("GEOMETRY_NAME", pszGFldName);
4780
0
                    }
4781
0
                }
4782
0
            }
4783
0
        }
4784
4785
        // If the source feature first geometry column is not nullable
4786
        // and that GEOMETRY_NULLABLE creation option is available, use it
4787
        // so as to be able to set the not null constraint (if the driver
4788
        // supports it)
4789
0
        if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4790
0
            nSrcGeomFieldCount >= 1 &&
4791
0
            !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4792
0
            pszDestCreationOptions != nullptr &&
4793
0
            strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") != nullptr &&
4794
0
            CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") == nullptr &&
4795
0
            !m_bForceNullable)
4796
0
        {
4797
0
            bGeomFieldNullable = false;
4798
0
            aosLCOTemp.SetNameValue("GEOMETRY_NULLABLE", "NO");
4799
0
            CPLDebug("GDALVectorTranslate", "Using GEOMETRY_NULLABLE=NO");
4800
0
        }
4801
4802
0
        if (psOptions->dfXYRes != OGRGeomCoordinatePrecision::UNKNOWN)
4803
0
        {
4804
0
            if (m_poDstDS->GetDriver()->GetMetadataItem(
4805
0
                    GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr &&
4806
0
                !OGRGeometryFactory::haveGEOS())
4807
0
            {
4808
0
                CPLError(CE_Warning, CPLE_AppDefined,
4809
0
                         "-xyRes specified, but driver does not expose the "
4810
0
                         "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, "
4811
0
                         "and this build has no GEOS support");
4812
0
            }
4813
4814
0
            oCoordPrec.dfXYResolution = psOptions->dfXYRes;
4815
0
            if (!psOptions->osXYResUnit.empty())
4816
0
            {
4817
0
                if (!poOutputSRS)
4818
0
                {
4819
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4820
0
                             "Unit suffix for -xyRes cannot be used with an "
4821
0
                             "unknown destination SRS");
4822
0
                    return nullptr;
4823
0
                }
4824
4825
0
                if (psOptions->osXYResUnit == "mm")
4826
0
                {
4827
0
                    oCoordPrec.dfXYResolution *= 1e-3;
4828
0
                }
4829
0
                else if (psOptions->osXYResUnit == "deg")
4830
0
                {
4831
0
                    double dfFactorDegToMeter =
4832
0
                        poOutputSRS->GetSemiMajor(nullptr) * M_PI / 180;
4833
0
                    oCoordPrec.dfXYResolution *= dfFactorDegToMeter;
4834
0
                }
4835
0
                else
4836
0
                {
4837
                    // Checked at argument parsing time
4838
0
                    CPLAssert(psOptions->osXYResUnit == "m");
4839
0
                }
4840
4841
0
                OGRGeomCoordinatePrecision tmp;
4842
0
                tmp.SetFromMeter(poOutputSRS, oCoordPrec.dfXYResolution, 0, 0);
4843
0
                oCoordPrec.dfXYResolution = tmp.dfXYResolution;
4844
0
            }
4845
0
        }
4846
4847
0
        if (psOptions->dfZRes != OGRGeomCoordinatePrecision::UNKNOWN)
4848
0
        {
4849
0
            if (m_poDstDS->GetDriver()->GetMetadataItem(
4850
0
                    GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4851
0
            {
4852
0
                CPLError(CE_Warning, CPLE_AppDefined,
4853
0
                         "-zRes specified, but driver does not expose the "
4854
0
                         "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4855
0
            }
4856
4857
0
            oCoordPrec.dfZResolution = psOptions->dfZRes;
4858
0
            if (!psOptions->osZResUnit.empty())
4859
0
            {
4860
0
                if (!poOutputSRS)
4861
0
                {
4862
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4863
0
                             "Unit suffix for -zRes cannot be used with an "
4864
0
                             "unknown destination SRS");
4865
0
                    return nullptr;
4866
0
                }
4867
4868
0
                if (psOptions->osZResUnit == "mm")
4869
0
                {
4870
0
                    oCoordPrec.dfZResolution *= 1e-3;
4871
0
                }
4872
0
                else
4873
0
                {
4874
                    // Checked at argument parsing time
4875
0
                    CPLAssert(psOptions->osZResUnit == "m");
4876
0
                }
4877
4878
0
                OGRGeomCoordinatePrecision tmp;
4879
0
                tmp.SetFromMeter(poOutputSRS, 0, oCoordPrec.dfZResolution, 0);
4880
0
                oCoordPrec.dfZResolution = tmp.dfZResolution;
4881
0
            }
4882
0
        }
4883
4884
0
        if (psOptions->dfMRes != OGRGeomCoordinatePrecision::UNKNOWN)
4885
0
        {
4886
0
            if (m_poDstDS->GetDriver()->GetMetadataItem(
4887
0
                    GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4888
0
            {
4889
0
                CPLError(CE_Warning, CPLE_AppDefined,
4890
0
                         "-mRes specified, but driver does not expose the "
4891
0
                         "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4892
0
            }
4893
4894
0
            oCoordPrec.dfMResolution = psOptions->dfMRes;
4895
0
        }
4896
4897
        // For JSONFG
4898
0
        CSLConstList papszMeasures = poSrcLayer->GetMetadata("MEASURES");
4899
0
        if (papszMeasures && pszDestCreationOptions)
4900
0
        {
4901
0
            for (const char *pszItem : {"UNIT", "DESCRIPTION"})
4902
0
            {
4903
0
                const char *pszValue =
4904
0
                    CSLFetchNameValue(papszMeasures, pszItem);
4905
0
                if (pszValue)
4906
0
                {
4907
0
                    const std::string osOptionName =
4908
0
                        std::string("MEASURE_").append(pszItem);
4909
0
                    if (strstr(pszDestCreationOptions, osOptionName.c_str()) &&
4910
0
                        CSLFetchNameValue(m_papszLCO, osOptionName.c_str()) ==
4911
0
                            nullptr)
4912
0
                    {
4913
0
                        aosLCOTemp.SetNameValue(osOptionName.c_str(), pszValue);
4914
0
                    }
4915
0
                }
4916
0
            }
4917
0
        }
4918
4919
0
        auto poSrcDriver = m_poSrcDS->GetDriver();
4920
4921
        // Force FID column as 64 bit if the source feature has a 64 bit FID,
4922
        // the target driver supports 64 bit FID and the user didn't set it
4923
        // manually.
4924
0
        if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
4925
0
            EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&
4926
0
            pszDestCreationOptions &&
4927
0
            strstr(pszDestCreationOptions, "FID64") != nullptr &&
4928
0
            CSLFetchNameValue(m_papszLCO, "FID64") == nullptr)
4929
0
        {
4930
0
            aosLCOTemp.SetNameValue("FID64", "YES");
4931
0
            CPLDebug("GDALVectorTranslate", "Using FID64=YES");
4932
0
        }
4933
4934
        // If output driver supports FID layer creation option, set it with
4935
        // the FID column name of the source layer
4936
0
        if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&
4937
0
            !EQUAL(poSrcLayer->GetFIDColumn(), "") &&
4938
0
            pszDestCreationOptions != nullptr &&
4939
0
            (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4940
0
             strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4941
0
            CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4942
0
        {
4943
0
            aosLCOTemp.SetNameValue("FID", poSrcLayer->GetFIDColumn());
4944
0
            if (!psOptions->bExplodeCollections)
4945
0
            {
4946
0
                CPLDebug("GDALVectorTranslate",
4947
0
                         "Using FID=%s and -preserve_fid",
4948
0
                         poSrcLayer->GetFIDColumn());
4949
0
                bPreserveFID = true;
4950
0
            }
4951
0
            else
4952
0
            {
4953
0
                CPLDebug("GDALVectorTranslate",
4954
0
                         "Using FID=%s and disable -preserve_fid because not "
4955
0
                         "compatible with -explodecollection",
4956
0
                         poSrcLayer->GetFIDColumn());
4957
0
                bPreserveFID = false;
4958
0
            }
4959
0
        }
4960
        // Detect scenario of converting from GPX to a format like GPKG
4961
        // Cf https://github.com/OSGeo/gdal/issues/9225
4962
0
        else if (!bPreserveFID && !m_bUnsetFid && !bAppend && poSrcDriver &&
4963
0
                 EQUAL(poSrcDriver->GetDescription(), "GPX") &&
4964
0
                 pszDestCreationOptions &&
4965
0
                 (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4966
0
                  strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4967
0
                 CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4968
0
        {
4969
0
            CPLDebug("GDALVectorTranslate",
4970
0
                     "Forcing -preserve_fid because source is GPX and layers "
4971
0
                     "have FID cross references");
4972
0
            bPreserveFID = true;
4973
0
        }
4974
        // Detect scenario of converting GML2 with fid attribute to GPKG
4975
0
        else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&
4976
0
                 CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4977
0
        {
4978
0
            int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid");
4979
0
            if (nFieldIdx >= 0 && poSrcLayer->GetLayerDefn()
4980
0
                                          ->GetFieldDefn(nFieldIdx)
4981
0
                                          ->GetType() == OFTString)
4982
0
            {
4983
0
                CPLDebug("GDALVectorTranslate",
4984
0
                         "Source layer has a non-string 'fid' column. Using "
4985
0
                         "FID=gpkg_fid for GeoPackage");
4986
0
                aosLCOTemp.SetNameValue("FID", "gpkg_fid");
4987
0
            }
4988
0
        }
4989
4990
        // For a MapInfo -> MapInfo translation, preserve the layer bounds.
4991
0
        if (m_poSrcDS->GetDriver() == m_poDstDS->GetDriver() &&
4992
0
            EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File") &&
4993
0
            (m_poOutputSRS == nullptr || !m_bTransform) &&
4994
0
            CSLFetchNameValue(m_papszLCO, "BOUNDS") == nullptr)
4995
0
        {
4996
0
            if (const char *pszBounds = poSrcLayer->GetMetadataItem("BOUNDS"))
4997
0
            {
4998
0
                CPLDebug("GDALVectorTranslate", "Setting -lco BOUNDS=%s",
4999
0
                         pszBounds);
5000
0
                aosLCOTemp.SetNameValue("BOUNDS", pszBounds);
5001
0
            }
5002
0
        }
5003
5004
        // If bAddOverwriteLCO is ON (set up when overwriting a CARTO layer),
5005
        // set OVERWRITE to YES so the new layer overwrites the old one
5006
0
        if (bAddOverwriteLCO)
5007
0
        {
5008
0
            aosLCOTemp.SetNameValue("OVERWRITE", "ON");
5009
0
            CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON");
5010
0
        }
5011
5012
0
        if (m_bNativeData &&
5013
0
            poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") !=
5014
0
                nullptr &&
5015
0
            poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA") !=
5016
0
                nullptr &&
5017
0
            pszDestCreationOptions != nullptr &&
5018
0
            strstr(pszDestCreationOptions, "NATIVE_DATA") != nullptr &&
5019
0
            strstr(pszDestCreationOptions, "NATIVE_MEDIA_TYPE") != nullptr)
5020
0
        {
5021
0
            aosLCOTemp.SetNameValue(
5022
0
                "NATIVE_DATA",
5023
0
                poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA"));
5024
0
            aosLCOTemp.SetNameValue("NATIVE_MEDIA_TYPE",
5025
0
                                    poSrcLayer->GetMetadataItem(
5026
0
                                        "NATIVE_MEDIA_TYPE", "NATIVE_DATA"));
5027
0
            CPLDebug("GDALVectorTranslate", "Transferring layer NATIVE_DATA");
5028
0
        }
5029
5030
        // For FileGeodatabase, automatically set
5031
        // CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES creation option if the source
5032
        // layer has a Shape_Area/Shape_Length field
5033
0
        if (pszDestCreationOptions &&
5034
0
            strstr(pszDestCreationOptions,
5035
0
                   "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&
5036
0
            CSLFetchNameValue(m_papszLCO,
5037
0
                              "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)
5038
0
        {
5039
0
            const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
5040
0
            const int nIdxShapeArea =
5041
0
                poSrcLayerDefn->GetFieldIndex("Shape_Area");
5042
0
            const int nIdxShapeLength =
5043
0
                poSrcLayerDefn->GetFieldIndex("Shape_Length");
5044
0
            if ((nIdxShapeArea >= 0 &&
5045
0
                 poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=
5046
0
                     nullptr &&
5047
0
                 EQUAL(
5048
0
                     poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),
5049
0
                     "FILEGEODATABASE_SHAPE_AREA") &&
5050
0
                 (m_papszSelFields == nullptr ||
5051
0
                  CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||
5052
0
                (nIdxShapeLength >= 0 &&
5053
0
                 poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=
5054
0
                     nullptr &&
5055
0
                 EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)
5056
0
                           ->GetDefault(),
5057
0
                       "FILEGEODATABASE_SHAPE_LENGTH") &&
5058
0
                 (m_papszSelFields == nullptr ||
5059
0
                  CSLFindString(m_papszSelFields, "Shape_Length") >= 0)))
5060
0
            {
5061
0
                aosLCOTemp.SetNameValue("CREATE_SHAPE_AREA_AND_LENGTH_FIELDS",
5062
0
                                        "YES");
5063
0
                CPLDebug("GDALVectorTranslate",
5064
0
                         "Setting CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES");
5065
0
            }
5066
0
        }
5067
5068
        // Use case of https://github.com/OSGeo/gdal/issues/11057#issuecomment-2495479779
5069
        // Conversion from GPKG to OCI.
5070
        // OCI distinguishes between TIMESTAMP and TIMESTAMP WITH TIME ZONE
5071
        // GeoPackage is supposed to have DateTime in UTC, so we set
5072
        // TIMESTAMP_WITH_TIME_ZONE=YES
5073
0
        if (poSrcDriver && pszDestCreationOptions &&
5074
0
            strstr(pszDestCreationOptions, "TIMESTAMP_WITH_TIME_ZONE") &&
5075
0
            CSLFetchNameValue(m_papszLCO, "TIMESTAMP_WITH_TIME_ZONE") ==
5076
0
                nullptr &&
5077
0
            EQUAL(poSrcDriver->GetDescription(), "GPKG"))
5078
0
        {
5079
0
            aosLCOTemp.SetNameValue("TIMESTAMP_WITH_TIME_ZONE", "YES");
5080
0
            CPLDebug("GDALVectorTranslate",
5081
0
                     "Setting TIMESTAMP_WITH_TIME_ZONE=YES");
5082
0
        }
5083
5084
0
        OGRGeomFieldDefn oGeomFieldDefn(
5085
0
            osGeomFieldName.c_str(),
5086
0
            static_cast<OGRwkbGeometryType>(eGCreateLayerType));
5087
0
        oGeomFieldDefn.SetSpatialRef(poOutputSRS);
5088
0
        oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);
5089
0
        oGeomFieldDefn.SetNullable(bGeomFieldNullable);
5090
0
        poDstLayer = m_poDstDS->CreateLayer(
5091
0
            pszNewLayerName,
5092
0
            eGCreateLayerType == wkbNone ? nullptr : &oGeomFieldDefn,
5093
0
            aosLCOTemp.List());
5094
5095
0
        if (poDstLayer == nullptr)
5096
0
        {
5097
0
            return nullptr;
5098
0
        }
5099
5100
        // Cf https://github.com/OSGeo/gdal/issues/6859
5101
        // warn if the user requests -t_srs but the driver uses a different SRS.
5102
0
        if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&
5103
            // MapInfo is somewhat lossy regarding SRS, so do not warn
5104
0
            !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))
5105
0
        {
5106
0
            auto poCreatedSRS = poDstLayer->GetSpatialRef();
5107
0
            if (poCreatedSRS != nullptr)
5108
0
            {
5109
0
                const char *const apszOptions[] = {
5110
0
                    "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
5111
0
                    "CRITERION=EQUIVALENT", nullptr};
5112
0
                if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))
5113
0
                {
5114
0
                    const char *pszTargetSRSName = m_poOutputSRS->GetName();
5115
0
                    const char *pszCreatedSRSName = poCreatedSRS->GetName();
5116
0
                    CPLError(CE_Warning, CPLE_AppDefined,
5117
0
                             "Target SRS %s not taken into account as target "
5118
0
                             "driver likely implements on-the-fly reprojection "
5119
0
                             "to %s",
5120
0
                             pszTargetSRSName ? pszTargetSRSName : "",
5121
0
                             pszCreatedSRSName ? pszCreatedSRSName : "");
5122
0
                }
5123
0
            }
5124
0
        }
5125
5126
0
        if (m_bCopyMD)
5127
0
        {
5128
0
            const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());
5129
0
            for (const char *pszMD : aosDomains)
5130
0
            {
5131
0
                if (!EQUAL(pszMD, GDAL_MDD_IMAGE_STRUCTURE) &&
5132
0
                    !EQUAL(pszMD, GDAL_MDD_SUBDATASETS))
5133
0
                {
5134
0
                    if (CSLConstList papszMD = poSrcLayer->GetMetadata(pszMD))
5135
0
                    {
5136
                        // MapInfo: Avoid overwriting the "BOUNDS" metadata on the output layer
5137
                        // with the value from the source layer. If the value should be
5138
                        // propagated, it will have been done via a layer creation option already.
5139
0
                        if (pszMD[0] == '\0' &&
5140
0
                            EQUAL(m_poDstDS->GetDriverName(), "MapInfo File"))
5141
0
                        {
5142
0
                            const char *pszBounds =
5143
0
                                aosLCOTemp.FetchNameValue("BOUNDS");
5144
0
                            CPLStringList aosTmpMD(CSLDuplicate(papszMD), true);
5145
0
                            aosTmpMD.SetNameValue("BOUNDS", pszBounds);
5146
0
                            poDstLayer->SetMetadata(aosTmpMD.List(), pszMD);
5147
0
                        }
5148
0
                        else
5149
0
                        {
5150
0
                            poDstLayer->SetMetadata(papszMD, pszMD);
5151
0
                        }
5152
0
                    }
5153
0
                }
5154
0
            }
5155
0
        }
5156
5157
0
        if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
5158
0
            m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
5159
0
        {
5160
0
            for (int i = 0; i < nSrcGeomFieldCount; i++)
5161
0
            {
5162
0
                anRequestedGeomFields.push_back(i);
5163
0
            }
5164
0
        }
5165
5166
0
        if (anRequestedGeomFields.size() > 1 ||
5167
0
            (anRequestedGeomFields.size() == 1 &&
5168
0
             m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))
5169
0
        {
5170
0
            for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());
5171
0
                 i++)
5172
0
            {
5173
0
                const int iSrcGeomField = anRequestedGeomFields[i];
5174
0
                OGRGeomFieldDefn oGFldDefn(
5175
0
                    poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));
5176
0
                if (m_poOutputSRS != nullptr)
5177
0
                {
5178
0
                    auto poOutputSRSClone =
5179
0
                        OGRSpatialReferenceRefCountedPtr::makeClone(
5180
0
                            m_poOutputSRS);
5181
0
                    oGFldDefn.SetSpatialRef(poOutputSRSClone.get());
5182
0
                }
5183
0
                if (bForceGType)
5184
0
                {
5185
0
                    oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5186
0
                }
5187
0
                else
5188
0
                {
5189
0
                    eGType = oGFldDefn.GetType();
5190
0
                    eGType =
5191
0
                        ConvertType(m_eGeomTypeConversion,
5192
0
                                    static_cast<OGRwkbGeometryType>(eGType));
5193
0
                    eGType = ForceCoordDimension(eGType, m_nCoordDim);
5194
0
                    oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5195
0
                }
5196
0
                if (m_bForceNullable)
5197
0
                    oGFldDefn.SetNullable(TRUE);
5198
0
                poDstLayer->CreateGeomField(&oGFldDefn);
5199
0
            }
5200
0
        }
5201
5202
0
        bAppend = false;
5203
0
    }
5204
5205
    /* -------------------------------------------------------------------- */
5206
    /*      Otherwise we will append to it, if append was requested.        */
5207
    /* -------------------------------------------------------------------- */
5208
0
    else if (!bAppend && !m_bNewDataSource)
5209
0
    {
5210
0
        if (psOptions->bInvokedFromGdalAlgorithm)
5211
0
        {
5212
0
            CPLError(CE_Failure, CPLE_AppDefined,
5213
0
                     "Layer %s already exists, and --append not specified. "
5214
0
                     "Consider using --append, or --overwrite-layer.",
5215
0
                     pszNewLayerName);
5216
0
        }
5217
0
        else
5218
0
        {
5219
0
            CPLError(CE_Failure, CPLE_AppDefined,
5220
0
                     "Layer %s already exists, and -append not specified.\n"
5221
0
                     "        Consider using -append, or -overwrite.",
5222
0
                     pszNewLayerName);
5223
0
        }
5224
0
        return nullptr;
5225
0
    }
5226
0
    else
5227
0
    {
5228
0
        if (CSLCount(m_papszLCO) > 0)
5229
0
        {
5230
0
            CPLError(
5231
0
                CE_Warning, CPLE_AppDefined,
5232
0
                "Layer creation options ignored since an existing layer is\n"
5233
0
                "         being appended to.");
5234
0
        }
5235
0
    }
5236
5237
    /* -------------------------------------------------------------------- */
5238
    /*      Process Layer style table                                       */
5239
    /* -------------------------------------------------------------------- */
5240
5241
0
    poDstLayer->SetStyleTable(poSrcLayer->GetStyleTable());
5242
    /* -------------------------------------------------------------------- */
5243
    /*      Add fields.  Default to copy all field.                         */
5244
    /*      If only a subset of all fields requested, then output only      */
5245
    /*      the selected fields, and in the order that they were            */
5246
    /*      selected.                                                       */
5247
    /* -------------------------------------------------------------------- */
5248
0
    const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
5249
0
    int iSrcFIDField = -1;
5250
5251
    // Initialize the index-to-index map to -1's
5252
0
    std::vector<int> anMap(nSrcFieldCount, -1);
5253
5254
0
    std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;
5255
5256
    /* Determine if NUMERIC field width narrowing is allowed */
5257
0
    auto poSrcDriver = m_poSrcDS->GetDriver();
5258
0
    const char *pszSrcWidthIncludesDecimalSeparator{
5259
0
        poSrcDriver ? poSrcDriver->GetMetadataItem(
5260
0
                          "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")
5261
0
                    : nullptr};
5262
0
    const bool bSrcWidthIncludesDecimalSeparator{
5263
0
        pszSrcWidthIncludesDecimalSeparator &&
5264
0
        EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};
5265
0
    const char *pszDstWidthIncludesDecimalSeparator{
5266
0
        m_poDstDS->GetDriver()->GetMetadataItem(
5267
0
            "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
5268
0
    const bool bDstWidthIncludesDecimalSeparator{
5269
0
        pszDstWidthIncludesDecimalSeparator &&
5270
0
        EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};
5271
0
    const char *pszSrcWidthIncludesMinusSign{
5272
0
        poSrcDriver ? poSrcDriver->GetMetadataItem(
5273
0
                          "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")
5274
0
                    : nullptr};
5275
0
    const bool bSrcWidthIncludesMinusSign{
5276
0
        pszSrcWidthIncludesMinusSign &&
5277
0
        EQUAL(pszSrcWidthIncludesMinusSign, "YES")};
5278
0
    const char *pszDstWidthIncludesMinusSign{
5279
0
        m_poDstDS->GetDriver()->GetMetadataItem(
5280
0
            "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
5281
0
    const bool bDstWidthIncludesMinusSign{
5282
0
        pszDstWidthIncludesMinusSign &&
5283
0
        EQUAL(pszDstWidthIncludesMinusSign, "YES")};
5284
5285
    // Calculate width delta
5286
0
    int iChangeWidthBy{0};
5287
5288
0
    if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)
5289
0
    {
5290
0
        iChangeWidthBy--;
5291
0
    }
5292
0
    else if (!bSrcWidthIncludesDecimalSeparator &&
5293
0
             bDstWidthIncludesDecimalSeparator)
5294
0
    {
5295
0
        iChangeWidthBy++;
5296
0
    }
5297
5298
    // We cannot assume there is no minus sign, we can only inflate here
5299
0
    if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)
5300
0
    {
5301
0
        iChangeWidthBy++;
5302
0
    }
5303
5304
0
    OGRArrowArrayStream streamSrc;
5305
5306
0
    const bool bUseWriteArrowBatch =
5307
0
        !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "OCI") &&
5308
0
        CanUseWriteArrowBatch(poSrcLayer, poDstLayer, bJustCreatedLayer,
5309
0
                              psOptions, bPreserveFID, streamSrc);
5310
5311
    /* Caution : at the time of writing, the MapInfo driver */
5312
    /* returns NULL until a field has been added */
5313
0
    OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
5314
5315
0
    if (bUseWriteArrowBatch)
5316
0
    {
5317
        // Fields created above
5318
0
    }
5319
0
    else if (m_papszFieldMap && bAppend)
5320
0
    {
5321
0
        bool bIdentity = false;
5322
5323
0
        if (EQUAL(m_papszFieldMap[0], "identity"))
5324
0
            bIdentity = true;
5325
0
        else if (CSLCount(m_papszFieldMap) != nSrcFieldCount)
5326
0
        {
5327
0
            CPLError(
5328
0
                CE_Failure, CPLE_AppDefined,
5329
0
                "Field map should contain the value 'identity' or "
5330
0
                "the same number of integer values as the source field count.");
5331
0
            return nullptr;
5332
0
        }
5333
5334
0
        for (int iField = 0; iField < nSrcFieldCount; iField++)
5335
0
        {
5336
0
            anMap[iField] = bIdentity ? iField : atoi(m_papszFieldMap[iField]);
5337
0
            if (anMap[iField] >= poDstFDefn->GetFieldCount())
5338
0
            {
5339
0
                CPLError(CE_Failure, CPLE_AppDefined,
5340
0
                         "Invalid destination field index %d.", anMap[iField]);
5341
0
                return nullptr;
5342
0
            }
5343
0
        }
5344
0
    }
5345
0
    else if (m_bSelFieldsSet && !bAppend)
5346
0
    {
5347
0
        int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5348
0
        for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5349
0
             iField++)
5350
0
        {
5351
0
            const int iSrcField =
5352
0
                poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5353
0
            if (iSrcField >= 0)
5354
0
            {
5355
0
                const OGRFieldDefn *poSrcFieldDefn =
5356
0
                    poSrcFDefn->GetFieldDefn(iSrcField);
5357
0
                OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5358
5359
0
                DoFieldTypeConversion(
5360
0
                    m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5361
0
                    m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5362
0
                    m_bForceNullable, m_bUnsetDefault);
5363
5364
0
                if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5365
0
                    oFieldDefn.GetWidth() != 0)
5366
0
                {
5367
0
                    oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5368
0
                }
5369
5370
                /* The field may have been already created at layer creation */
5371
0
                const int iDstField =
5372
0
                    poDstFDefn
5373
0
                        ? poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef())
5374
0
                        : -1;
5375
0
                if (iDstField >= 0)
5376
0
                {
5377
0
                    anMap[iSrcField] = iDstField;
5378
0
                }
5379
0
                else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5380
0
                {
5381
                    /* now that we've created a field, GetLayerDefn() won't
5382
                     * return NULL */
5383
0
                    if (poDstFDefn == nullptr)
5384
0
                        poDstFDefn = poDstLayer->GetLayerDefn();
5385
5386
                    /* Sanity check : if it fails, the driver is buggy */
5387
0
                    if (poDstFDefn != nullptr &&
5388
0
                        poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5389
0
                    {
5390
0
                        CPLError(CE_Warning, CPLE_AppDefined,
5391
0
                                 "The output driver has claimed to have added "
5392
0
                                 "the %s field, but it did not!",
5393
0
                                 oFieldDefn.GetNameRef());
5394
0
                    }
5395
0
                    else
5396
0
                    {
5397
0
                        anMap[iSrcField] = nDstFieldCount;
5398
0
                        nDstFieldCount++;
5399
0
                    }
5400
0
                }
5401
0
                else if (!psOptions->bSkipFailures)
5402
0
                    return nullptr;
5403
0
            }
5404
0
        }
5405
5406
        /* --------------------------------------------------------------------
5407
         */
5408
        /* Use SetIgnoredFields() on source layer if available */
5409
        /* --------------------------------------------------------------------
5410
         */
5411
0
        if (m_bSelFieldsSet && poSrcLayer->TestCapability(OLCIgnoreFields))
5412
0
        {
5413
0
            SetIgnoredFields(poSrcLayer);
5414
0
        }
5415
0
    }
5416
0
    else if (!bAppend || m_bAddMissingFields)
5417
0
    {
5418
0
        int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5419
5420
0
        const bool caseInsensitive =
5421
0
            !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");
5422
0
        const auto formatName = [caseInsensitive](const char *name)
5423
0
        {
5424
0
            if (caseInsensitive)
5425
0
            {
5426
0
                return CPLString(name).toupper();
5427
0
            }
5428
0
            else
5429
0
            {
5430
0
                return CPLString(name);
5431
0
            }
5432
0
        };
5433
5434
        /* Save the map of existing fields, before creating new ones */
5435
        /* This helps when converting a source layer that has duplicated field
5436
         * names */
5437
        /* which is a bad idea */
5438
0
        std::map<CPLString, int> oMapPreExistingFields;
5439
0
        std::unordered_set<std::string> oSetDstFieldNames;
5440
0
        for (int iField = 0; iField < nDstFieldCount; iField++)
5441
0
        {
5442
0
            const char *pszFieldName =
5443
0
                poDstFDefn->GetFieldDefn(iField)->GetNameRef();
5444
0
            CPLString osUpperFieldName(formatName(pszFieldName));
5445
0
            oSetDstFieldNames.insert(osUpperFieldName);
5446
0
            if (oMapPreExistingFields.find(osUpperFieldName) ==
5447
0
                oMapPreExistingFields.end())
5448
0
                oMapPreExistingFields[osUpperFieldName] = iField;
5449
            /*else
5450
                CPLError(CE_Warning, CPLE_AppDefined,
5451
                         "The target layer has already a duplicated field name
5452
               '%s' before " "adding the fields of the source layer",
5453
               pszFieldName); */
5454
0
        }
5455
5456
0
        const char *pszFIDColumn = poDstLayer->GetFIDColumn();
5457
5458
0
        std::vector<int> anSrcFieldIndices;
5459
0
        if (m_bSelFieldsSet)
5460
0
        {
5461
0
            for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5462
0
                 iField++)
5463
0
            {
5464
0
                const int iSrcField =
5465
0
                    poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5466
0
                if (iSrcField >= 0)
5467
0
                {
5468
0
                    anSrcFieldIndices.push_back(iSrcField);
5469
0
                }
5470
0
            }
5471
0
        }
5472
0
        else
5473
0
        {
5474
0
            for (int iField = 0; iField < nSrcFieldCount; iField++)
5475
0
            {
5476
0
                anSrcFieldIndices.push_back(iField);
5477
0
            }
5478
0
        }
5479
5480
0
        std::unordered_set<std::string> oSetSrcFieldNames;
5481
0
        for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)
5482
0
        {
5483
0
            oSetSrcFieldNames.insert(
5484
0
                formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));
5485
0
        }
5486
5487
        // For each source field name, memorize the last number suffix to have
5488
        // unique field names in the target. Let's imagine we have a source
5489
        // layer with the field name foo repeated twice After dealing the first
5490
        // field, oMapFieldNameToLastSuffix["foo"] will be 1, so when starting a
5491
        // unique name for the second field, we'll be able to start at 2. This
5492
        // avoids quadratic complexity if a big number of source field names are
5493
        // identical. Like in
5494
        // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37768
5495
0
        std::map<std::string, int> oMapFieldNameToLastSuffix;
5496
5497
0
        for (size_t i = 0; i < anSrcFieldIndices.size(); i++)
5498
0
        {
5499
0
            const int iField = anSrcFieldIndices[i];
5500
0
            const OGRFieldDefn *poSrcFieldDefn =
5501
0
                poSrcFDefn->GetFieldDefn(iField);
5502
0
            OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5503
5504
            // Avoid creating a field with the same name as the FID column
5505
0
            if (pszFIDColumn != nullptr &&
5506
0
                EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&
5507
0
                (oFieldDefn.GetType() == OFTInteger ||
5508
0
                 oFieldDefn.GetType() == OFTInteger64))
5509
0
            {
5510
0
                iSrcFIDField = iField;
5511
0
                continue;
5512
0
            }
5513
5514
0
            DoFieldTypeConversion(
5515
0
                m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5516
0
                m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5517
0
                m_bForceNullable, m_bUnsetDefault);
5518
5519
0
            if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5520
0
                oFieldDefn.GetWidth() != 0)
5521
0
            {
5522
0
                oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5523
0
            }
5524
5525
            /* The field may have been already created at layer creation */
5526
0
            {
5527
0
                const auto oIter = oMapPreExistingFields.find(
5528
0
                    formatName(oFieldDefn.GetNameRef()));
5529
0
                if (oIter != oMapPreExistingFields.end())
5530
0
                {
5531
0
                    anMap[iField] = oIter->second;
5532
0
                    continue;
5533
0
                }
5534
0
            }
5535
5536
0
            bool bHasRenamed = false;
5537
            /* In case the field name already exists in the target layer, */
5538
            /* build a unique field name */
5539
0
            if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=
5540
0
                oSetDstFieldNames.end())
5541
0
            {
5542
0
                const CPLString osTmpNameRaddixUC(
5543
0
                    formatName(oFieldDefn.GetNameRef()));
5544
0
                int nTry = 1;
5545
0
                const auto oIter =
5546
0
                    oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);
5547
0
                if (oIter != oMapFieldNameToLastSuffix.end())
5548
0
                    nTry = oIter->second;
5549
0
                CPLString osTmpNameUC = osTmpNameRaddixUC;
5550
0
                osTmpNameUC.reserve(osTmpNameUC.size() + 10);
5551
0
                while (true)
5552
0
                {
5553
0
                    ++nTry;
5554
0
                    char szTry[32];
5555
0
                    snprintf(szTry, sizeof(szTry), "%d", nTry);
5556
0
                    osTmpNameUC.replace(osTmpNameRaddixUC.size(),
5557
0
                                        std::string::npos, szTry);
5558
5559
                    /* Check that the proposed name doesn't exist either in the
5560
                     * already */
5561
                    /* created fields or in the source fields */
5562
0
                    if (oSetDstFieldNames.find(osTmpNameUC) ==
5563
0
                            oSetDstFieldNames.end() &&
5564
0
                        oSetSrcFieldNames.find(osTmpNameUC) ==
5565
0
                            oSetSrcFieldNames.end())
5566
0
                    {
5567
0
                        bHasRenamed = true;
5568
0
                        oFieldDefn.SetName(
5569
0
                            (CPLString(oFieldDefn.GetNameRef()) + szTry)
5570
0
                                .c_str());
5571
0
                        oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;
5572
0
                        break;
5573
0
                    }
5574
0
                }
5575
0
            }
5576
5577
            // Create field domain in output dataset if not already existing.
5578
0
            const std::string osDomainName(oFieldDefn.GetDomainName());
5579
0
            if (!osDomainName.empty())
5580
0
            {
5581
0
                if (m_poDstDS->TestCapability(ODsCAddFieldDomain) &&
5582
0
                    m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5583
0
                {
5584
0
                    const auto poSrcDomain =
5585
0
                        m_poSrcDS->GetFieldDomain(osDomainName);
5586
0
                    if (poSrcDomain)
5587
0
                    {
5588
0
                        std::string failureReason;
5589
0
                        if (!m_poDstDS->AddFieldDomain(
5590
0
                                std::unique_ptr<OGRFieldDomain>(
5591
0
                                    poSrcDomain->Clone()),
5592
0
                                failureReason))
5593
0
                        {
5594
0
                            oFieldDefn.SetDomainName(std::string());
5595
0
                            CPLDebug("OGR2OGR", "Cannot create domain %s: %s",
5596
0
                                     osDomainName.c_str(),
5597
0
                                     failureReason.c_str());
5598
0
                        }
5599
0
                    }
5600
0
                    else
5601
0
                    {
5602
0
                        CPLDebug("OGR2OGR",
5603
0
                                 "Cannot find domain %s in source dataset",
5604
0
                                 osDomainName.c_str());
5605
0
                    }
5606
0
                }
5607
0
                if (m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5608
0
                {
5609
0
                    oFieldDefn.SetDomainName(std::string());
5610
0
                }
5611
0
            }
5612
5613
0
            if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5614
0
            {
5615
                /* now that we've created a field, GetLayerDefn() won't return
5616
                 * NULL */
5617
0
                if (poDstFDefn == nullptr)
5618
0
                    poDstFDefn = poDstLayer->GetLayerDefn();
5619
5620
                /* Sanity check : if it fails, the driver is buggy */
5621
0
                if (poDstFDefn != nullptr &&
5622
0
                    poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5623
0
                {
5624
0
                    CPLError(CE_Warning, CPLE_AppDefined,
5625
0
                             "The output driver has claimed to have added the "
5626
0
                             "%s field, but it did not!",
5627
0
                             oFieldDefn.GetNameRef());
5628
0
                }
5629
0
                else
5630
0
                {
5631
0
                    if (poDstFDefn != nullptr)
5632
0
                    {
5633
0
                        const char *pszNewFieldName =
5634
0
                            poDstFDefn->GetFieldDefn(nDstFieldCount)
5635
0
                                ->GetNameRef();
5636
0
                        if (bHasRenamed)
5637
0
                        {
5638
0
                            CPLError(CE_Warning, CPLE_AppDefined,
5639
0
                                     "Field '%s' already exists. Renaming it "
5640
0
                                     "as '%s'",
5641
0
                                     poSrcFieldDefn->GetNameRef(),
5642
0
                                     pszNewFieldName);
5643
0
                        }
5644
0
                        oSetDstFieldNames.insert(formatName(pszNewFieldName));
5645
0
                    }
5646
5647
0
                    anMap[iField] = nDstFieldCount;
5648
0
                    nDstFieldCount++;
5649
0
                }
5650
0
            }
5651
0
            else if (!psOptions->bSkipFailures)
5652
0
                return nullptr;
5653
5654
0
            if (m_bResolveDomains && !osDomainName.empty())
5655
0
            {
5656
0
                const auto poSrcDomain =
5657
0
                    m_poSrcDS->GetFieldDomain(osDomainName);
5658
0
                if (poSrcDomain && poSrcDomain->GetDomainType() == OFDT_CODED)
5659
0
                {
5660
0
                    OGRFieldDefn oResolvedField(
5661
0
                        CPLSPrintf("%s_resolved", oFieldDefn.GetNameRef()),
5662
0
                        OFTString);
5663
0
                    if (poDstLayer->CreateField(&oResolvedField) == OGRERR_NONE)
5664
0
                    {
5665
0
                        TargetLayerInfo::ResolvedInfo resolvedInfo;
5666
0
                        resolvedInfo.nSrcField = iField;
5667
0
                        resolvedInfo.poDomain = poSrcDomain;
5668
0
                        oMapResolved[nDstFieldCount] = resolvedInfo;
5669
0
                        nDstFieldCount++;
5670
0
                    }
5671
0
                    else if (!psOptions->bSkipFailures)
5672
0
                        return nullptr;
5673
0
                }
5674
0
            }
5675
0
        }
5676
0
    }
5677
0
    else
5678
0
    {
5679
        /* For an existing layer, build the map by fetching the index in the
5680
         * destination */
5681
        /* layer for each source field */
5682
0
        if (poDstFDefn == nullptr)
5683
0
        {
5684
0
            CPLError(CE_Failure, CPLE_AppDefined, "poDstFDefn == NULL.");
5685
0
            return nullptr;
5686
0
        }
5687
5688
0
        for (int iField = 0; iField < nSrcFieldCount; iField++)
5689
0
        {
5690
0
            const OGRFieldDefn *poSrcFieldDefn =
5691
0
                poSrcFDefn->GetFieldDefn(iField);
5692
0
            const int iDstField = poDstLayer->FindFieldIndex(
5693
0
                poSrcFieldDefn->GetNameRef(), m_bExactFieldNameMatch);
5694
0
            if (iDstField >= 0)
5695
0
                anMap[iField] = iDstField;
5696
0
            else
5697
0
            {
5698
0
                if (m_bExactFieldNameMatch)
5699
0
                {
5700
0
                    const int iDstFieldCandidate = poDstLayer->FindFieldIndex(
5701
0
                        poSrcFieldDefn->GetNameRef(), false);
5702
0
                    if (iDstFieldCandidate >= 0)
5703
0
                    {
5704
0
                        CPLError(CE_Warning, CPLE_AppDefined,
5705
0
                                 "Source field '%s' could have been identified "
5706
0
                                 "with existing field '%s' of destination "
5707
0
                                 "layer '%s' if the -relaxedFieldNameMatch "
5708
0
                                 "option had been specified.",
5709
0
                                 poSrcFieldDefn->GetNameRef(),
5710
0
                                 poDstLayer->GetLayerDefn()
5711
0
                                     ->GetFieldDefn(iDstFieldCandidate)
5712
0
                                     ->GetNameRef(),
5713
0
                                 poDstLayer->GetName());
5714
0
                    }
5715
0
                }
5716
5717
0
                CPLDebug(
5718
0
                    "GDALVectorTranslate",
5719
0
                    "Skipping field '%s' not found in destination layer '%s'.",
5720
0
                    poSrcFieldDefn->GetNameRef(), poDstLayer->GetName());
5721
0
            }
5722
0
        }
5723
0
    }
5724
5725
0
    if (bOverwriteActuallyDone && !bAddOverwriteLCO &&
5726
0
        EQUAL(m_poDstDS->GetDriver()->GetDescription(), "PostgreSQL") &&
5727
0
        !psOptions->nLayerTransaction && psOptions->nGroupTransactions > 0 &&
5728
0
        CPLTestBool(CPLGetConfigOption("PG_COMMIT_WHEN_OVERWRITING", "YES")))
5729
0
    {
5730
0
        CPLDebug("GDALVectorTranslate",
5731
0
                 "Forcing transaction commit as table overwriting occurred");
5732
        // Commit when overwriting as this consumes a lot of PG resources
5733
        // and could result in """out of shared memory.
5734
        // You might need to increase max_locks_per_transaction."""" errors
5735
0
        if (m_poDstDS->CommitTransaction() == OGRERR_FAILURE ||
5736
0
            m_poDstDS->StartTransaction(psOptions->bForceTransaction) ==
5737
0
                OGRERR_FAILURE)
5738
0
        {
5739
0
            return nullptr;
5740
0
        }
5741
0
        nTotalEventsDone = 0;
5742
0
    }
5743
5744
0
    auto psInfo = std::make_unique<TargetLayerInfo>();
5745
0
    psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;
5746
0
    psInfo->m_nFeaturesRead = 0;
5747
0
    psInfo->m_bPerFeatureCT = false;
5748
0
    psInfo->m_poSrcLayer = poSrcLayer;
5749
0
    psInfo->m_poDstLayer = poDstLayer;
5750
0
    psInfo->m_aoReprojectionInfo.resize(
5751
0
        poDstLayer->GetLayerDefn()->GetGeomFieldCount());
5752
0
    psInfo->m_anMap = std::move(anMap);
5753
0
    psInfo->m_iSrcZField = iSrcZField;
5754
0
    psInfo->m_iSrcFIDField = iSrcFIDField;
5755
0
    if (anRequestedGeomFields.size() == 1)
5756
0
        psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];
5757
0
    else
5758
0
        psInfo->m_iRequestedSrcGeomField = -1;
5759
0
    psInfo->m_bPreserveFID = bPreserveFID;
5760
0
    psInfo->m_pszCTPipeline = m_pszCTPipeline;
5761
0
    psInfo->m_aosCTOptions = m_aosCTOptions;
5762
0
    psInfo->m_oMapResolved = std::move(oMapResolved);
5763
0
    for (const auto &kv : psInfo->m_oMapResolved)
5764
0
    {
5765
0
        const auto poDomain = kv.second.poDomain;
5766
0
        const auto poCodedDomain =
5767
0
            cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);
5768
0
        const auto enumeration = poCodedDomain->GetEnumeration();
5769
0
        std::map<std::string, std::string> oMapCodeValue;
5770
0
        for (int i = 0; enumeration[i].pszCode != nullptr; ++i)
5771
0
        {
5772
0
            oMapCodeValue[enumeration[i].pszCode] =
5773
0
                enumeration[i].pszValue ? enumeration[i].pszValue : "";
5774
0
        }
5775
0
        psInfo->m_oMapDomainToKV[poDomain] = std::move(oMapCodeValue);
5776
0
    }
5777
5778
    // Detect if we can directly pass the source feature to the CreateFeature()
5779
    // method of the target layer, without doing any copying of field content.
5780
0
    psInfo->m_bCanAvoidSetFrom = false;
5781
0
    if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)
5782
0
    {
5783
0
        psInfo->m_bCanAvoidSetFrom = true;
5784
0
        const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5785
0
        if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||
5786
0
            nSrcGeomFieldCount != nDstGeomFieldCount)
5787
0
        {
5788
0
            psInfo->m_bCanAvoidSetFrom = false;
5789
0
        }
5790
0
        else
5791
0
        {
5792
0
            for (int i = 0; i < nSrcFieldCount; ++i)
5793
0
            {
5794
0
                auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);
5795
0
                auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);
5796
0
                if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||
5797
0
                    psInfo->m_anMap[i] != i)
5798
0
                {
5799
0
                    psInfo->m_bCanAvoidSetFrom = false;
5800
0
                    break;
5801
0
                }
5802
0
            }
5803
0
            if (!psInfo->m_bCanAvoidSetFrom && nSrcGeomFieldCount > 1)
5804
0
            {
5805
0
                for (int i = 0; i < nSrcGeomFieldCount; ++i)
5806
0
                {
5807
0
                    auto poSrcGeomFieldDefn = poSrcFDefn->GetGeomFieldDefn(i);
5808
0
                    auto poDstGeomFieldDefn = poDstFDefn->GetGeomFieldDefn(i);
5809
0
                    if (!EQUAL(poSrcGeomFieldDefn->GetNameRef(),
5810
0
                               poDstGeomFieldDefn->GetNameRef()))
5811
0
                    {
5812
0
                        psInfo->m_bCanAvoidSetFrom = false;
5813
0
                        break;
5814
0
                    }
5815
0
                }
5816
0
            }
5817
0
        }
5818
0
    }
5819
5820
0
    psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()
5821
0
                                  ? nullptr
5822
0
                                  : psOptions->osSpatSRSDef.c_str();
5823
0
    psInfo->m_hSpatialFilter =
5824
0
        OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());
5825
0
    psInfo->m_pszGeomField =
5826
0
        psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;
5827
5828
0
    if (psOptions->nTZOffsetInSec != TZ_OFFSET_INVALID && poDstFDefn)
5829
0
    {
5830
0
        for (int i = 0; i < poDstFDefn->GetFieldCount(); ++i)
5831
0
        {
5832
0
            if (poDstFDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
5833
0
            {
5834
0
                psInfo->m_anDateTimeFieldIdx.push_back(i);
5835
0
            }
5836
0
        }
5837
0
    }
5838
5839
0
    psInfo->m_bSupportCurves = poDstLayer->TestCapability(OLCCurveGeometries);
5840
0
    psInfo->m_bSupportZ = poDstLayer->TestCapability(OLCZGeometries);
5841
0
    psInfo->m_bSupportM = poDstLayer->TestCapability(OLCMeasuredGeometries);
5842
5843
0
    psInfo->m_sArrowArrayStream = std::move(streamSrc);
5844
5845
0
    return psInfo;
5846
0
}
5847
5848
/************************************************************************/
5849
/*                              SetupCT()                               */
5850
/************************************************************************/
5851
5852
static bool
5853
SetupCT(TargetLayerInfo *psInfo, OGRLayer *poSrcLayer, bool bTransform,
5854
        bool bWrapDateline, const CPLString &osDateLineOffset,
5855
        const OGRSpatialReference *poUserSourceSRS, OGRFeature *poFeature,
5856
        const OGRSpatialReference *poOutputSRS,
5857
        OGRCoordinateTransformation *poGCPCoordTrans, bool bVerboseError)
5858
0
{
5859
0
    OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5860
0
    const int nDstGeomFieldCount =
5861
0
        poDstLayer->GetLayerDefn()->GetGeomFieldCount();
5862
0
    for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
5863
0
    {
5864
        /* --------------------------------------------------------------------
5865
         */
5866
        /*      Setup coordinate transformation if we need it. */
5867
        /* --------------------------------------------------------------------
5868
         */
5869
0
        const OGRSpatialReference *poSourceSRS = nullptr;
5870
0
        OGRCoordinateTransformation *poCT = nullptr;
5871
0
        char **papszTransformOptions = nullptr;
5872
5873
0
        int iSrcGeomField;
5874
0
        auto poDstGeomFieldDefn =
5875
0
            poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
5876
0
        if (psInfo->m_iRequestedSrcGeomField >= 0)
5877
0
        {
5878
0
            iSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5879
0
        }
5880
0
        else
5881
0
        {
5882
0
            iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
5883
0
                poDstGeomFieldDefn->GetNameRef());
5884
0
            if (iSrcGeomField < 0)
5885
0
            {
5886
0
                if (nDstGeomFieldCount == 1 &&
5887
0
                    poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
5888
0
                {
5889
0
                    iSrcGeomField = 0;
5890
0
                }
5891
0
                else
5892
0
                {
5893
0
                    continue;
5894
0
                }
5895
0
            }
5896
0
        }
5897
5898
0
        if (psInfo->m_nFeaturesRead == 0)
5899
0
        {
5900
0
            poSourceSRS = poUserSourceSRS;
5901
0
            if (poSourceSRS == nullptr)
5902
0
            {
5903
0
                if (iSrcGeomField > 0)
5904
0
                    poSourceSRS = poSrcLayer->GetLayerDefn()
5905
0
                                      ->GetGeomFieldDefn(iSrcGeomField)
5906
0
                                      ->GetSpatialRef();
5907
0
                else
5908
0
                    poSourceSRS = poSrcLayer->GetSpatialRef();
5909
0
            }
5910
0
        }
5911
0
        if (poSourceSRS == nullptr)
5912
0
        {
5913
0
            if (poFeature == nullptr)
5914
0
            {
5915
0
                if (bVerboseError)
5916
0
                {
5917
0
                    CPLError(CE_Failure, CPLE_AppDefined,
5918
0
                             "Non-null feature expected to set transformation");
5919
0
                }
5920
0
                return false;
5921
0
            }
5922
0
            OGRGeometry *poSrcGeometry =
5923
0
                poFeature->GetGeomFieldRef(iSrcGeomField);
5924
0
            if (poSrcGeometry)
5925
0
                poSourceSRS = poSrcGeometry->getSpatialReference();
5926
0
            psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);
5927
0
        }
5928
5929
0
        if (bTransform)
5930
0
        {
5931
0
            if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)
5932
0
            {
5933
0
                CPLError(CE_Failure, CPLE_AppDefined,
5934
0
                         "Can't transform coordinates, source layer has no\n"
5935
0
                         "coordinate system.  Use -s_srs to set one.");
5936
5937
0
                return false;
5938
0
            }
5939
5940
0
            if (psInfo->m_pszCTPipeline == nullptr)
5941
0
            {
5942
0
                CPLAssert(nullptr != poSourceSRS);
5943
0
                CPLAssert(nullptr != poOutputSRS);
5944
0
            }
5945
5946
0
            if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)
5947
0
            {
5948
0
                const auto &supportedSRSList =
5949
0
                    poSrcLayer->GetSupportedSRSList(iGeom);
5950
0
                if (!supportedSRSList.empty())
5951
0
                {
5952
0
                    const char *const apszOptions[] = {
5953
0
                        "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
5954
0
                    for (const auto &poSRS : supportedSRSList)
5955
0
                    {
5956
0
                        if (poSRS->IsSame(poOutputSRS, apszOptions))
5957
0
                        {
5958
0
                            OGRSpatialReference oSourceSRSBackup;
5959
0
                            if (poSourceSRS)
5960
0
                                oSourceSRSBackup = *poSourceSRS;
5961
0
                            if (poSrcLayer->SetActiveSRS(iGeom, poSRS.get()) ==
5962
0
                                OGRERR_NONE)
5963
0
                            {
5964
0
                                CPLDebug("ogr2ogr",
5965
0
                                         "Switching layer active SRS to %s",
5966
0
                                         poSRS->GetName());
5967
5968
0
                                if (psInfo->m_hSpatialFilter != nullptr &&
5969
0
                                    ((psInfo->m_iRequestedSrcGeomField < 0 &&
5970
0
                                      iGeom == 0) ||
5971
0
                                     (iGeom ==
5972
0
                                      psInfo->m_iRequestedSrcGeomField)))
5973
0
                                {
5974
0
                                    OGRSpatialReference oSpatSRS;
5975
0
                                    oSpatSRS.SetAxisMappingStrategy(
5976
0
                                        OAMS_TRADITIONAL_GIS_ORDER);
5977
0
                                    if (psInfo->m_pszSpatSRSDef)
5978
0
                                        oSpatSRS.SetFromUserInput(
5979
0
                                            psInfo->m_pszSpatSRSDef);
5980
0
                                    ApplySpatialFilter(
5981
0
                                        poSrcLayer,
5982
0
                                        OGRGeometry::FromHandle(
5983
0
                                            psInfo->m_hSpatialFilter),
5984
0
                                        !oSpatSRS.IsEmpty() ? &oSpatSRS
5985
0
                                        : !oSourceSRSBackup.IsEmpty()
5986
0
                                            ? &oSourceSRSBackup
5987
0
                                            : nullptr,
5988
0
                                        psInfo->m_pszGeomField, poOutputSRS);
5989
0
                                }
5990
5991
0
                                bTransform = false;
5992
0
                            }
5993
0
                            break;
5994
0
                        }
5995
0
                    }
5996
0
                }
5997
0
            }
5998
5999
0
            if (!bTransform)
6000
0
            {
6001
                // do nothing
6002
0
            }
6003
0
            else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&
6004
0
                     psInfo->m_aoReprojectionInfo[iGeom]
6005
0
                             .m_poCT->GetSourceCS() == poSourceSRS)
6006
0
            {
6007
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6008
0
            }
6009
0
            else
6010
0
            {
6011
0
                OGRCoordinateTransformationOptions options;
6012
0
                if (psInfo->m_pszCTPipeline)
6013
0
                {
6014
0
                    options.SetCoordinateOperation(psInfo->m_pszCTPipeline,
6015
0
                                                   false);
6016
0
                }
6017
6018
0
                bool bWarnAboutDifferentCoordinateOperations =
6019
0
                    poGCPCoordTrans == nullptr &&
6020
0
                    !(poSourceSRS && poSourceSRS->IsGeocentric());
6021
6022
0
                for (const auto &[key, value] :
6023
0
                     cpl::IterateNameValue(psInfo->m_aosCTOptions))
6024
0
                {
6025
0
                    if (EQUAL(key, "ALLOW_BALLPARK"))
6026
0
                    {
6027
0
                        options.SetBallparkAllowed(CPLTestBool(value));
6028
0
                    }
6029
0
                    else if (EQUAL(key, "ONLY_BEST"))
6030
0
                    {
6031
0
                        options.SetOnlyBest(CPLTestBool(value));
6032
0
                    }
6033
0
                    else if (EQUAL(key, "WARN_ABOUT_DIFFERENT_COORD_OP"))
6034
0
                    {
6035
0
                        if (!CPLTestBool(value))
6036
0
                            bWarnAboutDifferentCoordinateOperations = false;
6037
0
                    }
6038
0
                    else
6039
0
                    {
6040
0
                        CPLError(CE_Warning, CPLE_AppDefined,
6041
0
                                 "Unknown coordinate transform option: %s",
6042
0
                                 key);
6043
0
                    }
6044
0
                }
6045
6046
0
                auto poNewCT = std::unique_ptr<OGRCoordinateTransformation>(
6047
0
                    OGRCreateCoordinateTransformation(poSourceSRS, poOutputSRS,
6048
0
                                                      options));
6049
0
                if (poNewCT == nullptr)
6050
0
                {
6051
0
                    char *pszWKT = nullptr;
6052
6053
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6054
0
                             "Failed to create coordinate transformation "
6055
0
                             "between the\n"
6056
0
                             "following coordinate systems.  This may be "
6057
0
                             "because they\n"
6058
0
                             "are not transformable.");
6059
6060
0
                    if (poSourceSRS)
6061
0
                    {
6062
0
                        poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
6063
0
                        CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
6064
0
                                 pszWKT);
6065
0
                        CPLFree(pszWKT);
6066
0
                    }
6067
6068
0
                    if (poOutputSRS)
6069
0
                    {
6070
0
                        poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
6071
0
                        CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
6072
0
                                 pszWKT);
6073
0
                        CPLFree(pszWKT);
6074
0
                    }
6075
6076
0
                    return false;
6077
0
                }
6078
0
                if (poGCPCoordTrans)
6079
0
                {
6080
0
                    poNewCT = std::make_unique<CompositeCT>(poGCPCoordTrans,
6081
0
                                                            std::move(poNewCT));
6082
0
                }
6083
0
                else
6084
0
                {
6085
0
                    psInfo->m_aoReprojectionInfo[iGeom]
6086
0
                        .m_bWarnAboutDifferentCoordinateOperations =
6087
0
                        bWarnAboutDifferentCoordinateOperations;
6088
0
                }
6089
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT = std::move(poNewCT);
6090
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6091
0
                psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =
6092
0
                    !(poGCPCoordTrans == nullptr && poSourceSRS &&
6093
0
                      poSourceSRS->IsGeographic() && poOutputSRS &&
6094
0
                      poOutputSRS->IsGeographic());
6095
0
            }
6096
0
        }
6097
0
        else
6098
0
        {
6099
0
            const char *const apszOptions[] = {
6100
0
                "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
6101
0
                "CRITERION=EQUIVALENT", nullptr};
6102
0
            auto poDstGeomFieldDefnSpatialRef =
6103
0
                poDstGeomFieldDefn->GetSpatialRef();
6104
0
            if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&
6105
0
                poSourceSRS->GetDataAxisToSRSAxisMapping() !=
6106
0
                    poDstGeomFieldDefnSpatialRef
6107
0
                        ->GetDataAxisToSRSAxisMapping() &&
6108
0
                poSourceSRS->IsSame(poDstGeomFieldDefnSpatialRef, apszOptions))
6109
0
            {
6110
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT =
6111
0
                    std::make_unique<CompositeCT>(
6112
0
                        std::make_unique<AxisMappingCoordinateTransformation>(
6113
0
                            poSourceSRS->GetDataAxisToSRSAxisMapping(),
6114
0
                            poDstGeomFieldDefnSpatialRef
6115
0
                                ->GetDataAxisToSRSAxisMapping()),
6116
0
                        poGCPCoordTrans);
6117
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6118
0
            }
6119
0
            else if (poGCPCoordTrans)
6120
0
            {
6121
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT =
6122
0
                    std::make_unique<CompositeCT>(poGCPCoordTrans, nullptr);
6123
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6124
0
            }
6125
0
        }
6126
6127
0
        if (bWrapDateline)
6128
0
        {
6129
0
            if (bTransform && poCT != nullptr && poOutputSRS != nullptr &&
6130
0
                poOutputSRS->IsGeographic() &&
6131
0
                !poOutputSRS->IsDerivedGeographic())
6132
0
            {
6133
0
                papszTransformOptions =
6134
0
                    CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
6135
0
                if (!osDateLineOffset.empty())
6136
0
                {
6137
0
                    CPLString soOffset("DATELINEOFFSET=");
6138
0
                    soOffset += osDateLineOffset;
6139
0
                    papszTransformOptions =
6140
0
                        CSLAddString(papszTransformOptions, soOffset);
6141
0
                }
6142
0
            }
6143
0
            else if (poSourceSRS != nullptr && poSourceSRS->IsGeographic() &&
6144
0
                     !poSourceSRS->IsDerivedGeographic())
6145
0
            {
6146
0
                papszTransformOptions =
6147
0
                    CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
6148
0
                if (!osDateLineOffset.empty())
6149
0
                {
6150
0
                    CPLString soOffset("DATELINEOFFSET=");
6151
0
                    soOffset += osDateLineOffset;
6152
0
                    papszTransformOptions =
6153
0
                        CSLAddString(papszTransformOptions, soOffset);
6154
0
                }
6155
0
            }
6156
0
            else
6157
0
            {
6158
0
                CPLErrorOnce(CE_Failure, CPLE_IllegalArg,
6159
0
                             "-wrapdateline option only works when "
6160
0
                             "reprojecting to a geographic SRS");
6161
0
            }
6162
6163
0
            psInfo->m_aoReprojectionInfo[iGeom].m_aosTransformOptions.Assign(
6164
0
                papszTransformOptions);
6165
0
        }
6166
0
    }
6167
0
    return true;
6168
0
}
6169
6170
/************************************************************************/
6171
/*                  LayerTranslator::TranslateArrow()                   */
6172
/************************************************************************/
6173
6174
bool LayerTranslator::TranslateArrow(
6175
    TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,
6176
    GIntBig *pnReadFeatureCount, GDALProgressFunc pfnProgress,
6177
    void *pProgressArg, const GDALVectorTranslateOptions *psOptions)
6178
0
{
6179
0
    struct ArrowSchema schema;
6180
0
    CPLStringList aosOptionsWriteArrowBatch;
6181
0
    if (psInfo->m_bPreserveFID)
6182
0
    {
6183
0
        aosOptionsWriteArrowBatch.SetNameValue(
6184
0
            "FID", psInfo->m_poSrcLayer->GetFIDColumn());
6185
0
        aosOptionsWriteArrowBatch.SetNameValue("IF_FID_NOT_PRESERVED",
6186
0
                                               "WARNING");
6187
0
    }
6188
6189
0
    if (psInfo->m_sArrowArrayStream.get_schema(&schema) != 0)
6190
0
    {
6191
0
        CPLError(CE_Failure, CPLE_AppDefined, "stream.get_schema() failed");
6192
0
        return false;
6193
0
    }
6194
6195
0
    int iArrowGeomFieldIndex = -1;
6196
0
    if (m_bTransform)
6197
0
    {
6198
0
        iArrowGeomFieldIndex = GetArrowGeomFieldIndex(
6199
0
            &schema, psInfo->m_poSrcLayer->GetGeometryColumn());
6200
0
        if (!SetupCT(psInfo, psInfo->m_poSrcLayer, m_bTransform,
6201
0
                     m_bWrapDateline, m_osDateLineOffset, m_poUserSourceSRS,
6202
0
                     nullptr, m_poOutputSRS, m_poGCPCoordTrans, false))
6203
0
        {
6204
0
            return false;
6205
0
        }
6206
0
    }
6207
6208
0
    bool bRet = true;
6209
6210
0
    GIntBig nCount = 0;
6211
0
    bool bGoOn = true;
6212
0
    std::vector<GByte> abyModifiedWKB;
6213
0
    const int nNumReprojectionThreads = []()
6214
0
    {
6215
0
        const char *pszNumThreads = nullptr;
6216
0
        int nVal =
6217
0
            GDALGetNumThreads(GDAL_DEFAULT_MAX_THREAD_COUNT,
6218
0
                              /* bDefaultToAllCPUs = */ false, &pszNumThreads);
6219
0
        if (!pszNumThreads)
6220
0
            nVal = std::max(1, CPLGetNumCPUs() / 2);
6221
0
        return nVal;
6222
0
    }();
6223
6224
    // Somewhat arbitrary threshold (config option only/mostly for autotest purposes)
6225
0
    const int MIN_FEATURES_FOR_THREADED_REPROJ = atoi(CPLGetConfigOption(
6226
0
        "OGR2OGR_MIN_FEATURES_FOR_THREADED_REPROJ", "10000"));
6227
6228
0
    while (bGoOn)
6229
0
    {
6230
0
        struct ArrowArray array;
6231
        // Acquire source batch
6232
0
        if (psInfo->m_sArrowArrayStream.get_next(&array) != 0)
6233
0
        {
6234
0
            CPLError(CE_Failure, CPLE_AppDefined, "stream.get_next() failed");
6235
0
            bRet = false;
6236
0
            break;
6237
0
        }
6238
6239
0
        if (array.release == nullptr)
6240
0
        {
6241
            // End of stream
6242
0
            break;
6243
0
        }
6244
6245
        // Limit number of features in batch if needed
6246
0
        if (psOptions->nLimit >= 0 &&
6247
0
            nCount + array.length >= psOptions->nLimit)
6248
0
        {
6249
0
            const auto nAdjustedLength = psOptions->nLimit - nCount;
6250
0
            for (int i = 0; i < array.n_children; ++i)
6251
0
            {
6252
0
                if (array.children[i]->length == array.length)
6253
0
                    array.children[i]->length = nAdjustedLength;
6254
0
            }
6255
0
            array.length = nAdjustedLength;
6256
0
            nCount = psOptions->nLimit;
6257
0
            bGoOn = false;
6258
0
        }
6259
0
        else
6260
0
        {
6261
0
            nCount += array.length;
6262
0
        }
6263
6264
0
        const auto nArrayLength = array.length;
6265
6266
        // Coordinate reprojection
6267
0
        if (m_bTransform)
6268
0
        {
6269
0
            struct GeomArrayReleaser
6270
0
            {
6271
0
                const void *origin_buffers_2 = nullptr;
6272
0
                void (*origin_release)(struct ArrowArray *) = nullptr;
6273
0
                void *origin_private_data = nullptr;
6274
6275
0
                static void init(struct ArrowArray *psGeomArray)
6276
0
                {
6277
0
                    GeomArrayReleaser *releaser = new GeomArrayReleaser();
6278
0
                    CPLAssert(psGeomArray->n_buffers >= 3);
6279
0
                    releaser->origin_buffers_2 = psGeomArray->buffers[2];
6280
0
                    releaser->origin_private_data = psGeomArray->private_data;
6281
0
                    releaser->origin_release = psGeomArray->release;
6282
0
                    psGeomArray->release = GeomArrayReleaser::release;
6283
0
                    psGeomArray->private_data = releaser;
6284
0
                }
6285
6286
0
                static void release(struct ArrowArray *psGeomArray)
6287
0
                {
6288
0
                    GeomArrayReleaser *releaser =
6289
0
                        static_cast<GeomArrayReleaser *>(
6290
0
                            psGeomArray->private_data);
6291
0
                    psGeomArray->buffers[2] = releaser->origin_buffers_2;
6292
0
                    psGeomArray->private_data = releaser->origin_private_data;
6293
0
                    psGeomArray->release = releaser->origin_release;
6294
0
                    if (psGeomArray->release)
6295
0
                        psGeomArray->release(psGeomArray);
6296
0
                    delete releaser;
6297
0
                }
6298
0
            };
6299
6300
0
            auto *psGeomArray = array.children[iArrowGeomFieldIndex];
6301
0
            GeomArrayReleaser::init(psGeomArray);
6302
6303
0
            GByte *pabyWKB = static_cast<GByte *>(
6304
0
                const_cast<void *>(psGeomArray->buffers[2]));
6305
0
            const uint32_t *panOffsets =
6306
0
                static_cast<const uint32_t *>(psGeomArray->buffers[1]);
6307
0
            auto poCT = psInfo->m_aoReprojectionInfo[0].m_poCT.get();
6308
6309
0
            try
6310
0
            {
6311
0
                abyModifiedWKB.resize(panOffsets[nArrayLength]);
6312
0
            }
6313
0
            catch (const std::exception &)
6314
0
            {
6315
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6316
0
                bRet = false;
6317
0
                if (array.release)
6318
0
                    array.release(&array);
6319
0
                break;
6320
0
            }
6321
0
            memcpy(abyModifiedWKB.data(), pabyWKB, panOffsets[nArrayLength]);
6322
0
            psGeomArray->buffers[2] = abyModifiedWKB.data();
6323
6324
            // Collect left-most, right-most, top-most, bottom-most coordinates.
6325
0
            if (psInfo->m_aoReprojectionInfo[0]
6326
0
                    .m_bWarnAboutDifferentCoordinateOperations)
6327
0
            {
6328
0
                struct OGRWKBPointVisitor final : public OGRWKBPointUpdater
6329
0
                {
6330
0
                    TargetLayerInfo::ReprojectionInfo &m_info;
6331
6332
0
                    explicit OGRWKBPointVisitor(
6333
0
                        TargetLayerInfo::ReprojectionInfo &info)
6334
0
                        : m_info(info)
6335
0
                    {
6336
0
                    }
6337
6338
0
                    bool update(bool bNeedSwap, void *x, void *y, void *z,
6339
0
                                void * /* m */) override
6340
0
                    {
6341
0
                        double dfX, dfY, dfZ;
6342
0
                        memcpy(&dfX, x, sizeof(double));
6343
0
                        memcpy(&dfY, y, sizeof(double));
6344
0
                        if (bNeedSwap)
6345
0
                        {
6346
0
                            CPL_SWAP64PTR(&dfX);
6347
0
                            CPL_SWAP64PTR(&dfY);
6348
0
                        }
6349
0
                        if (z)
6350
0
                        {
6351
0
                            memcpy(&dfZ, z, sizeof(double));
6352
0
                            if (bNeedSwap)
6353
0
                            {
6354
0
                                CPL_SWAP64PTR(&dfZ);
6355
0
                            }
6356
0
                        }
6357
0
                        else
6358
0
                            dfZ = 0;
6359
0
                        m_info.UpdateExtremePoints(dfX, dfY, dfZ);
6360
0
                        return true;
6361
0
                    }
6362
0
                };
6363
6364
0
                OGRWKBPointVisitor oVisitor(psInfo->m_aoReprojectionInfo[0]);
6365
0
                const GByte *pabyValidity =
6366
0
                    static_cast<const GByte *>(psGeomArray->buffers[0]);
6367
6368
0
                for (size_t i = 0; i < static_cast<size_t>(nArrayLength); ++i)
6369
0
                {
6370
0
                    const size_t iShifted =
6371
0
                        static_cast<size_t>(i + psGeomArray->offset);
6372
0
                    if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6373
0
                                          (1 << (iShifted % 8))) != 0)
6374
0
                    {
6375
0
                        const auto nWKBSize =
6376
0
                            panOffsets[iShifted + 1] - panOffsets[iShifted];
6377
0
                        OGRWKBUpdatePoints(abyModifiedWKB.data() +
6378
0
                                               panOffsets[iShifted],
6379
0
                                           nWKBSize, oVisitor);
6380
0
                    }
6381
0
                }
6382
0
            }
6383
6384
0
            std::atomic<bool> atomicRet{true};
6385
0
            const auto oReprojectionLambda =
6386
0
                [psGeomArray, nArrayLength, panOffsets, &atomicRet,
6387
0
                 &abyModifiedWKB, &poCT](int iThread, int nThreads)
6388
0
            {
6389
0
                OGRWKBTransformCache oCache;
6390
0
                OGREnvelope3D sEnv3D;
6391
0
                auto poThisCT =
6392
0
                    std::unique_ptr<OGRCoordinateTransformation>(poCT->Clone());
6393
0
                if (!poThisCT)
6394
0
                {
6395
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6396
0
                             "Cannot clone OGRCoordinateTransformation");
6397
0
                    atomicRet = false;
6398
0
                    return;
6399
0
                }
6400
6401
0
                const GByte *pabyValidity =
6402
0
                    static_cast<const GByte *>(psGeomArray->buffers[0]);
6403
0
                const size_t iStart =
6404
0
                    static_cast<size_t>(iThread * nArrayLength / nThreads);
6405
0
                const size_t iMax = static_cast<size_t>(
6406
0
                    (iThread + 1) * nArrayLength / nThreads);
6407
0
                for (size_t i = iStart; i < iMax; ++i)
6408
0
                {
6409
0
                    const size_t iShifted =
6410
0
                        static_cast<size_t>(i + psGeomArray->offset);
6411
0
                    if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6412
0
                                          (1 << (iShifted % 8))) != 0)
6413
0
                    {
6414
0
                        const auto nWKBSize =
6415
0
                            panOffsets[iShifted + 1] - panOffsets[iShifted];
6416
0
                        if (!OGRWKBTransform(
6417
0
                                abyModifiedWKB.data() + panOffsets[iShifted],
6418
0
                                nWKBSize, poThisCT.get(), oCache, sEnv3D))
6419
0
                        {
6420
0
                            CPLError(CE_Failure, CPLE_AppDefined,
6421
0
                                     "Reprojection failed");
6422
0
                            atomicRet = false;
6423
0
                            break;
6424
0
                        }
6425
0
                    }
6426
0
                }
6427
0
            };
6428
6429
0
            if (nArrayLength >= MIN_FEATURES_FOR_THREADED_REPROJ &&
6430
0
                nNumReprojectionThreads >= 2)
6431
0
            {
6432
0
                std::vector<std::future<void>> oTasks;
6433
0
                for (int iThread = 0; iThread < nNumReprojectionThreads;
6434
0
                     ++iThread)
6435
0
                {
6436
0
                    oTasks.emplace_back(std::async(std::launch::async,
6437
0
                                                   oReprojectionLambda, iThread,
6438
0
                                                   nNumReprojectionThreads));
6439
0
                }
6440
0
                for (auto &oTask : oTasks)
6441
0
                {
6442
0
                    oTask.get();
6443
0
                }
6444
0
            }
6445
0
            else
6446
0
            {
6447
0
                oReprojectionLambda(0, 1);
6448
0
            }
6449
6450
0
            bRet = atomicRet;
6451
0
            if (!bRet)
6452
0
            {
6453
0
                if (array.release)
6454
0
                    array.release(&array);
6455
0
                break;
6456
0
            }
6457
0
        }
6458
6459
        // Write batch to target layer
6460
0
        const bool bWriteOK = psInfo->m_poDstLayer->WriteArrowBatch(
6461
0
            &schema, &array, aosOptionsWriteArrowBatch.List());
6462
6463
0
        if (array.release)
6464
0
            array.release(&array);
6465
6466
0
        if (!bWriteOK)
6467
0
        {
6468
0
            CPLError(CE_Failure, CPLE_AppDefined, "WriteArrowBatch() failed");
6469
0
            bRet = false;
6470
0
            break;
6471
0
        }
6472
6473
        /* Report progress */
6474
0
        if (pfnProgress)
6475
0
        {
6476
0
            if (!pfnProgress(nCountLayerFeatures
6477
0
                                 ? nCount * 1.0 / nCountLayerFeatures
6478
0
                                 : 1.0,
6479
0
                             "", pProgressArg))
6480
0
            {
6481
0
                bGoOn = false;
6482
0
                bRet = false;
6483
0
            }
6484
0
        }
6485
6486
0
        if (pnReadFeatureCount)
6487
0
            *pnReadFeatureCount = nCount;
6488
0
    }
6489
6490
0
    schema.release(&schema);
6491
6492
0
    return bRet;
6493
0
}
6494
6495
/************************************************************************/
6496
/*                     LayerTranslator::Translate()                     */
6497
/************************************************************************/
6498
6499
bool LayerTranslator::Translate(
6500
    std::unique_ptr<OGRFeature> poFeatureIn, TargetLayerInfo *psInfo,
6501
    GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
6502
    GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress, void *pProgressArg,
6503
    const GDALVectorTranslateOptions *psOptions)
6504
0
{
6505
0
    if (psInfo->m_bUseWriteArrowBatch)
6506
0
    {
6507
0
        return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,
6508
0
                              pfnProgress, pProgressArg, psOptions);
6509
0
    }
6510
6511
0
    const int eGType = m_eGType;
6512
0
    const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
6513
6514
0
    OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;
6515
0
    OGRLayer *poDstLayer = psInfo->m_poDstLayer;
6516
0
    const int *const panMap = psInfo->m_anMap.data();
6517
0
    const int iSrcZField = psInfo->m_iSrcZField;
6518
0
    const bool bPreserveFID = psInfo->m_bPreserveFID;
6519
0
    const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
6520
0
    const auto poDstFDefn = poDstLayer->GetLayerDefn();
6521
0
    const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
6522
0
    const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
6523
0
    const bool bExplodeCollections =
6524
0
        m_bExplodeCollections && nDstGeomFieldCount <= 1;
6525
0
    const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;
6526
6527
0
    if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
6528
0
    {
6529
0
        if (nSrcGeomFieldCount == 1)
6530
0
        {
6531
0
            poOutputSRS = poSrcLayer->GetSpatialRef();
6532
0
        }
6533
0
        else if (iRequestedSrcGeomField > 0)
6534
0
        {
6535
0
            poOutputSRS = poSrcLayer->GetLayerDefn()
6536
0
                              ->GetGeomFieldDefn(iRequestedSrcGeomField)
6537
0
                              ->GetSpatialRef();
6538
0
        }
6539
0
    }
6540
6541
    /* -------------------------------------------------------------------- */
6542
    /*      Transfer features.                                              */
6543
    /* -------------------------------------------------------------------- */
6544
0
    if (psOptions->nGroupTransactions)
6545
0
    {
6546
0
        if (psOptions->nLayerTransaction)
6547
0
        {
6548
0
            if (poDstLayer->StartTransaction() == OGRERR_FAILURE)
6549
0
            {
6550
0
                return false;
6551
0
            }
6552
0
        }
6553
0
    }
6554
6555
0
    std::unique_ptr<OGRFeature> poFeature;
6556
0
    auto poDstFeature = std::make_unique<OGRFeature>(poDstFDefn);
6557
0
    int nFeaturesInTransaction = 0;
6558
0
    GIntBig nCount = 0; /* written + failed */
6559
0
    GIntBig nFeaturesWritten = 0;
6560
0
    bool bRunSetPrecisionEvaluated = false;
6561
0
    bool bRunSetPrecision = false;
6562
6563
0
    bool bRet = true;
6564
0
    CPLErrorReset();
6565
6566
0
    bool bSetupCTOK = false;
6567
0
    if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&
6568
0
        !psInfo->m_bPerFeatureCT)
6569
0
    {
6570
0
        bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6571
0
                             m_osDateLineOffset, m_poUserSourceSRS, nullptr,
6572
0
                             poOutputSRS, m_poGCPCoordTrans, false);
6573
0
    }
6574
6575
0
    const bool bSingleIteration = poFeatureIn != nullptr;
6576
0
    while (true)
6577
0
    {
6578
0
        if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)
6579
0
        {
6580
0
            break;
6581
0
        }
6582
6583
0
        if (poFeatureIn != nullptr)
6584
0
            poFeature = std::move(poFeatureIn);
6585
0
        else if (psOptions->nFIDToFetch != OGRNullFID)
6586
0
            poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));
6587
0
        else
6588
0
            poFeature.reset(poSrcLayer->GetNextFeature());
6589
6590
0
        if (poFeature == nullptr)
6591
0
        {
6592
0
            if (CPLGetLastErrorType() == CE_Failure)
6593
0
            {
6594
0
                bRet = false;
6595
0
            }
6596
0
            break;
6597
0
        }
6598
6599
0
        if (!bSetupCTOK &&
6600
0
            (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))
6601
0
        {
6602
0
            if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6603
0
                         m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),
6604
0
                         poOutputSRS, m_poGCPCoordTrans, true))
6605
0
            {
6606
0
                return false;
6607
0
            }
6608
0
        }
6609
6610
0
        psInfo->m_nFeaturesRead++;
6611
6612
0
        int nIters = 1;
6613
0
        std::unique_ptr<OGRGeometryCollection> poCollToExplode;
6614
0
        int iGeomCollToExplode = -1;
6615
0
        OGRGeometry *poSrcGeometry = nullptr;
6616
0
        if (bExplodeCollections)
6617
0
        {
6618
0
            if (iRequestedSrcGeomField >= 0)
6619
0
                poSrcGeometry =
6620
0
                    poFeature->GetGeomFieldRef(iRequestedSrcGeomField);
6621
0
            else
6622
0
                poSrcGeometry = poFeature->GetGeometryRef();
6623
0
            if (poSrcGeometry &&
6624
0
                OGR_GT_IsSubClassOf(poSrcGeometry->getGeometryType(),
6625
0
                                    wkbGeometryCollection))
6626
0
            {
6627
0
                const int nParts =
6628
0
                    poSrcGeometry->toGeometryCollection()->getNumGeometries();
6629
0
                if (nParts > 0 ||
6630
0
                    wkbFlatten(poSrcGeometry->getGeometryType()) !=
6631
0
                        wkbGeometryCollection)
6632
0
                {
6633
0
                    iGeomCollToExplode = iRequestedSrcGeomField >= 0
6634
0
                                             ? iRequestedSrcGeomField
6635
0
                                             : 0;
6636
0
                    poCollToExplode.reset(
6637
0
                        poFeature->StealGeometry(iGeomCollToExplode)
6638
0
                            ->toGeometryCollection());
6639
0
                    nIters = std::max(1, nParts);
6640
0
                }
6641
0
            }
6642
0
        }
6643
6644
0
        const GIntBig nSrcFID = poFeature->GetFID();
6645
0
        GIntBig nDesiredFID = OGRNullFID;
6646
0
        if (bPreserveFID)
6647
0
            nDesiredFID = nSrcFID;
6648
0
        else if (psInfo->m_iSrcFIDField >= 0 &&
6649
0
                 poFeature->IsFieldSetAndNotNull(psInfo->m_iSrcFIDField))
6650
0
            nDesiredFID =
6651
0
                poFeature->GetFieldAsInteger64(psInfo->m_iSrcFIDField);
6652
6653
0
        for (int iPart = 0; iPart < nIters; iPart++)
6654
0
        {
6655
0
            if (psOptions->nLayerTransaction &&
6656
0
                ++nFeaturesInTransaction == psOptions->nGroupTransactions)
6657
0
            {
6658
0
                if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||
6659
0
                    poDstLayer->StartTransaction() == OGRERR_FAILURE)
6660
0
                {
6661
0
                    return false;
6662
0
                }
6663
0
                nFeaturesInTransaction = 0;
6664
0
            }
6665
0
            else if (!psOptions->nLayerTransaction &&
6666
0
                     psOptions->nGroupTransactions > 0 &&
6667
0
                     ++nTotalEventsDone >= psOptions->nGroupTransactions)
6668
0
            {
6669
0
                if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||
6670
0
                    m_poODS->StartTransaction(psOptions->bForceTransaction) ==
6671
0
                        OGRERR_FAILURE)
6672
0
                {
6673
0
                    return false;
6674
0
                }
6675
0
                nTotalEventsDone = 0;
6676
0
            }
6677
6678
0
            CPLErrorReset();
6679
0
            if (psInfo->m_bCanAvoidSetFrom)
6680
0
            {
6681
0
                poDstFeature = std::move(poFeature);
6682
                // From now on, poFeature is null !
6683
0
                poDstFeature->SetFDefnUnsafe(poDstFDefn);
6684
0
                poDstFeature->SetFID(nDesiredFID);
6685
0
            }
6686
0
            else
6687
0
            {
6688
                /* Optimization to avoid duplicating the source geometry in the
6689
                 */
6690
                /* target feature : we steal it from the source feature for
6691
                 * now... */
6692
0
                std::unique_ptr<OGRGeometry> poStolenGeometry;
6693
0
                if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&
6694
0
                    (nDstGeomFieldCount == 1 ||
6695
0
                     (nDstGeomFieldCount == 0 && m_poClipSrcOri)))
6696
0
                {
6697
0
                    poStolenGeometry.reset(poFeature->StealGeometry());
6698
0
                }
6699
0
                else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)
6700
0
                {
6701
0
                    poStolenGeometry.reset(
6702
0
                        poFeature->StealGeometry(iRequestedSrcGeomField));
6703
0
                }
6704
6705
0
                if (nDstGeomFieldCount == 0 && poStolenGeometry &&
6706
0
                    m_poClipSrcOri)
6707
0
                {
6708
0
                    if (poStolenGeometry->IsEmpty())
6709
0
                        goto end_loop;
6710
6711
0
                    const auto clipGeomDesc =
6712
0
                        GetSrcClipGeom(poStolenGeometry->getSpatialReference());
6713
6714
0
                    if (clipGeomDesc.poGeom && clipGeomDesc.poEnv)
6715
0
                    {
6716
0
                        OGREnvelope oEnv;
6717
0
                        poStolenGeometry->getEnvelope(&oEnv);
6718
0
                        if (!clipGeomDesc.poEnv->Contains(oEnv) &&
6719
0
                            !(clipGeomDesc.poEnv->Intersects(oEnv) &&
6720
0
                              clipGeomDesc.poGeom->Intersects(
6721
0
                                  poStolenGeometry.get())))
6722
0
                        {
6723
0
                            goto end_loop;
6724
0
                        }
6725
0
                    }
6726
0
                }
6727
6728
0
                poDstFeature->Reset();
6729
6730
0
                if (poDstFeature->SetFrom(
6731
0
                        poFeature.get(), panMap, /* bForgiving = */ TRUE,
6732
0
                        /* bUseISO8601ForDateTimeAsString = */ true) !=
6733
0
                    OGRERR_NONE)
6734
0
                {
6735
0
                    if (psOptions->nGroupTransactions)
6736
0
                    {
6737
0
                        if (psOptions->nLayerTransaction)
6738
0
                        {
6739
0
                            if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6740
0
                            {
6741
0
                                return false;
6742
0
                            }
6743
0
                        }
6744
0
                    }
6745
6746
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6747
0
                             "Unable to translate feature " CPL_FRMT_GIB
6748
0
                             " from layer %s.",
6749
0
                             nSrcFID, poSrcLayer->GetName());
6750
6751
0
                    return false;
6752
0
                }
6753
6754
                /* ... and now we can attach the stolen geometry */
6755
0
                if (poStolenGeometry)
6756
0
                {
6757
0
                    poDstFeature->SetGeometryDirectly(
6758
0
                        poStolenGeometry.release());
6759
0
                }
6760
6761
0
                if (!psInfo->m_oMapResolved.empty())
6762
0
                {
6763
0
                    for (const auto &kv : psInfo->m_oMapResolved)
6764
0
                    {
6765
0
                        const int nDstField = kv.first;
6766
0
                        const int nSrcField = kv.second.nSrcField;
6767
0
                        if (poFeature->IsFieldSetAndNotNull(nSrcField))
6768
0
                        {
6769
0
                            const auto poDomain = kv.second.poDomain;
6770
0
                            const auto &oMapKV =
6771
0
                                psInfo->m_oMapDomainToKV[poDomain];
6772
0
                            const auto iter = oMapKV.find(
6773
0
                                poFeature->GetFieldAsString(nSrcField));
6774
0
                            if (iter != oMapKV.end())
6775
0
                            {
6776
0
                                poDstFeature->SetField(nDstField,
6777
0
                                                       iter->second.c_str());
6778
0
                            }
6779
0
                        }
6780
0
                    }
6781
0
                }
6782
6783
0
                if (nDesiredFID != OGRNullFID)
6784
0
                    poDstFeature->SetFID(nDesiredFID);
6785
0
            }
6786
6787
0
            if (psOptions->bEmptyStrAsNull)
6788
0
            {
6789
0
                for (int i = 0; i < poDstFeature->GetFieldCount(); i++)
6790
0
                {
6791
0
                    if (!poDstFeature->IsFieldSetAndNotNull(i))
6792
0
                        continue;
6793
0
                    auto fieldDef = poDstFeature->GetFieldDefnRef(i);
6794
0
                    if (fieldDef->GetType() != OGRFieldType::OFTString)
6795
0
                        continue;
6796
0
                    auto str = poDstFeature->GetFieldAsString(i);
6797
0
                    if (strcmp(str, "") == 0)
6798
0
                        poDstFeature->SetFieldNull(i);
6799
0
                }
6800
0
            }
6801
6802
0
            if (!psInfo->m_anDateTimeFieldIdx.empty())
6803
0
            {
6804
0
                for (int i : psInfo->m_anDateTimeFieldIdx)
6805
0
                {
6806
0
                    if (!poDstFeature->IsFieldSetAndNotNull(i))
6807
0
                        continue;
6808
0
                    auto psField = poDstFeature->GetRawFieldRef(i);
6809
0
                    if (psField->Date.TZFlag == 0 || psField->Date.TZFlag == 1)
6810
0
                        continue;
6811
6812
0
                    const int nTZOffsetInSec =
6813
0
                        (psField->Date.TZFlag - 100) * 15 * 60;
6814
0
                    if (nTZOffsetInSec == psOptions->nTZOffsetInSec)
6815
0
                        continue;
6816
6817
0
                    struct tm brokendowntime;
6818
0
                    memset(&brokendowntime, 0, sizeof(brokendowntime));
6819
0
                    brokendowntime.tm_year = psField->Date.Year - 1900;
6820
0
                    brokendowntime.tm_mon = psField->Date.Month - 1;
6821
0
                    brokendowntime.tm_mday = psField->Date.Day;
6822
0
                    GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
6823
0
                    int nSec = psField->Date.Hour * 3600 +
6824
0
                               psField->Date.Minute * 60 +
6825
0
                               static_cast<int>(psField->Date.Second);
6826
0
                    nSec += psOptions->nTZOffsetInSec - nTZOffsetInSec;
6827
0
                    nUnixTime += nSec;
6828
0
                    CPLUnixTimeToYMDHMS(nUnixTime, &brokendowntime);
6829
6830
0
                    psField->Date.Year =
6831
0
                        static_cast<GInt16>(brokendowntime.tm_year + 1900);
6832
0
                    psField->Date.Month =
6833
0
                        static_cast<GByte>(brokendowntime.tm_mon + 1);
6834
0
                    psField->Date.Day =
6835
0
                        static_cast<GByte>(brokendowntime.tm_mday);
6836
0
                    psField->Date.Hour =
6837
0
                        static_cast<GByte>(brokendowntime.tm_hour);
6838
0
                    psField->Date.Minute =
6839
0
                        static_cast<GByte>(brokendowntime.tm_min);
6840
0
                    psField->Date.Second = static_cast<float>(
6841
0
                        brokendowntime.tm_sec + fmod(psField->Date.Second, 1));
6842
0
                    psField->Date.TZFlag = static_cast<GByte>(
6843
0
                        100 + psOptions->nTZOffsetInSec / (15 * 60));
6844
0
                }
6845
0
            }
6846
6847
            /* Erase native data if asked explicitly */
6848
0
            if (!m_bNativeData)
6849
0
            {
6850
0
                poDstFeature->SetNativeData(nullptr);
6851
0
                poDstFeature->SetNativeMediaType(nullptr);
6852
0
            }
6853
6854
0
            for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
6855
0
            {
6856
0
                std::unique_ptr<OGRGeometry> poDstGeometry;
6857
6858
0
                if (poCollToExplode && iGeom == iGeomCollToExplode)
6859
0
                {
6860
0
                    if (poSrcGeometry && poCollToExplode->IsEmpty())
6861
0
                    {
6862
0
                        const OGRwkbGeometryType eSrcType =
6863
0
                            poSrcGeometry->getGeometryType();
6864
0
                        const OGRwkbGeometryType eSrcFlattenType =
6865
0
                            wkbFlatten(eSrcType);
6866
0
                        OGRwkbGeometryType eDstType = eSrcType;
6867
0
                        switch (eSrcFlattenType)
6868
0
                        {
6869
0
                            case wkbMultiPoint:
6870
0
                                eDstType = wkbPoint;
6871
0
                                break;
6872
0
                            case wkbMultiLineString:
6873
0
                                eDstType = wkbLineString;
6874
0
                                break;
6875
0
                            case wkbMultiPolygon:
6876
0
                                eDstType = wkbPolygon;
6877
0
                                break;
6878
0
                            case wkbMultiCurve:
6879
0
                                eDstType = wkbCompoundCurve;
6880
0
                                break;
6881
0
                            case wkbMultiSurface:
6882
0
                                eDstType = wkbCurvePolygon;
6883
0
                                break;
6884
0
                            default:
6885
0
                                break;
6886
0
                        }
6887
0
                        eDstType =
6888
0
                            OGR_GT_SetModifier(eDstType, OGR_GT_HasZ(eSrcType),
6889
0
                                               OGR_GT_HasM(eSrcType));
6890
0
                        poDstGeometry.reset(
6891
0
                            OGRGeometryFactory::createGeometry(eDstType));
6892
0
                    }
6893
0
                    else
6894
0
                    {
6895
0
                        OGRGeometry *poPart =
6896
0
                            poCollToExplode->getGeometryRef(0);
6897
0
                        poCollToExplode->removeGeometry(0, FALSE);
6898
0
                        poDstGeometry.reset(poPart);
6899
0
                    }
6900
0
                }
6901
0
                else
6902
0
                {
6903
0
                    poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));
6904
0
                }
6905
0
                if (poDstGeometry == nullptr)
6906
0
                    continue;
6907
6908
                // poFeature hasn't been moved if iSrcZField != -1
6909
                // cppcheck-suppress accessMoved
6910
0
                if (iSrcZField != -1 && poFeature != nullptr)
6911
0
                {
6912
0
                    SetZ(poDstGeometry.get(),
6913
0
                         poFeature->GetFieldAsDouble(iSrcZField));
6914
                    /* This will correct the coordinate dimension to 3 */
6915
0
                    poDstGeometry.reset(poDstGeometry->clone());
6916
0
                }
6917
6918
0
                if (m_nCoordDim == 2 || m_nCoordDim == 3)
6919
0
                {
6920
0
                    poDstGeometry->setCoordinateDimension(m_nCoordDim);
6921
0
                }
6922
0
                else if (m_nCoordDim == 4)
6923
0
                {
6924
0
                    poDstGeometry->set3D(TRUE);
6925
0
                    poDstGeometry->setMeasured(TRUE);
6926
0
                }
6927
0
                else if (m_nCoordDim == COORD_DIM_XYM)
6928
0
                {
6929
0
                    poDstGeometry->set3D(FALSE);
6930
0
                    poDstGeometry->setMeasured(TRUE);
6931
0
                }
6932
0
                else if (m_nCoordDim == COORD_DIM_LAYER_DIM)
6933
0
                {
6934
0
                    const OGRwkbGeometryType eDstLayerGeomType =
6935
0
                        poDstLayer->GetLayerDefn()
6936
0
                            ->GetGeomFieldDefn(iGeom)
6937
0
                            ->GetType();
6938
0
                    poDstGeometry->set3D(wkbHasZ(eDstLayerGeomType));
6939
0
                    poDstGeometry->setMeasured(wkbHasM(eDstLayerGeomType));
6940
0
                }
6941
6942
0
                if (m_eGeomOp == GEOMOP_SEGMENTIZE)
6943
0
                {
6944
0
                    if (m_dfGeomOpParam > 0)
6945
0
                        poDstGeometry->segmentize(m_dfGeomOpParam);
6946
0
                }
6947
0
                else if (m_eGeomOp == GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY)
6948
0
                {
6949
0
                    if (m_dfGeomOpParam > 0)
6950
0
                    {
6951
0
                        auto poNewGeom = std::unique_ptr<OGRGeometry>(
6952
0
                            poDstGeometry->SimplifyPreserveTopology(
6953
0
                                m_dfGeomOpParam));
6954
0
                        if (poNewGeom)
6955
0
                        {
6956
0
                            poDstGeometry = std::move(poNewGeom);
6957
0
                        }
6958
0
                    }
6959
0
                }
6960
6961
0
                if (m_poClipSrcOri)
6962
0
                {
6963
0
                    if (poDstGeometry->IsEmpty())
6964
0
                        goto end_loop;
6965
6966
0
                    const auto clipGeomDesc =
6967
0
                        GetSrcClipGeom(poDstGeometry->getSpatialReference());
6968
6969
0
                    if (!(clipGeomDesc.poGeom && clipGeomDesc.poEnv))
6970
0
                        goto end_loop;
6971
6972
0
                    OGREnvelope oDstEnv;
6973
0
                    poDstGeometry->getEnvelope(&oDstEnv);
6974
6975
0
                    if (!(clipGeomDesc.bGeomIsRectangle &&
6976
0
                          clipGeomDesc.poEnv->Contains(oDstEnv)))
6977
0
                    {
6978
0
                        std::unique_ptr<OGRGeometry> poClipped;
6979
0
                        if (clipGeomDesc.poEnv->Intersects(oDstEnv))
6980
0
                        {
6981
0
                            poClipped.reset(clipGeomDesc.poGeom->Intersection(
6982
0
                                poDstGeometry.get()));
6983
0
                        }
6984
0
                        if (poClipped == nullptr || poClipped->IsEmpty())
6985
0
                        {
6986
0
                            goto end_loop;
6987
0
                        }
6988
6989
0
                        const int nDim = poDstGeometry->getDimension();
6990
0
                        if (poClipped->getDimension() < nDim &&
6991
0
                            wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
6992
0
                                           ->GetType()) != wkbUnknown)
6993
0
                        {
6994
0
                            CPLDebug(
6995
0
                                "OGR2OGR",
6996
0
                                "Discarding feature " CPL_FRMT_GIB
6997
0
                                " of layer %s, "
6998
0
                                "as its intersection with -clipsrc is a %s "
6999
0
                                "whereas the input is a %s",
7000
0
                                nSrcFID, poSrcLayer->GetName(),
7001
0
                                OGRToOGCGeomType(poClipped->getGeometryType()),
7002
0
                                OGRToOGCGeomType(
7003
0
                                    poDstGeometry->getGeometryType()));
7004
0
                            goto end_loop;
7005
0
                        }
7006
7007
0
                        poDstGeometry = OGRGeometryFactory::makeCompatibleWith(
7008
0
                            std::move(poClipped),
7009
0
                            poDstFDefn->GetGeomFieldDefn(iGeom)->GetType());
7010
0
                    }
7011
0
                }
7012
7013
0
                OGRCoordinateTransformation *const poCT =
7014
0
                    psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
7015
0
                char **const papszTransformOptions =
7016
0
                    psInfo->m_aoReprojectionInfo[iGeom]
7017
0
                        .m_aosTransformOptions.List();
7018
0
                const bool bReprojCanInvalidateValidity =
7019
0
                    psInfo->m_aoReprojectionInfo[iGeom]
7020
0
                        .m_bCanInvalidateValidity;
7021
7022
0
                if (poCT != nullptr || papszTransformOptions != nullptr)
7023
0
                {
7024
                    // If we need to change the geometry type to linear, and
7025
                    // we have a geometry with curves, then convert it to
7026
                    // linear first, to avoid invalidities due to the fact
7027
                    // that validity of arc portions isn't always kept while
7028
                    // reprojecting and then discretizing.
7029
0
                    if (bReprojCanInvalidateValidity &&
7030
0
                        (!psInfo->m_bSupportCurves ||
7031
0
                         m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
7032
0
                         m_eGeomTypeConversion ==
7033
0
                             GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))
7034
0
                    {
7035
0
                        if (poDstGeometry->hasCurveGeometry(TRUE))
7036
0
                        {
7037
0
                            OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
7038
0
                                poDstGeometry->getGeometryType());
7039
0
                            poDstGeometry = OGRGeometryFactory::forceTo(
7040
0
                                std::move(poDstGeometry), eTargetType);
7041
0
                        }
7042
0
                    }
7043
0
                    else if (bReprojCanInvalidateValidity &&
7044
0
                             eGType != GEOMTYPE_UNCHANGED &&
7045
0
                             !OGR_GT_IsNonLinear(
7046
0
                                 static_cast<OGRwkbGeometryType>(eGType)) &&
7047
0
                             poDstGeometry->hasCurveGeometry(TRUE))
7048
0
                    {
7049
0
                        poDstGeometry = OGRGeometryFactory::forceTo(
7050
0
                            std::move(poDstGeometry),
7051
0
                            static_cast<OGRwkbGeometryType>(eGType));
7052
0
                    }
7053
7054
                    // Collect left-most, right-most, top-most, bottom-most coordinates.
7055
0
                    if (psInfo->m_aoReprojectionInfo[iGeom]
7056
0
                            .m_bWarnAboutDifferentCoordinateOperations)
7057
0
                    {
7058
0
                        struct Visitor : public OGRDefaultConstGeometryVisitor
7059
0
                        {
7060
0
                            TargetLayerInfo::ReprojectionInfo &m_info;
7061
7062
0
                            explicit Visitor(
7063
0
                                TargetLayerInfo::ReprojectionInfo &info)
7064
0
                                : m_info(info)
7065
0
                            {
7066
0
                            }
7067
7068
0
                            using OGRDefaultConstGeometryVisitor::visit;
7069
7070
0
                            void visit(const OGRPoint *point) override
7071
0
                            {
7072
0
                                m_info.UpdateExtremePoints(point->getX(),
7073
0
                                                           point->getY(),
7074
0
                                                           point->getZ());
7075
0
                            }
7076
0
                        };
7077
7078
0
                        Visitor oVisit(psInfo->m_aoReprojectionInfo[iGeom]);
7079
0
                        poDstGeometry->accept(&oVisit);
7080
0
                    }
7081
7082
0
                    for (int iIter = 0; iIter < 2; ++iIter)
7083
0
                    {
7084
0
                        auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(
7085
0
                            OGRGeometryFactory::transformWithOptions(
7086
0
                                poDstGeometry.get(), poCT,
7087
0
                                papszTransformOptions,
7088
0
                                m_transformWithOptionsCache));
7089
0
                        if (poReprojectedGeom == nullptr)
7090
0
                        {
7091
0
                            if (psOptions->nGroupTransactions)
7092
0
                            {
7093
0
                                if (psOptions->nLayerTransaction)
7094
0
                                {
7095
0
                                    if (poDstLayer->CommitTransaction() !=
7096
0
                                            OGRERR_NONE &&
7097
0
                                        !psOptions->bSkipFailures)
7098
0
                                    {
7099
0
                                        return false;
7100
0
                                    }
7101
0
                                }
7102
0
                            }
7103
7104
0
                            CPLError(CE_Failure, CPLE_AppDefined,
7105
0
                                     "Failed to reproject feature " CPL_FRMT_GIB
7106
0
                                     " (geometry probably out of source or "
7107
0
                                     "destination SRS).",
7108
0
                                     nSrcFID);
7109
0
                            if (!psOptions->bSkipFailures)
7110
0
                            {
7111
0
                                return false;
7112
0
                            }
7113
0
                        }
7114
7115
                        // Check if a curve geometry is no longer valid after
7116
                        // reprojection
7117
0
                        const auto eType = poDstGeometry->getGeometryType();
7118
0
                        const auto eFlatType = wkbFlatten(eType);
7119
7120
0
                        std::string osReason;
7121
0
                        if (iIter == 0 && bReprojCanInvalidateValidity &&
7122
0
                            OGRGeometryFactory::haveGEOS() &&
7123
0
                            (eFlatType == wkbCurvePolygon ||
7124
0
                             eFlatType == wkbCompoundCurve ||
7125
0
                             eFlatType == wkbMultiCurve ||
7126
0
                             eFlatType == wkbMultiSurface) &&
7127
0
                            poDstGeometry->hasCurveGeometry(TRUE) &&
7128
0
                            poDstGeometry->IsValid(&osReason))
7129
0
                        {
7130
0
                            OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
7131
0
                                poDstGeometry->getGeometryType());
7132
0
                            auto poDstGeometryTmp = OGRGeometryFactory::forceTo(
7133
0
                                std::unique_ptr<OGRGeometry>(
7134
0
                                    poReprojectedGeom->clone()),
7135
0
                                eTargetType);
7136
0
                            if (!poDstGeometryTmp->IsValid(&osReason))
7137
0
                            {
7138
0
                                CPLDebug("OGR2OGR",
7139
0
                                         "Curve geometry no longer valid (%s) "
7140
0
                                         "after reprojection: transforming it "
7141
0
                                         "into linear one before reprojecting",
7142
0
                                         osReason.c_str());
7143
0
                                poDstGeometry = OGRGeometryFactory::forceTo(
7144
0
                                    std::move(poDstGeometry), eTargetType);
7145
0
                                poDstGeometry = OGRGeometryFactory::forceTo(
7146
0
                                    std::move(poDstGeometry), eType);
7147
0
                            }
7148
0
                            else
7149
0
                            {
7150
0
                                poDstGeometry = std::move(poReprojectedGeom);
7151
0
                                break;
7152
0
                            }
7153
0
                        }
7154
0
                        else
7155
0
                        {
7156
0
                            poDstGeometry = std::move(poReprojectedGeom);
7157
0
                            break;
7158
0
                        }
7159
0
                    }
7160
0
                }
7161
0
                else if (poOutputSRS != nullptr)
7162
0
                {
7163
0
                    poDstGeometry->assignSpatialReference(poOutputSRS);
7164
0
                }
7165
7166
0
                if (poDstGeometry != nullptr)
7167
0
                {
7168
0
                    if (m_poClipDstOri)
7169
0
                    {
7170
0
                        if (poDstGeometry->IsEmpty())
7171
0
                            goto end_loop;
7172
7173
0
                        const auto clipGeomDesc = GetDstClipGeom(
7174
0
                            poDstGeometry->getSpatialReference());
7175
0
                        if (!clipGeomDesc.poGeom || !clipGeomDesc.poEnv)
7176
0
                        {
7177
0
                            goto end_loop;
7178
0
                        }
7179
7180
0
                        OGREnvelope oDstEnv;
7181
0
                        poDstGeometry->getEnvelope(&oDstEnv);
7182
7183
0
                        if (!(clipGeomDesc.bGeomIsRectangle &&
7184
0
                              clipGeomDesc.poEnv->Contains(oDstEnv)))
7185
0
                        {
7186
0
                            std::unique_ptr<OGRGeometry> poClipped;
7187
0
                            if (clipGeomDesc.poEnv->Intersects(oDstEnv))
7188
0
                            {
7189
0
                                poClipped.reset(
7190
0
                                    clipGeomDesc.poGeom->Intersection(
7191
0
                                        poDstGeometry.get()));
7192
0
                            }
7193
7194
0
                            if (poClipped == nullptr || poClipped->IsEmpty())
7195
0
                            {
7196
0
                                goto end_loop;
7197
0
                            }
7198
7199
0
                            const int nDim = poDstGeometry->getDimension();
7200
0
                            if (poClipped->getDimension() < nDim &&
7201
0
                                wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
7202
0
                                               ->GetType()) != wkbUnknown)
7203
0
                            {
7204
0
                                CPLDebug(
7205
0
                                    "OGR2OGR",
7206
0
                                    "Discarding feature " CPL_FRMT_GIB
7207
0
                                    " of layer %s, "
7208
0
                                    "as its intersection with -clipdst is a %s "
7209
0
                                    "whereas the input is a %s",
7210
0
                                    nSrcFID, poSrcLayer->GetName(),
7211
0
                                    OGRToOGCGeomType(
7212
0
                                        poClipped->getGeometryType()),
7213
0
                                    OGRToOGCGeomType(
7214
0
                                        poDstGeometry->getGeometryType()));
7215
0
                                goto end_loop;
7216
0
                            }
7217
7218
0
                            poDstGeometry =
7219
0
                                OGRGeometryFactory::makeCompatibleWith(
7220
0
                                    std::move(poClipped),
7221
0
                                    poDstFDefn->GetGeomFieldDefn(iGeom)
7222
0
                                        ->GetType());
7223
0
                        }
7224
0
                    }
7225
7226
0
                    if (psOptions->dfXYRes !=
7227
0
                            OGRGeomCoordinatePrecision::UNKNOWN &&
7228
0
                        OGRGeometryFactory::haveGEOS() &&
7229
0
                        !poDstGeometry->hasCurveGeometry())
7230
0
                    {
7231
                        // OGR_APPLY_GEOM_SET_PRECISION default value for
7232
                        // OGRLayer::CreateFeature() purposes, but here in the
7233
                        // ogr2ogr -xyRes context, we force calling SetPrecision(),
7234
                        // unless the user explicitly asks not to do it by
7235
                        // setting the config option to NO.
7236
0
                        if (!bRunSetPrecisionEvaluated)
7237
0
                        {
7238
0
                            bRunSetPrecisionEvaluated = true;
7239
0
                            bRunSetPrecision = CPLTestBool(CPLGetConfigOption(
7240
0
                                "OGR_APPLY_GEOM_SET_PRECISION", "YES"));
7241
0
                        }
7242
0
                        if (bRunSetPrecision)
7243
0
                        {
7244
0
                            auto poNewGeom = std::unique_ptr<OGRGeometry>(
7245
0
                                poDstGeometry->SetPrecision(psOptions->dfXYRes,
7246
0
                                                            /* nFlags = */ 0));
7247
0
                            if (!poNewGeom)
7248
0
                                goto end_loop;
7249
0
                            poDstGeometry = std::move(poNewGeom);
7250
0
                        }
7251
0
                    }
7252
7253
0
                    if (m_bMakeValid)
7254
0
                    {
7255
0
                        const bool bIsGeomCollection =
7256
0
                            wkbFlatten(poDstGeometry->getGeometryType()) ==
7257
0
                            wkbGeometryCollection;
7258
0
                        auto poNewGeom = std::unique_ptr<OGRGeometry>(
7259
0
                            poDstGeometry->MakeValid());
7260
0
                        if (!poNewGeom)
7261
0
                            goto end_loop;
7262
0
                        poDstGeometry = std::move(poNewGeom);
7263
0
                        if (!bIsGeomCollection)
7264
0
                        {
7265
0
                            poDstGeometry.reset(
7266
0
                                OGRGeometryFactory::
7267
0
                                    removeLowerDimensionSubGeoms(
7268
0
                                        poDstGeometry.get()));
7269
0
                        }
7270
0
                    }
7271
7272
0
                    if (m_bSkipInvalidGeom && !poDstGeometry->IsValid())
7273
0
                        goto end_loop;
7274
7275
0
                    if (m_eGeomTypeConversion != GTC_DEFAULT)
7276
0
                    {
7277
0
                        OGRwkbGeometryType eTargetType =
7278
0
                            poDstGeometry->getGeometryType();
7279
0
                        eTargetType =
7280
0
                            ConvertType(m_eGeomTypeConversion, eTargetType);
7281
0
                        poDstGeometry = OGRGeometryFactory::forceTo(
7282
0
                            std::move(poDstGeometry), eTargetType);
7283
0
                    }
7284
0
                    else if (eGType != GEOMTYPE_UNCHANGED)
7285
0
                    {
7286
0
                        poDstGeometry = OGRGeometryFactory::forceTo(
7287
0
                            std::move(poDstGeometry),
7288
0
                            static_cast<OGRwkbGeometryType>(eGType));
7289
0
                    }
7290
0
                }
7291
7292
0
                if (poDstGeometry && !psOptions->bQuiet)
7293
0
                {
7294
0
                    if (!psInfo->m_bHasWarnedAboutCurves &&
7295
0
                        !psInfo->m_bSupportCurves &&
7296
0
                        OGR_GT_IsNonLinear(poDstGeometry->getGeometryType()))
7297
0
                    {
7298
0
                        CPLError(CE_Warning, CPLE_AppDefined,
7299
0
                                 "Attempt to write curve geometries to layer "
7300
0
                                 "%s that does not support them. They will be "
7301
0
                                 "linearized",
7302
0
                                 poDstLayer->GetDescription());
7303
0
                        psInfo->m_bHasWarnedAboutCurves = true;
7304
0
                    }
7305
0
                    if (!psInfo->m_bHasWarnedAboutZ && !psInfo->m_bSupportZ &&
7306
0
                        OGR_GT_HasZ(poDstGeometry->getGeometryType()))
7307
0
                    {
7308
0
                        CPLError(CE_Warning, CPLE_AppDefined,
7309
0
                                 "Attempt to write Z geometries to layer %s "
7310
0
                                 "that does not support them. Z component will "
7311
0
                                 "be discarded",
7312
0
                                 poDstLayer->GetDescription());
7313
0
                        psInfo->m_bHasWarnedAboutZ = true;
7314
0
                    }
7315
0
                    if (!psInfo->m_bHasWarnedAboutM && !psInfo->m_bSupportM &&
7316
0
                        OGR_GT_HasM(poDstGeometry->getGeometryType()))
7317
0
                    {
7318
0
                        CPLError(CE_Warning, CPLE_AppDefined,
7319
0
                                 "Attempt to write M geometries to layer %s "
7320
0
                                 "that does not support them. M component will "
7321
0
                                 "be discarded",
7322
0
                                 poDstLayer->GetDescription());
7323
0
                        psInfo->m_bHasWarnedAboutM = true;
7324
0
                    }
7325
0
                }
7326
7327
0
                poDstFeature->SetGeomField(iGeom, std::move(poDstGeometry));
7328
0
            }
7329
7330
0
            CPLErrorReset();
7331
0
            if ((psOptions->bUpsert
7332
0
                     ? poDstLayer->UpsertFeature(poDstFeature.get())
7333
0
                     : poDstLayer->CreateFeature(poDstFeature.get())) ==
7334
0
                OGRERR_NONE)
7335
0
            {
7336
0
                nFeaturesWritten++;
7337
0
                if (nDesiredFID != OGRNullFID &&
7338
0
                    poDstFeature->GetFID() != nDesiredFID)
7339
0
                {
7340
0
                    CPLError(CE_Warning, CPLE_AppDefined,
7341
0
                             "Feature id " CPL_FRMT_GIB " not preserved",
7342
0
                             nDesiredFID);
7343
0
                }
7344
0
            }
7345
0
            else if (!psOptions->bSkipFailures)
7346
0
            {
7347
0
                if (psOptions->nGroupTransactions)
7348
0
                {
7349
0
                    if (psOptions->nLayerTransaction)
7350
0
                        poDstLayer->RollbackTransaction();
7351
0
                }
7352
7353
0
                CPLError(CE_Failure, CPLE_AppDefined,
7354
0
                         "Unable to write feature " CPL_FRMT_GIB
7355
0
                         " from layer %s.",
7356
0
                         nSrcFID, poSrcLayer->GetName());
7357
7358
0
                return false;
7359
0
            }
7360
0
            else
7361
0
            {
7362
0
                CPLDebug("GDALVectorTranslate",
7363
0
                         "Unable to write feature " CPL_FRMT_GIB
7364
0
                         " into layer %s.",
7365
0
                         nSrcFID, poSrcLayer->GetName());
7366
0
                if (psOptions->nGroupTransactions)
7367
0
                {
7368
0
                    if (psOptions->nLayerTransaction)
7369
0
                    {
7370
0
                        poDstLayer->RollbackTransaction();
7371
0
                        CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());
7372
0
                    }
7373
0
                    else
7374
0
                    {
7375
0
                        m_poODS->RollbackTransaction();
7376
0
                        m_poODS->StartTransaction(psOptions->bForceTransaction);
7377
0
                    }
7378
0
                }
7379
0
            }
7380
7381
0
        end_loop:;  // nothing
7382
0
        }
7383
7384
        /* Report progress */
7385
0
        nCount++;
7386
0
        bool bGoOn = true;
7387
0
        if (pfnProgress)
7388
0
        {
7389
0
            bGoOn = pfnProgress(nCountLayerFeatures
7390
0
                                    ? nCount * 1.0 / nCountLayerFeatures
7391
0
                                    : 1.0,
7392
0
                                "", pProgressArg) != FALSE;
7393
0
        }
7394
0
        if (!bGoOn)
7395
0
        {
7396
0
            bRet = false;
7397
0
            break;
7398
0
        }
7399
7400
0
        if (pnReadFeatureCount)
7401
0
            *pnReadFeatureCount = nCount;
7402
7403
0
        if (psOptions->nFIDToFetch != OGRNullFID)
7404
0
            break;
7405
0
        if (bSingleIteration)
7406
0
            break;
7407
0
    }
7408
7409
0
    if (psOptions->nGroupTransactions)
7410
0
    {
7411
0
        if (psOptions->nLayerTransaction)
7412
0
        {
7413
0
            if (poDstLayer->CommitTransaction() != OGRERR_NONE)
7414
0
                bRet = false;
7415
0
        }
7416
0
    }
7417
7418
0
    if (!bSingleIteration)
7419
0
    {
7420
0
        CPLDebug("GDALVectorTranslate",
7421
0
                 CPL_FRMT_GIB " features written in layer '%s'",
7422
0
                 nFeaturesWritten, poDstLayer->GetName());
7423
0
    }
7424
7425
0
    return bRet;
7426
0
}
7427
7428
/************************************************************************/
7429
/*                  LayerTranslator::GetDstClipGeom()                   */
7430
/************************************************************************/
7431
7432
/** Returns the destination clip geometry and its envelope
7433
 *
7434
 * @param poGeomSRS The SRS into which the destination clip geometry should be
7435
 *                  expressed.
7436
 * @return the destination clip geometry and its envelope, or (nullptr, nullptr)
7437
 */
7438
LayerTranslator::ClipGeomDesc
7439
LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS)
7440
0
{
7441
0
    if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS)
7442
0
    {
7443
0
        auto poClipDstSRS = m_poClipDstOri->getSpatialReference();
7444
0
        if (poClipDstSRS && poGeomSRS && !poClipDstSRS->IsSame(poGeomSRS))
7445
0
        {
7446
            // Transform clip geom to geometry SRS
7447
0
            m_poClipDstReprojectedToDstSRS.reset(m_poClipDstOri->clone());
7448
0
            if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) !=
7449
0
                OGRERR_NONE)
7450
0
            {
7451
0
                return ClipGeomDesc();
7452
0
            }
7453
0
            m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS;
7454
0
        }
7455
0
        else if (!poClipDstSRS && poGeomSRS)
7456
0
        {
7457
0
            if (!m_bWarnedClipDstSRS)
7458
0
            {
7459
0
                m_bWarnedClipDstSRS = true;
7460
0
                CPLError(CE_Warning, CPLE_AppDefined,
7461
0
                         "Clip destination geometry has no "
7462
0
                         "attached SRS, but the feature's "
7463
0
                         "geometry has one. Assuming clip "
7464
0
                         "destination geometry SRS is the "
7465
0
                         "same as the feature's geometry");
7466
0
            }
7467
0
        }
7468
0
        m_oClipDstEnv = OGREnvelope();
7469
0
    }
7470
7471
0
    const auto poGeom = m_poClipDstReprojectedToDstSRS
7472
0
                            ? m_poClipDstReprojectedToDstSRS.get()
7473
0
                            : m_poClipDstOri;
7474
0
    if (poGeom && !m_oClipDstEnv.IsInit())
7475
0
    {
7476
0
        poGeom->getEnvelope(&m_oClipDstEnv);
7477
0
        m_bClipDstIsRectangle = poGeom->IsRectangle();
7478
0
    }
7479
0
    ClipGeomDesc ret;
7480
0
    ret.poGeom = poGeom;
7481
0
    ret.poEnv = poGeom ? &m_oClipDstEnv : nullptr;
7482
0
    ret.bGeomIsRectangle = m_bClipDstIsRectangle;
7483
0
    return ret;
7484
0
}
7485
7486
/************************************************************************/
7487
/*                  LayerTranslator::GetSrcClipGeom()                   */
7488
/************************************************************************/
7489
7490
/** Returns the source clip geometry and its envelope
7491
 *
7492
 * @param poGeomSRS The SRS into which the source clip geometry should be
7493
 *                  expressed.
7494
 * @return the source clip geometry and its envelope, or (nullptr, nullptr)
7495
 */
7496
LayerTranslator::ClipGeomDesc
7497
LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS)
7498
0
{
7499
0
    if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS)
7500
0
    {
7501
0
        auto poClipSrcSRS = m_poClipSrcOri->getSpatialReference();
7502
0
        if (poClipSrcSRS && poGeomSRS && !poClipSrcSRS->IsSame(poGeomSRS))
7503
0
        {
7504
            // Transform clip geom to geometry SRS
7505
0
            m_poClipSrcReprojectedToSrcSRS.reset(m_poClipSrcOri->clone());
7506
0
            if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) !=
7507
0
                OGRERR_NONE)
7508
0
            {
7509
0
                return ClipGeomDesc();
7510
0
            }
7511
0
            m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS;
7512
0
        }
7513
0
        else if (!poClipSrcSRS && poGeomSRS)
7514
0
        {
7515
0
            if (!m_bWarnedClipSrcSRS)
7516
0
            {
7517
0
                m_bWarnedClipSrcSRS = true;
7518
0
                CPLError(CE_Warning, CPLE_AppDefined,
7519
0
                         "Clip source geometry has no attached SRS, "
7520
0
                         "but the feature's geometry has one. "
7521
0
                         "Assuming clip source geometry SRS is the "
7522
0
                         "same as the feature's geometry");
7523
0
            }
7524
0
        }
7525
0
        m_oClipSrcEnv = OGREnvelope();
7526
0
    }
7527
7528
0
    const auto poGeom = m_poClipSrcReprojectedToSrcSRS
7529
0
                            ? m_poClipSrcReprojectedToSrcSRS.get()
7530
0
                            : m_poClipSrcOri;
7531
0
    if (poGeom && !m_oClipSrcEnv.IsInit())
7532
0
    {
7533
0
        poGeom->getEnvelope(&m_oClipSrcEnv);
7534
0
        m_bClipSrcIsRectangle = poGeom->IsRectangle();
7535
0
    }
7536
0
    ClipGeomDesc ret;
7537
0
    ret.poGeom = poGeom;
7538
0
    ret.poEnv = poGeom ? &m_oClipSrcEnv : nullptr;
7539
0
    ret.bGeomIsRectangle = m_bClipDstIsRectangle;
7540
0
    return ret;
7541
0
}
7542
7543
/************************************************************************/
7544
/*           TargetLayerInfo::CheckSameCoordinateOperation()            */
7545
/************************************************************************/
7546
7547
void TargetLayerInfo::CheckSameCoordinateOperation() const
7548
0
{
7549
0
    for (auto &info : m_aoReprojectionInfo)
7550
0
    {
7551
0
        if (info.m_bWarnAboutDifferentCoordinateOperations &&
7552
0
            info.m_dfLeftX <= info.m_dfRightX)
7553
0
        {
7554
            // Start recording if different coordinate operations are
7555
            // going to be used
7556
0
            OGRProjCTDifferentOperationsStart(info.m_poCT.get());
7557
7558
0
            {
7559
0
                CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
7560
0
                {
7561
0
                    double dfX = info.m_dfLeftX;
7562
0
                    double dfY = info.m_dfLeftY;
7563
0
                    double dfZ = info.m_dfLeftZ;
7564
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7565
0
                }
7566
7567
0
                {
7568
0
                    double dfX = info.m_dfRightX;
7569
0
                    double dfY = info.m_dfRightY;
7570
0
                    double dfZ = info.m_dfRightZ;
7571
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7572
0
                }
7573
7574
0
                {
7575
0
                    double dfX = info.m_dfTopX;
7576
0
                    double dfY = info.m_dfTopY;
7577
0
                    double dfZ = info.m_dfTopZ;
7578
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7579
0
                }
7580
7581
0
                {
7582
0
                    double dfX = info.m_dfBottomX;
7583
0
                    double dfY = info.m_dfBottomY;
7584
0
                    double dfZ = info.m_dfBottomZ;
7585
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7586
0
                }
7587
0
            }
7588
7589
0
            if (OGRProjCTDifferentOperationsUsed(info.m_poCT.get()))
7590
0
            {
7591
0
                CPLError(
7592
0
                    CE_Warning, CPLE_AppDefined,
7593
0
                    "Several coordinate operations have been used to transform "
7594
0
                    "layer %s. Artifacts may appear. You may consider "
7595
0
                    "using the -ct_opt ALLOW_BALLPARK=NO and/or "
7596
0
                    "-ct_opt ONLY_BEST=YES warping options, or specify "
7597
0
                    "a particular coordinate operation with -ct. "
7598
0
                    "This warning can be silenced with "
7599
0
                    "-ct_opt WARN_ABOUT_DIFFERENT_COORD_OP=NO.",
7600
0
                    m_poSrcLayer->GetName());
7601
0
            }
7602
7603
            // Stop recording
7604
0
            OGRProjCTDifferentOperationsStop(info.m_poCT.get());
7605
0
        }
7606
0
    }
7607
0
}
7608
7609
/************************************************************************/
7610
/*                GDALVectorTranslateOptionsGetParser()                 */
7611
/************************************************************************/
7612
7613
static std::unique_ptr<GDALArgumentParser> GDALVectorTranslateOptionsGetParser(
7614
    GDALVectorTranslateOptions *psOptions,
7615
    GDALVectorTranslateOptionsForBinary *psOptionsForBinary, int nCountClipSrc,
7616
    int nCountClipDst)
7617
0
{
7618
0
    auto argParser = std::make_unique<GDALArgumentParser>(
7619
0
        "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);
7620
7621
0
    argParser->add_description(
7622
0
        _("Converts simple features data between file formats."));
7623
7624
0
    argParser->add_epilog(
7625
0
        _("For more details, consult https://gdal.org/programs/ogr2ogr.html"));
7626
7627
0
    argParser->add_output_format_argument(psOptions->osFormat);
7628
7629
0
    argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);
7630
7631
0
    argParser->add_layer_creation_options_argument(psOptions->aosLCO);
7632
7633
0
    argParser->add_usage_newline();
7634
7635
0
    {
7636
0
        auto &group = argParser->add_mutually_exclusive_group();
7637
0
        group.add_argument("-append")
7638
0
            .flag()
7639
0
            .action([psOptions](const std::string &)
7640
0
                    { psOptions->eAccessMode = ACCESS_APPEND; })
7641
0
            .help(_("Append to existing layer instead of creating new."));
7642
7643
0
        group.add_argument("-upsert")
7644
0
            .flag()
7645
0
            .action(
7646
0
                [psOptions](const std::string &)
7647
0
                {
7648
0
                    psOptions->eAccessMode = ACCESS_APPEND;
7649
0
                    psOptions->bUpsert = true;
7650
0
                })
7651
0
            .help(_("Variant of -append where the UpsertFeature() operation is "
7652
0
                    "used to insert or update features."));
7653
7654
0
        group.add_argument("-overwrite")
7655
0
            .flag()
7656
0
            .action([psOptions](const std::string &)
7657
0
                    { psOptions->eAccessMode = ACCESS_OVERWRITE; })
7658
0
            .help(_("Delete the output layer and recreate it empty."));
7659
0
    }
7660
7661
0
    argParser->add_argument("-update")
7662
0
        .flag()
7663
0
        .action(
7664
0
            [psOptions](const std::string &)
7665
0
            {
7666
                /* Don't reset -append or -overwrite */
7667
0
                if (psOptions->eAccessMode != ACCESS_APPEND &&
7668
0
                    psOptions->eAccessMode != ACCESS_OVERWRITE)
7669
0
                    psOptions->eAccessMode = ACCESS_UPDATE;
7670
0
            })
7671
0
        .help(_("Open existing output datasource in update mode rather than "
7672
0
                "trying to create a new one."));
7673
7674
0
    argParser->add_argument("-sql")
7675
0
        .metavar("<statement>|@<filename>")
7676
0
        .action(
7677
0
            [psOptions](const std::string &s)
7678
0
            {
7679
0
                GByte *pabyRet = nullptr;
7680
0
                if (!s.empty() && s.front() == '@' &&
7681
0
                    VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7682
0
                                  10 * 1024 * 1024))
7683
0
                {
7684
0
                    GDALRemoveBOM(pabyRet);
7685
0
                    char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);
7686
0
                    psOptions->osSQLStatement =
7687
0
                        CPLRemoveSQLComments(pszSQLStatement);
7688
0
                    VSIFree(pszSQLStatement);
7689
0
                }
7690
0
                else
7691
0
                {
7692
0
                    psOptions->osSQLStatement = s;
7693
0
                }
7694
0
            })
7695
0
        .help(_("SQL statement to execute."));
7696
7697
0
    argParser->add_argument("-dialect")
7698
0
        .metavar("<dialect>")
7699
0
        .store_into(psOptions->osDialect)
7700
0
        .help(_("SQL dialect."));
7701
7702
0
    argParser->add_argument("-spat")
7703
0
        .metavar("<xmin> <ymin> <xmax> <ymax>")
7704
0
        .nargs(4)
7705
0
        .scan<'g', double>()
7706
0
        .help(_("Spatial query extents, in the SRS of the source layer(s) (or "
7707
0
                "the one specified with -spat_srs."));
7708
7709
0
    argParser->add_argument("-where")
7710
0
        .metavar("<restricted_where>|@<filename>")
7711
0
        .action(
7712
0
            [psOptions](const std::string &s)
7713
0
            {
7714
0
                GByte *pabyRet = nullptr;
7715
0
                if (!s.empty() && s.front() == '@' &&
7716
0
                    VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7717
0
                                  10 * 1024 * 1024))
7718
0
                {
7719
0
                    GDALRemoveBOM(pabyRet);
7720
0
                    char *pszWHERE = reinterpret_cast<char *>(pabyRet);
7721
0
                    psOptions->osWHERE = pszWHERE;
7722
0
                    VSIFree(pszWHERE);
7723
0
                }
7724
0
                else
7725
0
                {
7726
0
                    psOptions->osWHERE = s;
7727
0
                }
7728
0
            })
7729
0
        .help(_("Attribute query (like SQL WHERE)."));
7730
7731
0
    argParser->add_argument("-select")
7732
0
        .metavar("<field_list>")
7733
0
        .action(
7734
0
            [psOptions](const std::string &s)
7735
0
            {
7736
0
                psOptions->bSelFieldsSet = true;
7737
0
                psOptions->aosSelFields =
7738
0
                    CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);
7739
0
            })
7740
0
        .help(_("Comma-delimited list of fields from input layer to copy to "
7741
0
                "the new layer."));
7742
7743
0
    argParser->add_argument("-nln")
7744
0
        .metavar("<name>")
7745
0
        .store_into(psOptions->osNewLayerName)
7746
0
        .help(_("Assign an alternate name to the new layer."));
7747
7748
0
    argParser->add_argument("-nlt")
7749
0
        .metavar("<type>")
7750
0
        .append()
7751
0
        .action(
7752
0
            [psOptions](const std::string &osGeomNameIn)
7753
0
            {
7754
0
                bool bIs3D = false;
7755
0
                std::string osGeomName(osGeomNameIn);
7756
0
                if (osGeomName.size() > 3 &&
7757
0
                    STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,
7758
0
                                   "25D"))
7759
0
                {
7760
0
                    bIs3D = true;
7761
0
                    osGeomName.resize(osGeomName.size() - 3);
7762
0
                }
7763
0
                else if (osGeomName.size() > 1 &&
7764
0
                         STARTS_WITH_CI(
7765
0
                             osGeomName.c_str() + osGeomName.size() - 1, "Z"))
7766
0
                {
7767
0
                    bIs3D = true;
7768
0
                    osGeomName.pop_back();
7769
0
                }
7770
0
                if (EQUAL(osGeomName.c_str(), "NONE"))
7771
0
                {
7772
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7773
0
                    {
7774
0
                        throw std::invalid_argument(
7775
0
                            "Unsupported combination of -nlt arguments.");
7776
0
                    }
7777
0
                    psOptions->eGType = wkbNone;
7778
0
                }
7779
0
                else if (EQUAL(osGeomName.c_str(), "GEOMETRY"))
7780
0
                {
7781
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7782
0
                    {
7783
0
                        throw std::invalid_argument(
7784
0
                            "Unsupported combination of -nlt arguments.");
7785
0
                    }
7786
0
                    psOptions->eGType = wkbUnknown;
7787
0
                }
7788
0
                else if (EQUAL(osGeomName.c_str(), "PROMOTE_TO_MULTI"))
7789
0
                {
7790
0
                    if (psOptions->eGeomTypeConversion == GTC_CONVERT_TO_LINEAR)
7791
0
                        psOptions->eGeomTypeConversion =
7792
0
                            GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7793
0
                    else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7794
0
                        psOptions->eGeomTypeConversion = GTC_PROMOTE_TO_MULTI;
7795
0
                    else
7796
0
                    {
7797
0
                        throw std::invalid_argument(
7798
0
                            "Unsupported combination of -nlt arguments.");
7799
0
                    }
7800
0
                }
7801
0
                else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_LINEAR"))
7802
0
                {
7803
0
                    if (psOptions->eGeomTypeConversion == GTC_PROMOTE_TO_MULTI)
7804
0
                        psOptions->eGeomTypeConversion =
7805
0
                            GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7806
0
                    else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7807
0
                        psOptions->eGeomTypeConversion = GTC_CONVERT_TO_LINEAR;
7808
0
                    else
7809
0
                    {
7810
0
                        throw std::invalid_argument(
7811
0
                            "Unsupported combination of -nlt arguments.");
7812
0
                    }
7813
0
                }
7814
0
                else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_CURVE"))
7815
0
                {
7816
0
                    if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7817
0
                        psOptions->eGeomTypeConversion = GTC_CONVERT_TO_CURVE;
7818
0
                    else
7819
0
                    {
7820
0
                        throw std::invalid_argument(
7821
0
                            "Unsupported combination of -nlt arguments.");
7822
0
                    }
7823
0
                }
7824
0
                else
7825
0
                {
7826
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7827
0
                    {
7828
0
                        throw std::invalid_argument(
7829
0
                            "Unsupported combination of -nlt arguments.");
7830
0
                    }
7831
0
                    psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());
7832
0
                    if (psOptions->eGType == wkbUnknown)
7833
0
                    {
7834
0
                        throw std::invalid_argument(
7835
0
                            CPLSPrintf("-nlt %s: type not recognised.",
7836
0
                                       osGeomName.c_str()));
7837
0
                    }
7838
0
                }
7839
0
                if (psOptions->eGType != GEOMTYPE_UNCHANGED &&
7840
0
                    psOptions->eGType != wkbNone && bIs3D)
7841
0
                    psOptions->eGType = wkbSetZ(
7842
0
                        static_cast<OGRwkbGeometryType>(psOptions->eGType));
7843
0
            })
7844
0
        .help(_("Define the geometry type for the created layer."));
7845
7846
0
    argParser->add_argument("-s_srs")
7847
0
        .metavar("<srs_def>")
7848
0
        .store_into(psOptions->osSourceSRSDef)
7849
0
        .help(_("Set/override source SRS."));
7850
7851
0
    {
7852
0
        auto &group = argParser->add_mutually_exclusive_group();
7853
0
        group.add_argument("-a_srs")
7854
0
            .metavar("<srs_def>")
7855
0
            .action(
7856
0
                [psOptions](const std::string &osOutputSRSDef)
7857
0
                {
7858
0
                    psOptions->osOutputSRSDef = osOutputSRSDef;
7859
0
                    if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||
7860
0
                        EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))
7861
0
                    {
7862
0
                        psOptions->osOutputSRSDef.clear();
7863
0
                        psOptions->bNullifyOutputSRS = true;
7864
0
                    }
7865
0
                })
7866
0
            .help(_("Assign an output SRS, but without reprojecting."));
7867
7868
0
        group.add_argument("-t_srs")
7869
0
            .metavar("<srs_def>")
7870
0
            .action(
7871
0
                [psOptions](const std::string &osOutputSRSDef)
7872
0
                {
7873
0
                    psOptions->osOutputSRSDef = osOutputSRSDef;
7874
0
                    psOptions->bTransform = true;
7875
0
                })
7876
0
            .help(_("Reproject/transform to this SRS on output, and assign it "
7877
0
                    "as output SRS."));
7878
0
    }
7879
7880
    ///////////////////////////////////////////////////////////////////////
7881
0
    argParser->add_group("Field related options");
7882
7883
0
    argParser->add_argument("-addfields")
7884
0
        .flag()
7885
0
        .action(
7886
0
            [psOptions](const std::string &)
7887
0
            {
7888
0
                psOptions->bAddMissingFields = true;
7889
0
                psOptions->eAccessMode = ACCESS_APPEND;
7890
0
            })
7891
0
        .help(_("Same as append, but add also any new fields."));
7892
7893
0
    argParser->add_argument("-relaxedFieldNameMatch")
7894
0
        .flag()
7895
0
        .action([psOptions](const std::string &)
7896
0
                { psOptions->bExactFieldNameMatch = false; })
7897
0
        .help(_("Do field name matching between source and existing target "
7898
0
                "layer in a more relaxed way."));
7899
7900
0
    argParser->add_argument("-fieldTypeToString")
7901
0
        .metavar("All|<type1>[,<type2>]...")
7902
0
        .action(
7903
0
            [psOptions](const std::string &s)
7904
0
            {
7905
0
                psOptions->aosFieldTypesToString =
7906
0
                    CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7907
0
                CSLConstList iter = psOptions->aosFieldTypesToString.List();
7908
0
                while (*iter)
7909
0
                {
7910
0
                    if (IsFieldType(*iter))
7911
0
                    {
7912
                        /* Do nothing */
7913
0
                    }
7914
0
                    else if (EQUAL(*iter, "All"))
7915
0
                    {
7916
0
                        psOptions->aosFieldTypesToString.Clear();
7917
0
                        psOptions->aosFieldTypesToString.AddString("All");
7918
0
                        break;
7919
0
                    }
7920
0
                    else
7921
0
                    {
7922
0
                        throw std::invalid_argument(CPLSPrintf(
7923
0
                            "Unhandled type for fieldTypeToString option : %s",
7924
0
                            *iter));
7925
0
                    }
7926
0
                    iter++;
7927
0
                }
7928
0
            })
7929
0
        .help(_("Converts any field of the specified type to a field of type "
7930
0
                "string in the destination layer."));
7931
7932
0
    argParser->add_argument("-mapFieldType")
7933
0
        .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...")
7934
0
        .action(
7935
0
            [psOptions](const std::string &s)
7936
0
            {
7937
0
                psOptions->aosMapFieldType =
7938
0
                    CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7939
0
                CSLConstList iter = psOptions->aosMapFieldType.List();
7940
0
                while (*iter)
7941
0
                {
7942
0
                    char *pszKey = nullptr;
7943
0
                    const char *pszValue = CPLParseNameValue(*iter, &pszKey);
7944
0
                    if (pszKey && pszValue)
7945
0
                    {
7946
0
                        if (!((IsFieldType(pszKey) || EQUAL(pszKey, "All")) &&
7947
0
                              IsFieldType(pszValue)))
7948
0
                        {
7949
0
                            CPLFree(pszKey);
7950
0
                            throw std::invalid_argument(CPLSPrintf(
7951
0
                                "Invalid value for -mapFieldType : %s", *iter));
7952
0
                        }
7953
0
                    }
7954
0
                    CPLFree(pszKey);
7955
0
                    iter++;
7956
0
                }
7957
0
            })
7958
0
        .help(_("Converts any field of the specified type to another type."));
7959
7960
0
    argParser->add_argument("-fieldmap")
7961
0
        .metavar("<field_1>[,<field_2>]...")
7962
0
        .action(
7963
0
            [psOptions](const std::string &s)
7964
0
            {
7965
0
                psOptions->aosFieldMap =
7966
0
                    CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);
7967
0
            })
7968
0
        .help(_("Specifies the list of field indexes to be copied from the "
7969
0
                "source to the destination."));
7970
7971
0
    argParser->add_argument("-splitlistfields")
7972
0
        .store_into(psOptions->bSplitListFields)
7973
0
        .help(_("Split fields of type list type into as many fields of scalar "
7974
0
                "type as necessary."));
7975
7976
0
    argParser->add_argument("-maxsubfields")
7977
0
        .metavar("<n>")
7978
0
        .scan<'i', int>()
7979
0
        .action(
7980
0
            [psOptions](const std::string &s)
7981
0
            {
7982
0
                const int nVal = atoi(s.c_str());
7983
0
                if (nVal > 0)
7984
0
                {
7985
0
                    psOptions->nMaxSplitListSubFields = nVal;
7986
0
                }
7987
0
            })
7988
0
        .help(_("To be combined with -splitlistfields to limit the number of "
7989
0
                "subfields created for each split field."));
7990
7991
0
    argParser->add_argument("-emptyStrAsNull")
7992
0
        .store_into(psOptions->bEmptyStrAsNull)
7993
0
        .help(_("Treat empty string values as null."));
7994
7995
0
    argParser->add_argument("-forceNullable")
7996
0
        .store_into(psOptions->bForceNullable)
7997
0
        .help(_("Do not propagate not-nullable constraints to target layer if "
7998
0
                "they exist in source layer."));
7999
8000
0
    argParser->add_argument("-unsetFieldWidth")
8001
0
        .store_into(psOptions->bUnsetFieldWidth)
8002
0
        .help(_("Set field width and precision to 0."));
8003
8004
0
    argParser->add_argument("-unsetDefault")
8005
0
        .store_into(psOptions->bUnsetDefault)
8006
0
        .help(_("Do not propagate default field values to target layer if they "
8007
0
                "exist in source layer."));
8008
8009
0
    argParser->add_argument("-resolveDomains")
8010
0
        .store_into(psOptions->bResolveDomains)
8011
0
        .help(_("Cause any selected field that is linked to a coded field "
8012
0
                "domain will be accompanied by an additional field."));
8013
8014
0
    argParser->add_argument("-dateTimeTo")
8015
0
        .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>")
8016
0
        .action(
8017
0
            [psOptions](const std::string &s)
8018
0
            {
8019
0
                const char *pszFormat = s.c_str();
8020
0
                if (EQUAL(pszFormat, "UTC"))
8021
0
                {
8022
0
                    psOptions->nTZOffsetInSec = 0;
8023
0
                }
8024
0
                else if (STARTS_WITH_CI(pszFormat, "UTC") &&
8025
0
                         (strlen(pszFormat) == strlen("UTC+HH") ||
8026
0
                          strlen(pszFormat) == strlen("UTC+HH:MM")) &&
8027
0
                         (pszFormat[3] == '+' || pszFormat[3] == '-'))
8028
0
                {
8029
0
                    const int nHour = atoi(pszFormat + strlen("UTC+"));
8030
0
                    if (nHour < 0 || nHour > 14)
8031
0
                    {
8032
0
                        throw std::invalid_argument("Invalid UTC hour offset.");
8033
0
                    }
8034
0
                    else if (strlen(pszFormat) == strlen("UTC+HH"))
8035
0
                    {
8036
0
                        psOptions->nTZOffsetInSec = nHour * 3600;
8037
0
                        if (pszFormat[3] == '-')
8038
0
                            psOptions->nTZOffsetInSec =
8039
0
                                -psOptions->nTZOffsetInSec;
8040
0
                    }
8041
0
                    else  // if( strlen(pszFormat) == strlen("UTC+HH:MM") )
8042
0
                    {
8043
0
                        const int nMin = atoi(pszFormat + strlen("UTC+HH:"));
8044
0
                        if (nMin == 0 || nMin == 15 || nMin == 30 || nMin == 45)
8045
0
                        {
8046
0
                            psOptions->nTZOffsetInSec =
8047
0
                                nHour * 3600 + nMin * 60;
8048
0
                            if (pszFormat[3] == '-')
8049
0
                                psOptions->nTZOffsetInSec =
8050
0
                                    -psOptions->nTZOffsetInSec;
8051
0
                        }
8052
0
                    }
8053
0
                }
8054
0
                if (psOptions->nTZOffsetInSec == TZ_OFFSET_INVALID)
8055
0
                {
8056
0
                    throw std::invalid_argument(
8057
0
                        "Value of -dateTimeTo should be UTC, UTC(+|-)HH or "
8058
0
                        "UTC(+|-)HH:MM with HH in [0,14] and MM=00,15,30,45");
8059
0
                }
8060
0
            })
8061
0
        .help(_("Converts date time values from the timezone specified in the "
8062
0
                "source value to the target timezone."));
8063
8064
0
    argParser->add_argument("-noNativeData")
8065
0
        .flag()
8066
0
        .action([psOptions](const std::string &)
8067
0
                { psOptions->bNativeData = false; })
8068
0
        .help(_("Disable copying of native data."));
8069
8070
    ///////////////////////////////////////////////////////////////////////
8071
0
    argParser->add_group("Advanced geometry and SRS related options");
8072
8073
0
    argParser->add_argument("-dim")
8074
0
        .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM")
8075
0
        .action(
8076
0
            [psOptions](const std::string &osDim)
8077
0
            {
8078
0
                if (EQUAL(osDim.c_str(), "layer_dim"))
8079
0
                    psOptions->nCoordDim = COORD_DIM_LAYER_DIM;
8080
0
                else if (EQUAL(osDim.c_str(), "XY") ||
8081
0
                         EQUAL(osDim.c_str(), "2"))
8082
0
                    psOptions->nCoordDim = 2;
8083
0
                else if (EQUAL(osDim.c_str(), "XYZ") ||
8084
0
                         EQUAL(osDim.c_str(), "3"))
8085
0
                    psOptions->nCoordDim = 3;
8086
0
                else if (EQUAL(osDim.c_str(), "XYM"))
8087
0
                    psOptions->nCoordDim = COORD_DIM_XYM;
8088
0
                else if (EQUAL(osDim.c_str(), "XYZM"))
8089
0
                    psOptions->nCoordDim = 4;
8090
0
                else
8091
0
                {
8092
0
                    throw std::invalid_argument(CPLSPrintf(
8093
0
                        "-dim %s: value not handled.", osDim.c_str()));
8094
0
                }
8095
0
            })
8096
0
        .help(_("Force the coordinate dimension."));
8097
8098
0
    argParser->add_argument("-s_coord_epoch")
8099
0
        .metavar("<epoch>")
8100
0
        .store_into(psOptions->dfSourceCoordinateEpoch)
8101
0
        .help(_("Assign a coordinate epoch, linked with the source SRS."));
8102
8103
0
    argParser->add_argument("-a_coord_epoch")
8104
0
        .metavar("<epoch>")
8105
0
        .store_into(psOptions->dfOutputCoordinateEpoch)
8106
0
        .help(_("Assign a coordinate epoch, linked with the output SRS when "
8107
0
                "-a_srs is used."));
8108
8109
0
    argParser->add_argument("-t_coord_epoch")
8110
0
        .metavar("<epoch>")
8111
0
        .store_into(psOptions->dfOutputCoordinateEpoch)
8112
0
        .help(_("Assign a coordinate epoch, linked with the output SRS when "
8113
0
                "-t_srs is used."));
8114
8115
0
    argParser->add_argument("-ct")
8116
0
        .metavar("<pipeline_def>")
8117
0
        .action(
8118
0
            [psOptions](const std::string &s)
8119
0
            {
8120
0
                psOptions->osCTPipeline = s;
8121
0
                psOptions->bTransform = true;
8122
0
            })
8123
0
        .help(_("Override the default transformation from the source to the "
8124
0
                "target CRS."));
8125
8126
0
    argParser->add_argument("-ct_opt")
8127
0
        .metavar("<NAME>=<VALUE>")
8128
0
        .append()
8129
0
        .action([psOptions](const std::string &s)
8130
0
                { psOptions->aosCTOptions.AddString(s.c_str()); })
8131
0
        .help(_("Coordinate transform option(s)."));
8132
8133
0
    argParser->add_argument("-spat_srs")
8134
0
        .metavar("<srs_def>")
8135
0
        .store_into(psOptions->osSpatSRSDef)
8136
0
        .help(_("Override spatial filter SRS."));
8137
8138
0
    argParser->add_argument("-geomfield")
8139
0
        .metavar("<name>")
8140
0
        .action(
8141
0
            [psOptions](const std::string &s)
8142
0
            {
8143
0
                psOptions->osGeomField = s;
8144
0
                psOptions->bGeomFieldSet = true;
8145
0
            })
8146
0
        .help(_("Name of the geometry field on which the spatial filter "
8147
0
                "operates on."));
8148
8149
0
    argParser->add_argument("-segmentize")
8150
0
        .metavar("<max_dist>")
8151
0
        .store_into(psOptions->dfGeomOpParam)
8152
0
        .action([psOptions](const std::string &)
8153
0
                { psOptions->eGeomOp = GEOMOP_SEGMENTIZE; })
8154
0
        .help(_("Maximum distance between 2 nodes."));
8155
8156
0
    argParser->add_argument("-simplify")
8157
0
        .metavar("<tolerance>")
8158
0
        .store_into(psOptions->dfGeomOpParam)
8159
0
        .action([psOptions](const std::string &)
8160
0
                { psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY; })
8161
0
        .help(_("Distance tolerance for simplification."));
8162
8163
0
    argParser->add_argument("-makevalid")
8164
0
        .flag()
8165
0
        .action(
8166
0
            [psOptions](const std::string &)
8167
0
            {
8168
0
                if (!OGRGeometryFactory::haveGEOS())
8169
0
                {
8170
0
                    throw std::invalid_argument(
8171
0
                        "-makevalid only supported for builds against GEOS");
8172
0
                }
8173
0
                psOptions->bMakeValid = true;
8174
0
            })
8175
0
        .help(_("Fix geometries to be valid regarding the rules of the Simple "
8176
0
                "Features specification."));
8177
8178
0
    argParser->add_argument("-skipinvalid")
8179
0
        .flag()
8180
0
        .action(
8181
0
            [psOptions](const std::string &)
8182
0
            {
8183
0
                if (!OGRGeometryFactory::haveGEOS())
8184
0
                {
8185
0
                    throw std::invalid_argument(
8186
0
                        "-skipinvalid only supported for builds against GEOS");
8187
0
                }
8188
0
                psOptions->bSkipInvalidGeom = true;
8189
0
            })
8190
0
        .help(_("Whether to skip features with invalid geometries regarding the"
8191
0
                "rules of the Simple Features specification."));
8192
8193
0
    argParser->add_argument("-wrapdateline")
8194
0
        .store_into(psOptions->bWrapDateline)
8195
0
        .help(_("Split geometries crossing the dateline meridian."));
8196
8197
0
    argParser->add_argument("-datelineoffset")
8198
0
        .metavar("<val_in_degree>")
8199
0
        .default_value(psOptions->dfDateLineOffset)
8200
0
        .store_into(psOptions->dfDateLineOffset)
8201
0
        .help(_("Offset from dateline in degrees."));
8202
8203
0
    auto &clipsrcArg =
8204
0
        argParser->add_argument("-clipsrc")
8205
0
            .metavar(
8206
0
                "[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
8207
0
            .help(_("Clip geometries (in source SRS)."));
8208
0
    if (nCountClipSrc > 1)
8209
0
        clipsrcArg.nargs(nCountClipSrc);
8210
8211
0
    argParser->add_argument("-clipsrcsql")
8212
0
        .metavar("<sql_statement>")
8213
0
        .store_into(psOptions->osClipSrcSQL)
8214
0
        .help(_("Select desired geometries from the source clip datasource "
8215
0
                "using an SQL query."));
8216
8217
0
    argParser->add_argument("-clipsrclayer")
8218
0
        .metavar("<layername>")
8219
0
        .store_into(psOptions->osClipSrcLayer)
8220
0
        .help(_("Select the named layer from the source clip datasource."));
8221
8222
0
    argParser->add_argument("-clipsrcwhere")
8223
0
        .metavar("<expression>")
8224
0
        .store_into(psOptions->osClipSrcWhere)
8225
0
        .help(_("Restrict desired geometries from the source clip layer based "
8226
0
                "on an attribute query."));
8227
8228
0
    auto &clipdstArg =
8229
0
        argParser->add_argument("-clipdst")
8230
0
            .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>")
8231
0
            .help(_("Clip geometries (in target SRS)."));
8232
0
    if (nCountClipDst > 1)
8233
0
        clipdstArg.nargs(nCountClipDst);
8234
8235
0
    argParser->add_argument("-clipdstsql")
8236
0
        .metavar("<sql_statement>")
8237
0
        .store_into(psOptions->osClipDstSQL)
8238
0
        .help(_("Select desired geometries from the destination clip "
8239
0
                "datasource using an SQL query."));
8240
8241
0
    argParser->add_argument("-clipdstlayer")
8242
0
        .metavar("<layername>")
8243
0
        .store_into(psOptions->osClipDstLayer)
8244
0
        .help(
8245
0
            _("Select the named layer from the destination clip datasource."));
8246
8247
0
    argParser->add_argument("-clipdstwhere")
8248
0
        .metavar("<expression>")
8249
0
        .store_into(psOptions->osClipDstWhere)
8250
0
        .help(_("Restrict desired geometries from the destination clip layer "
8251
0
                "based on an attribute query."));
8252
8253
0
    argParser->add_argument("-explodecollections")
8254
0
        .store_into(psOptions->bExplodeCollections)
8255
0
        .help(_("Produce one feature for each geometry in any kind of geometry "
8256
0
                "collection in the source file."));
8257
8258
0
    argParser->add_argument("-zfield")
8259
0
        .metavar("<name>")
8260
0
        .store_into(psOptions->osZField)
8261
0
        .help(_("Uses the specified field to fill the Z coordinate of "
8262
0
                "geometries."));
8263
8264
0
    argParser->add_argument("-gcp")
8265
0
        .metavar(
8266
0
            "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")
8267
0
        .nargs(4, 5)
8268
0
        .append()
8269
0
        .scan<'g', double>()
8270
0
        .help(_("Add the indicated ground control point."));
8271
8272
0
    argParser->add_argument("-tps")
8273
0
        .flag()
8274
0
        .action([psOptions](const std::string &)
8275
0
                { psOptions->nTransformOrder = -1; })
8276
0
        .help(_("Force use of thin plate spline transformer based on available "
8277
0
                "GCPs."));
8278
8279
0
    argParser->add_argument("-order")
8280
0
        .metavar("1|2|3")
8281
0
        .store_into(psOptions->nTransformOrder)
8282
0
        .help(_("Order of polynomial used for warping."));
8283
8284
0
    argParser->add_argument("-xyRes")
8285
0
        .metavar("<val>[ m|mm|deg]")
8286
0
        .action(
8287
0
            [psOptions](const std::string &s)
8288
0
            {
8289
0
                const char *pszVal = s.c_str();
8290
8291
0
                char *endptr = nullptr;
8292
0
                psOptions->dfXYRes = CPLStrtodM(pszVal, &endptr);
8293
0
                if (!endptr)
8294
0
                {
8295
0
                    throw std::invalid_argument(
8296
0
                        "Invalid value for -xyRes. Must be of the form "
8297
0
                        "{numeric_value}[ ]?[m|mm|deg]?");
8298
0
                }
8299
0
                if (*endptr == ' ')
8300
0
                    ++endptr;
8301
0
                if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
8302
0
                    strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
8303
0
                {
8304
0
                    throw std::invalid_argument(
8305
0
                        "Invalid value for -xyRes. Must be of the form "
8306
0
                        "{numeric_value}[ ]?[m|mm|deg]?");
8307
0
                }
8308
0
                psOptions->osXYResUnit = endptr;
8309
0
            })
8310
0
        .help(_("Set/override the geometry X/Y coordinate resolution."));
8311
8312
0
    argParser->add_argument("-zRes")
8313
0
        .metavar("<val>[ m|mm]")
8314
0
        .action(
8315
0
            [psOptions](const std::string &s)
8316
0
            {
8317
0
                const char *pszVal = s.c_str();
8318
8319
0
                char *endptr = nullptr;
8320
0
                psOptions->dfZRes = CPLStrtodM(pszVal, &endptr);
8321
0
                if (!endptr)
8322
0
                {
8323
0
                    throw std::invalid_argument(
8324
0
                        "Invalid value for -zRes. Must be of the form "
8325
0
                        "{numeric_value}[ ]?[m|mm]?");
8326
0
                }
8327
0
                if (*endptr == ' ')
8328
0
                    ++endptr;
8329
0
                if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
8330
0
                    strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
8331
0
                {
8332
0
                    throw std::invalid_argument(
8333
0
                        "Invalid value for -zRes. Must be of the form "
8334
0
                        "{numeric_value}[ ]?[m|mm]?");
8335
0
                }
8336
0
                psOptions->osZResUnit = endptr;
8337
0
            })
8338
0
        .help(_("Set/override the geometry Z coordinate resolution."));
8339
8340
0
    argParser->add_argument("-mRes")
8341
0
        .metavar("<val>")
8342
0
        .store_into(psOptions->dfMRes)
8343
0
        .help(_("Set/override the geometry M coordinate resolution."));
8344
8345
0
    argParser->add_argument("-unsetCoordPrecision")
8346
0
        .store_into(psOptions->bUnsetCoordPrecision)
8347
0
        .help(_("Prevent the geometry coordinate resolution from being set on "
8348
0
                "target layer(s)."));
8349
8350
    ///////////////////////////////////////////////////////////////////////
8351
0
    argParser->add_group("Other options");
8352
8353
0
    argParser->add_quiet_argument(&psOptions->bQuiet);
8354
8355
0
    argParser->add_argument("-progress")
8356
0
        .store_into(psOptions->bDisplayProgress)
8357
0
        .help(_("Display progress on terminal. Only works if input layers have "
8358
0
                "the 'fast feature count' capability."));
8359
8360
0
    argParser->add_input_format_argument(
8361
0
        psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers
8362
0
                           : nullptr);
8363
8364
0
    argParser->add_open_options_argument(
8365
0
        psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);
8366
8367
0
    argParser->add_argument("-doo")
8368
0
        .metavar("<NAME>=<VALUE>")
8369
0
        .append()
8370
0
        .action([psOptions](const std::string &s)
8371
0
                { psOptions->aosDestOpenOptions.AddString(s.c_str()); })
8372
0
        .help(_("Open option(s) for output dataset."));
8373
8374
0
    argParser->add_usage_newline();
8375
8376
0
    argParser->add_argument("-fid")
8377
0
        .metavar("<FID>")
8378
0
        .store_into(psOptions->nFIDToFetch)
8379
0
        .help(_("If provided, only the feature with the specified feature id "
8380
0
                "will be processed."));
8381
8382
0
    argParser->add_argument("-preserve_fid")
8383
0
        .store_into(psOptions->bPreserveFID)
8384
0
        .help(_("Use the FID of the source features instead of letting the "
8385
0
                "output driver automatically assign a new one."));
8386
8387
0
    argParser->add_argument("-unsetFid")
8388
0
        .store_into(psOptions->bUnsetFid)
8389
0
        .help(_("Prevent the name of the source FID column and source feature "
8390
0
                "IDs from being reused."));
8391
8392
0
    {
8393
0
        auto &group = argParser->add_mutually_exclusive_group();
8394
0
        group.add_argument("-skip", "-skipfailures")
8395
0
            .flag()
8396
0
            .action(
8397
0
                [psOptions](const std::string &)
8398
0
                {
8399
0
                    psOptions->bSkipFailures = true;
8400
0
                    psOptions->nGroupTransactions = 1; /* #2409 */
8401
0
                })
8402
0
            .help(_("Continue after a failure, skipping the failed feature."));
8403
8404
0
        auto &arg = group.add_argument("-gt")
8405
0
                        .metavar("<n>|unlimited")
8406
0
                        .action(
8407
0
                            [psOptions](const std::string &s)
8408
0
                            {
8409
                                /* If skipfailures is already set we should not
8410
               modify nGroupTransactions = 1  #2409 */
8411
0
                                if (!psOptions->bSkipFailures)
8412
0
                                {
8413
0
                                    if (EQUAL(s.c_str(), "unlimited"))
8414
0
                                        psOptions->nGroupTransactions = -1;
8415
0
                                    else
8416
0
                                        psOptions->nGroupTransactions =
8417
0
                                            atoi(s.c_str());
8418
0
                                }
8419
0
                            })
8420
0
                        .help(_("Group <n> features per transaction "));
8421
8422
0
        argParser->add_hidden_alias_for(arg, "tg");
8423
0
    }
8424
8425
0
    argParser->add_argument("-limit")
8426
0
        .metavar("<nb_features>")
8427
0
        .store_into(psOptions->nLimit)
8428
0
        .help(_("Limit the number of features per layer."));
8429
8430
0
    argParser->add_argument("-ds_transaction")
8431
0
        .flag()
8432
0
        .action(
8433
0
            [psOptions](const std::string &)
8434
0
            {
8435
0
                psOptions->nLayerTransaction = FALSE;
8436
0
                psOptions->bForceTransaction = true;
8437
0
            })
8438
0
        .help(_("Force the use of a dataset level transaction."));
8439
8440
    /* Undocumented. Just a provision. Default behavior should be OK */
8441
0
    argParser->add_argument("-lyr_transaction")
8442
0
        .flag()
8443
0
        .hidden()
8444
0
        .action([psOptions](const std::string &)
8445
0
                { psOptions->nLayerTransaction = TRUE; })
8446
0
        .help(_("Force the use of a layer level transaction."));
8447
8448
0
    argParser->add_metadata_item_options_argument(
8449
0
        psOptions->aosMetadataOptions);
8450
8451
0
    argParser->add_argument("-nomd")
8452
0
        .flag()
8453
0
        .action([psOptions](const std::string &)
8454
0
                { psOptions->bCopyMD = false; })
8455
0
        .help(_("Disable copying of metadata from source dataset and layers "
8456
0
                "into target dataset and layers."));
8457
8458
    // Undocumented option used by gdal vector convert
8459
0
    argParser->add_argument("--no-overwrite")
8460
0
        .store_into(psOptions->bNoOverwrite)
8461
0
        .hidden();
8462
8463
    // Undocumented option used by gdal vector * algorithms
8464
0
    argParser->add_argument("--invoked-from-gdal-algorithm")
8465
0
        .store_into(psOptions->bInvokedFromGdalAlgorithm)
8466
0
        .hidden();
8467
8468
0
    if (psOptionsForBinary)
8469
0
    {
8470
0
        argParser->add_argument("dst_dataset_name")
8471
0
            .metavar("<dst_dataset_name>")
8472
0
            .store_into(psOptionsForBinary->osDestDataSource)
8473
0
            .help(_("Output dataset."));
8474
8475
0
        argParser->add_argument("src_dataset_name")
8476
0
            .metavar("<src_dataset_name>")
8477
0
            .store_into(psOptionsForBinary->osDataSource)
8478
0
            .help(_("Input dataset."));
8479
0
    }
8480
8481
0
    argParser->add_argument("layer")
8482
0
        .remaining()
8483
0
        .metavar("<layer_name>")
8484
0
        .help(_("Layer name"));
8485
0
    return argParser;
8486
0
}
8487
8488
/************************************************************************/
8489
/*                 GDALVectorTranslateGetParserUsage()                  */
8490
/************************************************************************/
8491
8492
std::string GDALVectorTranslateGetParserUsage()
8493
0
{
8494
0
    try
8495
0
    {
8496
0
        GDALVectorTranslateOptions sOptions;
8497
0
        GDALVectorTranslateOptionsForBinary sOptionsForBinary;
8498
0
        auto argParser = GDALVectorTranslateOptionsGetParser(
8499
0
            &sOptions, &sOptionsForBinary, 1, 1);
8500
0
        return argParser->usage();
8501
0
    }
8502
0
    catch (const std::exception &err)
8503
0
    {
8504
0
        CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
8505
0
                 err.what());
8506
0
        return std::string();
8507
0
    }
8508
0
}
8509
8510
/************************************************************************/
8511
/*                  CHECK_HAS_ENOUGH_ADDITIONAL_ARGS()                  */
8512
/************************************************************************/
8513
8514
#ifndef CheckHasEnoughAdditionalArgs_defined
8515
#define CheckHasEnoughAdditionalArgs_defined
8516
8517
static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,
8518
                                         int nExtraArg, int nArgc)
8519
0
{
8520
0
    if (i + nExtraArg >= nArgc)
8521
0
    {
8522
0
        CPLError(CE_Failure, CPLE_IllegalArg,
8523
0
                 "%s option requires %d argument%s", papszArgv[i], nExtraArg,
8524
0
                 nExtraArg == 1 ? "" : "s");
8525
0
        return false;
8526
0
    }
8527
0
    return true;
8528
0
}
8529
#endif
8530
8531
#define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \
8532
0
    if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc))         \
8533
0
    {                                                                          \
8534
0
        return nullptr;                                                        \
8535
0
    }
8536
8537
/************************************************************************/
8538
/*                   GDALVectorTranslateOptionsNew()                    */
8539
/************************************************************************/
8540
8541
/**
8542
 * allocates a GDALVectorTranslateOptions struct.
8543
 *
8544
 * @param papszArgv NULL terminated list of options (potentially including
8545
 * filename and open options too), or NULL. The accepted options are the ones of
8546
 * the <a href="/programs/ogr2ogr.html">ogr2ogr</a> utility.
8547
 * @param psOptionsForBinary (output) may be NULL (and should generally be
8548
 * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
8549
 *                           GDALVectorTranslateOptionsForBinaryNew() prior to
8550
 * this function. Will be filled with potentially present filename, open
8551
 * options,...
8552
 * @return pointer to the allocated GDALVectorTranslateOptions struct. Must be
8553
 * freed with GDALVectorTranslateOptionsFree().
8554
 *
8555
 * @since GDAL 2.1
8556
 */
8557
GDALVectorTranslateOptions *GDALVectorTranslateOptionsNew(
8558
    char **papszArgv, GDALVectorTranslateOptionsForBinary *psOptionsForBinary)
8559
0
{
8560
0
    auto psOptions = std::make_unique<GDALVectorTranslateOptions>();
8561
8562
0
    try
8563
0
    {
8564
        // Pre-processing for custom syntax that ArgumentParser does not support
8565
8566
0
        CPLStringList aosArgv;
8567
0
        const int nArgc = CSLCount(papszArgv);
8568
0
        int nCountClipSrc = 0;
8569
0
        int nCountClipDst = 0;
8570
0
        for (int i = 0;
8571
0
             i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
8572
0
        {
8573
0
            if (EQUAL(papszArgv[i], "-gcp"))
8574
0
            {
8575
                // repeated argument of varying size: not handled by argparse.
8576
8577
0
                CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
8578
0
                char *endptr = nullptr;
8579
                /* -gcp pixel line easting northing [elev] */
8580
8581
0
                psOptions->asGCPs.resize(psOptions->asGCPs.size() + 1);
8582
0
                auto &sGCP = psOptions->asGCPs.back();
8583
8584
0
                const auto oPixel = cpl::strict_parse<double>(papszArgv[++i]);
8585
0
                const auto oLine = cpl::strict_parse<double>(papszArgv[++i]);
8586
0
                const auto oX = cpl::strict_parse<double>(papszArgv[++i]);
8587
0
                const auto oY = cpl::strict_parse<double>(papszArgv[++i]);
8588
8589
0
                if (!oPixel.has_value() || !oLine.has_value() ||
8590
0
                    !oX.has_value() || !oY.has_value())
8591
0
                {
8592
0
                    CPLError(CE_Failure, CPLE_IllegalArg, "Invalid -gcp value");
8593
0
                    return nullptr;
8594
0
                }
8595
8596
0
                sGCP.Pixel() = oPixel.value();
8597
0
                sGCP.Line() = oLine.value();
8598
0
                sGCP.X() = oX.value();
8599
0
                sGCP.Y() = oY.value();
8600
8601
0
                if (papszArgv[i + 1] != nullptr &&
8602
0
                    (CPLStrtod(papszArgv[i + 1], &endptr) != 0.0 ||
8603
0
                     papszArgv[i + 1][0] == '0'))
8604
0
                {
8605
                    /* Check that last argument is really a number and not a
8606
                     * filename */
8607
                    /* looking like a number (see ticket #863) */
8608
0
                    if (endptr && *endptr == 0)
8609
0
                        sGCP.Z() = CPLAtof(papszArgv[++i]);
8610
0
                }
8611
8612
                /* should set id and info? */
8613
0
            }
8614
8615
0
            else if (EQUAL(papszArgv[i], "-clipsrc"))
8616
0
            {
8617
0
                if (nCountClipSrc)
8618
0
                {
8619
0
                    CPLError(CE_Failure, CPLE_AppDefined,
8620
0
                             "Duplicate argument %s", papszArgv[i]);
8621
0
                    return nullptr;
8622
0
                }
8623
                // argparse doesn't handle well variable number of values
8624
                // just before the positional arguments, so we have to detect
8625
                // it manually and set the correct number.
8626
0
                nCountClipSrc = 1;
8627
0
                CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8628
0
                if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8629
0
                    i + 4 < nArgc)
8630
0
                {
8631
0
                    nCountClipSrc = 4;
8632
0
                }
8633
8634
0
                for (int j = 0; j < 1 + nCountClipSrc; ++j)
8635
0
                {
8636
0
                    aosArgv.AddString(papszArgv[i]);
8637
0
                    ++i;
8638
0
                }
8639
0
                --i;
8640
0
            }
8641
8642
0
            else if (EQUAL(papszArgv[i], "-clipdst"))
8643
0
            {
8644
0
                if (nCountClipDst)
8645
0
                {
8646
0
                    CPLError(CE_Failure, CPLE_AppDefined,
8647
0
                             "Duplicate argument %s", papszArgv[i]);
8648
0
                    return nullptr;
8649
0
                }
8650
                // argparse doesn't handle well variable number of values
8651
                // just before the positional arguments, so we have to detect
8652
                // it manually and set the correct number.
8653
0
                nCountClipDst = 1;
8654
0
                CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8655
0
                if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8656
0
                    i + 4 < nArgc)
8657
0
                {
8658
0
                    nCountClipDst = 4;
8659
0
                }
8660
8661
0
                for (int j = 0; j < 1 + nCountClipDst; ++j)
8662
0
                {
8663
0
                    aosArgv.AddString(papszArgv[i]);
8664
0
                    ++i;
8665
0
                }
8666
0
                --i;
8667
0
            }
8668
8669
0
            else
8670
0
            {
8671
0
                aosArgv.AddString(papszArgv[i]);
8672
0
            }
8673
0
        }
8674
8675
0
        auto argParser = GDALVectorTranslateOptionsGetParser(
8676
0
            psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);
8677
8678
        // Collect non-positional arguments for VectorTranslateFrom() case
8679
0
        psOptions->aosArguments =
8680
0
            argParser->get_non_positional_arguments(aosArgv);
8681
8682
0
        argParser->parse_args_without_binary_name(aosArgv.List());
8683
8684
0
        if (psOptionsForBinary)
8685
0
            psOptionsForBinary->bQuiet = psOptions->bQuiet;
8686
8687
0
        if (auto oSpat = argParser->present<std::vector<double>>("-spat"))
8688
0
        {
8689
0
            const double dfMinX = (*oSpat)[0];
8690
0
            const double dfMinY = (*oSpat)[1];
8691
0
            const double dfMaxX = (*oSpat)[2];
8692
0
            const double dfMaxY = (*oSpat)[3];
8693
8694
0
            auto poSpatialFilter =
8695
0
                std::make_shared<OGRPolygon>(dfMinX, dfMinY, dfMaxX, dfMaxY);
8696
0
            psOptions->poSpatialFilter = poSpatialFilter;
8697
0
        }
8698
8699
0
        if (auto oClipSrc =
8700
0
                argParser->present<std::vector<std::string>>("-clipsrc"))
8701
0
        {
8702
0
            const std::string &osVal = (*oClipSrc)[0];
8703
8704
0
            psOptions->poClipSrc.reset();
8705
0
            psOptions->osClipSrcDS.clear();
8706
8707
0
            VSIStatBufL sStat;
8708
0
            psOptions->bClipSrc = true;
8709
0
            if (oClipSrc->size() == 4)
8710
0
            {
8711
0
                const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
8712
0
                const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
8713
0
                const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
8714
0
                const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
8715
8716
0
                OGRLinearRing oRing;
8717
8718
0
                oRing.addPoint(dfMinX, dfMinY);
8719
0
                oRing.addPoint(dfMinX, dfMaxY);
8720
0
                oRing.addPoint(dfMaxX, dfMaxY);
8721
0
                oRing.addPoint(dfMaxX, dfMinY);
8722
0
                oRing.addPoint(dfMinX, dfMinY);
8723
8724
0
                auto poPoly = std::make_shared<OGRPolygon>();
8725
0
                psOptions->poClipSrc = poPoly;
8726
0
                poPoly->addRing(&oRing);
8727
0
            }
8728
0
            else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8729
0
                      STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8730
0
                     VSIStatL(osVal.c_str(), &sStat) != 0)
8731
0
            {
8732
0
                psOptions->poClipSrc =
8733
0
                    OGRGeometryFactory::createFromWkt(osVal.c_str()).first;
8734
0
                if (psOptions->poClipSrc == nullptr)
8735
0
                {
8736
0
                    CPLError(
8737
0
                        CE_Failure, CPLE_IllegalArg,
8738
0
                        "Invalid -clipsrc geometry. Must be a valid POLYGON or "
8739
0
                        "MULTIPOLYGON WKT");
8740
0
                    return nullptr;
8741
0
                }
8742
0
            }
8743
0
            else if (EQUAL(osVal.c_str(), "spat_extent"))
8744
0
            {
8745
                // Nothing to do
8746
0
            }
8747
0
            else
8748
0
            {
8749
0
                psOptions->osClipSrcDS = osVal;
8750
0
            }
8751
0
        }
8752
8753
0
        if (auto oClipDst =
8754
0
                argParser->present<std::vector<std::string>>("-clipdst"))
8755
0
        {
8756
0
            const std::string &osVal = (*oClipDst)[0];
8757
8758
0
            psOptions->poClipDst.reset();
8759
0
            psOptions->osClipDstDS.clear();
8760
8761
0
            VSIStatBufL sStat;
8762
0
            if (oClipDst->size() == 4)
8763
0
            {
8764
0
                const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());
8765
0
                const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());
8766
0
                const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());
8767
0
                const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());
8768
8769
0
                auto poPoly = std::make_shared<OGRPolygon>(dfMinX, dfMinY,
8770
0
                                                           dfMaxX, dfMaxY);
8771
0
                psOptions->poClipDst = poPoly;
8772
0
            }
8773
0
            else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8774
0
                      STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8775
0
                     VSIStatL(osVal.c_str(), &sStat) != 0)
8776
0
            {
8777
0
                psOptions->poClipDst =
8778
0
                    OGRGeometryFactory::createFromWkt(osVal.c_str()).first;
8779
0
                if (psOptions->poClipDst == nullptr)
8780
0
                {
8781
0
                    CPLError(
8782
0
                        CE_Failure, CPLE_IllegalArg,
8783
0
                        "Invalid -clipdst geometry. Must be a valid POLYGON or "
8784
0
                        "MULTIPOLYGON WKT");
8785
0
                    return nullptr;
8786
0
                }
8787
0
            }
8788
0
            else
8789
0
            {
8790
0
                psOptions->osClipDstDS = osVal;
8791
0
            }
8792
0
        }
8793
8794
0
        auto layers = argParser->present<std::vector<std::string>>("layer");
8795
0
        if (layers)
8796
0
        {
8797
0
            for (const auto &layer : *layers)
8798
0
            {
8799
0
                psOptions->aosLayers.AddString(layer.c_str());
8800
0
            }
8801
0
        }
8802
0
        if (psOptionsForBinary)
8803
0
        {
8804
0
            psOptionsForBinary->eAccessMode = psOptions->eAccessMode;
8805
0
            psOptionsForBinary->osFormat = psOptions->osFormat;
8806
8807
0
            if (!(CPLTestBool(
8808
0
                    psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8809
0
                        "NATIVE_DATA",
8810
0
                        psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8811
0
                            "@NATIVE_DATA", "TRUE")))))
8812
0
            {
8813
0
                psOptions->bNativeData = false;
8814
0
            }
8815
8816
0
            if (psOptions->bNativeData &&
8817
0
                psOptionsForBinary->aosOpenOptions.FetchNameValue(
8818
0
                    "NATIVE_DATA") == nullptr &&
8819
0
                psOptionsForBinary->aosOpenOptions.FetchNameValue(
8820
0
                    "@NATIVE_DATA") == nullptr)
8821
0
            {
8822
0
                psOptionsForBinary->aosOpenOptions.AddString(
8823
0
                    "@NATIVE_DATA=YES");
8824
0
            }
8825
0
        }
8826
8827
0
        return psOptions.release();
8828
0
    }
8829
0
    catch (const std::exception &err)
8830
0
    {
8831
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
8832
0
        if (psOptionsForBinary)
8833
0
            psOptionsForBinary->bShowUsageIfError = true;
8834
0
        return nullptr;
8835
0
    }
8836
0
}
8837
8838
/************************************************************************/
8839
/*                   GDALVectorTranslateOptionsFree()                   */
8840
/************************************************************************/
8841
8842
/**
8843
 * Frees the GDALVectorTranslateOptions struct.
8844
 *
8845
 * @param psOptions the options struct for GDALVectorTranslate().
8846
 * @since GDAL 2.1
8847
 */
8848
8849
void GDALVectorTranslateOptionsFree(GDALVectorTranslateOptions *psOptions)
8850
0
{
8851
0
    delete psOptions;
8852
0
}
8853
8854
/************************************************************************/
8855
/*               GDALVectorTranslateOptionsSetProgress()                */
8856
/************************************************************************/
8857
8858
/**
8859
 * Set a progress function.
8860
 *
8861
 * @param psOptions the options struct for GDALVectorTranslate().
8862
 * @param pfnProgress the progress callback.
8863
 * @param pProgressData the user data for the progress callback.
8864
 *
8865
 * @since GDAL 2.1
8866
 */
8867
8868
void GDALVectorTranslateOptionsSetProgress(
8869
    GDALVectorTranslateOptions *psOptions, GDALProgressFunc pfnProgress,
8870
    void *pProgressData)
8871
0
{
8872
0
    psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
8873
0
    psOptions->pProgressData = pProgressData;
8874
0
    if (pfnProgress == GDALTermProgress)
8875
0
        psOptions->bQuiet = false;
8876
0
}
8877
8878
#undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS