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