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 1132 : static void ApplySpatialFilter(OGRLayer *poLayer, OGRGeometry *poSpatialFilter,
1472 : const OGRSpatialReference *poSpatSRS,
1473 : const char *pszGeomField,
1474 : const OGRSpatialReference *poSourceSRS)
1475 : {
1476 1132 : if (poSpatialFilter == nullptr)
1477 1124 : 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 965 : ~OGR2OGRSpatialReferenceHolder()
1882 965 : {
1883 965 : if (m_poSRS)
1884 147 : m_poSRS->Release();
1885 965 : }
1886 :
1887 147 : void assignNoRefIncrease(OGRSpatialReference *poSRS)
1888 : {
1889 147 : CPLAssert(m_poSRS == nullptr);
1890 147 : m_poSRS = poSRS;
1891 147 : }
1892 :
1893 2334 : OGRSpatialReference *get()
1894 : {
1895 2334 : 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 942 : static void CopyRelationships(GDALDataset *poODS, GDALDataset *poDS)
2254 : {
2255 942 : if (!poODS->GetDriver()->GetMetadataItem(GDAL_DCAP_CREATE_RELATIONSHIP))
2256 937 : return;
2257 :
2258 149 : const auto aosRelationshipNames = poDS->GetRelationshipNames();
2259 149 : if (aosRelationshipNames.empty())
2260 144 : 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 987 : GDALDatasetH GDALVectorTranslate(const char *pszDest, GDALDatasetH hDstDS,
2359 : int nSrcCount, GDALDatasetH *pahSrcDS,
2360 : const GDALVectorTranslateOptions *psOptionsIn,
2361 : int *pbUsageError)
2362 :
2363 : {
2364 987 : 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 987 : 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 987 : GDALDatasetH hSrcDS = pahSrcDS[0];
2383 987 : 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 1974 : : std::make_unique<GDALVectorTranslateOptions>();
2395 :
2396 987 : bool bAppend = false;
2397 987 : bool bUpdate = false;
2398 987 : bool bOverwrite = false;
2399 :
2400 987 : if (psOptions->eAccessMode == ACCESS_UPDATE)
2401 : {
2402 5 : bUpdate = true;
2403 : }
2404 982 : else if (psOptions->eAccessMode == ACCESS_APPEND)
2405 : {
2406 40 : bAppend = true;
2407 40 : bUpdate = true;
2408 : }
2409 942 : else if (psOptions->eAccessMode == ACCESS_OVERWRITE)
2410 : {
2411 17 : bOverwrite = true;
2412 17 : bUpdate = true;
2413 : }
2414 925 : else if (hDstDS != nullptr)
2415 : {
2416 8 : bUpdate = true;
2417 : }
2418 :
2419 987 : 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 986 : 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 986 : 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 986 : 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 985 : 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 993 : if (!psOptions->osSourceSRSDef.empty() &&
2468 993 : 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 985 : std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSpatSRS;
2482 985 : 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 985 : 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 976 : 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 974 : 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 983 : 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 982 : 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 979 : 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 978 : GDALDataset *poDS = GDALDataset::FromHandle(hSrcDS);
2599 978 : GDALDataset *poODS = nullptr;
2600 978 : GDALDriver *poDriver = nullptr;
2601 1956 : CPLString osDestFilename;
2602 :
2603 978 : if (hDstDS)
2604 : {
2605 26 : poODS = GDALDataset::FromHandle(hDstDS);
2606 26 : osDestFilename = poODS->GetDescription();
2607 : }
2608 : else
2609 : {
2610 952 : 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 1047 : !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 1202 : 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 1954 : std::vector<std::string> aoDrivers;
2661 977 : if (poODS == nullptr && psOptions->osFormat.empty())
2662 : {
2663 397 : const auto nErrorCount = CPLGetErrorCounter();
2664 397 : aoDrivers = CPLStringList(GDALGetOutputDriversForDatasetName(
2665 : pszDest, GDAL_OF_VECTOR, /* bSingleMatch = */ true,
2666 397 : /* bWarn = */ true));
2667 397 : if (!bUpdate && aoDrivers.size() == 1)
2668 : {
2669 351 : GDALDriverH hDriver = GDALGetDriverByName(aoDrivers[0].c_str());
2670 351 : const char *pszPrefix = GDALGetMetadataItem(
2671 : hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);
2672 351 : 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 976 : 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 976 : if (poODS)
2728 71 : poDriver = poODS->GetDriver();
2729 :
2730 : /* -------------------------------------------------------------------- */
2731 : /* Find the output driver. */
2732 : /* -------------------------------------------------------------------- */
2733 976 : bool bNewDataSource = false;
2734 976 : if (!bUpdate)
2735 : {
2736 905 : GDALDriverManager *poDM = GetGDALDriverManager();
2737 :
2738 905 : if (psOptions->bNoOverwrite && !EQUAL(pszDest, ""))
2739 : {
2740 135 : const char *pszType = "";
2741 135 : 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 905 : if (psOptions->osFormat.empty())
2752 : {
2753 361 : 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 349 : psOptions->osFormat = aoDrivers[0];
2770 : }
2771 359 : CPLDebug("GDAL", "Using %s driver", psOptions->osFormat.c_str());
2772 : }
2773 :
2774 903 : 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 903 : if (EQUAL(osOGRCompatFormat, "GMT") ||
2781 902 : EQUAL(osOGRCompatFormat, "VRT") ||
2782 1805 : EQUAL(osOGRCompatFormat, "SDTS") || EQUAL(osOGRCompatFormat, "PDS"))
2783 : {
2784 1 : osOGRCompatFormat = "OGR_" + osOGRCompatFormat;
2785 : }
2786 903 : poDriver = poDM->GetDriverByName(osOGRCompatFormat);
2787 903 : 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 903 : CSLConstList papszDriverMD = poDriver->GetMetadata();
2795 903 : 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 903 : if (poDriver->CanVectorTranslateFrom(
2805 903 : 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 899 : 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 877 : if (!psOptions->aosDestOpenOptions.empty())
2830 : {
2831 0 : CPLError(CE_Warning, CPLE_AppDefined,
2832 : "-doo ignored when creating the output datasource.");
2833 : }
2834 :
2835 : /* --------------------------------------------------------------------
2836 : */
2837 : /* Special case to improve user experience when translating */
2838 : /* a datasource with multiple layers into a shapefile. If the */
2839 : /* user gives a target datasource with .shp and it does not exist,
2840 : */
2841 : /* the shapefile driver will try to create a file, but this is not
2842 : */
2843 : /* appropriate because here we have several layers, so create */
2844 : /* a directory instead. */
2845 : /* --------------------------------------------------------------------
2846 : */
2847 :
2848 : const bool bSingleLayer =
2849 877 : (!psOptions->osSQLStatement.empty() ||
2850 1737 : psOptions->aosLayers.size() == 1 ||
2851 860 : (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1));
2852 :
2853 : VSIStatBufL sStat;
2854 2755 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
2855 124 : !bSingleLayer && psOptions->osNewLayerName.empty() &&
2856 1002 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "SHP") &&
2857 1 : VSIStatL(osDestFilename, &sStat) != 0)
2858 : {
2859 1 : if (VSIMkdir(osDestFilename, 0755) != 0)
2860 : {
2861 0 : CPLError(CE_Failure, CPLE_AppDefined,
2862 : "Failed to create directory %s\n"
2863 : "for shapefile datastore.",
2864 : osDestFilename.c_str());
2865 0 : return nullptr;
2866 : }
2867 : }
2868 :
2869 877 : CPLStringList aosDSCO(psOptions->aosDSCO);
2870 :
2871 877 : if (!aosDSCO.FetchNameValue("SINGLE_LAYER"))
2872 : {
2873 : // Informs the target driver (e.g. JSONFG) if a single layer
2874 : // will be created
2875 : const char *pszCOList =
2876 877 : poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
2877 877 : if (bSingleLayer && pszCOList && strstr(pszCOList, "SINGLE_LAYER"))
2878 : {
2879 4 : aosDSCO.SetNameValue("SINGLE_LAYER", "YES");
2880 : }
2881 : }
2882 :
2883 : /* --------------------------------------------------------------------
2884 : */
2885 : /* Create the output data source. */
2886 : /* --------------------------------------------------------------------
2887 : */
2888 877 : poODS = poDriver->Create(osDestFilename, 0, 0, 0, GDT_Unknown,
2889 877 : aosDSCO.List());
2890 877 : if (poODS == nullptr)
2891 : {
2892 6 : CPLError(CE_Failure, CPLE_AppDefined,
2893 : "%s driver failed to create %s",
2894 3 : psOptions->osFormat.c_str(), osDestFilename.c_str());
2895 3 : return nullptr;
2896 : }
2897 874 : bNewDataSource = true;
2898 :
2899 874 : if (psOptions->bCopyMD)
2900 : {
2901 1740 : const CPLStringList aosDomains(poDS->GetMetadataDomainList());
2902 993 : for (const char *pszMD : aosDomains)
2903 : {
2904 123 : if (CSLConstList papszMD = poDS->GetMetadata(pszMD))
2905 10 : poODS->SetMetadata(papszMD, pszMD);
2906 : }
2907 : }
2908 2 : for (const auto &[pszKey, pszValue] :
2909 876 : cpl::IterateNameValue(psOptions->aosMetadataOptions))
2910 : {
2911 1 : poODS->SetMetadataItem(pszKey, pszValue);
2912 : }
2913 :
2914 : // When writing to GeoJSON and using -nln, set the @NAME layer
2915 : // creation option to avoid the GeoJSON driver to potentially reuse
2916 : // the source feature collection name if the input is also GeoJSON.
2917 886 : if (!psOptions->osNewLayerName.empty() &&
2918 12 : EQUAL(psOptions->osFormat.c_str(), "GeoJSON"))
2919 : {
2920 1 : psOptions->aosLCO.SetNameValue("@NAME",
2921 1 : psOptions->osNewLayerName.c_str());
2922 : }
2923 : }
2924 : else
2925 : {
2926 75 : if (psOptions->bUpsert &&
2927 4 : poDriver->GetMetadataItem(GDAL_DCAP_UPSERT) == nullptr)
2928 : {
2929 2 : CPLError(CE_Failure, CPLE_NotSupported,
2930 : "%s driver doest not support upsert",
2931 2 : poODS->GetDriver()->GetDescription());
2932 2 : return nullptr;
2933 : }
2934 : }
2935 :
2936 : // Automatically close poODS on error, if it has been created by this
2937 : // method.
2938 1886 : GDALDatasetUniquePtr poODSUniquePtr(hDstDS == nullptr ? poODS : nullptr);
2939 :
2940 : // Some syntaxic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=....
2941 : // source [srclayer] -lco OVERWRITE=YES" work like "ogr2ogr -overwrite
2942 : // PG:dbname=.... source [srclayer]" The former syntax used to work at
2943 : // GDAL 1.1.8 time when it was documented in the PG driver, but was broken
2944 : // starting with GDAL 1.3.2
2945 : // (https://github.com/OSGeo/gdal/commit/29c108a6c9f651dfebae6d1313ba0e707a77c1aa)
2946 : // This could probably be generalized to other drivers that support the
2947 : // OVERWRITE layer creation option, but we'd need to make sure that they
2948 : // just do a DeleteLayer() call. The CARTO driver is an exception regarding
2949 : // that.
2950 961 : if (EQUAL(poODS->GetDriver()->GetDescription(), "PostgreSQL") &&
2951 18 : CPLTestBool(psOptions->aosLCO.FetchNameValueDef("OVERWRITE", "NO")))
2952 : {
2953 0 : if (bAppend)
2954 : {
2955 0 : CPLError(CE_Failure, CPLE_AppDefined,
2956 : "-append and -lco OVERWRITE=YES are mutually exclusive");
2957 0 : return nullptr;
2958 : }
2959 0 : bOverwrite = true;
2960 : }
2961 :
2962 : /* -------------------------------------------------------------------- */
2963 : /* For random reading */
2964 : /* -------------------------------------------------------------------- */
2965 : const bool bRandomLayerReading =
2966 943 : CPL_TO_BOOL(poDS->TestCapability(ODsCRandomLayerRead));
2967 17 : if (bRandomLayerReading && !poODS->TestCapability(ODsCRandomLayerWrite) &&
2968 960 : psOptions->aosLayers.size() != 1 && psOptions->osSQLStatement.empty() &&
2969 0 : !psOptions->bQuiet)
2970 : {
2971 0 : CPLError(CE_Warning, CPLE_AppDefined,
2972 : "Input datasource uses random layer reading, but "
2973 : "output datasource does not support random layer writing");
2974 : }
2975 :
2976 943 : if (psOptions->nLayerTransaction < 0)
2977 : {
2978 942 : if (bRandomLayerReading)
2979 17 : psOptions->nLayerTransaction = FALSE;
2980 : else
2981 925 : psOptions->nLayerTransaction =
2982 925 : !poODS->TestCapability(ODsCTransactions);
2983 : }
2984 1 : else if (psOptions->nLayerTransaction && bRandomLayerReading)
2985 : {
2986 0 : psOptions->nLayerTransaction = false;
2987 : }
2988 :
2989 : /* -------------------------------------------------------------------- */
2990 : /* Parse the output SRS definition if possible. */
2991 : /* -------------------------------------------------------------------- */
2992 943 : OGR2OGRSpatialReferenceHolder oOutputSRSHolder;
2993 943 : if (!psOptions->osOutputSRSDef.empty())
2994 : {
2995 144 : oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());
2996 144 : oOutputSRSHolder.get()->SetAxisMappingStrategy(
2997 : OAMS_TRADITIONAL_GIS_ORDER);
2998 288 : if (oOutputSRSHolder.get()->SetFromUserInput(
2999 288 : psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)
3000 : {
3001 0 : CPLError(CE_Failure, CPLE_AppDefined,
3002 : "Failed to process SRS definition: %s",
3003 0 : psOptions->osOutputSRSDef.c_str());
3004 0 : return nullptr;
3005 : }
3006 288 : oOutputSRSHolder.get()->SetCoordinateEpoch(
3007 144 : psOptions->dfOutputCoordinateEpoch);
3008 : }
3009 :
3010 : /* -------------------------------------------------------------------- */
3011 : /* Parse the source SRS definition if possible. */
3012 : /* -------------------------------------------------------------------- */
3013 1886 : OGRSpatialReference oSourceSRS;
3014 943 : OGRSpatialReference *poSourceSRS = nullptr;
3015 943 : if (!psOptions->osSourceSRSDef.empty())
3016 : {
3017 8 : oSourceSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
3018 8 : if (oSourceSRS.SetFromUserInput(psOptions->osSourceSRSDef.c_str()) !=
3019 : OGRERR_NONE)
3020 : {
3021 0 : CPLError(CE_Failure, CPLE_AppDefined,
3022 : "Failed to process SRS definition: %s",
3023 0 : psOptions->osSourceSRSDef.c_str());
3024 0 : return nullptr;
3025 : }
3026 8 : oSourceSRS.SetCoordinateEpoch(psOptions->dfSourceCoordinateEpoch);
3027 8 : poSourceSRS = &oSourceSRS;
3028 : }
3029 :
3030 : /* -------------------------------------------------------------------- */
3031 : /* Create a transformation object from the source to */
3032 : /* destination coordinate system. */
3033 : /* -------------------------------------------------------------------- */
3034 943 : std::unique_ptr<GCPCoordTransformation> poGCPCoordTrans;
3035 943 : if (!psOptions->asGCPs.empty())
3036 : {
3037 7 : poGCPCoordTrans = std::make_unique<GCPCoordTransformation>(
3038 7 : static_cast<int>(psOptions->asGCPs.size()),
3039 7 : gdal::GCP::c_ptr(psOptions->asGCPs), psOptions->nTransformOrder,
3040 14 : poSourceSRS ? poSourceSRS : oOutputSRSHolder.get());
3041 7 : if (!(poGCPCoordTrans->IsValid()))
3042 : {
3043 1 : return nullptr;
3044 : }
3045 : }
3046 :
3047 : /* -------------------------------------------------------------------- */
3048 : /* Create layer setup and transformer objects. */
3049 : /* -------------------------------------------------------------------- */
3050 1884 : SetupTargetLayer oSetup;
3051 942 : oSetup.m_poSrcDS = poDS;
3052 942 : oSetup.m_poDstDS = poODS;
3053 942 : oSetup.m_papszLCO = psOptions->aosLCO.List();
3054 942 : oSetup.m_poOutputSRS = oOutputSRSHolder.get();
3055 942 : oSetup.m_bTransform = psOptions->bTransform;
3056 942 : oSetup.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
3057 942 : oSetup.m_poUserSourceSRS = poSourceSRS;
3058 942 : oSetup.m_bSelFieldsSet = psOptions->bSelFieldsSet;
3059 942 : oSetup.m_papszSelFields = psOptions->aosSelFields.List();
3060 942 : oSetup.m_bAppend = bAppend;
3061 942 : oSetup.m_bAddMissingFields = psOptions->bAddMissingFields;
3062 942 : oSetup.m_eGType = psOptions->eGType;
3063 942 : oSetup.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
3064 942 : oSetup.m_nCoordDim = psOptions->nCoordDim;
3065 942 : oSetup.m_bOverwrite = bOverwrite;
3066 942 : oSetup.m_papszFieldTypesToString = psOptions->aosFieldTypesToString.List();
3067 942 : oSetup.m_papszMapFieldType = psOptions->aosMapFieldType.List();
3068 942 : oSetup.m_bUnsetFieldWidth = psOptions->bUnsetFieldWidth;
3069 942 : oSetup.m_bExplodeCollections = psOptions->bExplodeCollections;
3070 942 : oSetup.m_pszZField =
3071 942 : psOptions->osZField.empty() ? nullptr : psOptions->osZField.c_str();
3072 942 : oSetup.m_papszFieldMap = psOptions->aosFieldMap.List();
3073 942 : oSetup.m_pszWHERE =
3074 942 : psOptions->osWHERE.empty() ? nullptr : psOptions->osWHERE.c_str();
3075 942 : oSetup.m_bExactFieldNameMatch = psOptions->bExactFieldNameMatch;
3076 942 : oSetup.m_bQuiet = psOptions->bQuiet;
3077 942 : oSetup.m_bForceNullable = psOptions->bForceNullable;
3078 942 : oSetup.m_bResolveDomains = psOptions->bResolveDomains;
3079 942 : oSetup.m_bUnsetDefault = psOptions->bUnsetDefault;
3080 942 : oSetup.m_bUnsetFid = psOptions->bUnsetFid;
3081 942 : oSetup.m_bPreserveFID = psOptions->bPreserveFID;
3082 942 : oSetup.m_bCopyMD = psOptions->bCopyMD;
3083 942 : oSetup.m_bNativeData = psOptions->bNativeData;
3084 942 : oSetup.m_bNewDataSource = bNewDataSource;
3085 942 : oSetup.m_pszCTPipeline = psOptions->osCTPipeline.empty()
3086 942 : ? nullptr
3087 4 : : psOptions->osCTPipeline.c_str();
3088 942 : oSetup.m_aosCTOptions = psOptions->aosCTOptions;
3089 :
3090 1884 : LayerTranslator oTranslator;
3091 942 : oTranslator.m_poSrcDS = poDS;
3092 942 : oTranslator.m_poODS = poODS;
3093 942 : oTranslator.m_bTransform = psOptions->bTransform;
3094 942 : oTranslator.m_bWrapDateline = psOptions->bWrapDateline;
3095 : oTranslator.m_osDateLineOffset =
3096 942 : CPLOPrintf("%g", psOptions->dfDateLineOffset);
3097 942 : oTranslator.m_poOutputSRS = oOutputSRSHolder.get();
3098 942 : oTranslator.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
3099 942 : oTranslator.m_poUserSourceSRS = poSourceSRS;
3100 942 : oTranslator.m_poGCPCoordTrans = poGCPCoordTrans.get();
3101 942 : oTranslator.m_eGType = psOptions->eGType;
3102 942 : oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
3103 942 : oTranslator.m_bMakeValid = psOptions->bMakeValid;
3104 942 : oTranslator.m_bSkipInvalidGeom = psOptions->bSkipInvalidGeom;
3105 942 : oTranslator.m_nCoordDim = psOptions->nCoordDim;
3106 942 : oTranslator.m_eGeomOp = psOptions->eGeomOp;
3107 942 : oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam;
3108 : // Do not emit warning if the user specified directly the clip source geom
3109 942 : if (psOptions->osClipSrcDS.empty())
3110 934 : oTranslator.m_bWarnedClipSrcSRS = true;
3111 942 : oTranslator.m_poClipSrcOri = psOptions->poClipSrc.get();
3112 : // Do not emit warning if the user specified directly the clip dest geom
3113 942 : if (psOptions->osClipDstDS.empty())
3114 935 : oTranslator.m_bWarnedClipDstSRS = true;
3115 942 : oTranslator.m_poClipDstOri = psOptions->poClipDst.get();
3116 942 : oTranslator.m_bExplodeCollections = psOptions->bExplodeCollections;
3117 942 : oTranslator.m_bNativeData = psOptions->bNativeData;
3118 942 : oTranslator.m_nLimit = psOptions->nLimit;
3119 :
3120 942 : if (psOptions->nGroupTransactions)
3121 : {
3122 941 : if (!psOptions->nLayerTransaction)
3123 166 : poODS->StartTransaction(psOptions->bForceTransaction);
3124 : }
3125 :
3126 942 : GIntBig nTotalEventsDone = 0;
3127 :
3128 : /* -------------------------------------------------------------------- */
3129 : /* Special case for -sql clause. No source layers required. */
3130 : /* -------------------------------------------------------------------- */
3131 942 : int nRetCode = 0;
3132 :
3133 942 : if (!psOptions->osSQLStatement.empty())
3134 : {
3135 : /* Special case: if output=input, then we must likely destroy the */
3136 : /* old table before to avoid transaction issues. */
3137 12 : if (poDS == poODS && !psOptions->osNewLayerName.empty() && bOverwrite)
3138 0 : GetLayerAndOverwriteIfNecessary(
3139 0 : poODS, psOptions->osNewLayerName.c_str(), bOverwrite, nullptr,
3140 : nullptr, nullptr);
3141 :
3142 12 : if (!psOptions->osWHERE.empty())
3143 0 : CPLError(CE_Warning, CPLE_AppDefined,
3144 : "-where clause ignored in combination with -sql.");
3145 12 : if (psOptions->aosLayers.size() > 0)
3146 0 : CPLError(CE_Warning, CPLE_AppDefined,
3147 : "layer names ignored in combination with -sql.");
3148 :
3149 24 : OGRLayer *poResultSet = poDS->ExecuteSQL(
3150 12 : psOptions->osSQLStatement.c_str(),
3151 12 : (!psOptions->bGeomFieldSet) ? psOptions->poSpatialFilter.get()
3152 : : nullptr,
3153 12 : psOptions->osDialect.empty() ? nullptr
3154 14 : : psOptions->osDialect.c_str());
3155 :
3156 12 : if (poResultSet != nullptr)
3157 : {
3158 12 : if (psOptions->poSpatialFilter && psOptions->bGeomFieldSet)
3159 : {
3160 0 : int iGeomField = poResultSet->GetLayerDefn()->GetGeomFieldIndex(
3161 0 : psOptions->osGeomField.c_str());
3162 0 : if (iGeomField >= 0)
3163 0 : poResultSet->SetSpatialFilter(
3164 0 : iGeomField, psOptions->poSpatialFilter.get());
3165 : else
3166 0 : CPLError(CE_Warning, CPLE_AppDefined,
3167 : "Cannot find geometry field %s.",
3168 0 : psOptions->osGeomField.c_str());
3169 : }
3170 :
3171 12 : GIntBig nCountLayerFeatures = 0;
3172 12 : GDALProgressFunc pfnProgress = nullptr;
3173 12 : void *pProgressArg = nullptr;
3174 12 : if (psOptions->bDisplayProgress)
3175 : {
3176 1 : if (bRandomLayerReading)
3177 : {
3178 1 : pfnProgress = psOptions->pfnProgress;
3179 1 : pProgressArg = psOptions->pProgressData;
3180 : }
3181 0 : else if (!poResultSet->TestCapability(OLCFastFeatureCount))
3182 : {
3183 0 : if (!psOptions->bInvokedFromGdalVectorConvert)
3184 : {
3185 0 : CPLError(
3186 : CE_Warning, CPLE_AppDefined,
3187 : "Progress turned off as fast feature count is not "
3188 : "available.");
3189 : }
3190 0 : psOptions->bDisplayProgress = false;
3191 : }
3192 : else
3193 : {
3194 0 : nCountLayerFeatures = poResultSet->GetFeatureCount();
3195 0 : pfnProgress = psOptions->pfnProgress;
3196 0 : pProgressArg = psOptions->pProgressData;
3197 : }
3198 : }
3199 :
3200 12 : std::unique_ptr<OGRLayer> poLayerToFree;
3201 12 : OGRLayer *poPassedLayer = poResultSet;
3202 12 : if (psOptions->bSplitListFields)
3203 : {
3204 : auto poLayer = std::make_unique<OGRSplitListFieldLayer>(
3205 0 : poPassedLayer, psOptions->nMaxSplitListSubFields);
3206 0 : int nRet = poLayer->BuildLayerDefn(nullptr, nullptr);
3207 0 : if (nRet)
3208 : {
3209 0 : poLayerToFree = std::move(poLayer);
3210 0 : poPassedLayer = poLayerToFree.get();
3211 : }
3212 : }
3213 :
3214 : /* --------------------------------------------------------------------
3215 : */
3216 : /* Special case to improve user experience when translating
3217 : * into */
3218 : /* single file shapefile and source has only one layer, and
3219 : * that */
3220 : /* the layer name isn't specified */
3221 : /* --------------------------------------------------------------------
3222 : */
3223 : VSIStatBufL sStat;
3224 3 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3225 3 : psOptions->osNewLayerName.empty() &&
3226 3 : VSIStatL(osDestFilename, &sStat) == 0 &&
3227 15 : VSI_ISREG(sStat.st_mode) &&
3228 12 : (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||
3229 12 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||
3230 12 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))
3231 : {
3232 0 : psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);
3233 : }
3234 :
3235 : auto psInfo = oSetup.Setup(poPassedLayer,
3236 12 : psOptions->osNewLayerName.empty()
3237 : ? nullptr
3238 1 : : psOptions->osNewLayerName.c_str(),
3239 37 : psOptions.get(), nTotalEventsDone);
3240 :
3241 12 : poPassedLayer->ResetReading();
3242 :
3243 24 : if (psInfo == nullptr ||
3244 24 : !oTranslator.Translate(nullptr, psInfo.get(),
3245 : nCountLayerFeatures, nullptr,
3246 : nTotalEventsDone, pfnProgress,
3247 12 : pProgressArg, psOptions.get()))
3248 : {
3249 0 : CPLError(CE_Failure, CPLE_AppDefined,
3250 : "Terminating translation prematurely after failed\n"
3251 : "translation from sql statement.");
3252 :
3253 0 : nRetCode = 1;
3254 : }
3255 : else
3256 : {
3257 12 : psInfo->CheckSameCoordinateOperation();
3258 : }
3259 :
3260 12 : poDS->ReleaseResultSet(poResultSet);
3261 : }
3262 : else
3263 : {
3264 0 : if (CPLGetLastErrorNo() != 0)
3265 0 : nRetCode = 1;
3266 : }
3267 : }
3268 :
3269 : /* -------------------------------------------------------------------- */
3270 : /* Special case for layer interleaving mode. */
3271 : /* -------------------------------------------------------------------- */
3272 930 : else if (bRandomLayerReading)
3273 : {
3274 16 : if (psOptions->bSplitListFields)
3275 : {
3276 0 : CPLError(CE_Failure, CPLE_AppDefined,
3277 : "-splitlistfields not supported in this mode");
3278 0 : return nullptr;
3279 : }
3280 :
3281 : // Make sure to probe all layers in case some are by default invisible
3282 28 : for (const char *pszLayer : psOptions->aosLayers)
3283 : {
3284 12 : OGRLayer *poLayer = poDS->GetLayerByName(pszLayer);
3285 :
3286 12 : if (poLayer == nullptr)
3287 : {
3288 0 : CPLError(CE_Failure, CPLE_AppDefined,
3289 : "Couldn't fetch requested layer %s!", pszLayer);
3290 0 : return nullptr;
3291 : }
3292 : }
3293 :
3294 16 : const int nSrcLayerCount = poDS->GetLayerCount();
3295 16 : std::vector<AssociatedLayers> pasAssocLayers(nSrcLayerCount);
3296 :
3297 : /* --------------------------------------------------------------------
3298 : */
3299 : /* Special case to improve user experience when translating into */
3300 : /* single file shapefile and source has only one layer, and that */
3301 : /* the layer name isn't specified */
3302 : /* --------------------------------------------------------------------
3303 : */
3304 : VSIStatBufL sStat;
3305 53 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3306 5 : (psOptions->aosLayers.size() == 1 || nSrcLayerCount == 1) &&
3307 0 : psOptions->osNewLayerName.empty() &&
3308 21 : VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3309 16 : (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||
3310 16 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||
3311 16 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))
3312 : {
3313 0 : psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);
3314 : }
3315 :
3316 16 : GDALProgressFunc pfnProgress = nullptr;
3317 16 : void *pProgressArg = nullptr;
3318 16 : if (!psOptions->bQuiet)
3319 : {
3320 16 : pfnProgress = psOptions->pfnProgress;
3321 16 : pProgressArg = psOptions->pProgressData;
3322 : }
3323 :
3324 : /* --------------------------------------------------------------------
3325 : */
3326 : /* If no target layer specified, use all source layers. */
3327 : /* --------------------------------------------------------------------
3328 : */
3329 16 : if (psOptions->aosLayers.empty())
3330 : {
3331 148 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3332 : {
3333 135 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3334 :
3335 135 : if (poLayer == nullptr)
3336 : {
3337 0 : CPLError(CE_Failure, CPLE_AppDefined,
3338 : "Couldn't fetch advertised layer %d!", iLayer);
3339 0 : return nullptr;
3340 : }
3341 :
3342 135 : psOptions->aosLayers.AddString(poLayer->GetName());
3343 : }
3344 : }
3345 : else
3346 : {
3347 3 : const bool bSrcIsOSM = (strcmp(poDS->GetDriverName(), "OSM") == 0);
3348 3 : if (bSrcIsOSM)
3349 : {
3350 6 : CPLString osInterestLayers = "SET interest_layers =";
3351 15 : for (int iLayer = 0; iLayer < psOptions->aosLayers.size();
3352 : iLayer++)
3353 : {
3354 12 : if (iLayer != 0)
3355 9 : osInterestLayers += ",";
3356 12 : osInterestLayers += psOptions->aosLayers[iLayer];
3357 : }
3358 :
3359 3 : poDS->ExecuteSQL(osInterestLayers.c_str(), nullptr, nullptr);
3360 : }
3361 : }
3362 :
3363 : /* --------------------------------------------------------------------
3364 : */
3365 : /* First pass to set filters. */
3366 : /* --------------------------------------------------------------------
3367 : */
3368 16 : std::map<OGRLayer *, int> oMapLayerToIdx;
3369 :
3370 166 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3371 : {
3372 150 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3373 150 : if (poLayer == nullptr)
3374 : {
3375 0 : CPLError(CE_Failure, CPLE_AppDefined,
3376 : "Couldn't fetch advertised layer %d!", iLayer);
3377 0 : return nullptr;
3378 : }
3379 :
3380 150 : pasAssocLayers[iLayer].poSrcLayer = poLayer;
3381 :
3382 150 : if (psOptions->aosLayers.FindString(poLayer->GetName()) >= 0)
3383 : {
3384 147 : if (!psOptions->osWHERE.empty())
3385 : {
3386 0 : if (poLayer->SetAttributeFilter(
3387 0 : psOptions->osWHERE.c_str()) != OGRERR_NONE)
3388 : {
3389 0 : CPLError(CE_Failure, CPLE_AppDefined,
3390 : "SetAttributeFilter(%s) on layer '%s' failed.",
3391 0 : psOptions->osWHERE.c_str(),
3392 0 : poLayer->GetName());
3393 0 : if (!psOptions->bSkipFailures)
3394 : {
3395 0 : return nullptr;
3396 : }
3397 : }
3398 : }
3399 :
3400 294 : ApplySpatialFilter(
3401 147 : poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3402 147 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3403 : : nullptr,
3404 : poSourceSRS);
3405 :
3406 147 : oMapLayerToIdx[poLayer] = iLayer;
3407 : }
3408 : }
3409 :
3410 : /* --------------------------------------------------------------------
3411 : */
3412 : /* Second pass to process features in a interleaved layer mode. */
3413 : /* --------------------------------------------------------------------
3414 : */
3415 16 : bool bTargetLayersHaveBeenCreated = false;
3416 : while (true)
3417 : {
3418 991 : OGRLayer *poFeatureLayer = nullptr;
3419 : auto poFeature = std::unique_ptr<OGRFeature>(poDS->GetNextFeature(
3420 991 : &poFeatureLayer, nullptr, pfnProgress, pProgressArg));
3421 991 : if (poFeature == nullptr)
3422 16 : break;
3423 : std::map<OGRLayer *, int>::const_iterator oIter =
3424 975 : oMapLayerToIdx.find(poFeatureLayer);
3425 975 : if (oIter == oMapLayerToIdx.end())
3426 : {
3427 : // Feature in a layer that is not a layer of interest.
3428 : // nothing to do
3429 : }
3430 : else
3431 : {
3432 975 : if (!bTargetLayersHaveBeenCreated)
3433 : {
3434 : // We defer target layer creation at the first feature
3435 : // retrieved since getting the layer definition can be
3436 : // costly (case of the GMLAS driver) and thus we'd better
3437 : // taking advantage from the progress callback of
3438 : // GetNextFeature.
3439 15 : bTargetLayersHaveBeenCreated = true;
3440 160 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3441 : {
3442 145 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3443 290 : if (psOptions->aosLayers.FindString(
3444 290 : poLayer->GetName()) < 0)
3445 3 : continue;
3446 :
3447 : auto psInfo = oSetup.Setup(
3448 : poLayer,
3449 142 : psOptions->osNewLayerName.empty()
3450 : ? nullptr
3451 0 : : psOptions->osNewLayerName.c_str(),
3452 284 : psOptions.get(), nTotalEventsDone);
3453 :
3454 142 : if (psInfo == nullptr && !psOptions->bSkipFailures)
3455 : {
3456 0 : return nullptr;
3457 : }
3458 :
3459 142 : pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3460 : }
3461 15 : if (nRetCode)
3462 0 : break;
3463 : }
3464 :
3465 975 : int iLayer = oIter->second;
3466 975 : TargetLayerInfo *psInfo = pasAssocLayers[iLayer].psInfo.get();
3467 2923 : if ((psInfo == nullptr ||
3468 1949 : !oTranslator.Translate(std::move(poFeature), psInfo, 0,
3469 : nullptr, nTotalEventsDone, nullptr,
3470 1950 : nullptr, psOptions.get())) &&
3471 1 : !psOptions->bSkipFailures)
3472 : {
3473 0 : CPLError(
3474 : CE_Failure, CPLE_AppDefined,
3475 : "Terminating translation prematurely after failed\n"
3476 : "translation of layer %s (use -skipfailures to skip "
3477 : "errors)",
3478 0 : poFeatureLayer->GetName());
3479 :
3480 0 : nRetCode = 1;
3481 0 : break;
3482 : }
3483 : }
3484 975 : } // while true
3485 :
3486 16 : if (pfnProgress)
3487 : {
3488 0 : pfnProgress(1.0, "", pProgressArg);
3489 : }
3490 :
3491 166 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3492 : {
3493 150 : if (pasAssocLayers[iLayer].psInfo)
3494 141 : pasAssocLayers[iLayer].psInfo->CheckSameCoordinateOperation();
3495 : }
3496 :
3497 16 : if (!bTargetLayersHaveBeenCreated)
3498 : {
3499 : // bTargetLayersHaveBeenCreated not used after here.
3500 : // bTargetLayersHaveBeenCreated = true;
3501 6 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3502 : {
3503 5 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3504 5 : if (psOptions->aosLayers.FindString(poLayer->GetName()) < 0)
3505 0 : continue;
3506 :
3507 : auto psInfo =
3508 : oSetup.Setup(poLayer,
3509 5 : psOptions->osNewLayerName.empty()
3510 : ? nullptr
3511 0 : : psOptions->osNewLayerName.c_str(),
3512 10 : psOptions.get(), nTotalEventsDone);
3513 :
3514 5 : if (psInfo == nullptr && !psOptions->bSkipFailures)
3515 : {
3516 0 : return nullptr;
3517 : }
3518 :
3519 5 : pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3520 : }
3521 : }
3522 : }
3523 :
3524 : else
3525 : {
3526 914 : std::vector<OGRLayer *> apoLayers;
3527 :
3528 : /* --------------------------------------------------------------------
3529 : */
3530 : /* Process each data source layer. */
3531 : /* --------------------------------------------------------------------
3532 : */
3533 914 : if (psOptions->aosLayers.empty())
3534 : {
3535 902 : const int nLayerCount = poDS->GetLayerCount();
3536 :
3537 1866 : for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3538 : {
3539 964 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3540 :
3541 964 : if (poLayer == nullptr)
3542 : {
3543 0 : CPLError(CE_Failure, CPLE_AppDefined,
3544 : "Couldn't fetch advertised layer %d!", iLayer);
3545 0 : return nullptr;
3546 : }
3547 964 : if (!poDS->IsLayerPrivate(iLayer))
3548 : {
3549 964 : apoLayers.push_back(poLayer);
3550 : }
3551 : }
3552 : }
3553 : /* --------------------------------------------------------------------
3554 : */
3555 : /* Process specified data source layers. */
3556 : /* --------------------------------------------------------------------
3557 : */
3558 : else
3559 : {
3560 :
3561 33 : for (int iLayer = 0; psOptions->aosLayers[iLayer] != nullptr;
3562 : iLayer++)
3563 : {
3564 : OGRLayer *poLayer =
3565 21 : poDS->GetLayerByName(psOptions->aosLayers[iLayer]);
3566 :
3567 21 : if (poLayer == nullptr)
3568 : {
3569 0 : CPLError(CE_Failure, CPLE_AppDefined,
3570 : "Couldn't fetch requested layer '%s'!",
3571 0 : psOptions->aosLayers[iLayer]);
3572 0 : if (!psOptions->bSkipFailures)
3573 : {
3574 0 : return nullptr;
3575 : }
3576 : }
3577 :
3578 21 : apoLayers.emplace_back(poLayer);
3579 : }
3580 : }
3581 :
3582 : /* --------------------------------------------------------------------
3583 : */
3584 : /* Special case to improve user experience when translating into */
3585 : /* single file shapefile and source has only one layer, and that */
3586 : /* the layer name isn't specified */
3587 : /* --------------------------------------------------------------------
3588 : */
3589 : VSIStatBufL sStat;
3590 914 : const int nLayerCount = static_cast<int>(apoLayers.size());
3591 137 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3592 134 : nLayerCount == 1 && psOptions->osNewLayerName.empty() &&
3593 1062 : VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3594 925 : (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||
3595 916 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||
3596 915 : EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))
3597 : {
3598 10 : psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);
3599 : }
3600 :
3601 914 : std::vector<GIntBig> anLayerCountFeatures(nLayerCount);
3602 914 : GIntBig nCountLayersFeatures = 0;
3603 914 : GIntBig nAccCountFeatures = 0;
3604 :
3605 : /* First pass to apply filters and count all features if necessary */
3606 1899 : for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3607 : {
3608 985 : OGRLayer *poLayer = apoLayers[iLayer];
3609 985 : if (poLayer == nullptr)
3610 0 : continue;
3611 :
3612 985 : if (!psOptions->osWHERE.empty())
3613 : {
3614 8 : if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=
3615 : OGRERR_NONE)
3616 : {
3617 0 : CPLError(CE_Failure, CPLE_AppDefined,
3618 : "SetAttributeFilter(%s) on layer '%s' failed.",
3619 0 : psOptions->osWHERE.c_str(), poLayer->GetName());
3620 0 : if (!psOptions->bSkipFailures)
3621 : {
3622 0 : return nullptr;
3623 : }
3624 : }
3625 : }
3626 :
3627 1969 : ApplySpatialFilter(
3628 985 : poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3629 985 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3630 : : nullptr,
3631 : poSourceSRS);
3632 :
3633 985 : if (psOptions->bDisplayProgress)
3634 : {
3635 16 : if (!poLayer->TestCapability(OLCFastFeatureCount))
3636 : {
3637 1 : if (!psOptions->bInvokedFromGdalVectorConvert)
3638 : {
3639 0 : CPLError(
3640 : CE_Warning, CPLE_NotSupported,
3641 : "Progress turned off as fast feature count is not "
3642 : "available.");
3643 : }
3644 1 : psOptions->bDisplayProgress = false;
3645 : }
3646 : else
3647 : {
3648 15 : anLayerCountFeatures[iLayer] = poLayer->GetFeatureCount();
3649 15 : if (psOptions->nLimit >= 0)
3650 0 : anLayerCountFeatures[iLayer] = std::min(
3651 0 : anLayerCountFeatures[iLayer], psOptions->nLimit);
3652 30 : if (anLayerCountFeatures[iLayer] >= 0 &&
3653 15 : anLayerCountFeatures[iLayer] <=
3654 15 : std::numeric_limits<GIntBig>::max() -
3655 : nCountLayersFeatures)
3656 : {
3657 14 : nCountLayersFeatures += anLayerCountFeatures[iLayer];
3658 : }
3659 : else
3660 : {
3661 1 : nCountLayersFeatures = 0;
3662 1 : psOptions->bDisplayProgress = false;
3663 : }
3664 : }
3665 : }
3666 : }
3667 :
3668 : /* Second pass to do the real job */
3669 1899 : for (int iLayer = 0; iLayer < nLayerCount && nRetCode == 0; iLayer++)
3670 : {
3671 985 : OGRLayer *poLayer = apoLayers[iLayer];
3672 985 : if (poLayer == nullptr)
3673 0 : continue;
3674 :
3675 985 : std::unique_ptr<OGRLayer> poLayerToFree;
3676 985 : OGRLayer *poPassedLayer = poLayer;
3677 985 : if (psOptions->bSplitListFields)
3678 : {
3679 : auto poSLFLayer = std::make_unique<OGRSplitListFieldLayer>(
3680 2 : poPassedLayer, psOptions->nMaxSplitListSubFields);
3681 :
3682 1 : GDALProgressFunc pfnProgress = nullptr;
3683 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
3684 2 : pProgressArg(nullptr, GDALDestroyScaledProgress);
3685 :
3686 1 : if (psOptions->bDisplayProgress &&
3687 1 : psOptions->nMaxSplitListSubFields != 1 &&
3688 : nCountLayersFeatures != 0)
3689 : {
3690 0 : pfnProgress = GDALScaledProgress;
3691 0 : pProgressArg.reset(GDALCreateScaledProgress(
3692 : nAccCountFeatures * 1.0 / nCountLayersFeatures,
3693 0 : (nAccCountFeatures + anLayerCountFeatures[iLayer] / 2) *
3694 : 1.0 / nCountLayersFeatures,
3695 0 : psOptions->pfnProgress, psOptions->pProgressData));
3696 : }
3697 :
3698 : int nRet =
3699 1 : poSLFLayer->BuildLayerDefn(pfnProgress, pProgressArg.get());
3700 1 : if (nRet)
3701 : {
3702 1 : poLayerToFree = std::move(poSLFLayer);
3703 1 : poPassedLayer = poLayerToFree.get();
3704 : }
3705 : }
3706 :
3707 985 : GDALProgressFunc pfnProgress = nullptr;
3708 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
3709 1970 : pProgressArg(nullptr, GDALDestroyScaledProgress);
3710 :
3711 985 : if (psOptions->bDisplayProgress)
3712 : {
3713 13 : if (nCountLayersFeatures != 0)
3714 : {
3715 13 : pfnProgress = GDALScaledProgress;
3716 13 : GIntBig nStart = 0;
3717 13 : if (poPassedLayer != poLayer &&
3718 0 : psOptions->nMaxSplitListSubFields != 1)
3719 0 : nStart = anLayerCountFeatures[iLayer] / 2;
3720 13 : pProgressArg.reset(GDALCreateScaledProgress(
3721 13 : (nAccCountFeatures + nStart) * 1.0 /
3722 : nCountLayersFeatures,
3723 13 : (nAccCountFeatures + anLayerCountFeatures[iLayer]) *
3724 : 1.0 / nCountLayersFeatures,
3725 13 : psOptions->pfnProgress, psOptions->pProgressData));
3726 : }
3727 :
3728 13 : nAccCountFeatures += anLayerCountFeatures[iLayer];
3729 : }
3730 :
3731 : auto psInfo = oSetup.Setup(poPassedLayer,
3732 985 : psOptions->osNewLayerName.empty()
3733 : ? nullptr
3734 37 : : psOptions->osNewLayerName.c_str(),
3735 2992 : psOptions.get(), nTotalEventsDone);
3736 :
3737 985 : poPassedLayer->ResetReading();
3738 :
3739 3936 : if ((psInfo == nullptr ||
3740 2951 : !oTranslator.Translate(nullptr, psInfo.get(),
3741 983 : anLayerCountFeatures[iLayer], nullptr,
3742 : nTotalEventsDone, pfnProgress,
3743 1970 : pProgressArg.get(), psOptions.get())) &&
3744 15 : !psOptions->bSkipFailures)
3745 : {
3746 14 : CPLError(CE_Failure, CPLE_AppDefined,
3747 : "Terminating translation prematurely after failed\n"
3748 : "translation of layer %s (use -skipfailures to skip "
3749 : "errors)",
3750 14 : poLayer->GetName());
3751 :
3752 14 : nRetCode = 1;
3753 : }
3754 :
3755 985 : if (psInfo)
3756 983 : psInfo->CheckSameCoordinateOperation();
3757 : }
3758 : }
3759 :
3760 942 : CopyRelationships(poODS, poDS);
3761 :
3762 : /* -------------------------------------------------------------------- */
3763 : /* Process DS style table */
3764 : /* -------------------------------------------------------------------- */
3765 :
3766 942 : poODS->SetStyleTable(poDS->GetStyleTable());
3767 :
3768 942 : if (psOptions->nGroupTransactions)
3769 : {
3770 941 : if (!psOptions->nLayerTransaction)
3771 : {
3772 166 : if (nRetCode != 0 && !psOptions->bSkipFailures)
3773 6 : poODS->RollbackTransaction();
3774 : else
3775 : {
3776 160 : OGRErr eRet = poODS->CommitTransaction();
3777 160 : if (eRet != OGRERR_NONE && eRet != OGRERR_UNSUPPORTED_OPERATION)
3778 : {
3779 1 : nRetCode = 1;
3780 : }
3781 : }
3782 : }
3783 : }
3784 :
3785 : // Note: this guarantees that the file can be opened in a consistent state,
3786 : // without requiring to close poODS, only if the driver declares
3787 : // DCAP_FLUSHCACHE_CONSISTENT_STATE
3788 942 : if (poODS->FlushCache() != CE_None)
3789 0 : nRetCode = 1;
3790 :
3791 942 : if (nRetCode == 0)
3792 : {
3793 927 : if (hDstDS)
3794 25 : return hDstDS;
3795 : else
3796 902 : return GDALDataset::ToHandle(poODSUniquePtr.release());
3797 : }
3798 :
3799 15 : return nullptr;
3800 : }
3801 :
3802 : /************************************************************************/
3803 : /* SetZ() */
3804 : /************************************************************************/
3805 :
3806 : namespace
3807 : {
3808 : class SetZVisitor : public OGRDefaultGeometryVisitor
3809 : {
3810 : double m_dfZ;
3811 :
3812 : public:
3813 30 : explicit SetZVisitor(double dfZ) : m_dfZ(dfZ)
3814 : {
3815 30 : }
3816 :
3817 : using OGRDefaultGeometryVisitor::visit;
3818 :
3819 735 : void visit(OGRPoint *poPoint) override
3820 : {
3821 735 : poPoint->setZ(m_dfZ);
3822 735 : }
3823 : };
3824 : } // namespace
3825 :
3826 30 : static void SetZ(OGRGeometry *poGeom, double dfZ)
3827 : {
3828 30 : if (poGeom == nullptr)
3829 0 : return;
3830 60 : SetZVisitor visitor(dfZ);
3831 30 : poGeom->set3D(true);
3832 30 : poGeom->accept(&visitor);
3833 : }
3834 :
3835 : /************************************************************************/
3836 : /* ForceCoordDimension() */
3837 : /************************************************************************/
3838 :
3839 1278 : static int ForceCoordDimension(int eGType, int nCoordDim)
3840 : {
3841 1278 : if (nCoordDim == 2 && eGType != wkbNone)
3842 3 : return wkbFlatten(eGType);
3843 1275 : else if (nCoordDim == 3 && eGType != wkbNone)
3844 3 : return wkbSetZ(wkbFlatten(eGType));
3845 1272 : else if (nCoordDim == COORD_DIM_XYM && eGType != wkbNone)
3846 2 : return wkbSetM(wkbFlatten(eGType));
3847 1270 : else if (nCoordDim == 4 && eGType != wkbNone)
3848 2 : return OGR_GT_SetModifier(static_cast<OGRwkbGeometryType>(eGType), TRUE,
3849 2 : TRUE);
3850 : else
3851 1268 : return eGType;
3852 : }
3853 :
3854 : /************************************************************************/
3855 : /* GetLayerAndOverwriteIfNecessary() */
3856 : /************************************************************************/
3857 :
3858 1144 : static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
3859 : const char *pszNewLayerName,
3860 : bool bOverwrite,
3861 : bool *pbErrorOccurred,
3862 : bool *pbOverwriteActuallyDone,
3863 : bool *pbAddOverwriteLCO)
3864 : {
3865 1144 : if (pbErrorOccurred)
3866 1144 : *pbErrorOccurred = false;
3867 1144 : if (pbOverwriteActuallyDone)
3868 1144 : *pbOverwriteActuallyDone = false;
3869 1144 : if (pbAddOverwriteLCO)
3870 1144 : *pbAddOverwriteLCO = false;
3871 :
3872 : /* GetLayerByName() can instantiate layers that would have been */
3873 : /* 'hidden' otherwise, for example, non-spatial tables in a */
3874 : /* PostGIS-enabled database, so this apparently useless command is */
3875 : /* not useless. (#4012) */
3876 1144 : CPLPushErrorHandler(CPLQuietErrorHandler);
3877 1144 : OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
3878 1144 : CPLPopErrorHandler();
3879 1144 : CPLErrorReset();
3880 :
3881 1144 : int iLayer = -1;
3882 1144 : if (poDstLayer != nullptr)
3883 : {
3884 62 : const int nLayerCount = poDstDS->GetLayerCount();
3885 376 : for (iLayer = 0; iLayer < nLayerCount; iLayer++)
3886 : {
3887 376 : OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
3888 376 : if (poLayer == poDstLayer)
3889 62 : break;
3890 : }
3891 :
3892 62 : if (iLayer == nLayerCount)
3893 : /* should not happen with an ideal driver */
3894 0 : poDstLayer = nullptr;
3895 : }
3896 :
3897 : /* -------------------------------------------------------------------- */
3898 : /* If the user requested overwrite, and we have the layer in */
3899 : /* question we need to delete it now so it will get recreated */
3900 : /* (overwritten). */
3901 : /* -------------------------------------------------------------------- */
3902 1144 : if (poDstLayer != nullptr && bOverwrite)
3903 : {
3904 : /* When using the CARTO driver we don't want to delete the layer if */
3905 : /* it's going to be recreated. Instead we mark it to be overwritten */
3906 : /* when the new creation is requested */
3907 16 : if (poDstDS->GetDriver()->GetMetadataItem(
3908 32 : GDAL_DS_LAYER_CREATIONOPTIONLIST) != nullptr &&
3909 32 : strstr(poDstDS->GetDriver()->GetMetadataItem(
3910 16 : GDAL_DS_LAYER_CREATIONOPTIONLIST),
3911 : "CARTODBFY") != nullptr)
3912 : {
3913 0 : if (pbAddOverwriteLCO)
3914 0 : *pbAddOverwriteLCO = true;
3915 0 : if (pbOverwriteActuallyDone)
3916 0 : *pbOverwriteActuallyDone = true;
3917 : }
3918 16 : else if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
3919 : {
3920 0 : CPLError(CE_Failure, CPLE_AppDefined,
3921 : "DeleteLayer() failed when overwrite requested.");
3922 0 : if (pbErrorOccurred)
3923 0 : *pbErrorOccurred = true;
3924 : }
3925 : else
3926 : {
3927 16 : if (pbOverwriteActuallyDone)
3928 16 : *pbOverwriteActuallyDone = true;
3929 : }
3930 16 : poDstLayer = nullptr;
3931 : }
3932 :
3933 1144 : return poDstLayer;
3934 : }
3935 :
3936 : /************************************************************************/
3937 : /* ConvertType() */
3938 : /************************************************************************/
3939 :
3940 1271 : static OGRwkbGeometryType ConvertType(GeomTypeConversion eGeomTypeConversion,
3941 : OGRwkbGeometryType eGType)
3942 : {
3943 1271 : OGRwkbGeometryType eRetType = eGType;
3944 :
3945 1271 : if (eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
3946 : eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3947 : {
3948 13 : eRetType = OGR_GT_GetLinear(eRetType);
3949 : }
3950 :
3951 1271 : if (eGeomTypeConversion == GTC_PROMOTE_TO_MULTI ||
3952 : eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3953 : {
3954 12 : if (eRetType == wkbTriangle || eRetType == wkbTIN ||
3955 : eRetType == wkbPolyhedralSurface)
3956 : {
3957 0 : eRetType = wkbMultiPolygon;
3958 : }
3959 12 : else if (!OGR_GT_IsSubClassOf(eRetType, wkbGeometryCollection))
3960 : {
3961 8 : eRetType = OGR_GT_GetCollection(eRetType);
3962 : }
3963 : }
3964 :
3965 1271 : if (eGeomTypeConversion == GTC_CONVERT_TO_CURVE)
3966 2 : eRetType = OGR_GT_GetCurve(eRetType);
3967 :
3968 1271 : return eRetType;
3969 : }
3970 :
3971 : /************************************************************************/
3972 : /* DoFieldTypeConversion() */
3973 : /************************************************************************/
3974 :
3975 3682 : static void DoFieldTypeConversion(GDALDataset *poDstDS,
3976 : OGRFieldDefn &oFieldDefn,
3977 : CSLConstList papszFieldTypesToString,
3978 : CSLConstList papszMapFieldType,
3979 : bool bUnsetFieldWidth, bool bQuiet,
3980 : bool bForceNullable, bool bUnsetDefault)
3981 : {
3982 3682 : if (papszFieldTypesToString != nullptr)
3983 : {
3984 0 : CPLString osLookupString;
3985 : osLookupString.Printf(
3986 : "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3987 0 : OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
3988 :
3989 0 : int iIdx = CSLFindString(papszFieldTypesToString, osLookupString);
3990 0 : if (iIdx < 0)
3991 0 : iIdx = CSLFindString(
3992 : papszFieldTypesToString,
3993 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
3994 0 : if (iIdx < 0)
3995 0 : iIdx = CSLFindString(papszFieldTypesToString, "All");
3996 0 : if (iIdx >= 0)
3997 : {
3998 0 : oFieldDefn.SetSubType(OFSTNone);
3999 0 : oFieldDefn.SetType(OFTString);
4000 : }
4001 : }
4002 3682 : else if (papszMapFieldType != nullptr)
4003 : {
4004 28 : CPLString osLookupString;
4005 : osLookupString.Printf(
4006 : "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4007 14 : OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
4008 :
4009 : const char *pszType =
4010 14 : CSLFetchNameValue(papszMapFieldType, osLookupString);
4011 14 : if (pszType == nullptr)
4012 13 : pszType = CSLFetchNameValue(
4013 : papszMapFieldType,
4014 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
4015 14 : if (pszType == nullptr)
4016 10 : pszType = CSLFetchNameValue(papszMapFieldType, "All");
4017 14 : if (pszType != nullptr)
4018 : {
4019 : int iSubType;
4020 4 : int iType = GetFieldType(pszType, &iSubType);
4021 4 : if (iType >= 0 && iSubType >= 0)
4022 : {
4023 4 : oFieldDefn.SetSubType(OFSTNone);
4024 4 : oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
4025 4 : oFieldDefn.SetSubType(static_cast<OGRFieldSubType>(iSubType));
4026 4 : if (iType == OFTInteger)
4027 1 : oFieldDefn.SetWidth(0);
4028 : }
4029 : }
4030 : }
4031 3682 : if (bUnsetFieldWidth)
4032 : {
4033 6 : oFieldDefn.SetWidth(0);
4034 6 : oFieldDefn.SetPrecision(0);
4035 : }
4036 3682 : if (bForceNullable)
4037 4 : oFieldDefn.SetNullable(TRUE);
4038 3682 : if (bUnsetDefault)
4039 2 : oFieldDefn.SetDefault(nullptr);
4040 :
4041 3682 : const auto poDstDriver = poDstDS->GetDriver();
4042 : const char *pszCreationFieldDataTypes =
4043 : poDstDriver
4044 3682 : ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES)
4045 3682 : : nullptr;
4046 : const char *pszCreationFieldDataSubtypes =
4047 : poDstDriver
4048 3682 : ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES)
4049 3682 : : nullptr;
4050 7249 : if (pszCreationFieldDataTypes &&
4051 3567 : strstr(pszCreationFieldDataTypes,
4052 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == nullptr)
4053 : {
4054 30 : if (pszCreationFieldDataSubtypes &&
4055 58 : (oFieldDefn.GetType() == OFTIntegerList ||
4056 55 : oFieldDefn.GetType() == OFTInteger64List ||
4057 53 : oFieldDefn.GetType() == OFTRealList ||
4058 88 : oFieldDefn.GetType() == OFTStringList) &&
4059 25 : strstr(pszCreationFieldDataSubtypes, "JSON"))
4060 : {
4061 5 : if (!bQuiet)
4062 : {
4063 5 : CPLError(
4064 : CE_Warning, CPLE_AppDefined,
4065 : "The output driver does not seem to natively support %s "
4066 : "type for field %s. Converting it to String(JSON) instead. "
4067 : "-mapFieldType can be used to control field type "
4068 : "conversion.",
4069 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4070 : oFieldDefn.GetNameRef());
4071 : }
4072 5 : oFieldDefn.SetSubType(OFSTNone);
4073 5 : oFieldDefn.SetType(OFTString);
4074 5 : oFieldDefn.SetSubType(OFSTJSON);
4075 : }
4076 27 : else if (oFieldDefn.GetType() == OFTInteger64)
4077 : {
4078 1 : if (!bQuiet)
4079 : {
4080 1 : CPLError(
4081 : CE_Warning, CPLE_AppDefined,
4082 : "The output driver does not seem to natively support %s "
4083 : "type for field %s. Converting it to Real instead. "
4084 : "-mapFieldType can be used to control field type "
4085 : "conversion.",
4086 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4087 : oFieldDefn.GetNameRef());
4088 : }
4089 1 : oFieldDefn.SetType(OFTReal);
4090 : }
4091 30 : else if (oFieldDefn.GetType() == OFTDateTime && poDstDriver &&
4092 4 : EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile"))
4093 : {
4094 : // Just be silent. The shapefile driver will itself emit a
4095 : // warning mentioning it converts DateTime to String.
4096 : }
4097 25 : else if (!bQuiet)
4098 : {
4099 25 : CPLError(
4100 : CE_Warning, CPLE_AppDefined,
4101 : "The output driver does not natively support %s type for "
4102 : "field %s. Misconversion can happen. "
4103 : "-mapFieldType can be used to control field type conversion.",
4104 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4105 : oFieldDefn.GetNameRef());
4106 : }
4107 : }
4108 3650 : else if (!pszCreationFieldDataTypes)
4109 : {
4110 : // All drivers supporting OFTInteger64 should advertise it theoretically
4111 115 : if (oFieldDefn.GetType() == OFTInteger64)
4112 : {
4113 1 : if (!bQuiet)
4114 : {
4115 1 : CPLError(CE_Warning, CPLE_AppDefined,
4116 : "The output driver does not seem to natively support "
4117 : "%s type "
4118 : "for field %s. Converting it to Real instead. "
4119 : "-mapFieldType can be used to control field type "
4120 : "conversion.",
4121 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
4122 : oFieldDefn.GetNameRef());
4123 : }
4124 1 : oFieldDefn.SetType(OFTReal);
4125 : }
4126 : }
4127 3682 : }
4128 :
4129 : /************************************************************************/
4130 : /* GetArrowGeomFieldIndex() */
4131 : /************************************************************************/
4132 :
4133 24 : static int GetArrowGeomFieldIndex(const struct ArrowSchema *psLayerSchema,
4134 : const char *pszFieldName)
4135 : {
4136 24 : if (strcmp(psLayerSchema->format, "+s") == 0) // struct
4137 : {
4138 82 : for (int i = 0; i < psLayerSchema->n_children; ++i)
4139 : {
4140 82 : const auto psSchema = psLayerSchema->children[i];
4141 82 : if (strcmp(psSchema->format, "z") == 0) // binary
4142 : {
4143 24 : if (strcmp(psSchema->name, pszFieldName) == 0)
4144 : {
4145 22 : return i;
4146 : }
4147 : else
4148 : {
4149 : // Check if ARROW:extension:name = ogc.wkb or geoarrow.wkb
4150 2 : const char *pabyMetadata = psSchema->metadata;
4151 2 : if (pabyMetadata)
4152 : {
4153 : const auto oMetadata =
4154 2 : OGRParseArrowMetadata(pabyMetadata);
4155 2 : auto oIter = oMetadata.find(ARROW_EXTENSION_NAME_KEY);
4156 4 : if (oIter != oMetadata.end() &&
4157 2 : (oIter->second == EXTENSION_NAME_OGC_WKB ||
4158 0 : oIter->second == EXTENSION_NAME_GEOARROW_WKB))
4159 : {
4160 2 : return i;
4161 : }
4162 : }
4163 : }
4164 : }
4165 : }
4166 : }
4167 0 : return -1;
4168 : }
4169 :
4170 : /************************************************************************/
4171 : /* BuildGetArrowStreamOptions() */
4172 : /************************************************************************/
4173 :
4174 : static CPLStringList
4175 167 : BuildGetArrowStreamOptions(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,
4176 : const GDALVectorTranslateOptions *psOptions,
4177 : bool bPreserveFID)
4178 : {
4179 167 : CPLStringList aosOptionsGetArrowStream;
4180 167 : aosOptionsGetArrowStream.SetNameValue("SILENCE_GET_SCHEMA_ERROR", "YES");
4181 167 : aosOptionsGetArrowStream.SetNameValue("GEOMETRY_ENCODING", "WKB");
4182 167 : if (!bPreserveFID)
4183 137 : aosOptionsGetArrowStream.SetNameValue("INCLUDE_FID", "NO");
4184 167 : if (psOptions->nLimit >= 0)
4185 : {
4186 : aosOptionsGetArrowStream.SetNameValue(
4187 : "MAX_FEATURES_IN_BATCH",
4188 : CPLSPrintf(CPL_FRMT_GIB,
4189 2 : std::min<GIntBig>(psOptions->nLimit,
4190 2 : (psOptions->nGroupTransactions > 0
4191 4 : ? psOptions->nGroupTransactions
4192 2 : : 65536))));
4193 : }
4194 165 : else if (psOptions->nGroupTransactions > 0)
4195 : {
4196 : aosOptionsGetArrowStream.SetNameValue(
4197 : "MAX_FEATURES_IN_BATCH",
4198 165 : CPLSPrintf("%d", psOptions->nGroupTransactions));
4199 : }
4200 :
4201 167 : auto poSrcDS = poSrcLayer->GetDataset();
4202 167 : auto poDstDS = poDstLayer->GetDataset();
4203 167 : if (poSrcDS && poDstDS)
4204 : {
4205 163 : auto poSrcDriver = poSrcDS->GetDriver();
4206 163 : auto poDstDriver = poDstDS->GetDriver();
4207 :
4208 206 : const auto IsArrowNativeDriver = [](GDALDriver *poDriver)
4209 : {
4210 206 : return EQUAL(poDriver->GetDescription(), "ARROW") ||
4211 289 : EQUAL(poDriver->GetDescription(), "PARQUET") ||
4212 289 : EQUAL(poDriver->GetDescription(), "ADBC");
4213 : };
4214 :
4215 206 : if (poSrcDriver && poDstDriver && !IsArrowNativeDriver(poSrcDriver) &&
4216 43 : !IsArrowNativeDriver(poDstDriver))
4217 : {
4218 : // For non-Arrow-native drivers, request DateTime as string, to
4219 : // allow mix of timezones
4220 : aosOptionsGetArrowStream.SetNameValue(GAS_OPT_DATETIME_AS_STRING,
4221 40 : "YES");
4222 : }
4223 : }
4224 :
4225 167 : return aosOptionsGetArrowStream;
4226 : }
4227 :
4228 : /************************************************************************/
4229 : /* SetupTargetLayer::CanUseWriteArrowBatch() */
4230 : /************************************************************************/
4231 :
4232 1140 : bool SetupTargetLayer::CanUseWriteArrowBatch(
4233 : OGRLayer *poSrcLayer, OGRLayer *poDstLayer, bool bJustCreatedLayer,
4234 : const GDALVectorTranslateOptions *psOptions, bool bPreserveFID,
4235 : bool &bError, OGRArrowArrayStream &streamSrc)
4236 : {
4237 1140 : bError = false;
4238 :
4239 : // Check if we can use the Arrow interface to get and write features
4240 : // as it will be faster if the input driver has a fast
4241 : // implementation of GetArrowStream().
4242 : // We also can only do that only if using ogr2ogr without options that
4243 : // alter features.
4244 : // OGR2OGR_USE_ARROW_API config option is mostly for testing purposes
4245 : // or as a safety belt if things turned bad...
4246 1140 : bool bUseWriteArrowBatch = false;
4247 1140 : if (((poSrcLayer->TestCapability(OLCFastGetArrowStream) &&
4248 : // As we don't control the input array size when the input or output
4249 : // drivers are Arrow/Parquet (as they don't use the generic
4250 : // implementation), we can't guarantee that ROW_GROUP_SIZE/BATCH_SIZE
4251 : // layer creation options will be honored.
4252 175 : !psOptions->aosLCO.FetchNameValue("ROW_GROUP_SIZE") &&
4253 173 : !psOptions->aosLCO.FetchNameValue("BATCH_SIZE") &&
4254 170 : CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "YES"))) ||
4255 971 : CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "NO"))) &&
4256 180 : !psOptions->bUpsert && !psOptions->bSkipFailures &&
4257 348 : !psOptions->poClipSrc && !psOptions->poClipDst &&
4258 340 : psOptions->asGCPs.empty() && !psOptions->bWrapDateline &&
4259 170 : !m_bAddMissingFields && m_eGType == GEOMTYPE_UNCHANGED &&
4260 169 : psOptions->eGeomOp == GEOMOP_NONE &&
4261 169 : m_eGeomTypeConversion == GTC_DEFAULT && m_nCoordDim < 0 &&
4262 169 : !m_papszFieldTypesToString && !m_papszMapFieldType &&
4263 169 : !m_bUnsetFieldWidth && !m_bExplodeCollections && !m_pszZField &&
4264 168 : m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains &&
4265 168 : !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID &&
4266 168 : psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN &&
4267 2280 : !psOptions->bMakeValid && !psOptions->bSkipInvalidGeom)
4268 : {
4269 168 : if (psOptions->bTransform)
4270 : {
4271 : // To simplify implementation for now
4272 26 : if (poSrcLayer->GetLayerDefn()->GetGeomFieldCount() != 1 ||
4273 13 : poDstLayer->GetLayerDefn()->GetGeomFieldCount() != 1)
4274 : {
4275 1 : return false;
4276 : }
4277 13 : const auto poSrcSRS = m_poUserSourceSRS ? m_poUserSourceSRS
4278 12 : : poSrcLayer->GetLayerDefn()
4279 12 : ->GetGeomFieldDefn(0)
4280 12 : ->GetSpatialRef();
4281 13 : if (!OGRGeometryFactory::isTransformWithOptionsRegularTransform(
4282 : poSrcSRS, m_poOutputSRS, nullptr))
4283 : {
4284 1 : return false;
4285 : }
4286 : }
4287 :
4288 167 : if (m_bSelFieldsSet)
4289 : {
4290 2 : SetIgnoredFields(poSrcLayer);
4291 : }
4292 :
4293 : const CPLStringList aosGetArrowStreamOptions(BuildGetArrowStreamOptions(
4294 167 : poSrcLayer, poDstLayer, psOptions, bPreserveFID));
4295 167 : if (poSrcLayer->GetArrowStream(streamSrc.get(),
4296 167 : aosGetArrowStreamOptions.List()))
4297 : {
4298 : struct ArrowSchema schemaSrc;
4299 167 : if (streamSrc.get_schema(&schemaSrc) == 0)
4300 : {
4301 179 : if (psOptions->bTransform &&
4302 12 : GetArrowGeomFieldIndex(&schemaSrc,
4303 12 : poSrcLayer->GetGeometryColumn()) < 0)
4304 : {
4305 0 : schemaSrc.release(&schemaSrc);
4306 0 : streamSrc.clear();
4307 0 : return false;
4308 : }
4309 :
4310 167 : std::string osErrorMsg;
4311 167 : if (poDstLayer->IsArrowSchemaSupported(&schemaSrc, nullptr,
4312 167 : osErrorMsg))
4313 : {
4314 : const OGRFeatureDefn *poSrcFDefn =
4315 167 : poSrcLayer->GetLayerDefn();
4316 : const OGRFeatureDefn *poDstFDefn =
4317 167 : poDstLayer->GetLayerDefn();
4318 165 : if (bJustCreatedLayer && poDstFDefn &&
4319 497 : poDstFDefn->GetFieldCount() == 0 &&
4320 165 : poDstFDefn->GetGeomFieldCount() ==
4321 165 : poSrcFDefn->GetGeomFieldCount())
4322 : {
4323 : // Create output fields using CreateFieldFromArrowSchema()
4324 1273 : for (int i = 0; i < schemaSrc.n_children; ++i)
4325 : {
4326 1108 : const char *pszFieldName =
4327 1108 : schemaSrc.children[i]->name;
4328 :
4329 : const auto iSrcField =
4330 1108 : poSrcFDefn->GetFieldIndex(pszFieldName);
4331 1108 : if (iSrcField >= 0)
4332 : {
4333 : const auto poSrcFieldDefn =
4334 910 : poSrcFDefn->GetFieldDefn(iSrcField);
4335 : // Create field domain in output dataset if not already existing.
4336 : const std::string osDomainName(
4337 1820 : poSrcFieldDefn->GetDomainName());
4338 910 : if (!osDomainName.empty())
4339 : {
4340 33 : if (m_poDstDS->TestCapability(
4341 22 : ODsCAddFieldDomain) &&
4342 11 : m_poDstDS->GetFieldDomain(
4343 11 : osDomainName) == nullptr)
4344 : {
4345 : const auto poSrcDomain =
4346 22 : m_poSrcDS->GetFieldDomain(
4347 11 : osDomainName);
4348 11 : if (poSrcDomain)
4349 : {
4350 22 : std::string failureReason;
4351 11 : if (!m_poDstDS->AddFieldDomain(
4352 22 : std::unique_ptr<
4353 : OGRFieldDomain>(
4354 11 : poSrcDomain->Clone()),
4355 11 : failureReason))
4356 : {
4357 0 : CPLDebug("OGR2OGR",
4358 : "Cannot create domain "
4359 : "%s: %s",
4360 : osDomainName.c_str(),
4361 : failureReason.c_str());
4362 : }
4363 : }
4364 : else
4365 : {
4366 0 : CPLDebug("OGR2OGR",
4367 : "Cannot find domain %s in "
4368 : "source dataset",
4369 : osDomainName.c_str());
4370 : }
4371 : }
4372 : }
4373 : }
4374 :
4375 3324 : if (!EQUAL(pszFieldName, "OGC_FID") &&
4376 1108 : !EQUAL(pszFieldName, "wkb_geometry") &&
4377 1100 : !EQUAL(pszFieldName,
4378 1070 : poSrcLayer->GetFIDColumn()) &&
4379 1070 : poSrcFDefn->GetGeomFieldIndex(pszFieldName) <
4380 2216 : 0 &&
4381 919 : !poDstLayer->CreateFieldFromArrowSchema(
4382 919 : schemaSrc.children[i], nullptr))
4383 : {
4384 0 : CPLError(CE_Failure, CPLE_AppDefined,
4385 : "Cannot create field %s",
4386 : pszFieldName);
4387 0 : schemaSrc.release(&schemaSrc);
4388 0 : streamSrc.clear();
4389 0 : return false;
4390 : }
4391 : }
4392 165 : bUseWriteArrowBatch = true;
4393 : }
4394 2 : else if (!bJustCreatedLayer)
4395 : {
4396 : // If the layer already exist, get its schema, and
4397 : // check that it looks to be the same as the source
4398 : // one
4399 : struct ArrowArrayStream streamDst;
4400 2 : if (poDstLayer->GetArrowStream(
4401 2 : &streamDst, aosGetArrowStreamOptions.List()))
4402 : {
4403 : struct ArrowSchema schemaDst;
4404 2 : if (streamDst.get_schema(&streamDst, &schemaDst) ==
4405 : 0)
4406 : {
4407 2 : if (schemaDst.n_children ==
4408 2 : schemaSrc.n_children)
4409 : {
4410 2 : bUseWriteArrowBatch = true;
4411 : }
4412 2 : schemaDst.release(&schemaDst);
4413 : }
4414 2 : streamDst.release(&streamDst);
4415 : }
4416 : }
4417 167 : if (bUseWriteArrowBatch)
4418 : {
4419 167 : CPLDebug("OGR2OGR", "Using WriteArrowBatch()");
4420 : }
4421 : }
4422 : else
4423 : {
4424 0 : CPLDebug("OGR2OGR",
4425 : "Cannot use WriteArrowBatch() because "
4426 : "input layer schema is not supported by output "
4427 : "layer: %s",
4428 : osErrorMsg.c_str());
4429 : }
4430 167 : schemaSrc.release(&schemaSrc);
4431 : }
4432 167 : if (!bUseWriteArrowBatch)
4433 0 : streamSrc.clear();
4434 : }
4435 : }
4436 1139 : return bUseWriteArrowBatch;
4437 : }
4438 :
4439 : /************************************************************************/
4440 : /* SetupTargetLayer::SetIgnoredFields() */
4441 : /************************************************************************/
4442 :
4443 12 : void SetupTargetLayer::SetIgnoredFields(OGRLayer *poSrcLayer)
4444 : {
4445 12 : bool bUseIgnoredFields = true;
4446 24 : CPLStringList aosWHEREUsedFields;
4447 12 : const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
4448 :
4449 12 : if (m_pszWHERE)
4450 : {
4451 : /* We must not ignore fields used in the -where expression
4452 : * (#4015) */
4453 4 : OGRFeatureQuery oFeatureQuery;
4454 2 : if (oFeatureQuery.Compile(poSrcFDefn, m_pszWHERE, FALSE, nullptr) ==
4455 : OGRERR_NONE)
4456 : {
4457 0 : aosWHEREUsedFields = oFeatureQuery.GetUsedFields();
4458 : }
4459 : else
4460 : {
4461 2 : bUseIgnoredFields = false;
4462 : }
4463 : }
4464 :
4465 24 : CPLStringList aosIgnoredFields;
4466 40 : for (int iSrcField = 0;
4467 40 : bUseIgnoredFields && iSrcField < poSrcFDefn->GetFieldCount();
4468 : iSrcField++)
4469 : {
4470 : const char *pszFieldName =
4471 28 : poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();
4472 : bool bFieldRequested =
4473 28 : CSLFindString(m_papszSelFields, pszFieldName) >= 0;
4474 28 : bFieldRequested |= aosWHEREUsedFields.FindString(pszFieldName) >= 0;
4475 28 : bFieldRequested |=
4476 28 : (m_pszZField != nullptr && EQUAL(pszFieldName, m_pszZField));
4477 :
4478 : // If the source field is not requested, add it to the list of ignored
4479 : // fields.
4480 28 : if (!bFieldRequested)
4481 15 : aosIgnoredFields.push_back(pszFieldName);
4482 : }
4483 12 : if (bUseIgnoredFields)
4484 10 : poSrcLayer->SetIgnoredFields(
4485 10 : const_cast<const char **>(aosIgnoredFields.List()));
4486 12 : }
4487 :
4488 : /************************************************************************/
4489 : /* SetupTargetLayer::Setup() */
4490 : /************************************************************************/
4491 :
4492 : std::unique_ptr<TargetLayerInfo>
4493 1144 : SetupTargetLayer::Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
4494 : GDALVectorTranslateOptions *psOptions,
4495 : GIntBig &nTotalEventsDone)
4496 : {
4497 1144 : int eGType = m_eGType;
4498 1144 : bool bPreserveFID = m_bPreserveFID;
4499 1144 : bool bAppend = m_bAppend;
4500 :
4501 1144 : if (pszNewLayerName == nullptr)
4502 1106 : pszNewLayerName = poSrcLayer->GetName();
4503 :
4504 : /* -------------------------------------------------------------------- */
4505 : /* Get other info. */
4506 : /* -------------------------------------------------------------------- */
4507 1144 : const OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
4508 :
4509 : /* -------------------------------------------------------------------- */
4510 : /* Find requested geometry fields. */
4511 : /* -------------------------------------------------------------------- */
4512 2288 : std::vector<int> anRequestedGeomFields;
4513 1144 : const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
4514 1144 : if (m_bSelFieldsSet && !bAppend)
4515 : {
4516 44 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4517 : iField++)
4518 : {
4519 27 : int iSrcField = poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4520 27 : if (iSrcField >= 0)
4521 : {
4522 : /* do nothing */
4523 : }
4524 : else
4525 : {
4526 3 : iSrcField =
4527 3 : poSrcFDefn->GetGeomFieldIndex(m_papszSelFields[iField]);
4528 3 : if (iSrcField >= 0)
4529 : {
4530 3 : anRequestedGeomFields.push_back(iSrcField);
4531 : }
4532 : else
4533 : {
4534 0 : CPLError(CE_Failure, CPLE_AppDefined,
4535 : "Field '%s' not found in source layer.",
4536 0 : m_papszSelFields[iField]);
4537 0 : if (!psOptions->bSkipFailures)
4538 0 : return nullptr;
4539 : }
4540 : }
4541 : }
4542 :
4543 18 : if (anRequestedGeomFields.size() > 1 &&
4544 1 : !m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4545 : {
4546 0 : CPLError(CE_Failure, CPLE_AppDefined,
4547 : "Several geometry fields requested, but output "
4548 : "datasource does not support multiple geometry "
4549 : "fields.");
4550 0 : if (!psOptions->bSkipFailures)
4551 0 : return nullptr;
4552 : else
4553 0 : anRequestedGeomFields.resize(0);
4554 : }
4555 : }
4556 :
4557 1144 : const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
4558 1144 : if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
4559 : {
4560 996 : if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())
4561 994 : poOutputSRS = poSrcLayer->GetSpatialRef();
4562 2 : else if (anRequestedGeomFields.size() == 1)
4563 : {
4564 1 : int iSrcGeomField = anRequestedGeomFields[0];
4565 : poOutputSRS =
4566 1 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetSpatialRef();
4567 : }
4568 : }
4569 :
4570 1144 : int iSrcZField = -1;
4571 1144 : if (m_pszZField != nullptr)
4572 : {
4573 4 : iSrcZField = poSrcFDefn->GetFieldIndex(m_pszZField);
4574 4 : if (iSrcZField < 0)
4575 : {
4576 1 : CPLError(CE_Warning, CPLE_AppDefined,
4577 : "zfield '%s' does not exist in layer %s", m_pszZField,
4578 1 : poSrcLayer->GetName());
4579 : }
4580 : }
4581 :
4582 : /* -------------------------------------------------------------------- */
4583 : /* Find the layer. */
4584 : /* -------------------------------------------------------------------- */
4585 :
4586 : bool bErrorOccurred;
4587 : bool bOverwriteActuallyDone;
4588 : bool bAddOverwriteLCO;
4589 2288 : OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(
4590 1144 : m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,
4591 : &bOverwriteActuallyDone, &bAddOverwriteLCO);
4592 1144 : const bool bJustCreatedLayer = (poDstLayer == nullptr);
4593 1144 : if (bErrorOccurred)
4594 0 : return nullptr;
4595 :
4596 : /* -------------------------------------------------------------------- */
4597 : /* If the layer does not exist, then create it. */
4598 : /* -------------------------------------------------------------------- */
4599 1144 : if (poDstLayer == nullptr)
4600 : {
4601 1098 : if (!m_poDstDS->TestCapability(ODsCCreateLayer))
4602 : {
4603 0 : CPLError(
4604 : CE_Failure, CPLE_AppDefined,
4605 : "Layer '%s' does not already exist in the output dataset, and "
4606 : "cannot be created by the output driver.",
4607 : pszNewLayerName);
4608 4 : return nullptr;
4609 : }
4610 :
4611 1098 : bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);
4612 1098 : if (!bForceGType)
4613 : {
4614 1080 : if (anRequestedGeomFields.empty())
4615 : {
4616 1078 : eGType = poSrcFDefn->GetGeomType();
4617 : }
4618 2 : else if (anRequestedGeomFields.size() == 1)
4619 : {
4620 1 : int iSrcGeomField = anRequestedGeomFields[0];
4621 1 : eGType = poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetType();
4622 : }
4623 : else
4624 : {
4625 1 : eGType = wkbNone;
4626 : }
4627 :
4628 : bool bHasZ =
4629 1080 : CPL_TO_BOOL(wkbHasZ(static_cast<OGRwkbGeometryType>(eGType)));
4630 1080 : eGType = ConvertType(m_eGeomTypeConversion,
4631 : static_cast<OGRwkbGeometryType>(eGType));
4632 :
4633 1080 : if (m_bExplodeCollections)
4634 : {
4635 12 : const OGRwkbGeometryType eFGType = wkbFlatten(eGType);
4636 12 : if (eFGType == wkbMultiPoint)
4637 : {
4638 1 : eGType = wkbPoint;
4639 : }
4640 11 : else if (eFGType == wkbMultiLineString)
4641 : {
4642 0 : eGType = wkbLineString;
4643 : }
4644 11 : else if (eFGType == wkbMultiPolygon)
4645 : {
4646 0 : eGType = wkbPolygon;
4647 : }
4648 11 : else if (eFGType == wkbGeometryCollection ||
4649 11 : eFGType == wkbMultiCurve || eFGType == wkbMultiSurface)
4650 : {
4651 0 : eGType = wkbUnknown;
4652 : }
4653 : }
4654 :
4655 1080 : if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))
4656 114 : eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));
4657 : }
4658 :
4659 1098 : eGType = ForceCoordDimension(eGType, m_nCoordDim);
4660 :
4661 1098 : CPLErrorReset();
4662 :
4663 1098 : CPLStringList aosLCOTemp(CSLDuplicate(m_papszLCO));
4664 : const char *pszDestCreationOptions =
4665 1098 : m_poDstDS->GetDriver()->GetMetadataItem(
4666 1098 : GDAL_DS_LAYER_CREATIONOPTIONLIST);
4667 :
4668 1098 : int eGCreateLayerType = eGType;
4669 1111 : if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4670 13 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4671 : {
4672 12 : eGCreateLayerType = wkbNone;
4673 : }
4674 : // If the source layer has a single geometry column that is not nullable
4675 : // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it
4676 : // so as to be able to set the not null constraint (if the driver
4677 : // supports it) and that the output driver has no GEOMETRY_NULLABLE
4678 : // layer creation option. Same if the source geometry column has a non
4679 : // empty name that is not overridden, and that the output driver has no
4680 : // GEOMETRY_NAME layer creation option, but no LAUNDER option (if
4681 : // laundering is available, then we might want to launder the geometry
4682 : // column name as well)
4683 888 : else if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4684 886 : nSrcGeomFieldCount == 1 &&
4685 886 : m_poDstDS->TestCapability(
4686 3137 : ODsCCreateGeomFieldAfterCreateLayer) &&
4687 277 : ((!poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4688 2 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") ==
4689 2 : nullptr &&
4690 2 : (pszDestCreationOptions == nullptr ||
4691 2 : strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") !=
4692 0 : nullptr) &&
4693 0 : !m_bForceNullable) ||
4694 277 : (poSrcLayer->GetGeometryColumn() != nullptr &&
4695 277 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&
4696 277 : !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&
4697 48 : (pszDestCreationOptions == nullptr ||
4698 48 : strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==
4699 8 : nullptr ||
4700 8 : strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&
4701 48 : poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <
4702 : 0)))
4703 : {
4704 48 : anRequestedGeomFields.push_back(0);
4705 48 : eGCreateLayerType = wkbNone;
4706 : }
4707 1039 : else if (anRequestedGeomFields.size() == 1 &&
4708 1 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4709 : {
4710 0 : eGCreateLayerType = wkbNone;
4711 : }
4712 :
4713 1098 : OGRGeomCoordinatePrecision oCoordPrec;
4714 1098 : std::string osGeomFieldName;
4715 1098 : bool bGeomFieldNullable = true;
4716 :
4717 : {
4718 1098 : int iSrcGeomField = -1;
4719 1308 : if (anRequestedGeomFields.empty() &&
4720 210 : (nSrcGeomFieldCount == 1 ||
4721 210 : (!m_poDstDS->TestCapability(
4722 277 : ODsCCreateGeomFieldAfterCreateLayer) &&
4723 : nSrcGeomFieldCount > 1)))
4724 : {
4725 839 : iSrcGeomField = 0;
4726 : }
4727 259 : else if (anRequestedGeomFields.size() == 1)
4728 : {
4729 49 : iSrcGeomField = anRequestedGeomFields[0];
4730 : }
4731 :
4732 1098 : if (iSrcGeomField >= 0)
4733 : {
4734 : const auto poSrcGeomFieldDefn =
4735 888 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);
4736 888 : if (!psOptions->bUnsetCoordPrecision)
4737 : {
4738 887 : oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()
4739 1774 : .ConvertToOtherSRS(
4740 887 : poSrcGeomFieldDefn->GetSpatialRef(),
4741 887 : poOutputSRS);
4742 : }
4743 :
4744 : bGeomFieldNullable =
4745 888 : CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());
4746 :
4747 888 : const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();
4748 1123 : if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&
4749 235 : poSrcFDefn->GetFieldIndex(pszGFldName) < 0)
4750 : {
4751 234 : osGeomFieldName = pszGFldName;
4752 :
4753 : // Use source geometry field name as much as possible
4754 234 : if (eGType != wkbNone && pszDestCreationOptions &&
4755 234 : strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=
4756 468 : nullptr &&
4757 171 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==
4758 : nullptr)
4759 : {
4760 171 : aosLCOTemp.SetNameValue("GEOMETRY_NAME", pszGFldName);
4761 : }
4762 : }
4763 : }
4764 : }
4765 :
4766 : // If the source feature first geometry column is not nullable
4767 : // and that GEOMETRY_NULLABLE creation option is available, use it
4768 : // so as to be able to set the not null constraint (if the driver
4769 : // supports it)
4770 900 : if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4771 851 : nSrcGeomFieldCount >= 1 &&
4772 851 : !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4773 0 : pszDestCreationOptions != nullptr &&
4774 0 : strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") != nullptr &&
4775 1998 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") == nullptr &&
4776 0 : !m_bForceNullable)
4777 : {
4778 0 : bGeomFieldNullable = false;
4779 0 : aosLCOTemp.SetNameValue("GEOMETRY_NULLABLE", "NO");
4780 0 : CPLDebug("GDALVectorTranslate", "Using GEOMETRY_NULLABLE=NO");
4781 : }
4782 :
4783 1098 : if (psOptions->dfXYRes != OGRGeomCoordinatePrecision::UNKNOWN)
4784 : {
4785 7 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4786 8 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr &&
4787 1 : !OGRGeometryFactory::haveGEOS())
4788 : {
4789 0 : CPLError(CE_Warning, CPLE_AppDefined,
4790 : "-xyRes specified, but driver does not expose the "
4791 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, "
4792 : "and this build has no GEOS support");
4793 : }
4794 :
4795 7 : oCoordPrec.dfXYResolution = psOptions->dfXYRes;
4796 7 : if (!psOptions->osXYResUnit.empty())
4797 : {
4798 5 : if (!poOutputSRS)
4799 : {
4800 1 : CPLError(CE_Failure, CPLE_AppDefined,
4801 : "Unit suffix for -xyRes cannot be used with an "
4802 : "unknown destination SRS");
4803 1 : return nullptr;
4804 : }
4805 :
4806 4 : if (psOptions->osXYResUnit == "mm")
4807 : {
4808 1 : oCoordPrec.dfXYResolution *= 1e-3;
4809 : }
4810 3 : else if (psOptions->osXYResUnit == "deg")
4811 : {
4812 : double dfFactorDegToMeter =
4813 2 : poOutputSRS->GetSemiMajor(nullptr) * M_PI / 180;
4814 2 : oCoordPrec.dfXYResolution *= dfFactorDegToMeter;
4815 : }
4816 : else
4817 : {
4818 : // Checked at argument parsing time
4819 1 : CPLAssert(psOptions->osXYResUnit == "m");
4820 : }
4821 :
4822 4 : OGRGeomCoordinatePrecision tmp;
4823 4 : tmp.SetFromMeter(poOutputSRS, oCoordPrec.dfXYResolution, 0, 0);
4824 4 : oCoordPrec.dfXYResolution = tmp.dfXYResolution;
4825 : }
4826 : }
4827 :
4828 1097 : if (psOptions->dfZRes != OGRGeomCoordinatePrecision::UNKNOWN)
4829 : {
4830 4 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4831 4 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4832 : {
4833 0 : CPLError(CE_Warning, CPLE_AppDefined,
4834 : "-zRes specified, but driver does not expose the "
4835 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4836 : }
4837 :
4838 4 : oCoordPrec.dfZResolution = psOptions->dfZRes;
4839 4 : if (!psOptions->osZResUnit.empty())
4840 : {
4841 3 : if (!poOutputSRS)
4842 : {
4843 1 : CPLError(CE_Failure, CPLE_AppDefined,
4844 : "Unit suffix for -zRes cannot be used with an "
4845 : "unknown destination SRS");
4846 1 : return nullptr;
4847 : }
4848 :
4849 2 : if (psOptions->osZResUnit == "mm")
4850 : {
4851 1 : oCoordPrec.dfZResolution *= 1e-3;
4852 : }
4853 : else
4854 : {
4855 : // Checked at argument parsing time
4856 1 : CPLAssert(psOptions->osZResUnit == "m");
4857 : }
4858 :
4859 2 : OGRGeomCoordinatePrecision tmp;
4860 2 : tmp.SetFromMeter(poOutputSRS, 0, oCoordPrec.dfZResolution, 0);
4861 2 : oCoordPrec.dfZResolution = tmp.dfZResolution;
4862 : }
4863 : }
4864 :
4865 1096 : if (psOptions->dfMRes != OGRGeomCoordinatePrecision::UNKNOWN)
4866 : {
4867 3 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4868 3 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4869 : {
4870 0 : CPLError(CE_Warning, CPLE_AppDefined,
4871 : "-mRes specified, but driver does not expose the "
4872 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4873 : }
4874 :
4875 3 : oCoordPrec.dfMResolution = psOptions->dfMRes;
4876 : }
4877 :
4878 : // For JSONFG
4879 1096 : CSLConstList papszMeasures = poSrcLayer->GetMetadata("MEASURES");
4880 1096 : if (papszMeasures && pszDestCreationOptions)
4881 : {
4882 6 : for (const char *pszItem : {"UNIT", "DESCRIPTION"})
4883 : {
4884 : const char *pszValue =
4885 4 : CSLFetchNameValue(papszMeasures, pszItem);
4886 4 : if (pszValue)
4887 : {
4888 : const std::string osOptionName =
4889 12 : std::string("MEASURE_").append(pszItem);
4890 8 : if (strstr(pszDestCreationOptions, osOptionName.c_str()) &&
4891 4 : CSLFetchNameValue(m_papszLCO, osOptionName.c_str()) ==
4892 : nullptr)
4893 : {
4894 4 : aosLCOTemp.SetNameValue(osOptionName.c_str(), pszValue);
4895 : }
4896 : }
4897 : }
4898 : }
4899 :
4900 1096 : auto poSrcDriver = m_poSrcDS->GetDriver();
4901 :
4902 : // Force FID column as 64 bit if the source feature has a 64 bit FID,
4903 : // the target driver supports 64 bit FID and the user didn't set it
4904 : // manually.
4905 1096 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
4906 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&
4907 1 : pszDestCreationOptions &&
4908 1097 : strstr(pszDestCreationOptions, "FID64") != nullptr &&
4909 0 : CSLFetchNameValue(m_papszLCO, "FID64") == nullptr)
4910 : {
4911 0 : aosLCOTemp.SetNameValue("FID64", "YES");
4912 0 : CPLDebug("GDALVectorTranslate", "Using FID64=YES");
4913 : }
4914 :
4915 : // If output driver supports FID layer creation option, set it with
4916 : // the FID column name of the source layer
4917 1094 : if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&
4918 1093 : !EQUAL(poSrcLayer->GetFIDColumn(), "") &&
4919 71 : pszDestCreationOptions != nullptr &&
4920 71 : (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4921 2192 : strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4922 64 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4923 : {
4924 64 : aosLCOTemp.SetNameValue("FID", poSrcLayer->GetFIDColumn());
4925 64 : if (!psOptions->bExplodeCollections)
4926 : {
4927 63 : CPLDebug("GDALVectorTranslate",
4928 : "Using FID=%s and -preserve_fid",
4929 63 : poSrcLayer->GetFIDColumn());
4930 63 : bPreserveFID = true;
4931 : }
4932 : else
4933 : {
4934 1 : CPLDebug("GDALVectorTranslate",
4935 : "Using FID=%s and disable -preserve_fid because not "
4936 : "compatible with -explodecollection",
4937 1 : poSrcLayer->GetFIDColumn());
4938 1 : bPreserveFID = false;
4939 : }
4940 : }
4941 : // Detect scenario of converting from GPX to a format like GPKG
4942 : // Cf https://github.com/OSGeo/gdal/issues/9225
4943 1027 : else if (!bPreserveFID && !m_bUnsetFid && !bAppend && poSrcDriver &&
4944 870 : EQUAL(poSrcDriver->GetDescription(), "GPX") &&
4945 5 : pszDestCreationOptions &&
4946 5 : (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4947 2059 : strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4948 5 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4949 : {
4950 5 : CPLDebug("GDALVectorTranslate",
4951 : "Forcing -preserve_fid because source is GPX and layers "
4952 : "have FID cross references");
4953 5 : bPreserveFID = true;
4954 : }
4955 : // Detect scenario of converting GML2 with fid attribute to GPKG
4956 1116 : else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&
4957 89 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4958 : {
4959 87 : int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid");
4960 88 : if (nFieldIdx >= 0 && poSrcLayer->GetLayerDefn()
4961 1 : ->GetFieldDefn(nFieldIdx)
4962 1 : ->GetType() == OFTString)
4963 : {
4964 1 : CPLDebug("GDALVectorTranslate",
4965 : "Source layer has a non-string 'fid' column. Using "
4966 : "FID=gpkg_fid for GeoPackage");
4967 1 : aosLCOTemp.SetNameValue("FID", "gpkg_fid");
4968 : }
4969 : }
4970 :
4971 : // For a MapInfo -> MapInfo translation, preserve the layer bounds.
4972 1096 : if (m_poSrcDS->GetDriver() == m_poDstDS->GetDriver() &&
4973 442 : EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File") &&
4974 1541 : (m_poOutputSRS == nullptr || !m_bTransform) &&
4975 3 : CSLFetchNameValue(m_papszLCO, "BOUNDS") == nullptr)
4976 : {
4977 3 : if (const char *pszBounds = poSrcLayer->GetMetadataItem("BOUNDS"))
4978 : {
4979 3 : CPLDebug("GDALVectorTranslate", "Setting -lco BOUNDS=%s",
4980 : pszBounds);
4981 3 : aosLCOTemp.SetNameValue("BOUNDS", pszBounds);
4982 : }
4983 : }
4984 :
4985 : // If bAddOverwriteLCO is ON (set up when overwriting a CARTO layer),
4986 : // set OVERWRITE to YES so the new layer overwrites the old one
4987 1096 : if (bAddOverwriteLCO)
4988 : {
4989 0 : aosLCOTemp.SetNameValue("OVERWRITE", "ON");
4990 0 : CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON");
4991 : }
4992 :
4993 3287 : if (m_bNativeData &&
4994 1095 : poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") !=
4995 25 : nullptr &&
4996 25 : poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA") !=
4997 25 : nullptr &&
4998 25 : pszDestCreationOptions != nullptr &&
4999 2216 : strstr(pszDestCreationOptions, "NATIVE_DATA") != nullptr &&
5000 25 : strstr(pszDestCreationOptions, "NATIVE_MEDIA_TYPE") != nullptr)
5001 : {
5002 : aosLCOTemp.SetNameValue(
5003 : "NATIVE_DATA",
5004 25 : poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA"));
5005 : aosLCOTemp.SetNameValue("NATIVE_MEDIA_TYPE",
5006 : poSrcLayer->GetMetadataItem(
5007 25 : "NATIVE_MEDIA_TYPE", "NATIVE_DATA"));
5008 25 : CPLDebug("GDALVectorTranslate", "Transferring layer NATIVE_DATA");
5009 : }
5010 :
5011 : // For FileGeodatabase, automatically set
5012 : // CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES creation option if the source
5013 : // layer has a Shape_Area/Shape_Length field
5014 2171 : if (pszDestCreationOptions &&
5015 1075 : strstr(pszDestCreationOptions,
5016 2171 : "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&
5017 28 : CSLFetchNameValue(m_papszLCO,
5018 : "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)
5019 : {
5020 28 : const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
5021 : const int nIdxShapeArea =
5022 28 : poSrcLayerDefn->GetFieldIndex("Shape_Area");
5023 : const int nIdxShapeLength =
5024 28 : poSrcLayerDefn->GetFieldIndex("Shape_Length");
5025 30 : if ((nIdxShapeArea >= 0 &&
5026 2 : poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=
5027 2 : nullptr &&
5028 2 : EQUAL(
5029 : poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),
5030 2 : "FILEGEODATABASE_SHAPE_AREA") &&
5031 2 : (m_papszSelFields == nullptr ||
5032 31 : CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||
5033 1 : (nIdxShapeLength >= 0 &&
5034 1 : poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=
5035 1 : nullptr &&
5036 1 : EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)
5037 : ->GetDefault(),
5038 1 : "FILEGEODATABASE_SHAPE_LENGTH") &&
5039 1 : (m_papszSelFields == nullptr ||
5040 0 : CSLFindString(m_papszSelFields, "Shape_Length") >= 0)))
5041 : {
5042 : aosLCOTemp.SetNameValue("CREATE_SHAPE_AREA_AND_LENGTH_FIELDS",
5043 3 : "YES");
5044 3 : CPLDebug("GDALVectorTranslate",
5045 : "Setting CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES");
5046 : }
5047 : }
5048 :
5049 : // Use case of https://github.com/OSGeo/gdal/issues/11057#issuecomment-2495479779
5050 : // Conversion from GPKG to OCI.
5051 : // OCI distinguishes between TIMESTAMP and TIMESTAMP WITH TIME ZONE
5052 : // GeoPackage is supposed to have DateTime in UTC, so we set
5053 : // TIMESTAMP_WITH_TIME_ZONE=YES
5054 941 : if (poSrcDriver && pszDestCreationOptions &&
5055 920 : strstr(pszDestCreationOptions, "TIMESTAMP_WITH_TIME_ZONE") &&
5056 0 : CSLFetchNameValue(m_papszLCO, "TIMESTAMP_WITH_TIME_ZONE") ==
5057 2037 : nullptr &&
5058 0 : EQUAL(poSrcDriver->GetDescription(), "GPKG"))
5059 : {
5060 0 : aosLCOTemp.SetNameValue("TIMESTAMP_WITH_TIME_ZONE", "YES");
5061 0 : CPLDebug("GDALVectorTranslate",
5062 : "Setting TIMESTAMP_WITH_TIME_ZONE=YES");
5063 : }
5064 :
5065 : OGRGeomFieldDefn oGeomFieldDefn(
5066 : osGeomFieldName.c_str(),
5067 1096 : static_cast<OGRwkbGeometryType>(eGCreateLayerType));
5068 1096 : oGeomFieldDefn.SetSpatialRef(poOutputSRS);
5069 1096 : oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);
5070 1096 : oGeomFieldDefn.SetNullable(bGeomFieldNullable);
5071 1096 : poDstLayer = m_poDstDS->CreateLayer(
5072 : pszNewLayerName,
5073 : eGCreateLayerType == wkbNone ? nullptr : &oGeomFieldDefn,
5074 1096 : aosLCOTemp.List());
5075 :
5076 1096 : if (poDstLayer == nullptr)
5077 : {
5078 2 : return nullptr;
5079 : }
5080 :
5081 : // Cf https://github.com/OSGeo/gdal/issues/6859
5082 : // warn if the user requests -t_srs but the driver uses a different SRS.
5083 1130 : if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&
5084 : // MapInfo is somewhat lossy regarding SRS, so do not warn
5085 36 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))
5086 : {
5087 35 : auto poCreatedSRS = poDstLayer->GetSpatialRef();
5088 35 : if (poCreatedSRS != nullptr)
5089 : {
5090 21 : const char *const apszOptions[] = {
5091 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
5092 : "CRITERION=EQUIVALENT", nullptr};
5093 21 : if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))
5094 : {
5095 1 : const char *pszTargetSRSName = m_poOutputSRS->GetName();
5096 1 : const char *pszCreatedSRSName = poCreatedSRS->GetName();
5097 1 : CPLError(CE_Warning, CPLE_AppDefined,
5098 : "Target SRS %s not taken into account as target "
5099 : "driver likely implements on-the-fly reprojection "
5100 : "to %s",
5101 : pszTargetSRSName ? pszTargetSRSName : "",
5102 : pszCreatedSRSName ? pszCreatedSRSName : "");
5103 : }
5104 : }
5105 : }
5106 :
5107 1094 : if (m_bCopyMD)
5108 : {
5109 2180 : const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());
5110 1635 : for (const char *pszMD : aosDomains)
5111 : {
5112 545 : if (!EQUAL(pszMD, "IMAGE_STRUCTURE") &&
5113 545 : !EQUAL(pszMD, "SUBDATASETS"))
5114 : {
5115 545 : if (CSLConstList papszMD = poSrcLayer->GetMetadata(pszMD))
5116 : {
5117 : // MapInfo: Avoid overwriting the "BOUNDS" metadata on the output layer
5118 : // with the value from the source layer. If the value should be
5119 : // propagated, it will have been done via a layer creation option already.
5120 736 : if (pszMD[0] == '\0' &&
5121 241 : EQUAL(m_poDstDS->GetDriverName(), "MapInfo File"))
5122 : {
5123 : const char *pszBounds =
5124 6 : aosLCOTemp.FetchNameValue("BOUNDS");
5125 12 : CPLStringList aosTmpMD(CSLDuplicate(papszMD), true);
5126 6 : aosTmpMD.SetNameValue("BOUNDS", pszBounds);
5127 6 : poDstLayer->SetMetadata(aosTmpMD.List(), pszMD);
5128 : }
5129 : else
5130 : {
5131 489 : poDstLayer->SetMetadata(papszMD, pszMD);
5132 : }
5133 : }
5134 : }
5135 : }
5136 : }
5137 :
5138 1107 : if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
5139 13 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
5140 : {
5141 143 : for (int i = 0; i < nSrcGeomFieldCount; i++)
5142 : {
5143 131 : anRequestedGeomFields.push_back(i);
5144 : }
5145 : }
5146 :
5147 2224 : if (anRequestedGeomFields.size() > 1 ||
5148 1081 : (anRequestedGeomFields.size() == 1 &&
5149 49 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))
5150 : {
5151 242 : for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());
5152 : i++)
5153 : {
5154 181 : const int iSrcGeomField = anRequestedGeomFields[i];
5155 : OGRGeomFieldDefn oGFldDefn(
5156 362 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));
5157 181 : if (m_poOutputSRS != nullptr)
5158 : {
5159 13 : auto poOutputSRSClone = m_poOutputSRS->Clone();
5160 13 : oGFldDefn.SetSpatialRef(poOutputSRSClone);
5161 13 : poOutputSRSClone->Release();
5162 : }
5163 181 : if (bForceGType)
5164 : {
5165 1 : oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5166 : }
5167 : else
5168 : {
5169 180 : eGType = oGFldDefn.GetType();
5170 180 : eGType =
5171 180 : ConvertType(m_eGeomTypeConversion,
5172 : static_cast<OGRwkbGeometryType>(eGType));
5173 180 : eGType = ForceCoordDimension(eGType, m_nCoordDim);
5174 180 : oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
5175 : }
5176 181 : if (m_bForceNullable)
5177 2 : oGFldDefn.SetNullable(TRUE);
5178 181 : poDstLayer->CreateGeomField(&oGFldDefn);
5179 : }
5180 : }
5181 :
5182 1094 : bAppend = false;
5183 : }
5184 :
5185 : /* -------------------------------------------------------------------- */
5186 : /* Otherwise we will append to it, if append was requested. */
5187 : /* -------------------------------------------------------------------- */
5188 46 : else if (!bAppend && !m_bNewDataSource)
5189 : {
5190 0 : if (psOptions->bInvokedFromGdalVectorConvert)
5191 : {
5192 0 : CPLError(CE_Failure, CPLE_AppDefined,
5193 : "Layer %s already exists, and --append not specified. "
5194 : "Consider using --append, or --overwrite-layer.",
5195 : pszNewLayerName);
5196 : }
5197 : else
5198 : {
5199 0 : CPLError(CE_Failure, CPLE_AppDefined,
5200 : "Layer %s already exists, and -append not specified.\n"
5201 : " Consider using -append, or -overwrite.",
5202 : pszNewLayerName);
5203 : }
5204 0 : return nullptr;
5205 : }
5206 : else
5207 : {
5208 46 : if (CSLCount(m_papszLCO) > 0)
5209 : {
5210 0 : CPLError(
5211 : CE_Warning, CPLE_AppDefined,
5212 : "Layer creation options ignored since an existing layer is\n"
5213 : " being appended to.");
5214 : }
5215 : }
5216 :
5217 : /* -------------------------------------------------------------------- */
5218 : /* Process Layer style table */
5219 : /* -------------------------------------------------------------------- */
5220 :
5221 1140 : poDstLayer->SetStyleTable(poSrcLayer->GetStyleTable());
5222 : /* -------------------------------------------------------------------- */
5223 : /* Add fields. Default to copy all field. */
5224 : /* If only a subset of all fields requested, then output only */
5225 : /* the selected fields, and in the order that they were */
5226 : /* selected. */
5227 : /* -------------------------------------------------------------------- */
5228 1140 : const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
5229 1140 : int iSrcFIDField = -1;
5230 :
5231 : // Initialize the index-to-index map to -1's
5232 2280 : std::vector<int> anMap(nSrcFieldCount, -1);
5233 :
5234 2280 : std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;
5235 :
5236 : /* Determine if NUMERIC field width narrowing is allowed */
5237 1140 : auto poSrcDriver = m_poSrcDS->GetDriver();
5238 : const char *pszSrcWidthIncludesDecimalSeparator{
5239 2124 : poSrcDriver ? poSrcDriver->GetMetadataItem(
5240 984 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")
5241 1140 : : nullptr};
5242 1140 : const bool bSrcWidthIncludesDecimalSeparator{
5243 1442 : pszSrcWidthIncludesDecimalSeparator &&
5244 302 : EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};
5245 : const char *pszDstWidthIncludesDecimalSeparator{
5246 1140 : m_poDstDS->GetDriver()->GetMetadataItem(
5247 1140 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
5248 1140 : const bool bDstWidthIncludesDecimalSeparator{
5249 1348 : pszDstWidthIncludesDecimalSeparator &&
5250 208 : EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};
5251 : const char *pszSrcWidthIncludesMinusSign{
5252 2124 : poSrcDriver ? poSrcDriver->GetMetadataItem(
5253 984 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")
5254 1140 : : nullptr};
5255 1140 : const bool bSrcWidthIncludesMinusSign{
5256 1442 : pszSrcWidthIncludesMinusSign &&
5257 302 : EQUAL(pszSrcWidthIncludesMinusSign, "YES")};
5258 : const char *pszDstWidthIncludesMinusSign{
5259 1140 : m_poDstDS->GetDriver()->GetMetadataItem(
5260 1140 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
5261 1140 : const bool bDstWidthIncludesMinusSign{
5262 1348 : pszDstWidthIncludesMinusSign &&
5263 208 : EQUAL(pszDstWidthIncludesMinusSign, "YES")};
5264 :
5265 : // Calculate width delta
5266 1140 : int iChangeWidthBy{0};
5267 :
5268 1140 : if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)
5269 : {
5270 175 : iChangeWidthBy--;
5271 : }
5272 965 : else if (!bSrcWidthIncludesDecimalSeparator &&
5273 : bDstWidthIncludesDecimalSeparator)
5274 : {
5275 81 : iChangeWidthBy++;
5276 : }
5277 :
5278 : // We cannot assume there is no minus sign, we can only inflate here
5279 1140 : if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)
5280 : {
5281 81 : iChangeWidthBy++;
5282 : }
5283 :
5284 1140 : bool bError = false;
5285 2280 : OGRArrowArrayStream streamSrc;
5286 :
5287 : const bool bUseWriteArrowBatch =
5288 2280 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "OCI") &&
5289 1140 : CanUseWriteArrowBatch(poSrcLayer, poDstLayer, bJustCreatedLayer,
5290 1140 : psOptions, bPreserveFID, bError, streamSrc);
5291 1140 : if (bError)
5292 0 : return nullptr;
5293 :
5294 : /* Caution : at the time of writing, the MapInfo driver */
5295 : /* returns NULL until a field has been added */
5296 1140 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
5297 :
5298 1140 : if (bUseWriteArrowBatch)
5299 : {
5300 : // Fields created above
5301 : }
5302 973 : else if (m_papszFieldMap && bAppend)
5303 : {
5304 2 : bool bIdentity = false;
5305 :
5306 2 : if (EQUAL(m_papszFieldMap[0], "identity"))
5307 1 : bIdentity = true;
5308 1 : else if (CSLCount(m_papszFieldMap) != nSrcFieldCount)
5309 : {
5310 0 : CPLError(
5311 : CE_Failure, CPLE_AppDefined,
5312 : "Field map should contain the value 'identity' or "
5313 : "the same number of integer values as the source field count.");
5314 0 : return nullptr;
5315 : }
5316 :
5317 32 : for (int iField = 0; iField < nSrcFieldCount; iField++)
5318 : {
5319 30 : anMap[iField] = bIdentity ? iField : atoi(m_papszFieldMap[iField]);
5320 30 : if (anMap[iField] >= poDstFDefn->GetFieldCount())
5321 : {
5322 0 : CPLError(CE_Failure, CPLE_AppDefined,
5323 0 : "Invalid destination field index %d.", anMap[iField]);
5324 0 : return nullptr;
5325 : }
5326 2 : }
5327 : }
5328 971 : else if (m_bSelFieldsSet && !bAppend)
5329 : {
5330 15 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5331 40 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5332 : iField++)
5333 : {
5334 : const int iSrcField =
5335 25 : poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5336 25 : if (iSrcField >= 0)
5337 : {
5338 : const OGRFieldDefn *poSrcFieldDefn =
5339 22 : poSrcFDefn->GetFieldDefn(iSrcField);
5340 44 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5341 :
5342 22 : DoFieldTypeConversion(
5343 : m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5344 22 : m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5345 22 : m_bForceNullable, m_bUnsetDefault);
5346 :
5347 22 : if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5348 0 : oFieldDefn.GetWidth() != 0)
5349 : {
5350 0 : oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5351 : }
5352 :
5353 : /* The field may have been already created at layer creation */
5354 : const int iDstField =
5355 : poDstFDefn
5356 22 : ? poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef())
5357 22 : : -1;
5358 22 : if (iDstField >= 0)
5359 : {
5360 0 : anMap[iSrcField] = iDstField;
5361 : }
5362 22 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5363 : {
5364 : /* now that we've created a field, GetLayerDefn() won't
5365 : * return NULL */
5366 22 : if (poDstFDefn == nullptr)
5367 0 : poDstFDefn = poDstLayer->GetLayerDefn();
5368 :
5369 : /* Sanity check : if it fails, the driver is buggy */
5370 44 : if (poDstFDefn != nullptr &&
5371 22 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5372 : {
5373 0 : CPLError(CE_Warning, CPLE_AppDefined,
5374 : "The output driver has claimed to have added "
5375 : "the %s field, but it did not!",
5376 : oFieldDefn.GetNameRef());
5377 : }
5378 : else
5379 : {
5380 22 : anMap[iSrcField] = nDstFieldCount;
5381 22 : nDstFieldCount++;
5382 : }
5383 : }
5384 : }
5385 : }
5386 :
5387 : /* --------------------------------------------------------------------
5388 : */
5389 : /* Use SetIgnoredFields() on source layer if available */
5390 : /* --------------------------------------------------------------------
5391 : */
5392 15 : if (m_bSelFieldsSet && poSrcLayer->TestCapability(OLCIgnoreFields))
5393 : {
5394 10 : SetIgnoredFields(poSrcLayer);
5395 15 : }
5396 : }
5397 956 : else if (!bAppend || m_bAddMissingFields)
5398 : {
5399 922 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5400 :
5401 : const bool caseInsensitive =
5402 922 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");
5403 14542 : const auto formatName = [caseInsensitive](const char *name)
5404 : {
5405 14542 : if (caseInsensitive)
5406 : {
5407 28380 : return CPLString(name).toupper();
5408 : }
5409 : else
5410 : {
5411 352 : return CPLString(name);
5412 : }
5413 922 : };
5414 :
5415 : /* Save the map of existing fields, before creating new ones */
5416 : /* This helps when converting a source layer that has duplicated field
5417 : * names */
5418 : /* which is a bad idea */
5419 1844 : std::map<CPLString, int> oMapPreExistingFields;
5420 1844 : std::unordered_set<std::string> oSetDstFieldNames;
5421 1080 : for (int iField = 0; iField < nDstFieldCount; iField++)
5422 : {
5423 : const char *pszFieldName =
5424 158 : poDstFDefn->GetFieldDefn(iField)->GetNameRef();
5425 316 : CPLString osUpperFieldName(formatName(pszFieldName));
5426 158 : oSetDstFieldNames.insert(osUpperFieldName);
5427 158 : if (oMapPreExistingFields.find(osUpperFieldName) ==
5428 316 : oMapPreExistingFields.end())
5429 158 : oMapPreExistingFields[osUpperFieldName] = iField;
5430 : /*else
5431 : CPLError(CE_Warning, CPLE_AppDefined,
5432 : "The target layer has already a duplicated field name
5433 : '%s' before " "adding the fields of the source layer",
5434 : pszFieldName); */
5435 : }
5436 :
5437 922 : const char *pszFIDColumn = poDstLayer->GetFIDColumn();
5438 :
5439 1844 : std::vector<int> anSrcFieldIndices;
5440 922 : if (m_bSelFieldsSet)
5441 : {
5442 2 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5443 : iField++)
5444 : {
5445 : const int iSrcField =
5446 1 : poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5447 1 : if (iSrcField >= 0)
5448 : {
5449 1 : anSrcFieldIndices.push_back(iSrcField);
5450 : }
5451 : }
5452 : }
5453 : else
5454 : {
5455 4581 : for (int iField = 0; iField < nSrcFieldCount; iField++)
5456 : {
5457 3660 : anSrcFieldIndices.push_back(iField);
5458 : }
5459 : }
5460 :
5461 1844 : std::unordered_set<std::string> oSetSrcFieldNames;
5462 4584 : for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)
5463 : {
5464 : oSetSrcFieldNames.insert(
5465 3662 : formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));
5466 : }
5467 :
5468 : // For each source field name, memorize the last number suffix to have
5469 : // unique field names in the target. Let's imagine we have a source
5470 : // layer with the field name foo repeated twice After dealing the first
5471 : // field, oMapFieldNameToLastSuffix["foo"] will be 1, so when starting a
5472 : // unique name for the second field, we'll be able to start at 2. This
5473 : // avoids quadratic complexity if a big number of source field names are
5474 : // identical. Like in
5475 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37768
5476 1844 : std::map<std::string, int> oMapFieldNameToLastSuffix;
5477 :
5478 4583 : for (size_t i = 0; i < anSrcFieldIndices.size(); i++)
5479 : {
5480 3661 : const int iField = anSrcFieldIndices[i];
5481 : const OGRFieldDefn *poSrcFieldDefn =
5482 3661 : poSrcFDefn->GetFieldDefn(iField);
5483 3661 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5484 :
5485 : // Avoid creating a field with the same name as the FID column
5486 7323 : if (pszFIDColumn != nullptr &&
5487 3662 : EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&
5488 1 : (oFieldDefn.GetType() == OFTInteger ||
5489 0 : oFieldDefn.GetType() == OFTInteger64))
5490 : {
5491 1 : iSrcFIDField = iField;
5492 1 : continue;
5493 : }
5494 :
5495 3660 : DoFieldTypeConversion(
5496 : m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5497 3660 : m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5498 3660 : m_bForceNullable, m_bUnsetDefault);
5499 :
5500 3860 : if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5501 200 : oFieldDefn.GetWidth() != 0)
5502 : {
5503 148 : oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5504 : }
5505 :
5506 : /* The field may have been already created at layer creation */
5507 : {
5508 : const auto oIter = oMapPreExistingFields.find(
5509 3660 : formatName(oFieldDefn.GetNameRef()));
5510 3660 : if (oIter != oMapPreExistingFields.end())
5511 : {
5512 120 : anMap[iField] = oIter->second;
5513 120 : continue;
5514 : }
5515 : }
5516 :
5517 3540 : bool bHasRenamed = false;
5518 : /* In case the field name already exists in the target layer, */
5519 : /* build a unique field name */
5520 3540 : if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=
5521 7080 : oSetDstFieldNames.end())
5522 : {
5523 : const CPLString osTmpNameRaddixUC(
5524 4 : formatName(oFieldDefn.GetNameRef()));
5525 2 : int nTry = 1;
5526 : const auto oIter =
5527 2 : oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);
5528 2 : if (oIter != oMapFieldNameToLastSuffix.end())
5529 1 : nTry = oIter->second;
5530 2 : CPLString osTmpNameUC = osTmpNameRaddixUC;
5531 2 : osTmpNameUC.reserve(osTmpNameUC.size() + 10);
5532 : while (true)
5533 : {
5534 3 : ++nTry;
5535 : char szTry[32];
5536 3 : snprintf(szTry, sizeof(szTry), "%d", nTry);
5537 : osTmpNameUC.replace(osTmpNameRaddixUC.size(),
5538 3 : std::string::npos, szTry);
5539 :
5540 : /* Check that the proposed name doesn't exist either in the
5541 : * already */
5542 : /* created fields or in the source fields */
5543 3 : if (oSetDstFieldNames.find(osTmpNameUC) ==
5544 9 : oSetDstFieldNames.end() &&
5545 3 : oSetSrcFieldNames.find(osTmpNameUC) ==
5546 6 : oSetSrcFieldNames.end())
5547 : {
5548 2 : bHasRenamed = true;
5549 2 : oFieldDefn.SetName(
5550 4 : (CPLString(oFieldDefn.GetNameRef()) + szTry)
5551 : .c_str());
5552 2 : oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;
5553 2 : break;
5554 : }
5555 1 : }
5556 : }
5557 :
5558 : // Create field domain in output dataset if not already existing.
5559 7080 : const std::string osDomainName(oFieldDefn.GetDomainName());
5560 3540 : if (!osDomainName.empty())
5561 : {
5562 26 : if (m_poDstDS->TestCapability(ODsCAddFieldDomain) &&
5563 13 : m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5564 : {
5565 : const auto poSrcDomain =
5566 13 : m_poSrcDS->GetFieldDomain(osDomainName);
5567 13 : if (poSrcDomain)
5568 : {
5569 22 : std::string failureReason;
5570 11 : if (!m_poDstDS->AddFieldDomain(
5571 22 : std::unique_ptr<OGRFieldDomain>(
5572 11 : poSrcDomain->Clone()),
5573 11 : failureReason))
5574 : {
5575 0 : oFieldDefn.SetDomainName(std::string());
5576 0 : CPLDebug("OGR2OGR", "Cannot create domain %s: %s",
5577 : osDomainName.c_str(),
5578 : failureReason.c_str());
5579 : }
5580 : }
5581 : else
5582 : {
5583 2 : CPLDebug("OGR2OGR",
5584 : "Cannot find domain %s in source dataset",
5585 : osDomainName.c_str());
5586 : }
5587 : }
5588 13 : if (m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5589 : {
5590 2 : oFieldDefn.SetDomainName(std::string());
5591 : }
5592 : }
5593 :
5594 3540 : if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5595 : {
5596 : /* now that we've created a field, GetLayerDefn() won't return
5597 : * NULL */
5598 3520 : if (poDstFDefn == nullptr)
5599 0 : poDstFDefn = poDstLayer->GetLayerDefn();
5600 :
5601 : /* Sanity check : if it fails, the driver is buggy */
5602 7040 : if (poDstFDefn != nullptr &&
5603 3520 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5604 : {
5605 0 : CPLError(CE_Warning, CPLE_AppDefined,
5606 : "The output driver has claimed to have added the "
5607 : "%s field, but it did not!",
5608 : oFieldDefn.GetNameRef());
5609 : }
5610 : else
5611 : {
5612 3520 : if (poDstFDefn != nullptr)
5613 : {
5614 : const char *pszNewFieldName =
5615 3520 : poDstFDefn->GetFieldDefn(nDstFieldCount)
5616 3520 : ->GetNameRef();
5617 3520 : if (bHasRenamed)
5618 : {
5619 2 : CPLError(CE_Warning, CPLE_AppDefined,
5620 : "Field '%s' already exists. Renaming it "
5621 : "as '%s'",
5622 : poSrcFieldDefn->GetNameRef(),
5623 : pszNewFieldName);
5624 : }
5625 3520 : oSetDstFieldNames.insert(formatName(pszNewFieldName));
5626 : }
5627 :
5628 3520 : anMap[iField] = nDstFieldCount;
5629 3520 : nDstFieldCount++;
5630 : }
5631 : }
5632 :
5633 3540 : if (m_bResolveDomains && !osDomainName.empty())
5634 : {
5635 : const auto poSrcDomain =
5636 3 : m_poSrcDS->GetFieldDomain(osDomainName);
5637 3 : if (poSrcDomain && poSrcDomain->GetDomainType() == OFDT_CODED)
5638 : {
5639 : OGRFieldDefn oResolvedField(
5640 : CPLSPrintf("%s_resolved", oFieldDefn.GetNameRef()),
5641 2 : OFTString);
5642 1 : if (poDstLayer->CreateField(&oResolvedField) == OGRERR_NONE)
5643 : {
5644 : TargetLayerInfo::ResolvedInfo resolvedInfo;
5645 1 : resolvedInfo.nSrcField = iField;
5646 1 : resolvedInfo.poDomain = poSrcDomain;
5647 1 : oMapResolved[nDstFieldCount] = resolvedInfo;
5648 1 : nDstFieldCount++;
5649 : }
5650 : }
5651 : }
5652 922 : }
5653 : }
5654 : else
5655 : {
5656 : /* For an existing layer, build the map by fetching the index in the
5657 : * destination */
5658 : /* layer for each source field */
5659 34 : if (poDstFDefn == nullptr)
5660 : {
5661 0 : CPLError(CE_Failure, CPLE_AppDefined, "poDstFDefn == NULL.");
5662 0 : return nullptr;
5663 : }
5664 :
5665 114 : for (int iField = 0; iField < nSrcFieldCount; iField++)
5666 : {
5667 : const OGRFieldDefn *poSrcFieldDefn =
5668 80 : poSrcFDefn->GetFieldDefn(iField);
5669 80 : const int iDstField = poDstLayer->FindFieldIndex(
5670 80 : poSrcFieldDefn->GetNameRef(), m_bExactFieldNameMatch);
5671 80 : if (iDstField >= 0)
5672 76 : anMap[iField] = iDstField;
5673 : else
5674 : {
5675 4 : if (m_bExactFieldNameMatch)
5676 : {
5677 4 : const int iDstFieldCandidate = poDstLayer->FindFieldIndex(
5678 4 : poSrcFieldDefn->GetNameRef(), false);
5679 4 : if (iDstFieldCandidate >= 0)
5680 : {
5681 1 : CPLError(CE_Warning, CPLE_AppDefined,
5682 : "Source field '%s' could have been identified "
5683 : "with existing field '%s' of destination "
5684 : "layer '%s' if the -relaxedFieldNameMatch "
5685 : "option had been specified.",
5686 : poSrcFieldDefn->GetNameRef(),
5687 1 : poDstLayer->GetLayerDefn()
5688 1 : ->GetFieldDefn(iDstFieldCandidate)
5689 : ->GetNameRef(),
5690 1 : poDstLayer->GetName());
5691 : }
5692 : }
5693 :
5694 4 : CPLDebug(
5695 : "GDALVectorTranslate",
5696 : "Skipping field '%s' not found in destination layer '%s'.",
5697 4 : poSrcFieldDefn->GetNameRef(), poDstLayer->GetName());
5698 : }
5699 : }
5700 : }
5701 :
5702 16 : if (bOverwriteActuallyDone && !bAddOverwriteLCO &&
5703 16 : EQUAL(m_poDstDS->GetDriver()->GetDescription(), "PostgreSQL") &&
5704 1162 : !psOptions->nLayerTransaction && psOptions->nGroupTransactions > 0 &&
5705 6 : CPLTestBool(CPLGetConfigOption("PG_COMMIT_WHEN_OVERWRITING", "YES")))
5706 : {
5707 6 : CPLDebug("GDALVectorTranslate",
5708 : "Forcing transaction commit as table overwriting occurred");
5709 : // Commit when overwriting as this consumes a lot of PG resources
5710 : // and could result in """out of shared memory.
5711 : // You might need to increase max_locks_per_transaction."""" errors
5712 12 : if (m_poDstDS->CommitTransaction() == OGRERR_FAILURE ||
5713 6 : m_poDstDS->StartTransaction(psOptions->bForceTransaction) ==
5714 : OGRERR_FAILURE)
5715 : {
5716 0 : return nullptr;
5717 : }
5718 6 : nTotalEventsDone = 0;
5719 : }
5720 :
5721 2280 : auto psInfo = std::make_unique<TargetLayerInfo>();
5722 1140 : psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;
5723 1140 : psInfo->m_nFeaturesRead = 0;
5724 1140 : psInfo->m_bPerFeatureCT = false;
5725 1140 : psInfo->m_poSrcLayer = poSrcLayer;
5726 1140 : psInfo->m_poDstLayer = poDstLayer;
5727 1140 : psInfo->m_aoReprojectionInfo.resize(
5728 1140 : poDstLayer->GetLayerDefn()->GetGeomFieldCount());
5729 1140 : psInfo->m_anMap = std::move(anMap);
5730 1140 : psInfo->m_iSrcZField = iSrcZField;
5731 1140 : psInfo->m_iSrcFIDField = iSrcFIDField;
5732 1140 : if (anRequestedGeomFields.size() == 1)
5733 49 : psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];
5734 : else
5735 1091 : psInfo->m_iRequestedSrcGeomField = -1;
5736 1140 : psInfo->m_bPreserveFID = bPreserveFID;
5737 1140 : psInfo->m_pszCTPipeline = m_pszCTPipeline;
5738 1140 : psInfo->m_aosCTOptions = m_aosCTOptions;
5739 1140 : psInfo->m_oMapResolved = std::move(oMapResolved);
5740 1141 : for (const auto &kv : psInfo->m_oMapResolved)
5741 : {
5742 1 : const auto poDomain = kv.second.poDomain;
5743 : const auto poCodedDomain =
5744 1 : cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);
5745 1 : const auto enumeration = poCodedDomain->GetEnumeration();
5746 2 : std::map<std::string, std::string> oMapCodeValue;
5747 4 : for (int i = 0; enumeration[i].pszCode != nullptr; ++i)
5748 : {
5749 6 : oMapCodeValue[enumeration[i].pszCode] =
5750 6 : enumeration[i].pszValue ? enumeration[i].pszValue : "";
5751 : }
5752 1 : psInfo->m_oMapDomainToKV[poDomain] = std::move(oMapCodeValue);
5753 : }
5754 :
5755 : // Detect if we can directly pass the source feature to the CreateFeature()
5756 : // method of the target layer, without doing any copying of field content.
5757 1140 : psInfo->m_bCanAvoidSetFrom = false;
5758 1140 : if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)
5759 : {
5760 1125 : psInfo->m_bCanAvoidSetFrom = true;
5761 1125 : const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5762 1125 : if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||
5763 : nSrcGeomFieldCount != nDstGeomFieldCount)
5764 : {
5765 165 : psInfo->m_bCanAvoidSetFrom = false;
5766 : }
5767 : else
5768 : {
5769 4264 : for (int i = 0; i < nSrcFieldCount; ++i)
5770 : {
5771 3346 : auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);
5772 3346 : auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);
5773 6682 : if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||
5774 3336 : psInfo->m_anMap[i] != i)
5775 : {
5776 42 : psInfo->m_bCanAvoidSetFrom = false;
5777 42 : break;
5778 : }
5779 : }
5780 960 : if (!psInfo->m_bCanAvoidSetFrom && nSrcGeomFieldCount > 1)
5781 : {
5782 4 : for (int i = 0; i < nSrcGeomFieldCount; ++i)
5783 : {
5784 3 : auto poSrcGeomFieldDefn = poSrcFDefn->GetGeomFieldDefn(i);
5785 3 : auto poDstGeomFieldDefn = poDstFDefn->GetGeomFieldDefn(i);
5786 3 : if (!EQUAL(poSrcGeomFieldDefn->GetNameRef(),
5787 : poDstGeomFieldDefn->GetNameRef()))
5788 : {
5789 1 : psInfo->m_bCanAvoidSetFrom = false;
5790 1 : break;
5791 : }
5792 : }
5793 : }
5794 : }
5795 : }
5796 :
5797 2280 : psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()
5798 1140 : ? nullptr
5799 4 : : psOptions->osSpatSRSDef.c_str();
5800 1140 : psInfo->m_hSpatialFilter =
5801 1140 : OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());
5802 1140 : psInfo->m_pszGeomField =
5803 1140 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;
5804 :
5805 1140 : if (psOptions->nTZOffsetInSec != TZ_OFFSET_INVALID && poDstFDefn)
5806 : {
5807 15 : for (int i = 0; i < poDstFDefn->GetFieldCount(); ++i)
5808 : {
5809 10 : if (poDstFDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
5810 : {
5811 5 : psInfo->m_anDateTimeFieldIdx.push_back(i);
5812 : }
5813 : }
5814 : }
5815 :
5816 1140 : psInfo->m_bSupportCurves =
5817 1140 : CPL_TO_BOOL(poDstLayer->TestCapability(OLCCurveGeometries));
5818 :
5819 1140 : psInfo->m_sArrowArrayStream = std::move(streamSrc);
5820 :
5821 1140 : return psInfo;
5822 : }
5823 :
5824 : /************************************************************************/
5825 : /* SetupCT() */
5826 : /************************************************************************/
5827 :
5828 : static bool
5829 912 : SetupCT(TargetLayerInfo *psInfo, OGRLayer *poSrcLayer, bool bTransform,
5830 : bool bWrapDateline, const CPLString &osDateLineOffset,
5831 : const OGRSpatialReference *poUserSourceSRS, OGRFeature *poFeature,
5832 : const OGRSpatialReference *poOutputSRS,
5833 : OGRCoordinateTransformation *poGCPCoordTrans, bool bVerboseError)
5834 : {
5835 912 : OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5836 : const int nDstGeomFieldCount =
5837 912 : poDstLayer->GetLayerDefn()->GetGeomFieldCount();
5838 1763 : for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
5839 : {
5840 : /* --------------------------------------------------------------------
5841 : */
5842 : /* Setup coordinate transformation if we need it. */
5843 : /* --------------------------------------------------------------------
5844 : */
5845 852 : const OGRSpatialReference *poSourceSRS = nullptr;
5846 852 : OGRCoordinateTransformation *poCT = nullptr;
5847 852 : char **papszTransformOptions = nullptr;
5848 :
5849 : int iSrcGeomField;
5850 : auto poDstGeomFieldDefn =
5851 852 : poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
5852 852 : if (psInfo->m_iRequestedSrcGeomField >= 0)
5853 : {
5854 38 : iSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5855 : }
5856 : else
5857 : {
5858 1628 : iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
5859 814 : poDstGeomFieldDefn->GetNameRef());
5860 814 : if (iSrcGeomField < 0)
5861 : {
5862 348 : if (nDstGeomFieldCount == 1 &&
5863 174 : poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
5864 : {
5865 168 : iSrcGeomField = 0;
5866 : }
5867 : else
5868 : {
5869 6 : continue;
5870 : }
5871 : }
5872 : }
5873 :
5874 846 : if (psInfo->m_nFeaturesRead == 0)
5875 : {
5876 845 : poSourceSRS = poUserSourceSRS;
5877 845 : if (poSourceSRS == nullptr)
5878 : {
5879 837 : if (iSrcGeomField > 0)
5880 121 : poSourceSRS = poSrcLayer->GetLayerDefn()
5881 121 : ->GetGeomFieldDefn(iSrcGeomField)
5882 121 : ->GetSpatialRef();
5883 : else
5884 716 : poSourceSRS = poSrcLayer->GetSpatialRef();
5885 : }
5886 : }
5887 846 : if (poSourceSRS == nullptr)
5888 : {
5889 350 : if (poFeature == nullptr)
5890 : {
5891 1 : if (bVerboseError)
5892 : {
5893 0 : CPLError(CE_Failure, CPLE_AppDefined,
5894 : "Non-null feature expected to set transformation");
5895 : }
5896 1 : return false;
5897 : }
5898 : OGRGeometry *poSrcGeometry =
5899 349 : poFeature->GetGeomFieldRef(iSrcGeomField);
5900 349 : if (poSrcGeometry)
5901 277 : poSourceSRS = poSrcGeometry->getSpatialReference();
5902 349 : psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);
5903 : }
5904 :
5905 845 : if (bTransform)
5906 : {
5907 39 : if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)
5908 : {
5909 0 : CPLError(CE_Failure, CPLE_AppDefined,
5910 : "Can't transform coordinates, source layer has no\n"
5911 : "coordinate system. Use -s_srs to set one.");
5912 :
5913 0 : return false;
5914 : }
5915 :
5916 39 : if (psInfo->m_pszCTPipeline == nullptr)
5917 : {
5918 35 : CPLAssert(nullptr != poSourceSRS);
5919 35 : CPLAssert(nullptr != poOutputSRS);
5920 : }
5921 :
5922 39 : if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)
5923 : {
5924 : const auto &supportedSRSList =
5925 37 : poSrcLayer->GetSupportedSRSList(iGeom);
5926 37 : if (!supportedSRSList.empty())
5927 : {
5928 1 : const char *const apszOptions[] = {
5929 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
5930 1 : for (const auto &poSRS : supportedSRSList)
5931 : {
5932 1 : if (poSRS->IsSame(poOutputSRS, apszOptions))
5933 : {
5934 2 : OGRSpatialReference oSourceSRSBackup;
5935 1 : if (poSourceSRS)
5936 1 : oSourceSRSBackup = *poSourceSRS;
5937 1 : if (poSrcLayer->SetActiveSRS(iGeom, poSRS.get()) ==
5938 : OGRERR_NONE)
5939 : {
5940 1 : CPLDebug("ogr2ogr",
5941 : "Switching layer active SRS to %s",
5942 : poSRS->GetName());
5943 :
5944 1 : if (psInfo->m_hSpatialFilter != nullptr &&
5945 0 : ((psInfo->m_iRequestedSrcGeomField < 0 &&
5946 0 : iGeom == 0) ||
5947 : (iGeom ==
5948 0 : psInfo->m_iRequestedSrcGeomField)))
5949 : {
5950 0 : OGRSpatialReference oSpatSRS;
5951 0 : oSpatSRS.SetAxisMappingStrategy(
5952 : OAMS_TRADITIONAL_GIS_ORDER);
5953 0 : if (psInfo->m_pszSpatSRSDef)
5954 0 : oSpatSRS.SetFromUserInput(
5955 : psInfo->m_pszSpatSRSDef);
5956 0 : ApplySpatialFilter(
5957 : poSrcLayer,
5958 : OGRGeometry::FromHandle(
5959 : psInfo->m_hSpatialFilter),
5960 0 : !oSpatSRS.IsEmpty() ? &oSpatSRS
5961 0 : : !oSourceSRSBackup.IsEmpty()
5962 : ? &oSourceSRSBackup
5963 : : nullptr,
5964 : psInfo->m_pszGeomField, poOutputSRS);
5965 : }
5966 :
5967 1 : bTransform = false;
5968 : }
5969 1 : break;
5970 : }
5971 : }
5972 : }
5973 : }
5974 :
5975 39 : if (!bTransform)
5976 : {
5977 : // do nothing
5978 : }
5979 39 : else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&
5980 1 : psInfo->m_aoReprojectionInfo[iGeom]
5981 1 : .m_poCT->GetSourceCS() == poSourceSRS)
5982 : {
5983 0 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5984 : }
5985 : else
5986 : {
5987 38 : OGRCoordinateTransformationOptions options;
5988 38 : if (psInfo->m_pszCTPipeline)
5989 : {
5990 4 : options.SetCoordinateOperation(psInfo->m_pszCTPipeline,
5991 : false);
5992 : }
5993 :
5994 : bool bWarnAboutDifferentCoordinateOperations =
5995 75 : poGCPCoordTrans == nullptr &&
5996 37 : !(poSourceSRS && poSourceSRS->IsGeocentric());
5997 :
5998 0 : for (const auto &[key, value] :
5999 38 : cpl::IterateNameValue(psInfo->m_aosCTOptions))
6000 : {
6001 0 : if (EQUAL(key, "ALLOW_BALLPARK"))
6002 : {
6003 0 : options.SetBallparkAllowed(CPLTestBool(value));
6004 : }
6005 0 : else if (EQUAL(key, "ONLY_BEST"))
6006 : {
6007 0 : options.SetOnlyBest(CPLTestBool(value));
6008 : }
6009 0 : else if (EQUAL(key, "WARN_ABOUT_DIFFERENT_COORD_OP"))
6010 : {
6011 0 : if (!CPLTestBool(value))
6012 0 : bWarnAboutDifferentCoordinateOperations = false;
6013 : }
6014 : else
6015 : {
6016 0 : CPLError(CE_Warning, CPLE_AppDefined,
6017 : "Unknown coordinate transform option: %s",
6018 : key);
6019 : }
6020 : }
6021 :
6022 : auto poNewCT = std::unique_ptr<OGRCoordinateTransformation>(
6023 : OGRCreateCoordinateTransformation(poSourceSRS, poOutputSRS,
6024 38 : options));
6025 38 : if (poNewCT == nullptr)
6026 : {
6027 0 : char *pszWKT = nullptr;
6028 :
6029 0 : CPLError(CE_Failure, CPLE_AppDefined,
6030 : "Failed to create coordinate transformation "
6031 : "between the\n"
6032 : "following coordinate systems. This may be "
6033 : "because they\n"
6034 : "are not transformable.");
6035 :
6036 0 : if (poSourceSRS)
6037 : {
6038 0 : poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
6039 0 : CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
6040 : pszWKT);
6041 0 : CPLFree(pszWKT);
6042 : }
6043 :
6044 0 : if (poOutputSRS)
6045 : {
6046 0 : poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
6047 0 : CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
6048 : pszWKT);
6049 0 : CPLFree(pszWKT);
6050 : }
6051 :
6052 0 : return false;
6053 : }
6054 38 : if (poGCPCoordTrans)
6055 : {
6056 2 : poNewCT = std::make_unique<CompositeCT>(poGCPCoordTrans,
6057 2 : std::move(poNewCT));
6058 : }
6059 : else
6060 : {
6061 37 : psInfo->m_aoReprojectionInfo[iGeom]
6062 37 : .m_bWarnAboutDifferentCoordinateOperations =
6063 : bWarnAboutDifferentCoordinateOperations;
6064 : }
6065 38 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT = std::move(poNewCT);
6066 38 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6067 38 : psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =
6068 75 : !(poGCPCoordTrans == nullptr && poSourceSRS &&
6069 37 : poSourceSRS->IsGeographic() && poOutputSRS &&
6070 4 : poOutputSRS->IsGeographic());
6071 : }
6072 : }
6073 : else
6074 : {
6075 806 : const char *const apszOptions[] = {
6076 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
6077 : "CRITERION=EQUIVALENT", nullptr};
6078 : auto poDstGeomFieldDefnSpatialRef =
6079 806 : poDstGeomFieldDefn->GetSpatialRef();
6080 459 : if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&
6081 374 : poSourceSRS->GetDataAxisToSRSAxisMapping() !=
6082 : poDstGeomFieldDefnSpatialRef
6083 1265 : ->GetDataAxisToSRSAxisMapping() &&
6084 3 : poSourceSRS->IsSame(poDstGeomFieldDefnSpatialRef, apszOptions))
6085 : {
6086 0 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT =
6087 0 : std::make_unique<CompositeCT>(
6088 0 : std::make_unique<AxisMappingCoordinateTransformation>(
6089 : poSourceSRS->GetDataAxisToSRSAxisMapping(),
6090 : poDstGeomFieldDefnSpatialRef
6091 : ->GetDataAxisToSRSAxisMapping()),
6092 0 : poGCPCoordTrans);
6093 0 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6094 : }
6095 806 : else if (poGCPCoordTrans)
6096 : {
6097 5 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT =
6098 10 : std::make_unique<CompositeCT>(poGCPCoordTrans, nullptr);
6099 5 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6100 : }
6101 : }
6102 :
6103 845 : if (bWrapDateline)
6104 : {
6105 2 : if (bTransform && poCT != nullptr && poOutputSRS != nullptr &&
6106 8 : poOutputSRS->IsGeographic() &&
6107 1 : !poOutputSRS->IsDerivedGeographic())
6108 : {
6109 : papszTransformOptions =
6110 1 : CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
6111 1 : if (!osDateLineOffset.empty())
6112 : {
6113 1 : CPLString soOffset("DATELINEOFFSET=");
6114 1 : soOffset += osDateLineOffset;
6115 : papszTransformOptions =
6116 1 : CSLAddString(papszTransformOptions, soOffset);
6117 : }
6118 : }
6119 8 : else if (poSourceSRS != nullptr && poSourceSRS->IsGeographic() &&
6120 4 : !poSourceSRS->IsDerivedGeographic())
6121 : {
6122 : papszTransformOptions =
6123 4 : CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
6124 4 : if (!osDateLineOffset.empty())
6125 : {
6126 4 : CPLString soOffset("DATELINEOFFSET=");
6127 4 : soOffset += osDateLineOffset;
6128 : papszTransformOptions =
6129 4 : CSLAddString(papszTransformOptions, soOffset);
6130 : }
6131 : }
6132 : else
6133 : {
6134 0 : CPLErrorOnce(CE_Failure, CPLE_IllegalArg,
6135 : "-wrapdateline option only works when "
6136 : "reprojecting to a geographic SRS");
6137 : }
6138 :
6139 5 : psInfo->m_aoReprojectionInfo[iGeom].m_aosTransformOptions.Assign(
6140 5 : papszTransformOptions);
6141 : }
6142 : }
6143 911 : return true;
6144 : }
6145 :
6146 : /************************************************************************/
6147 : /* LayerTranslator::TranslateArrow() */
6148 : /************************************************************************/
6149 :
6150 167 : bool LayerTranslator::TranslateArrow(
6151 : TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,
6152 : GIntBig *pnReadFeatureCount, GDALProgressFunc pfnProgress,
6153 : void *pProgressArg, const GDALVectorTranslateOptions *psOptions)
6154 : {
6155 : struct ArrowSchema schema;
6156 334 : CPLStringList aosOptionsWriteArrowBatch;
6157 167 : if (psInfo->m_bPreserveFID)
6158 : {
6159 : aosOptionsWriteArrowBatch.SetNameValue(
6160 30 : "FID", psInfo->m_poSrcLayer->GetFIDColumn());
6161 : aosOptionsWriteArrowBatch.SetNameValue("IF_FID_NOT_PRESERVED",
6162 30 : "WARNING");
6163 : }
6164 :
6165 167 : if (psInfo->m_sArrowArrayStream.get_schema(&schema) != 0)
6166 : {
6167 0 : CPLError(CE_Failure, CPLE_AppDefined, "stream.get_schema() failed");
6168 0 : return false;
6169 : }
6170 :
6171 167 : int iArrowGeomFieldIndex = -1;
6172 167 : if (m_bTransform)
6173 : {
6174 12 : iArrowGeomFieldIndex = GetArrowGeomFieldIndex(
6175 12 : &schema, psInfo->m_poSrcLayer->GetGeometryColumn());
6176 12 : if (!SetupCT(psInfo, psInfo->m_poSrcLayer, m_bTransform,
6177 12 : m_bWrapDateline, m_osDateLineOffset, m_poUserSourceSRS,
6178 : nullptr, m_poOutputSRS, m_poGCPCoordTrans, false))
6179 : {
6180 0 : return false;
6181 : }
6182 : }
6183 :
6184 167 : bool bRet = true;
6185 :
6186 167 : GIntBig nCount = 0;
6187 167 : bool bGoOn = true;
6188 167 : std::vector<GByte> abyModifiedWKB;
6189 167 : const int nNumReprojectionThreads = []()
6190 : {
6191 167 : const int nNumCPUs = CPLGetNumCPUs();
6192 167 : if (nNumCPUs <= 1)
6193 : {
6194 0 : return 1;
6195 : }
6196 : else
6197 : {
6198 : const char *pszNumThreads =
6199 167 : CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
6200 167 : if (pszNumThreads)
6201 : {
6202 0 : if (EQUAL(pszNumThreads, "ALL_CPUS"))
6203 0 : return CPLGetNumCPUs();
6204 0 : return std::min(atoi(pszNumThreads), 1024);
6205 : }
6206 : else
6207 : {
6208 167 : return std::max(2, nNumCPUs / 2);
6209 : }
6210 : }
6211 167 : }();
6212 :
6213 : // Somewhat arbitrary threshold (config option only/mostly for autotest purposes)
6214 167 : const int MIN_FEATURES_FOR_THREADED_REPROJ = atoi(CPLGetConfigOption(
6215 : "OGR2OGR_MIN_FEATURES_FOR_THREADED_REPROJ", "10000"));
6216 :
6217 325 : while (bGoOn)
6218 : {
6219 : struct ArrowArray array;
6220 : // Acquire source batch
6221 323 : if (psInfo->m_sArrowArrayStream.get_next(&array) != 0)
6222 : {
6223 0 : CPLError(CE_Failure, CPLE_AppDefined, "stream.get_next() failed");
6224 0 : bRet = false;
6225 165 : break;
6226 : }
6227 :
6228 323 : if (array.release == nullptr)
6229 : {
6230 : // End of stream
6231 165 : break;
6232 : }
6233 :
6234 : // Limit number of features in batch if needed
6235 158 : if (psOptions->nLimit >= 0 &&
6236 2 : nCount + array.length >= psOptions->nLimit)
6237 : {
6238 2 : const auto nAdjustedLength = psOptions->nLimit - nCount;
6239 14 : for (int i = 0; i < array.n_children; ++i)
6240 : {
6241 12 : if (array.children[i]->length == array.length)
6242 12 : array.children[i]->length = nAdjustedLength;
6243 : }
6244 2 : array.length = nAdjustedLength;
6245 2 : nCount = psOptions->nLimit;
6246 2 : bGoOn = false;
6247 : }
6248 : else
6249 : {
6250 156 : nCount += array.length;
6251 : }
6252 :
6253 158 : const auto nArrayLength = array.length;
6254 :
6255 : // Coordinate reprojection
6256 158 : if (m_bTransform)
6257 : {
6258 : struct GeomArrayReleaser
6259 : {
6260 : const void *origin_buffers_2 = nullptr;
6261 : void (*origin_release)(struct ArrowArray *) = nullptr;
6262 : void *origin_private_data = nullptr;
6263 :
6264 11 : static void init(struct ArrowArray *psGeomArray)
6265 : {
6266 11 : GeomArrayReleaser *releaser = new GeomArrayReleaser();
6267 11 : CPLAssert(psGeomArray->n_buffers >= 3);
6268 11 : releaser->origin_buffers_2 = psGeomArray->buffers[2];
6269 11 : releaser->origin_private_data = psGeomArray->private_data;
6270 11 : releaser->origin_release = psGeomArray->release;
6271 11 : psGeomArray->release = GeomArrayReleaser::release;
6272 11 : psGeomArray->private_data = releaser;
6273 11 : }
6274 :
6275 11 : static void release(struct ArrowArray *psGeomArray)
6276 : {
6277 11 : GeomArrayReleaser *releaser =
6278 : static_cast<GeomArrayReleaser *>(
6279 : psGeomArray->private_data);
6280 11 : psGeomArray->buffers[2] = releaser->origin_buffers_2;
6281 11 : psGeomArray->private_data = releaser->origin_private_data;
6282 11 : psGeomArray->release = releaser->origin_release;
6283 11 : if (psGeomArray->release)
6284 11 : psGeomArray->release(psGeomArray);
6285 11 : delete releaser;
6286 11 : }
6287 : };
6288 :
6289 11 : auto *psGeomArray = array.children[iArrowGeomFieldIndex];
6290 11 : GeomArrayReleaser::init(psGeomArray);
6291 :
6292 11 : GByte *pabyWKB = static_cast<GByte *>(
6293 11 : const_cast<void *>(psGeomArray->buffers[2]));
6294 11 : const uint32_t *panOffsets =
6295 11 : static_cast<const uint32_t *>(psGeomArray->buffers[1]);
6296 11 : auto poCT = psInfo->m_aoReprojectionInfo[0].m_poCT.get();
6297 :
6298 : try
6299 : {
6300 11 : abyModifiedWKB.resize(panOffsets[nArrayLength]);
6301 : }
6302 0 : catch (const std::exception &)
6303 : {
6304 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6305 0 : bRet = false;
6306 0 : if (array.release)
6307 0 : array.release(&array);
6308 0 : break;
6309 : }
6310 11 : memcpy(abyModifiedWKB.data(), pabyWKB, panOffsets[nArrayLength]);
6311 11 : psGeomArray->buffers[2] = abyModifiedWKB.data();
6312 :
6313 : // Collect left-most, right-most, top-most, bottom-most coordinates.
6314 11 : if (psInfo->m_aoReprojectionInfo[0]
6315 11 : .m_bWarnAboutDifferentCoordinateOperations)
6316 : {
6317 : struct OGRWKBPointVisitor final : public OGRWKBPointUpdater
6318 : {
6319 : TargetLayerInfo::ReprojectionInfo &m_info;
6320 :
6321 11 : explicit OGRWKBPointVisitor(
6322 : TargetLayerInfo::ReprojectionInfo &info)
6323 11 : : m_info(info)
6324 : {
6325 11 : }
6326 :
6327 10262 : bool update(bool bNeedSwap, void *x, void *y, void *z,
6328 : void * /* m */) override
6329 : {
6330 : double dfX, dfY, dfZ;
6331 10262 : memcpy(&dfX, x, sizeof(double));
6332 10262 : memcpy(&dfY, y, sizeof(double));
6333 10262 : if (bNeedSwap)
6334 : {
6335 0 : CPL_SWAP64PTR(&dfX);
6336 0 : CPL_SWAP64PTR(&dfY);
6337 : }
6338 10262 : if (z)
6339 : {
6340 0 : memcpy(&dfZ, z, sizeof(double));
6341 0 : if (bNeedSwap)
6342 : {
6343 0 : CPL_SWAP64PTR(&dfZ);
6344 : }
6345 : }
6346 : else
6347 10262 : dfZ = 0;
6348 10262 : m_info.UpdateExtremePoints(dfX, dfY, dfZ);
6349 10262 : return true;
6350 : }
6351 : };
6352 :
6353 22 : OGRWKBPointVisitor oVisitor(psInfo->m_aoReprojectionInfo[0]);
6354 11 : const GByte *pabyValidity =
6355 11 : static_cast<const GByte *>(psGeomArray->buffers[0]);
6356 :
6357 10046 : for (size_t i = 0; i < static_cast<size_t>(nArrayLength); ++i)
6358 : {
6359 10035 : const size_t iShifted =
6360 10035 : static_cast<size_t>(i + psGeomArray->offset);
6361 10035 : if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6362 24 : (1 << (iShifted % 8))) != 0)
6363 : {
6364 10027 : const auto nWKBSize =
6365 10027 : panOffsets[iShifted + 1] - panOffsets[iShifted];
6366 10027 : OGRWKBUpdatePoints(abyModifiedWKB.data() +
6367 10027 : panOffsets[iShifted],
6368 : nWKBSize, oVisitor);
6369 : }
6370 : }
6371 : }
6372 :
6373 11 : std::atomic<bool> atomicRet{true};
6374 : const auto oReprojectionLambda =
6375 16 : [psGeomArray, nArrayLength, panOffsets, &atomicRet,
6376 40148 : &abyModifiedWKB, &poCT](int iThread, int nThreads)
6377 : {
6378 : OGRWKBTransformCache oCache;
6379 16 : OGREnvelope3D sEnv3D;
6380 : auto poThisCT =
6381 16 : std::unique_ptr<OGRCoordinateTransformation>(poCT->Clone());
6382 16 : if (!poThisCT)
6383 : {
6384 0 : CPLError(CE_Failure, CPLE_AppDefined,
6385 : "Cannot clone OGRCoordinateTransformation");
6386 0 : atomicRet = false;
6387 0 : return;
6388 : }
6389 :
6390 16 : const GByte *pabyValidity =
6391 16 : static_cast<const GByte *>(psGeomArray->buffers[0]);
6392 16 : const size_t iStart =
6393 16 : static_cast<size_t>(iThread * nArrayLength / nThreads);
6394 16 : const size_t iMax = static_cast<size_t>(
6395 16 : (iThread + 1) * nArrayLength / nThreads);
6396 10051 : for (size_t i = iStart; i < iMax; ++i)
6397 : {
6398 10035 : const size_t iShifted =
6399 10035 : static_cast<size_t>(i + psGeomArray->offset);
6400 10035 : if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6401 24 : (1 << (iShifted % 8))) != 0)
6402 : {
6403 10027 : const auto nWKBSize =
6404 10027 : panOffsets[iShifted + 1] - panOffsets[iShifted];
6405 20054 : if (!OGRWKBTransform(
6406 10027 : abyModifiedWKB.data() + panOffsets[iShifted],
6407 : nWKBSize, poThisCT.get(), oCache, sEnv3D))
6408 : {
6409 0 : CPLError(CE_Failure, CPLE_AppDefined,
6410 : "Reprojection failed");
6411 0 : atomicRet = false;
6412 0 : break;
6413 : }
6414 : }
6415 : }
6416 11 : };
6417 :
6418 11 : if (nArrayLength >= MIN_FEATURES_FOR_THREADED_REPROJ &&
6419 5 : nNumReprojectionThreads >= 2)
6420 : {
6421 10 : std::vector<std::future<void>> oTasks;
6422 15 : for (int iThread = 0; iThread < nNumReprojectionThreads;
6423 : ++iThread)
6424 : {
6425 20 : oTasks.emplace_back(std::async(std::launch::async,
6426 : oReprojectionLambda, iThread,
6427 10 : nNumReprojectionThreads));
6428 : }
6429 15 : for (auto &oTask : oTasks)
6430 : {
6431 10 : oTask.get();
6432 5 : }
6433 : }
6434 : else
6435 : {
6436 6 : oReprojectionLambda(0, 1);
6437 : }
6438 :
6439 11 : bRet = atomicRet;
6440 11 : if (!bRet)
6441 : {
6442 0 : if (array.release)
6443 0 : array.release(&array);
6444 0 : break;
6445 : }
6446 : }
6447 :
6448 : // Write batch to target layer
6449 158 : const bool bWriteOK = psInfo->m_poDstLayer->WriteArrowBatch(
6450 158 : &schema, &array, aosOptionsWriteArrowBatch.List());
6451 :
6452 158 : if (array.release)
6453 38 : array.release(&array);
6454 :
6455 158 : if (!bWriteOK)
6456 : {
6457 0 : CPLError(CE_Failure, CPLE_AppDefined, "WriteArrowBatch() failed");
6458 0 : bRet = false;
6459 0 : break;
6460 : }
6461 :
6462 : /* Report progress */
6463 158 : if (pfnProgress)
6464 : {
6465 0 : if (!pfnProgress(nCountLayerFeatures
6466 0 : ? nCount * 1.0 / nCountLayerFeatures
6467 : : 1.0,
6468 : "", pProgressArg))
6469 : {
6470 0 : bGoOn = false;
6471 0 : bRet = false;
6472 : }
6473 : }
6474 :
6475 158 : if (pnReadFeatureCount)
6476 0 : *pnReadFeatureCount = nCount;
6477 : }
6478 :
6479 167 : schema.release(&schema);
6480 :
6481 167 : return bRet;
6482 : }
6483 :
6484 : /************************************************************************/
6485 : /* LayerTranslator::Translate() */
6486 : /************************************************************************/
6487 :
6488 1969 : bool LayerTranslator::Translate(
6489 : std::unique_ptr<OGRFeature> poFeatureIn, TargetLayerInfo *psInfo,
6490 : GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
6491 : GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress, void *pProgressArg,
6492 : const GDALVectorTranslateOptions *psOptions)
6493 : {
6494 1969 : if (psInfo->m_bUseWriteArrowBatch)
6495 : {
6496 167 : return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,
6497 167 : pfnProgress, pProgressArg, psOptions);
6498 : }
6499 :
6500 1802 : const int eGType = m_eGType;
6501 1802 : const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
6502 :
6503 1802 : OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;
6504 1802 : OGRLayer *poDstLayer = psInfo->m_poDstLayer;
6505 1802 : const int *const panMap = psInfo->m_anMap.data();
6506 1802 : const int iSrcZField = psInfo->m_iSrcZField;
6507 1802 : const bool bPreserveFID = psInfo->m_bPreserveFID;
6508 1802 : const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
6509 1802 : const auto poDstFDefn = poDstLayer->GetLayerDefn();
6510 1802 : const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
6511 1802 : const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
6512 1802 : const bool bExplodeCollections =
6513 1802 : m_bExplodeCollections && nDstGeomFieldCount <= 1;
6514 1802 : const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;
6515 :
6516 1802 : if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
6517 : {
6518 1769 : if (nSrcGeomFieldCount == 1)
6519 : {
6520 730 : poOutputSRS = poSrcLayer->GetSpatialRef();
6521 : }
6522 1039 : else if (iRequestedSrcGeomField > 0)
6523 : {
6524 1 : poOutputSRS = poSrcLayer->GetLayerDefn()
6525 1 : ->GetGeomFieldDefn(iRequestedSrcGeomField)
6526 1 : ->GetSpatialRef();
6527 : }
6528 : }
6529 :
6530 : /* -------------------------------------------------------------------- */
6531 : /* Transfer features. */
6532 : /* -------------------------------------------------------------------- */
6533 1802 : if (psOptions->nGroupTransactions)
6534 : {
6535 1801 : if (psOptions->nLayerTransaction)
6536 : {
6537 685 : if (poDstLayer->StartTransaction() == OGRERR_FAILURE)
6538 : {
6539 0 : return false;
6540 : }
6541 : }
6542 : }
6543 :
6544 1802 : std::unique_ptr<OGRFeature> poFeature;
6545 3604 : auto poDstFeature = std::make_unique<OGRFeature>(poDstFDefn);
6546 1802 : int nFeaturesInTransaction = 0;
6547 1802 : GIntBig nCount = 0; /* written + failed */
6548 1802 : GIntBig nFeaturesWritten = 0;
6549 1802 : bool bRunSetPrecisionEvaluated = false;
6550 1802 : bool bRunSetPrecision = false;
6551 :
6552 1802 : bool bRet = true;
6553 1802 : CPLErrorReset();
6554 :
6555 1802 : bool bSetupCTOK = false;
6556 1802 : if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&
6557 26 : !psInfo->m_bPerFeatureCT)
6558 : {
6559 26 : bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6560 26 : m_osDateLineOffset, m_poUserSourceSRS, nullptr,
6561 : poOutputSRS, m_poGCPCoordTrans, false);
6562 : }
6563 :
6564 1802 : const bool bSingleIteration = poFeatureIn != nullptr;
6565 : while (true)
6566 : {
6567 15411 : if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)
6568 : {
6569 9 : break;
6570 : }
6571 :
6572 15402 : if (poFeatureIn != nullptr)
6573 974 : poFeature = std::move(poFeatureIn);
6574 14428 : else if (psOptions->nFIDToFetch != OGRNullFID)
6575 5 : poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));
6576 : else
6577 14423 : poFeature.reset(poSrcLayer->GetNextFeature());
6578 :
6579 15402 : if (poFeature == nullptr)
6580 : {
6581 809 : if (CPLGetLastErrorType() == CE_Failure)
6582 : {
6583 8 : bRet = false;
6584 : }
6585 809 : break;
6586 : }
6587 :
6588 14593 : if (!bSetupCTOK &&
6589 14482 : (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))
6590 : {
6591 1748 : if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6592 874 : m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),
6593 : poOutputSRS, m_poGCPCoordTrans, true))
6594 : {
6595 4 : return false;
6596 : }
6597 : }
6598 :
6599 14593 : psInfo->m_nFeaturesRead++;
6600 :
6601 14593 : int nIters = 1;
6602 0 : std::unique_ptr<OGRGeometryCollection> poCollToExplode;
6603 14593 : int iGeomCollToExplode = -1;
6604 14593 : OGRGeometry *poSrcGeometry = nullptr;
6605 14593 : if (bExplodeCollections)
6606 : {
6607 13 : if (iRequestedSrcGeomField >= 0)
6608 : poSrcGeometry =
6609 0 : poFeature->GetGeomFieldRef(iRequestedSrcGeomField);
6610 : else
6611 13 : poSrcGeometry = poFeature->GetGeometryRef();
6612 26 : if (poSrcGeometry &&
6613 13 : OGR_GT_IsSubClassOf(poSrcGeometry->getGeometryType(),
6614 : wkbGeometryCollection))
6615 : {
6616 : const int nParts =
6617 12 : poSrcGeometry->toGeometryCollection()->getNumGeometries();
6618 21 : if (nParts > 0 ||
6619 9 : wkbFlatten(poSrcGeometry->getGeometryType()) !=
6620 : wkbGeometryCollection)
6621 : {
6622 11 : iGeomCollToExplode = iRequestedSrcGeomField >= 0
6623 : ? iRequestedSrcGeomField
6624 : : 0;
6625 11 : poCollToExplode.reset(
6626 : poFeature->StealGeometry(iGeomCollToExplode)
6627 : ->toGeometryCollection());
6628 11 : nIters = std::max(1, nParts);
6629 : }
6630 : }
6631 : }
6632 :
6633 14593 : const GIntBig nSrcFID = poFeature->GetFID();
6634 14593 : GIntBig nDesiredFID = OGRNullFID;
6635 14593 : if (bPreserveFID)
6636 1164 : nDesiredFID = nSrcFID;
6637 13430 : else if (psInfo->m_iSrcFIDField >= 0 &&
6638 1 : poFeature->IsFieldSetAndNotNull(psInfo->m_iSrcFIDField))
6639 : nDesiredFID =
6640 1 : poFeature->GetFieldAsInteger64(psInfo->m_iSrcFIDField);
6641 :
6642 29185 : for (int iPart = 0; iPart < nIters; iPart++)
6643 : {
6644 20512 : if (psOptions->nLayerTransaction &&
6645 5916 : ++nFeaturesInTransaction == psOptions->nGroupTransactions)
6646 : {
6647 12 : if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||
6648 6 : poDstLayer->StartTransaction() == OGRERR_FAILURE)
6649 : {
6650 0 : return false;
6651 : }
6652 6 : nFeaturesInTransaction = 0;
6653 : }
6654 37860 : else if (!psOptions->nLayerTransaction &&
6655 23250 : psOptions->nGroupTransactions > 0 &&
6656 8660 : ++nTotalEventsDone >= psOptions->nGroupTransactions)
6657 : {
6658 40 : if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||
6659 20 : m_poODS->StartTransaction(psOptions->bForceTransaction) ==
6660 : OGRERR_FAILURE)
6661 : {
6662 0 : return false;
6663 : }
6664 20 : nTotalEventsDone = 0;
6665 : }
6666 :
6667 14596 : CPLErrorReset();
6668 14596 : if (psInfo->m_bCanAvoidSetFrom)
6669 : {
6670 14337 : poDstFeature = std::move(poFeature);
6671 : // From now on, poFeature is null !
6672 14337 : poDstFeature->SetFDefnUnsafe(poDstFDefn);
6673 14337 : poDstFeature->SetFID(nDesiredFID);
6674 : }
6675 : else
6676 : {
6677 : /* Optimization to avoid duplicating the source geometry in the
6678 : */
6679 : /* target feature : we steal it from the source feature for
6680 : * now... */
6681 0 : std::unique_ptr<OGRGeometry> poStolenGeometry;
6682 259 : if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&
6683 84 : (nDstGeomFieldCount == 1 ||
6684 84 : (nDstGeomFieldCount == 0 && m_poClipSrcOri)))
6685 : {
6686 134 : poStolenGeometry.reset(poFeature->StealGeometry());
6687 : }
6688 125 : else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)
6689 : {
6690 0 : poStolenGeometry.reset(
6691 : poFeature->StealGeometry(iRequestedSrcGeomField));
6692 : }
6693 :
6694 259 : if (nDstGeomFieldCount == 0 && poStolenGeometry &&
6695 0 : m_poClipSrcOri)
6696 : {
6697 0 : if (poStolenGeometry->IsEmpty())
6698 0 : goto end_loop;
6699 :
6700 : const auto clipGeomDesc =
6701 0 : GetSrcClipGeom(poStolenGeometry->getSpatialReference());
6702 :
6703 0 : if (clipGeomDesc.poGeom && clipGeomDesc.poEnv)
6704 : {
6705 0 : OGREnvelope oEnv;
6706 0 : poStolenGeometry->getEnvelope(&oEnv);
6707 0 : if (!clipGeomDesc.poEnv->Contains(oEnv) &&
6708 0 : !(clipGeomDesc.poEnv->Intersects(oEnv) &&
6709 0 : clipGeomDesc.poGeom->Intersects(
6710 0 : poStolenGeometry.get())))
6711 : {
6712 0 : goto end_loop;
6713 : }
6714 : }
6715 : }
6716 :
6717 259 : poDstFeature->Reset();
6718 :
6719 518 : if (poDstFeature->SetFrom(
6720 259 : poFeature.get(), panMap, /* bForgiving = */ TRUE,
6721 259 : /* bUseISO8601ForDateTimeAsString = */ true) !=
6722 : OGRERR_NONE)
6723 : {
6724 0 : if (psOptions->nGroupTransactions)
6725 : {
6726 0 : if (psOptions->nLayerTransaction)
6727 : {
6728 0 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6729 : {
6730 0 : return false;
6731 : }
6732 : }
6733 : }
6734 :
6735 0 : CPLError(CE_Failure, CPLE_AppDefined,
6736 : "Unable to translate feature " CPL_FRMT_GIB
6737 : " from layer %s.",
6738 0 : nSrcFID, poSrcLayer->GetName());
6739 :
6740 0 : return false;
6741 : }
6742 :
6743 : /* ... and now we can attach the stolen geometry */
6744 259 : if (poStolenGeometry)
6745 : {
6746 127 : poDstFeature->SetGeometryDirectly(
6747 : poStolenGeometry.release());
6748 : }
6749 :
6750 259 : if (!psInfo->m_oMapResolved.empty())
6751 : {
6752 4 : for (const auto &kv : psInfo->m_oMapResolved)
6753 : {
6754 2 : const int nDstField = kv.first;
6755 2 : const int nSrcField = kv.second.nSrcField;
6756 2 : if (poFeature->IsFieldSetAndNotNull(nSrcField))
6757 : {
6758 2 : const auto poDomain = kv.second.poDomain;
6759 : const auto &oMapKV =
6760 2 : psInfo->m_oMapDomainToKV[poDomain];
6761 : const auto iter = oMapKV.find(
6762 2 : poFeature->GetFieldAsString(nSrcField));
6763 2 : if (iter != oMapKV.end())
6764 : {
6765 2 : poDstFeature->SetField(nDstField,
6766 1 : iter->second.c_str());
6767 : }
6768 : }
6769 : }
6770 : }
6771 :
6772 259 : if (nDesiredFID != OGRNullFID)
6773 2 : poDstFeature->SetFID(nDesiredFID);
6774 : }
6775 :
6776 14596 : if (psOptions->bEmptyStrAsNull)
6777 : {
6778 2 : for (int i = 0; i < poDstFeature->GetFieldCount(); i++)
6779 : {
6780 1 : if (!poDstFeature->IsFieldSetAndNotNull(i))
6781 0 : continue;
6782 1 : auto fieldDef = poDstFeature->GetFieldDefnRef(i);
6783 1 : if (fieldDef->GetType() != OGRFieldType::OFTString)
6784 0 : continue;
6785 1 : auto str = poDstFeature->GetFieldAsString(i);
6786 1 : if (strcmp(str, "") == 0)
6787 1 : poDstFeature->SetFieldNull(i);
6788 : }
6789 : }
6790 :
6791 14596 : if (!psInfo->m_anDateTimeFieldIdx.empty())
6792 : {
6793 40 : for (int i : psInfo->m_anDateTimeFieldIdx)
6794 : {
6795 20 : if (!poDstFeature->IsFieldSetAndNotNull(i))
6796 11 : continue;
6797 15 : auto psField = poDstFeature->GetRawFieldRef(i);
6798 15 : if (psField->Date.TZFlag == 0 || psField->Date.TZFlag == 1)
6799 5 : continue;
6800 :
6801 10 : const int nTZOffsetInSec =
6802 10 : (psField->Date.TZFlag - 100) * 15 * 60;
6803 10 : if (nTZOffsetInSec == psOptions->nTZOffsetInSec)
6804 1 : continue;
6805 :
6806 : struct tm brokendowntime;
6807 9 : memset(&brokendowntime, 0, sizeof(brokendowntime));
6808 9 : brokendowntime.tm_year = psField->Date.Year - 1900;
6809 9 : brokendowntime.tm_mon = psField->Date.Month - 1;
6810 9 : brokendowntime.tm_mday = psField->Date.Day;
6811 9 : GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
6812 9 : int nSec = psField->Date.Hour * 3600 +
6813 9 : psField->Date.Minute * 60 +
6814 9 : static_cast<int>(psField->Date.Second);
6815 9 : nSec += psOptions->nTZOffsetInSec - nTZOffsetInSec;
6816 9 : nUnixTime += nSec;
6817 9 : CPLUnixTimeToYMDHMS(nUnixTime, &brokendowntime);
6818 :
6819 9 : psField->Date.Year =
6820 9 : static_cast<GInt16>(brokendowntime.tm_year + 1900);
6821 9 : psField->Date.Month =
6822 9 : static_cast<GByte>(brokendowntime.tm_mon + 1);
6823 9 : psField->Date.Day =
6824 9 : static_cast<GByte>(brokendowntime.tm_mday);
6825 9 : psField->Date.Hour =
6826 9 : static_cast<GByte>(brokendowntime.tm_hour);
6827 9 : psField->Date.Minute =
6828 9 : static_cast<GByte>(brokendowntime.tm_min);
6829 9 : psField->Date.Second = static_cast<float>(
6830 9 : brokendowntime.tm_sec + fmod(psField->Date.Second, 1));
6831 9 : psField->Date.TZFlag = static_cast<GByte>(
6832 9 : 100 + psOptions->nTZOffsetInSec / (15 * 60));
6833 : }
6834 : }
6835 :
6836 : /* Erase native data if asked explicitly */
6837 14596 : if (!m_bNativeData)
6838 : {
6839 1 : poDstFeature->SetNativeData(nullptr);
6840 1 : poDstFeature->SetNativeMediaType(nullptr);
6841 : }
6842 :
6843 22784 : for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
6844 : {
6845 0 : std::unique_ptr<OGRGeometry> poDstGeometry;
6846 :
6847 8235 : if (poCollToExplode && iGeom == iGeomCollToExplode)
6848 : {
6849 14 : if (poSrcGeometry && poCollToExplode->IsEmpty())
6850 : {
6851 : const OGRwkbGeometryType eSrcType =
6852 8 : poSrcGeometry->getGeometryType();
6853 : const OGRwkbGeometryType eSrcFlattenType =
6854 8 : wkbFlatten(eSrcType);
6855 8 : OGRwkbGeometryType eDstType = eSrcType;
6856 8 : switch (eSrcFlattenType)
6857 : {
6858 4 : case wkbMultiPoint:
6859 4 : eDstType = wkbPoint;
6860 4 : break;
6861 1 : case wkbMultiLineString:
6862 1 : eDstType = wkbLineString;
6863 1 : break;
6864 1 : case wkbMultiPolygon:
6865 1 : eDstType = wkbPolygon;
6866 1 : break;
6867 1 : case wkbMultiCurve:
6868 1 : eDstType = wkbCompoundCurve;
6869 1 : break;
6870 1 : case wkbMultiSurface:
6871 1 : eDstType = wkbCurvePolygon;
6872 1 : break;
6873 0 : default:
6874 0 : break;
6875 : }
6876 : eDstType =
6877 8 : OGR_GT_SetModifier(eDstType, OGR_GT_HasZ(eSrcType),
6878 : OGR_GT_HasM(eSrcType));
6879 8 : poDstGeometry.reset(
6880 : OGRGeometryFactory::createGeometry(eDstType));
6881 : }
6882 : else
6883 : {
6884 : OGRGeometry *poPart =
6885 6 : poCollToExplode->getGeometryRef(0);
6886 6 : poCollToExplode->removeGeometry(0, FALSE);
6887 6 : poDstGeometry.reset(poPart);
6888 : }
6889 : }
6890 : else
6891 : {
6892 8221 : poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));
6893 : }
6894 8235 : if (poDstGeometry == nullptr)
6895 656 : continue;
6896 :
6897 : // poFeature hasn't been moved if iSrcZField != -1
6898 : // cppcheck-suppress accessMoved
6899 7579 : if (iSrcZField != -1 && poFeature != nullptr)
6900 : {
6901 30 : SetZ(poDstGeometry.get(),
6902 : poFeature->GetFieldAsDouble(iSrcZField));
6903 : /* This will correct the coordinate dimension to 3 */
6904 30 : poDstGeometry.reset(poDstGeometry->clone());
6905 : }
6906 :
6907 7579 : if (m_nCoordDim == 2 || m_nCoordDim == 3)
6908 : {
6909 24 : poDstGeometry->setCoordinateDimension(m_nCoordDim);
6910 : }
6911 7555 : else if (m_nCoordDim == 4)
6912 : {
6913 2 : poDstGeometry->set3D(TRUE);
6914 2 : poDstGeometry->setMeasured(TRUE);
6915 : }
6916 7553 : else if (m_nCoordDim == COORD_DIM_XYM)
6917 : {
6918 2 : poDstGeometry->set3D(FALSE);
6919 2 : poDstGeometry->setMeasured(TRUE);
6920 : }
6921 7551 : else if (m_nCoordDim == COORD_DIM_LAYER_DIM)
6922 : {
6923 : const OGRwkbGeometryType eDstLayerGeomType =
6924 2 : poDstLayer->GetLayerDefn()
6925 2 : ->GetGeomFieldDefn(iGeom)
6926 2 : ->GetType();
6927 2 : poDstGeometry->set3D(wkbHasZ(eDstLayerGeomType));
6928 2 : poDstGeometry->setMeasured(wkbHasM(eDstLayerGeomType));
6929 : }
6930 :
6931 7579 : if (m_eGeomOp == GEOMOP_SEGMENTIZE)
6932 : {
6933 20 : if (m_dfGeomOpParam > 0)
6934 20 : poDstGeometry->segmentize(m_dfGeomOpParam);
6935 : }
6936 7559 : else if (m_eGeomOp == GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY)
6937 : {
6938 1 : if (m_dfGeomOpParam > 0)
6939 : {
6940 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6941 : poDstGeometry->SimplifyPreserveTopology(
6942 2 : m_dfGeomOpParam));
6943 1 : if (poNewGeom)
6944 : {
6945 1 : poDstGeometry = std::move(poNewGeom);
6946 : }
6947 : }
6948 : }
6949 :
6950 7579 : if (m_poClipSrcOri)
6951 : {
6952 50 : if (poDstGeometry->IsEmpty())
6953 26 : goto end_loop;
6954 :
6955 : const auto clipGeomDesc =
6956 50 : GetSrcClipGeom(poDstGeometry->getSpatialReference());
6957 :
6958 50 : if (!(clipGeomDesc.poGeom && clipGeomDesc.poEnv))
6959 0 : goto end_loop;
6960 :
6961 50 : OGREnvelope oDstEnv;
6962 50 : poDstGeometry->getEnvelope(&oDstEnv);
6963 :
6964 50 : if (!(clipGeomDesc.bGeomIsRectangle &&
6965 0 : clipGeomDesc.poEnv->Contains(oDstEnv)))
6966 : {
6967 0 : std::unique_ptr<OGRGeometry> poClipped;
6968 50 : if (clipGeomDesc.poEnv->Intersects(oDstEnv))
6969 : {
6970 30 : poClipped.reset(clipGeomDesc.poGeom->Intersection(
6971 30 : poDstGeometry.get()));
6972 : }
6973 50 : if (poClipped == nullptr || poClipped->IsEmpty())
6974 : {
6975 25 : goto end_loop;
6976 : }
6977 :
6978 25 : const int nDim = poDstGeometry->getDimension();
6979 26 : if (poClipped->getDimension() < nDim &&
6980 1 : wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
6981 : ->GetType()) != wkbUnknown)
6982 : {
6983 3 : CPLDebug(
6984 : "OGR2OGR",
6985 : "Discarding feature " CPL_FRMT_GIB
6986 : " of layer %s, "
6987 : "as its intersection with -clipsrc is a %s "
6988 : "whereas the input is a %s",
6989 1 : nSrcFID, poSrcLayer->GetName(),
6990 1 : OGRToOGCGeomType(poClipped->getGeometryType()),
6991 : OGRToOGCGeomType(
6992 1 : poDstGeometry->getGeometryType()));
6993 1 : goto end_loop;
6994 : }
6995 :
6996 72 : poDstGeometry = OGRGeometryFactory::makeCompatibleWith(
6997 24 : std::move(poClipped),
6998 48 : poDstFDefn->GetGeomFieldDefn(iGeom)->GetType());
6999 : }
7000 : }
7001 :
7002 : OGRCoordinateTransformation *const poCT =
7003 7553 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
7004 : char **const papszTransformOptions =
7005 7553 : psInfo->m_aoReprojectionInfo[iGeom]
7006 7553 : .m_aosTransformOptions.List();
7007 : const bool bReprojCanInvalidateValidity =
7008 7553 : psInfo->m_aoReprojectionInfo[iGeom]
7009 7553 : .m_bCanInvalidateValidity;
7010 :
7011 7553 : if (poCT != nullptr || papszTransformOptions != nullptr)
7012 : {
7013 : // If we need to change the geometry type to linear, and
7014 : // we have a geometry with curves, then convert it to
7015 : // linear first, to avoid invalidities due to the fact
7016 : // that validity of arc portions isn't always kept while
7017 : // reprojecting and then discretizing.
7018 124 : if (bReprojCanInvalidateValidity &&
7019 122 : (!psInfo->m_bSupportCurves ||
7020 51 : m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
7021 49 : m_eGeomTypeConversion ==
7022 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))
7023 : {
7024 73 : if (poDstGeometry->hasCurveGeometry(TRUE))
7025 : {
7026 4 : OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
7027 4 : poDstGeometry->getGeometryType());
7028 4 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
7029 : poDstGeometry.release(), eTargetType));
7030 73 : }
7031 : }
7032 49 : else if (bReprojCanInvalidateValidity &&
7033 2 : eGType != GEOMTYPE_UNCHANGED &&
7034 2 : !OGR_GT_IsNonLinear(
7035 100 : static_cast<OGRwkbGeometryType>(eGType)) &&
7036 2 : poDstGeometry->hasCurveGeometry(TRUE))
7037 : {
7038 2 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
7039 : poDstGeometry.release(),
7040 : static_cast<OGRwkbGeometryType>(eGType)));
7041 : }
7042 :
7043 : // Collect left-most, right-most, top-most, bottom-most coordinates.
7044 124 : if (psInfo->m_aoReprojectionInfo[iGeom]
7045 124 : .m_bWarnAboutDifferentCoordinateOperations)
7046 : {
7047 : struct Visitor : public OGRDefaultConstGeometryVisitor
7048 : {
7049 : TargetLayerInfo::ReprojectionInfo &m_info;
7050 :
7051 110 : explicit Visitor(
7052 : TargetLayerInfo::ReprojectionInfo &info)
7053 110 : : m_info(info)
7054 : {
7055 110 : }
7056 :
7057 : using OGRDefaultConstGeometryVisitor::visit;
7058 :
7059 2814 : void visit(const OGRPoint *point) override
7060 : {
7061 2814 : m_info.UpdateExtremePoints(point->getX(),
7062 : point->getY(),
7063 : point->getZ());
7064 2814 : }
7065 : };
7066 :
7067 220 : Visitor oVisit(psInfo->m_aoReprojectionInfo[iGeom]);
7068 110 : poDstGeometry->accept(&oVisit);
7069 : }
7070 :
7071 125 : for (int iIter = 0; iIter < 2; ++iIter)
7072 : {
7073 : auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(
7074 : OGRGeometryFactory::transformWithOptions(
7075 125 : poDstGeometry.get(), poCT,
7076 : papszTransformOptions,
7077 125 : m_transformWithOptionsCache));
7078 125 : if (poReprojectedGeom == nullptr)
7079 : {
7080 0 : if (psOptions->nGroupTransactions)
7081 : {
7082 0 : if (psOptions->nLayerTransaction)
7083 : {
7084 0 : if (poDstLayer->CommitTransaction() !=
7085 0 : OGRERR_NONE &&
7086 0 : !psOptions->bSkipFailures)
7087 : {
7088 0 : return false;
7089 : }
7090 : }
7091 : }
7092 :
7093 0 : CPLError(CE_Failure, CPLE_AppDefined,
7094 : "Failed to reproject feature " CPL_FRMT_GIB
7095 : " (geometry probably out of source or "
7096 : "destination SRS).",
7097 : nSrcFID);
7098 0 : if (!psOptions->bSkipFailures)
7099 : {
7100 0 : return false;
7101 : }
7102 : }
7103 :
7104 : // Check if a curve geometry is no longer valid after
7105 : // reprojection
7106 125 : const auto eType = poDstGeometry->getGeometryType();
7107 125 : const auto eFlatType = wkbFlatten(eType);
7108 :
7109 4 : const auto IsValid = [](const OGRGeometry *poGeom)
7110 : {
7111 : CPLErrorHandlerPusher oErrorHandler(
7112 8 : CPLQuietErrorHandler);
7113 8 : return poGeom->IsValid();
7114 : };
7115 :
7116 124 : if (iIter == 0 && bReprojCanInvalidateValidity &&
7117 122 : OGRGeometryFactory::haveGEOS() &&
7118 120 : (eFlatType == wkbCurvePolygon ||
7119 120 : eFlatType == wkbCompoundCurve ||
7120 120 : eFlatType == wkbMultiCurve ||
7121 2 : eFlatType == wkbMultiSurface) &&
7122 251 : poDstGeometry->hasCurveGeometry(TRUE) &&
7123 2 : IsValid(poDstGeometry.get()))
7124 : {
7125 2 : OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
7126 2 : poDstGeometry->getGeometryType());
7127 : auto poDstGeometryTmp =
7128 : std::unique_ptr<OGRGeometry>(
7129 : OGRGeometryFactory::forceTo(
7130 2 : poReprojectedGeom->clone(),
7131 2 : eTargetType));
7132 2 : if (!IsValid(poDstGeometryTmp.get()))
7133 : {
7134 1 : CPLDebug("OGR2OGR",
7135 : "Curve geometry no longer valid after "
7136 : "reprojection: transforming it into "
7137 : "linear one before reprojecting");
7138 1 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
7139 : poDstGeometry.release(), eTargetType));
7140 1 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
7141 : poDstGeometry.release(), eType));
7142 : }
7143 : else
7144 : {
7145 1 : poDstGeometry = std::move(poReprojectedGeom);
7146 1 : break;
7147 : }
7148 : }
7149 : else
7150 : {
7151 123 : poDstGeometry = std::move(poReprojectedGeom);
7152 123 : break;
7153 : }
7154 124 : }
7155 : }
7156 7429 : else if (poOutputSRS != nullptr)
7157 : {
7158 6298 : poDstGeometry->assignSpatialReference(poOutputSRS);
7159 : }
7160 :
7161 7553 : if (poDstGeometry != nullptr)
7162 : {
7163 7553 : if (m_poClipDstOri)
7164 : {
7165 40 : if (poDstGeometry->IsEmpty())
7166 20 : goto end_loop;
7167 :
7168 : const auto clipGeomDesc = GetDstClipGeom(
7169 40 : poDstGeometry->getSpatialReference());
7170 40 : if (!clipGeomDesc.poGeom || !clipGeomDesc.poEnv)
7171 : {
7172 0 : goto end_loop;
7173 : }
7174 :
7175 40 : OGREnvelope oDstEnv;
7176 40 : poDstGeometry->getEnvelope(&oDstEnv);
7177 :
7178 74 : if (!(clipGeomDesc.bGeomIsRectangle &&
7179 34 : clipGeomDesc.poEnv->Contains(oDstEnv)))
7180 : {
7181 0 : std::unique_ptr<OGRGeometry> poClipped;
7182 35 : if (clipGeomDesc.poEnv->Intersects(oDstEnv))
7183 : {
7184 20 : poClipped.reset(
7185 20 : clipGeomDesc.poGeom->Intersection(
7186 20 : poDstGeometry.get()));
7187 : }
7188 :
7189 35 : if (poClipped == nullptr || poClipped->IsEmpty())
7190 : {
7191 19 : goto end_loop;
7192 : }
7193 :
7194 16 : const int nDim = poDstGeometry->getDimension();
7195 17 : if (poClipped->getDimension() < nDim &&
7196 1 : wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
7197 : ->GetType()) != wkbUnknown)
7198 : {
7199 3 : CPLDebug(
7200 : "OGR2OGR",
7201 : "Discarding feature " CPL_FRMT_GIB
7202 : " of layer %s, "
7203 : "as its intersection with -clipdst is a %s "
7204 : "whereas the input is a %s",
7205 1 : nSrcFID, poSrcLayer->GetName(),
7206 : OGRToOGCGeomType(
7207 1 : poClipped->getGeometryType()),
7208 : OGRToOGCGeomType(
7209 1 : poDstGeometry->getGeometryType()));
7210 1 : goto end_loop;
7211 : }
7212 :
7213 : poDstGeometry =
7214 45 : OGRGeometryFactory::makeCompatibleWith(
7215 15 : std::move(poClipped),
7216 15 : poDstFDefn->GetGeomFieldDefn(iGeom)
7217 15 : ->GetType());
7218 : }
7219 : }
7220 :
7221 15066 : if (psOptions->dfXYRes !=
7222 1 : OGRGeomCoordinatePrecision::UNKNOWN &&
7223 7534 : OGRGeometryFactory::haveGEOS() &&
7224 1 : !poDstGeometry->hasCurveGeometry())
7225 : {
7226 : // OGR_APPLY_GEOM_SET_PRECISION default value for
7227 : // OGRLayer::CreateFeature() purposes, but here in the
7228 : // ogr2ogr -xyRes context, we force calling SetPrecision(),
7229 : // unless the user explicitly asks not to do it by
7230 : // setting the config option to NO.
7231 1 : if (!bRunSetPrecisionEvaluated)
7232 : {
7233 1 : bRunSetPrecisionEvaluated = true;
7234 1 : bRunSetPrecision = CPLTestBool(CPLGetConfigOption(
7235 : "OGR_APPLY_GEOM_SET_PRECISION", "YES"));
7236 : }
7237 1 : if (bRunSetPrecision)
7238 : {
7239 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
7240 1 : poDstGeometry->SetPrecision(psOptions->dfXYRes,
7241 1 : /* nFlags = */ 0));
7242 1 : if (!poNewGeom)
7243 0 : goto end_loop;
7244 1 : poDstGeometry = std::move(poNewGeom);
7245 : }
7246 : }
7247 :
7248 7533 : if (m_bMakeValid)
7249 : {
7250 : const bool bIsGeomCollection =
7251 7 : wkbFlatten(poDstGeometry->getGeometryType()) ==
7252 7 : wkbGeometryCollection;
7253 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
7254 7 : poDstGeometry->MakeValid());
7255 7 : if (!poNewGeom)
7256 0 : goto end_loop;
7257 7 : poDstGeometry = std::move(poNewGeom);
7258 7 : if (!bIsGeomCollection)
7259 : {
7260 6 : poDstGeometry.reset(
7261 : OGRGeometryFactory::
7262 : removeLowerDimensionSubGeoms(
7263 6 : poDstGeometry.get()));
7264 : }
7265 : }
7266 :
7267 7533 : if (m_bSkipInvalidGeom && !poDstGeometry->IsValid())
7268 1 : goto end_loop;
7269 :
7270 7532 : if (m_eGeomTypeConversion != GTC_DEFAULT)
7271 : {
7272 : OGRwkbGeometryType eTargetType =
7273 11 : poDstGeometry->getGeometryType();
7274 : eTargetType =
7275 11 : ConvertType(m_eGeomTypeConversion, eTargetType);
7276 11 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
7277 : poDstGeometry.release(), eTargetType));
7278 : }
7279 7521 : else if (eGType != GEOMTYPE_UNCHANGED)
7280 : {
7281 59 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
7282 : poDstGeometry.release(),
7283 : static_cast<OGRwkbGeometryType>(eGType)));
7284 : }
7285 : }
7286 :
7287 7532 : poDstFeature->SetGeomFieldDirectly(iGeom,
7288 : poDstGeometry.release());
7289 : }
7290 :
7291 14549 : CPLErrorReset();
7292 29098 : if ((psOptions->bUpsert
7293 14549 : ? poDstLayer->UpsertFeature(poDstFeature.get())
7294 14549 : : poDstLayer->CreateFeature(poDstFeature.get())) ==
7295 : OGRERR_NONE)
7296 : {
7297 14542 : nFeaturesWritten++;
7298 15699 : if (nDesiredFID != OGRNullFID &&
7299 1157 : poDstFeature->GetFID() != nDesiredFID)
7300 : {
7301 0 : CPLError(CE_Warning, CPLE_AppDefined,
7302 : "Feature id " CPL_FRMT_GIB " not preserved",
7303 : nDesiredFID);
7304 : }
7305 : }
7306 7 : else if (!psOptions->bSkipFailures)
7307 : {
7308 4 : if (psOptions->nGroupTransactions)
7309 : {
7310 4 : if (psOptions->nLayerTransaction)
7311 0 : poDstLayer->RollbackTransaction();
7312 : }
7313 :
7314 4 : CPLError(CE_Failure, CPLE_AppDefined,
7315 : "Unable to write feature " CPL_FRMT_GIB
7316 : " from layer %s.",
7317 4 : nSrcFID, poSrcLayer->GetName());
7318 :
7319 4 : return false;
7320 : }
7321 : else
7322 : {
7323 3 : CPLDebug("GDALVectorTranslate",
7324 : "Unable to write feature " CPL_FRMT_GIB
7325 : " into layer %s.",
7326 3 : nSrcFID, poSrcLayer->GetName());
7327 3 : if (psOptions->nGroupTransactions)
7328 : {
7329 3 : if (psOptions->nLayerTransaction)
7330 : {
7331 2 : poDstLayer->RollbackTransaction();
7332 2 : CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());
7333 : }
7334 : else
7335 : {
7336 1 : m_poODS->RollbackTransaction();
7337 1 : m_poODS->StartTransaction(psOptions->bForceTransaction);
7338 : }
7339 : }
7340 : }
7341 :
7342 14592 : end_loop:; // nothing
7343 : }
7344 :
7345 : /* Report progress */
7346 14589 : nCount++;
7347 14589 : bool bGoOn = true;
7348 14589 : if (pfnProgress)
7349 : {
7350 5295 : bGoOn = pfnProgress(nCountLayerFeatures
7351 2646 : ? nCount * 1.0 / nCountLayerFeatures
7352 : : 1.0,
7353 : "", pProgressArg) != FALSE;
7354 : }
7355 14589 : if (!bGoOn)
7356 : {
7357 1 : bRet = false;
7358 1 : break;
7359 : }
7360 :
7361 14588 : if (pnReadFeatureCount)
7362 0 : *pnReadFeatureCount = nCount;
7363 :
7364 14588 : if (psOptions->nFIDToFetch != OGRNullFID)
7365 5 : break;
7366 14583 : if (bSingleIteration)
7367 974 : break;
7368 13609 : }
7369 :
7370 1798 : if (psOptions->nGroupTransactions)
7371 : {
7372 1797 : if (psOptions->nLayerTransaction)
7373 : {
7374 685 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
7375 0 : bRet = false;
7376 : }
7377 : }
7378 :
7379 1798 : if (!bSingleIteration)
7380 : {
7381 824 : CPLDebug("GDALVectorTranslate",
7382 : CPL_FRMT_GIB " features written in layer '%s'",
7383 824 : nFeaturesWritten, poDstLayer->GetName());
7384 : }
7385 :
7386 1798 : return bRet;
7387 : }
7388 :
7389 : /************************************************************************/
7390 : /* LayerTranslator::GetDstClipGeom() */
7391 : /************************************************************************/
7392 :
7393 : /** Returns the destination clip geometry and its envelope
7394 : *
7395 : * @param poGeomSRS The SRS into which the destination clip geometry should be
7396 : * expressed.
7397 : * @return the destination clip geometry and its envelope, or (nullptr, nullptr)
7398 : */
7399 : LayerTranslator::ClipGeomDesc
7400 40 : LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS)
7401 : {
7402 40 : if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS)
7403 : {
7404 36 : auto poClipDstSRS = m_poClipDstOri->getSpatialReference();
7405 36 : if (poClipDstSRS && poGeomSRS && !poClipDstSRS->IsSame(poGeomSRS))
7406 : {
7407 : // Transform clip geom to geometry SRS
7408 1 : m_poClipDstReprojectedToDstSRS.reset(m_poClipDstOri->clone());
7409 1 : if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) !=
7410 : OGRERR_NONE)
7411 : {
7412 0 : return ClipGeomDesc();
7413 : }
7414 1 : m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS;
7415 : }
7416 35 : else if (!poClipDstSRS && poGeomSRS)
7417 : {
7418 35 : if (!m_bWarnedClipDstSRS)
7419 : {
7420 2 : m_bWarnedClipDstSRS = true;
7421 2 : CPLError(CE_Warning, CPLE_AppDefined,
7422 : "Clip destination geometry has no "
7423 : "attached SRS, but the feature's "
7424 : "geometry has one. Assuming clip "
7425 : "destination geometry SRS is the "
7426 : "same as the feature's geometry");
7427 : }
7428 : }
7429 36 : m_oClipDstEnv = OGREnvelope();
7430 : }
7431 :
7432 : const auto poGeom = m_poClipDstReprojectedToDstSRS
7433 40 : ? m_poClipDstReprojectedToDstSRS.get()
7434 40 : : m_poClipDstOri;
7435 40 : if (poGeom && !m_oClipDstEnv.IsInit())
7436 : {
7437 40 : poGeom->getEnvelope(&m_oClipDstEnv);
7438 40 : m_bClipDstIsRectangle = poGeom->IsRectangle();
7439 : }
7440 40 : ClipGeomDesc ret;
7441 40 : ret.poGeom = poGeom;
7442 40 : ret.poEnv = poGeom ? &m_oClipDstEnv : nullptr;
7443 40 : ret.bGeomIsRectangle = m_bClipDstIsRectangle;
7444 40 : return ret;
7445 : }
7446 :
7447 : /************************************************************************/
7448 : /* LayerTranslator::GetSrcClipGeom() */
7449 : /************************************************************************/
7450 :
7451 : /** Returns the source clip geometry and its envelope
7452 : *
7453 : * @param poGeomSRS The SRS into which the source clip geometry should be
7454 : * expressed.
7455 : * @return the source clip geometry and its envelope, or (nullptr, nullptr)
7456 : */
7457 : LayerTranslator::ClipGeomDesc
7458 50 : LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS)
7459 : {
7460 50 : if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS)
7461 : {
7462 42 : auto poClipSrcSRS = m_poClipSrcOri->getSpatialReference();
7463 42 : if (poClipSrcSRS && poGeomSRS && !poClipSrcSRS->IsSame(poGeomSRS))
7464 : {
7465 : // Transform clip geom to geometry SRS
7466 1 : m_poClipSrcReprojectedToSrcSRS.reset(m_poClipSrcOri->clone());
7467 1 : if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) !=
7468 : OGRERR_NONE)
7469 : {
7470 0 : return ClipGeomDesc();
7471 : }
7472 1 : m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS;
7473 : }
7474 41 : else if (!poClipSrcSRS && poGeomSRS)
7475 : {
7476 41 : if (!m_bWarnedClipSrcSRS)
7477 : {
7478 3 : m_bWarnedClipSrcSRS = true;
7479 3 : CPLError(CE_Warning, CPLE_AppDefined,
7480 : "Clip source geometry has no attached SRS, "
7481 : "but the feature's geometry has one. "
7482 : "Assuming clip source geometry SRS is the "
7483 : "same as the feature's geometry");
7484 : }
7485 : }
7486 42 : m_oClipSrcEnv = OGREnvelope();
7487 : }
7488 :
7489 : const auto poGeom = m_poClipSrcReprojectedToSrcSRS
7490 50 : ? m_poClipSrcReprojectedToSrcSRS.get()
7491 50 : : m_poClipSrcOri;
7492 50 : if (poGeom && !m_oClipSrcEnv.IsInit())
7493 : {
7494 50 : poGeom->getEnvelope(&m_oClipSrcEnv);
7495 50 : m_bClipSrcIsRectangle = poGeom->IsRectangle();
7496 : }
7497 50 : ClipGeomDesc ret;
7498 50 : ret.poGeom = poGeom;
7499 50 : ret.poEnv = poGeom ? &m_oClipSrcEnv : nullptr;
7500 50 : ret.bGeomIsRectangle = m_bClipDstIsRectangle;
7501 50 : return ret;
7502 : }
7503 :
7504 : /************************************************************************/
7505 : /* TargetLayerInfo::CheckSameCoordinateOperation() */
7506 : /************************************************************************/
7507 :
7508 1136 : void TargetLayerInfo::CheckSameCoordinateOperation() const
7509 : {
7510 2178 : for (auto &info : m_aoReprojectionInfo)
7511 : {
7512 1042 : if (info.m_bWarnAboutDifferentCoordinateOperations &&
7513 36 : info.m_dfLeftX <= info.m_dfRightX)
7514 : {
7515 : // Start recording if different coordinate operations are
7516 : // going to be used
7517 35 : OGRProjCTDifferentOperationsStart(info.m_poCT.get());
7518 :
7519 : {
7520 70 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
7521 : {
7522 35 : double dfX = info.m_dfLeftX;
7523 35 : double dfY = info.m_dfLeftY;
7524 35 : double dfZ = info.m_dfLeftZ;
7525 35 : info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7526 : }
7527 :
7528 : {
7529 35 : double dfX = info.m_dfRightX;
7530 35 : double dfY = info.m_dfRightY;
7531 35 : double dfZ = info.m_dfRightZ;
7532 35 : info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7533 : }
7534 :
7535 : {
7536 35 : double dfX = info.m_dfTopX;
7537 35 : double dfY = info.m_dfTopY;
7538 35 : double dfZ = info.m_dfTopZ;
7539 35 : info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7540 : }
7541 :
7542 : {
7543 35 : double dfX = info.m_dfBottomX;
7544 35 : double dfY = info.m_dfBottomY;
7545 35 : double dfZ = info.m_dfBottomZ;
7546 35 : info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);
7547 : }
7548 : }
7549 :
7550 35 : if (OGRProjCTDifferentOperationsUsed(info.m_poCT.get()))
7551 : {
7552 0 : CPLError(
7553 : CE_Warning, CPLE_AppDefined,
7554 : "Several coordinate operations have been used to transform "
7555 : "layer %s. Artifacts may appear. You may consider "
7556 : "using the -ct_opt ALLOW_BALLPARK=NO and/or "
7557 : "-ct_opt ONLY_BEST=YES warping options, or specify "
7558 : "a particular coordinate operation with -ct. "
7559 : "This warning can be silenced with "
7560 : "-ct_opt WARN_ABOUT_DIFFERENT_COORD_OP=NO.",
7561 0 : m_poSrcLayer->GetName());
7562 : }
7563 :
7564 : // Stop recording
7565 35 : OGRProjCTDifferentOperationsStop(info.m_poCT.get());
7566 : }
7567 : }
7568 1136 : }
7569 :
7570 : /************************************************************************/
7571 : /* GDALVectorTranslateOptionsGetParser() */
7572 : /************************************************************************/
7573 :
7574 1025 : static std::unique_ptr<GDALArgumentParser> GDALVectorTranslateOptionsGetParser(
7575 : GDALVectorTranslateOptions *psOptions,
7576 : GDALVectorTranslateOptionsForBinary *psOptionsForBinary, int nCountClipSrc,
7577 : int nCountClipDst)
7578 : {
7579 : auto argParser = std::make_unique<GDALArgumentParser>(
7580 1025 : "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);
7581 :
7582 1025 : argParser->add_description(
7583 1025 : _("Converts simple features data between file formats."));
7584 :
7585 1025 : argParser->add_epilog(
7586 1025 : _("For more details, consult https://gdal.org/programs/ogr2ogr.html"));
7587 :
7588 1025 : argParser->add_output_format_argument(psOptions->osFormat);
7589 :
7590 1025 : argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);
7591 :
7592 1025 : argParser->add_layer_creation_options_argument(psOptions->aosLCO);
7593 :
7594 1025 : argParser->add_usage_newline();
7595 :
7596 : {
7597 1025 : auto &group = argParser->add_mutually_exclusive_group();
7598 1025 : group.add_argument("-append")
7599 1025 : .flag()
7600 35 : .action([psOptions](const std::string &)
7601 1025 : { psOptions->eAccessMode = ACCESS_APPEND; })
7602 1025 : .help(_("Append to existing layer instead of creating new."));
7603 :
7604 1025 : group.add_argument("-upsert")
7605 1025 : .flag()
7606 : .action(
7607 4 : [psOptions](const std::string &)
7608 : {
7609 4 : psOptions->eAccessMode = ACCESS_APPEND;
7610 4 : psOptions->bUpsert = true;
7611 1025 : })
7612 : .help(_("Variant of -append where the UpsertFeature() operation is "
7613 1025 : "used to insert or update features."));
7614 :
7615 1025 : group.add_argument("-overwrite")
7616 1025 : .flag()
7617 17 : .action([psOptions](const std::string &)
7618 1025 : { psOptions->eAccessMode = ACCESS_OVERWRITE; })
7619 1025 : .help(_("Delete the output layer and recreate it empty."));
7620 : }
7621 :
7622 1025 : argParser->add_argument("-update")
7623 1025 : .flag()
7624 : .action(
7625 22 : [psOptions](const std::string &)
7626 : {
7627 : /* Don't reset -append or -overwrite */
7628 8 : if (psOptions->eAccessMode != ACCESS_APPEND &&
7629 7 : psOptions->eAccessMode != ACCESS_OVERWRITE)
7630 7 : psOptions->eAccessMode = ACCESS_UPDATE;
7631 1025 : })
7632 : .help(_("Open existing output datasource in update mode rather than "
7633 1025 : "trying to create a new one."));
7634 :
7635 1025 : argParser->add_argument("-sql")
7636 2050 : .metavar("<statement>|@<filename>")
7637 : .action(
7638 24 : [psOptions](const std::string &s)
7639 : {
7640 12 : GByte *pabyRet = nullptr;
7641 15 : if (!s.empty() && s.front() == '@' &&
7642 3 : VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7643 : 10 * 1024 * 1024))
7644 : {
7645 3 : GDALRemoveBOM(pabyRet);
7646 3 : char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);
7647 : psOptions->osSQLStatement =
7648 3 : CPLRemoveSQLComments(pszSQLStatement);
7649 3 : VSIFree(pszSQLStatement);
7650 : }
7651 : else
7652 : {
7653 9 : psOptions->osSQLStatement = s;
7654 : }
7655 1037 : })
7656 1025 : .help(_("SQL statement to execute."));
7657 :
7658 1025 : argParser->add_argument("-dialect")
7659 2050 : .metavar("<dialect>")
7660 1025 : .store_into(psOptions->osDialect)
7661 1025 : .help(_("SQL dialect."));
7662 :
7663 1025 : argParser->add_argument("-spat")
7664 2050 : .metavar("<xmin> <ymin> <xmax> <ymax>")
7665 1025 : .nargs(4)
7666 1025 : .scan<'g', double>()
7667 : .help(_("Spatial query extents, in the SRS of the source layer(s) (or "
7668 1025 : "the one specified with -spat_srs."));
7669 :
7670 1025 : argParser->add_argument("-where")
7671 2050 : .metavar("<restricted_where>|@<filename>")
7672 : .action(
7673 16 : [psOptions](const std::string &s)
7674 : {
7675 8 : GByte *pabyRet = nullptr;
7676 9 : if (!s.empty() && s.front() == '@' &&
7677 1 : VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7678 : 10 * 1024 * 1024))
7679 : {
7680 1 : GDALRemoveBOM(pabyRet);
7681 1 : char *pszWHERE = reinterpret_cast<char *>(pabyRet);
7682 1 : psOptions->osWHERE = pszWHERE;
7683 1 : VSIFree(pszWHERE);
7684 : }
7685 : else
7686 : {
7687 7 : psOptions->osWHERE = s;
7688 : }
7689 1033 : })
7690 1025 : .help(_("Attribute query (like SQL WHERE)."));
7691 :
7692 1025 : argParser->add_argument("-select")
7693 2050 : .metavar("<field_list>")
7694 : .action(
7695 38 : [psOptions](const std::string &s)
7696 : {
7697 19 : psOptions->bSelFieldsSet = true;
7698 : psOptions->aosSelFields =
7699 19 : CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);
7700 1025 : })
7701 : .help(_("Comma-delimited list of fields from input layer to copy to "
7702 1025 : "the new layer."));
7703 :
7704 1025 : argParser->add_argument("-nln")
7705 2050 : .metavar("<name>")
7706 1025 : .store_into(psOptions->osNewLayerName)
7707 1025 : .help(_("Assign an alternate name to the new layer."));
7708 :
7709 1025 : argParser->add_argument("-nlt")
7710 2050 : .metavar("<type>")
7711 1025 : .append()
7712 : .action(
7713 233 : [psOptions](const std::string &osGeomNameIn)
7714 : {
7715 51 : bool bIs3D = false;
7716 102 : std::string osGeomName(osGeomNameIn);
7717 102 : if (osGeomName.size() > 3 &&
7718 51 : STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,
7719 : "25D"))
7720 : {
7721 1 : bIs3D = true;
7722 1 : osGeomName.resize(osGeomName.size() - 3);
7723 : }
7724 100 : else if (osGeomName.size() > 1 &&
7725 50 : STARTS_WITH_CI(
7726 : osGeomName.c_str() + osGeomName.size() - 1, "Z"))
7727 : {
7728 0 : bIs3D = true;
7729 0 : osGeomName.pop_back();
7730 : }
7731 51 : if (EQUAL(osGeomName.c_str(), "NONE"))
7732 : {
7733 1 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7734 : {
7735 : throw std::invalid_argument(
7736 0 : "Unsupported combination of -nlt arguments.");
7737 : }
7738 1 : psOptions->eGType = wkbNone;
7739 : }
7740 50 : else if (EQUAL(osGeomName.c_str(), "GEOMETRY"))
7741 : {
7742 4 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7743 : {
7744 : throw std::invalid_argument(
7745 0 : "Unsupported combination of -nlt arguments.");
7746 : }
7747 4 : psOptions->eGType = wkbUnknown;
7748 : }
7749 46 : else if (EQUAL(osGeomName.c_str(), "PROMOTE_TO_MULTI"))
7750 : {
7751 8 : if (psOptions->eGeomTypeConversion == GTC_CONVERT_TO_LINEAR)
7752 2 : psOptions->eGeomTypeConversion =
7753 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7754 6 : else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7755 5 : psOptions->eGeomTypeConversion = GTC_PROMOTE_TO_MULTI;
7756 : else
7757 : {
7758 : throw std::invalid_argument(
7759 1 : "Unsupported combination of -nlt arguments.");
7760 : }
7761 : }
7762 38 : else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_LINEAR"))
7763 : {
7764 12 : if (psOptions->eGeomTypeConversion == GTC_PROMOTE_TO_MULTI)
7765 2 : psOptions->eGeomTypeConversion =
7766 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7767 10 : else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7768 9 : psOptions->eGeomTypeConversion = GTC_CONVERT_TO_LINEAR;
7769 : else
7770 : {
7771 : throw std::invalid_argument(
7772 1 : "Unsupported combination of -nlt arguments.");
7773 : }
7774 : }
7775 26 : else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_CURVE"))
7776 : {
7777 7 : if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7778 5 : psOptions->eGeomTypeConversion = GTC_CONVERT_TO_CURVE;
7779 : else
7780 : {
7781 : throw std::invalid_argument(
7782 2 : "Unsupported combination of -nlt arguments.");
7783 : }
7784 : }
7785 : else
7786 : {
7787 19 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7788 : {
7789 : throw std::invalid_argument(
7790 3 : "Unsupported combination of -nlt arguments.");
7791 : }
7792 16 : psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());
7793 16 : if (psOptions->eGType == wkbUnknown)
7794 : {
7795 : throw std::invalid_argument(
7796 : CPLSPrintf("-nlt %s: type not recognised.",
7797 0 : osGeomName.c_str()));
7798 : }
7799 : }
7800 44 : if (psOptions->eGType != GEOMTYPE_UNCHANGED &&
7801 25 : psOptions->eGType != wkbNone && bIs3D)
7802 1 : psOptions->eGType = wkbSetZ(
7803 : static_cast<OGRwkbGeometryType>(psOptions->eGType));
7804 1069 : })
7805 1025 : .help(_("Define the geometry type for the created layer."));
7806 :
7807 1025 : argParser->add_argument("-s_srs")
7808 2050 : .metavar("<srs_def>")
7809 1025 : .store_into(psOptions->osSourceSRSDef)
7810 1025 : .help(_("Set/override source SRS."));
7811 :
7812 : {
7813 1025 : auto &group = argParser->add_mutually_exclusive_group();
7814 1025 : group.add_argument("-a_srs")
7815 2050 : .metavar("<srs_def>")
7816 : .action(
7817 353 : [psOptions](const std::string &osOutputSRSDef)
7818 : {
7819 115 : psOptions->osOutputSRSDef = osOutputSRSDef;
7820 230 : if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||
7821 115 : EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))
7822 : {
7823 4 : psOptions->osOutputSRSDef.clear();
7824 4 : psOptions->bNullifyOutputSRS = true;
7825 : }
7826 1025 : })
7827 1025 : .help(_("Assign an output SRS, but without reprojecting."));
7828 :
7829 1025 : group.add_argument("-t_srs")
7830 2050 : .metavar("<srs_def>")
7831 : .action(
7832 72 : [psOptions](const std::string &osOutputSRSDef)
7833 : {
7834 36 : psOptions->osOutputSRSDef = osOutputSRSDef;
7835 36 : psOptions->bTransform = true;
7836 1025 : })
7837 : .help(_("Reproject/transform to this SRS on output, and assign it "
7838 1025 : "as output SRS."));
7839 : }
7840 :
7841 : ///////////////////////////////////////////////////////////////////////
7842 1025 : argParser->add_group("Field related options");
7843 :
7844 1025 : argParser->add_argument("-addfields")
7845 1025 : .flag()
7846 : .action(
7847 2 : [psOptions](const std::string &)
7848 : {
7849 2 : psOptions->bAddMissingFields = true;
7850 2 : psOptions->eAccessMode = ACCESS_APPEND;
7851 1025 : })
7852 1025 : .help(_("Same as append, but add also any new fields."));
7853 :
7854 1025 : argParser->add_argument("-relaxedFieldNameMatch")
7855 1025 : .flag()
7856 1 : .action([psOptions](const std::string &)
7857 1025 : { psOptions->bExactFieldNameMatch = false; })
7858 : .help(_("Do field name matching between source and existing target "
7859 1025 : "layer in a more relaxed way."));
7860 :
7861 1025 : argParser->add_argument("-fieldTypeToString")
7862 2050 : .metavar("All|<type1>[,<type2>]...")
7863 : .action(
7864 0 : [psOptions](const std::string &s)
7865 : {
7866 : psOptions->aosFieldTypesToString =
7867 0 : CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7868 0 : CSLConstList iter = psOptions->aosFieldTypesToString.List();
7869 0 : while (*iter)
7870 : {
7871 0 : if (IsFieldType(*iter))
7872 : {
7873 : /* Do nothing */
7874 : }
7875 0 : else if (EQUAL(*iter, "All"))
7876 : {
7877 0 : psOptions->aosFieldTypesToString.Clear();
7878 0 : psOptions->aosFieldTypesToString.AddString("All");
7879 0 : break;
7880 : }
7881 : else
7882 : {
7883 : throw std::invalid_argument(CPLSPrintf(
7884 : "Unhandled type for fieldTypeToString option : %s",
7885 0 : *iter));
7886 : }
7887 0 : iter++;
7888 : }
7889 1025 : })
7890 : .help(_("Converts any field of the specified type to a field of type "
7891 1025 : "string in the destination layer."));
7892 :
7893 1025 : argParser->add_argument("-mapFieldType")
7894 2050 : .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...")
7895 : .action(
7896 12 : [psOptions](const std::string &s)
7897 : {
7898 : psOptions->aosMapFieldType =
7899 4 : CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7900 4 : CSLConstList iter = psOptions->aosMapFieldType.List();
7901 8 : while (*iter)
7902 : {
7903 4 : char *pszKey = nullptr;
7904 4 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
7905 4 : if (pszKey && pszValue)
7906 : {
7907 8 : if (!((IsFieldType(pszKey) || EQUAL(pszKey, "All")) &&
7908 4 : IsFieldType(pszValue)))
7909 : {
7910 0 : CPLFree(pszKey);
7911 : throw std::invalid_argument(CPLSPrintf(
7912 0 : "Invalid value for -mapFieldType : %s", *iter));
7913 : }
7914 : }
7915 4 : CPLFree(pszKey);
7916 4 : iter++;
7917 : }
7918 1029 : })
7919 1025 : .help(_("Converts any field of the specified type to another type."));
7920 :
7921 1025 : argParser->add_argument("-fieldmap")
7922 2050 : .metavar("<field_1>[,<field_2>]...")
7923 : .action(
7924 4 : [psOptions](const std::string &s)
7925 : {
7926 : psOptions->aosFieldMap =
7927 2 : CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);
7928 1025 : })
7929 : .help(_("Specifies the list of field indexes to be copied from the "
7930 1025 : "source to the destination."));
7931 :
7932 1025 : argParser->add_argument("-splitlistfields")
7933 1025 : .store_into(psOptions->bSplitListFields)
7934 : .help(_("Split fields of type list type into as many fields of scalar "
7935 1025 : "type as necessary."));
7936 :
7937 1025 : argParser->add_argument("-maxsubfields")
7938 2050 : .metavar("<n>")
7939 1025 : .scan<'i', int>()
7940 : .action(
7941 0 : [psOptions](const std::string &s)
7942 : {
7943 0 : const int nVal = atoi(s.c_str());
7944 0 : if (nVal > 0)
7945 : {
7946 0 : psOptions->nMaxSplitListSubFields = nVal;
7947 : }
7948 1025 : })
7949 : .help(_("To be combined with -splitlistfields to limit the number of "
7950 1025 : "subfields created for each split field."));
7951 :
7952 1025 : argParser->add_argument("-emptyStrAsNull")
7953 1025 : .store_into(psOptions->bEmptyStrAsNull)
7954 1025 : .help(_("Treat empty string values as null."));
7955 :
7956 1025 : argParser->add_argument("-forceNullable")
7957 1025 : .store_into(psOptions->bForceNullable)
7958 : .help(_("Do not propagate not-nullable constraints to target layer if "
7959 1025 : "they exist in source layer."));
7960 :
7961 1025 : argParser->add_argument("-unsetFieldWidth")
7962 1025 : .store_into(psOptions->bUnsetFieldWidth)
7963 1025 : .help(_("Set field width and precision to 0."));
7964 :
7965 1025 : argParser->add_argument("-unsetDefault")
7966 1025 : .store_into(psOptions->bUnsetDefault)
7967 : .help(_("Do not propagate default field values to target layer if they "
7968 1025 : "exist in source layer."));
7969 :
7970 1025 : argParser->add_argument("-resolveDomains")
7971 1025 : .store_into(psOptions->bResolveDomains)
7972 : .help(_("Cause any selected field that is linked to a coded field "
7973 1025 : "domain will be accompanied by an additional field."));
7974 :
7975 1025 : argParser->add_argument("-dateTimeTo")
7976 2050 : .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>")
7977 : .action(
7978 33 : [psOptions](const std::string &s)
7979 : {
7980 13 : const char *pszFormat = s.c_str();
7981 13 : if (EQUAL(pszFormat, "UTC"))
7982 : {
7983 1 : psOptions->nTZOffsetInSec = 0;
7984 : }
7985 12 : else if (STARTS_WITH_CI(pszFormat, "UTC") &&
7986 11 : (strlen(pszFormat) == strlen("UTC+HH") ||
7987 9 : strlen(pszFormat) == strlen("UTC+HH:MM")) &&
7988 7 : (pszFormat[3] == '+' || pszFormat[3] == '-'))
7989 : {
7990 6 : const int nHour = atoi(pszFormat + strlen("UTC+"));
7991 6 : if (nHour < 0 || nHour > 14)
7992 : {
7993 1 : throw std::invalid_argument("Invalid UTC hour offset.");
7994 : }
7995 5 : else if (strlen(pszFormat) == strlen("UTC+HH"))
7996 : {
7997 0 : psOptions->nTZOffsetInSec = nHour * 3600;
7998 0 : if (pszFormat[3] == '-')
7999 0 : psOptions->nTZOffsetInSec =
8000 0 : -psOptions->nTZOffsetInSec;
8001 : }
8002 : else // if( strlen(pszFormat) == strlen("UTC+HH:MM") )
8003 : {
8004 5 : const int nMin = atoi(pszFormat + strlen("UTC+HH:"));
8005 5 : if (nMin == 0 || nMin == 15 || nMin == 30 || nMin == 45)
8006 : {
8007 4 : psOptions->nTZOffsetInSec =
8008 4 : nHour * 3600 + nMin * 60;
8009 4 : if (pszFormat[3] == '-')
8010 3 : psOptions->nTZOffsetInSec =
8011 3 : -psOptions->nTZOffsetInSec;
8012 : }
8013 : }
8014 : }
8015 12 : if (psOptions->nTZOffsetInSec == TZ_OFFSET_INVALID)
8016 : {
8017 : throw std::invalid_argument(
8018 : "Value of -dateTimeTo should be UTC, UTC(+|-)HH or "
8019 7 : "UTC(+|-)HH:MM with HH in [0,14] and MM=00,15,30,45");
8020 : }
8021 1030 : })
8022 : .help(_("Converts date time values from the timezone specified in the "
8023 1025 : "source value to the target timezone."));
8024 :
8025 1025 : argParser->add_argument("-noNativeData")
8026 1025 : .flag()
8027 1 : .action([psOptions](const std::string &)
8028 1025 : { psOptions->bNativeData = false; })
8029 1025 : .help(_("Disable copying of native data."));
8030 :
8031 : ///////////////////////////////////////////////////////////////////////
8032 1025 : argParser->add_group("Advanced geometry and SRS related options");
8033 :
8034 1025 : argParser->add_argument("-dim")
8035 2050 : .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM")
8036 : .action(
8037 24 : [psOptions](const std::string &osDim)
8038 : {
8039 12 : if (EQUAL(osDim.c_str(), "layer_dim"))
8040 2 : psOptions->nCoordDim = COORD_DIM_LAYER_DIM;
8041 18 : else if (EQUAL(osDim.c_str(), "XY") ||
8042 8 : EQUAL(osDim.c_str(), "2"))
8043 3 : psOptions->nCoordDim = 2;
8044 12 : else if (EQUAL(osDim.c_str(), "XYZ") ||
8045 5 : EQUAL(osDim.c_str(), "3"))
8046 3 : psOptions->nCoordDim = 3;
8047 4 : else if (EQUAL(osDim.c_str(), "XYM"))
8048 2 : psOptions->nCoordDim = COORD_DIM_XYM;
8049 2 : else if (EQUAL(osDim.c_str(), "XYZM"))
8050 2 : psOptions->nCoordDim = 4;
8051 : else
8052 : {
8053 : throw std::invalid_argument(CPLSPrintf(
8054 0 : "-dim %s: value not handled.", osDim.c_str()));
8055 : }
8056 1037 : })
8057 1025 : .help(_("Force the coordinate dimension."));
8058 :
8059 1025 : argParser->add_argument("-s_coord_epoch")
8060 2050 : .metavar("<epoch>")
8061 1025 : .store_into(psOptions->dfSourceCoordinateEpoch)
8062 1025 : .help(_("Assign a coordinate epoch, linked with the source SRS."));
8063 :
8064 1025 : argParser->add_argument("-a_coord_epoch")
8065 2050 : .metavar("<epoch>")
8066 1025 : .store_into(psOptions->dfOutputCoordinateEpoch)
8067 : .help(_("Assign a coordinate epoch, linked with the output SRS when "
8068 1025 : "-a_srs is used."));
8069 :
8070 1025 : argParser->add_argument("-t_coord_epoch")
8071 2050 : .metavar("<epoch>")
8072 1025 : .store_into(psOptions->dfOutputCoordinateEpoch)
8073 : .help(_("Assign a coordinate epoch, linked with the output SRS when "
8074 1025 : "-t_srs is used."));
8075 :
8076 1025 : argParser->add_argument("-ct")
8077 2050 : .metavar("<pipeline_def>")
8078 : .action(
8079 8 : [psOptions](const std::string &s)
8080 : {
8081 4 : psOptions->osCTPipeline = s;
8082 4 : psOptions->bTransform = true;
8083 1025 : })
8084 : .help(_("Override the default transformation from the source to the "
8085 1025 : "target CRS."));
8086 :
8087 1025 : argParser->add_argument("-ct_opt")
8088 2050 : .metavar("<NAME>=<VALUE>")
8089 1025 : .append()
8090 0 : .action([psOptions](const std::string &s)
8091 1025 : { psOptions->aosCTOptions.AddString(s.c_str()); })
8092 1025 : .help(_("Coordinate transform option(s)."));
8093 :
8094 1025 : argParser->add_argument("-spat_srs")
8095 2050 : .metavar("<srs_def>")
8096 1025 : .store_into(psOptions->osSpatSRSDef)
8097 1025 : .help(_("Override spatial filter SRS."));
8098 :
8099 1025 : argParser->add_argument("-geomfield")
8100 2050 : .metavar("<name>")
8101 : .action(
8102 2 : [psOptions](const std::string &s)
8103 : {
8104 1 : psOptions->osGeomField = s;
8105 1 : psOptions->bGeomFieldSet = true;
8106 1025 : })
8107 : .help(_("Name of the geometry field on which the spatial filter "
8108 1025 : "operates on."));
8109 :
8110 1025 : argParser->add_argument("-segmentize")
8111 2050 : .metavar("<max_dist>")
8112 1025 : .store_into(psOptions->dfGeomOpParam)
8113 2 : .action([psOptions](const std::string &)
8114 1025 : { psOptions->eGeomOp = GEOMOP_SEGMENTIZE; })
8115 1025 : .help(_("Maximum distance between 2 nodes."));
8116 :
8117 1025 : argParser->add_argument("-simplify")
8118 2050 : .metavar("<tolerance>")
8119 1025 : .store_into(psOptions->dfGeomOpParam)
8120 1 : .action([psOptions](const std::string &)
8121 1025 : { psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY; })
8122 1025 : .help(_("Distance tolerance for simplification."));
8123 :
8124 1025 : argParser->add_argument("-makevalid")
8125 1025 : .flag()
8126 : .action(
8127 10 : [psOptions](const std::string &)
8128 : {
8129 5 : if (!OGRGeometryFactory::haveGEOS())
8130 : {
8131 : throw std::invalid_argument(
8132 0 : "-makevalid only supported for builds against GEOS");
8133 : }
8134 5 : psOptions->bMakeValid = true;
8135 1030 : })
8136 : .help(_("Fix geometries to be valid regarding the rules of the Simple "
8137 1025 : "Features specification."));
8138 :
8139 1025 : argParser->add_argument("-skipinvalid")
8140 1025 : .flag()
8141 : .action(
8142 2 : [psOptions](const std::string &)
8143 : {
8144 1 : if (!OGRGeometryFactory::haveGEOS())
8145 : {
8146 : throw std::invalid_argument(
8147 0 : "-skipinvalid only supported for builds against GEOS");
8148 : }
8149 1 : psOptions->bSkipInvalidGeom = true;
8150 1026 : })
8151 : .help(_("Whether to skip features with invalid geometries regarding the"
8152 1025 : "rules of the Simple Features specification."));
8153 :
8154 1025 : argParser->add_argument("-wrapdateline")
8155 1025 : .store_into(psOptions->bWrapDateline)
8156 1025 : .help(_("Split geometries crossing the dateline meridian."));
8157 :
8158 1025 : argParser->add_argument("-datelineoffset")
8159 2050 : .metavar("<val_in_degree>")
8160 1025 : .default_value(psOptions->dfDateLineOffset)
8161 1025 : .store_into(psOptions->dfDateLineOffset)
8162 1025 : .help(_("Offset from dateline in degrees."));
8163 :
8164 : auto &clipsrcArg =
8165 1025 : argParser->add_argument("-clipsrc")
8166 : .metavar(
8167 2050 : "[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
8168 1025 : .help(_("Clip geometries (in source SRS)."));
8169 1025 : if (nCountClipSrc > 1)
8170 1 : clipsrcArg.nargs(nCountClipSrc);
8171 :
8172 1025 : argParser->add_argument("-clipsrcsql")
8173 2050 : .metavar("<sql_statement>")
8174 1025 : .store_into(psOptions->osClipSrcSQL)
8175 : .help(_("Select desired geometries from the source clip datasource "
8176 1025 : "using an SQL query."));
8177 :
8178 1025 : argParser->add_argument("-clipsrclayer")
8179 2050 : .metavar("<layername>")
8180 1025 : .store_into(psOptions->osClipSrcLayer)
8181 1025 : .help(_("Select the named layer from the source clip datasource."));
8182 :
8183 1025 : argParser->add_argument("-clipsrcwhere")
8184 2050 : .metavar("<expression>")
8185 1025 : .store_into(psOptions->osClipSrcWhere)
8186 : .help(_("Restrict desired geometries from the source clip layer based "
8187 1025 : "on an attribute query."));
8188 :
8189 : auto &clipdstArg =
8190 1025 : argParser->add_argument("-clipdst")
8191 2050 : .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>")
8192 1025 : .help(_("Clip geometries (in target SRS)."));
8193 1025 : if (nCountClipDst > 1)
8194 2 : clipdstArg.nargs(nCountClipDst);
8195 :
8196 1025 : argParser->add_argument("-clipdstsql")
8197 2050 : .metavar("<sql_statement>")
8198 1025 : .store_into(psOptions->osClipDstSQL)
8199 : .help(_("Select desired geometries from the destination clip "
8200 1025 : "datasource using an SQL query."));
8201 :
8202 1025 : argParser->add_argument("-clipdstlayer")
8203 2050 : .metavar("<layername>")
8204 1025 : .store_into(psOptions->osClipDstLayer)
8205 : .help(
8206 1025 : _("Select the named layer from the destination clip datasource."));
8207 :
8208 1025 : argParser->add_argument("-clipdstwhere")
8209 2050 : .metavar("<expression>")
8210 1025 : .store_into(psOptions->osClipDstWhere)
8211 : .help(_("Restrict desired geometries from the destination clip layer "
8212 1025 : "based on an attribute query."));
8213 :
8214 1025 : argParser->add_argument("-explodecollections")
8215 1025 : .store_into(psOptions->bExplodeCollections)
8216 : .help(_("Produce one feature for each geometry in any kind of geometry "
8217 1025 : "collection in the source file."));
8218 :
8219 1025 : argParser->add_argument("-zfield")
8220 2050 : .metavar("<name>")
8221 1025 : .store_into(psOptions->osZField)
8222 : .help(_("Uses the specified field to fill the Z coordinate of "
8223 1025 : "geometries."));
8224 :
8225 1025 : argParser->add_argument("-gcp")
8226 : .metavar(
8227 2050 : "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")
8228 1025 : .nargs(4, 5)
8229 1025 : .append()
8230 1025 : .scan<'g', double>()
8231 1025 : .help(_("Add the indicated ground control point."));
8232 :
8233 1025 : argParser->add_argument("-tps")
8234 1025 : .flag()
8235 1 : .action([psOptions](const std::string &)
8236 1025 : { psOptions->nTransformOrder = -1; })
8237 : .help(_("Force use of thin plate spline transformer based on available "
8238 1025 : "GCPs."));
8239 :
8240 1025 : argParser->add_argument("-order")
8241 2050 : .metavar("1|2|3")
8242 1025 : .store_into(psOptions->nTransformOrder)
8243 1025 : .help(_("Order of polynomial used for warping."));
8244 :
8245 1025 : argParser->add_argument("-xyRes")
8246 2050 : .metavar("<val>[ m|mm|deg]")
8247 : .action(
8248 25 : [psOptions](const std::string &s)
8249 : {
8250 9 : const char *pszVal = s.c_str();
8251 :
8252 9 : char *endptr = nullptr;
8253 9 : psOptions->dfXYRes = CPLStrtodM(pszVal, &endptr);
8254 9 : if (!endptr)
8255 : {
8256 : throw std::invalid_argument(
8257 : "Invalid value for -xyRes. Must be of the form "
8258 0 : "{numeric_value}[ ]?[m|mm|deg]?");
8259 : }
8260 9 : if (*endptr == ' ')
8261 6 : ++endptr;
8262 9 : if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
8263 5 : strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
8264 : {
8265 : throw std::invalid_argument(
8266 : "Invalid value for -xyRes. Must be of the form "
8267 2 : "{numeric_value}[ ]?[m|mm|deg]?");
8268 : }
8269 7 : psOptions->osXYResUnit = endptr;
8270 1032 : })
8271 1025 : .help(_("Set/override the geometry X/Y coordinate resolution."));
8272 :
8273 1025 : argParser->add_argument("-zRes")
8274 2050 : .metavar("<val>[ m|mm]")
8275 : .action(
8276 16 : [psOptions](const std::string &s)
8277 : {
8278 6 : const char *pszVal = s.c_str();
8279 :
8280 6 : char *endptr = nullptr;
8281 6 : psOptions->dfZRes = CPLStrtodM(pszVal, &endptr);
8282 6 : if (!endptr)
8283 : {
8284 : throw std::invalid_argument(
8285 : "Invalid value for -zRes. Must be of the form "
8286 0 : "{numeric_value}[ ]?[m|mm]?");
8287 : }
8288 6 : if (*endptr == ' ')
8289 4 : ++endptr;
8290 6 : if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
8291 3 : strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
8292 : {
8293 : throw std::invalid_argument(
8294 : "Invalid value for -zRes. Must be of the form "
8295 2 : "{numeric_value}[ ]?[m|mm]?");
8296 : }
8297 4 : psOptions->osZResUnit = endptr;
8298 1029 : })
8299 1025 : .help(_("Set/override the geometry Z coordinate resolution."));
8300 :
8301 1025 : argParser->add_argument("-mRes")
8302 2050 : .metavar("<val>")
8303 1025 : .store_into(psOptions->dfMRes)
8304 1025 : .help(_("Set/override the geometry M coordinate resolution."));
8305 :
8306 1025 : argParser->add_argument("-unsetCoordPrecision")
8307 1025 : .store_into(psOptions->bUnsetCoordPrecision)
8308 : .help(_("Prevent the geometry coordinate resolution from being set on "
8309 1025 : "target layer(s)."));
8310 :
8311 : ///////////////////////////////////////////////////////////////////////
8312 1025 : argParser->add_group("Other options");
8313 :
8314 1025 : argParser->add_quiet_argument(&psOptions->bQuiet);
8315 :
8316 1025 : argParser->add_argument("-progress")
8317 1025 : .store_into(psOptions->bDisplayProgress)
8318 : .help(_("Display progress on terminal. Only works if input layers have "
8319 1025 : "the 'fast feature count' capability."));
8320 :
8321 : argParser->add_input_format_argument(
8322 : psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers
8323 1025 : : nullptr);
8324 :
8325 : argParser->add_open_options_argument(
8326 1025 : psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);
8327 :
8328 1025 : argParser->add_argument("-doo")
8329 2050 : .metavar("<NAME>=<VALUE>")
8330 1025 : .append()
8331 0 : .action([psOptions](const std::string &s)
8332 1025 : { psOptions->aosDestOpenOptions.AddString(s.c_str()); })
8333 1025 : .help(_("Open option(s) for output dataset."));
8334 :
8335 1025 : argParser->add_usage_newline();
8336 :
8337 1025 : argParser->add_argument("-fid")
8338 2050 : .metavar("<FID>")
8339 1025 : .store_into(psOptions->nFIDToFetch)
8340 : .help(_("If provided, only the feature with the specified feature id "
8341 1025 : "will be processed."));
8342 :
8343 1025 : argParser->add_argument("-preserve_fid")
8344 1025 : .store_into(psOptions->bPreserveFID)
8345 : .help(_("Use the FID of the source features instead of letting the "
8346 1025 : "output driver automatically assign a new one."));
8347 :
8348 1025 : argParser->add_argument("-unsetFid")
8349 1025 : .store_into(psOptions->bUnsetFid)
8350 : .help(_("Prevent the name of the source FID column and source feature "
8351 1025 : "IDs from being reused."));
8352 :
8353 : {
8354 1025 : auto &group = argParser->add_mutually_exclusive_group();
8355 1025 : group.add_argument("-skip", "-skipfailures")
8356 1025 : .flag()
8357 : .action(
8358 6 : [psOptions](const std::string &)
8359 : {
8360 6 : psOptions->bSkipFailures = true;
8361 6 : psOptions->nGroupTransactions = 1; /* #2409 */
8362 1025 : })
8363 1025 : .help(_("Continue after a failure, skipping the failed feature."));
8364 :
8365 1025 : auto &arg = group.add_argument("-gt")
8366 2050 : .metavar("<n>|unlimited")
8367 : .action(
8368 8 : [psOptions](const std::string &s)
8369 : {
8370 : /* If skipfailures is already set we should not
8371 : modify nGroupTransactions = 1 #2409 */
8372 4 : if (!psOptions->bSkipFailures)
8373 : {
8374 4 : if (EQUAL(s.c_str(), "unlimited"))
8375 1 : psOptions->nGroupTransactions = -1;
8376 : else
8377 3 : psOptions->nGroupTransactions =
8378 3 : atoi(s.c_str());
8379 : }
8380 1025 : })
8381 1025 : .help(_("Group <n> features per transaction "));
8382 :
8383 1025 : argParser->add_hidden_alias_for(arg, "tg");
8384 : }
8385 :
8386 1025 : argParser->add_argument("-limit")
8387 2050 : .metavar("<nb_features>")
8388 1025 : .store_into(psOptions->nLimit)
8389 1025 : .help(_("Limit the number of features per layer."));
8390 :
8391 1025 : argParser->add_argument("-ds_transaction")
8392 1025 : .flag()
8393 : .action(
8394 1 : [psOptions](const std::string &)
8395 : {
8396 1 : psOptions->nLayerTransaction = FALSE;
8397 1 : psOptions->bForceTransaction = true;
8398 1025 : })
8399 1025 : .help(_("Force the use of a dataset level transaction."));
8400 :
8401 : /* Undocumented. Just a provision. Default behavior should be OK */
8402 1025 : argParser->add_argument("-lyr_transaction")
8403 1025 : .flag()
8404 1025 : .hidden()
8405 0 : .action([psOptions](const std::string &)
8406 1025 : { psOptions->nLayerTransaction = TRUE; })
8407 1025 : .help(_("Force the use of a layer level transaction."));
8408 :
8409 : argParser->add_metadata_item_options_argument(
8410 1025 : psOptions->aosMetadataOptions);
8411 :
8412 1025 : argParser->add_argument("-nomd")
8413 1025 : .flag()
8414 4 : .action([psOptions](const std::string &)
8415 1025 : { psOptions->bCopyMD = false; })
8416 : .help(_("Disable copying of metadata from source dataset and layers "
8417 1025 : "into target dataset and layers."));
8418 :
8419 : // Undocumented option used by gdal vector convert
8420 1025 : argParser->add_argument("--no-overwrite")
8421 1025 : .store_into(psOptions->bNoOverwrite)
8422 1025 : .hidden();
8423 :
8424 : // Undocumented option used by gdal vector convert
8425 1025 : argParser->add_argument("--invoked-from-gdal-vector-convert")
8426 1025 : .store_into(psOptions->bInvokedFromGdalVectorConvert)
8427 1025 : .hidden();
8428 :
8429 1025 : if (psOptionsForBinary)
8430 : {
8431 133 : argParser->add_argument("dst_dataset_name")
8432 266 : .metavar("<dst_dataset_name>")
8433 133 : .store_into(psOptionsForBinary->osDestDataSource)
8434 133 : .help(_("Output dataset."));
8435 :
8436 133 : argParser->add_argument("src_dataset_name")
8437 266 : .metavar("<src_dataset_name>")
8438 133 : .store_into(psOptionsForBinary->osDataSource)
8439 133 : .help(_("Input dataset."));
8440 : }
8441 :
8442 1025 : argParser->add_argument("layer")
8443 1025 : .remaining()
8444 2050 : .metavar("<layer_name>")
8445 1025 : .help(_("Layer name"));
8446 1025 : return argParser;
8447 : }
8448 :
8449 : /************************************************************************/
8450 : /* GDALVectorTranslateGetParserUsage() */
8451 : /************************************************************************/
8452 :
8453 1 : std::string GDALVectorTranslateGetParserUsage()
8454 : {
8455 : try
8456 : {
8457 2 : GDALVectorTranslateOptions sOptions;
8458 2 : GDALVectorTranslateOptionsForBinary sOptionsForBinary;
8459 : auto argParser = GDALVectorTranslateOptionsGetParser(
8460 2 : &sOptions, &sOptionsForBinary, 1, 1);
8461 1 : return argParser->usage();
8462 : }
8463 0 : catch (const std::exception &err)
8464 : {
8465 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
8466 0 : err.what());
8467 0 : return std::string();
8468 : }
8469 : }
8470 :
8471 : /************************************************************************/
8472 : /* CHECK_HAS_ENOUGH_ADDITIONAL_ARGS() */
8473 : /************************************************************************/
8474 :
8475 : #ifndef CheckHasEnoughAdditionalArgs_defined
8476 : #define CheckHasEnoughAdditionalArgs_defined
8477 :
8478 57 : static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,
8479 : int nExtraArg, int nArgc)
8480 : {
8481 57 : if (i + nExtraArg >= nArgc)
8482 : {
8483 2 : CPLError(CE_Failure, CPLE_IllegalArg,
8484 2 : "%s option requires %d argument%s", papszArgv[i], nExtraArg,
8485 : nExtraArg == 1 ? "" : "s");
8486 2 : return false;
8487 : }
8488 55 : return true;
8489 : }
8490 : #endif
8491 :
8492 : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
8493 : if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc)) \
8494 : { \
8495 : return nullptr; \
8496 : }
8497 :
8498 : /************************************************************************/
8499 : /* GDALVectorTranslateOptionsNew() */
8500 : /************************************************************************/
8501 :
8502 : /**
8503 : * allocates a GDALVectorTranslateOptions struct.
8504 : *
8505 : * @param papszArgv NULL terminated list of options (potentially including
8506 : * filename and open options too), or NULL. The accepted options are the ones of
8507 : * the <a href="/programs/ogr2ogr.html">ogr2ogr</a> utility.
8508 : * @param psOptionsForBinary (output) may be NULL (and should generally be
8509 : * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
8510 : * GDALVectorTranslateOptionsForBinaryNew() prior to
8511 : * this function. Will be filled with potentially present filename, open
8512 : * options,...
8513 : * @return pointer to the allocated GDALVectorTranslateOptions struct. Must be
8514 : * freed with GDALVectorTranslateOptionsFree().
8515 : *
8516 : * @since GDAL 2.1
8517 : */
8518 1028 : GDALVectorTranslateOptions *GDALVectorTranslateOptionsNew(
8519 : char **papszArgv, GDALVectorTranslateOptionsForBinary *psOptionsForBinary)
8520 : {
8521 2056 : auto psOptions = std::make_unique<GDALVectorTranslateOptions>();
8522 :
8523 : /* -------------------------------------------------------------------- */
8524 : /* Pre-processing for custom syntax that ArgumentParser does not */
8525 : /* support. */
8526 : /* -------------------------------------------------------------------- */
8527 :
8528 2056 : CPLStringList aosArgv;
8529 1028 : const int nArgc = CSLCount(papszArgv);
8530 1028 : int nCountClipSrc = 0;
8531 1028 : int nCountClipDst = 0;
8532 4726 : for (int i = 0;
8533 4726 : i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
8534 : {
8535 3702 : if (EQUAL(papszArgv[i], "-gcp"))
8536 : {
8537 : // repeated argument of varying size: not handled by argparse.
8538 :
8539 18 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
8540 18 : char *endptr = nullptr;
8541 : /* -gcp pixel line easting northing [elev] */
8542 :
8543 18 : psOptions->asGCPs.resize(psOptions->asGCPs.size() + 1);
8544 18 : auto &sGCP = psOptions->asGCPs.back();
8545 :
8546 18 : sGCP.Pixel() = CPLAtof(papszArgv[++i]);
8547 18 : sGCP.Line() = CPLAtof(papszArgv[++i]);
8548 18 : sGCP.X() = CPLAtof(papszArgv[++i]);
8549 18 : sGCP.Y() = CPLAtof(papszArgv[++i]);
8550 33 : if (papszArgv[i + 1] != nullptr &&
8551 15 : (CPLStrtod(papszArgv[i + 1], &endptr) != 0.0 ||
8552 15 : papszArgv[i + 1][0] == '0'))
8553 : {
8554 : /* Check that last argument is really a number and not a
8555 : * filename */
8556 : /* looking like a number (see ticket #863) */
8557 0 : if (endptr && *endptr == 0)
8558 0 : sGCP.Z() = CPLAtof(papszArgv[++i]);
8559 : }
8560 :
8561 : /* should set id and info? */
8562 : }
8563 :
8564 3684 : else if (EQUAL(papszArgv[i], "-clipsrc"))
8565 : {
8566 23 : if (nCountClipSrc)
8567 : {
8568 1 : CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
8569 1 : papszArgv[i]);
8570 1 : return nullptr;
8571 : }
8572 : // argparse doesn't handle well variable number of values
8573 : // just before the positional arguments, so we have to detect
8574 : // it manually and set the correct number.
8575 22 : nCountClipSrc = 1;
8576 22 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8577 24 : if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8578 3 : i + 4 < nArgc)
8579 : {
8580 2 : nCountClipSrc = 4;
8581 : }
8582 :
8583 69 : for (int j = 0; j < 1 + nCountClipSrc; ++j)
8584 : {
8585 48 : aosArgv.AddString(papszArgv[i]);
8586 48 : ++i;
8587 : }
8588 21 : --i;
8589 : }
8590 :
8591 3661 : else if (EQUAL(papszArgv[i], "-clipdst"))
8592 : {
8593 18 : if (nCountClipDst)
8594 : {
8595 1 : CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
8596 1 : papszArgv[i]);
8597 1 : return nullptr;
8598 : }
8599 : // argparse doesn't handle well variable number of values
8600 : // just before the positional arguments, so we have to detect
8601 : // it manually and set the correct number.
8602 17 : nCountClipDst = 1;
8603 17 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8604 20 : if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8605 4 : i + 4 < nArgc)
8606 : {
8607 3 : nCountClipDst = 4;
8608 : }
8609 :
8610 57 : for (int j = 0; j < 1 + nCountClipDst; ++j)
8611 : {
8612 41 : aosArgv.AddString(papszArgv[i]);
8613 41 : ++i;
8614 : }
8615 16 : --i;
8616 : }
8617 :
8618 : else
8619 : {
8620 3643 : aosArgv.AddString(papszArgv[i]);
8621 : }
8622 : }
8623 :
8624 : try
8625 : {
8626 : auto argParser = GDALVectorTranslateOptionsGetParser(
8627 2048 : psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);
8628 :
8629 : // Collect non-positional arguments for VectorTranslateFrom() case
8630 1023 : psOptions->aosArguments =
8631 2047 : argParser->get_non_positional_arguments(aosArgv);
8632 :
8633 1023 : argParser->parse_args_without_binary_name(aosArgv.List());
8634 :
8635 1000 : if (psOptionsForBinary)
8636 131 : psOptionsForBinary->bQuiet = psOptions->bQuiet;
8637 :
8638 1008 : if (auto oSpat = argParser->present<std::vector<double>>("-spat"))
8639 : {
8640 8 : const double dfMinX = (*oSpat)[0];
8641 8 : const double dfMinY = (*oSpat)[1];
8642 8 : const double dfMaxX = (*oSpat)[2];
8643 8 : const double dfMaxY = (*oSpat)[3];
8644 :
8645 : auto poSpatialFilter =
8646 16 : std::make_shared<OGRPolygon>(dfMinX, dfMinY, dfMaxX, dfMaxY);
8647 8 : psOptions->poSpatialFilter = poSpatialFilter;
8648 : }
8649 :
8650 1000 : if (auto oClipSrc =
8651 1000 : argParser->present<std::vector<std::string>>("-clipsrc"))
8652 : {
8653 20 : const std::string &osVal = (*oClipSrc)[0];
8654 :
8655 20 : psOptions->poClipSrc.reset();
8656 20 : psOptions->osClipSrcDS.clear();
8657 :
8658 : VSIStatBufL sStat;
8659 20 : psOptions->bClipSrc = true;
8660 20 : if (oClipSrc->size() == 4)
8661 : {
8662 1 : const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
8663 1 : const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
8664 1 : const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
8665 1 : const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
8666 :
8667 2 : OGRLinearRing oRing;
8668 :
8669 1 : oRing.addPoint(dfMinX, dfMinY);
8670 1 : oRing.addPoint(dfMinX, dfMaxY);
8671 1 : oRing.addPoint(dfMaxX, dfMaxY);
8672 1 : oRing.addPoint(dfMaxX, dfMinY);
8673 1 : oRing.addPoint(dfMinX, dfMinY);
8674 :
8675 2 : auto poPoly = std::make_shared<OGRPolygon>();
8676 1 : psOptions->poClipSrc = poPoly;
8677 1 : poPoly->addRing(&oRing);
8678 : }
8679 19 : else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8680 27 : STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8681 8 : VSIStatL(osVal.c_str(), &sStat) != 0)
8682 : {
8683 8 : psOptions->poClipSrc =
8684 16 : OGRGeometryFactory::createFromWkt(osVal.c_str()).first;
8685 8 : if (psOptions->poClipSrc == nullptr)
8686 : {
8687 0 : CPLError(
8688 : CE_Failure, CPLE_IllegalArg,
8689 : "Invalid -clipsrc geometry. Must be a valid POLYGON or "
8690 : "MULTIPOLYGON WKT");
8691 0 : return nullptr;
8692 : }
8693 : }
8694 11 : else if (EQUAL(osVal.c_str(), "spat_extent"))
8695 : {
8696 : // Nothing to do
8697 : }
8698 : else
8699 : {
8700 10 : psOptions->osClipSrcDS = osVal;
8701 : }
8702 : }
8703 :
8704 1000 : if (auto oClipDst =
8705 1000 : argParser->present<std::vector<std::string>>("-clipdst"))
8706 : {
8707 15 : const std::string &osVal = (*oClipDst)[0];
8708 :
8709 15 : psOptions->poClipDst.reset();
8710 15 : psOptions->osClipDstDS.clear();
8711 :
8712 : VSIStatBufL sStat;
8713 15 : if (oClipDst->size() == 4)
8714 : {
8715 2 : const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());
8716 2 : const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());
8717 2 : const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());
8718 2 : const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());
8719 :
8720 : auto poPoly = std::make_shared<OGRPolygon>(dfMinX, dfMinY,
8721 4 : dfMaxX, dfMaxY);
8722 2 : psOptions->poClipDst = poPoly;
8723 : }
8724 13 : else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8725 16 : STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8726 3 : VSIStatL(osVal.c_str(), &sStat) != 0)
8727 : {
8728 3 : psOptions->poClipDst =
8729 6 : OGRGeometryFactory::createFromWkt(osVal.c_str()).first;
8730 3 : if (psOptions->poClipDst == nullptr)
8731 : {
8732 0 : CPLError(
8733 : CE_Failure, CPLE_IllegalArg,
8734 : "Invalid -clipdst geometry. Must be a valid POLYGON or "
8735 : "MULTIPOLYGON WKT");
8736 0 : return nullptr;
8737 : }
8738 : }
8739 : else
8740 : {
8741 10 : psOptions->osClipDstDS = osVal;
8742 : }
8743 : }
8744 :
8745 2000 : auto layers = argParser->present<std::vector<std::string>>("layer");
8746 1000 : if (layers)
8747 : {
8748 58 : for (const auto &layer : *layers)
8749 : {
8750 40 : psOptions->aosLayers.AddString(layer.c_str());
8751 : }
8752 : }
8753 1000 : if (psOptionsForBinary)
8754 : {
8755 131 : psOptionsForBinary->eAccessMode = psOptions->eAccessMode;
8756 131 : psOptionsForBinary->osFormat = psOptions->osFormat;
8757 :
8758 131 : if (!(CPLTestBool(
8759 : psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8760 : "NATIVE_DATA",
8761 : psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8762 : "@NATIVE_DATA", "TRUE")))))
8763 : {
8764 0 : psOptions->bNativeData = false;
8765 : }
8766 :
8767 131 : if (psOptions->bNativeData &&
8768 130 : psOptionsForBinary->aosOpenOptions.FetchNameValue(
8769 261 : "NATIVE_DATA") == nullptr &&
8770 130 : psOptionsForBinary->aosOpenOptions.FetchNameValue(
8771 : "@NATIVE_DATA") == nullptr)
8772 : {
8773 : psOptionsForBinary->aosOpenOptions.AddString(
8774 130 : "@NATIVE_DATA=YES");
8775 : }
8776 : }
8777 :
8778 1000 : return psOptions.release();
8779 : }
8780 24 : catch (const std::exception &err)
8781 : {
8782 24 : CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
8783 24 : if (psOptionsForBinary)
8784 1 : psOptionsForBinary->bShowUsageIfError = true;
8785 24 : return nullptr;
8786 : }
8787 : }
8788 :
8789 : /************************************************************************/
8790 : /* GDALVectorTranslateOptionsFree() */
8791 : /************************************************************************/
8792 :
8793 : /**
8794 : * Frees the GDALVectorTranslateOptions struct.
8795 : *
8796 : * @param psOptions the options struct for GDALVectorTranslate().
8797 : * @since GDAL 2.1
8798 : */
8799 :
8800 998 : void GDALVectorTranslateOptionsFree(GDALVectorTranslateOptions *psOptions)
8801 : {
8802 998 : delete psOptions;
8803 998 : }
8804 :
8805 : /************************************************************************/
8806 : /* GDALVectorTranslateOptionsSetProgress() */
8807 : /************************************************************************/
8808 :
8809 : /**
8810 : * Set a progress function.
8811 : *
8812 : * @param psOptions the options struct for GDALVectorTranslate().
8813 : * @param pfnProgress the progress callback.
8814 : * @param pProgressData the user data for the progress callback.
8815 : *
8816 : * @since GDAL 2.1
8817 : */
8818 :
8819 338 : void GDALVectorTranslateOptionsSetProgress(
8820 : GDALVectorTranslateOptions *psOptions, GDALProgressFunc pfnProgress,
8821 : void *pProgressData)
8822 : {
8823 338 : psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
8824 338 : psOptions->pProgressData = pProgressData;
8825 338 : if (pfnProgress == GDALTermProgress)
8826 129 : psOptions->bQuiet = false;
8827 338 : }
8828 :
8829 : #undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS
|