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