LCOV - code coverage report
Current view: top level - apps - ogr2ogr_lib.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3205 3980 80.5 %
Date: 2026-01-15 17:31:20 Functions: 114 151 75.5 %

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

Generated by: LCOV version 1.14