Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: "write" step of "vector pipeline" 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "gdalalg_vector_write.h" 14 : #include "cpl_string.h" 15 : #include "gdal_utils.h" 16 : #include "gdal_priv.h" 17 : 18 : #ifndef _ 19 : #define _(x) (x) 20 : #endif 21 : 22 : //! @cond Doxygen_Suppress 23 : 24 : /************************************************************************/ 25 : /* GDALVectorWriteAlgorithm::GDALVectorWriteAlgorithm() */ 26 : /************************************************************************/ 27 : 28 492 : GDALVectorWriteAlgorithm::GDALVectorWriteAlgorithm() 29 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 30 0 : ConstructorOptions() 31 492 : .SetStandaloneStep(false) 32 984 : .SetNoCreateEmptyLayersArgument(true)) 33 : { 34 492 : AddVectorOutputArgs(/* hiddenForCLI = */ false, 35 : /* shortNameOutputLayerAllowed=*/true); 36 492 : } 37 : 38 : /************************************************************************/ 39 : /* GDALVectorWriteAlgorithm::RunStep() */ 40 : /************************************************************************/ 41 : 42 : namespace 43 : { 44 46 : class OGRReadBufferedLayer 45 : : public OGRLayer, 46 : public OGRGetNextFeatureThroughRaw<OGRReadBufferedLayer> 47 : { 48 : public: 49 23 : explicit OGRReadBufferedLayer(OGRLayer &srcLayer) 50 23 : : m_srcLayer(srcLayer), m_poFeature(nullptr) 51 : { 52 23 : m_poFeature.reset(m_srcLayer.GetNextFeature()); 53 23 : } 54 : 55 : ~OGRReadBufferedLayer() override; 56 : 57 2 : const char *GetDescription() const override 58 : { 59 2 : return m_srcLayer.GetDescription(); 60 : } 61 : 62 27 : GIntBig GetFeatureCount(int bForce) override 63 : { 64 27 : if (m_poAttrQuery == nullptr && m_poFilterGeom == nullptr) 65 : { 66 17 : return m_srcLayer.GetFeatureCount(bForce); 67 : } 68 : 69 10 : return OGRLayer::GetFeatureCount(bForce); 70 : } 71 : 72 327 : const OGRFeatureDefn *GetLayerDefn() const override 73 : { 74 327 : return m_srcLayer.GetLayerDefn(); 75 : } 76 : 77 205 : OGRFeature *GetNextRawFeature() 78 : { 79 205 : auto ret = m_poFeature.release(); 80 205 : m_poFeature.reset(m_srcLayer.GetNextFeature()); 81 205 : return ret; 82 : } 83 : 84 171 : DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGRReadBufferedLayer) 85 : 86 4 : OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent, 87 : bool bForce) override 88 : { 89 4 : return m_srcLayer.GetExtent(iGeomField, psExtent, bForce); 90 : } 91 : 92 0 : OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent, 93 : bool bForce) override 94 : { 95 0 : return m_srcLayer.GetExtent3D(iGeomField, psExtent, bForce); 96 : } 97 : 98 23 : const OGRFeature *PeekNextFeature() const 99 : { 100 23 : return m_poFeature.get(); 101 : } 102 : 103 70 : int TestCapability(const char *pszCap) const override 104 : { 105 70 : if (EQUAL(pszCap, OLCFastFeatureCount) || 106 70 : EQUAL(pszCap, OLCFastGetExtent) || 107 67 : EQUAL(pszCap, OLCFastGetExtent3D) || 108 67 : EQUAL(pszCap, OLCZGeometries) || 109 61 : EQUAL(pszCap, OLCMeasuredGeometries) || 110 53 : EQUAL(pszCap, OLCCurveGeometries)) 111 : { 112 25 : return m_srcLayer.TestCapability(pszCap); 113 : } 114 : 115 45 : return false; 116 : } 117 : 118 168 : void ResetReading() override 119 : { 120 168 : m_srcLayer.ResetReading(); 121 168 : m_poFeature.reset(m_srcLayer.GetNextFeature()); 122 168 : } 123 : 124 : private: 125 : OGRLayer &m_srcLayer; 126 : std::unique_ptr<OGRFeature> m_poFeature; 127 : }; 128 : 129 : OGRReadBufferedLayer::~OGRReadBufferedLayer() = default; 130 : 131 : class GDALReadBufferedDataset final : public GDALDataset 132 : { 133 : public: 134 10 : explicit GDALReadBufferedDataset(GDALDataset &srcDS) : m_srcDS(srcDS) 135 : { 136 10 : m_srcDS.Reference(); 137 : 138 33 : for (int i = 0; i < srcDS.GetLayerCount(); i++) 139 : { 140 : auto poLayer = 141 46 : std::make_unique<OGRReadBufferedLayer>(*srcDS.GetLayer(i)); 142 23 : if (poLayer->PeekNextFeature()) 143 : { 144 14 : m_layers.push_back(std::move(poLayer)); 145 : } 146 : } 147 10 : } 148 : 149 : ~GDALReadBufferedDataset() override; 150 : 151 71 : int GetLayerCount() const override 152 : { 153 71 : return static_cast<int>(m_layers.size()); 154 : } 155 : 156 54 : const OGRLayer *GetLayer(int nLayer) const override 157 : { 158 54 : if (nLayer < 0 || nLayer >= static_cast<int>(m_layers.size())) 159 : { 160 4 : return nullptr; 161 : } 162 50 : return m_layers[nLayer].get(); 163 : } 164 : 165 : private: 166 : GDALDataset &m_srcDS; 167 : std::vector<std::unique_ptr<OGRReadBufferedLayer>> m_layers{}; 168 : }; 169 : 170 20 : GDALReadBufferedDataset::~GDALReadBufferedDataset() 171 : { 172 10 : m_srcDS.Release(); 173 20 : } 174 : 175 : } // namespace 176 : 177 371 : bool GDALVectorWriteAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt) 178 : { 179 371 : auto pfnProgress = ctxt.m_pfnProgress; 180 371 : auto pProgressData = ctxt.m_pProgressData; 181 371 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 182 371 : CPLAssert(poSrcDS); 183 : 184 371 : std::unique_ptr<GDALDataset> poReadBufferedDataset; 185 : 186 371 : if (m_noCreateEmptyLayers) 187 : { 188 10 : if (poSrcDS->TestCapability(ODsCRandomLayerRead)) 189 : { 190 1 : CPLError( 191 : CE_Warning, CPLE_AppDefined, 192 : "Source dataset supports random-layer reading, but this " 193 : "is not compatible with --no-create-empty-layers. Attempting " 194 : "to read features by layer, but this may fail if the " 195 : "source dataset is large."); 196 : } 197 : 198 : poReadBufferedDataset = 199 10 : std::make_unique<GDALReadBufferedDataset>(*poSrcDS); 200 : 201 10 : if (m_format == "stream") 202 : { 203 8 : m_outputDataset.Set(std::move(poReadBufferedDataset)); 204 8 : return true; 205 : } 206 : 207 2 : poSrcDS = poReadBufferedDataset.get(); 208 : } 209 : 210 363 : if (m_format == "stream") 211 : { 212 155 : m_outputDataset.Set(poSrcDS); 213 155 : return true; 214 : } 215 : 216 416 : CPLStringList aosOptions; 217 208 : aosOptions.AddString("--invoked-from-gdal-algorithm"); 218 208 : if (!m_overwrite) 219 : { 220 198 : aosOptions.AddString("--no-overwrite"); 221 : } 222 208 : if (m_overwriteLayer) 223 : { 224 5 : aosOptions.AddString("-overwrite"); 225 : } 226 208 : if (m_appendLayer) 227 : { 228 3 : aosOptions.AddString("-append"); 229 : } 230 208 : if (m_upsert) 231 : { 232 2 : aosOptions.AddString("-upsert"); 233 : } 234 208 : if (!m_format.empty()) 235 : { 236 125 : aosOptions.AddString("-of"); 237 125 : aosOptions.AddString(m_format.c_str()); 238 : } 239 210 : for (const auto &co : m_creationOptions) 240 : { 241 2 : aosOptions.AddString("-dsco"); 242 2 : aosOptions.AddString(co.c_str()); 243 : } 244 212 : for (const auto &co : m_layerCreationOptions) 245 : { 246 4 : aosOptions.AddString("-lco"); 247 4 : aosOptions.AddString(co.c_str()); 248 : } 249 208 : if (!m_outputLayerName.empty()) 250 : { 251 5 : aosOptions.AddString("-nln"); 252 5 : aosOptions.AddString(m_outputLayerName.c_str()); 253 : } 254 208 : if (pfnProgress && pfnProgress != GDALDummyProgress) 255 : { 256 9 : aosOptions.AddString("-progress"); 257 : } 258 208 : if (m_skipErrors) 259 : { 260 2 : aosOptions.AddString("-skipfailures"); 261 : } 262 : 263 208 : GDALDataset *poRetDS = nullptr; 264 : GDALDatasetH hOutDS = 265 208 : GDALDataset::ToHandle(m_outputDataset.GetDatasetRef()); 266 : GDALVectorTranslateOptions *psOptions = 267 208 : GDALVectorTranslateOptionsNew(aosOptions.List(), nullptr); 268 208 : if (psOptions) 269 : { 270 208 : GDALVectorTranslateOptionsSetProgress(psOptions, pfnProgress, 271 : pProgressData); 272 : 273 208 : GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS); 274 208 : poRetDS = GDALDataset::FromHandle( 275 208 : GDALVectorTranslate(m_outputDataset.GetName().c_str(), hOutDS, 1, 276 : &hSrcDS, psOptions, nullptr)); 277 208 : GDALVectorTranslateOptionsFree(psOptions); 278 : } 279 : 280 208 : if (!poRetDS) 281 : { 282 14 : return false; 283 : } 284 : 285 194 : if (!hOutDS) 286 : { 287 183 : m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS)); 288 : } 289 : 290 194 : return true; 291 : } 292 : 293 : //! @endcond