LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_create.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 178 221 80.5 %
Date: 2026-07-09 08:35:43 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "vector create" subcommand
       5             :  * Author:   Alessandro Pasotti <elpaso at itopen dot it>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2026, Alessandro Pasotti <elpaso at itopen dot it>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include <regex>
      14             : #include "gdalalg_vector_create.h"
      15             : #include "gdal_utils.h"
      16             : #include "ogr_schema_override.h"
      17             : 
      18             : //! @cond Doxygen_Suppress
      19             : 
      20             : #ifndef _
      21             : #define _(x) (x)
      22             : #endif
      23             : 
      24             : /************************************************************************/
      25             : /*        GDALVectorCreateAlgorithm::GDALVectorCreateAlgorithm()        */
      26             : /************************************************************************/
      27             : 
      28         132 : GDALVectorCreateAlgorithm::GDALVectorCreateAlgorithm(bool standaloneStep)
      29             :     : GDALVectorPipelineStepAlgorithm(
      30             :           NAME, DESCRIPTION, HELP_URL,
      31           0 :           ConstructorOptions()
      32         132 :               .SetStandaloneStep(standaloneStep)
      33         264 :               .SetOutputFormatCreateCapability(GDAL_DCAP_CREATE)
      34             : 
      35             :               // Remove defaults because input is the optional template
      36         132 :               .SetAddDefaultArguments(false)
      37             : 
      38             :               // For --like input template
      39         132 :               .SetAutoOpenInputDatasets(true)
      40         264 :               .SetInputDatasetHelpMsg(_("Template vector dataset"))
      41         264 :               .SetInputDatasetAlias("like")
      42         132 :               .SetInputDatasetRequired(false)
      43         132 :               .SetInputDatasetPositional(false)
      44         132 :               .SetInputDatasetMaxCount(1)
      45         264 :               .SetInputDatasetMetaVar("TEMPLATE-DATASET")
      46             : 
      47             :               // Remove arguments that don't make sense in a create context
      48             :               // Note: this is required despite SetAddDefaultArguments(false)
      49         132 :               .SetAddUpsertArgument(false)
      50         132 :               .SetAddSkipErrorsArgument(false)
      51         396 :               .SetAddAppendLayerArgument(false))
      52             : {
      53         132 :     if (standaloneStep)
      54         132 :         AddProgressArg(/* hidden = */ true);
      55             : 
      56         132 :     AddVectorInputArgs(false);
      57         132 :     AddVectorOutputArgs(/* hiddenForCLI = */ false,
      58             :                         /* shortNameOutputLayerAllowed=*/false);
      59         132 :     AddGeometryTypeArg(&m_geometryType, _("Layer geometry type"));
      60             : 
      61             :     // Add optional geometry field name argument, not all drivers support it, and if not specified, the default "geom" name will be used.
      62             :     auto &geomFieldNameArg =
      63             :         AddArg("geometry-field", 0,
      64             :                _("Name of the geometry field to create (if supported by the "
      65             :                  "output format)"),
      66         264 :                &m_geometryFieldName)
      67         264 :             .SetMetaVar("GEOMETRY-FIELD")
      68         132 :             .SetDefault(m_geometryFieldName);
      69             : 
      70         264 :     AddArg("crs", 0, _("Set CRS"), &m_crs)
      71         264 :         .AddHiddenAlias("srs")
      72         132 :         .SetIsCRSArg(/*noneAllowed=*/false);
      73             : 
      74         132 :     AddArg("fid", 0, _("FID column name"), &m_fidColumnName);
      75             : 
      76         132 :     constexpr auto inputMutexGroup = "like-schema-field";
      77             : 
      78             :     // Apply mutex to GDAL_ARG_NAME_INPUT
      79             :     // This is hackish and I really don't like const_cast but I couldn't find another way.
      80             :     const_cast<GDALAlgorithmArgDecl &>(
      81         264 :         GetArg(GDAL_ARG_NAME_INPUT)->GetDeclaration())
      82         132 :         .SetMutualExclusionGroup(inputMutexGroup);
      83             : 
      84             :     // Add --schema argument to read OGR_SCHEMA and populate field definitions from it. It is mutually exclusive with --like and --field arguments.
      85             :     AddArg("schema", 0,
      86             :            _("Read OGR_SCHEMA and populate field definitions from it"),
      87         264 :            &m_schemaJsonOrPath)
      88         264 :         .SetMetaVar("SCHEMA_JSON")
      89         132 :         .SetRepeatedArgAllowed(false)
      90         132 :         .SetMutualExclusionGroup(inputMutexGroup);
      91             : 
      92             :     // Add field definition argument
      93             :     AddFieldDefinitionArg(&m_fieldStrDefinitions, &m_fieldDefinitions,
      94         132 :                           _("Add a field definition to the output layer"))
      95         264 :         .SetMetaVar("<NAME>:<TYPE>[(,<WIDTH>[,<PRECISION>])]")
      96         132 :         .SetPackedValuesAllowed(false)
      97         132 :         .SetRepeatedArgAllowed(true)
      98         132 :         .SetMutualExclusionGroup(inputMutexGroup);
      99             : 
     100         132 :     AddValidationAction(
     101         182 :         [this, &geomFieldNameArg]()
     102             :         {
     103          65 :             if ((!m_schemaJsonOrPath.empty() || !m_inputDataset.empty()) &&
     104          34 :                 ((!m_geometryFieldName.empty() &&
     105          17 :                   geomFieldNameArg.IsExplicitlySet()) ||
     106          16 :                  !m_geometryType.empty() || !m_fieldDefinitions.empty() ||
     107          14 :                  !m_crs.empty() || !m_fidColumnName.empty()))
     108             :             {
     109           5 :                 ReportError(CE_Failure, CPLE_AppDefined,
     110             :                             "When --schema or --like is specified, "
     111             :                             "--geometry-field, --geometry-type, --field, "
     112             :                             "--crs and --fid options must not be specified.");
     113           5 :                 return false;
     114             :             }
     115          43 :             return true;
     116             :         });
     117         132 : }
     118             : 
     119             : /************************************************************************/
     120             : /*                 GDALVectorCreateAlgorithm::RunStep()                 */
     121             : /************************************************************************/
     122             : 
     123          39 : bool GDALVectorCreateAlgorithm::RunStep(GDALPipelineStepRunContext &)
     124             : {
     125             : 
     126          39 :     const std::string &datasetName = m_outputDataset.GetName();
     127             :     const std::string outputLayerName =
     128          39 :         m_outputLayerName.empty() ? CPLGetBasenameSafe(datasetName.c_str())
     129          78 :                                   : m_outputLayerName;
     130             : 
     131          39 :     std::unique_ptr<GDALDataset> poDstDS;
     132          39 :     poDstDS.reset(GDALDataset::Open(datasetName.c_str(),
     133             :                                     GDAL_OF_VECTOR | GDAL_OF_UPDATE, nullptr,
     134             :                                     nullptr, nullptr));
     135             : 
     136          39 :     if (poDstDS && !m_update)
     137             :     {
     138           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     139             :                     "Dataset %s already exists. Specify the "
     140             :                     "--%s option to open it in update mode.",
     141             :                     datasetName.c_str(), GDAL_ARG_NAME_UPDATE);
     142           0 :         return false;
     143             :     }
     144             : 
     145          39 :     GDALDataset *poSrcDS = m_inputDataset.empty()
     146          39 :                                ? nullptr
     147           6 :                                : m_inputDataset.front().GetDatasetRef();
     148             : 
     149          78 :     OGRSchemaOverride oSchemaOverride;
     150             : 
     151          11 :     const auto loadJSON = [this,
     152          11 :                            &oSchemaOverride](const std::string &source) -> bool
     153             :     {
     154             :         // This error count is necessary because LoadFromJSON tries to load
     155             :         // the content as a file first (and set an error it if fails) then tries
     156             :         // to load as a JSON string but even if it succeeds an error is still
     157             :         // set and not cleared.
     158          11 :         const auto nErrorCount = CPLGetErrorCounter();
     159          11 :         if (!oSchemaOverride.LoadFromJSON(source,
     160             :                                           /* allowGeometryFields */ true))
     161             :         {
     162             :             // Get the last error message and report it, since LoadFromJSON doesn't do it itself.
     163           0 :             if (nErrorCount != CPLGetErrorCounter())
     164             :             {
     165           0 :                 const std::string lastErrorMsg = CPLGetLastErrorMsg();
     166           0 :                 CPLErrorReset();
     167           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     168             :                             "Cannot parse OGR_SCHEMA: %s.",
     169             :                             lastErrorMsg.c_str());
     170             :             }
     171             :             else
     172             :             {
     173           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     174             :                             "Cannot parse OGR_SCHEMA (unknown error).");
     175             :             }
     176           0 :             return false;
     177             :         }
     178          11 :         else if (nErrorCount != CPLGetErrorCounter())
     179             :         {
     180          11 :             CPLErrorReset();
     181             :         }
     182          11 :         return true;
     183          39 :     };
     184             : 
     185             :     // Use the input dataset as to create an OGR_SCHEMA
     186          39 :     if (poSrcDS)
     187             :     {
     188             :         // Export the schema using GDALVectorInfo
     189           6 :         CPLStringList aosOptions;
     190             : 
     191           6 :         aosOptions.AddString("-schema");
     192             : 
     193             :         // Must be last, as positional
     194           6 :         aosOptions.AddString("dummy");
     195           6 :         aosOptions.AddString("-al");
     196             : 
     197             :         GDALVectorInfoOptions *psInfo =
     198           6 :             GDALVectorInfoOptionsNew(aosOptions.List(), nullptr);
     199             : 
     200           6 :         char *ret = GDALVectorInfo(GDALDataset::ToHandle(poSrcDS), psInfo);
     201           6 :         GDALVectorInfoOptionsFree(psInfo);
     202           6 :         if (!ret)
     203           0 :             return false;
     204             : 
     205           6 :         if (!loadJSON(ret))
     206             :         {
     207           0 :             CPLFree(ret);
     208           0 :             return false;
     209             :         }
     210           6 :         CPLFree(ret);
     211             :     }
     212          33 :     else if (!m_schemaJsonOrPath.empty() && !loadJSON(m_schemaJsonOrPath))
     213             :     {
     214           0 :         return false;
     215             :     }
     216             : 
     217          39 :     if (m_standaloneStep)
     218             :     {
     219          39 :         if (m_format.empty())
     220             :         {
     221             :             const auto aosFormats =
     222             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
     223          39 :                     m_outputDataset.GetName().c_str(), GDAL_OF_VECTOR,
     224             :                     /* bSingleMatch = */ true,
     225          39 :                     /* bWarn = */ true));
     226          39 :             if (aosFormats.size() != 1)
     227             :             {
     228           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     229             :                             "Cannot guess driver for %s",
     230           0 :                             m_outputDataset.GetName().c_str());
     231           0 :                 return false;
     232             :             }
     233          39 :             m_format = aosFormats[0];
     234             :         }
     235             :     }
     236             :     else
     237             :     {
     238           0 :         m_format = "MEM";
     239             :     }
     240             : 
     241             :     auto poDstDriver =
     242          39 :         GetGDALDriverManager()->GetDriverByName(m_format.c_str());
     243          39 :     if (!poDstDriver)
     244             :     {
     245           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s.",
     246             :                     m_format.c_str());
     247           0 :         return false;
     248             :     }
     249             : 
     250          39 :     if (!poDstDS)
     251          27 :         poDstDS.reset(poDstDriver->Create(datasetName.c_str(), 0, 0, 0,
     252             :                                           GDT_Unknown,
     253          54 :                                           CPLStringList(m_creationOptions)));
     254             : 
     255          39 :     if (!poDstDS)
     256             :     {
     257           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot create dataset %s.",
     258             :                     datasetName.c_str());
     259           0 :         return false;
     260             :     }
     261             : 
     262             :     // An OGR_SCHEMA has been provided
     263          39 :     if (!oSchemaOverride.GetLayerOverrides().empty())
     264             :     {
     265             :         // Checks if input layer names were specified and the layers exists in the schema
     266          11 :         if (!m_inputLayerNames.empty())
     267             :         {
     268          12 :             for (const auto &inputLayerName : m_inputLayerNames)
     269             :             {
     270           7 :                 if (!oSchemaOverride.GetLayerOverride(inputLayerName).IsValid())
     271             :                 {
     272           0 :                     ReportError(CE_Failure, CPLE_AppDefined,
     273             :                                 "The specified input layer name '%s' doesn't "
     274             :                                 "exist in the provided template or schema.",
     275             :                                 inputLayerName.c_str());
     276           0 :                     return false;
     277             :                 }
     278             :             }
     279             :         }
     280             : 
     281             :         // If there are multiple layers check if the destination format supports
     282             :         // multiple layers, and if not, error out.
     283          11 :         if (oSchemaOverride.GetLayerOverrides().size() > 1 &&
     284           6 :             !GDALGetMetadataItem(poDstDriver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
     285          17 :                                  nullptr) &&
     286           2 :             m_inputLayerNames.size() != 1)
     287             :         {
     288           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     289             :                         "The output format %s doesn't support multiple layers.",
     290           1 :                         poDstDriver->GetDescription());
     291           1 :             return false;
     292             :         }
     293             : 
     294             :         // If output layer name was specified and there is more than one layer in the schema,
     295             :         // error out since we won't know which layer to apply it to
     296          12 :         if (!m_outputLayerName.empty() &&
     297          12 :             oSchemaOverride.GetLayerOverrides().size() > 1 &&
     298           2 :             m_inputLayerNames.size() != 1)
     299             :         {
     300           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     301             :                         "Output layer name should not be specified when there "
     302             :                         "are multiple layers in the schema.");
     303           1 :             return false;
     304             :         }
     305             : 
     306           9 :         std::vector<std::string> layersToBeCreated;
     307          25 :         for (const auto &oLayerOverride : oSchemaOverride.GetLayerOverrides())
     308             :         {
     309             : 
     310          27 :             if (!m_inputLayerNames.empty() &&
     311           0 :                 std::find(m_inputLayerNames.begin(), m_inputLayerNames.end(),
     312          11 :                           oLayerOverride.GetLayerName()) ==
     313          27 :                     m_inputLayerNames.end())
     314             :             {
     315             :                 // This layer is not in the list of input layers to consider, so skip it
     316           6 :                 continue;
     317             :             }
     318          10 :             layersToBeCreated.push_back(oLayerOverride.GetLayerName());
     319             :         }
     320             : 
     321             :         // Loop over layers in the OGR_SCHEMA and create them
     322          19 :         for (const auto &layerToCreate : layersToBeCreated)
     323             :         {
     324             :             const auto &oLayerOverride =
     325          10 :                 oSchemaOverride.GetLayerOverride(layerToCreate);
     326          10 :             if (!oLayerOverride.IsValid())
     327             :             {
     328           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     329             :                             "Invalid layer override for layer '%s'.",
     330             :                             layerToCreate.c_str());
     331           0 :                 return false;
     332             :             }
     333             : 
     334             :             // We can use the defined layer name only if there is a single layer to be created
     335             :             const std::string userSpecifiedNewName =
     336          10 :                 !m_outputLayerName.empty() ? m_outputLayerName
     337          10 :                                            : oLayerOverride.GetLayerName();
     338             :             const std::string outputLayerNewName =
     339          12 :                 layersToBeCreated.size() > 1 ? oLayerOverride.GetLayerName()
     340          12 :                                              : userSpecifiedNewName;
     341             : 
     342          10 :             if (!CreateLayer(poDstDS.get(), outputLayerNewName,
     343             :                              oLayerOverride.GetFIDColumnName(),
     344          20 :                              oLayerOverride.GetFieldDefinitions(),
     345          20 :                              oLayerOverride.GetGeomFieldDefinitions()))
     346             :             {
     347           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     348             :                             "Cannot create layer '%s'",
     349           0 :                             oLayerOverride.GetLayerName().c_str());
     350           0 :                 return false;
     351             :             }
     352             :         }
     353             :     }
     354             :     else
     355             :     {
     356          28 :         std::vector<OGRGeomFieldDefn> geometryFieldDefinitions;
     357          28 :         if (!m_geometryType.empty())
     358             :         {
     359             :             const OGRwkbGeometryType eDstType =
     360          26 :                 OGRFromOGCGeomType(m_geometryType.c_str());
     361          27 :             if (eDstType == wkbUnknown &&
     362           1 :                 !STARTS_WITH_CI(m_geometryType.c_str(), "GEOMETRY"))
     363             :             {
     364           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     365             :                             "Unsupported geometry type: '%s'.",
     366             :                             m_geometryType.c_str());
     367           0 :                 return false;
     368             :             }
     369             :             else
     370             :             {
     371             :                 OGRGeomFieldDefn oGeomFieldDefn(m_geometryFieldName.c_str(),
     372          26 :                                                 eDstType);
     373          26 :                 if (!m_crs.empty())
     374             :                 {
     375             :                     auto poSRS =
     376          25 :                         OGRSpatialReferenceRefCountedPtr::makeInstance();
     377          25 :                     if (poSRS->SetFromUserInput(m_crs.c_str()) != OGRERR_NONE)
     378             :                     {
     379           0 :                         ReportError(CE_Failure, CPLE_AppDefined,
     380             :                                     "Cannot parse CRS definition: '%s'.",
     381             :                                     m_crs.c_str());
     382           0 :                         return false;
     383             :                     }
     384             :                     else
     385             :                     {
     386          25 :                         oGeomFieldDefn.SetSpatialRef(poSRS.get());
     387             :                     }
     388             :                 }
     389          26 :                 geometryFieldDefinitions.push_back(std::move(oGeomFieldDefn));
     390             :             }
     391             :         }
     392             : 
     393          28 :         if (!CreateLayer(poDstDS.get(), outputLayerName, m_fidColumnName,
     394          56 :                          GetOutputFields(), geometryFieldDefinitions))
     395             :         {
     396           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     397             :                         "Cannot create layer '%s'.", outputLayerName.c_str());
     398           1 :             return false;
     399             :         }
     400             :     }
     401             : 
     402          36 :     m_outputDataset.Set(std::move(poDstDS));
     403          36 :     return true;
     404             : }
     405             : 
     406             : /************************************************************************/
     407             : /*                 GDALVectorCreateAlgorithm::RunImpl()                 */
     408             : /************************************************************************/
     409          39 : bool GDALVectorCreateAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
     410             :                                         void *pProgressData)
     411             : {
     412          39 :     GDALPipelineStepRunContext stepCtxt;
     413          39 :     stepCtxt.m_pfnProgress = pfnProgress;
     414          39 :     stepCtxt.m_pProgressData = pProgressData;
     415          39 :     return RunPreStepPipelineValidations() && RunStep(stepCtxt);
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*             GDALVectorCreateAlgorithm::GetOutputFields()             */
     420             : /************************************************************************/
     421          28 : std::vector<OGRFieldDefn> GDALVectorCreateAlgorithm::GetOutputFields() const
     422             : {
     423             :     // This is where we will eventually implement override logic to modify field
     424             :     // definitions based on input dataset and/or OGR_SCHEMA, but for now we just
     425             :     // return the field definitions as specified by the user through --field arguments.
     426          28 :     return m_fieldDefinitions;
     427             : }
     428             : 
     429             : /************************************************************************/
     430             : /*               GDALVectorCreateAlgorithm::CreateLayer()               */
     431             : /************************************************************************/
     432          38 : bool GDALVectorCreateAlgorithm::CreateLayer(
     433             :     GDALDataset *poDstDS, const std::string &layerName,
     434             :     const std::string &fidColumnName,
     435             :     const std::vector<OGRFieldDefn> &fieldDefinitions,
     436             :     const std::vector<OGRGeomFieldDefn> &geometryFieldDefinitions) const
     437             : {
     438          38 :     if (auto poExistingDstLayer = poDstDS->GetLayerByName(layerName.c_str()))
     439             :     {
     440           1 :         if (GetOverwriteLayer())
     441             :         {
     442           1 :             int iLayer = -1;
     443           1 :             const int nLayerCount = poDstDS->GetLayerCount();
     444           2 :             for (iLayer = 0; iLayer < nLayerCount; iLayer++)
     445             :             {
     446           2 :                 if (poDstDS->GetLayer(iLayer) == poExistingDstLayer)
     447           1 :                     break;
     448             :             }
     449             : 
     450           1 :             if (iLayer < nLayerCount)
     451             :             {
     452           1 :                 if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
     453             :                 {
     454           0 :                     ReportError(CE_Failure, CPLE_AppDefined,
     455             :                                 "Cannot delete layer '%s'.", layerName.c_str());
     456           0 :                     return false;
     457             :                 }
     458             :             }
     459             :         }
     460             :         else
     461             :         {
     462           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     463             :                         "Layer '%s' already exists. Specify the "
     464             :                         "--%s option to overwrite it.",
     465             :                         layerName.c_str(), GDAL_ARG_NAME_OVERWRITE_LAYER);
     466           0 :             return false;
     467             :         }
     468             :     }
     469          37 :     else if (GetOverwriteLayer())
     470             :     {
     471           1 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot find layer '%s'.",
     472             :                     layerName.c_str());
     473           1 :         return false;
     474             :     }
     475             : 
     476             :     // Get the geometry field definition, if any
     477          37 :     std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDefn;
     478          37 :     if (!geometryFieldDefinitions.empty())
     479             :     {
     480          33 :         if (geometryFieldDefinitions.size() > 1)
     481             :         {
     482             :             // NOTE: this limitation may eventually be removed,
     483             :             // but for now we don't want to deal with the complexity
     484             :             // of creating multiple geometry fields with various drivers that
     485             :             // may or may not support it
     486           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     487             :                         "Multiple geometry fields are not supported.");
     488           0 :             return false;
     489             :         }
     490             :         poGeomFieldDefn =
     491          33 :             std::make_unique<OGRGeomFieldDefn>(geometryFieldDefinitions[0]);
     492             :     }
     493             : 
     494          74 :     CPLStringList aosCreationOptions(GetLayerCreationOptions());
     495          74 :     if (aosCreationOptions.FetchNameValue("FID") == nullptr &&
     496          37 :         !fidColumnName.empty())
     497             :     {
     498           7 :         auto poDstDriver = poDstDS->GetDriver();
     499           7 :         if (poDstDriver && poDstDriver->HasLayerCreationOption("FID"))
     500             :         {
     501           7 :             aosCreationOptions.SetNameValue("FID", fidColumnName.c_str());
     502             :         }
     503             :     }
     504          37 :     auto poDstLayer = poDstDS->CreateLayer(
     505          37 :         layerName.c_str(), poGeomFieldDefn.get(), aosCreationOptions.List());
     506          37 :     if (!poDstLayer)
     507             :     {
     508           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot create layer '%s'.",
     509             :                     layerName.c_str());
     510           0 :         return false;
     511             :     }
     512             : 
     513          72 :     for (const auto &oFieldDefn : fieldDefinitions)
     514             :     {
     515          35 :         if (poDstLayer->CreateField(&oFieldDefn) != OGRERR_NONE)
     516             :         {
     517           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     518             :                         "Cannot create field '%s' in layer '%s'.",
     519             :                         oFieldDefn.GetNameRef(), layerName.c_str());
     520           0 :             return false;
     521             :         }
     522             :     }
     523             : 
     524          37 :     return true;
     525             : }
     526             : 
     527             : /************************************************************************/
     528             : /*                ~GDALVectorCreateAlgorithmStandalone()                */
     529             : /************************************************************************/
     530             : GDALVectorCreateAlgorithmStandalone::~GDALVectorCreateAlgorithmStandalone() =
     531             :     default;
     532             : 
     533             : //! @endcond

Generated by: LCOV version 1.14