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