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