Coverage Report

Created: 2026-04-01 06:20

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