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