Coverage Report

Created: 2025-12-31 06:48

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