Coverage Report

Created: 2025-08-28 06:57

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