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