Coverage Report

Created: 2026-02-14 06:52

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