Coverage Report

Created: 2025-11-16 06:25

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