Coverage Report

Created: 2026-07-25 06:50

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