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