Coverage Report

Created: 2025-06-13 06:18

/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
                {
2787
0
                    psOptions->osFormat = "ESRI Shapefile";
2788
0
                }
2789
0
                else
2790
0
                {
2791
0
                    CPLError(CE_Failure, CPLE_AppDefined,
2792
0
                             "Cannot guess driver for %s", pszDest);
2793
0
                    return nullptr;
2794
0
                }
2795
0
            }
2796
0
            else
2797
0
            {
2798
0
                psOptions->osFormat = aoDrivers[0];
2799
0
            }
2800
0
            CPLDebug("GDAL", "Using %s driver", psOptions->osFormat.c_str());
2801
0
        }
2802
2803
0
        CPLString osOGRCompatFormat(psOptions->osFormat);
2804
        // Special processing for non-unified drivers that have the same name
2805
        // as GDAL and OGR drivers. GMT should become OGR_GMT.
2806
        // Other candidates could be VRT, SDTS and PDS, but they don't
2807
        // have write capabilities. But do the substitution to get a sensible
2808
        // error message
2809
0
        if (EQUAL(osOGRCompatFormat, "GMT") ||
2810
0
            EQUAL(osOGRCompatFormat, "VRT") ||
2811
0
            EQUAL(osOGRCompatFormat, "SDTS") || EQUAL(osOGRCompatFormat, "PDS"))
2812
0
        {
2813
0
            osOGRCompatFormat = "OGR_" + osOGRCompatFormat;
2814
0
        }
2815
0
        poDriver = poDM->GetDriverByName(osOGRCompatFormat);
2816
0
        if (poDriver == nullptr)
2817
0
        {
2818
0
            CPLError(CE_Failure, CPLE_AppDefined, "Unable to find driver `%s'.",
2819
0
                     psOptions->osFormat.c_str());
2820
0
            return nullptr;
2821
0
        }
2822
2823
0
        char **papszDriverMD = poDriver->GetMetadata();
2824
0
        if (!CPLTestBool(
2825
0
                CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")))
2826
0
        {
2827
0
            CPLError(CE_Failure, CPLE_AppDefined,
2828
0
                     "%s driver has no vector capabilities.",
2829
0
                     psOptions->osFormat.c_str());
2830
0
            return nullptr;
2831
0
        }
2832
2833
0
        if (poDriver->CanVectorTranslateFrom(
2834
0
                pszDest, poDS, psOptions->aosArguments.List(), nullptr))
2835
0
        {
2836
0
            return poDriver->VectorTranslateFrom(
2837
0
                pszDest, poDS, psOptions->aosArguments.List(),
2838
0
                psOptions->pfnProgress, psOptions->pProgressData);
2839
0
        }
2840
2841
0
        if (!CPLTestBool(
2842
0
                CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
2843
0
        {
2844
0
            if (CPLTestBool(CSLFetchNameValueDef(
2845
0
                    papszDriverMD, GDAL_DCAP_CREATECOPY, "FALSE")))
2846
0
            {
2847
0
                poODS = GDALVectorTranslateCreateCopy(poDriver, pszDest, poDS,
2848
0
                                                      psOptions.get());
2849
0
                return poODS;
2850
0
            }
2851
2852
0
            CPLError(CE_Failure, CPLE_AppDefined,
2853
0
                     "%s driver does not support data source creation.",
2854
0
                     psOptions->osFormat.c_str());
2855
0
            return nullptr;
2856
0
        }
2857
2858
0
        if (!psOptions->aosDestOpenOptions.empty())
2859
0
        {
2860
0
            CPLError(CE_Warning, CPLE_AppDefined,
2861
0
                     "-doo ignored when creating the output datasource.");
2862
0
        }
2863
2864
        /* --------------------------------------------------------------------
2865
         */
2866
        /*      Special case to improve user experience when translating */
2867
        /*      a datasource with multiple layers into a shapefile. If the */
2868
        /*      user gives a target datasource with .shp and it does not exist,
2869
         */
2870
        /*      the shapefile driver will try to create a file, but this is not
2871
         */
2872
        /*      appropriate because here we have several layers, so create */
2873
        /*      a directory instead. */
2874
        /* --------------------------------------------------------------------
2875
         */
2876
0
        VSIStatBufL sStat;
2877
0
        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
2878
0
            psOptions->osSQLStatement.empty() &&
2879
0
            (psOptions->aosLayers.size() > 1 ||
2880
0
             (psOptions->aosLayers.empty() && poDS->GetLayerCount() > 1)) &&
2881
0
            psOptions->osNewLayerName.empty() &&
2882
0
            EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "SHP") &&
2883
0
            VSIStatL(osDestFilename, &sStat) != 0)
2884
0
        {
2885
0
            if (VSIMkdir(osDestFilename, 0755) != 0)
2886
0
            {
2887
0
                CPLError(CE_Failure, CPLE_AppDefined,
2888
0
                         "Failed to create directory %s\n"
2889
0
                         "for shapefile datastore.",
2890
0
                         osDestFilename.c_str());
2891
0
                return nullptr;
2892
0
            }
2893
0
        }
2894
2895
0
        CPLStringList aosDSCO(psOptions->aosDSCO);
2896
2897
0
        if (!aosDSCO.FetchNameValue("SINGLE_LAYER"))
2898
0
        {
2899
            // Informs the target driver (e.g. JSONFG) if a single layer
2900
            // will be created
2901
0
            const char *pszCOList =
2902
0
                poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
2903
0
            if (pszCOList && strstr(pszCOList, "SINGLE_LAYER") &&
2904
0
                (!psOptions->osSQLStatement.empty() ||
2905
0
                 psOptions->aosLayers.size() == 1 ||
2906
0
                 (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1)))
2907
0
            {
2908
0
                aosDSCO.SetNameValue("SINGLE_LAYER", "YES");
2909
0
            }
2910
0
        }
2911
2912
        /* --------------------------------------------------------------------
2913
         */
2914
        /*      Create the output data source. */
2915
        /* --------------------------------------------------------------------
2916
         */
2917
0
        poODS = poDriver->Create(osDestFilename, 0, 0, 0, GDT_Unknown,
2918
0
                                 aosDSCO.List());
2919
0
        if (poODS == nullptr)
2920
0
        {
2921
0
            CPLError(CE_Failure, CPLE_AppDefined,
2922
0
                     "%s driver failed to create %s",
2923
0
                     psOptions->osFormat.c_str(), osDestFilename.c_str());
2924
0
            return nullptr;
2925
0
        }
2926
0
        bNewDataSource = true;
2927
2928
0
        if (psOptions->bCopyMD)
2929
0
        {
2930
0
            const CPLStringList aosDomains(poDS->GetMetadataDomainList());
2931
0
            for (const char *pszMD : aosDomains)
2932
0
            {
2933
0
                if (char **papszMD = poDS->GetMetadata(pszMD))
2934
0
                    poODS->SetMetadata(papszMD, pszMD);
2935
0
            }
2936
0
        }
2937
0
        for (const auto &[pszKey, pszValue] :
2938
0
             cpl::IterateNameValue(psOptions->aosMetadataOptions))
2939
0
        {
2940
0
            poODS->SetMetadataItem(pszKey, pszValue);
2941
0
        }
2942
2943
        // When writing to GeoJSON and using -nln, set the @NAME layer
2944
        // creation option to avoid the GeoJSON driver to potentially reuse
2945
        // the source feature collection name if the input is also GeoJSON.
2946
0
        if (!psOptions->osNewLayerName.empty() &&
2947
0
            EQUAL(psOptions->osFormat.c_str(), "GeoJSON"))
2948
0
        {
2949
0
            psOptions->aosLCO.SetNameValue("@NAME",
2950
0
                                           psOptions->osNewLayerName.c_str());
2951
0
        }
2952
0
    }
2953
2954
    // Automatically close poODS on error, if it has been created by this
2955
    // method.
2956
0
    GDALDatasetUniquePtr poODSUniquePtr(hDstDS == nullptr ? poODS : nullptr);
2957
2958
    // Some syntaxic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=....
2959
    // source [srclayer] -lco OVERWRITE=YES" work like "ogr2ogr -overwrite
2960
    // PG:dbname=.... source [srclayer]" The former syntax used to work at
2961
    // GDAL 1.1.8 time when it was documented in the PG driver, but was broken
2962
    // starting with GDAL 1.3.2
2963
    // (https://github.com/OSGeo/gdal/commit/29c108a6c9f651dfebae6d1313ba0e707a77c1aa)
2964
    // This could probably be generalized to other drivers that support the
2965
    // OVERWRITE layer creation option, but we'd need to make sure that they
2966
    // just do a DeleteLayer() call. The CARTO driver is an exception regarding
2967
    // that.
2968
0
    if (EQUAL(poODS->GetDriver()->GetDescription(), "PostgreSQL") &&
2969
0
        CPLTestBool(psOptions->aosLCO.FetchNameValueDef("OVERWRITE", "NO")))
2970
0
    {
2971
0
        if (bAppend)
2972
0
        {
2973
0
            CPLError(CE_Failure, CPLE_AppDefined,
2974
0
                     "-append and -lco OVERWRITE=YES are mutually exclusive");
2975
0
            return nullptr;
2976
0
        }
2977
0
        bOverwrite = true;
2978
0
    }
2979
2980
    /* -------------------------------------------------------------------- */
2981
    /*      For random reading                                              */
2982
    /* -------------------------------------------------------------------- */
2983
0
    const bool bRandomLayerReading =
2984
0
        CPL_TO_BOOL(poDS->TestCapability(ODsCRandomLayerRead));
2985
0
    if (bRandomLayerReading && !poODS->TestCapability(ODsCRandomLayerWrite) &&
2986
0
        psOptions->aosLayers.size() != 1 && psOptions->osSQLStatement.empty() &&
2987
0
        !psOptions->bQuiet)
2988
0
    {
2989
0
        CPLError(CE_Warning, CPLE_AppDefined,
2990
0
                 "Input datasource uses random layer reading, but "
2991
0
                 "output datasource does not support random layer writing");
2992
0
    }
2993
2994
0
    if (psOptions->nLayerTransaction < 0)
2995
0
    {
2996
0
        if (bRandomLayerReading)
2997
0
            psOptions->nLayerTransaction = FALSE;
2998
0
        else
2999
0
            psOptions->nLayerTransaction =
3000
0
                !poODS->TestCapability(ODsCTransactions);
3001
0
    }
3002
0
    else if (psOptions->nLayerTransaction && bRandomLayerReading)
3003
0
    {
3004
0
        psOptions->nLayerTransaction = false;
3005
0
    }
3006
3007
    /* -------------------------------------------------------------------- */
3008
    /*      Parse the output SRS definition if possible.                    */
3009
    /* -------------------------------------------------------------------- */
3010
0
    OGR2OGRSpatialReferenceHolder oOutputSRSHolder;
3011
0
    if (!psOptions->osOutputSRSDef.empty())
3012
0
    {
3013
0
        oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());
3014
0
        oOutputSRSHolder.get()->SetAxisMappingStrategy(
3015
0
            OAMS_TRADITIONAL_GIS_ORDER);
3016
0
        if (oOutputSRSHolder.get()->SetFromUserInput(
3017
0
                psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)
3018
0
        {
3019
0
            CPLError(CE_Failure, CPLE_AppDefined,
3020
0
                     "Failed to process SRS definition: %s",
3021
0
                     psOptions->osOutputSRSDef.c_str());
3022
0
            return nullptr;
3023
0
        }
3024
0
        oOutputSRSHolder.get()->SetCoordinateEpoch(
3025
0
            psOptions->dfOutputCoordinateEpoch);
3026
0
    }
3027
3028
    /* -------------------------------------------------------------------- */
3029
    /*      Parse the source SRS definition if possible.                    */
3030
    /* -------------------------------------------------------------------- */
3031
0
    OGRSpatialReference oSourceSRS;
3032
0
    OGRSpatialReference *poSourceSRS = nullptr;
3033
0
    if (!psOptions->osSourceSRSDef.empty())
3034
0
    {
3035
0
        oSourceSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
3036
0
        if (oSourceSRS.SetFromUserInput(psOptions->osSourceSRSDef.c_str()) !=
3037
0
            OGRERR_NONE)
3038
0
        {
3039
0
            CPLError(CE_Failure, CPLE_AppDefined,
3040
0
                     "Failed to process SRS definition: %s",
3041
0
                     psOptions->osSourceSRSDef.c_str());
3042
0
            return nullptr;
3043
0
        }
3044
0
        oSourceSRS.SetCoordinateEpoch(psOptions->dfSourceCoordinateEpoch);
3045
0
        poSourceSRS = &oSourceSRS;
3046
0
    }
3047
3048
    /* -------------------------------------------------------------------- */
3049
    /*      Create a transformation object from the source to               */
3050
    /*      destination coordinate system.                                  */
3051
    /* -------------------------------------------------------------------- */
3052
0
    std::unique_ptr<GCPCoordTransformation> poGCPCoordTrans;
3053
0
    if (psOptions->oGCPs.nGCPCount > 0)
3054
0
    {
3055
0
        poGCPCoordTrans = std::make_unique<GCPCoordTransformation>(
3056
0
            psOptions->oGCPs.nGCPCount, psOptions->oGCPs.pasGCPs,
3057
0
            psOptions->nTransformOrder,
3058
0
            poSourceSRS ? poSourceSRS : oOutputSRSHolder.get());
3059
0
        if (!(poGCPCoordTrans->IsValid()))
3060
0
        {
3061
0
            return nullptr;
3062
0
        }
3063
0
    }
3064
3065
    /* -------------------------------------------------------------------- */
3066
    /*      Create layer setup and transformer objects.                     */
3067
    /* -------------------------------------------------------------------- */
3068
0
    SetupTargetLayer oSetup;
3069
0
    oSetup.m_poSrcDS = poDS;
3070
0
    oSetup.m_poDstDS = poODS;
3071
0
    oSetup.m_papszLCO = psOptions->aosLCO.List();
3072
0
    oSetup.m_poOutputSRS = oOutputSRSHolder.get();
3073
0
    oSetup.m_bTransform = psOptions->bTransform;
3074
0
    oSetup.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
3075
0
    oSetup.m_poUserSourceSRS = poSourceSRS;
3076
0
    oSetup.m_bSelFieldsSet = psOptions->bSelFieldsSet;
3077
0
    oSetup.m_papszSelFields = psOptions->aosSelFields.List();
3078
0
    oSetup.m_bAppend = bAppend;
3079
0
    oSetup.m_bAddMissingFields = psOptions->bAddMissingFields;
3080
0
    oSetup.m_eGType = psOptions->eGType;
3081
0
    oSetup.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
3082
0
    oSetup.m_nCoordDim = psOptions->nCoordDim;
3083
0
    oSetup.m_bOverwrite = bOverwrite;
3084
0
    oSetup.m_papszFieldTypesToString = psOptions->aosFieldTypesToString.List();
3085
0
    oSetup.m_papszMapFieldType = psOptions->aosMapFieldType.List();
3086
0
    oSetup.m_bUnsetFieldWidth = psOptions->bUnsetFieldWidth;
3087
0
    oSetup.m_bExplodeCollections = psOptions->bExplodeCollections;
3088
0
    oSetup.m_pszZField =
3089
0
        psOptions->osZField.empty() ? nullptr : psOptions->osZField.c_str();
3090
0
    oSetup.m_papszFieldMap = psOptions->aosFieldMap.List();
3091
0
    oSetup.m_pszWHERE =
3092
0
        psOptions->osWHERE.empty() ? nullptr : psOptions->osWHERE.c_str();
3093
0
    oSetup.m_bExactFieldNameMatch = psOptions->bExactFieldNameMatch;
3094
0
    oSetup.m_bQuiet = psOptions->bQuiet;
3095
0
    oSetup.m_bForceNullable = psOptions->bForceNullable;
3096
0
    oSetup.m_bResolveDomains = psOptions->bResolveDomains;
3097
0
    oSetup.m_bUnsetDefault = psOptions->bUnsetDefault;
3098
0
    oSetup.m_bUnsetFid = psOptions->bUnsetFid;
3099
0
    oSetup.m_bPreserveFID = psOptions->bPreserveFID;
3100
0
    oSetup.m_bCopyMD = psOptions->bCopyMD;
3101
0
    oSetup.m_bNativeData = psOptions->bNativeData;
3102
0
    oSetup.m_bNewDataSource = bNewDataSource;
3103
0
    oSetup.m_pszCTPipeline = psOptions->osCTPipeline.empty()
3104
0
                                 ? nullptr
3105
0
                                 : psOptions->osCTPipeline.c_str();
3106
0
    oSetup.m_aosCTOptions = psOptions->aosCTOptions;
3107
3108
0
    LayerTranslator oTranslator;
3109
0
    oTranslator.m_poSrcDS = poDS;
3110
0
    oTranslator.m_poODS = poODS;
3111
0
    oTranslator.m_bTransform = psOptions->bTransform;
3112
0
    oTranslator.m_bWrapDateline = psOptions->bWrapDateline;
3113
0
    oTranslator.m_osDateLineOffset =
3114
0
        CPLOPrintf("%g", psOptions->dfDateLineOffset);
3115
0
    oTranslator.m_poOutputSRS = oOutputSRSHolder.get();
3116
0
    oTranslator.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
3117
0
    oTranslator.m_poUserSourceSRS = poSourceSRS;
3118
0
    oTranslator.m_poGCPCoordTrans = poGCPCoordTrans.get();
3119
0
    oTranslator.m_eGType = psOptions->eGType;
3120
0
    oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
3121
0
    oTranslator.m_bMakeValid = psOptions->bMakeValid;
3122
0
    oTranslator.m_bSkipInvalidGeom = psOptions->bSkipInvalidGeom;
3123
0
    oTranslator.m_nCoordDim = psOptions->nCoordDim;
3124
0
    oTranslator.m_eGeomOp = psOptions->eGeomOp;
3125
0
    oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam;
3126
    // Do not emit warning if the user specified directly the clip source geom
3127
0
    if (psOptions->osClipSrcDS.empty())
3128
0
        oTranslator.m_bWarnedClipSrcSRS = true;
3129
0
    oTranslator.m_poClipSrcOri = psOptions->poClipSrc.get();
3130
    // Do not emit warning if the user specified directly the clip dest geom
3131
0
    if (psOptions->osClipDstDS.empty())
3132
0
        oTranslator.m_bWarnedClipDstSRS = true;
3133
0
    oTranslator.m_poClipDstOri = psOptions->poClipDst.get();
3134
0
    oTranslator.m_bExplodeCollections = psOptions->bExplodeCollections;
3135
0
    oTranslator.m_bNativeData = psOptions->bNativeData;
3136
0
    oTranslator.m_nLimit = psOptions->nLimit;
3137
3138
0
    if (psOptions->nGroupTransactions)
3139
0
    {
3140
0
        if (!psOptions->nLayerTransaction)
3141
0
            poODS->StartTransaction(psOptions->bForceTransaction);
3142
0
    }
3143
3144
0
    GIntBig nTotalEventsDone = 0;
3145
3146
    /* -------------------------------------------------------------------- */
3147
    /*      Special case for -sql clause.  No source layers required.       */
3148
    /* -------------------------------------------------------------------- */
3149
0
    int nRetCode = 0;
3150
3151
0
    if (!psOptions->osSQLStatement.empty())
3152
0
    {
3153
        /* Special case: if output=input, then we must likely destroy the */
3154
        /* old table before to avoid transaction issues. */
3155
0
        if (poDS == poODS && !psOptions->osNewLayerName.empty() && bOverwrite)
3156
0
            GetLayerAndOverwriteIfNecessary(
3157
0
                poODS, psOptions->osNewLayerName.c_str(), bOverwrite, nullptr,
3158
0
                nullptr, nullptr);
3159
3160
0
        if (!psOptions->osWHERE.empty())
3161
0
            CPLError(CE_Warning, CPLE_AppDefined,
3162
0
                     "-where clause ignored in combination with -sql.");
3163
0
        if (psOptions->aosLayers.size() > 0)
3164
0
            CPLError(CE_Warning, CPLE_AppDefined,
3165
0
                     "layer names ignored in combination with -sql.");
3166
3167
0
        OGRLayer *poResultSet = poDS->ExecuteSQL(
3168
0
            psOptions->osSQLStatement.c_str(),
3169
0
            (!psOptions->bGeomFieldSet) ? psOptions->poSpatialFilter.get()
3170
0
                                        : nullptr,
3171
0
            psOptions->osDialect.empty() ? nullptr
3172
0
                                         : psOptions->osDialect.c_str());
3173
3174
0
        if (poResultSet != nullptr)
3175
0
        {
3176
0
            if (psOptions->poSpatialFilter && psOptions->bGeomFieldSet)
3177
0
            {
3178
0
                int iGeomField = poResultSet->GetLayerDefn()->GetGeomFieldIndex(
3179
0
                    psOptions->osGeomField.c_str());
3180
0
                if (iGeomField >= 0)
3181
0
                    poResultSet->SetSpatialFilter(
3182
0
                        iGeomField, psOptions->poSpatialFilter.get());
3183
0
                else
3184
0
                    CPLError(CE_Warning, CPLE_AppDefined,
3185
0
                             "Cannot find geometry field %s.",
3186
0
                             psOptions->osGeomField.c_str());
3187
0
            }
3188
3189
0
            GIntBig nCountLayerFeatures = 0;
3190
0
            GDALProgressFunc pfnProgress = nullptr;
3191
0
            void *pProgressArg = nullptr;
3192
0
            if (psOptions->bDisplayProgress)
3193
0
            {
3194
0
                if (bRandomLayerReading)
3195
0
                {
3196
0
                    pfnProgress = psOptions->pfnProgress;
3197
0
                    pProgressArg = psOptions->pProgressData;
3198
0
                }
3199
0
                else if (!poResultSet->TestCapability(OLCFastFeatureCount))
3200
0
                {
3201
0
                    CPLError(CE_Warning, CPLE_AppDefined,
3202
0
                             "Progress turned off as fast feature count is not "
3203
0
                             "available.");
3204
0
                    psOptions->bDisplayProgress = false;
3205
0
                }
3206
0
                else
3207
0
                {
3208
0
                    nCountLayerFeatures = poResultSet->GetFeatureCount();
3209
0
                    pfnProgress = psOptions->pfnProgress;
3210
0
                    pProgressArg = psOptions->pProgressData;
3211
0
                }
3212
0
            }
3213
3214
0
            OGRLayer *poPassedLayer = poResultSet;
3215
0
            if (psOptions->bSplitListFields)
3216
0
            {
3217
0
                auto poLayer = new OGRSplitListFieldLayer(
3218
0
                    poPassedLayer, psOptions->nMaxSplitListSubFields);
3219
0
                poPassedLayer = poLayer;
3220
0
                int nRet = poLayer->BuildLayerDefn(nullptr, nullptr);
3221
0
                if (!nRet)
3222
0
                {
3223
0
                    delete poPassedLayer;
3224
0
                    poPassedLayer = poResultSet;
3225
0
                }
3226
0
            }
3227
3228
            /* --------------------------------------------------------------------
3229
             */
3230
            /*      Special case to improve user experience when translating
3231
             * into   */
3232
            /*      single file shapefile and source has only one layer, and
3233
             * that   */
3234
            /*      the layer name isn't specified */
3235
            /* --------------------------------------------------------------------
3236
             */
3237
0
            VSIStatBufL sStat;
3238
0
            if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3239
0
                psOptions->osNewLayerName.empty() &&
3240
0
                VSIStatL(osDestFilename, &sStat) == 0 &&
3241
0
                VSI_ISREG(sStat.st_mode) &&
3242
0
                (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||
3243
0
                 EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||
3244
0
                 EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))
3245
0
            {
3246
0
                psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);
3247
0
            }
3248
3249
0
            auto psInfo = oSetup.Setup(poPassedLayer,
3250
0
                                       psOptions->osNewLayerName.empty()
3251
0
                                           ? nullptr
3252
0
                                           : psOptions->osNewLayerName.c_str(),
3253
0
                                       psOptions.get(), nTotalEventsDone);
3254
3255
0
            poPassedLayer->ResetReading();
3256
3257
0
            if (psInfo == nullptr ||
3258
0
                !oTranslator.Translate(nullptr, psInfo.get(),
3259
0
                                       nCountLayerFeatures, nullptr,
3260
0
                                       nTotalEventsDone, pfnProgress,
3261
0
                                       pProgressArg, psOptions.get()))
3262
0
            {
3263
0
                CPLError(CE_Failure, CPLE_AppDefined,
3264
0
                         "Terminating translation prematurely after failed\n"
3265
0
                         "translation from sql statement.");
3266
3267
0
                nRetCode = 1;
3268
0
            }
3269
0
            else
3270
0
            {
3271
0
                psInfo->CheckSameCoordinateOperation();
3272
0
            }
3273
3274
0
            if (poPassedLayer != poResultSet)
3275
0
                delete poPassedLayer;
3276
3277
0
            poDS->ReleaseResultSet(poResultSet);
3278
0
        }
3279
0
        else
3280
0
        {
3281
0
            if (CPLGetLastErrorNo() != 0)
3282
0
                nRetCode = 1;
3283
0
        }
3284
0
    }
3285
3286
    /* -------------------------------------------------------------------- */
3287
    /*      Special case for layer interleaving mode.                       */
3288
    /* -------------------------------------------------------------------- */
3289
0
    else if (bRandomLayerReading)
3290
0
    {
3291
0
        if (psOptions->bSplitListFields)
3292
0
        {
3293
0
            CPLError(CE_Failure, CPLE_AppDefined,
3294
0
                     "-splitlistfields not supported in this mode");
3295
0
            return nullptr;
3296
0
        }
3297
3298
        // Make sure to probe all layers in case some are by default invisible
3299
0
        for (const char *pszLayer : psOptions->aosLayers)
3300
0
        {
3301
0
            OGRLayer *poLayer = poDS->GetLayerByName(pszLayer);
3302
3303
0
            if (poLayer == nullptr)
3304
0
            {
3305
0
                CPLError(CE_Failure, CPLE_AppDefined,
3306
0
                         "Couldn't fetch requested layer %s!", pszLayer);
3307
0
                return nullptr;
3308
0
            }
3309
0
        }
3310
3311
0
        const int nSrcLayerCount = poDS->GetLayerCount();
3312
0
        std::vector<AssociatedLayers> pasAssocLayers(nSrcLayerCount);
3313
3314
        /* --------------------------------------------------------------------
3315
         */
3316
        /*      Special case to improve user experience when translating into */
3317
        /*      single file shapefile and source has only one layer, and that */
3318
        /*      the layer name isn't specified */
3319
        /* --------------------------------------------------------------------
3320
         */
3321
0
        VSIStatBufL sStat;
3322
0
        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3323
0
            (psOptions->aosLayers.size() == 1 || nSrcLayerCount == 1) &&
3324
0
            psOptions->osNewLayerName.empty() &&
3325
0
            VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3326
0
            (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||
3327
0
             EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||
3328
0
             EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))
3329
0
        {
3330
0
            psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);
3331
0
        }
3332
3333
0
        GDALProgressFunc pfnProgress = nullptr;
3334
0
        void *pProgressArg = nullptr;
3335
0
        if (!psOptions->bQuiet)
3336
0
        {
3337
0
            pfnProgress = psOptions->pfnProgress;
3338
0
            pProgressArg = psOptions->pProgressData;
3339
0
        }
3340
3341
        /* --------------------------------------------------------------------
3342
         */
3343
        /*      If no target layer specified, use all source layers. */
3344
        /* --------------------------------------------------------------------
3345
         */
3346
0
        if (psOptions->aosLayers.empty())
3347
0
        {
3348
0
            for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3349
0
            {
3350
0
                OGRLayer *poLayer = poDS->GetLayer(iLayer);
3351
3352
0
                if (poLayer == nullptr)
3353
0
                {
3354
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3355
0
                             "Couldn't fetch advertised layer %d!", iLayer);
3356
0
                    return nullptr;
3357
0
                }
3358
3359
0
                psOptions->aosLayers.AddString(poLayer->GetName());
3360
0
            }
3361
0
        }
3362
0
        else
3363
0
        {
3364
0
            const bool bSrcIsOSM = (strcmp(poDS->GetDriverName(), "OSM") == 0);
3365
0
            if (bSrcIsOSM)
3366
0
            {
3367
0
                CPLString osInterestLayers = "SET interest_layers =";
3368
0
                for (int iLayer = 0; iLayer < psOptions->aosLayers.size();
3369
0
                     iLayer++)
3370
0
                {
3371
0
                    if (iLayer != 0)
3372
0
                        osInterestLayers += ",";
3373
0
                    osInterestLayers += psOptions->aosLayers[iLayer];
3374
0
                }
3375
3376
0
                poDS->ExecuteSQL(osInterestLayers.c_str(), nullptr, nullptr);
3377
0
            }
3378
0
        }
3379
3380
        /* --------------------------------------------------------------------
3381
         */
3382
        /*      First pass to set filters. */
3383
        /* --------------------------------------------------------------------
3384
         */
3385
0
        std::map<OGRLayer *, int> oMapLayerToIdx;
3386
3387
0
        for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3388
0
        {
3389
0
            OGRLayer *poLayer = poDS->GetLayer(iLayer);
3390
0
            if (poLayer == nullptr)
3391
0
            {
3392
0
                CPLError(CE_Failure, CPLE_AppDefined,
3393
0
                         "Couldn't fetch advertised layer %d!", iLayer);
3394
0
                return nullptr;
3395
0
            }
3396
3397
0
            pasAssocLayers[iLayer].poSrcLayer = poLayer;
3398
3399
0
            if (psOptions->aosLayers.FindString(poLayer->GetName()) >= 0)
3400
0
            {
3401
0
                if (!psOptions->osWHERE.empty())
3402
0
                {
3403
0
                    if (poLayer->SetAttributeFilter(
3404
0
                            psOptions->osWHERE.c_str()) != OGRERR_NONE)
3405
0
                    {
3406
0
                        CPLError(CE_Failure, CPLE_AppDefined,
3407
0
                                 "SetAttributeFilter(%s) on layer '%s' failed.",
3408
0
                                 psOptions->osWHERE.c_str(),
3409
0
                                 poLayer->GetName());
3410
0
                        if (!psOptions->bSkipFailures)
3411
0
                        {
3412
0
                            return nullptr;
3413
0
                        }
3414
0
                    }
3415
0
                }
3416
3417
0
                ApplySpatialFilter(
3418
0
                    poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3419
0
                    psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3420
0
                                             : nullptr,
3421
0
                    poSourceSRS);
3422
3423
0
                oMapLayerToIdx[poLayer] = iLayer;
3424
0
            }
3425
0
        }
3426
3427
        /* --------------------------------------------------------------------
3428
         */
3429
        /*      Second pass to process features in a interleaved layer mode. */
3430
        /* --------------------------------------------------------------------
3431
         */
3432
0
        bool bTargetLayersHaveBeenCreated = false;
3433
0
        while (true)
3434
0
        {
3435
0
            OGRLayer *poFeatureLayer = nullptr;
3436
0
            auto poFeature = std::unique_ptr<OGRFeature>(poDS->GetNextFeature(
3437
0
                &poFeatureLayer, nullptr, pfnProgress, pProgressArg));
3438
0
            if (poFeature == nullptr)
3439
0
                break;
3440
0
            std::map<OGRLayer *, int>::const_iterator oIter =
3441
0
                oMapLayerToIdx.find(poFeatureLayer);
3442
0
            if (oIter == oMapLayerToIdx.end())
3443
0
            {
3444
                // Feature in a layer that is not a layer of interest.
3445
                // nothing to do
3446
0
            }
3447
0
            else
3448
0
            {
3449
0
                if (!bTargetLayersHaveBeenCreated)
3450
0
                {
3451
                    // We defer target layer creation at the first feature
3452
                    // retrieved since getting the layer definition can be
3453
                    // costly (case of the GMLAS driver) and thus we'd better
3454
                    // taking advantage from the progress callback of
3455
                    // GetNextFeature.
3456
0
                    bTargetLayersHaveBeenCreated = true;
3457
0
                    for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3458
0
                    {
3459
0
                        OGRLayer *poLayer = poDS->GetLayer(iLayer);
3460
0
                        if (psOptions->aosLayers.FindString(
3461
0
                                poLayer->GetName()) < 0)
3462
0
                            continue;
3463
3464
0
                        auto psInfo = oSetup.Setup(
3465
0
                            poLayer,
3466
0
                            psOptions->osNewLayerName.empty()
3467
0
                                ? nullptr
3468
0
                                : psOptions->osNewLayerName.c_str(),
3469
0
                            psOptions.get(), nTotalEventsDone);
3470
3471
0
                        if (psInfo == nullptr && !psOptions->bSkipFailures)
3472
0
                        {
3473
0
                            return nullptr;
3474
0
                        }
3475
3476
0
                        pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3477
0
                    }
3478
0
                    if (nRetCode)
3479
0
                        break;
3480
0
                }
3481
3482
0
                int iLayer = oIter->second;
3483
0
                TargetLayerInfo *psInfo = pasAssocLayers[iLayer].psInfo.get();
3484
0
                if ((psInfo == nullptr ||
3485
0
                     !oTranslator.Translate(poFeature.release(), psInfo, 0,
3486
0
                                            nullptr, nTotalEventsDone, nullptr,
3487
0
                                            nullptr, psOptions.get())) &&
3488
0
                    !psOptions->bSkipFailures)
3489
0
                {
3490
0
                    CPLError(
3491
0
                        CE_Failure, CPLE_AppDefined,
3492
0
                        "Terminating translation prematurely after failed\n"
3493
0
                        "translation of layer %s (use -skipfailures to skip "
3494
0
                        "errors)",
3495
0
                        poFeatureLayer->GetName());
3496
3497
0
                    nRetCode = 1;
3498
0
                    break;
3499
0
                }
3500
0
            }
3501
0
        }  // while true
3502
3503
0
        if (pfnProgress)
3504
0
        {
3505
0
            pfnProgress(1.0, "", pProgressArg);
3506
0
        }
3507
3508
0
        for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3509
0
        {
3510
0
            if (pasAssocLayers[iLayer].psInfo)
3511
0
                pasAssocLayers[iLayer].psInfo->CheckSameCoordinateOperation();
3512
0
        }
3513
3514
0
        if (!bTargetLayersHaveBeenCreated)
3515
0
        {
3516
            // bTargetLayersHaveBeenCreated not used after here.
3517
            // bTargetLayersHaveBeenCreated = true;
3518
0
            for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3519
0
            {
3520
0
                OGRLayer *poLayer = poDS->GetLayer(iLayer);
3521
0
                if (psOptions->aosLayers.FindString(poLayer->GetName()) < 0)
3522
0
                    continue;
3523
3524
0
                auto psInfo =
3525
0
                    oSetup.Setup(poLayer,
3526
0
                                 psOptions->osNewLayerName.empty()
3527
0
                                     ? nullptr
3528
0
                                     : psOptions->osNewLayerName.c_str(),
3529
0
                                 psOptions.get(), nTotalEventsDone);
3530
3531
0
                if (psInfo == nullptr && !psOptions->bSkipFailures)
3532
0
                {
3533
0
                    return nullptr;
3534
0
                }
3535
3536
0
                pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3537
0
            }
3538
0
        }
3539
0
    }
3540
3541
0
    else
3542
0
    {
3543
0
        std::vector<OGRLayer *> apoLayers;
3544
3545
        /* --------------------------------------------------------------------
3546
         */
3547
        /*      Process each data source layer. */
3548
        /* --------------------------------------------------------------------
3549
         */
3550
0
        if (psOptions->aosLayers.empty())
3551
0
        {
3552
0
            const int nLayerCount = poDS->GetLayerCount();
3553
3554
0
            for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3555
0
            {
3556
0
                OGRLayer *poLayer = poDS->GetLayer(iLayer);
3557
3558
0
                if (poLayer == nullptr)
3559
0
                {
3560
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3561
0
                             "Couldn't fetch advertised layer %d!", iLayer);
3562
0
                    return nullptr;
3563
0
                }
3564
0
                if (!poDS->IsLayerPrivate(iLayer))
3565
0
                {
3566
0
                    apoLayers.push_back(poLayer);
3567
0
                }
3568
0
            }
3569
0
        }
3570
        /* --------------------------------------------------------------------
3571
         */
3572
        /*      Process specified data source layers. */
3573
        /* --------------------------------------------------------------------
3574
         */
3575
0
        else
3576
0
        {
3577
3578
0
            for (int iLayer = 0; psOptions->aosLayers[iLayer] != nullptr;
3579
0
                 iLayer++)
3580
0
            {
3581
0
                OGRLayer *poLayer =
3582
0
                    poDS->GetLayerByName(psOptions->aosLayers[iLayer]);
3583
3584
0
                if (poLayer == nullptr)
3585
0
                {
3586
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3587
0
                             "Couldn't fetch requested layer '%s'!",
3588
0
                             psOptions->aosLayers[iLayer]);
3589
0
                    if (!psOptions->bSkipFailures)
3590
0
                    {
3591
0
                        return nullptr;
3592
0
                    }
3593
0
                }
3594
3595
0
                apoLayers.emplace_back(poLayer);
3596
0
            }
3597
0
        }
3598
3599
        /* --------------------------------------------------------------------
3600
         */
3601
        /*      Special case to improve user experience when translating into */
3602
        /*      single file shapefile and source has only one layer, and that */
3603
        /*      the layer name isn't specified */
3604
        /* --------------------------------------------------------------------
3605
         */
3606
0
        VSIStatBufL sStat;
3607
0
        const int nLayerCount = static_cast<int>(apoLayers.size());
3608
0
        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3609
0
            nLayerCount == 1 && psOptions->osNewLayerName.empty() &&
3610
0
            VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3611
0
            (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||
3612
0
             EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||
3613
0
             EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))
3614
0
        {
3615
0
            psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);
3616
0
        }
3617
3618
0
        std::vector<GIntBig> anLayerCountFeatures(nLayerCount);
3619
0
        GIntBig nCountLayersFeatures = 0;
3620
0
        GIntBig nAccCountFeatures = 0;
3621
3622
        /* First pass to apply filters and count all features if necessary */
3623
0
        for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3624
0
        {
3625
0
            OGRLayer *poLayer = apoLayers[iLayer];
3626
0
            if (poLayer == nullptr)
3627
0
                continue;
3628
3629
0
            if (!psOptions->osWHERE.empty())
3630
0
            {
3631
0
                if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=
3632
0
                    OGRERR_NONE)
3633
0
                {
3634
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3635
0
                             "SetAttributeFilter(%s) on layer '%s' failed.",
3636
0
                             psOptions->osWHERE.c_str(), poLayer->GetName());
3637
0
                    if (!psOptions->bSkipFailures)
3638
0
                    {
3639
0
                        return nullptr;
3640
0
                    }
3641
0
                }
3642
0
            }
3643
3644
0
            ApplySpatialFilter(
3645
0
                poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3646
0
                psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3647
0
                                         : nullptr,
3648
0
                poSourceSRS);
3649
3650
0
            if (psOptions->bDisplayProgress)
3651
0
            {
3652
0
                if (!poLayer->TestCapability(OLCFastFeatureCount))
3653
0
                {
3654
0
                    CPLError(CE_Warning, CPLE_NotSupported,
3655
0
                             "Progress turned off as fast feature count is not "
3656
0
                             "available.");
3657
0
                    psOptions->bDisplayProgress = false;
3658
0
                }
3659
0
                else
3660
0
                {
3661
0
                    anLayerCountFeatures[iLayer] = poLayer->GetFeatureCount();
3662
0
                    if (psOptions->nLimit >= 0)
3663
0
                        anLayerCountFeatures[iLayer] = std::min(
3664
0
                            anLayerCountFeatures[iLayer], psOptions->nLimit);
3665
0
                    if (anLayerCountFeatures[iLayer] >= 0 &&
3666
0
                        anLayerCountFeatures[iLayer] <=
3667
0
                            std::numeric_limits<GIntBig>::max() -
3668
0
                                nCountLayersFeatures)
3669
0
                    {
3670
0
                        nCountLayersFeatures += anLayerCountFeatures[iLayer];
3671
0
                    }
3672
0
                    else
3673
0
                    {
3674
0
                        nCountLayersFeatures = 0;
3675
0
                        psOptions->bDisplayProgress = false;
3676
0
                    }
3677
0
                }
3678
0
            }
3679
0
        }
3680
3681
        /* Second pass to do the real job */
3682
0
        for (int iLayer = 0; iLayer < nLayerCount && nRetCode == 0; iLayer++)
3683
0
        {
3684
0
            OGRLayer *poLayer = apoLayers[iLayer];
3685
0
            if (poLayer == nullptr)
3686
0
                continue;
3687
3688
0
            GDALProgressFunc pfnProgress = nullptr;
3689
0
            void *pProgressArg = nullptr;
3690
3691
0
            OGRLayer *poPassedLayer = poLayer;
3692
0
            if (psOptions->bSplitListFields)
3693
0
            {
3694
0
                auto poSLFLayer = new OGRSplitListFieldLayer(
3695
0
                    poPassedLayer, psOptions->nMaxSplitListSubFields);
3696
0
                poPassedLayer = poSLFLayer;
3697
3698
0
                if (psOptions->bDisplayProgress &&
3699
0
                    psOptions->nMaxSplitListSubFields != 1 &&
3700
0
                    nCountLayersFeatures != 0)
3701
0
                {
3702
0
                    pfnProgress = GDALScaledProgress;
3703
0
                    pProgressArg = GDALCreateScaledProgress(
3704
0
                        nAccCountFeatures * 1.0 / nCountLayersFeatures,
3705
0
                        (nAccCountFeatures + anLayerCountFeatures[iLayer] / 2) *
3706
0
                            1.0 / nCountLayersFeatures,
3707
0
                        psOptions->pfnProgress, psOptions->pProgressData);
3708
0
                }
3709
0
                else
3710
0
                {
3711
0
                    pfnProgress = nullptr;
3712
0
                    pProgressArg = nullptr;
3713
0
                }
3714
3715
0
                int nRet =
3716
0
                    poSLFLayer->BuildLayerDefn(pfnProgress, pProgressArg);
3717
0
                if (!nRet)
3718
0
                {
3719
0
                    delete poPassedLayer;
3720
0
                    poPassedLayer = poLayer;
3721
0
                }
3722
3723
0
                if (psOptions->bDisplayProgress)
3724
0
                    GDALDestroyScaledProgress(pProgressArg);
3725
0
                pfnProgress = nullptr;
3726
0
                pProgressArg = nullptr;
3727
0
            }
3728
3729
0
            if (psOptions->bDisplayProgress)
3730
0
            {
3731
0
                if (nCountLayersFeatures != 0)
3732
0
                {
3733
0
                    pfnProgress = GDALScaledProgress;
3734
0
                    GIntBig nStart = 0;
3735
0
                    if (poPassedLayer != poLayer &&
3736
0
                        psOptions->nMaxSplitListSubFields != 1)
3737
0
                        nStart = anLayerCountFeatures[iLayer] / 2;
3738
0
                    pProgressArg = GDALCreateScaledProgress(
3739
0
                        (nAccCountFeatures + nStart) * 1.0 /
3740
0
                            nCountLayersFeatures,
3741
0
                        (nAccCountFeatures + anLayerCountFeatures[iLayer]) *
3742
0
                            1.0 / nCountLayersFeatures,
3743
0
                        psOptions->pfnProgress, psOptions->pProgressData);
3744
0
                }
3745
3746
0
                nAccCountFeatures += anLayerCountFeatures[iLayer];
3747
0
            }
3748
3749
0
            auto psInfo = oSetup.Setup(poPassedLayer,
3750
0
                                       psOptions->osNewLayerName.empty()
3751
0
                                           ? nullptr
3752
0
                                           : psOptions->osNewLayerName.c_str(),
3753
0
                                       psOptions.get(), nTotalEventsDone);
3754
3755
0
            poPassedLayer->ResetReading();
3756
3757
0
            if ((psInfo == nullptr ||
3758
0
                 !oTranslator.Translate(nullptr, psInfo.get(),
3759
0
                                        anLayerCountFeatures[iLayer], nullptr,
3760
0
                                        nTotalEventsDone, pfnProgress,
3761
0
                                        pProgressArg, psOptions.get())) &&
3762
0
                !psOptions->bSkipFailures)
3763
0
            {
3764
0
                CPLError(CE_Failure, CPLE_AppDefined,
3765
0
                         "Terminating translation prematurely after failed\n"
3766
0
                         "translation of layer %s (use -skipfailures to skip "
3767
0
                         "errors)",
3768
0
                         poLayer->GetName());
3769
3770
0
                nRetCode = 1;
3771
0
            }
3772
3773
0
            if (psInfo)
3774
0
                psInfo->CheckSameCoordinateOperation();
3775
3776
0
            if (poPassedLayer != poLayer)
3777
0
                delete poPassedLayer;
3778
3779
0
            if (psOptions->bDisplayProgress)
3780
0
                GDALDestroyScaledProgress(pProgressArg);
3781
0
        }
3782
0
    }
3783
3784
0
    CopyRelationships(poODS, poDS);
3785
3786
    /* -------------------------------------------------------------------- */
3787
    /*      Process DS style table                                          */
3788
    /* -------------------------------------------------------------------- */
3789
3790
0
    poODS->SetStyleTable(poDS->GetStyleTable());
3791
3792
0
    if (psOptions->nGroupTransactions)
3793
0
    {
3794
0
        if (!psOptions->nLayerTransaction)
3795
0
        {
3796
0
            if (nRetCode != 0 && !psOptions->bSkipFailures)
3797
0
                poODS->RollbackTransaction();
3798
0
            else
3799
0
            {
3800
0
                OGRErr eRet = poODS->CommitTransaction();
3801
0
                if (eRet != OGRERR_NONE && eRet != OGRERR_UNSUPPORTED_OPERATION)
3802
0
                {
3803
0
                    nRetCode = 1;
3804
0
                }
3805
0
            }
3806
0
        }
3807
0
    }
3808
3809
    // Note: this guarantees that the file can be opened in a consistent state,
3810
    // without requiring to close poODS, only if the driver declares
3811
    // DCAP_FLUSHCACHE_CONSISTENT_STATE
3812
0
    if (poODS->FlushCache() != CE_None)
3813
0
        nRetCode = 1;
3814
3815
0
    if (nRetCode == 0)
3816
0
    {
3817
0
        if (hDstDS)
3818
0
            return hDstDS;
3819
0
        else
3820
0
            return GDALDataset::ToHandle(poODSUniquePtr.release());
3821
0
    }
3822
3823
0
    return nullptr;
3824
0
}
3825
3826
/************************************************************************/
3827
/*                               SetZ()                                 */
3828
/************************************************************************/
3829
3830
namespace
3831
{
3832
class SetZVisitor : public OGRDefaultGeometryVisitor
3833
{
3834
    double m_dfZ;
3835
3836
  public:
3837
0
    explicit SetZVisitor(double dfZ) : m_dfZ(dfZ)
3838
0
    {
3839
0
    }
3840
3841
    using OGRDefaultGeometryVisitor::visit;
3842
3843
    void visit(OGRPoint *poPoint) override
3844
0
    {
3845
0
        poPoint->setZ(m_dfZ);
3846
0
    }
3847
};
3848
}  // namespace
3849
3850
static void SetZ(OGRGeometry *poGeom, double dfZ)
3851
0
{
3852
0
    if (poGeom == nullptr)
3853
0
        return;
3854
0
    SetZVisitor visitor(dfZ);
3855
0
    poGeom->set3D(true);
3856
0
    poGeom->accept(&visitor);
3857
0
}
3858
3859
/************************************************************************/
3860
/*                       ForceCoordDimension()                          */
3861
/************************************************************************/
3862
3863
static int ForceCoordDimension(int eGType, int nCoordDim)
3864
0
{
3865
0
    if (nCoordDim == 2 && eGType != wkbNone)
3866
0
        return wkbFlatten(eGType);
3867
0
    else if (nCoordDim == 3 && eGType != wkbNone)
3868
0
        return wkbSetZ(wkbFlatten(eGType));
3869
0
    else if (nCoordDim == COORD_DIM_XYM && eGType != wkbNone)
3870
0
        return wkbSetM(wkbFlatten(eGType));
3871
0
    else if (nCoordDim == 4 && eGType != wkbNone)
3872
0
        return OGR_GT_SetModifier(static_cast<OGRwkbGeometryType>(eGType), TRUE,
3873
0
                                  TRUE);
3874
0
    else
3875
0
        return eGType;
3876
0
}
3877
3878
/************************************************************************/
3879
/*                   GetLayerAndOverwriteIfNecessary()                  */
3880
/************************************************************************/
3881
3882
static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
3883
                                                 const char *pszNewLayerName,
3884
                                                 bool bOverwrite,
3885
                                                 bool *pbErrorOccurred,
3886
                                                 bool *pbOverwriteActuallyDone,
3887
                                                 bool *pbAddOverwriteLCO)
3888
0
{
3889
0
    if (pbErrorOccurred)
3890
0
        *pbErrorOccurred = false;
3891
0
    if (pbOverwriteActuallyDone)
3892
0
        *pbOverwriteActuallyDone = false;
3893
0
    if (pbAddOverwriteLCO)
3894
0
        *pbAddOverwriteLCO = false;
3895
3896
    /* GetLayerByName() can instantiate layers that would have been */
3897
    /* 'hidden' otherwise, for example, non-spatial tables in a */
3898
    /* PostGIS-enabled database, so this apparently useless command is */
3899
    /* not useless. (#4012) */
3900
0
    CPLPushErrorHandler(CPLQuietErrorHandler);
3901
0
    OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
3902
0
    CPLPopErrorHandler();
3903
0
    CPLErrorReset();
3904
3905
0
    int iLayer = -1;
3906
0
    if (poDstLayer != nullptr)
3907
0
    {
3908
0
        const int nLayerCount = poDstDS->GetLayerCount();
3909
0
        for (iLayer = 0; iLayer < nLayerCount; iLayer++)
3910
0
        {
3911
0
            OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
3912
0
            if (poLayer == poDstLayer)
3913
0
                break;
3914
0
        }
3915
3916
0
        if (iLayer == nLayerCount)
3917
            /* should not happen with an ideal driver */
3918
0
            poDstLayer = nullptr;
3919
0
    }
3920
3921
    /* -------------------------------------------------------------------- */
3922
    /*      If the user requested overwrite, and we have the layer in       */
3923
    /*      question we need to delete it now so it will get recreated      */
3924
    /*      (overwritten).                                                  */
3925
    /* -------------------------------------------------------------------- */
3926
0
    if (poDstLayer != nullptr && bOverwrite)
3927
0
    {
3928
        /* When using the CARTO driver we don't want to delete the layer if */
3929
        /* it's going to be recreated. Instead we mark it to be overwritten */
3930
        /* when the new creation is requested */
3931
0
        if (poDstDS->GetDriver()->GetMetadataItem(
3932
0
                GDAL_DS_LAYER_CREATIONOPTIONLIST) != nullptr &&
3933
0
            strstr(poDstDS->GetDriver()->GetMetadataItem(
3934
0
                       GDAL_DS_LAYER_CREATIONOPTIONLIST),
3935
0
                   "CARTODBFY") != nullptr)
3936
0
        {
3937
0
            if (pbAddOverwriteLCO)
3938
0
                *pbAddOverwriteLCO = true;
3939
0
            if (pbOverwriteActuallyDone)
3940
0
                *pbOverwriteActuallyDone = true;
3941
0
        }
3942
0
        else if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
3943
0
        {
3944
0
            CPLError(CE_Failure, CPLE_AppDefined,
3945
0
                     "DeleteLayer() failed when overwrite requested.");
3946
0
            if (pbErrorOccurred)
3947
0
                *pbErrorOccurred = true;
3948
0
        }
3949
0
        else
3950
0
        {
3951
0
            if (pbOverwriteActuallyDone)
3952
0
                *pbOverwriteActuallyDone = true;
3953
0
        }
3954
0
        poDstLayer = nullptr;
3955
0
    }
3956
3957
0
    return poDstLayer;
3958
0
}
3959
3960
/************************************************************************/
3961
/*                          ConvertType()                               */
3962
/************************************************************************/
3963
3964
static OGRwkbGeometryType ConvertType(GeomTypeConversion eGeomTypeConversion,
3965
                                      OGRwkbGeometryType eGType)
3966
0
{
3967
0
    OGRwkbGeometryType eRetType = eGType;
3968
3969
0
    if (eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
3970
0
        eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3971
0
    {
3972
0
        eRetType = OGR_GT_GetLinear(eRetType);
3973
0
    }
3974
3975
0
    if (eGeomTypeConversion == GTC_PROMOTE_TO_MULTI ||
3976
0
        eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3977
0
    {
3978
0
        if (eRetType == wkbTriangle || eRetType == wkbTIN ||
3979
0
            eRetType == wkbPolyhedralSurface)
3980
0
        {
3981
0
            eRetType = wkbMultiPolygon;
3982
0
        }
3983
0
        else if (!OGR_GT_IsSubClassOf(eRetType, wkbGeometryCollection))
3984
0
        {
3985
0
            eRetType = OGR_GT_GetCollection(eRetType);
3986
0
        }
3987
0
    }
3988
3989
0
    if (eGeomTypeConversion == GTC_CONVERT_TO_CURVE)
3990
0
        eRetType = OGR_GT_GetCurve(eRetType);
3991
3992
0
    return eRetType;
3993
0
}
3994
3995
/************************************************************************/
3996
/*                        DoFieldTypeConversion()                       */
3997
/************************************************************************/
3998
3999
static void DoFieldTypeConversion(GDALDataset *poDstDS,
4000
                                  OGRFieldDefn &oFieldDefn,
4001
                                  CSLConstList papszFieldTypesToString,
4002
                                  CSLConstList papszMapFieldType,
4003
                                  bool bUnsetFieldWidth, bool bQuiet,
4004
                                  bool bForceNullable, bool bUnsetDefault)
4005
0
{
4006
0
    if (papszFieldTypesToString != nullptr)
4007
0
    {
4008
0
        CPLString osLookupString;
4009
0
        osLookupString.Printf(
4010
0
            "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4011
0
            OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
4012
4013
0
        int iIdx = CSLFindString(papszFieldTypesToString, osLookupString);
4014
0
        if (iIdx < 0)
4015
0
            iIdx = CSLFindString(
4016
0
                papszFieldTypesToString,
4017
0
                OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
4018
0
        if (iIdx < 0)
4019
0
            iIdx = CSLFindString(papszFieldTypesToString, "All");
4020
0
        if (iIdx >= 0)
4021
0
        {
4022
0
            oFieldDefn.SetSubType(OFSTNone);
4023
0
            oFieldDefn.SetType(OFTString);
4024
0
        }
4025
0
    }
4026
0
    else if (papszMapFieldType != nullptr)
4027
0
    {
4028
0
        CPLString osLookupString;
4029
0
        osLookupString.Printf(
4030
0
            "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4031
0
            OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
4032
4033
0
        const char *pszType =
4034
0
            CSLFetchNameValue(papszMapFieldType, osLookupString);
4035
0
        if (pszType == nullptr)
4036
0
            pszType = CSLFetchNameValue(
4037
0
                papszMapFieldType,
4038
0
                OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
4039
0
        if (pszType == nullptr)
4040
0
            pszType = CSLFetchNameValue(papszMapFieldType, "All");
4041
0
        if (pszType != nullptr)
4042
0
        {
4043
0
            int iSubType;
4044
0
            int iType = GetFieldType(pszType, &iSubType);
4045
0
            if (iType >= 0 && iSubType >= 0)
4046
0
            {
4047
0
                oFieldDefn.SetSubType(OFSTNone);
4048
0
                oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
4049
0
                oFieldDefn.SetSubType(static_cast<OGRFieldSubType>(iSubType));
4050
0
                if (iType == OFTInteger)
4051
0
                    oFieldDefn.SetWidth(0);
4052
0
            }
4053
0
        }
4054
0
    }
4055
0
    if (bUnsetFieldWidth)
4056
0
    {
4057
0
        oFieldDefn.SetWidth(0);
4058
0
        oFieldDefn.SetPrecision(0);
4059
0
    }
4060
0
    if (bForceNullable)
4061
0
        oFieldDefn.SetNullable(TRUE);
4062
0
    if (bUnsetDefault)
4063
0
        oFieldDefn.SetDefault(nullptr);
4064
4065
0
    const auto poDstDriver = poDstDS->GetDriver();
4066
0
    const char *pszCreationFieldDataTypes =
4067
0
        poDstDriver
4068
0
            ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES)
4069
0
            : nullptr;
4070
0
    const char *pszCreationFieldDataSubtypes =
4071
0
        poDstDriver
4072
0
            ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES)
4073
0
            : nullptr;
4074
0
    if (pszCreationFieldDataTypes &&
4075
0
        strstr(pszCreationFieldDataTypes,
4076
0
               OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == nullptr)
4077
0
    {
4078
0
        if (pszCreationFieldDataSubtypes &&
4079
0
            (oFieldDefn.GetType() == OFTIntegerList ||
4080
0
             oFieldDefn.GetType() == OFTInteger64List ||
4081
0
             oFieldDefn.GetType() == OFTRealList ||
4082
0
             oFieldDefn.GetType() == OFTStringList) &&
4083
0
            strstr(pszCreationFieldDataSubtypes, "JSON"))
4084
0
        {
4085
0
            if (!bQuiet)
4086
0
            {
4087
0
                CPLError(
4088
0
                    CE_Warning, CPLE_AppDefined,
4089
0
                    "The output driver does not seem to natively support %s "
4090
0
                    "type for field %s. Converting it to String(JSON) instead. "
4091
0
                    "-mapFieldType can be used to control field type "
4092
0
                    "conversion.",
4093
0
                    OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4094
0
                    oFieldDefn.GetNameRef());
4095
0
            }
4096
0
            oFieldDefn.SetSubType(OFSTNone);
4097
0
            oFieldDefn.SetType(OFTString);
4098
0
            oFieldDefn.SetSubType(OFSTJSON);
4099
0
        }
4100
0
        else if (oFieldDefn.GetType() == OFTInteger64)
4101
0
        {
4102
0
            if (!bQuiet)
4103
0
            {
4104
0
                CPLError(
4105
0
                    CE_Warning, CPLE_AppDefined,
4106
0
                    "The output driver does not seem to natively support %s "
4107
0
                    "type for field %s. Converting it to Real instead. "
4108
0
                    "-mapFieldType can be used to control field type "
4109
0
                    "conversion.",
4110
0
                    OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4111
0
                    oFieldDefn.GetNameRef());
4112
0
            }
4113
0
            oFieldDefn.SetType(OFTReal);
4114
0
        }
4115
0
        else if (oFieldDefn.GetType() == OFTDateTime && poDstDriver &&
4116
0
                 EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile"))
4117
0
        {
4118
            // Just be silent. The shapefile driver will itself emit a
4119
            // warning mentioning it converts DateTime to String.
4120
0
        }
4121
0
        else if (!bQuiet)
4122
0
        {
4123
0
            CPLError(
4124
0
                CE_Warning, CPLE_AppDefined,
4125
0
                "The output driver does not natively support %s type for "
4126
0
                "field %s. Misconversion can happen. "
4127
0
                "-mapFieldType can be used to control field type conversion.",
4128
0
                OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4129
0
                oFieldDefn.GetNameRef());
4130
0
        }
4131
0
    }
4132
0
    else if (!pszCreationFieldDataTypes)
4133
0
    {
4134
        // All drivers supporting OFTInteger64 should advertise it theoretically
4135
0
        if (oFieldDefn.GetType() == OFTInteger64)
4136
0
        {
4137
0
            if (!bQuiet)
4138
0
            {
4139
0
                CPLError(CE_Warning, CPLE_AppDefined,
4140
0
                         "The output driver does not seem to natively support "
4141
0
                         "%s type "
4142
0
                         "for field %s. Converting it to Real instead. "
4143
0
                         "-mapFieldType can be used to control field type "
4144
0
                         "conversion.",
4145
0
                         OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4146
0
                         oFieldDefn.GetNameRef());
4147
0
            }
4148
0
            oFieldDefn.SetType(OFTReal);
4149
0
        }
4150
0
    }
4151
0
}
4152
4153
/************************************************************************/
4154
/*                        GetArrowGeomFieldIndex()                      */
4155
/************************************************************************/
4156
4157
static int GetArrowGeomFieldIndex(const struct ArrowSchema *psLayerSchema,
4158
                                  const char *pszFieldName)
4159
0
{
4160
0
    if (strcmp(psLayerSchema->format, "+s") == 0)  // struct
4161
0
    {
4162
0
        for (int i = 0; i < psLayerSchema->n_children; ++i)
4163
0
        {
4164
0
            const auto psSchema = psLayerSchema->children[i];
4165
0
            if (strcmp(psSchema->format, "z") == 0)  // binary
4166
0
            {
4167
0
                if (strcmp(psSchema->name, pszFieldName) == 0)
4168
0
                {
4169
0
                    return i;
4170
0
                }
4171
0
                else
4172
0
                {
4173
                    // Check if ARROW:extension:name = ogc.wkb or geoarrow.wkb
4174
0
                    const char *pabyMetadata = psSchema->metadata;
4175
0
                    if (pabyMetadata)
4176
0
                    {
4177
0
                        const auto oMetadata =
4178
0
                            OGRParseArrowMetadata(pabyMetadata);
4179
0
                        auto oIter = oMetadata.find(ARROW_EXTENSION_NAME_KEY);
4180
0
                        if (oIter != oMetadata.end() &&
4181
0
                            (oIter->second == EXTENSION_NAME_OGC_WKB ||
4182
0
                             oIter->second == EXTENSION_NAME_GEOARROW_WKB))
4183
0
                        {
4184
0
                            return i;
4185
0
                        }
4186
0
                    }
4187
0
                }
4188
0
            }
4189
0
        }
4190
0
    }
4191
0
    return -1;
4192
0
}
4193
4194
/************************************************************************/
4195
/*                        BuildGetArrowStreamOptions()                  */
4196
/************************************************************************/
4197
4198
static CPLStringList
4199
BuildGetArrowStreamOptions(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,
4200
                           const GDALVectorTranslateOptions *psOptions,
4201
                           bool bPreserveFID)
4202
0
{
4203
0
    CPLStringList aosOptionsGetArrowStream;
4204
0
    aosOptionsGetArrowStream.SetNameValue("SILENCE_GET_SCHEMA_ERROR", "YES");
4205
0
    aosOptionsGetArrowStream.SetNameValue("GEOMETRY_ENCODING", "WKB");
4206
0
    if (!bPreserveFID)
4207
0
        aosOptionsGetArrowStream.SetNameValue("INCLUDE_FID", "NO");
4208
0
    if (psOptions->nLimit >= 0)
4209
0
    {
4210
0
        aosOptionsGetArrowStream.SetNameValue(
4211
0
            "MAX_FEATURES_IN_BATCH",
4212
0
            CPLSPrintf(CPL_FRMT_GIB,
4213
0
                       std::min<GIntBig>(psOptions->nLimit,
4214
0
                                         (psOptions->nGroupTransactions > 0
4215
0
                                              ? psOptions->nGroupTransactions
4216
0
                                              : 65536))));
4217
0
    }
4218
0
    else if (psOptions->nGroupTransactions > 0)
4219
0
    {
4220
0
        aosOptionsGetArrowStream.SetNameValue(
4221
0
            "MAX_FEATURES_IN_BATCH",
4222
0
            CPLSPrintf("%d", psOptions->nGroupTransactions));
4223
0
    }
4224
4225
0
    auto poSrcDS = poSrcLayer->GetDataset();
4226
0
    auto poDstDS = poDstLayer->GetDataset();
4227
0
    if (poSrcDS && poDstDS)
4228
0
    {
4229
0
        auto poSrcDriver = poSrcDS->GetDriver();
4230
0
        auto poDstDriver = poDstDS->GetDriver();
4231
4232
0
        const auto IsArrowNativeDriver = [](GDALDriver *poDriver)
4233
0
        {
4234
0
            return EQUAL(poDriver->GetDescription(), "ARROW") ||
4235
0
                   EQUAL(poDriver->GetDescription(), "PARQUET") ||
4236
0
                   EQUAL(poDriver->GetDescription(), "ADBC");
4237
0
        };
4238
4239
0
        if (poSrcDriver && poDstDriver && !IsArrowNativeDriver(poSrcDriver) &&
4240
0
            !IsArrowNativeDriver(poDstDriver))
4241
0
        {
4242
            // For non-Arrow-native drivers, request DateTime as string, to
4243
            // allow mix of timezones
4244
0
            aosOptionsGetArrowStream.SetNameValue(GAS_OPT_DATETIME_AS_STRING,
4245
0
                                                  "YES");
4246
0
        }
4247
0
    }
4248
4249
0
    return aosOptionsGetArrowStream;
4250
0
}
4251
4252
/************************************************************************/
4253
/*                 SetupTargetLayer::CanUseWriteArrowBatch()            */
4254
/************************************************************************/
4255
4256
bool SetupTargetLayer::CanUseWriteArrowBatch(
4257
    OGRLayer *poSrcLayer, OGRLayer *poDstLayer, bool bJustCreatedLayer,
4258
    const GDALVectorTranslateOptions *psOptions, bool bPreserveFID,
4259
    bool &bError, OGRArrowArrayStream &streamSrc)
4260
0
{
4261
0
    bError = false;
4262
4263
    // Check if we can use the Arrow interface to get and write features
4264
    // as it will be faster if the input driver has a fast
4265
    // implementation of GetArrowStream().
4266
    // We also can only do that only if using ogr2ogr without options that
4267
    // alter features.
4268
    // OGR2OGR_USE_ARROW_API config option is mostly for testing purposes
4269
    // or as a safety belt if things turned bad...
4270
0
    bool bUseWriteArrowBatch = false;
4271
0
    if (((poSrcLayer->TestCapability(OLCFastGetArrowStream) &&
4272
          // As we don't control the input array size when the input or output
4273
          // drivers are Arrow/Parquet (as they don't use the generic
4274
          // implementation), we can't guarantee that ROW_GROUP_SIZE/BATCH_SIZE
4275
          // layer creation options will be honored.
4276
0
          !psOptions->aosLCO.FetchNameValue("ROW_GROUP_SIZE") &&
4277
0
          !psOptions->aosLCO.FetchNameValue("BATCH_SIZE") &&
4278
0
          CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "YES"))) ||
4279
0
         CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "NO"))) &&
4280
0
        !psOptions->bUpsert && !psOptions->bSkipFailures &&
4281
0
        !psOptions->poClipSrc && !psOptions->poClipDst &&
4282
0
        psOptions->oGCPs.nGCPCount == 0 && !psOptions->bWrapDateline &&
4283
0
        !m_papszSelFields && !m_bAddMissingFields &&
4284
0
        m_eGType == GEOMTYPE_UNCHANGED && psOptions->eGeomOp == GEOMOP_NONE &&
4285
0
        m_eGeomTypeConversion == GTC_DEFAULT && m_nCoordDim < 0 &&
4286
0
        !m_papszFieldTypesToString && !m_papszMapFieldType &&
4287
0
        !m_bUnsetFieldWidth && !m_bExplodeCollections && !m_pszZField &&
4288
0
        m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains &&
4289
0
        !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID &&
4290
0
        psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN &&
4291
0
        !psOptions->bMakeValid && !psOptions->bSkipInvalidGeom)
4292
0
    {
4293
0
        if (psOptions->bTransform)
4294
0
        {
4295
            // To simplify implementation for now
4296
0
            if (poSrcLayer->GetLayerDefn()->GetGeomFieldCount() != 1 ||
4297
0
                poDstLayer->GetLayerDefn()->GetGeomFieldCount() != 1)
4298
0
            {
4299
0
                return false;
4300
0
            }
4301
0
            const auto poSrcSRS = m_poUserSourceSRS ? m_poUserSourceSRS
4302
0
                                                    : poSrcLayer->GetLayerDefn()
4303
0
                                                          ->GetGeomFieldDefn(0)
4304
0
                                                          ->GetSpatialRef();
4305
0
            if (!OGRGeometryFactory::isTransformWithOptionsRegularTransform(
4306
0
                    poSrcSRS, m_poOutputSRS, nullptr))
4307
0
            {
4308
0
                return false;
4309
0
            }
4310
0
        }
4311
4312
0
        const CPLStringList aosGetArrowStreamOptions(BuildGetArrowStreamOptions(
4313
0
            poSrcLayer, poDstLayer, psOptions, bPreserveFID));
4314
0
        if (poSrcLayer->GetArrowStream(streamSrc.get(),
4315
0
                                       aosGetArrowStreamOptions.List()))
4316
0
        {
4317
0
            struct ArrowSchema schemaSrc;
4318
0
            if (streamSrc.get_schema(&schemaSrc) == 0)
4319
0
            {
4320
0
                if (psOptions->bTransform &&
4321
0
                    GetArrowGeomFieldIndex(&schemaSrc,
4322
0
                                           poSrcLayer->GetGeometryColumn()) < 0)
4323
0
                {
4324
0
                    schemaSrc.release(&schemaSrc);
4325
0
                    streamSrc.clear();
4326
0
                    return false;
4327
0
                }
4328
4329
0
                std::string osErrorMsg;
4330
0
                if (poDstLayer->IsArrowSchemaSupported(&schemaSrc, nullptr,
4331
0
                                                       osErrorMsg))
4332
0
                {
4333
0
                    const OGRFeatureDefn *poSrcFDefn =
4334
0
                        poSrcLayer->GetLayerDefn();
4335
0
                    const OGRFeatureDefn *poDstFDefn =
4336
0
                        poDstLayer->GetLayerDefn();
4337
0
                    if (bJustCreatedLayer && poDstFDefn &&
4338
0
                        poDstFDefn->GetFieldCount() == 0 &&
4339
0
                        poDstFDefn->GetGeomFieldCount() ==
4340
0
                            poSrcFDefn->GetGeomFieldCount())
4341
0
                    {
4342
                        // Create output fields using CreateFieldFromArrowSchema()
4343
0
                        for (int i = 0; i < schemaSrc.n_children; ++i)
4344
0
                        {
4345
0
                            const char *pszFieldName =
4346
0
                                schemaSrc.children[i]->name;
4347
4348
0
                            const auto iSrcField =
4349
0
                                poSrcFDefn->GetFieldIndex(pszFieldName);
4350
0
                            if (iSrcField >= 0)
4351
0
                            {
4352
0
                                const auto poSrcFieldDefn =
4353
0
                                    poSrcFDefn->GetFieldDefn(iSrcField);
4354
                                // Create field domain in output dataset if not already existing.
4355
0
                                const std::string osDomainName(
4356
0
                                    poSrcFieldDefn->GetDomainName());
4357
0
                                if (!osDomainName.empty())
4358
0
                                {
4359
0
                                    if (m_poDstDS->TestCapability(
4360
0
                                            ODsCAddFieldDomain) &&
4361
0
                                        m_poDstDS->GetFieldDomain(
4362
0
                                            osDomainName) == nullptr)
4363
0
                                    {
4364
0
                                        const auto poSrcDomain =
4365
0
                                            m_poSrcDS->GetFieldDomain(
4366
0
                                                osDomainName);
4367
0
                                        if (poSrcDomain)
4368
0
                                        {
4369
0
                                            std::string failureReason;
4370
0
                                            if (!m_poDstDS->AddFieldDomain(
4371
0
                                                    std::unique_ptr<
4372
0
                                                        OGRFieldDomain>(
4373
0
                                                        poSrcDomain->Clone()),
4374
0
                                                    failureReason))
4375
0
                                            {
4376
0
                                                CPLDebug("OGR2OGR",
4377
0
                                                         "Cannot create domain "
4378
0
                                                         "%s: %s",
4379
0
                                                         osDomainName.c_str(),
4380
0
                                                         failureReason.c_str());
4381
0
                                            }
4382
0
                                        }
4383
0
                                        else
4384
0
                                        {
4385
0
                                            CPLDebug("OGR2OGR",
4386
0
                                                     "Cannot find domain %s in "
4387
0
                                                     "source dataset",
4388
0
                                                     osDomainName.c_str());
4389
0
                                        }
4390
0
                                    }
4391
0
                                }
4392
0
                            }
4393
4394
0
                            if (!EQUAL(pszFieldName, "OGC_FID") &&
4395
0
                                !EQUAL(pszFieldName, "wkb_geometry") &&
4396
0
                                !EQUAL(pszFieldName,
4397
0
                                       poSrcLayer->GetFIDColumn()) &&
4398
0
                                poSrcFDefn->GetGeomFieldIndex(pszFieldName) <
4399
0
                                    0 &&
4400
0
                                !poDstLayer->CreateFieldFromArrowSchema(
4401
0
                                    schemaSrc.children[i], nullptr))
4402
0
                            {
4403
0
                                CPLError(CE_Failure, CPLE_AppDefined,
4404
0
                                         "Cannot create field %s",
4405
0
                                         pszFieldName);
4406
0
                                schemaSrc.release(&schemaSrc);
4407
0
                                streamSrc.clear();
4408
0
                                return false;
4409
0
                            }
4410
0
                        }
4411
0
                        bUseWriteArrowBatch = true;
4412
0
                    }
4413
0
                    else if (!bJustCreatedLayer)
4414
0
                    {
4415
                        // If the layer already exist, get its schema, and
4416
                        // check that it looks to be the same as the source
4417
                        // one
4418
0
                        struct ArrowArrayStream streamDst;
4419
0
                        if (poDstLayer->GetArrowStream(
4420
0
                                &streamDst, aosGetArrowStreamOptions.List()))
4421
0
                        {
4422
0
                            struct ArrowSchema schemaDst;
4423
0
                            if (streamDst.get_schema(&streamDst, &schemaDst) ==
4424
0
                                0)
4425
0
                            {
4426
0
                                if (schemaDst.n_children ==
4427
0
                                    schemaSrc.n_children)
4428
0
                                {
4429
0
                                    bUseWriteArrowBatch = true;
4430
0
                                }
4431
0
                                schemaDst.release(&schemaDst);
4432
0
                            }
4433
0
                            streamDst.release(&streamDst);
4434
0
                        }
4435
0
                    }
4436
0
                    if (bUseWriteArrowBatch)
4437
0
                    {
4438
0
                        CPLDebug("OGR2OGR", "Using WriteArrowBatch()");
4439
0
                    }
4440
0
                }
4441
0
                else
4442
0
                {
4443
0
                    CPLDebug("OGR2OGR",
4444
0
                             "Cannot use WriteArrowBatch() because "
4445
0
                             "input layer schema is not supported by output "
4446
0
                             "layer: %s",
4447
0
                             osErrorMsg.c_str());
4448
0
                }
4449
0
                schemaSrc.release(&schemaSrc);
4450
0
            }
4451
0
            if (!bUseWriteArrowBatch)
4452
0
                streamSrc.clear();
4453
0
        }
4454
0
    }
4455
0
    return bUseWriteArrowBatch;
4456
0
}
4457
4458
/************************************************************************/
4459
/*                   SetupTargetLayer::Setup()                          */
4460
/************************************************************************/
4461
4462
std::unique_ptr<TargetLayerInfo>
4463
SetupTargetLayer::Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
4464
                        GDALVectorTranslateOptions *psOptions,
4465
                        GIntBig &nTotalEventsDone)
4466
0
{
4467
0
    int eGType = m_eGType;
4468
0
    bool bPreserveFID = m_bPreserveFID;
4469
0
    bool bAppend = m_bAppend;
4470
4471
0
    if (pszNewLayerName == nullptr)
4472
0
        pszNewLayerName = poSrcLayer->GetName();
4473
4474
    /* -------------------------------------------------------------------- */
4475
    /*      Get other info.                                                 */
4476
    /* -------------------------------------------------------------------- */
4477
0
    OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
4478
4479
    /* -------------------------------------------------------------------- */
4480
    /*      Find requested geometry fields.                                 */
4481
    /* -------------------------------------------------------------------- */
4482
0
    std::vector<int> anRequestedGeomFields;
4483
0
    const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
4484
0
    if (m_bSelFieldsSet && !bAppend)
4485
0
    {
4486
0
        for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4487
0
             iField++)
4488
0
        {
4489
0
            int iSrcField = poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4490
0
            if (iSrcField >= 0)
4491
0
            {
4492
                /* do nothing */
4493
0
            }
4494
0
            else
4495
0
            {
4496
0
                iSrcField =
4497
0
                    poSrcFDefn->GetGeomFieldIndex(m_papszSelFields[iField]);
4498
0
                if (iSrcField >= 0)
4499
0
                {
4500
0
                    anRequestedGeomFields.push_back(iSrcField);
4501
0
                }
4502
0
                else
4503
0
                {
4504
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4505
0
                             "Field '%s' not found in source layer.",
4506
0
                             m_papszSelFields[iField]);
4507
0
                    if (!psOptions->bSkipFailures)
4508
0
                        return nullptr;
4509
0
                }
4510
0
            }
4511
0
        }
4512
4513
0
        if (anRequestedGeomFields.size() > 1 &&
4514
0
            !m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4515
0
        {
4516
0
            CPLError(CE_Failure, CPLE_AppDefined,
4517
0
                     "Several geometry fields requested, but output "
4518
0
                     "datasource does not support multiple geometry "
4519
0
                     "fields.");
4520
0
            if (!psOptions->bSkipFailures)
4521
0
                return nullptr;
4522
0
            else
4523
0
                anRequestedGeomFields.resize(0);
4524
0
        }
4525
0
    }
4526
4527
0
    const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
4528
0
    if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
4529
0
    {
4530
0
        if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())
4531
0
            poOutputSRS = poSrcLayer->GetSpatialRef();
4532
0
        else if (anRequestedGeomFields.size() == 1)
4533
0
        {
4534
0
            int iSrcGeomField = anRequestedGeomFields[0];
4535
0
            poOutputSRS =
4536
0
                poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetSpatialRef();
4537
0
        }
4538
0
    }
4539
4540
0
    int iSrcZField = -1;
4541
0
    if (m_pszZField != nullptr)
4542
0
    {
4543
0
        iSrcZField = poSrcFDefn->GetFieldIndex(m_pszZField);
4544
0
        if (iSrcZField < 0)
4545
0
        {
4546
0
            CPLError(CE_Warning, CPLE_AppDefined,
4547
0
                     "zfield '%s' does not exist in layer %s", m_pszZField,
4548
0
                     poSrcLayer->GetName());
4549
0
        }
4550
0
    }
4551
4552
    /* -------------------------------------------------------------------- */
4553
    /*      Find the layer.                                                 */
4554
    /* -------------------------------------------------------------------- */
4555
4556
0
    bool bErrorOccurred;
4557
0
    bool bOverwriteActuallyDone;
4558
0
    bool bAddOverwriteLCO;
4559
0
    OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(
4560
0
        m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,
4561
0
        &bOverwriteActuallyDone, &bAddOverwriteLCO);
4562
0
    const bool bJustCreatedLayer = (poDstLayer == nullptr);
4563
0
    if (bErrorOccurred)
4564
0
        return nullptr;
4565
4566
    /* -------------------------------------------------------------------- */
4567
    /*      If the layer does not exist, then create it.                    */
4568
    /* -------------------------------------------------------------------- */
4569
0
    if (poDstLayer == nullptr)
4570
0
    {
4571
0
        if (!m_poDstDS->TestCapability(ODsCCreateLayer))
4572
0
        {
4573
0
            CPLError(
4574
0
                CE_Failure, CPLE_AppDefined,
4575
0
                "Layer '%s' does not already exist in the output dataset, and "
4576
0
                "cannot be created by the output driver.",
4577
0
                pszNewLayerName);
4578
0
            return nullptr;
4579
0
        }
4580
4581
0
        bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);
4582
0
        if (!bForceGType)
4583
0
        {
4584
0
            if (anRequestedGeomFields.empty())
4585
0
            {
4586
0
                eGType = poSrcFDefn->GetGeomType();
4587
0
            }
4588
0
            else if (anRequestedGeomFields.size() == 1)
4589
0
            {
4590
0
                int iSrcGeomField = anRequestedGeomFields[0];
4591
0
                eGType = poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetType();
4592
0
            }
4593
0
            else
4594
0
            {
4595
0
                eGType = wkbNone;
4596
0
            }
4597
4598
0
            bool bHasZ =
4599
0
                CPL_TO_BOOL(wkbHasZ(static_cast<OGRwkbGeometryType>(eGType)));
4600
0
            eGType = ConvertType(m_eGeomTypeConversion,
4601
0
                                 static_cast<OGRwkbGeometryType>(eGType));
4602
4603
0
            if (m_bExplodeCollections)
4604
0
            {
4605
0
                const OGRwkbGeometryType eFGType = wkbFlatten(eGType);
4606
0
                if (eFGType == wkbMultiPoint)
4607
0
                {
4608
0
                    eGType = wkbPoint;
4609
0
                }
4610
0
                else if (eFGType == wkbMultiLineString)
4611
0
                {
4612
0
                    eGType = wkbLineString;
4613
0
                }
4614
0
                else if (eFGType == wkbMultiPolygon)
4615
0
                {
4616
0
                    eGType = wkbPolygon;
4617
0
                }
4618
0
                else if (eFGType == wkbGeometryCollection ||
4619
0
                         eFGType == wkbMultiCurve || eFGType == wkbMultiSurface)
4620
0
                {
4621
0
                    eGType = wkbUnknown;
4622
0
                }
4623
0
            }
4624
4625
0
            if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))
4626
0
                eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));
4627
0
        }
4628
4629
0
        eGType = ForceCoordDimension(eGType, m_nCoordDim);
4630
4631
0
        CPLErrorReset();
4632
4633
0
        char **papszLCOTemp = CSLDuplicate(m_papszLCO);
4634
0
        const char *pszDestCreationOptions =
4635
0
            m_poDstDS->GetDriver()->GetMetadataItem(
4636
0
                GDAL_DS_LAYER_CREATIONOPTIONLIST);
4637
4638
0
        int eGCreateLayerType = eGType;
4639
0
        if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4640
0
            m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4641
0
        {
4642
0
            eGCreateLayerType = wkbNone;
4643
0
        }
4644
        // If the source layer has a single geometry column that is not nullable
4645
        // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it
4646
        // so as to be able to set the not null constraint (if the driver
4647
        // supports it) and that the output driver has no GEOMETRY_NULLABLE
4648
        // layer creation option. Same if the source geometry column has a non
4649
        // empty name that is not overridden, and that the output driver has no
4650
        // GEOMETRY_NAME layer creation option, but no LAUNDER option (if
4651
        // laundering is available, then we might want to launder the geometry
4652
        // column name as well)
4653
0
        else if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4654
0
                 nSrcGeomFieldCount == 1 &&
4655
0
                 m_poDstDS->TestCapability(
4656
0
                     ODsCCreateGeomFieldAfterCreateLayer) &&
4657
0
                 ((!poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4658
0
                   CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") ==
4659
0
                       nullptr &&
4660
0
                   (pszDestCreationOptions == nullptr ||
4661
0
                    strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") !=
4662
0
                        nullptr) &&
4663
0
                   !m_bForceNullable) ||
4664
0
                  (poSrcLayer->GetGeometryColumn() != nullptr &&
4665
0
                   CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&
4666
0
                   !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&
4667
0
                   (pszDestCreationOptions == nullptr ||
4668
0
                    strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==
4669
0
                        nullptr ||
4670
0
                    strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&
4671
0
                   poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <
4672
0
                       0)))
4673
0
        {
4674
0
            anRequestedGeomFields.push_back(0);
4675
0
            eGCreateLayerType = wkbNone;
4676
0
        }
4677
0
        else if (anRequestedGeomFields.size() == 1 &&
4678
0
                 m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4679
0
        {
4680
0
            eGCreateLayerType = wkbNone;
4681
0
        }
4682
4683
0
        OGRGeomCoordinatePrecision oCoordPrec;
4684
0
        std::string osGeomFieldName;
4685
0
        bool bGeomFieldNullable = true;
4686
4687
0
        {
4688
0
            int iSrcGeomField = -1;
4689
0
            if (anRequestedGeomFields.empty() &&
4690
0
                (nSrcGeomFieldCount == 1 ||
4691
0
                 (!m_poDstDS->TestCapability(
4692
0
                      ODsCCreateGeomFieldAfterCreateLayer) &&
4693
0
                  nSrcGeomFieldCount > 1)))
4694
0
            {
4695
0
                iSrcGeomField = 0;
4696
0
            }
4697
0
            else if (anRequestedGeomFields.size() == 1)
4698
0
            {
4699
0
                iSrcGeomField = anRequestedGeomFields[0];
4700
0
            }
4701
4702
0
            if (iSrcGeomField >= 0)
4703
0
            {
4704
0
                const auto poSrcGeomFieldDefn =
4705
0
                    poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);
4706
0
                if (!psOptions->bUnsetCoordPrecision)
4707
0
                {
4708
0
                    oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()
4709
0
                                     .ConvertToOtherSRS(
4710
0
                                         poSrcGeomFieldDefn->GetSpatialRef(),
4711
0
                                         poOutputSRS);
4712
0
                }
4713
4714
0
                bGeomFieldNullable =
4715
0
                    CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());
4716
4717
0
                const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();
4718
0
                if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&
4719
0
                    poSrcFDefn->GetFieldIndex(pszGFldName) < 0)
4720
0
                {
4721
0
                    osGeomFieldName = pszGFldName;
4722
4723
                    // Use source geometry field name as much as possible
4724
0
                    if (eGType != wkbNone && pszDestCreationOptions &&
4725
0
                        strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=
4726
0
                            nullptr &&
4727
0
                        CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==
4728
0
                            nullptr)
4729
0
                    {
4730
0
                        papszLCOTemp = CSLSetNameValue(
4731
0
                            papszLCOTemp, "GEOMETRY_NAME", pszGFldName);
4732
0
                    }
4733
0
                }
4734
0
            }
4735
0
        }
4736
4737
        // If the source feature first geometry column is not nullable
4738
        // and that GEOMETRY_NULLABLE creation option is available, use it
4739
        // so as to be able to set the not null constraint (if the driver
4740
        // supports it)
4741
0
        if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4742
0
            nSrcGeomFieldCount >= 1 &&
4743
0
            !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4744
0
            pszDestCreationOptions != nullptr &&
4745
0
            strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") != nullptr &&
4746
0
            CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") == nullptr &&
4747
0
            !m_bForceNullable)
4748
0
        {
4749
0
            bGeomFieldNullable = false;
4750
0
            papszLCOTemp =
4751
0
                CSLSetNameValue(papszLCOTemp, "GEOMETRY_NULLABLE", "NO");
4752
0
            CPLDebug("GDALVectorTranslate", "Using GEOMETRY_NULLABLE=NO");
4753
0
        }
4754
4755
0
        if (psOptions->dfXYRes != OGRGeomCoordinatePrecision::UNKNOWN)
4756
0
        {
4757
0
            if (m_poDstDS->GetDriver()->GetMetadataItem(
4758
0
                    GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr &&
4759
0
                !OGRGeometryFactory::haveGEOS())
4760
0
            {
4761
0
                CPLError(CE_Warning, CPLE_AppDefined,
4762
0
                         "-xyRes specified, but driver does not expose the "
4763
0
                         "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, "
4764
0
                         "and this build has no GEOS support");
4765
0
            }
4766
4767
0
            oCoordPrec.dfXYResolution = psOptions->dfXYRes;
4768
0
            if (!psOptions->osXYResUnit.empty())
4769
0
            {
4770
0
                if (!poOutputSRS)
4771
0
                {
4772
0
                    CSLDestroy(papszLCOTemp);
4773
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4774
0
                             "Unit suffix for -xyRes cannot be used with an "
4775
0
                             "unknown destination SRS");
4776
0
                    return nullptr;
4777
0
                }
4778
4779
0
                if (psOptions->osXYResUnit == "mm")
4780
0
                {
4781
0
                    oCoordPrec.dfXYResolution *= 1e-3;
4782
0
                }
4783
0
                else if (psOptions->osXYResUnit == "deg")
4784
0
                {
4785
0
                    double dfFactorDegToMeter =
4786
0
                        poOutputSRS->GetSemiMajor(nullptr) * M_PI / 180;
4787
0
                    oCoordPrec.dfXYResolution *= dfFactorDegToMeter;
4788
0
                }
4789
0
                else
4790
0
                {
4791
                    // Checked at argument parsing time
4792
0
                    CPLAssert(psOptions->osXYResUnit == "m");
4793
0
                }
4794
4795
0
                OGRGeomCoordinatePrecision tmp;
4796
0
                tmp.SetFromMeter(poOutputSRS, oCoordPrec.dfXYResolution, 0, 0);
4797
0
                oCoordPrec.dfXYResolution = tmp.dfXYResolution;
4798
0
            }
4799
0
        }
4800
4801
0
        if (psOptions->dfZRes != OGRGeomCoordinatePrecision::UNKNOWN)
4802
0
        {
4803
0
            if (m_poDstDS->GetDriver()->GetMetadataItem(
4804
0
                    GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4805
0
            {
4806
0
                CPLError(CE_Warning, CPLE_AppDefined,
4807
0
                         "-zRes specified, but driver does not expose the "
4808
0
                         "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4809
0
            }
4810
4811
0
            oCoordPrec.dfZResolution = psOptions->dfZRes;
4812
0
            if (!psOptions->osZResUnit.empty())
4813
0
            {
4814
0
                if (!poOutputSRS)
4815
0
                {
4816
0
                    CSLDestroy(papszLCOTemp);
4817
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4818
0
                             "Unit suffix for -zRes cannot be used with an "
4819
0
                             "unknown destination SRS");
4820
0
                    return nullptr;
4821
0
                }
4822
4823
0
                if (psOptions->osZResUnit == "mm")
4824
0
                {
4825
0
                    oCoordPrec.dfZResolution *= 1e-3;
4826
0
                }
4827
0
                else
4828
0
                {
4829
                    // Checked at argument parsing time
4830
0
                    CPLAssert(psOptions->osZResUnit == "m");
4831
0
                }
4832
4833
0
                OGRGeomCoordinatePrecision tmp;
4834
0
                tmp.SetFromMeter(poOutputSRS, 0, oCoordPrec.dfZResolution, 0);
4835
0
                oCoordPrec.dfZResolution = tmp.dfZResolution;
4836
0
            }
4837
0
        }
4838
4839
0
        if (psOptions->dfMRes != OGRGeomCoordinatePrecision::UNKNOWN)
4840
0
        {
4841
0
            if (m_poDstDS->GetDriver()->GetMetadataItem(
4842
0
                    GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4843
0
            {
4844
0
                CPLError(CE_Warning, CPLE_AppDefined,
4845
0
                         "-mRes specified, but driver does not expose the "
4846
0
                         "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4847
0
            }
4848
4849
0
            oCoordPrec.dfMResolution = psOptions->dfMRes;
4850
0
        }
4851
4852
0
        auto poSrcDriver = m_poSrcDS->GetDriver();
4853
4854
        // Force FID column as 64 bit if the source feature has a 64 bit FID,
4855
        // the target driver supports 64 bit FID and the user didn't set it
4856
        // manually.
4857
0
        if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
4858
0
            EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&
4859
0
            pszDestCreationOptions &&
4860
0
            strstr(pszDestCreationOptions, "FID64") != nullptr &&
4861
0
            CSLFetchNameValue(m_papszLCO, "FID64") == nullptr)
4862
0
        {
4863
0
            papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID64", "YES");
4864
0
            CPLDebug("GDALVectorTranslate", "Using FID64=YES");
4865
0
        }
4866
4867
        // If output driver supports FID layer creation option, set it with
4868
        // the FID column name of the source layer
4869
0
        if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&
4870
0
            !EQUAL(poSrcLayer->GetFIDColumn(), "") &&
4871
0
            pszDestCreationOptions != nullptr &&
4872
0
            (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4873
0
             strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4874
0
            CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4875
0
        {
4876
0
            papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID",
4877
0
                                           poSrcLayer->GetFIDColumn());
4878
0
            if (!psOptions->bExplodeCollections)
4879
0
            {
4880
0
                CPLDebug("GDALVectorTranslate",
4881
0
                         "Using FID=%s and -preserve_fid",
4882
0
                         poSrcLayer->GetFIDColumn());
4883
0
                bPreserveFID = true;
4884
0
            }
4885
0
            else
4886
0
            {
4887
0
                CPLDebug("GDALVectorTranslate",
4888
0
                         "Using FID=%s and disable -preserve_fid because not "
4889
0
                         "compatible with -explodecollection",
4890
0
                         poSrcLayer->GetFIDColumn());
4891
0
                bPreserveFID = false;
4892
0
            }
4893
0
        }
4894
        // Detect scenario of converting from GPX to a format like GPKG
4895
        // Cf https://github.com/OSGeo/gdal/issues/9225
4896
0
        else if (!bPreserveFID && !m_bUnsetFid && !bAppend && poSrcDriver &&
4897
0
                 EQUAL(poSrcDriver->GetDescription(), "GPX") &&
4898
0
                 pszDestCreationOptions &&
4899
0
                 (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4900
0
                  strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4901
0
                 CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4902
0
        {
4903
0
            CPLDebug("GDALVectorTranslate",
4904
0
                     "Forcing -preserve_fid because source is GPX and layers "
4905
0
                     "have FID cross references");
4906
0
            bPreserveFID = true;
4907
0
        }
4908
        // Detect scenario of converting GML2 with fid attribute to GPKG
4909
0
        else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&
4910
0
                 CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4911
0
        {
4912
0
            int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid");
4913
0
            if (nFieldIdx >= 0 && poSrcLayer->GetLayerDefn()
4914
0
                                          ->GetFieldDefn(nFieldIdx)
4915
0
                                          ->GetType() == OFTString)
4916
0
            {
4917
0
                CPLDebug("GDALVectorTranslate",
4918
0
                         "Source layer has a non-string 'fid' column. Using "
4919
0
                         "FID=gpkg_fid for GeoPackage");
4920
0
                papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID", "gpkg_fid");
4921
0
            }
4922
0
        }
4923
4924
        // If bAddOverwriteLCO is ON (set up when overwriting a CARTO layer),
4925
        // set OVERWRITE to YES so the new layer overwrites the old one
4926
0
        if (bAddOverwriteLCO)
4927
0
        {
4928
0
            papszLCOTemp = CSLSetNameValue(papszLCOTemp, "OVERWRITE", "ON");
4929
0
            CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON");
4930
0
        }
4931
4932
0
        if (m_bNativeData &&
4933
0
            poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") !=
4934
0
                nullptr &&
4935
0
            poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA") !=
4936
0
                nullptr &&
4937
0
            pszDestCreationOptions != nullptr &&
4938
0
            strstr(pszDestCreationOptions, "NATIVE_DATA") != nullptr &&
4939
0
            strstr(pszDestCreationOptions, "NATIVE_MEDIA_TYPE") != nullptr)
4940
0
        {
4941
0
            papszLCOTemp = CSLSetNameValue(
4942
0
                papszLCOTemp, "NATIVE_DATA",
4943
0
                poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA"));
4944
0
            papszLCOTemp =
4945
0
                CSLSetNameValue(papszLCOTemp, "NATIVE_MEDIA_TYPE",
4946
0
                                poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE",
4947
0
                                                            "NATIVE_DATA"));
4948
0
            CPLDebug("GDALVectorTranslate", "Transferring layer NATIVE_DATA");
4949
0
        }
4950
4951
        // For FileGeodatabase, automatically set
4952
        // CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES creation option if the source
4953
        // layer has a Shape_Area/Shape_Length field
4954
0
        if (pszDestCreationOptions &&
4955
0
            strstr(pszDestCreationOptions,
4956
0
                   "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&
4957
0
            CSLFetchNameValue(m_papszLCO,
4958
0
                              "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)
4959
0
        {
4960
0
            const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
4961
0
            const int nIdxShapeArea =
4962
0
                poSrcLayerDefn->GetFieldIndex("Shape_Area");
4963
0
            const int nIdxShapeLength =
4964
0
                poSrcLayerDefn->GetFieldIndex("Shape_Length");
4965
0
            if ((nIdxShapeArea >= 0 &&
4966
0
                 poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=
4967
0
                     nullptr &&
4968
0
                 EQUAL(
4969
0
                     poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),
4970
0
                     "FILEGEODATABASE_SHAPE_AREA") &&
4971
0
                 (m_papszSelFields == nullptr ||
4972
0
                  CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||
4973
0
                (nIdxShapeLength >= 0 &&
4974
0
                 poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=
4975
0
                     nullptr &&
4976
0
                 EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)
4977
0
                           ->GetDefault(),
4978
0
                       "FILEGEODATABASE_SHAPE_LENGTH") &&
4979
0
                 (m_papszSelFields == nullptr ||
4980
0
                  CSLFindString(m_papszSelFields, "Shape_Length") >= 0)))
4981
0
            {
4982
0
                papszLCOTemp = CSLSetNameValue(
4983
0
                    papszLCOTemp, "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS", "YES");
4984
0
                CPLDebug("GDALVectorTranslate",
4985
0
                         "Setting CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES");
4986
0
            }
4987
0
        }
4988
4989
        // Use case of https://github.com/OSGeo/gdal/issues/11057#issuecomment-2495479779
4990
        // Conversion from GPKG to OCI.
4991
        // OCI distinguishes between TIMESTAMP and TIMESTAMP WITH TIME ZONE
4992
        // GeoPackage is supposed to have DateTime in UTC, so we set
4993
        // TIMESTAMP_WITH_TIME_ZONE=YES
4994
0
        if (poSrcDriver && pszDestCreationOptions &&
4995
0
            strstr(pszDestCreationOptions, "TIMESTAMP_WITH_TIME_ZONE") &&
4996
0
            CSLFetchNameValue(m_papszLCO, "TIMESTAMP_WITH_TIME_ZONE") ==
4997
0
                nullptr &&
4998
0
            EQUAL(poSrcDriver->GetDescription(), "GPKG"))
4999
0
        {
5000
0
            papszLCOTemp = CSLSetNameValue(papszLCOTemp,
5001
0
                                           "TIMESTAMP_WITH_TIME_ZONE", "YES");
5002
0
            CPLDebug("GDALVectorTranslate",
5003
0
                     "Setting TIMESTAMP_WITH_TIME_ZONE=YES");
5004
0
        }
5005
5006
0
        OGRGeomFieldDefn oGeomFieldDefn(
5007
0
            osGeomFieldName.c_str(),
5008
0
            static_cast<OGRwkbGeometryType>(eGCreateLayerType));
5009
0
        oGeomFieldDefn.SetSpatialRef(poOutputSRS);
5010
0
        oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);
5011
0
        oGeomFieldDefn.SetNullable(bGeomFieldNullable);
5012
0
        poDstLayer = m_poDstDS->CreateLayer(
5013
0
            pszNewLayerName,
5014
0
            eGCreateLayerType == wkbNone ? nullptr : &oGeomFieldDefn,
5015
0
            papszLCOTemp);
5016
0
        CSLDestroy(papszLCOTemp);
5017
5018
0
        if (poDstLayer == nullptr)
5019
0
        {
5020
0
            return nullptr;
5021
0
        }
5022
5023
        // Cf https://github.com/OSGeo/gdal/issues/6859
5024
        // warn if the user requests -t_srs but the driver uses a different SRS.
5025
0
        if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&
5026
            // MapInfo is somewhat lossy regarding SRS, so do not warn
5027
0
            !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))
5028
0
        {
5029
0
            auto poCreatedSRS = poDstLayer->GetSpatialRef();
5030
0
            if (poCreatedSRS != nullptr)
5031
0
            {
5032
0
                const char *const apszOptions[] = {
5033
0
                    "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
5034
0
                    "CRITERION=EQUIVALENT", nullptr};
5035
0
                if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))
5036
0
                {
5037
0
                    const char *pszTargetSRSName = m_poOutputSRS->GetName();
5038
0
                    const char *pszCreatedSRSName = poCreatedSRS->GetName();
5039
0
                    CPLError(CE_Warning, CPLE_AppDefined,
5040
0
                             "Target SRS %s not taken into account as target "
5041
0
                             "driver likely implements on-the-fly reprojection "
5042
0
                             "to %s",
5043
0
                             pszTargetSRSName ? pszTargetSRSName : "",
5044
0
                             pszCreatedSRSName ? pszCreatedSRSName : "");
5045
0
                }
5046
0
            }
5047
0
        }
5048
5049
0
        if (m_bCopyMD)
5050
0
        {
5051
0
            const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());
5052
0
            for (const char *pszMD : aosDomains)
5053
0
            {
5054
0
                if (!EQUAL(pszMD, "IMAGE_STRUCTURE") &&
5055
0
                    !EQUAL(pszMD, "SUBDATASETS"))
5056
0
                {
5057
0
                    if (char **papszMD = poSrcLayer->GetMetadata(pszMD))
5058
0
                        poDstLayer->SetMetadata(papszMD, pszMD);
5059
0
                }
5060
0
            }
5061
0
        }
5062
5063
0
        if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
5064
0
            m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
5065
0
        {
5066
0
            for (int i = 0; i < nSrcGeomFieldCount; i++)
5067
0
            {
5068
0
                anRequestedGeomFields.push_back(i);
5069
0
            }
5070
0
        }
5071
5072
0
        if (anRequestedGeomFields.size() > 1 ||
5073
0
            (anRequestedGeomFields.size() == 1 &&
5074
0
             m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))
5075
0
        {
5076
0
            for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());
5077
0
                 i++)
5078
0
            {
5079
0
                const int iSrcGeomField = anRequestedGeomFields[i];
5080
0
                OGRGeomFieldDefn oGFldDefn(
5081
0
                    poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));
5082
0
                if (m_poOutputSRS != nullptr)
5083
0
                {
5084
0
                    auto poOutputSRSClone = m_poOutputSRS->Clone();
5085
0
                    oGFldDefn.SetSpatialRef(poOutputSRSClone);
5086
0
                    poOutputSRSClone->Release();
5087
0
                }
5088
0
                if (bForceGType)
5089
0
                {
5090
0
                    oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5091
0
                }
5092
0
                else
5093
0
                {
5094
0
                    eGType = oGFldDefn.GetType();
5095
0
                    eGType =
5096
0
                        ConvertType(m_eGeomTypeConversion,
5097
0
                                    static_cast<OGRwkbGeometryType>(eGType));
5098
0
                    eGType = ForceCoordDimension(eGType, m_nCoordDim);
5099
0
                    oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5100
0
                }
5101
0
                if (m_bForceNullable)
5102
0
                    oGFldDefn.SetNullable(TRUE);
5103
0
                poDstLayer->CreateGeomField(&oGFldDefn);
5104
0
            }
5105
0
        }
5106
5107
0
        bAppend = false;
5108
0
    }
5109
5110
    /* -------------------------------------------------------------------- */
5111
    /*      Otherwise we will append to it, if append was requested.        */
5112
    /* -------------------------------------------------------------------- */
5113
0
    else if (!bAppend && !m_bNewDataSource)
5114
0
    {
5115
0
        if (psOptions->bInvokedFromGdalVectorConvert)
5116
0
        {
5117
0
            CPLError(CE_Failure, CPLE_AppDefined,
5118
0
                     "Layer %s already exists, and --append not specified. "
5119
0
                     "Consider using --append, or --overwrite-layer.",
5120
0
                     pszNewLayerName);
5121
0
        }
5122
0
        else
5123
0
        {
5124
0
            CPLError(CE_Failure, CPLE_AppDefined,
5125
0
                     "Layer %s already exists, and -append not specified.\n"
5126
0
                     "        Consider using -append, or -overwrite.",
5127
0
                     pszNewLayerName);
5128
0
        }
5129
0
        return nullptr;
5130
0
    }
5131
0
    else
5132
0
    {
5133
0
        if (CSLCount(m_papszLCO) > 0)
5134
0
        {
5135
0
            CPLError(
5136
0
                CE_Warning, CPLE_AppDefined,
5137
0
                "Layer creation options ignored since an existing layer is\n"
5138
0
                "         being appended to.");
5139
0
        }
5140
0
    }
5141
5142
    /* -------------------------------------------------------------------- */
5143
    /*      Process Layer style table                                       */
5144
    /* -------------------------------------------------------------------- */
5145
5146
0
    poDstLayer->SetStyleTable(poSrcLayer->GetStyleTable());
5147
    /* -------------------------------------------------------------------- */
5148
    /*      Add fields.  Default to copy all field.                         */
5149
    /*      If only a subset of all fields requested, then output only      */
5150
    /*      the selected fields, and in the order that they were            */
5151
    /*      selected.                                                       */
5152
    /* -------------------------------------------------------------------- */
5153
0
    const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
5154
0
    int iSrcFIDField = -1;
5155
5156
    // Initialize the index-to-index map to -1's
5157
0
    std::vector<int> anMap(nSrcFieldCount, -1);
5158
5159
0
    std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;
5160
5161
    /* Determine if NUMERIC field width narrowing is allowed */
5162
0
    auto poSrcDriver = m_poSrcDS->GetDriver();
5163
0
    const char *pszSrcWidthIncludesDecimalSeparator{
5164
0
        poSrcDriver ? poSrcDriver->GetMetadataItem(
5165
0
                          "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")
5166
0
                    : nullptr};
5167
0
    const bool bSrcWidthIncludesDecimalSeparator{
5168
0
        pszSrcWidthIncludesDecimalSeparator &&
5169
0
        EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};
5170
0
    const char *pszDstWidthIncludesDecimalSeparator{
5171
0
        m_poDstDS->GetDriver()->GetMetadataItem(
5172
0
            "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
5173
0
    const bool bDstWidthIncludesDecimalSeparator{
5174
0
        pszDstWidthIncludesDecimalSeparator &&
5175
0
        EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};
5176
0
    const char *pszSrcWidthIncludesMinusSign{
5177
0
        poSrcDriver ? poSrcDriver->GetMetadataItem(
5178
0
                          "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")
5179
0
                    : nullptr};
5180
0
    const bool bSrcWidthIncludesMinusSign{
5181
0
        pszSrcWidthIncludesMinusSign &&
5182
0
        EQUAL(pszSrcWidthIncludesMinusSign, "YES")};
5183
0
    const char *pszDstWidthIncludesMinusSign{
5184
0
        m_poDstDS->GetDriver()->GetMetadataItem(
5185
0
            "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
5186
0
    const bool bDstWidthIncludesMinusSign{
5187
0
        pszDstWidthIncludesMinusSign &&
5188
0
        EQUAL(pszDstWidthIncludesMinusSign, "YES")};
5189
5190
    // Calculate width delta
5191
0
    int iChangeWidthBy{0};
5192
5193
0
    if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)
5194
0
    {
5195
0
        iChangeWidthBy--;
5196
0
    }
5197
0
    else if (!bSrcWidthIncludesDecimalSeparator &&
5198
0
             bDstWidthIncludesDecimalSeparator)
5199
0
    {
5200
0
        iChangeWidthBy++;
5201
0
    }
5202
5203
    // We cannot assume there is no minus sign, we can only inflate here
5204
0
    if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)
5205
0
    {
5206
0
        iChangeWidthBy++;
5207
0
    }
5208
5209
0
    bool bError = false;
5210
0
    OGRArrowArrayStream streamSrc;
5211
5212
0
    const bool bUseWriteArrowBatch =
5213
0
        !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "OCI") &&
5214
0
        CanUseWriteArrowBatch(poSrcLayer, poDstLayer, bJustCreatedLayer,
5215
0
                              psOptions, bPreserveFID, bError, streamSrc);
5216
0
    if (bError)
5217
0
        return nullptr;
5218
5219
    /* Caution : at the time of writing, the MapInfo driver */
5220
    /* returns NULL until a field has been added */
5221
0
    OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
5222
5223
0
    if (bUseWriteArrowBatch)
5224
0
    {
5225
        // Fields created above
5226
0
    }
5227
0
    else if (m_papszFieldMap && bAppend)
5228
0
    {
5229
0
        bool bIdentity = false;
5230
5231
0
        if (EQUAL(m_papszFieldMap[0], "identity"))
5232
0
            bIdentity = true;
5233
0
        else if (CSLCount(m_papszFieldMap) != nSrcFieldCount)
5234
0
        {
5235
0
            CPLError(
5236
0
                CE_Failure, CPLE_AppDefined,
5237
0
                "Field map should contain the value 'identity' or "
5238
0
                "the same number of integer values as the source field count.");
5239
0
            return nullptr;
5240
0
        }
5241
5242
0
        for (int iField = 0; iField < nSrcFieldCount; iField++)
5243
0
        {
5244
0
            anMap[iField] = bIdentity ? iField : atoi(m_papszFieldMap[iField]);
5245
0
            if (anMap[iField] >= poDstFDefn->GetFieldCount())
5246
0
            {
5247
0
                CPLError(CE_Failure, CPLE_AppDefined,
5248
0
                         "Invalid destination field index %d.", anMap[iField]);
5249
0
                return nullptr;
5250
0
            }
5251
0
        }
5252
0
    }
5253
0
    else if (m_bSelFieldsSet && !bAppend)
5254
0
    {
5255
0
        int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5256
0
        for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5257
0
             iField++)
5258
0
        {
5259
0
            const int iSrcField =
5260
0
                poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5261
0
            if (iSrcField >= 0)
5262
0
            {
5263
0
                OGRFieldDefn *poSrcFieldDefn =
5264
0
                    poSrcFDefn->GetFieldDefn(iSrcField);
5265
0
                OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5266
5267
0
                DoFieldTypeConversion(
5268
0
                    m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5269
0
                    m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5270
0
                    m_bForceNullable, m_bUnsetDefault);
5271
5272
0
                if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5273
0
                    oFieldDefn.GetWidth() != 0)
5274
0
                {
5275
0
                    oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5276
0
                }
5277
5278
                /* The field may have been already created at layer creation */
5279
0
                const int iDstField =
5280
0
                    poDstFDefn
5281
0
                        ? poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef())
5282
0
                        : -1;
5283
0
                if (iDstField >= 0)
5284
0
                {
5285
0
                    anMap[iSrcField] = iDstField;
5286
0
                }
5287
0
                else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5288
0
                {
5289
                    /* now that we've created a field, GetLayerDefn() won't
5290
                     * return NULL */
5291
0
                    if (poDstFDefn == nullptr)
5292
0
                        poDstFDefn = poDstLayer->GetLayerDefn();
5293
5294
                    /* Sanity check : if it fails, the driver is buggy */
5295
0
                    if (poDstFDefn != nullptr &&
5296
0
                        poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5297
0
                    {
5298
0
                        CPLError(CE_Warning, CPLE_AppDefined,
5299
0
                                 "The output driver has claimed to have added "
5300
0
                                 "the %s field, but it did not!",
5301
0
                                 oFieldDefn.GetNameRef());
5302
0
                    }
5303
0
                    else
5304
0
                    {
5305
0
                        anMap[iSrcField] = nDstFieldCount;
5306
0
                        nDstFieldCount++;
5307
0
                    }
5308
0
                }
5309
0
            }
5310
0
        }
5311
5312
        /* --------------------------------------------------------------------
5313
         */
5314
        /* Use SetIgnoredFields() on source layer if available */
5315
        /* --------------------------------------------------------------------
5316
         */
5317
0
        if (poSrcLayer->TestCapability(OLCIgnoreFields))
5318
0
        {
5319
0
            bool bUseIgnoredFields = true;
5320
0
            char **papszWHEREUsedFields = nullptr;
5321
5322
0
            if (m_pszWHERE)
5323
0
            {
5324
                /* We must not ignore fields used in the -where expression
5325
                 * (#4015) */
5326
0
                OGRFeatureQuery oFeatureQuery;
5327
0
                if (oFeatureQuery.Compile(poSrcLayer->GetLayerDefn(),
5328
0
                                          m_pszWHERE, FALSE,
5329
0
                                          nullptr) == OGRERR_NONE)
5330
0
                {
5331
0
                    papszWHEREUsedFields = oFeatureQuery.GetUsedFields();
5332
0
                }
5333
0
                else
5334
0
                {
5335
0
                    bUseIgnoredFields = false;
5336
0
                }
5337
0
            }
5338
5339
0
            char **papszIgnoredFields = nullptr;
5340
5341
0
            for (int iSrcField = 0;
5342
0
                 bUseIgnoredFields && iSrcField < poSrcFDefn->GetFieldCount();
5343
0
                 iSrcField++)
5344
0
            {
5345
0
                const char *pszFieldName =
5346
0
                    poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();
5347
0
                bool bFieldRequested = false;
5348
0
                for (int iField = 0;
5349
0
                     m_papszSelFields && m_papszSelFields[iField]; iField++)
5350
0
                {
5351
0
                    if (EQUAL(pszFieldName, m_papszSelFields[iField]))
5352
0
                    {
5353
0
                        bFieldRequested = true;
5354
0
                        break;
5355
0
                    }
5356
0
                }
5357
0
                bFieldRequested |=
5358
0
                    CSLFindString(papszWHEREUsedFields, pszFieldName) >= 0;
5359
0
                bFieldRequested |= (m_pszZField != nullptr &&
5360
0
                                    EQUAL(pszFieldName, m_pszZField));
5361
5362
                /* If source field not requested, add it to ignored files list
5363
                 */
5364
0
                if (!bFieldRequested)
5365
0
                    papszIgnoredFields =
5366
0
                        CSLAddString(papszIgnoredFields, pszFieldName);
5367
0
            }
5368
0
            if (bUseIgnoredFields)
5369
0
                poSrcLayer->SetIgnoredFields(
5370
0
                    const_cast<const char **>(papszIgnoredFields));
5371
0
            CSLDestroy(papszIgnoredFields);
5372
0
            CSLDestroy(papszWHEREUsedFields);
5373
0
        }
5374
0
    }
5375
0
    else if (!bAppend || m_bAddMissingFields)
5376
0
    {
5377
0
        int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5378
5379
0
        const bool caseInsensitive =
5380
0
            !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");
5381
0
        const auto formatName = [caseInsensitive](const char *name)
5382
0
        {
5383
0
            if (caseInsensitive)
5384
0
            {
5385
0
                return CPLString(name).toupper();
5386
0
            }
5387
0
            else
5388
0
            {
5389
0
                return CPLString(name);
5390
0
            }
5391
0
        };
5392
5393
        /* Save the map of existing fields, before creating new ones */
5394
        /* This helps when converting a source layer that has duplicated field
5395
         * names */
5396
        /* which is a bad idea */
5397
0
        std::map<CPLString, int> oMapPreExistingFields;
5398
0
        std::unordered_set<std::string> oSetDstFieldNames;
5399
0
        for (int iField = 0; iField < nDstFieldCount; iField++)
5400
0
        {
5401
0
            const char *pszFieldName =
5402
0
                poDstFDefn->GetFieldDefn(iField)->GetNameRef();
5403
0
            CPLString osUpperFieldName(formatName(pszFieldName));
5404
0
            oSetDstFieldNames.insert(osUpperFieldName);
5405
0
            if (oMapPreExistingFields.find(osUpperFieldName) ==
5406
0
                oMapPreExistingFields.end())
5407
0
                oMapPreExistingFields[osUpperFieldName] = iField;
5408
            /*else
5409
                CPLError(CE_Warning, CPLE_AppDefined,
5410
                         "The target layer has already a duplicated field name
5411
               '%s' before " "adding the fields of the source layer",
5412
               pszFieldName); */
5413
0
        }
5414
5415
0
        const char *pszFIDColumn = poDstLayer->GetFIDColumn();
5416
5417
0
        std::vector<int> anSrcFieldIndices;
5418
0
        if (m_bSelFieldsSet)
5419
0
        {
5420
0
            for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5421
0
                 iField++)
5422
0
            {
5423
0
                const int iSrcField =
5424
0
                    poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5425
0
                if (iSrcField >= 0)
5426
0
                {
5427
0
                    anSrcFieldIndices.push_back(iSrcField);
5428
0
                }
5429
0
            }
5430
0
        }
5431
0
        else
5432
0
        {
5433
0
            for (int iField = 0; iField < nSrcFieldCount; iField++)
5434
0
            {
5435
0
                anSrcFieldIndices.push_back(iField);
5436
0
            }
5437
0
        }
5438
5439
0
        std::unordered_set<std::string> oSetSrcFieldNames;
5440
0
        for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)
5441
0
        {
5442
0
            oSetSrcFieldNames.insert(
5443
0
                formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));
5444
0
        }
5445
5446
        // For each source field name, memorize the last number suffix to have
5447
        // unique field names in the target. Let's imagine we have a source
5448
        // layer with the field name foo repeated twice After dealing the first
5449
        // field, oMapFieldNameToLastSuffix["foo"] will be 1, so when starting a
5450
        // unique name for the second field, we'll be able to start at 2. This
5451
        // avoids quadratic complexity if a big number of source field names are
5452
        // identical. Like in
5453
        // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37768
5454
0
        std::map<std::string, int> oMapFieldNameToLastSuffix;
5455
5456
0
        for (size_t i = 0; i < anSrcFieldIndices.size(); i++)
5457
0
        {
5458
0
            const int iField = anSrcFieldIndices[i];
5459
0
            const OGRFieldDefn *poSrcFieldDefn =
5460
0
                poSrcFDefn->GetFieldDefn(iField);
5461
0
            OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5462
5463
            // Avoid creating a field with the same name as the FID column
5464
0
            if (pszFIDColumn != nullptr &&
5465
0
                EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&
5466
0
                (oFieldDefn.GetType() == OFTInteger ||
5467
0
                 oFieldDefn.GetType() == OFTInteger64))
5468
0
            {
5469
0
                iSrcFIDField = iField;
5470
0
                continue;
5471
0
            }
5472
5473
0
            DoFieldTypeConversion(
5474
0
                m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5475
0
                m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5476
0
                m_bForceNullable, m_bUnsetDefault);
5477
5478
0
            if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5479
0
                oFieldDefn.GetWidth() != 0)
5480
0
            {
5481
0
                oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5482
0
            }
5483
5484
            /* The field may have been already created at layer creation */
5485
0
            {
5486
0
                const auto oIter = oMapPreExistingFields.find(
5487
0
                    formatName(oFieldDefn.GetNameRef()));
5488
0
                if (oIter != oMapPreExistingFields.end())
5489
0
                {
5490
0
                    anMap[iField] = oIter->second;
5491
0
                    continue;
5492
0
                }
5493
0
            }
5494
5495
0
            bool bHasRenamed = false;
5496
            /* In case the field name already exists in the target layer, */
5497
            /* build a unique field name */
5498
0
            if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=
5499
0
                oSetDstFieldNames.end())
5500
0
            {
5501
0
                const CPLString osTmpNameRaddixUC(
5502
0
                    formatName(oFieldDefn.GetNameRef()));
5503
0
                int nTry = 1;
5504
0
                const auto oIter =
5505
0
                    oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);
5506
0
                if (oIter != oMapFieldNameToLastSuffix.end())
5507
0
                    nTry = oIter->second;
5508
0
                CPLString osTmpNameUC = osTmpNameRaddixUC;
5509
0
                osTmpNameUC.reserve(osTmpNameUC.size() + 10);
5510
0
                while (true)
5511
0
                {
5512
0
                    ++nTry;
5513
0
                    char szTry[32];
5514
0
                    snprintf(szTry, sizeof(szTry), "%d", nTry);
5515
0
                    osTmpNameUC.replace(osTmpNameRaddixUC.size(),
5516
0
                                        std::string::npos, szTry);
5517
5518
                    /* Check that the proposed name doesn't exist either in the
5519
                     * already */
5520
                    /* created fields or in the source fields */
5521
0
                    if (oSetDstFieldNames.find(osTmpNameUC) ==
5522
0
                            oSetDstFieldNames.end() &&
5523
0
                        oSetSrcFieldNames.find(osTmpNameUC) ==
5524
0
                            oSetSrcFieldNames.end())
5525
0
                    {
5526
0
                        bHasRenamed = true;
5527
0
                        oFieldDefn.SetName(
5528
0
                            (CPLString(oFieldDefn.GetNameRef()) + szTry)
5529
0
                                .c_str());
5530
0
                        oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;
5531
0
                        break;
5532
0
                    }
5533
0
                }
5534
0
            }
5535
5536
            // Create field domain in output dataset if not already existing.
5537
0
            const std::string osDomainName(oFieldDefn.GetDomainName());
5538
0
            if (!osDomainName.empty())
5539
0
            {
5540
0
                if (m_poDstDS->TestCapability(ODsCAddFieldDomain) &&
5541
0
                    m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5542
0
                {
5543
0
                    const auto poSrcDomain =
5544
0
                        m_poSrcDS->GetFieldDomain(osDomainName);
5545
0
                    if (poSrcDomain)
5546
0
                    {
5547
0
                        std::string failureReason;
5548
0
                        if (!m_poDstDS->AddFieldDomain(
5549
0
                                std::unique_ptr<OGRFieldDomain>(
5550
0
                                    poSrcDomain->Clone()),
5551
0
                                failureReason))
5552
0
                        {
5553
0
                            oFieldDefn.SetDomainName(std::string());
5554
0
                            CPLDebug("OGR2OGR", "Cannot create domain %s: %s",
5555
0
                                     osDomainName.c_str(),
5556
0
                                     failureReason.c_str());
5557
0
                        }
5558
0
                    }
5559
0
                    else
5560
0
                    {
5561
0
                        CPLDebug("OGR2OGR",
5562
0
                                 "Cannot find domain %s in source dataset",
5563
0
                                 osDomainName.c_str());
5564
0
                    }
5565
0
                }
5566
0
                if (m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5567
0
                {
5568
0
                    oFieldDefn.SetDomainName(std::string());
5569
0
                }
5570
0
            }
5571
5572
0
            if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5573
0
            {
5574
                /* now that we've created a field, GetLayerDefn() won't return
5575
                 * NULL */
5576
0
                if (poDstFDefn == nullptr)
5577
0
                    poDstFDefn = poDstLayer->GetLayerDefn();
5578
5579
                /* Sanity check : if it fails, the driver is buggy */
5580
0
                if (poDstFDefn != nullptr &&
5581
0
                    poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5582
0
                {
5583
0
                    CPLError(CE_Warning, CPLE_AppDefined,
5584
0
                             "The output driver has claimed to have added the "
5585
0
                             "%s field, but it did not!",
5586
0
                             oFieldDefn.GetNameRef());
5587
0
                }
5588
0
                else
5589
0
                {
5590
0
                    if (poDstFDefn != nullptr)
5591
0
                    {
5592
0
                        const char *pszNewFieldName =
5593
0
                            poDstFDefn->GetFieldDefn(nDstFieldCount)
5594
0
                                ->GetNameRef();
5595
0
                        if (bHasRenamed)
5596
0
                        {
5597
0
                            CPLError(CE_Warning, CPLE_AppDefined,
5598
0
                                     "Field '%s' already exists. Renaming it "
5599
0
                                     "as '%s'",
5600
0
                                     poSrcFieldDefn->GetNameRef(),
5601
0
                                     pszNewFieldName);
5602
0
                        }
5603
0
                        oSetDstFieldNames.insert(formatName(pszNewFieldName));
5604
0
                    }
5605
5606
0
                    anMap[iField] = nDstFieldCount;
5607
0
                    nDstFieldCount++;
5608
0
                }
5609
0
            }
5610
5611
0
            if (m_bResolveDomains && !osDomainName.empty())
5612
0
            {
5613
0
                const auto poSrcDomain =
5614
0
                    m_poSrcDS->GetFieldDomain(osDomainName);
5615
0
                if (poSrcDomain && poSrcDomain->GetDomainType() == OFDT_CODED)
5616
0
                {
5617
0
                    OGRFieldDefn oResolvedField(
5618
0
                        CPLSPrintf("%s_resolved", oFieldDefn.GetNameRef()),
5619
0
                        OFTString);
5620
0
                    if (poDstLayer->CreateField(&oResolvedField) == OGRERR_NONE)
5621
0
                    {
5622
0
                        TargetLayerInfo::ResolvedInfo resolvedInfo;
5623
0
                        resolvedInfo.nSrcField = iField;
5624
0
                        resolvedInfo.poDomain = poSrcDomain;
5625
0
                        oMapResolved[nDstFieldCount] = resolvedInfo;
5626
0
                        nDstFieldCount++;
5627
0
                    }
5628
0
                }
5629
0
            }
5630
0
        }
5631
0
    }
5632
0
    else
5633
0
    {
5634
        /* For an existing layer, build the map by fetching the index in the
5635
         * destination */
5636
        /* layer for each source field */
5637
0
        if (poDstFDefn == nullptr)
5638
0
        {
5639
0
            CPLError(CE_Failure, CPLE_AppDefined, "poDstFDefn == NULL.");
5640
0
            return nullptr;
5641
0
        }
5642
5643
0
        for (int iField = 0; iField < nSrcFieldCount; iField++)
5644
0
        {
5645
0
            OGRFieldDefn *poSrcFieldDefn = poSrcFDefn->GetFieldDefn(iField);
5646
0
            const int iDstField = poDstLayer->FindFieldIndex(
5647
0
                poSrcFieldDefn->GetNameRef(), m_bExactFieldNameMatch);
5648
0
            if (iDstField >= 0)
5649
0
                anMap[iField] = iDstField;
5650
0
            else
5651
0
            {
5652
0
                if (m_bExactFieldNameMatch)
5653
0
                {
5654
0
                    const int iDstFieldCandidate = poDstLayer->FindFieldIndex(
5655
0
                        poSrcFieldDefn->GetNameRef(), false);
5656
0
                    if (iDstFieldCandidate >= 0)
5657
0
                    {
5658
0
                        CPLError(CE_Warning, CPLE_AppDefined,
5659
0
                                 "Source field '%s' could have been identified "
5660
0
                                 "with existing field '%s' of destination "
5661
0
                                 "layer '%s' if the -relaxedFieldNameMatch "
5662
0
                                 "option had been specified.",
5663
0
                                 poSrcFieldDefn->GetNameRef(),
5664
0
                                 poDstLayer->GetLayerDefn()
5665
0
                                     ->GetFieldDefn(iDstFieldCandidate)
5666
0
                                     ->GetNameRef(),
5667
0
                                 poDstLayer->GetName());
5668
0
                    }
5669
0
                }
5670
5671
0
                CPLDebug(
5672
0
                    "GDALVectorTranslate",
5673
0
                    "Skipping field '%s' not found in destination layer '%s'.",
5674
0
                    poSrcFieldDefn->GetNameRef(), poDstLayer->GetName());
5675
0
            }
5676
0
        }
5677
0
    }
5678
5679
0
    if (bOverwriteActuallyDone && !bAddOverwriteLCO &&
5680
0
        EQUAL(m_poDstDS->GetDriver()->GetDescription(), "PostgreSQL") &&
5681
0
        !psOptions->nLayerTransaction && psOptions->nGroupTransactions > 0 &&
5682
0
        CPLTestBool(CPLGetConfigOption("PG_COMMIT_WHEN_OVERWRITING", "YES")))
5683
0
    {
5684
0
        CPLDebug("GDALVectorTranslate",
5685
0
                 "Forcing transaction commit as table overwriting occurred");
5686
        // Commit when overwriting as this consumes a lot of PG resources
5687
        // and could result in """out of shared memory.
5688
        // You might need to increase max_locks_per_transaction."""" errors
5689
0
        if (m_poDstDS->CommitTransaction() == OGRERR_FAILURE ||
5690
0
            m_poDstDS->StartTransaction(psOptions->bForceTransaction) ==
5691
0
                OGRERR_FAILURE)
5692
0
        {
5693
0
            return nullptr;
5694
0
        }
5695
0
        nTotalEventsDone = 0;
5696
0
    }
5697
5698
0
    auto psInfo = std::make_unique<TargetLayerInfo>();
5699
0
    psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;
5700
0
    psInfo->m_nFeaturesRead = 0;
5701
0
    psInfo->m_bPerFeatureCT = false;
5702
0
    psInfo->m_poSrcLayer = poSrcLayer;
5703
0
    psInfo->m_poDstLayer = poDstLayer;
5704
0
    psInfo->m_aoReprojectionInfo.resize(
5705
0
        poDstLayer->GetLayerDefn()->GetGeomFieldCount());
5706
0
    psInfo->m_anMap = std::move(anMap);
5707
0
    psInfo->m_iSrcZField = iSrcZField;
5708
0
    psInfo->m_iSrcFIDField = iSrcFIDField;
5709
0
    if (anRequestedGeomFields.size() == 1)
5710
0
        psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];
5711
0
    else
5712
0
        psInfo->m_iRequestedSrcGeomField = -1;
5713
0
    psInfo->m_bPreserveFID = bPreserveFID;
5714
0
    psInfo->m_pszCTPipeline = m_pszCTPipeline;
5715
0
    psInfo->m_aosCTOptions = m_aosCTOptions;
5716
0
    psInfo->m_oMapResolved = std::move(oMapResolved);
5717
0
    for (const auto &kv : psInfo->m_oMapResolved)
5718
0
    {
5719
0
        const auto poDomain = kv.second.poDomain;
5720
0
        const auto poCodedDomain =
5721
0
            cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);
5722
0
        const auto enumeration = poCodedDomain->GetEnumeration();
5723
0
        std::map<std::string, std::string> oMapCodeValue;
5724
0
        for (int i = 0; enumeration[i].pszCode != nullptr; ++i)
5725
0
        {
5726
0
            oMapCodeValue[enumeration[i].pszCode] =
5727
0
                enumeration[i].pszValue ? enumeration[i].pszValue : "";
5728
0
        }
5729
0
        psInfo->m_oMapDomainToKV[poDomain] = std::move(oMapCodeValue);
5730
0
    }
5731
5732
    // Detect if we can directly pass the source feature to the CreateFeature()
5733
    // method of the target layer, without doing any copying of field content.
5734
0
    psInfo->m_bCanAvoidSetFrom = false;
5735
0
    if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)
5736
0
    {
5737
0
        psInfo->m_bCanAvoidSetFrom = true;
5738
0
        const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5739
0
        if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||
5740
0
            nSrcGeomFieldCount != nDstGeomFieldCount)
5741
0
        {
5742
0
            psInfo->m_bCanAvoidSetFrom = false;
5743
0
        }
5744
0
        else
5745
0
        {
5746
0
            for (int i = 0; i < nSrcFieldCount; ++i)
5747
0
            {
5748
0
                auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);
5749
0
                auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);
5750
0
                if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||
5751
0
                    psInfo->m_anMap[i] != i)
5752
0
                {
5753
0
                    psInfo->m_bCanAvoidSetFrom = false;
5754
0
                    break;
5755
0
                }
5756
0
            }
5757
0
            if (!psInfo->m_bCanAvoidSetFrom && nSrcGeomFieldCount > 1)
5758
0
            {
5759
0
                for (int i = 0; i < nSrcGeomFieldCount; ++i)
5760
0
                {
5761
0
                    auto poSrcGeomFieldDefn = poSrcFDefn->GetGeomFieldDefn(i);
5762
0
                    auto poDstGeomFieldDefn = poDstFDefn->GetGeomFieldDefn(i);
5763
0
                    if (!EQUAL(poSrcGeomFieldDefn->GetNameRef(),
5764
0
                               poDstGeomFieldDefn->GetNameRef()))
5765
0
                    {
5766
0
                        psInfo->m_bCanAvoidSetFrom = false;
5767
0
                        break;
5768
0
                    }
5769
0
                }
5770
0
            }
5771
0
        }
5772
0
    }
5773
5774
0
    psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()
5775
0
                                  ? nullptr
5776
0
                                  : psOptions->osSpatSRSDef.c_str();
5777
0
    psInfo->m_hSpatialFilter =
5778
0
        OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());
5779
0
    psInfo->m_pszGeomField =
5780
0
        psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;
5781
5782
0
    if (psOptions->nTZOffsetInSec != TZ_OFFSET_INVALID && poDstFDefn)
5783
0
    {
5784
0
        for (int i = 0; i < poDstFDefn->GetFieldCount(); ++i)
5785
0
        {
5786
0
            if (poDstFDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
5787
0
            {
5788
0
                psInfo->m_anDateTimeFieldIdx.push_back(i);
5789
0
            }
5790
0
        }
5791
0
    }
5792
5793
0
    psInfo->m_bSupportCurves =
5794
0
        CPL_TO_BOOL(poDstLayer->TestCapability(OLCCurveGeometries));
5795
5796
0
    psInfo->m_sArrowArrayStream = std::move(streamSrc);
5797
5798
0
    return psInfo;
5799
0
}
5800
5801
/************************************************************************/
5802
/*                               SetupCT()                              */
5803
/************************************************************************/
5804
5805
static bool
5806
SetupCT(TargetLayerInfo *psInfo, OGRLayer *poSrcLayer, bool bTransform,
5807
        bool bWrapDateline, const CPLString &osDateLineOffset,
5808
        const OGRSpatialReference *poUserSourceSRS, OGRFeature *poFeature,
5809
        const OGRSpatialReference *poOutputSRS,
5810
        OGRCoordinateTransformation *poGCPCoordTrans, bool bVerboseError)
5811
0
{
5812
0
    OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5813
0
    const int nDstGeomFieldCount =
5814
0
        poDstLayer->GetLayerDefn()->GetGeomFieldCount();
5815
0
    for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
5816
0
    {
5817
        /* --------------------------------------------------------------------
5818
         */
5819
        /*      Setup coordinate transformation if we need it. */
5820
        /* --------------------------------------------------------------------
5821
         */
5822
0
        const OGRSpatialReference *poSourceSRS = nullptr;
5823
0
        OGRCoordinateTransformation *poCT = nullptr;
5824
0
        char **papszTransformOptions = nullptr;
5825
5826
0
        int iSrcGeomField;
5827
0
        auto poDstGeomFieldDefn =
5828
0
            poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
5829
0
        if (psInfo->m_iRequestedSrcGeomField >= 0)
5830
0
        {
5831
0
            iSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5832
0
        }
5833
0
        else
5834
0
        {
5835
0
            iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
5836
0
                poDstGeomFieldDefn->GetNameRef());
5837
0
            if (iSrcGeomField < 0)
5838
0
            {
5839
0
                if (nDstGeomFieldCount == 1 &&
5840
0
                    poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
5841
0
                {
5842
0
                    iSrcGeomField = 0;
5843
0
                }
5844
0
                else
5845
0
                {
5846
0
                    continue;
5847
0
                }
5848
0
            }
5849
0
        }
5850
5851
0
        if (psInfo->m_nFeaturesRead == 0)
5852
0
        {
5853
0
            poSourceSRS = poUserSourceSRS;
5854
0
            if (poSourceSRS == nullptr)
5855
0
            {
5856
0
                if (iSrcGeomField > 0)
5857
0
                    poSourceSRS = poSrcLayer->GetLayerDefn()
5858
0
                                      ->GetGeomFieldDefn(iSrcGeomField)
5859
0
                                      ->GetSpatialRef();
5860
0
                else
5861
0
                    poSourceSRS = poSrcLayer->GetSpatialRef();
5862
0
            }
5863
0
        }
5864
0
        if (poSourceSRS == nullptr)
5865
0
        {
5866
0
            if (poFeature == nullptr)
5867
0
            {
5868
0
                if (bVerboseError)
5869
0
                {
5870
0
                    CPLError(CE_Failure, CPLE_AppDefined,
5871
0
                             "Non-null feature expected to set transformation");
5872
0
                }
5873
0
                return false;
5874
0
            }
5875
0
            OGRGeometry *poSrcGeometry =
5876
0
                poFeature->GetGeomFieldRef(iSrcGeomField);
5877
0
            if (poSrcGeometry)
5878
0
                poSourceSRS = poSrcGeometry->getSpatialReference();
5879
0
            psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);
5880
0
        }
5881
5882
0
        if (bTransform)
5883
0
        {
5884
0
            if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)
5885
0
            {
5886
0
                CPLError(CE_Failure, CPLE_AppDefined,
5887
0
                         "Can't transform coordinates, source layer has no\n"
5888
0
                         "coordinate system.  Use -s_srs to set one.");
5889
5890
0
                return false;
5891
0
            }
5892
5893
0
            if (psInfo->m_pszCTPipeline == nullptr)
5894
0
            {
5895
0
                CPLAssert(nullptr != poSourceSRS);
5896
0
                CPLAssert(nullptr != poOutputSRS);
5897
0
            }
5898
5899
0
            if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)
5900
0
            {
5901
0
                const auto &supportedSRSList =
5902
0
                    poSrcLayer->GetSupportedSRSList(iGeom);
5903
0
                if (!supportedSRSList.empty())
5904
0
                {
5905
0
                    const char *const apszOptions[] = {
5906
0
                        "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
5907
0
                    for (const auto &poSRS : supportedSRSList)
5908
0
                    {
5909
0
                        if (poSRS->IsSame(poOutputSRS, apszOptions))
5910
0
                        {
5911
0
                            OGRSpatialReference oSourceSRSBackup;
5912
0
                            if (poSourceSRS)
5913
0
                                oSourceSRSBackup = *poSourceSRS;
5914
0
                            if (poSrcLayer->SetActiveSRS(iGeom, poSRS.get()) ==
5915
0
                                OGRERR_NONE)
5916
0
                            {
5917
0
                                CPLDebug("ogr2ogr",
5918
0
                                         "Switching layer active SRS to %s",
5919
0
                                         poSRS->GetName());
5920
5921
0
                                if (psInfo->m_hSpatialFilter != nullptr &&
5922
0
                                    ((psInfo->m_iRequestedSrcGeomField < 0 &&
5923
0
                                      iGeom == 0) ||
5924
0
                                     (iGeom ==
5925
0
                                      psInfo->m_iRequestedSrcGeomField)))
5926
0
                                {
5927
0
                                    OGRSpatialReference oSpatSRS;
5928
0
                                    oSpatSRS.SetAxisMappingStrategy(
5929
0
                                        OAMS_TRADITIONAL_GIS_ORDER);
5930
0
                                    if (psInfo->m_pszSpatSRSDef)
5931
0
                                        oSpatSRS.SetFromUserInput(
5932
0
                                            psInfo->m_pszSpatSRSDef);
5933
0
                                    ApplySpatialFilter(
5934
0
                                        poSrcLayer,
5935
0
                                        OGRGeometry::FromHandle(
5936
0
                                            psInfo->m_hSpatialFilter),
5937
0
                                        !oSpatSRS.IsEmpty() ? &oSpatSRS
5938
0
                                        : !oSourceSRSBackup.IsEmpty()
5939
0
                                            ? &oSourceSRSBackup
5940
0
                                            : nullptr,
5941
0
                                        psInfo->m_pszGeomField, poOutputSRS);
5942
0
                                }
5943
5944
0
                                bTransform = false;
5945
0
                            }
5946
0
                            break;
5947
0
                        }
5948
0
                    }
5949
0
                }
5950
0
            }
5951
5952
0
            if (!bTransform)
5953
0
            {
5954
                // do nothing
5955
0
            }
5956
0
            else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&
5957
0
                     psInfo->m_aoReprojectionInfo[iGeom]
5958
0
                             .m_poCT->GetSourceCS() == poSourceSRS)
5959
0
            {
5960
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5961
0
            }
5962
0
            else
5963
0
            {
5964
0
                OGRCoordinateTransformationOptions options;
5965
0
                if (psInfo->m_pszCTPipeline)
5966
0
                {
5967
0
                    options.SetCoordinateOperation(psInfo->m_pszCTPipeline,
5968
0
                                                   false);
5969
0
                }
5970
5971
0
                bool bWarnAboutDifferentCoordinateOperations =
5972
0
                    poGCPCoordTrans == nullptr &&
5973
0
                    !(poSourceSRS && poSourceSRS->IsGeocentric());
5974
5975
0
                for (const auto &[key, value] :
5976
0
                     cpl::IterateNameValue(psInfo->m_aosCTOptions))
5977
0
                {
5978
0
                    if (EQUAL(key, "ALLOW_BALLPARK"))
5979
0
                    {
5980
0
                        options.SetBallparkAllowed(CPLTestBool(value));
5981
0
                    }
5982
0
                    else if (EQUAL(key, "ONLY_BEST"))
5983
0
                    {
5984
0
                        options.SetOnlyBest(CPLTestBool(value));
5985
0
                    }
5986
0
                    else if (EQUAL(key, "WARN_ABOUT_DIFFERENT_COORD_OP"))
5987
0
                    {
5988
0
                        if (!CPLTestBool(value))
5989
0
                            bWarnAboutDifferentCoordinateOperations = false;
5990
0
                    }
5991
0
                    else
5992
0
                    {
5993
0
                        CPLError(CE_Warning, CPLE_AppDefined,
5994
0
                                 "Unknown coordinate transform option: %s",
5995
0
                                 key);
5996
0
                    }
5997
0
                }
5998
5999
0
                poCT = OGRCreateCoordinateTransformation(poSourceSRS,
6000
0
                                                         poOutputSRS, options);
6001
0
                if (poCT == nullptr)
6002
0
                {
6003
0
                    char *pszWKT = nullptr;
6004
6005
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6006
0
                             "Failed to create coordinate transformation "
6007
0
                             "between the\n"
6008
0
                             "following coordinate systems.  This may be "
6009
0
                             "because they\n"
6010
0
                             "are not transformable.");
6011
6012
0
                    if (poSourceSRS)
6013
0
                    {
6014
0
                        poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
6015
0
                        CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
6016
0
                                 pszWKT);
6017
0
                        CPLFree(pszWKT);
6018
0
                    }
6019
6020
0
                    if (poOutputSRS)
6021
0
                    {
6022
0
                        poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
6023
0
                        CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
6024
0
                                 pszWKT);
6025
0
                        CPLFree(pszWKT);
6026
0
                    }
6027
6028
0
                    return false;
6029
0
                }
6030
0
                if (poGCPCoordTrans)
6031
0
                    poCT = new CompositeCT(poGCPCoordTrans, false, poCT, true);
6032
0
                else
6033
0
                    psInfo->m_aoReprojectionInfo[iGeom]
6034
0
                        .m_bWarnAboutDifferentCoordinateOperations =
6035
0
                        bWarnAboutDifferentCoordinateOperations;
6036
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(poCT);
6037
0
                psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =
6038
0
                    !(poGCPCoordTrans == nullptr && poSourceSRS &&
6039
0
                      poSourceSRS->IsGeographic() && poOutputSRS &&
6040
0
                      poOutputSRS->IsGeographic());
6041
0
            }
6042
0
        }
6043
0
        else
6044
0
        {
6045
0
            const char *const apszOptions[] = {
6046
0
                "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
6047
0
                "CRITERION=EQUIVALENT", nullptr};
6048
0
            auto poDstGeomFieldDefnSpatialRef =
6049
0
                poDstGeomFieldDefn->GetSpatialRef();
6050
0
            if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&
6051
0
                poSourceSRS->GetDataAxisToSRSAxisMapping() !=
6052
0
                    poDstGeomFieldDefnSpatialRef
6053
0
                        ->GetDataAxisToSRSAxisMapping() &&
6054
0
                poSourceSRS->IsSame(poDstGeomFieldDefnSpatialRef, apszOptions))
6055
0
            {
6056
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(
6057
0
                    new CompositeCT(
6058
0
                        new AxisMappingCoordinateTransformation(
6059
0
                            poSourceSRS->GetDataAxisToSRSAxisMapping(),
6060
0
                            poDstGeomFieldDefnSpatialRef
6061
0
                                ->GetDataAxisToSRSAxisMapping()),
6062
0
                        true, poGCPCoordTrans, false));
6063
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6064
0
            }
6065
0
            else if (poGCPCoordTrans)
6066
0
            {
6067
0
                psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(
6068
0
                    new CompositeCT(poGCPCoordTrans, false, nullptr, false));
6069
0
                poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6070
0
            }
6071
0
        }
6072
6073
0
        if (bWrapDateline)
6074
0
        {
6075
0
            if (bTransform && poCT != nullptr && poOutputSRS != nullptr &&
6076
0
                poOutputSRS->IsGeographic())
6077
0
            {
6078
0
                papszTransformOptions =
6079
0
                    CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
6080
0
                if (!osDateLineOffset.empty())
6081
0
                {
6082
0
                    CPLString soOffset("DATELINEOFFSET=");
6083
0
                    soOffset += osDateLineOffset;
6084
0
                    papszTransformOptions =
6085
0
                        CSLAddString(papszTransformOptions, soOffset);
6086
0
                }
6087
0
            }
6088
0
            else if (poSourceSRS != nullptr && poSourceSRS->IsGeographic())
6089
0
            {
6090
0
                papszTransformOptions =
6091
0
                    CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
6092
0
                if (!osDateLineOffset.empty())
6093
0
                {
6094
0
                    CPLString soOffset("DATELINEOFFSET=");
6095
0
                    soOffset += osDateLineOffset;
6096
0
                    papszTransformOptions =
6097
0
                        CSLAddString(papszTransformOptions, soOffset);
6098
0
                }
6099
0
            }
6100
0
            else
6101
0
            {
6102
0
                CPLErrorOnce(CE_Failure, CPLE_IllegalArg,
6103
0
                             "-wrapdateline option only works when "
6104
0
                             "reprojecting to a geographic SRS");
6105
0
            }
6106
6107
0
            psInfo->m_aoReprojectionInfo[iGeom].m_aosTransformOptions.Assign(
6108
0
                papszTransformOptions);
6109
0
        }
6110
0
    }
6111
0
    return true;
6112
0
}
6113
6114
/************************************************************************/
6115
/*                 LayerTranslator::TranslateArrow()                    */
6116
/************************************************************************/
6117
6118
bool LayerTranslator::TranslateArrow(
6119
    TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,
6120
    GIntBig *pnReadFeatureCount, GDALProgressFunc pfnProgress,
6121
    void *pProgressArg, const GDALVectorTranslateOptions *psOptions)
6122
0
{
6123
0
    struct ArrowSchema schema;
6124
0
    CPLStringList aosOptionsWriteArrowBatch;
6125
0
    if (psInfo->m_bPreserveFID)
6126
0
    {
6127
0
        aosOptionsWriteArrowBatch.SetNameValue(
6128
0
            "FID", psInfo->m_poSrcLayer->GetFIDColumn());
6129
0
        aosOptionsWriteArrowBatch.SetNameValue("IF_FID_NOT_PRESERVED",
6130
0
                                               "WARNING");
6131
0
    }
6132
6133
0
    if (psInfo->m_sArrowArrayStream.get_schema(&schema) != 0)
6134
0
    {
6135
0
        CPLError(CE_Failure, CPLE_AppDefined, "stream.get_schema() failed");
6136
0
        return false;
6137
0
    }
6138
6139
0
    int iArrowGeomFieldIndex = -1;
6140
0
    if (m_bTransform)
6141
0
    {
6142
0
        iArrowGeomFieldIndex = GetArrowGeomFieldIndex(
6143
0
            &schema, psInfo->m_poSrcLayer->GetGeometryColumn());
6144
0
        if (!SetupCT(psInfo, psInfo->m_poSrcLayer, m_bTransform,
6145
0
                     m_bWrapDateline, m_osDateLineOffset, m_poUserSourceSRS,
6146
0
                     nullptr, m_poOutputSRS, m_poGCPCoordTrans, false))
6147
0
        {
6148
0
            return false;
6149
0
        }
6150
0
    }
6151
6152
0
    bool bRet = true;
6153
6154
0
    GIntBig nCount = 0;
6155
0
    bool bGoOn = true;
6156
0
    std::vector<GByte> abyModifiedWKB;
6157
0
    const int nNumReprojectionThreads = []()
6158
0
    {
6159
0
        const int nNumCPUs = CPLGetNumCPUs();
6160
0
        if (nNumCPUs <= 1)
6161
0
        {
6162
0
            return 1;
6163
0
        }
6164
0
        else
6165
0
        {
6166
0
            const char *pszNumThreads =
6167
0
                CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
6168
0
            if (pszNumThreads)
6169
0
            {
6170
0
                if (EQUAL(pszNumThreads, "ALL_CPUS"))
6171
0
                    return CPLGetNumCPUs();
6172
0
                return std::min(atoi(pszNumThreads), 1024);
6173
0
            }
6174
0
            else
6175
0
            {
6176
0
                return std::max(2, nNumCPUs / 2);
6177
0
            }
6178
0
        }
6179
0
    }();
6180
6181
    // Somewhat arbitrary threshold (config option only/mostly for autotest purposes)
6182
0
    const int MIN_FEATURES_FOR_THREADED_REPROJ = atoi(CPLGetConfigOption(
6183
0
        "OGR2OGR_MIN_FEATURES_FOR_THREADED_REPROJ", "10000"));
6184
6185
0
    while (bGoOn)
6186
0
    {
6187
0
        struct ArrowArray array;
6188
        // Acquire source batch
6189
0
        if (psInfo->m_sArrowArrayStream.get_next(&array) != 0)
6190
0
        {
6191
0
            CPLError(CE_Failure, CPLE_AppDefined, "stream.get_next() failed");
6192
0
            bRet = false;
6193
0
            break;
6194
0
        }
6195
6196
0
        if (array.release == nullptr)
6197
0
        {
6198
            // End of stream
6199
0
            break;
6200
0
        }
6201
6202
        // Limit number of features in batch if needed
6203
0
        if (psOptions->nLimit >= 0 &&
6204
0
            nCount + array.length >= psOptions->nLimit)
6205
0
        {
6206
0
            const auto nAdjustedLength = psOptions->nLimit - nCount;
6207
0
            for (int i = 0; i < array.n_children; ++i)
6208
0
            {
6209
0
                if (array.children[i]->length == array.length)
6210
0
                    array.children[i]->length = nAdjustedLength;
6211
0
            }
6212
0
            array.length = nAdjustedLength;
6213
0
            nCount = psOptions->nLimit;
6214
0
            bGoOn = false;
6215
0
        }
6216
0
        else
6217
0
        {
6218
0
            nCount += array.length;
6219
0
        }
6220
6221
0
        const auto nArrayLength = array.length;
6222
6223
        // Coordinate reprojection
6224
0
        if (m_bTransform)
6225
0
        {
6226
0
            struct GeomArrayReleaser
6227
0
            {
6228
0
                const void *origin_buffers_2 = nullptr;
6229
0
                void (*origin_release)(struct ArrowArray *) = nullptr;
6230
0
                void *origin_private_data = nullptr;
6231
6232
0
                static void init(struct ArrowArray *psGeomArray)
6233
0
                {
6234
0
                    GeomArrayReleaser *releaser = new GeomArrayReleaser();
6235
0
                    CPLAssert(psGeomArray->n_buffers >= 3);
6236
0
                    releaser->origin_buffers_2 = psGeomArray->buffers[2];
6237
0
                    releaser->origin_private_data = psGeomArray->private_data;
6238
0
                    releaser->origin_release = psGeomArray->release;
6239
0
                    psGeomArray->release = GeomArrayReleaser::release;
6240
0
                    psGeomArray->private_data = releaser;
6241
0
                }
6242
6243
0
                static void release(struct ArrowArray *psGeomArray)
6244
0
                {
6245
0
                    GeomArrayReleaser *releaser =
6246
0
                        static_cast<GeomArrayReleaser *>(
6247
0
                            psGeomArray->private_data);
6248
0
                    psGeomArray->buffers[2] = releaser->origin_buffers_2;
6249
0
                    psGeomArray->private_data = releaser->origin_private_data;
6250
0
                    psGeomArray->release = releaser->origin_release;
6251
0
                    if (psGeomArray->release)
6252
0
                        psGeomArray->release(psGeomArray);
6253
0
                    delete releaser;
6254
0
                }
6255
0
            };
6256
6257
0
            auto *psGeomArray = array.children[iArrowGeomFieldIndex];
6258
0
            GeomArrayReleaser::init(psGeomArray);
6259
6260
0
            GByte *pabyWKB = static_cast<GByte *>(
6261
0
                const_cast<void *>(psGeomArray->buffers[2]));
6262
0
            const uint32_t *panOffsets =
6263
0
                static_cast<const uint32_t *>(psGeomArray->buffers[1]);
6264
0
            auto poCT = psInfo->m_aoReprojectionInfo[0].m_poCT.get();
6265
6266
0
            try
6267
0
            {
6268
0
                abyModifiedWKB.resize(panOffsets[nArrayLength]);
6269
0
            }
6270
0
            catch (const std::exception &)
6271
0
            {
6272
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6273
0
                bRet = false;
6274
0
                if (array.release)
6275
0
                    array.release(&array);
6276
0
                break;
6277
0
            }
6278
0
            memcpy(abyModifiedWKB.data(), pabyWKB, panOffsets[nArrayLength]);
6279
0
            psGeomArray->buffers[2] = abyModifiedWKB.data();
6280
6281
            // Collect left-most, right-most, top-most, bottom-most coordinates.
6282
0
            if (psInfo->m_aoReprojectionInfo[0]
6283
0
                    .m_bWarnAboutDifferentCoordinateOperations)
6284
0
            {
6285
0
                struct OGRWKBPointVisitor final : public OGRWKBPointUpdater
6286
0
                {
6287
0
                    TargetLayerInfo::ReprojectionInfo &m_info;
6288
6289
0
                    explicit OGRWKBPointVisitor(
6290
0
                        TargetLayerInfo::ReprojectionInfo &info)
6291
0
                        : m_info(info)
6292
0
                    {
6293
0
                    }
6294
6295
0
                    bool update(bool bNeedSwap, void *x, void *y, void *z,
6296
0
                                void * /* m */) override
6297
0
                    {
6298
0
                        double dfX, dfY, dfZ;
6299
0
                        memcpy(&dfX, x, sizeof(double));
6300
0
                        memcpy(&dfY, y, sizeof(double));
6301
0
                        if (bNeedSwap)
6302
0
                        {
6303
0
                            CPL_SWAP64PTR(&dfX);
6304
0
                            CPL_SWAP64PTR(&dfY);
6305
0
                        }
6306
0
                        if (z)
6307
0
                        {
6308
0
                            memcpy(&dfZ, z, sizeof(double));
6309
0
                            if (bNeedSwap)
6310
0
                            {
6311
0
                                CPL_SWAP64PTR(&dfZ);
6312
0
                            }
6313
0
                        }
6314
0
                        else
6315
0
                            dfZ = 0;
6316
0
                        m_info.UpdateExtremePoints(dfX, dfY, dfZ);
6317
0
                        return true;
6318
0
                    }
6319
0
                };
6320
6321
0
                OGRWKBPointVisitor oVisitor(psInfo->m_aoReprojectionInfo[0]);
6322
0
                const GByte *pabyValidity =
6323
0
                    static_cast<const GByte *>(psGeomArray->buffers[0]);
6324
6325
0
                for (size_t i = 0; i < static_cast<size_t>(nArrayLength); ++i)
6326
0
                {
6327
0
                    const size_t iShifted =
6328
0
                        static_cast<size_t>(i + psGeomArray->offset);
6329
0
                    if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6330
0
                                          (1 << (iShifted % 8))) != 0)
6331
0
                    {
6332
0
                        const auto nWKBSize =
6333
0
                            panOffsets[iShifted + 1] - panOffsets[iShifted];
6334
0
                        OGRWKBUpdatePoints(abyModifiedWKB.data() +
6335
0
                                               panOffsets[iShifted],
6336
0
                                           nWKBSize, oVisitor);
6337
0
                    }
6338
0
                }
6339
0
            }
6340
6341
0
            std::atomic<bool> atomicRet{true};
6342
0
            const auto oReprojectionLambda =
6343
0
                [psGeomArray, nArrayLength, panOffsets, &atomicRet,
6344
0
                 &abyModifiedWKB, &poCT](int iThread, int nThreads)
6345
0
            {
6346
0
                OGRWKBTransformCache oCache;
6347
0
                OGREnvelope3D sEnv3D;
6348
0
                auto poThisCT =
6349
0
                    std::unique_ptr<OGRCoordinateTransformation>(poCT->Clone());
6350
0
                if (!poThisCT)
6351
0
                {
6352
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6353
0
                             "Cannot clone OGRCoordinateTransformation");
6354
0
                    atomicRet = false;
6355
0
                    return;
6356
0
                }
6357
6358
0
                const GByte *pabyValidity =
6359
0
                    static_cast<const GByte *>(psGeomArray->buffers[0]);
6360
0
                const size_t iStart =
6361
0
                    static_cast<size_t>(iThread * nArrayLength / nThreads);
6362
0
                const size_t iMax = static_cast<size_t>(
6363
0
                    (iThread + 1) * nArrayLength / nThreads);
6364
0
                for (size_t i = iStart; i < iMax; ++i)
6365
0
                {
6366
0
                    const size_t iShifted =
6367
0
                        static_cast<size_t>(i + psGeomArray->offset);
6368
0
                    if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6369
0
                                          (1 << (iShifted % 8))) != 0)
6370
0
                    {
6371
0
                        const auto nWKBSize =
6372
0
                            panOffsets[iShifted + 1] - panOffsets[iShifted];
6373
0
                        if (!OGRWKBTransform(
6374
0
                                abyModifiedWKB.data() + panOffsets[iShifted],
6375
0
                                nWKBSize, poThisCT.get(), oCache, sEnv3D))
6376
0
                        {
6377
0
                            CPLError(CE_Failure, CPLE_AppDefined,
6378
0
                                     "Reprojection failed");
6379
0
                            atomicRet = false;
6380
0
                            break;
6381
0
                        }
6382
0
                    }
6383
0
                }
6384
0
            };
6385
6386
0
            if (nArrayLength >= MIN_FEATURES_FOR_THREADED_REPROJ &&
6387
0
                nNumReprojectionThreads >= 2)
6388
0
            {
6389
0
                std::vector<std::future<void>> oTasks;
6390
0
                for (int iThread = 0; iThread < nNumReprojectionThreads;
6391
0
                     ++iThread)
6392
0
                {
6393
0
                    oTasks.emplace_back(std::async(std::launch::async,
6394
0
                                                   oReprojectionLambda, iThread,
6395
0
                                                   nNumReprojectionThreads));
6396
0
                }
6397
0
                for (auto &oTask : oTasks)
6398
0
                {
6399
0
                    oTask.get();
6400
0
                }
6401
0
            }
6402
0
            else
6403
0
            {
6404
0
                oReprojectionLambda(0, 1);
6405
0
            }
6406
6407
0
            bRet = atomicRet;
6408
0
            if (!bRet)
6409
0
            {
6410
0
                if (array.release)
6411
0
                    array.release(&array);
6412
0
                break;
6413
0
            }
6414
0
        }
6415
6416
        // Write batch to target layer
6417
0
        const bool bWriteOK = psInfo->m_poDstLayer->WriteArrowBatch(
6418
0
            &schema, &array, aosOptionsWriteArrowBatch.List());
6419
6420
0
        if (array.release)
6421
0
            array.release(&array);
6422
6423
0
        if (!bWriteOK)
6424
0
        {
6425
0
            CPLError(CE_Failure, CPLE_AppDefined, "WriteArrowBatch() failed");
6426
0
            bRet = false;
6427
0
            break;
6428
0
        }
6429
6430
        /* Report progress */
6431
0
        if (pfnProgress)
6432
0
        {
6433
0
            if (!pfnProgress(nCountLayerFeatures
6434
0
                                 ? nCount * 1.0 / nCountLayerFeatures
6435
0
                                 : 1.0,
6436
0
                             "", pProgressArg))
6437
0
            {
6438
0
                bGoOn = false;
6439
0
                bRet = false;
6440
0
            }
6441
0
        }
6442
6443
0
        if (pnReadFeatureCount)
6444
0
            *pnReadFeatureCount = nCount;
6445
0
    }
6446
6447
0
    schema.release(&schema);
6448
6449
0
    return bRet;
6450
0
}
6451
6452
/************************************************************************/
6453
/*                     LayerTranslator::Translate()                     */
6454
/************************************************************************/
6455
6456
bool LayerTranslator::Translate(
6457
    OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,
6458
    GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
6459
    GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress, void *pProgressArg,
6460
    const GDALVectorTranslateOptions *psOptions)
6461
0
{
6462
0
    if (psInfo->m_bUseWriteArrowBatch)
6463
0
    {
6464
0
        return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,
6465
0
                              pfnProgress, pProgressArg, psOptions);
6466
0
    }
6467
6468
0
    const int eGType = m_eGType;
6469
0
    const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
6470
6471
0
    OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;
6472
0
    OGRLayer *poDstLayer = psInfo->m_poDstLayer;
6473
0
    const int *const panMap = psInfo->m_anMap.data();
6474
0
    const int iSrcZField = psInfo->m_iSrcZField;
6475
0
    const bool bPreserveFID = psInfo->m_bPreserveFID;
6476
0
    const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
6477
0
    const auto poDstFDefn = poDstLayer->GetLayerDefn();
6478
0
    const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
6479
0
    const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
6480
0
    const bool bExplodeCollections =
6481
0
        m_bExplodeCollections && nDstGeomFieldCount <= 1;
6482
0
    const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;
6483
6484
0
    if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
6485
0
    {
6486
0
        if (nSrcGeomFieldCount == 1)
6487
0
        {
6488
0
            poOutputSRS = poSrcLayer->GetSpatialRef();
6489
0
        }
6490
0
        else if (iRequestedSrcGeomField > 0)
6491
0
        {
6492
0
            poOutputSRS = poSrcLayer->GetLayerDefn()
6493
0
                              ->GetGeomFieldDefn(iRequestedSrcGeomField)
6494
0
                              ->GetSpatialRef();
6495
0
        }
6496
0
    }
6497
6498
    /* -------------------------------------------------------------------- */
6499
    /*      Transfer features.                                              */
6500
    /* -------------------------------------------------------------------- */
6501
0
    if (psOptions->nGroupTransactions)
6502
0
    {
6503
0
        if (psOptions->nLayerTransaction)
6504
0
        {
6505
0
            if (poDstLayer->StartTransaction() == OGRERR_FAILURE)
6506
0
            {
6507
0
                delete poFeatureIn;
6508
0
                return false;
6509
0
            }
6510
0
        }
6511
0
    }
6512
6513
0
    std::unique_ptr<OGRFeature> poFeature;
6514
0
    std::unique_ptr<OGRFeature> poDstFeature(new OGRFeature(poDstFDefn));
6515
0
    int nFeaturesInTransaction = 0;
6516
0
    GIntBig nCount = 0; /* written + failed */
6517
0
    GIntBig nFeaturesWritten = 0;
6518
0
    bool bRunSetPrecisionEvaluated = false;
6519
0
    bool bRunSetPrecision = false;
6520
6521
0
    bool bRet = true;
6522
0
    CPLErrorReset();
6523
6524
0
    bool bSetupCTOK = false;
6525
0
    if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&
6526
0
        !psInfo->m_bPerFeatureCT)
6527
0
    {
6528
0
        bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6529
0
                             m_osDateLineOffset, m_poUserSourceSRS, nullptr,
6530
0
                             poOutputSRS, m_poGCPCoordTrans, false);
6531
0
    }
6532
6533
0
    while (true)
6534
0
    {
6535
0
        if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)
6536
0
        {
6537
0
            break;
6538
0
        }
6539
6540
0
        if (poFeatureIn != nullptr)
6541
0
            poFeature.reset(poFeatureIn);
6542
0
        else if (psOptions->nFIDToFetch != OGRNullFID)
6543
0
            poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));
6544
0
        else
6545
0
            poFeature.reset(poSrcLayer->GetNextFeature());
6546
6547
0
        if (poFeature == nullptr)
6548
0
        {
6549
0
            if (CPLGetLastErrorType() == CE_Failure)
6550
0
            {
6551
0
                bRet = false;
6552
0
            }
6553
0
            break;
6554
0
        }
6555
6556
0
        if (!bSetupCTOK &&
6557
0
            (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))
6558
0
        {
6559
0
            if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6560
0
                         m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),
6561
0
                         poOutputSRS, m_poGCPCoordTrans, true))
6562
0
            {
6563
0
                return false;
6564
0
            }
6565
0
        }
6566
6567
0
        psInfo->m_nFeaturesRead++;
6568
6569
0
        int nIters = 1;
6570
0
        std::unique_ptr<OGRGeometryCollection> poCollToExplode;
6571
0
        int iGeomCollToExplode = -1;
6572
0
        OGRGeometry *poSrcGeometry = nullptr;
6573
0
        if (bExplodeCollections)
6574
0
        {
6575
0
            if (iRequestedSrcGeomField >= 0)
6576
0
                poSrcGeometry =
6577
0
                    poFeature->GetGeomFieldRef(iRequestedSrcGeomField);
6578
0
            else
6579
0
                poSrcGeometry = poFeature->GetGeometryRef();
6580
0
            if (poSrcGeometry &&
6581
0
                OGR_GT_IsSubClassOf(poSrcGeometry->getGeometryType(),
6582
0
                                    wkbGeometryCollection))
6583
0
            {
6584
0
                const int nParts =
6585
0
                    poSrcGeometry->toGeometryCollection()->getNumGeometries();
6586
0
                if (nParts > 0 ||
6587
0
                    wkbFlatten(poSrcGeometry->getGeometryType()) !=
6588
0
                        wkbGeometryCollection)
6589
0
                {
6590
0
                    iGeomCollToExplode = iRequestedSrcGeomField >= 0
6591
0
                                             ? iRequestedSrcGeomField
6592
0
                                             : 0;
6593
0
                    poCollToExplode.reset(
6594
0
                        poFeature->StealGeometry(iGeomCollToExplode)
6595
0
                            ->toGeometryCollection());
6596
0
                    nIters = std::max(1, nParts);
6597
0
                }
6598
0
            }
6599
0
        }
6600
6601
0
        const GIntBig nSrcFID = poFeature->GetFID();
6602
0
        GIntBig nDesiredFID = OGRNullFID;
6603
0
        if (bPreserveFID)
6604
0
            nDesiredFID = nSrcFID;
6605
0
        else if (psInfo->m_iSrcFIDField >= 0 &&
6606
0
                 poFeature->IsFieldSetAndNotNull(psInfo->m_iSrcFIDField))
6607
0
            nDesiredFID =
6608
0
                poFeature->GetFieldAsInteger64(psInfo->m_iSrcFIDField);
6609
6610
0
        for (int iPart = 0; iPart < nIters; iPart++)
6611
0
        {
6612
0
            if (psOptions->nLayerTransaction &&
6613
0
                ++nFeaturesInTransaction == psOptions->nGroupTransactions)
6614
0
            {
6615
0
                if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||
6616
0
                    poDstLayer->StartTransaction() == OGRERR_FAILURE)
6617
0
                {
6618
0
                    return false;
6619
0
                }
6620
0
                nFeaturesInTransaction = 0;
6621
0
            }
6622
0
            else if (!psOptions->nLayerTransaction &&
6623
0
                     psOptions->nGroupTransactions > 0 &&
6624
0
                     ++nTotalEventsDone >= psOptions->nGroupTransactions)
6625
0
            {
6626
0
                if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||
6627
0
                    m_poODS->StartTransaction(psOptions->bForceTransaction) ==
6628
0
                        OGRERR_FAILURE)
6629
0
                {
6630
0
                    return false;
6631
0
                }
6632
0
                nTotalEventsDone = 0;
6633
0
            }
6634
6635
0
            CPLErrorReset();
6636
0
            if (psInfo->m_bCanAvoidSetFrom)
6637
0
            {
6638
0
                poDstFeature = std::move(poFeature);
6639
                // From now on, poFeature is null !
6640
0
                poDstFeature->SetFDefnUnsafe(poDstFDefn);
6641
0
                poDstFeature->SetFID(nDesiredFID);
6642
0
            }
6643
0
            else
6644
0
            {
6645
                /* Optimization to avoid duplicating the source geometry in the
6646
                 */
6647
                /* target feature : we steal it from the source feature for
6648
                 * now... */
6649
0
                std::unique_ptr<OGRGeometry> poStolenGeometry;
6650
0
                if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&
6651
0
                    (nDstGeomFieldCount == 1 ||
6652
0
                     (nDstGeomFieldCount == 0 && m_poClipSrcOri)))
6653
0
                {
6654
0
                    poStolenGeometry.reset(poFeature->StealGeometry());
6655
0
                }
6656
0
                else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)
6657
0
                {
6658
0
                    poStolenGeometry.reset(
6659
0
                        poFeature->StealGeometry(iRequestedSrcGeomField));
6660
0
                }
6661
6662
0
                if (nDstGeomFieldCount == 0 && poStolenGeometry &&
6663
0
                    m_poClipSrcOri)
6664
0
                {
6665
0
                    if (poStolenGeometry->IsEmpty())
6666
0
                        goto end_loop;
6667
6668
0
                    const auto clipGeomDesc =
6669
0
                        GetSrcClipGeom(poStolenGeometry->getSpatialReference());
6670
6671
0
                    if (clipGeomDesc.poGeom && clipGeomDesc.poEnv)
6672
0
                    {
6673
0
                        OGREnvelope oEnv;
6674
0
                        poStolenGeometry->getEnvelope(&oEnv);
6675
0
                        if (!clipGeomDesc.poEnv->Contains(oEnv) &&
6676
0
                            !(clipGeomDesc.poEnv->Intersects(oEnv) &&
6677
0
                              clipGeomDesc.poGeom->Intersects(
6678
0
                                  poStolenGeometry.get())))
6679
0
                        {
6680
0
                            goto end_loop;
6681
0
                        }
6682
0
                    }
6683
0
                }
6684
6685
0
                poDstFeature->Reset();
6686
6687
0
                if (poDstFeature->SetFrom(
6688
0
                        poFeature.get(), panMap, /* bForgiving = */ TRUE,
6689
0
                        /* bUseISO8601ForDateTimeAsString = */ true) !=
6690
0
                    OGRERR_NONE)
6691
0
                {
6692
0
                    if (psOptions->nGroupTransactions)
6693
0
                    {
6694
0
                        if (psOptions->nLayerTransaction)
6695
0
                        {
6696
0
                            if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6697
0
                            {
6698
0
                                return false;
6699
0
                            }
6700
0
                        }
6701
0
                    }
6702
6703
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6704
0
                             "Unable to translate feature " CPL_FRMT_GIB
6705
0
                             " from layer %s.",
6706
0
                             nSrcFID, poSrcLayer->GetName());
6707
6708
0
                    return false;
6709
0
                }
6710
6711
                /* ... and now we can attach the stolen geometry */
6712
0
                if (poStolenGeometry)
6713
0
                {
6714
0
                    poDstFeature->SetGeometryDirectly(
6715
0
                        poStolenGeometry.release());
6716
0
                }
6717
6718
0
                if (!psInfo->m_oMapResolved.empty())
6719
0
                {
6720
0
                    for (const auto &kv : psInfo->m_oMapResolved)
6721
0
                    {
6722
0
                        const int nDstField = kv.first;
6723
0
                        const int nSrcField = kv.second.nSrcField;
6724
0
                        if (poFeature->IsFieldSetAndNotNull(nSrcField))
6725
0
                        {
6726
0
                            const auto poDomain = kv.second.poDomain;
6727
0
                            const auto &oMapKV =
6728
0
                                psInfo->m_oMapDomainToKV[poDomain];
6729
0
                            const auto iter = oMapKV.find(
6730
0
                                poFeature->GetFieldAsString(nSrcField));
6731
0
                            if (iter != oMapKV.end())
6732
0
                            {
6733
0
                                poDstFeature->SetField(nDstField,
6734
0
                                                       iter->second.c_str());
6735
0
                            }
6736
0
                        }
6737
0
                    }
6738
0
                }
6739
6740
0
                if (nDesiredFID != OGRNullFID)
6741
0
                    poDstFeature->SetFID(nDesiredFID);
6742
0
            }
6743
6744
0
            if (psOptions->bEmptyStrAsNull)
6745
0
            {
6746
0
                for (int i = 0; i < poDstFeature->GetFieldCount(); i++)
6747
0
                {
6748
0
                    if (!poDstFeature->IsFieldSetAndNotNull(i))
6749
0
                        continue;
6750
0
                    auto fieldDef = poDstFeature->GetFieldDefnRef(i);
6751
0
                    if (fieldDef->GetType() != OGRFieldType::OFTString)
6752
0
                        continue;
6753
0
                    auto str = poDstFeature->GetFieldAsString(i);
6754
0
                    if (strcmp(str, "") == 0)
6755
0
                        poDstFeature->SetFieldNull(i);
6756
0
                }
6757
0
            }
6758
6759
0
            if (!psInfo->m_anDateTimeFieldIdx.empty())
6760
0
            {
6761
0
                for (int i : psInfo->m_anDateTimeFieldIdx)
6762
0
                {
6763
0
                    if (!poDstFeature->IsFieldSetAndNotNull(i))
6764
0
                        continue;
6765
0
                    auto psField = poDstFeature->GetRawFieldRef(i);
6766
0
                    if (psField->Date.TZFlag == 0 || psField->Date.TZFlag == 1)
6767
0
                        continue;
6768
6769
0
                    const int nTZOffsetInSec =
6770
0
                        (psField->Date.TZFlag - 100) * 15 * 60;
6771
0
                    if (nTZOffsetInSec == psOptions->nTZOffsetInSec)
6772
0
                        continue;
6773
6774
0
                    struct tm brokendowntime;
6775
0
                    memset(&brokendowntime, 0, sizeof(brokendowntime));
6776
0
                    brokendowntime.tm_year = psField->Date.Year - 1900;
6777
0
                    brokendowntime.tm_mon = psField->Date.Month - 1;
6778
0
                    brokendowntime.tm_mday = psField->Date.Day;
6779
0
                    GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
6780
0
                    int nSec = psField->Date.Hour * 3600 +
6781
0
                               psField->Date.Minute * 60 +
6782
0
                               static_cast<int>(psField->Date.Second);
6783
0
                    nSec += psOptions->nTZOffsetInSec - nTZOffsetInSec;
6784
0
                    nUnixTime += nSec;
6785
0
                    CPLUnixTimeToYMDHMS(nUnixTime, &brokendowntime);
6786
6787
0
                    psField->Date.Year =
6788
0
                        static_cast<GInt16>(brokendowntime.tm_year + 1900);
6789
0
                    psField->Date.Month =
6790
0
                        static_cast<GByte>(brokendowntime.tm_mon + 1);
6791
0
                    psField->Date.Day =
6792
0
                        static_cast<GByte>(brokendowntime.tm_mday);
6793
0
                    psField->Date.Hour =
6794
0
                        static_cast<GByte>(brokendowntime.tm_hour);
6795
0
                    psField->Date.Minute =
6796
0
                        static_cast<GByte>(brokendowntime.tm_min);
6797
0
                    psField->Date.Second = static_cast<float>(
6798
0
                        brokendowntime.tm_sec + fmod(psField->Date.Second, 1));
6799
0
                    psField->Date.TZFlag = static_cast<GByte>(
6800
0
                        100 + psOptions->nTZOffsetInSec / (15 * 60));
6801
0
                }
6802
0
            }
6803
6804
            /* Erase native data if asked explicitly */
6805
0
            if (!m_bNativeData)
6806
0
            {
6807
0
                poDstFeature->SetNativeData(nullptr);
6808
0
                poDstFeature->SetNativeMediaType(nullptr);
6809
0
            }
6810
6811
0
            for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
6812
0
            {
6813
0
                std::unique_ptr<OGRGeometry> poDstGeometry;
6814
6815
0
                if (poCollToExplode && iGeom == iGeomCollToExplode)
6816
0
                {
6817
0
                    if (poSrcGeometry && poCollToExplode->IsEmpty())
6818
0
                    {
6819
0
                        const OGRwkbGeometryType eSrcType =
6820
0
                            poSrcGeometry->getGeometryType();
6821
0
                        const OGRwkbGeometryType eSrcFlattenType =
6822
0
                            wkbFlatten(eSrcType);
6823
0
                        OGRwkbGeometryType eDstType = eSrcType;
6824
0
                        switch (eSrcFlattenType)
6825
0
                        {
6826
0
                            case wkbMultiPoint:
6827
0
                                eDstType = wkbPoint;
6828
0
                                break;
6829
0
                            case wkbMultiLineString:
6830
0
                                eDstType = wkbLineString;
6831
0
                                break;
6832
0
                            case wkbMultiPolygon:
6833
0
                                eDstType = wkbPolygon;
6834
0
                                break;
6835
0
                            case wkbMultiCurve:
6836
0
                                eDstType = wkbCompoundCurve;
6837
0
                                break;
6838
0
                            case wkbMultiSurface:
6839
0
                                eDstType = wkbCurvePolygon;
6840
0
                                break;
6841
0
                            default:
6842
0
                                break;
6843
0
                        }
6844
0
                        eDstType =
6845
0
                            OGR_GT_SetModifier(eDstType, OGR_GT_HasZ(eSrcType),
6846
0
                                               OGR_GT_HasM(eSrcType));
6847
0
                        poDstGeometry.reset(
6848
0
                            OGRGeometryFactory::createGeometry(eDstType));
6849
0
                    }
6850
0
                    else
6851
0
                    {
6852
0
                        OGRGeometry *poPart =
6853
0
                            poCollToExplode->getGeometryRef(0);
6854
0
                        poCollToExplode->removeGeometry(0, FALSE);
6855
0
                        poDstGeometry.reset(poPart);
6856
0
                    }
6857
0
                }
6858
0
                else
6859
0
                {
6860
0
                    poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));
6861
0
                }
6862
0
                if (poDstGeometry == nullptr)
6863
0
                    continue;
6864
6865
                // poFeature hasn't been moved if iSrcZField != -1
6866
                // cppcheck-suppress accessMoved
6867
0
                if (iSrcZField != -1 && poFeature != nullptr)
6868
0
                {
6869
0
                    SetZ(poDstGeometry.get(),
6870
0
                         poFeature->GetFieldAsDouble(iSrcZField));
6871
                    /* This will correct the coordinate dimension to 3 */
6872
0
                    poDstGeometry.reset(poDstGeometry->clone());
6873
0
                }
6874
6875
0
                if (m_nCoordDim == 2 || m_nCoordDim == 3)
6876
0
                {
6877
0
                    poDstGeometry->setCoordinateDimension(m_nCoordDim);
6878
0
                }
6879
0
                else if (m_nCoordDim == 4)
6880
0
                {
6881
0
                    poDstGeometry->set3D(TRUE);
6882
0
                    poDstGeometry->setMeasured(TRUE);
6883
0
                }
6884
0
                else if (m_nCoordDim == COORD_DIM_XYM)
6885
0
                {
6886
0
                    poDstGeometry->set3D(FALSE);
6887
0
                    poDstGeometry->setMeasured(TRUE);
6888
0
                }
6889
0
                else if (m_nCoordDim == COORD_DIM_LAYER_DIM)
6890
0
                {
6891
0
                    const OGRwkbGeometryType eDstLayerGeomType =
6892
0
                        poDstLayer->GetLayerDefn()
6893
0
                            ->GetGeomFieldDefn(iGeom)
6894
0
                            ->GetType();
6895
0
                    poDstGeometry->set3D(wkbHasZ(eDstLayerGeomType));
6896
0
                    poDstGeometry->setMeasured(wkbHasM(eDstLayerGeomType));
6897
0
                }
6898
6899
0
                if (m_eGeomOp == GEOMOP_SEGMENTIZE)
6900
0
                {
6901
0
                    if (m_dfGeomOpParam > 0)
6902
0
                        poDstGeometry->segmentize(m_dfGeomOpParam);
6903
0
                }
6904
0
                else if (m_eGeomOp == GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY)
6905
0
                {
6906
0
                    if (m_dfGeomOpParam > 0)
6907
0
                    {
6908
0
                        auto poNewGeom = std::unique_ptr<OGRGeometry>(
6909
0
                            poDstGeometry->SimplifyPreserveTopology(
6910
0
                                m_dfGeomOpParam));
6911
0
                        if (poNewGeom)
6912
0
                        {
6913
0
                            poDstGeometry = std::move(poNewGeom);
6914
0
                        }
6915
0
                    }
6916
0
                }
6917
6918
0
                if (m_poClipSrcOri)
6919
0
                {
6920
0
                    if (poDstGeometry->IsEmpty())
6921
0
                        goto end_loop;
6922
6923
0
                    const auto clipGeomDesc =
6924
0
                        GetSrcClipGeom(poDstGeometry->getSpatialReference());
6925
6926
0
                    if (!(clipGeomDesc.poGeom && clipGeomDesc.poEnv))
6927
0
                        goto end_loop;
6928
6929
0
                    OGREnvelope oDstEnv;
6930
0
                    poDstGeometry->getEnvelope(&oDstEnv);
6931
6932
0
                    if (!(clipGeomDesc.bGeomIsRectangle &&
6933
0
                          clipGeomDesc.poEnv->Contains(oDstEnv)))
6934
0
                    {
6935
0
                        std::unique_ptr<OGRGeometry> poClipped;
6936
0
                        if (clipGeomDesc.poEnv->Intersects(oDstEnv))
6937
0
                        {
6938
0
                            poClipped.reset(clipGeomDesc.poGeom->Intersection(
6939
0
                                poDstGeometry.get()));
6940
0
                        }
6941
0
                        if (poClipped == nullptr || poClipped->IsEmpty())
6942
0
                        {
6943
0
                            goto end_loop;
6944
0
                        }
6945
6946
0
                        const int nDim = poDstGeometry->getDimension();
6947
0
                        if (poClipped->getDimension() < nDim &&
6948
0
                            wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
6949
0
                                           ->GetType()) != wkbUnknown)
6950
0
                        {
6951
0
                            CPLDebug(
6952
0
                                "OGR2OGR",
6953
0
                                "Discarding feature " CPL_FRMT_GIB
6954
0
                                " of layer %s, "
6955
0
                                "as its intersection with -clipsrc is a %s "
6956
0
                                "whereas the input is a %s",
6957
0
                                nSrcFID, poSrcLayer->GetName(),
6958
0
                                OGRToOGCGeomType(poClipped->getGeometryType()),
6959
0
                                OGRToOGCGeomType(
6960
0
                                    poDstGeometry->getGeometryType()));
6961
0
                            goto end_loop;
6962
0
                        }
6963
6964
0
                        poDstGeometry = std::move(poClipped);
6965
0
                    }
6966
0
                }
6967
6968
0
                OGRCoordinateTransformation *const poCT =
6969
0
                    psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6970
0
                char **const papszTransformOptions =
6971
0
                    psInfo->m_aoReprojectionInfo[iGeom]
6972
0
                        .m_aosTransformOptions.List();
6973
0
                const bool bReprojCanInvalidateValidity =
6974
0
                    psInfo->m_aoReprojectionInfo[iGeom]
6975
0
                        .m_bCanInvalidateValidity;
6976
6977
0
                if (poCT != nullptr || papszTransformOptions != nullptr)
6978
0
                {
6979
                    // If we need to change the geometry type to linear, and
6980
                    // we have a geometry with curves, then convert it to
6981
                    // linear first, to avoid invalidities due to the fact
6982
                    // that validity of arc portions isn't always kept while
6983
                    // reprojecting and then discretizing.
6984
0
                    if (bReprojCanInvalidateValidity &&
6985
0
                        (!psInfo->m_bSupportCurves ||
6986
0
                         m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
6987
0
                         m_eGeomTypeConversion ==
6988
0
                             GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))
6989
0
                    {
6990
0
                        if (poDstGeometry->hasCurveGeometry(TRUE))
6991
0
                        {
6992
0
                            OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
6993
0
                                poDstGeometry->getGeometryType());
6994
0
                            poDstGeometry.reset(OGRGeometryFactory::forceTo(
6995
0
                                poDstGeometry.release(), eTargetType));
6996
0
                        }
6997
0
                    }
6998
0
                    else if (bReprojCanInvalidateValidity &&
6999
0
                             eGType != GEOMTYPE_UNCHANGED &&
7000
0
                             !OGR_GT_IsNonLinear(
7001
0
                                 static_cast<OGRwkbGeometryType>(eGType)) &&
7002
0
                             poDstGeometry->hasCurveGeometry(TRUE))
7003
0
                    {
7004
0
                        poDstGeometry.reset(OGRGeometryFactory::forceTo(
7005
0
                            poDstGeometry.release(),
7006
0
                            static_cast<OGRwkbGeometryType>(eGType)));
7007
0
                    }
7008
7009
                    // Collect left-most, right-most, top-most, bottom-most coordinates.
7010
0
                    if (psInfo->m_aoReprojectionInfo[iGeom]
7011
0
                            .m_bWarnAboutDifferentCoordinateOperations)
7012
0
                    {
7013
0
                        struct Visitor : public OGRDefaultConstGeometryVisitor
7014
0
                        {
7015
0
                            TargetLayerInfo::ReprojectionInfo &m_info;
7016
7017
0
                            explicit Visitor(
7018
0
                                TargetLayerInfo::ReprojectionInfo &info)
7019
0
                                : m_info(info)
7020
0
                            {
7021
0
                            }
7022
7023
0
                            using OGRDefaultConstGeometryVisitor::visit;
7024
7025
0
                            void visit(const OGRPoint *point) override
7026
0
                            {
7027
0
                                m_info.UpdateExtremePoints(point->getX(),
7028
0
                                                           point->getY(),
7029
0
                                                           point->getZ());
7030
0
                            }
7031
0
                        };
7032
7033
0
                        Visitor oVisit(psInfo->m_aoReprojectionInfo[iGeom]);
7034
0
                        poDstGeometry->accept(&oVisit);
7035
0
                    }
7036
7037
0
                    for (int iIter = 0; iIter < 2; ++iIter)
7038
0
                    {
7039
0
                        auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(
7040
0
                            OGRGeometryFactory::transformWithOptions(
7041
0
                                poDstGeometry.get(), poCT,
7042
0
                                papszTransformOptions,
7043
0
                                m_transformWithOptionsCache));
7044
0
                        if (poReprojectedGeom == nullptr)
7045
0
                        {
7046
0
                            if (psOptions->nGroupTransactions)
7047
0
                            {
7048
0
                                if (psOptions->nLayerTransaction)
7049
0
                                {
7050
0
                                    if (poDstLayer->CommitTransaction() !=
7051
0
                                            OGRERR_NONE &&
7052
0
                                        !psOptions->bSkipFailures)
7053
0
                                    {
7054
0
                                        return false;
7055
0
                                    }
7056
0
                                }
7057
0
                            }
7058
7059
0
                            CPLError(CE_Failure, CPLE_AppDefined,
7060
0
                                     "Failed to reproject feature " CPL_FRMT_GIB
7061
0
                                     " (geometry probably out of source or "
7062
0
                                     "destination SRS).",
7063
0
                                     nSrcFID);
7064
0
                            if (!psOptions->bSkipFailures)
7065
0
                            {
7066
0
                                return false;
7067
0
                            }
7068
0
                        }
7069
7070
                        // Check if a curve geometry is no longer valid after
7071
                        // reprojection
7072
0
                        const auto eType = poDstGeometry->getGeometryType();
7073
0
                        const auto eFlatType = wkbFlatten(eType);
7074
7075
0
                        const auto IsValid = [](const OGRGeometry *poGeom)
7076
0
                        {
7077
0
                            CPLErrorHandlerPusher oErrorHandler(
7078
0
                                CPLQuietErrorHandler);
7079
0
                            return poGeom->IsValid();
7080
0
                        };
7081
7082
0
                        if (iIter == 0 && bReprojCanInvalidateValidity &&
7083
0
                            OGRGeometryFactory::haveGEOS() &&
7084
0
                            (eFlatType == wkbCurvePolygon ||
7085
0
                             eFlatType == wkbCompoundCurve ||
7086
0
                             eFlatType == wkbMultiCurve ||
7087
0
                             eFlatType == wkbMultiSurface) &&
7088
0
                            poDstGeometry->hasCurveGeometry(TRUE) &&
7089
0
                            IsValid(poDstGeometry.get()))
7090
0
                        {
7091
0
                            OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
7092
0
                                poDstGeometry->getGeometryType());
7093
0
                            auto poDstGeometryTmp =
7094
0
                                std::unique_ptr<OGRGeometry>(
7095
0
                                    OGRGeometryFactory::forceTo(
7096
0
                                        poReprojectedGeom->clone(),
7097
0
                                        eTargetType));
7098
0
                            if (!IsValid(poDstGeometryTmp.get()))
7099
0
                            {
7100
0
                                CPLDebug("OGR2OGR",
7101
0
                                         "Curve geometry no longer valid after "
7102
0
                                         "reprojection: transforming it into "
7103
0
                                         "linear one before reprojecting");
7104
0
                                poDstGeometry.reset(OGRGeometryFactory::forceTo(
7105
0
                                    poDstGeometry.release(), eTargetType));
7106
0
                                poDstGeometry.reset(OGRGeometryFactory::forceTo(
7107
0
                                    poDstGeometry.release(), eType));
7108
0
                            }
7109
0
                            else
7110
0
                            {
7111
0
                                poDstGeometry = std::move(poReprojectedGeom);
7112
0
                                break;
7113
0
                            }
7114
0
                        }
7115
0
                        else
7116
0
                        {
7117
0
                            poDstGeometry = std::move(poReprojectedGeom);
7118
0
                            break;
7119
0
                        }
7120
0
                    }
7121
0
                }
7122
0
                else if (poOutputSRS != nullptr)
7123
0
                {
7124
0
                    poDstGeometry->assignSpatialReference(poOutputSRS);
7125
0
                }
7126
7127
0
                if (poDstGeometry != nullptr)
7128
0
                {
7129
0
                    if (m_poClipDstOri)
7130
0
                    {
7131
0
                        if (poDstGeometry->IsEmpty())
7132
0
                            goto end_loop;
7133
7134
0
                        const auto clipGeomDesc = GetDstClipGeom(
7135
0
                            poDstGeometry->getSpatialReference());
7136
0
                        if (!clipGeomDesc.poGeom || !clipGeomDesc.poEnv)
7137
0
                        {
7138
0
                            goto end_loop;
7139
0
                        }
7140
7141
0
                        OGREnvelope oDstEnv;
7142
0
                        poDstGeometry->getEnvelope(&oDstEnv);
7143
7144
0
                        if (!(clipGeomDesc.bGeomIsRectangle &&
7145
0
                              clipGeomDesc.poEnv->Contains(oDstEnv)))
7146
0
                        {
7147
0
                            std::unique_ptr<OGRGeometry> poClipped;
7148
0
                            if (clipGeomDesc.poEnv->Intersects(oDstEnv))
7149
0
                            {
7150
0
                                poClipped.reset(
7151
0
                                    clipGeomDesc.poGeom->Intersection(
7152
0
                                        poDstGeometry.get()));
7153
0
                            }
7154
7155
0
                            if (poClipped == nullptr || poClipped->IsEmpty())
7156
0
                            {
7157
0
                                goto end_loop;
7158
0
                            }
7159
7160
0
                            const int nDim = poDstGeometry->getDimension();
7161
0
                            if (poClipped->getDimension() < nDim &&
7162
0
                                wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
7163
0
                                               ->GetType()) != wkbUnknown)
7164
0
                            {
7165
0
                                CPLDebug(
7166
0
                                    "OGR2OGR",
7167
0
                                    "Discarding feature " CPL_FRMT_GIB
7168
0
                                    " of layer %s, "
7169
0
                                    "as its intersection with -clipdst is a %s "
7170
0
                                    "whereas the input is a %s",
7171
0
                                    nSrcFID, poSrcLayer->GetName(),
7172
0
                                    OGRToOGCGeomType(
7173
0
                                        poClipped->getGeometryType()),
7174
0
                                    OGRToOGCGeomType(
7175
0
                                        poDstGeometry->getGeometryType()));
7176
0
                                goto end_loop;
7177
0
                            }
7178
7179
0
                            poDstGeometry = std::move(poClipped);
7180
0
                        }
7181
0
                    }
7182
7183
0
                    if (psOptions->dfXYRes !=
7184
0
                            OGRGeomCoordinatePrecision::UNKNOWN &&
7185
0
                        OGRGeometryFactory::haveGEOS() &&
7186
0
                        !poDstGeometry->hasCurveGeometry())
7187
0
                    {
7188
                        // OGR_APPLY_GEOM_SET_PRECISION default value for
7189
                        // OGRLayer::CreateFeature() purposes, but here in the
7190
                        // ogr2ogr -xyRes context, we force calling SetPrecision(),
7191
                        // unless the user explicitly asks not to do it by
7192
                        // setting the config option to NO.
7193
0
                        if (!bRunSetPrecisionEvaluated)
7194
0
                        {
7195
0
                            bRunSetPrecisionEvaluated = true;
7196
0
                            bRunSetPrecision = CPLTestBool(CPLGetConfigOption(
7197
0
                                "OGR_APPLY_GEOM_SET_PRECISION", "YES"));
7198
0
                        }
7199
0
                        if (bRunSetPrecision)
7200
0
                        {
7201
0
                            auto poNewGeom = std::unique_ptr<OGRGeometry>(
7202
0
                                poDstGeometry->SetPrecision(psOptions->dfXYRes,
7203
0
                                                            /* nFlags = */ 0));
7204
0
                            if (!poNewGeom)
7205
0
                                goto end_loop;
7206
0
                            poDstGeometry = std::move(poNewGeom);
7207
0
                        }
7208
0
                    }
7209
7210
0
                    if (m_bMakeValid)
7211
0
                    {
7212
0
                        const bool bIsGeomCollection =
7213
0
                            wkbFlatten(poDstGeometry->getGeometryType()) ==
7214
0
                            wkbGeometryCollection;
7215
0
                        auto poNewGeom = std::unique_ptr<OGRGeometry>(
7216
0
                            poDstGeometry->MakeValid());
7217
0
                        if (!poNewGeom)
7218
0
                            goto end_loop;
7219
0
                        poDstGeometry = std::move(poNewGeom);
7220
0
                        if (!bIsGeomCollection)
7221
0
                        {
7222
0
                            poDstGeometry.reset(
7223
0
                                OGRGeometryFactory::
7224
0
                                    removeLowerDimensionSubGeoms(
7225
0
                                        poDstGeometry.get()));
7226
0
                        }
7227
0
                    }
7228
7229
0
                    if (m_bSkipInvalidGeom && !poDstGeometry->IsValid())
7230
0
                        goto end_loop;
7231
7232
0
                    if (m_eGeomTypeConversion != GTC_DEFAULT)
7233
0
                    {
7234
0
                        OGRwkbGeometryType eTargetType =
7235
0
                            poDstGeometry->getGeometryType();
7236
0
                        eTargetType =
7237
0
                            ConvertType(m_eGeomTypeConversion, eTargetType);
7238
0
                        poDstGeometry.reset(OGRGeometryFactory::forceTo(
7239
0
                            poDstGeometry.release(), eTargetType));
7240
0
                    }
7241
0
                    else if (eGType != GEOMTYPE_UNCHANGED)
7242
0
                    {
7243
0
                        poDstGeometry.reset(OGRGeometryFactory::forceTo(
7244
0
                            poDstGeometry.release(),
7245
0
                            static_cast<OGRwkbGeometryType>(eGType)));
7246
0
                    }
7247
0
                }
7248
7249
0
                poDstFeature->SetGeomFieldDirectly(iGeom,
7250
0
                                                   poDstGeometry.release());
7251
0
            }
7252
7253
0
            CPLErrorReset();
7254
0
            if ((psOptions->bUpsert
7255
0
                     ? poDstLayer->UpsertFeature(poDstFeature.get())
7256
0
                     : poDstLayer->CreateFeature(poDstFeature.get())) ==
7257
0
                OGRERR_NONE)
7258
0
            {
7259
0
                nFeaturesWritten++;
7260
0
                if (nDesiredFID != OGRNullFID &&
7261
0
                    poDstFeature->GetFID() != nDesiredFID)
7262
0
                {
7263
0
                    CPLError(CE_Warning, CPLE_AppDefined,
7264
0
                             "Feature id " CPL_FRMT_GIB " not preserved",
7265
0
                             nDesiredFID);
7266
0
                }
7267
0
            }
7268
0
            else if (!psOptions->bSkipFailures)
7269
0
            {
7270
0
                if (psOptions->nGroupTransactions)
7271
0
                {
7272
0
                    if (psOptions->nLayerTransaction)
7273
0
                        poDstLayer->RollbackTransaction();
7274
0
                }
7275
7276
0
                CPLError(CE_Failure, CPLE_AppDefined,
7277
0
                         "Unable to write feature " CPL_FRMT_GIB
7278
0
                         " from layer %s.",
7279
0
                         nSrcFID, poSrcLayer->GetName());
7280
7281
0
                return false;
7282
0
            }
7283
0
            else
7284
0
            {
7285
0
                CPLDebug("GDALVectorTranslate",
7286
0
                         "Unable to write feature " CPL_FRMT_GIB
7287
0
                         " into layer %s.",
7288
0
                         nSrcFID, poSrcLayer->GetName());
7289
0
                if (psOptions->nGroupTransactions)
7290
0
                {
7291
0
                    if (psOptions->nLayerTransaction)
7292
0
                    {
7293
0
                        poDstLayer->RollbackTransaction();
7294
0
                        CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());
7295
0
                    }
7296
0
                    else
7297
0
                    {
7298
0
                        m_poODS->RollbackTransaction();
7299
0
                        m_poODS->StartTransaction(psOptions->bForceTransaction);
7300
0
                    }
7301
0
                }
7302
0
            }
7303
7304
0
        end_loop:;  // nothing
7305
0
        }
7306
7307
        /* Report progress */
7308
0
        nCount++;
7309
0
        bool bGoOn = true;
7310
0
        if (pfnProgress)
7311
0
        {
7312
0
            bGoOn = pfnProgress(nCountLayerFeatures
7313
0
                                    ? nCount * 1.0 / nCountLayerFeatures
7314
0
                                    : 1.0,
7315
0
                                "", pProgressArg) != FALSE;
7316
0
        }
7317
0
        if (!bGoOn)
7318
0
        {
7319
0
            bRet = false;
7320
0
            break;
7321
0
        }
7322
7323
0
        if (pnReadFeatureCount)
7324
0
            *pnReadFeatureCount = nCount;
7325
7326
0
        if (psOptions->nFIDToFetch != OGRNullFID)
7327
0
            break;
7328
0
        if (poFeatureIn != nullptr)
7329
0
            break;
7330
0
    }
7331
7332
0
    if (psOptions->nGroupTransactions)
7333
0
    {
7334
0
        if (psOptions->nLayerTransaction)
7335
0
        {
7336
0
            if (poDstLayer->CommitTransaction() != OGRERR_NONE)
7337
0
                bRet = false;
7338
0
        }
7339
0
    }
7340
7341
0
    if (poFeatureIn == nullptr)
7342
0
    {
7343
0
        CPLDebug("GDALVectorTranslate",
7344
0
                 CPL_FRMT_GIB " features written in layer '%s'",
7345
0
                 nFeaturesWritten, poDstLayer->GetName());
7346
0
    }
7347
7348
0
    return bRet;
7349
0
}
7350
7351
/************************************************************************/
7352
/*                LayerTranslator::GetDstClipGeom()                     */
7353
/************************************************************************/
7354
7355
/** Returns the destination clip geometry and its envelope
7356
 *
7357
 * @param poGeomSRS The SRS into which the destination clip geometry should be
7358
 *                  expressed.
7359
 * @return the destination clip geometry and its envelope, or (nullptr, nullptr)
7360
 */
7361
LayerTranslator::ClipGeomDesc
7362
LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS)
7363
0
{
7364
0
    if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS)
7365
0
    {
7366
0
        auto poClipDstSRS = m_poClipDstOri->getSpatialReference();
7367
0
        if (poClipDstSRS && poGeomSRS && !poClipDstSRS->IsSame(poGeomSRS))
7368
0
        {
7369
            // Transform clip geom to geometry SRS
7370
0
            m_poClipDstReprojectedToDstSRS.reset(m_poClipDstOri->clone());
7371
0
            if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) !=
7372
0
                OGRERR_NONE)
7373
0
            {
7374
0
                return ClipGeomDesc();
7375
0
            }
7376
0
            m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS;
7377
0
        }
7378
0
        else if (!poClipDstSRS && poGeomSRS)
7379
0
        {
7380
0
            if (!m_bWarnedClipDstSRS)
7381
0
            {
7382
0
                m_bWarnedClipDstSRS = true;
7383
0
                CPLError(CE_Warning, CPLE_AppDefined,
7384
0
                         "Clip destination geometry has no "
7385
0
                         "attached SRS, but the feature's "
7386
0
                         "geometry has one. Assuming clip "
7387
0
                         "destination geometry SRS is the "
7388
0
                         "same as the feature's geometry");
7389
0
            }
7390
0
        }
7391
0
        m_oClipDstEnv = OGREnvelope();
7392
0
    }
7393
7394
0
    const auto poGeom = m_poClipDstReprojectedToDstSRS
7395
0
                            ? m_poClipDstReprojectedToDstSRS.get()
7396
0
                            : m_poClipDstOri;
7397
0
    if (poGeom && !m_oClipDstEnv.IsInit())
7398
0
    {
7399
0
        poGeom->getEnvelope(&m_oClipDstEnv);
7400
0
        m_bClipDstIsRectangle = poGeom->IsRectangle();
7401
0
    }
7402
0
    ClipGeomDesc ret;
7403
0
    ret.poGeom = poGeom;
7404
0
    ret.poEnv = poGeom ? &m_oClipDstEnv : nullptr;
7405
0
    ret.bGeomIsRectangle = m_bClipDstIsRectangle;
7406
0
    return ret;
7407
0
}
7408
7409
/************************************************************************/
7410
/*                LayerTranslator::GetSrcClipGeom()                     */
7411
/************************************************************************/
7412
7413
/** Returns the source clip geometry and its envelope
7414
 *
7415
 * @param poGeomSRS The SRS into which the source clip geometry should be
7416
 *                  expressed.
7417
 * @return the source clip geometry and its envelope, or (nullptr, nullptr)
7418
 */
7419
LayerTranslator::ClipGeomDesc
7420
LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS)
7421
0
{
7422
0
    if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS)
7423
0
    {
7424
0
        auto poClipSrcSRS = m_poClipSrcOri->getSpatialReference();
7425
0
        if (poClipSrcSRS && poGeomSRS && !poClipSrcSRS->IsSame(poGeomSRS))
7426
0
        {
7427
            // Transform clip geom to geometry SRS
7428
0
            m_poClipSrcReprojectedToSrcSRS.reset(m_poClipSrcOri->clone());
7429
0
            if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) !=
7430
0
                OGRERR_NONE)
7431
0
            {
7432
0
                return ClipGeomDesc();
7433
0
            }
7434
0
            m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS;
7435
0
        }
7436
0
        else if (!poClipSrcSRS && poGeomSRS)
7437
0
        {
7438
0
            if (!m_bWarnedClipSrcSRS)
7439
0
            {
7440
0
                m_bWarnedClipSrcSRS = true;
7441
0
                CPLError(CE_Warning, CPLE_AppDefined,
7442
0
                         "Clip source geometry has no attached SRS, "
7443
0
                         "but the feature's geometry has one. "
7444
0
                         "Assuming clip source geometry SRS is the "
7445
0
                         "same as the feature's geometry");
7446
0
            }
7447
0
        }
7448
0
        m_oClipSrcEnv = OGREnvelope();
7449
0
    }
7450
7451
0
    const auto poGeom = m_poClipSrcReprojectedToSrcSRS
7452
0
                            ? m_poClipSrcReprojectedToSrcSRS.get()
7453
0
                            : m_poClipSrcOri;
7454
0
    if (poGeom && !m_oClipSrcEnv.IsInit())
7455
0
    {
7456
0
        poGeom->getEnvelope(&m_oClipSrcEnv);
7457
0
        m_bClipSrcIsRectangle = poGeom->IsRectangle();
7458
0
    }
7459
0
    ClipGeomDesc ret;
7460
0
    ret.poGeom = poGeom;
7461
0
    ret.poEnv = poGeom ? &m_oClipSrcEnv : nullptr;
7462
0
    ret.bGeomIsRectangle = m_bClipDstIsRectangle;
7463
0
    return ret;
7464
0
}
7465
7466
/************************************************************************/
7467
/*               TargetLayerInfo::CheckSameCoordinateOperation()        */
7468
/************************************************************************/
7469
7470
void TargetLayerInfo::CheckSameCoordinateOperation() const
7471
0
{
7472
0
    for (auto &info : m_aoReprojectionInfo)
7473
0
    {
7474
0
        if (info.m_bWarnAboutDifferentCoordinateOperations &&
7475
0
            info.m_dfLeftX <= info.m_dfRightX)
7476
0
        {
7477
            // Start recording if different coordinate operations are
7478
            // going to be used
7479
0
            OGRProjCTDifferentOperationsStart(info.m_poCT.get());
7480
7481
0
            {
7482
0
                CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
7483
0
                {
7484
0
                    double dfX = info.m_dfLeftX;
7485
0
                    double dfY = info.m_dfLeftY;
7486
0
                    double dfZ = info.m_dfLeftZ;
7487
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7488
0
                }
7489
7490
0
                {
7491
0
                    double dfX = info.m_dfRightX;
7492
0
                    double dfY = info.m_dfRightY;
7493
0
                    double dfZ = info.m_dfRightZ;
7494
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7495
0
                }
7496
7497
0
                {
7498
0
                    double dfX = info.m_dfTopX;
7499
0
                    double dfY = info.m_dfTopY;
7500
0
                    double dfZ = info.m_dfTopZ;
7501
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7502
0
                }
7503
7504
0
                {
7505
0
                    double dfX = info.m_dfBottomX;
7506
0
                    double dfY = info.m_dfBottomY;
7507
0
                    double dfZ = info.m_dfBottomZ;
7508
0
                    info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7509
0
                }
7510
0
            }
7511
7512
0
            if (OGRProjCTDifferentOperationsUsed(info.m_poCT.get()))
7513
0
            {
7514
0
                CPLError(
7515
0
                    CE_Warning, CPLE_AppDefined,
7516
0
                    "Several coordinate operations have been used to transform "
7517
0
                    "layer %s. Artifacts may appear. You may consider "
7518
0
                    "using the -ct_opt ALLOW_BALLPARK=NO and/or "
7519
0
                    "-ct_opt ONLY_BEST=YES warping options, or specify "
7520
0
                    "a particular coordinate operation with -ct. "
7521
0
                    "This warning can be silenced with "
7522
0
                    "-ct_opt WARN_ABOUT_DIFFERENT_COORD_OP=NO.",
7523
0
                    m_poSrcLayer->GetName());
7524
0
            }
7525
7526
            // Stop recording
7527
0
            OGRProjCTDifferentOperationsStop(info.m_poCT.get());
7528
0
        }
7529
0
    }
7530
0
}
7531
7532
/************************************************************************/
7533
/*                   GDALVectorTranslateOptionsGetParser()              */
7534
/************************************************************************/
7535
7536
static std::unique_ptr<GDALArgumentParser> GDALVectorTranslateOptionsGetParser(
7537
    GDALVectorTranslateOptions *psOptions,
7538
    GDALVectorTranslateOptionsForBinary *psOptionsForBinary, int nCountClipSrc,
7539
    int nCountClipDst)
7540
0
{
7541
0
    auto argParser = std::make_unique<GDALArgumentParser>(
7542
0
        "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);
7543
7544
0
    argParser->add_description(
7545
0
        _("Converts simple features data between file formats."));
7546
7547
0
    argParser->add_epilog(
7548
0
        _("For more details, consult https://gdal.org/programs/ogr2ogr.html"));
7549
7550
0
    argParser->add_output_format_argument(psOptions->osFormat);
7551
7552
0
    argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);
7553
7554
0
    argParser->add_layer_creation_options_argument(psOptions->aosLCO);
7555
7556
0
    argParser->add_usage_newline();
7557
7558
0
    {
7559
0
        auto &group = argParser->add_mutually_exclusive_group();
7560
0
        group.add_argument("-append")
7561
0
            .flag()
7562
0
            .action([psOptions](const std::string &)
7563
0
                    { psOptions->eAccessMode = ACCESS_APPEND; })
7564
0
            .help(_("Append to existing layer instead of creating new."));
7565
7566
0
        group.add_argument("-upsert")
7567
0
            .flag()
7568
0
            .action(
7569
0
                [psOptions](const std::string &)
7570
0
                {
7571
0
                    psOptions->eAccessMode = ACCESS_APPEND;
7572
0
                    psOptions->bUpsert = true;
7573
0
                })
7574
0
            .help(_("Variant of -append where the UpsertFeature() operation is "
7575
0
                    "used to insert or update features."));
7576
7577
0
        group.add_argument("-overwrite")
7578
0
            .flag()
7579
0
            .action([psOptions](const std::string &)
7580
0
                    { psOptions->eAccessMode = ACCESS_OVERWRITE; })
7581
0
            .help(_("Delete the output layer and recreate it empty."));
7582
0
    }
7583
7584
0
    argParser->add_argument("-update")
7585
0
        .flag()
7586
0
        .action(
7587
0
            [psOptions](const std::string &)
7588
0
            {
7589
                /* Don't reset -append or -overwrite */
7590
0
                if (psOptions->eAccessMode != ACCESS_APPEND &&
7591
0
                    psOptions->eAccessMode != ACCESS_OVERWRITE)
7592
0
                    psOptions->eAccessMode = ACCESS_UPDATE;
7593
0
            })
7594
0
        .help(_("Open existing output datasource in update mode rather than "
7595
0
                "trying to create a new one."));
7596
7597
0
    argParser->add_argument("-sql")
7598
0
        .metavar("<statement>|@<filename>")
7599
0
        .action(
7600
0
            [psOptions](const std::string &s)
7601
0
            {
7602
0
                GByte *pabyRet = nullptr;
7603
0
                if (!s.empty() && s.front() == '@' &&
7604
0
                    VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7605
0
                                  1024 * 1024))
7606
0
                {
7607
0
                    GDALRemoveBOM(pabyRet);
7608
0
                    char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);
7609
0
                    psOptions->osSQLStatement =
7610
0
                        CPLRemoveSQLComments(pszSQLStatement);
7611
0
                    VSIFree(pszSQLStatement);
7612
0
                }
7613
0
                else
7614
0
                {
7615
0
                    psOptions->osSQLStatement = s;
7616
0
                }
7617
0
            })
7618
0
        .help(_("SQL statement to execute."));
7619
7620
0
    argParser->add_argument("-dialect")
7621
0
        .metavar("<dialect>")
7622
0
        .store_into(psOptions->osDialect)
7623
0
        .help(_("SQL dialect."));
7624
7625
0
    argParser->add_argument("-spat")
7626
0
        .metavar("<xmin> <ymin> <xmax> <ymax>")
7627
0
        .nargs(4)
7628
0
        .scan<'g', double>()
7629
0
        .help(_("Spatial query extents, in the SRS of the source layer(s) (or "
7630
0
                "the one specified with -spat_srs."));
7631
7632
0
    argParser->add_argument("-where")
7633
0
        .metavar("<restricted_where>|@<filename>")
7634
0
        .action(
7635
0
            [psOptions](const std::string &s)
7636
0
            {
7637
0
                GByte *pabyRet = nullptr;
7638
0
                if (!s.empty() && s.front() == '@' &&
7639
0
                    VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7640
0
                                  1024 * 1024))
7641
0
                {
7642
0
                    GDALRemoveBOM(pabyRet);
7643
0
                    char *pszWHERE = reinterpret_cast<char *>(pabyRet);
7644
0
                    psOptions->osWHERE = pszWHERE;
7645
0
                    VSIFree(pszWHERE);
7646
0
                }
7647
0
                else
7648
0
                {
7649
0
                    psOptions->osWHERE = s;
7650
0
                }
7651
0
            })
7652
0
        .help(_("Attribute query (like SQL WHERE)."));
7653
7654
0
    argParser->add_argument("-select")
7655
0
        .metavar("<field_list>")
7656
0
        .action(
7657
0
            [psOptions](const std::string &s)
7658
0
            {
7659
0
                psOptions->bSelFieldsSet = true;
7660
0
                psOptions->aosSelFields =
7661
0
                    CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);
7662
0
            })
7663
0
        .help(_("Comma-delimited list of fields from input layer to copy to "
7664
0
                "the new layer."));
7665
7666
0
    argParser->add_argument("-nln")
7667
0
        .metavar("<name>")
7668
0
        .store_into(psOptions->osNewLayerName)
7669
0
        .help(_("Assign an alternate name to the new layer."));
7670
7671
0
    argParser->add_argument("-nlt")
7672
0
        .metavar("<type>")
7673
0
        .append()
7674
0
        .action(
7675
0
            [psOptions](const std::string &osGeomNameIn)
7676
0
            {
7677
0
                bool bIs3D = false;
7678
0
                std::string osGeomName(osGeomNameIn);
7679
0
                if (osGeomName.size() > 3 &&
7680
0
                    STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,
7681
0
                                   "25D"))
7682
0
                {
7683
0
                    bIs3D = true;
7684
0
                    osGeomName.resize(osGeomName.size() - 3);
7685
0
                }
7686
0
                else if (osGeomName.size() > 1 &&
7687
0
                         STARTS_WITH_CI(
7688
0
                             osGeomName.c_str() + osGeomName.size() - 1, "Z"))
7689
0
                {
7690
0
                    bIs3D = true;
7691
0
                    osGeomName.pop_back();
7692
0
                }
7693
0
                if (EQUAL(osGeomName.c_str(), "NONE"))
7694
0
                {
7695
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7696
0
                    {
7697
0
                        throw std::invalid_argument(
7698
0
                            "Unsupported combination of -nlt arguments.");
7699
0
                    }
7700
0
                    psOptions->eGType = wkbNone;
7701
0
                }
7702
0
                else if (EQUAL(osGeomName.c_str(), "GEOMETRY"))
7703
0
                {
7704
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7705
0
                    {
7706
0
                        throw std::invalid_argument(
7707
0
                            "Unsupported combination of -nlt arguments.");
7708
0
                    }
7709
0
                    psOptions->eGType = wkbUnknown;
7710
0
                }
7711
0
                else if (EQUAL(osGeomName.c_str(), "PROMOTE_TO_MULTI"))
7712
0
                {
7713
0
                    if (psOptions->eGeomTypeConversion == GTC_CONVERT_TO_LINEAR)
7714
0
                        psOptions->eGeomTypeConversion =
7715
0
                            GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7716
0
                    else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7717
0
                        psOptions->eGeomTypeConversion = GTC_PROMOTE_TO_MULTI;
7718
0
                    else
7719
0
                    {
7720
0
                        throw std::invalid_argument(
7721
0
                            "Unsupported combination of -nlt arguments.");
7722
0
                    }
7723
0
                }
7724
0
                else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_LINEAR"))
7725
0
                {
7726
0
                    if (psOptions->eGeomTypeConversion == GTC_PROMOTE_TO_MULTI)
7727
0
                        psOptions->eGeomTypeConversion =
7728
0
                            GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7729
0
                    else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7730
0
                        psOptions->eGeomTypeConversion = GTC_CONVERT_TO_LINEAR;
7731
0
                    else
7732
0
                    {
7733
0
                        throw std::invalid_argument(
7734
0
                            "Unsupported combination of -nlt arguments.");
7735
0
                    }
7736
0
                }
7737
0
                else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_CURVE"))
7738
0
                {
7739
0
                    if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7740
0
                        psOptions->eGeomTypeConversion = GTC_CONVERT_TO_CURVE;
7741
0
                    else
7742
0
                    {
7743
0
                        throw std::invalid_argument(
7744
0
                            "Unsupported combination of -nlt arguments.");
7745
0
                    }
7746
0
                }
7747
0
                else
7748
0
                {
7749
0
                    if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7750
0
                    {
7751
0
                        throw std::invalid_argument(
7752
0
                            "Unsupported combination of -nlt arguments.");
7753
0
                    }
7754
0
                    psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());
7755
0
                    if (psOptions->eGType == wkbUnknown)
7756
0
                    {
7757
0
                        throw std::invalid_argument(
7758
0
                            CPLSPrintf("-nlt %s: type not recognised.",
7759
0
                                       osGeomName.c_str()));
7760
0
                    }
7761
0
                }
7762
0
                if (psOptions->eGType != GEOMTYPE_UNCHANGED &&
7763
0
                    psOptions->eGType != wkbNone && bIs3D)
7764
0
                    psOptions->eGType = wkbSetZ(
7765
0
                        static_cast<OGRwkbGeometryType>(psOptions->eGType));
7766
0
            })
7767
0
        .help(_("Define the geometry type for the created layer."));
7768
7769
0
    argParser->add_argument("-s_srs")
7770
0
        .metavar("<srs_def>")
7771
0
        .store_into(psOptions->osSourceSRSDef)
7772
0
        .help(_("Set/override source SRS."));
7773
7774
0
    {
7775
0
        auto &group = argParser->add_mutually_exclusive_group();
7776
0
        group.add_argument("-a_srs")
7777
0
            .metavar("<srs_def>")
7778
0
            .action(
7779
0
                [psOptions](const std::string &osOutputSRSDef)
7780
0
                {
7781
0
                    psOptions->osOutputSRSDef = osOutputSRSDef;
7782
0
                    if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||
7783
0
                        EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))
7784
0
                    {
7785
0
                        psOptions->osOutputSRSDef.clear();
7786
0
                        psOptions->bNullifyOutputSRS = true;
7787
0
                    }
7788
0
                })
7789
0
            .help(_("Assign an output SRS, but without reprojecting."));
7790
7791
0
        group.add_argument("-t_srs")
7792
0
            .metavar("<srs_def>")
7793
0
            .action(
7794
0
                [psOptions](const std::string &osOutputSRSDef)
7795
0
                {
7796
0
                    psOptions->osOutputSRSDef = osOutputSRSDef;
7797
0
                    psOptions->bTransform = true;
7798
0
                })
7799
0
            .help(_("Reproject/transform to this SRS on output, and assign it "
7800
0
                    "as output SRS."));
7801
0
    }
7802
7803
    ///////////////////////////////////////////////////////////////////////
7804
0
    argParser->add_group("Field related options");
7805
7806
0
    argParser->add_argument("-addfields")
7807
0
        .flag()
7808
0
        .action(
7809
0
            [psOptions](const std::string &)
7810
0
            {
7811
0
                psOptions->bAddMissingFields = true;
7812
0
                psOptions->eAccessMode = ACCESS_APPEND;
7813
0
            })
7814
0
        .help(_("Same as append, but add also any new fields."));
7815
7816
0
    argParser->add_argument("-relaxedFieldNameMatch")
7817
0
        .flag()
7818
0
        .action([psOptions](const std::string &)
7819
0
                { psOptions->bExactFieldNameMatch = false; })
7820
0
        .help(_("Do field name matching between source and existing target "
7821
0
                "layer in a more relaxed way."));
7822
7823
0
    argParser->add_argument("-fieldTypeToString")
7824
0
        .metavar("All|<type1>[,<type2>]...")
7825
0
        .action(
7826
0
            [psOptions](const std::string &s)
7827
0
            {
7828
0
                psOptions->aosFieldTypesToString =
7829
0
                    CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7830
0
                CSLConstList iter = psOptions->aosFieldTypesToString.List();
7831
0
                while (*iter)
7832
0
                {
7833
0
                    if (IsFieldType(*iter))
7834
0
                    {
7835
                        /* Do nothing */
7836
0
                    }
7837
0
                    else if (EQUAL(*iter, "All"))
7838
0
                    {
7839
0
                        psOptions->aosFieldTypesToString.Clear();
7840
0
                        psOptions->aosFieldTypesToString.AddString("All");
7841
0
                        break;
7842
0
                    }
7843
0
                    else
7844
0
                    {
7845
0
                        throw std::invalid_argument(CPLSPrintf(
7846
0
                            "Unhandled type for fieldTypeToString option : %s",
7847
0
                            *iter));
7848
0
                    }
7849
0
                    iter++;
7850
0
                }
7851
0
            })
7852
0
        .help(_("Converts any field of the specified type to a field of type "
7853
0
                "string in the destination layer."));
7854
7855
0
    argParser->add_argument("-mapFieldType")
7856
0
        .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...")
7857
0
        .action(
7858
0
            [psOptions](const std::string &s)
7859
0
            {
7860
0
                psOptions->aosMapFieldType =
7861
0
                    CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7862
0
                CSLConstList iter = psOptions->aosMapFieldType.List();
7863
0
                while (*iter)
7864
0
                {
7865
0
                    char *pszKey = nullptr;
7866
0
                    const char *pszValue = CPLParseNameValue(*iter, &pszKey);
7867
0
                    if (pszKey && pszValue)
7868
0
                    {
7869
0
                        if (!((IsFieldType(pszKey) || EQUAL(pszKey, "All")) &&
7870
0
                              IsFieldType(pszValue)))
7871
0
                        {
7872
0
                            CPLFree(pszKey);
7873
0
                            throw std::invalid_argument(CPLSPrintf(
7874
0
                                "Invalid value for -mapFieldType : %s", *iter));
7875
0
                        }
7876
0
                    }
7877
0
                    CPLFree(pszKey);
7878
0
                    iter++;
7879
0
                }
7880
0
            })
7881
0
        .help(_("Converts any field of the specified type to another type."));
7882
7883
0
    argParser->add_argument("-fieldmap")
7884
0
        .metavar("<field_1>[,<field_2>]...")
7885
0
        .action(
7886
0
            [psOptions](const std::string &s)
7887
0
            {
7888
0
                psOptions->aosFieldMap =
7889
0
                    CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);
7890
0
            })
7891
0
        .help(_("Specifies the list of field indexes to be copied from the "
7892
0
                "source to the destination."));
7893
7894
0
    argParser->add_argument("-splitlistfields")
7895
0
        .store_into(psOptions->bSplitListFields)
7896
0
        .help(_("Split fields of type list type into as many fields of scalar "
7897
0
                "type as necessary."));
7898
7899
0
    argParser->add_argument("-maxsubfields")
7900
0
        .metavar("<n>")
7901
0
        .scan<'i', int>()
7902
0
        .action(
7903
0
            [psOptions](const std::string &s)
7904
0
            {
7905
0
                const int nVal = atoi(s.c_str());
7906
0
                if (nVal > 0)
7907
0
                {
7908
0
                    psOptions->nMaxSplitListSubFields = nVal;
7909
0
                }
7910
0
            })
7911
0
        .help(_("To be combined with -splitlistfields to limit the number of "
7912
0
                "subfields created for each split field."));
7913
7914
0
    argParser->add_argument("-emptyStrAsNull")
7915
0
        .store_into(psOptions->bEmptyStrAsNull)
7916
0
        .help(_("Treat empty string values as null."));
7917
7918
0
    argParser->add_argument("-forceNullable")
7919
0
        .store_into(psOptions->bForceNullable)
7920
0
        .help(_("Do not propagate not-nullable constraints to target layer if "
7921
0
                "they exist in source layer."));
7922
7923
0
    argParser->add_argument("-unsetFieldWidth")
7924
0
        .store_into(psOptions->bUnsetFieldWidth)
7925
0
        .help(_("Set field width and precision to 0."));
7926
7927
0
    argParser->add_argument("-unsetDefault")
7928
0
        .store_into(psOptions->bUnsetDefault)
7929
0
        .help(_("Do not propagate default field values to target layer if they "
7930
0
                "exist in source layer."));
7931
7932
0
    argParser->add_argument("-resolveDomains")
7933
0
        .store_into(psOptions->bResolveDomains)
7934
0
        .help(_("Cause any selected field that is linked to a coded field "
7935
0
                "domain will be accompanied by an additional field."));
7936
7937
0
    argParser->add_argument("-dateTimeTo")
7938
0
        .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>")
7939
0
        .action(
7940
0
            [psOptions](const std::string &s)
7941
0
            {
7942
0
                const char *pszFormat = s.c_str();
7943
0
                if (EQUAL(pszFormat, "UTC"))
7944
0
                {
7945
0
                    psOptions->nTZOffsetInSec = 0;
7946
0
                }
7947
0
                else if (STARTS_WITH_CI(pszFormat, "UTC") &&
7948
0
                         (strlen(pszFormat) == strlen("UTC+HH") ||
7949
0
                          strlen(pszFormat) == strlen("UTC+HH:MM")) &&
7950
0
                         (pszFormat[3] == '+' || pszFormat[3] == '-'))
7951
0
                {
7952
0
                    const int nHour = atoi(pszFormat + strlen("UTC+"));
7953
0
                    if (nHour < 0 || nHour > 14)
7954
0
                    {
7955
0
                        throw std::invalid_argument("Invalid UTC hour offset.");
7956
0
                    }
7957
0
                    else if (strlen(pszFormat) == strlen("UTC+HH"))
7958
0
                    {
7959
0
                        psOptions->nTZOffsetInSec = nHour * 3600;
7960
0
                        if (pszFormat[3] == '-')
7961
0
                            psOptions->nTZOffsetInSec =
7962
0
                                -psOptions->nTZOffsetInSec;
7963
0
                    }
7964
0
                    else  // if( strlen(pszFormat) == strlen("UTC+HH:MM") )
7965
0
                    {
7966
0
                        const int nMin = atoi(pszFormat + strlen("UTC+HH:"));
7967
0
                        if (nMin == 0 || nMin == 15 || nMin == 30 || nMin == 45)
7968
0
                        {
7969
0
                            psOptions->nTZOffsetInSec =
7970
0
                                nHour * 3600 + nMin * 60;
7971
0
                            if (pszFormat[3] == '-')
7972
0
                                psOptions->nTZOffsetInSec =
7973
0
                                    -psOptions->nTZOffsetInSec;
7974
0
                        }
7975
0
                    }
7976
0
                }
7977
0
                if (psOptions->nTZOffsetInSec == TZ_OFFSET_INVALID)
7978
0
                {
7979
0
                    throw std::invalid_argument(
7980
0
                        "Value of -dateTimeTo should be UTC, UTC(+|-)HH or "
7981
0
                        "UTC(+|-)HH:MM with HH in [0,14] and MM=00,15,30,45");
7982
0
                }
7983
0
            })
7984
0
        .help(_("Converts date time values from the timezone specified in the "
7985
0
                "source value to the target timezone."));
7986
7987
0
    argParser->add_argument("-noNativeData")
7988
0
        .flag()
7989
0
        .action([psOptions](const std::string &)
7990
0
                { psOptions->bNativeData = false; })
7991
0
        .help(_("Disable copying of native data."));
7992
7993
    ///////////////////////////////////////////////////////////////////////
7994
0
    argParser->add_group("Advanced geometry and SRS related options");
7995
7996
0
    argParser->add_argument("-dim")
7997
0
        .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM")
7998
0
        .action(
7999
0
            [psOptions](const std::string &osDim)
8000
0
            {
8001
0
                if (EQUAL(osDim.c_str(), "layer_dim"))
8002
0
                    psOptions->nCoordDim = COORD_DIM_LAYER_DIM;
8003
0
                else if (EQUAL(osDim.c_str(), "XY") ||
8004
0
                         EQUAL(osDim.c_str(), "2"))
8005
0
                    psOptions->nCoordDim = 2;
8006
0
                else if (EQUAL(osDim.c_str(), "XYZ") ||
8007
0
                         EQUAL(osDim.c_str(), "3"))
8008
0
                    psOptions->nCoordDim = 3;
8009
0
                else if (EQUAL(osDim.c_str(), "XYM"))
8010
0
                    psOptions->nCoordDim = COORD_DIM_XYM;
8011
0
                else if (EQUAL(osDim.c_str(), "XYZM"))
8012
0
                    psOptions->nCoordDim = 4;
8013
0
                else
8014
0
                {
8015
0
                    throw std::invalid_argument(CPLSPrintf(
8016
0
                        "-dim %s: value not handled.", osDim.c_str()));
8017
0
                }
8018
0
            })
8019
0
        .help(_("Force the coordinate dimension."));
8020
8021
0
    argParser->add_argument("-s_coord_epoch")
8022
0
        .metavar("<epoch>")
8023
0
        .store_into(psOptions->dfSourceCoordinateEpoch)
8024
0
        .help(_("Assign a coordinate epoch, linked with the source SRS."));
8025
8026
0
    argParser->add_argument("-a_coord_epoch")
8027
0
        .metavar("<epoch>")
8028
0
        .store_into(psOptions->dfOutputCoordinateEpoch)
8029
0
        .help(_("Assign a coordinate epoch, linked with the output SRS when "
8030
0
                "-a_srs is used."));
8031
8032
0
    argParser->add_argument("-t_coord_epoch")
8033
0
        .metavar("<epoch>")
8034
0
        .store_into(psOptions->dfOutputCoordinateEpoch)
8035
0
        .help(_("Assign a coordinate epoch, linked with the output SRS when "
8036
0
                "-t_srs is used."));
8037
8038
0
    argParser->add_argument("-ct")
8039
0
        .metavar("<pipeline_def>")
8040
0
        .action(
8041
0
            [psOptions](const std::string &s)
8042
0
            {
8043
0
                psOptions->osCTPipeline = s;
8044
0
                psOptions->bTransform = true;
8045
0
            })
8046
0
        .help(_("Override the default transformation from the source to the "
8047
0
                "target CRS."));
8048
8049
0
    argParser->add_argument("-ct_opt")
8050
0
        .metavar("<NAME>=<VALUE>")
8051
0
        .append()
8052
0
        .action([psOptions](const std::string &s)
8053
0
                { psOptions->aosCTOptions.AddString(s.c_str()); })
8054
0
        .help(_("Coordinate transform option(s)."));
8055
8056
0
    argParser->add_argument("-spat_srs")
8057
0
        .metavar("<srs_def>")
8058
0
        .store_into(psOptions->osSpatSRSDef)
8059
0
        .help(_("Override spatial filter SRS."));
8060
8061
0
    argParser->add_argument("-geomfield")
8062
0
        .metavar("<name>")
8063
0
        .action(
8064
0
            [psOptions](const std::string &s)
8065
0
            {
8066
0
                psOptions->osGeomField = s;
8067
0
                psOptions->bGeomFieldSet = true;
8068
0
            })
8069
0
        .help(_("Name of the geometry field on which the spatial filter "
8070
0
                "operates on."));
8071
8072
0
    argParser->add_argument("-segmentize")
8073
0
        .metavar("<max_dist>")
8074
0
        .store_into(psOptions->dfGeomOpParam)
8075
0
        .action([psOptions](const std::string &)
8076
0
                { psOptions->eGeomOp = GEOMOP_SEGMENTIZE; })
8077
0
        .help(_("Maximum distance between 2 nodes."));
8078
8079
0
    argParser->add_argument("-simplify")
8080
0
        .metavar("<tolerance>")
8081
0
        .store_into(psOptions->dfGeomOpParam)
8082
0
        .action([psOptions](const std::string &)
8083
0
                { psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY; })
8084
0
        .help(_("Distance tolerance for simplification."));
8085
8086
0
    argParser->add_argument("-makevalid")
8087
0
        .flag()
8088
0
        .action(
8089
0
            [psOptions](const std::string &)
8090
0
            {
8091
0
                if (!OGRGeometryFactory::haveGEOS())
8092
0
                {
8093
0
                    throw std::invalid_argument(
8094
0
                        "-makevalid only supported for builds against GEOS");
8095
0
                }
8096
0
                psOptions->bMakeValid = true;
8097
0
            })
8098
0
        .help(_("Fix geometries to be valid regarding the rules of the Simple "
8099
0
                "Features specification."));
8100
8101
0
    argParser->add_argument("-skipinvalid")
8102
0
        .flag()
8103
0
        .action(
8104
0
            [psOptions](const std::string &)
8105
0
            {
8106
0
                if (!OGRGeometryFactory::haveGEOS())
8107
0
                {
8108
0
                    throw std::invalid_argument(
8109
0
                        "-skipinvalid only supported for builds against GEOS");
8110
0
                }
8111
0
                psOptions->bSkipInvalidGeom = true;
8112
0
            })
8113
0
        .help(_("Whether to skip features with invalid geometries regarding the"
8114
0
                "rules of the Simple Features specification."));
8115
8116
0
    argParser->add_argument("-wrapdateline")
8117
0
        .store_into(psOptions->bWrapDateline)
8118
0
        .help(_("Split geometries crossing the dateline meridian."));
8119
8120
0
    argParser->add_argument("-datelineoffset")
8121
0
        .metavar("<val_in_degree>")
8122
0
        .default_value(psOptions->dfDateLineOffset)
8123
0
        .store_into(psOptions->dfDateLineOffset)
8124
0
        .help(_("Offset from dateline in degrees."));
8125
8126
0
    auto &clipsrcArg =
8127
0
        argParser->add_argument("-clipsrc")
8128
0
            .metavar(
8129
0
                "[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
8130
0
            .help(_("Clip geometries (in source SRS)."));
8131
0
    if (nCountClipSrc > 1)
8132
0
        clipsrcArg.nargs(nCountClipSrc);
8133
8134
0
    argParser->add_argument("-clipsrcsql")
8135
0
        .metavar("<sql_statement>")
8136
0
        .store_into(psOptions->osClipSrcSQL)
8137
0
        .help(_("Select desired geometries from the source clip datasource "
8138
0
                "using an SQL query."));
8139
8140
0
    argParser->add_argument("-clipsrclayer")
8141
0
        .metavar("<layername>")
8142
0
        .store_into(psOptions->osClipSrcLayer)
8143
0
        .help(_("Select the named layer from the source clip datasource."));
8144
8145
0
    argParser->add_argument("-clipsrcwhere")
8146
0
        .metavar("<expression>")
8147
0
        .store_into(psOptions->osClipSrcWhere)
8148
0
        .help(_("Restrict desired geometries from the source clip layer based "
8149
0
                "on an attribute query."));
8150
8151
0
    auto &clipdstArg =
8152
0
        argParser->add_argument("-clipdst")
8153
0
            .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>")
8154
0
            .help(_("Clip geometries (in target SRS)."));
8155
0
    if (nCountClipDst > 1)
8156
0
        clipdstArg.nargs(nCountClipDst);
8157
8158
0
    argParser->add_argument("-clipdstsql")
8159
0
        .metavar("<sql_statement>")
8160
0
        .store_into(psOptions->osClipDstSQL)
8161
0
        .help(_("Select desired geometries from the destination clip "
8162
0
                "datasource using an SQL query."));
8163
8164
0
    argParser->add_argument("-clipdstlayer")
8165
0
        .metavar("<layername>")
8166
0
        .store_into(psOptions->osClipDstLayer)
8167
0
        .help(
8168
0
            _("Select the named layer from the destination clip datasource."));
8169
8170
0
    argParser->add_argument("-clipdstwhere")
8171
0
        .metavar("<expression>")
8172
0
        .store_into(psOptions->osClipDstWhere)
8173
0
        .help(_("Restrict desired geometries from the destination clip layer "
8174
0
                "based on an attribute query."));
8175
8176
0
    argParser->add_argument("-explodecollections")
8177
0
        .store_into(psOptions->bExplodeCollections)
8178
0
        .help(_("Produce one feature for each geometry in any kind of geometry "
8179
0
                "collection in the source file."));
8180
8181
0
    argParser->add_argument("-zfield")
8182
0
        .metavar("<name>")
8183
0
        .store_into(psOptions->osZField)
8184
0
        .help(_("Uses the specified field to fill the Z coordinate of "
8185
0
                "geometries."));
8186
8187
0
    argParser->add_argument("-gcp")
8188
0
        .metavar(
8189
0
            "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")
8190
0
        .nargs(4, 5)
8191
0
        .append()
8192
0
        .scan<'g', double>()
8193
0
        .help(_("Add the indicated ground control point."));
8194
8195
0
    argParser->add_argument("-tps")
8196
0
        .flag()
8197
0
        .action([psOptions](const std::string &)
8198
0
                { psOptions->nTransformOrder = -1; })
8199
0
        .help(_("Force use of thin plate spline transformer based on available "
8200
0
                "GCPs."));
8201
8202
0
    argParser->add_argument("-order")
8203
0
        .metavar("1|2|3")
8204
0
        .store_into(psOptions->nTransformOrder)
8205
0
        .help(_("Order of polynomial used for warping."));
8206
8207
0
    argParser->add_argument("-xyRes")
8208
0
        .metavar("<val>[ m|mm|deg]")
8209
0
        .action(
8210
0
            [psOptions](const std::string &s)
8211
0
            {
8212
0
                const char *pszVal = s.c_str();
8213
8214
0
                char *endptr = nullptr;
8215
0
                psOptions->dfXYRes = CPLStrtodM(pszVal, &endptr);
8216
0
                if (!endptr)
8217
0
                {
8218
0
                    throw std::invalid_argument(
8219
0
                        "Invalid value for -xyRes. Must be of the form "
8220
0
                        "{numeric_value}[ ]?[m|mm|deg]?");
8221
0
                }
8222
0
                if (*endptr == ' ')
8223
0
                    ++endptr;
8224
0
                if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
8225
0
                    strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
8226
0
                {
8227
0
                    throw std::invalid_argument(
8228
0
                        "Invalid value for -xyRes. Must be of the form "
8229
0
                        "{numeric_value}[ ]?[m|mm|deg]?");
8230
0
                }
8231
0
                psOptions->osXYResUnit = endptr;
8232
0
            })
8233
0
        .help(_("Set/override the geometry X/Y coordinate resolution."));
8234
8235
0
    argParser->add_argument("-zRes")
8236
0
        .metavar("<val>[ m|mm]")
8237
0
        .action(
8238
0
            [psOptions](const std::string &s)
8239
0
            {
8240
0
                const char *pszVal = s.c_str();
8241
8242
0
                char *endptr = nullptr;
8243
0
                psOptions->dfZRes = CPLStrtodM(pszVal, &endptr);
8244
0
                if (!endptr)
8245
0
                {
8246
0
                    throw std::invalid_argument(
8247
0
                        "Invalid value for -zRes. Must be of the form "
8248
0
                        "{numeric_value}[ ]?[m|mm]?");
8249
0
                }
8250
0
                if (*endptr == ' ')
8251
0
                    ++endptr;
8252
0
                if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
8253
0
                    strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
8254
0
                {
8255
0
                    throw std::invalid_argument(
8256
0
                        "Invalid value for -zRes. Must be of the form "
8257
0
                        "{numeric_value}[ ]?[m|mm]?");
8258
0
                }
8259
0
                psOptions->osZResUnit = endptr;
8260
0
            })
8261
0
        .help(_("Set/override the geometry Z coordinate resolution."));
8262
8263
0
    argParser->add_argument("-mRes")
8264
0
        .metavar("<val>")
8265
0
        .store_into(psOptions->dfMRes)
8266
0
        .help(_("Set/override the geometry M coordinate resolution."));
8267
8268
0
    argParser->add_argument("-unsetCoordPrecision")
8269
0
        .store_into(psOptions->bUnsetCoordPrecision)
8270
0
        .help(_("Prevent the geometry coordinate resolution from being set on "
8271
0
                "target layer(s)."));
8272
8273
    ///////////////////////////////////////////////////////////////////////
8274
0
    argParser->add_group("Other options");
8275
8276
0
    argParser->add_quiet_argument(&psOptions->bQuiet);
8277
8278
0
    argParser->add_argument("-progress")
8279
0
        .store_into(psOptions->bDisplayProgress)
8280
0
        .help(_("Display progress on terminal. Only works if input layers have "
8281
0
                "the 'fast feature count' capability."));
8282
8283
0
    argParser->add_input_format_argument(
8284
0
        psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers
8285
0
                           : nullptr);
8286
8287
0
    argParser->add_open_options_argument(
8288
0
        psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);
8289
8290
0
    argParser->add_argument("-doo")
8291
0
        .metavar("<NAME>=<VALUE>")
8292
0
        .append()
8293
0
        .action([psOptions](const std::string &s)
8294
0
                { psOptions->aosDestOpenOptions.AddString(s.c_str()); })
8295
0
        .help(_("Open option(s) for output dataset."));
8296
8297
0
    argParser->add_usage_newline();
8298
8299
0
    argParser->add_argument("-fid")
8300
0
        .metavar("<FID>")
8301
0
        .store_into(psOptions->nFIDToFetch)
8302
0
        .help(_("If provided, only the feature with the specified feature id "
8303
0
                "will be processed."));
8304
8305
0
    argParser->add_argument("-preserve_fid")
8306
0
        .store_into(psOptions->bPreserveFID)
8307
0
        .help(_("Use the FID of the source features instead of letting the "
8308
0
                "output driver automatically assign a new one."));
8309
8310
0
    argParser->add_argument("-unsetFid")
8311
0
        .store_into(psOptions->bUnsetFid)
8312
0
        .help(_("Prevent the name of the source FID column and source feature "
8313
0
                "IDs from being re-used."));
8314
8315
0
    {
8316
0
        auto &group = argParser->add_mutually_exclusive_group();
8317
0
        group.add_argument("-skip", "-skipfailures")
8318
0
            .flag()
8319
0
            .action(
8320
0
                [psOptions](const std::string &)
8321
0
                {
8322
0
                    psOptions->bSkipFailures = true;
8323
0
                    psOptions->nGroupTransactions = 1; /* #2409 */
8324
0
                })
8325
0
            .help(_("Continue after a failure, skipping the failed feature."));
8326
8327
0
        auto &arg = group.add_argument("-gt")
8328
0
                        .metavar("<n>|unlimited")
8329
0
                        .action(
8330
0
                            [psOptions](const std::string &s)
8331
0
                            {
8332
                                /* If skipfailures is already set we should not
8333
               modify nGroupTransactions = 1  #2409 */
8334
0
                                if (!psOptions->bSkipFailures)
8335
0
                                {
8336
0
                                    if (EQUAL(s.c_str(), "unlimited"))
8337
0
                                        psOptions->nGroupTransactions = -1;
8338
0
                                    else
8339
0
                                        psOptions->nGroupTransactions =
8340
0
                                            atoi(s.c_str());
8341
0
                                }
8342
0
                            })
8343
0
                        .help(_("Group <n> features per transaction "));
8344
8345
0
        argParser->add_hidden_alias_for(arg, "tg");
8346
0
    }
8347
8348
0
    argParser->add_argument("-limit")
8349
0
        .metavar("<nb_features>")
8350
0
        .store_into(psOptions->nLimit)
8351
0
        .help(_("Limit the number of features per layer."));
8352
8353
0
    argParser->add_argument("-ds_transaction")
8354
0
        .flag()
8355
0
        .action(
8356
0
            [psOptions](const std::string &)
8357
0
            {
8358
0
                psOptions->nLayerTransaction = FALSE;
8359
0
                psOptions->bForceTransaction = true;
8360
0
            })
8361
0
        .help(_("Force the use of a dataset level transaction."));
8362
8363
    /* Undocumented. Just a provision. Default behavior should be OK */
8364
0
    argParser->add_argument("-lyr_transaction")
8365
0
        .flag()
8366
0
        .hidden()
8367
0
        .action([psOptions](const std::string &)
8368
0
                { psOptions->nLayerTransaction = TRUE; })
8369
0
        .help(_("Force the use of a layer level transaction."));
8370
8371
0
    argParser->add_metadata_item_options_argument(
8372
0
        psOptions->aosMetadataOptions);
8373
8374
0
    argParser->add_argument("-nomd")
8375
0
        .flag()
8376
0
        .action([psOptions](const std::string &)
8377
0
                { psOptions->bCopyMD = false; })
8378
0
        .help(_("Disable copying of metadata from source dataset and layers "
8379
0
                "into target dataset and layers."));
8380
8381
    // Undocumented option used by gdal vector convert
8382
0
    argParser->add_argument("--no-overwrite")
8383
0
        .store_into(psOptions->bNoOverwrite)
8384
0
        .hidden();
8385
8386
    // Undocumented option used by gdal vector convert
8387
0
    argParser->add_argument("--invoked-from-gdal-vector-convert")
8388
0
        .store_into(psOptions->bInvokedFromGdalVectorConvert)
8389
0
        .hidden();
8390
8391
0
    if (psOptionsForBinary)
8392
0
    {
8393
0
        argParser->add_argument("dst_dataset_name")
8394
0
            .metavar("<dst_dataset_name>")
8395
0
            .store_into(psOptionsForBinary->osDestDataSource)
8396
0
            .help(_("Output dataset."));
8397
8398
0
        argParser->add_argument("src_dataset_name")
8399
0
            .metavar("<src_dataset_name>")
8400
0
            .store_into(psOptionsForBinary->osDataSource)
8401
0
            .help(_("Input dataset."));
8402
0
    }
8403
8404
0
    argParser->add_argument("layer")
8405
0
        .remaining()
8406
0
        .metavar("<layer_name>")
8407
0
        .help(_("Layer name"));
8408
0
    return argParser;
8409
0
}
8410
8411
/************************************************************************/
8412
/*                    GDALVectorTranslateGetParserUsage()               */
8413
/************************************************************************/
8414
8415
std::string GDALVectorTranslateGetParserUsage()
8416
0
{
8417
0
    try
8418
0
    {
8419
0
        GDALVectorTranslateOptions sOptions;
8420
0
        GDALVectorTranslateOptionsForBinary sOptionsForBinary;
8421
0
        auto argParser = GDALVectorTranslateOptionsGetParser(
8422
0
            &sOptions, &sOptionsForBinary, 1, 1);
8423
0
        return argParser->usage();
8424
0
    }
8425
0
    catch (const std::exception &err)
8426
0
    {
8427
0
        CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
8428
0
                 err.what());
8429
0
        return std::string();
8430
0
    }
8431
0
}
8432
8433
/************************************************************************/
8434
/*                   CHECK_HAS_ENOUGH_ADDITIONAL_ARGS()                 */
8435
/************************************************************************/
8436
8437
#ifndef CheckHasEnoughAdditionalArgs_defined
8438
#define CheckHasEnoughAdditionalArgs_defined
8439
8440
static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,
8441
                                         int nExtraArg, int nArgc)
8442
0
{
8443
0
    if (i + nExtraArg >= nArgc)
8444
0
    {
8445
0
        CPLError(CE_Failure, CPLE_IllegalArg,
8446
0
                 "%s option requires %d argument%s", papszArgv[i], nExtraArg,
8447
0
                 nExtraArg == 1 ? "" : "s");
8448
0
        return false;
8449
0
    }
8450
0
    return true;
8451
0
}
8452
#endif
8453
8454
#define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \
8455
0
    if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc))         \
8456
0
    {                                                                          \
8457
0
        return nullptr;                                                        \
8458
0
    }
8459
8460
/************************************************************************/
8461
/*                       GDALVectorTranslateOptionsNew()                */
8462
/************************************************************************/
8463
8464
/**
8465
 * allocates a GDALVectorTranslateOptions struct.
8466
 *
8467
 * @param papszArgv NULL terminated list of options (potentially including
8468
 * filename and open options too), or NULL. The accepted options are the ones of
8469
 * the <a href="/programs/ogr2ogr.html">ogr2ogr</a> utility.
8470
 * @param psOptionsForBinary (output) may be NULL (and should generally be
8471
 * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
8472
 *                           GDALVectorTranslateOptionsForBinaryNew() prior to
8473
 * this function. Will be filled with potentially present filename, open
8474
 * options,...
8475
 * @return pointer to the allocated GDALVectorTranslateOptions struct. Must be
8476
 * freed with GDALVectorTranslateOptionsFree().
8477
 *
8478
 * @since GDAL 2.1
8479
 */
8480
GDALVectorTranslateOptions *GDALVectorTranslateOptionsNew(
8481
    char **papszArgv, GDALVectorTranslateOptionsForBinary *psOptionsForBinary)
8482
0
{
8483
0
    auto psOptions = std::make_unique<GDALVectorTranslateOptions>();
8484
8485
    /* -------------------------------------------------------------------- */
8486
    /*      Pre-processing for custom syntax that ArgumentParser does not   */
8487
    /*      support.                                                        */
8488
    /* -------------------------------------------------------------------- */
8489
8490
0
    CPLStringList aosArgv;
8491
0
    const int nArgc = CSLCount(papszArgv);
8492
0
    int nCountClipSrc = 0;
8493
0
    int nCountClipDst = 0;
8494
0
    for (int i = 0;
8495
0
         i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
8496
0
    {
8497
0
        if (EQUAL(papszArgv[i], "-gcp"))
8498
0
        {
8499
            // repeated argument of varying size: not handled by argparse.
8500
8501
0
            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
8502
0
            char *endptr = nullptr;
8503
            /* -gcp pixel line easting northing [elev] */
8504
8505
0
            psOptions->oGCPs.nGCPCount++;
8506
0
            psOptions->oGCPs.pasGCPs = static_cast<GDAL_GCP *>(
8507
0
                CPLRealloc(psOptions->oGCPs.pasGCPs,
8508
0
                           sizeof(GDAL_GCP) * psOptions->oGCPs.nGCPCount));
8509
0
            GDALInitGCPs(1, psOptions->oGCPs.pasGCPs +
8510
0
                                psOptions->oGCPs.nGCPCount - 1);
8511
8512
0
            psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]
8513
0
                .dfGCPPixel = CPLAtof(papszArgv[++i]);
8514
0
            psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPLine =
8515
0
                CPLAtof(papszArgv[++i]);
8516
0
            psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPX =
8517
0
                CPLAtof(papszArgv[++i]);
8518
0
            psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPY =
8519
0
                CPLAtof(papszArgv[++i]);
8520
0
            if (papszArgv[i + 1] != nullptr &&
8521
0
                (CPLStrtod(papszArgv[i + 1], &endptr) != 0.0 ||
8522
0
                 papszArgv[i + 1][0] == '0'))
8523
0
            {
8524
                /* Check that last argument is really a number and not a
8525
                 * filename */
8526
                /* looking like a number (see ticket #863) */
8527
0
                if (endptr && *endptr == 0)
8528
0
                    psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]
8529
0
                        .dfGCPZ = CPLAtof(papszArgv[++i]);
8530
0
            }
8531
8532
            /* should set id and info? */
8533
0
        }
8534
8535
0
        else if (EQUAL(papszArgv[i], "-clipsrc"))
8536
0
        {
8537
0
            if (nCountClipSrc)
8538
0
            {
8539
0
                CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
8540
0
                         papszArgv[i]);
8541
0
                return nullptr;
8542
0
            }
8543
            // argparse doesn't handle well variable number of values
8544
            // just before the positional arguments, so we have to detect
8545
            // it manually and set the correct number.
8546
0
            nCountClipSrc = 1;
8547
0
            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8548
0
            if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8549
0
                i + 4 < nArgc)
8550
0
            {
8551
0
                nCountClipSrc = 4;
8552
0
            }
8553
8554
0
            for (int j = 0; j < 1 + nCountClipSrc; ++j)
8555
0
            {
8556
0
                aosArgv.AddString(papszArgv[i]);
8557
0
                ++i;
8558
0
            }
8559
0
            --i;
8560
0
        }
8561
8562
0
        else if (EQUAL(papszArgv[i], "-clipdst"))
8563
0
        {
8564
0
            if (nCountClipDst)
8565
0
            {
8566
0
                CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
8567
0
                         papszArgv[i]);
8568
0
                return nullptr;
8569
0
            }
8570
            // argparse doesn't handle well variable number of values
8571
            // just before the positional arguments, so we have to detect
8572
            // it manually and set the correct number.
8573
0
            nCountClipDst = 1;
8574
0
            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8575
0
            if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8576
0
                i + 4 < nArgc)
8577
0
            {
8578
0
                nCountClipDst = 4;
8579
0
            }
8580
8581
0
            for (int j = 0; j < 1 + nCountClipDst; ++j)
8582
0
            {
8583
0
                aosArgv.AddString(papszArgv[i]);
8584
0
                ++i;
8585
0
            }
8586
0
            --i;
8587
0
        }
8588
8589
0
        else
8590
0
        {
8591
0
            aosArgv.AddString(papszArgv[i]);
8592
0
        }
8593
0
    }
8594
8595
0
    try
8596
0
    {
8597
0
        auto argParser = GDALVectorTranslateOptionsGetParser(
8598
0
            psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);
8599
8600
        // Collect non-positional arguments for VectorTranslateFrom() case
8601
0
        psOptions->aosArguments =
8602
0
            argParser->get_non_positional_arguments(aosArgv);
8603
8604
0
        argParser->parse_args_without_binary_name(aosArgv.List());
8605
8606
0
        if (psOptionsForBinary)
8607
0
            psOptionsForBinary->bQuiet = psOptions->bQuiet;
8608
8609
0
        if (auto oSpat = argParser->present<std::vector<double>>("-spat"))
8610
0
        {
8611
0
            OGRLinearRing oRing;
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
            oRing.addPoint(dfMinX, dfMinY);
8618
0
            oRing.addPoint(dfMinX, dfMaxY);
8619
0
            oRing.addPoint(dfMaxX, dfMaxY);
8620
0
            oRing.addPoint(dfMaxX, dfMinY);
8621
0
            oRing.addPoint(dfMinX, dfMinY);
8622
8623
0
            auto poSpatialFilter = std::make_shared<OGRPolygon>();
8624
0
            poSpatialFilter->addRing(&oRing);
8625
0
            psOptions->poSpatialFilter = poSpatialFilter;
8626
0
        }
8627
8628
0
        if (auto oClipSrc =
8629
0
                argParser->present<std::vector<std::string>>("-clipsrc"))
8630
0
        {
8631
0
            const std::string &osVal = (*oClipSrc)[0];
8632
8633
0
            psOptions->poClipSrc.reset();
8634
0
            psOptions->osClipSrcDS.clear();
8635
8636
0
            VSIStatBufL sStat;
8637
0
            psOptions->bClipSrc = true;
8638
0
            if (oClipSrc->size() == 4)
8639
0
            {
8640
0
                const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
8641
0
                const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
8642
0
                const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
8643
0
                const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
8644
8645
0
                OGRLinearRing oRing;
8646
8647
0
                oRing.addPoint(dfMinX, dfMinY);
8648
0
                oRing.addPoint(dfMinX, dfMaxY);
8649
0
                oRing.addPoint(dfMaxX, dfMaxY);
8650
0
                oRing.addPoint(dfMaxX, dfMinY);
8651
0
                oRing.addPoint(dfMinX, dfMinY);
8652
8653
0
                auto poPoly = std::make_shared<OGRPolygon>();
8654
0
                psOptions->poClipSrc = poPoly;
8655
0
                poPoly->addRing(&oRing);
8656
0
            }
8657
0
            else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8658
0
                      STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8659
0
                     VSIStatL(osVal.c_str(), &sStat) != 0)
8660
0
            {
8661
0
                psOptions->poClipSrc =
8662
0
                    OGRGeometryFactory::createFromWkt(osVal.c_str()).first;
8663
0
                if (psOptions->poClipSrc == nullptr)
8664
0
                {
8665
0
                    CPLError(
8666
0
                        CE_Failure, CPLE_IllegalArg,
8667
0
                        "Invalid -clipsrc geometry. Must be a valid POLYGON or "
8668
0
                        "MULTIPOLYGON WKT");
8669
0
                    return nullptr;
8670
0
                }
8671
0
            }
8672
0
            else if (EQUAL(osVal.c_str(), "spat_extent"))
8673
0
            {
8674
                // Nothing to do
8675
0
            }
8676
0
            else
8677
0
            {
8678
0
                psOptions->osClipSrcDS = osVal;
8679
0
            }
8680
0
        }
8681
8682
0
        if (auto oClipDst =
8683
0
                argParser->present<std::vector<std::string>>("-clipdst"))
8684
0
        {
8685
0
            const std::string &osVal = (*oClipDst)[0];
8686
8687
0
            psOptions->poClipDst.reset();
8688
0
            psOptions->osClipDstDS.clear();
8689
8690
0
            VSIStatBufL sStat;
8691
0
            if (oClipDst->size() == 4)
8692
0
            {
8693
0
                const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());
8694
0
                const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());
8695
0
                const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());
8696
0
                const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());
8697
8698
0
                OGRLinearRing oRing;
8699
8700
0
                oRing.addPoint(dfMinX, dfMinY);
8701
0
                oRing.addPoint(dfMinX, dfMaxY);
8702
0
                oRing.addPoint(dfMaxX, dfMaxY);
8703
0
                oRing.addPoint(dfMaxX, dfMinY);
8704
0
                oRing.addPoint(dfMinX, dfMinY);
8705
8706
0
                auto poPoly = std::make_shared<OGRPolygon>();
8707
0
                psOptions->poClipDst = poPoly;
8708
0
                poPoly->addRing(&oRing);
8709
0
            }
8710
0
            else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8711
0
                      STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8712
0
                     VSIStatL(osVal.c_str(), &sStat) != 0)
8713
0
            {
8714
0
                psOptions->poClipDst =
8715
0
                    OGRGeometryFactory::createFromWkt(osVal.c_str()).first;
8716
0
                if (psOptions->poClipDst == nullptr)
8717
0
                {
8718
0
                    CPLError(
8719
0
                        CE_Failure, CPLE_IllegalArg,
8720
0
                        "Invalid -clipdst geometry. Must be a valid POLYGON or "
8721
0
                        "MULTIPOLYGON WKT");
8722
0
                    return nullptr;
8723
0
                }
8724
0
            }
8725
0
            else
8726
0
            {
8727
0
                psOptions->osClipDstDS = osVal;
8728
0
            }
8729
0
        }
8730
8731
0
        auto layers = argParser->present<std::vector<std::string>>("layer");
8732
0
        if (layers)
8733
0
        {
8734
0
            for (const auto &layer : *layers)
8735
0
            {
8736
0
                psOptions->aosLayers.AddString(layer.c_str());
8737
0
            }
8738
0
        }
8739
0
        if (psOptionsForBinary)
8740
0
        {
8741
0
            psOptionsForBinary->eAccessMode = psOptions->eAccessMode;
8742
0
            psOptionsForBinary->osFormat = psOptions->osFormat;
8743
8744
0
            if (!(CPLTestBool(
8745
0
                    psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8746
0
                        "NATIVE_DATA",
8747
0
                        psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8748
0
                            "@NATIVE_DATA", "TRUE")))))
8749
0
            {
8750
0
                psOptions->bNativeData = false;
8751
0
            }
8752
8753
0
            if (psOptions->bNativeData &&
8754
0
                psOptionsForBinary->aosOpenOptions.FetchNameValue(
8755
0
                    "NATIVE_DATA") == nullptr &&
8756
0
                psOptionsForBinary->aosOpenOptions.FetchNameValue(
8757
0
                    "@NATIVE_DATA") == nullptr)
8758
0
            {
8759
0
                psOptionsForBinary->aosOpenOptions.AddString(
8760
0
                    "@NATIVE_DATA=YES");
8761
0
            }
8762
0
        }
8763
8764
0
        return psOptions.release();
8765
0
    }
8766
0
    catch (const std::exception &err)
8767
0
    {
8768
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
8769
0
        if (psOptionsForBinary)
8770
0
            psOptionsForBinary->bShowUsageIfError = true;
8771
0
        return nullptr;
8772
0
    }
8773
0
}
8774
8775
/************************************************************************/
8776
/*                      GDALVectorTranslateOptionsFree()                */
8777
/************************************************************************/
8778
8779
/**
8780
 * Frees the GDALVectorTranslateOptions struct.
8781
 *
8782
 * @param psOptions the options struct for GDALVectorTranslate().
8783
 * @since GDAL 2.1
8784
 */
8785
8786
void GDALVectorTranslateOptionsFree(GDALVectorTranslateOptions *psOptions)
8787
0
{
8788
0
    delete psOptions;
8789
0
}
8790
8791
/************************************************************************/
8792
/*                 GDALVectorTranslateOptionsSetProgress()              */
8793
/************************************************************************/
8794
8795
/**
8796
 * Set a progress function.
8797
 *
8798
 * @param psOptions the options struct for GDALVectorTranslate().
8799
 * @param pfnProgress the progress callback.
8800
 * @param pProgressData the user data for the progress callback.
8801
 *
8802
 * @since GDAL 2.1
8803
 */
8804
8805
void GDALVectorTranslateOptionsSetProgress(
8806
    GDALVectorTranslateOptions *psOptions, GDALProgressFunc pfnProgress,
8807
    void *pProgressData)
8808
0
{
8809
0
    psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
8810
0
    psOptions->pProgressData = pProgressData;
8811
0
    if (pfnProgress == GDALTermProgress)
8812
0
        psOptions->bQuiet = false;
8813
0
}
8814
8815
#undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS