Coverage Report

Created: 2026-04-10 07:04

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