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
|