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