LCOV - code coverage report
Current view: top level - apps - ogr2ogr_lib.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3157 3894 81.1 %
Date: 2025-01-18 12:42:00 Functions: 115 143 80.4 %

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

Generated by: LCOV version 1.14