LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/flatgeobuf - ogrflatgeobufeditablelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 77 95 81.1 %
Date: 2024-11-21 22:18:42 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  FlatGeobuf driver
       4             :  * Purpose:  Implements OGRFlatGeobufEditableLayer class.
       5             :  * Author:   Björn Harrtell <bjorn at wololo dot org>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2020, Björn Harrtell <bjorn at wololo dot org>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogrsf_frmts.h"
      14             : #include "cpl_vsi_virtual.h"
      15             : #include "cpl_conv.h"
      16             : #include "cpl_json.h"
      17             : #include "cpl_http.h"
      18             : #include "ogr_p.h"
      19             : 
      20             : #include "ogr_flatgeobuf.h"
      21             : #include "geometryreader.h"
      22             : #include "geometrywriter.h"
      23             : 
      24             : #include <algorithm>
      25             : #include <stdexcept>
      26             : 
      27             : using namespace flatbuffers;
      28             : using namespace FlatGeobuf;
      29             : using namespace ogr_flatgeobuf;
      30             : 
      31             : class OGRFlatGeobufEditableLayerSynchronizer final
      32             :     : public IOGREditableLayerSynchronizer
      33             : {
      34             :     OGRFlatGeobufLayer *m_poFlatGeobufLayer;
      35             :     char **m_papszOpenOptions;
      36             : 
      37             :   public:
      38           1 :     OGRFlatGeobufEditableLayerSynchronizer(
      39             :         OGRFlatGeobufLayer *poFlatGeobufLayer, char **papszOpenOptions)
      40           1 :         : m_poFlatGeobufLayer(poFlatGeobufLayer),
      41           1 :           m_papszOpenOptions(CSLDuplicate(papszOpenOptions))
      42             :     {
      43           1 :     }
      44             : 
      45             :     virtual ~OGRFlatGeobufEditableLayerSynchronizer() override;
      46             : 
      47             :     virtual OGRErr EditableSyncToDisk(OGRLayer *poEditableLayer,
      48             :                                       OGRLayer **ppoDecoratedLayer) override;
      49             : };
      50             : 
      51           2 : OGRFlatGeobufEditableLayerSynchronizer::
      52           1 :     ~OGRFlatGeobufEditableLayerSynchronizer()
      53             : {
      54           1 :     CSLDestroy(m_papszOpenOptions);
      55           2 : }
      56             : 
      57           1 : OGRErr OGRFlatGeobufEditableLayerSynchronizer::EditableSyncToDisk(
      58             :     OGRLayer *poEditableLayer, OGRLayer **ppoDecoratedLayer)
      59             : {
      60           1 :     CPLDebugOnly("FlatGeobuf", "EditableSyncToDisk called");
      61             : 
      62           1 :     CPLAssert(m_poFlatGeobufLayer == *ppoDecoratedLayer);
      63             : 
      64           2 :     const CPLString osLayerName(m_poFlatGeobufLayer->GetName());
      65           2 :     const CPLString osFilename(m_poFlatGeobufLayer->GetFilename());
      66             :     VSIStatBufL sStatBuf;
      67           2 :     CPLString osTmpFilename(osFilename);
      68           1 :     if (VSIStatL(osFilename, &sStatBuf) == 0)
      69             :     {
      70           1 :         osTmpFilename += "_ogr_tmp.fgb";
      71             :     }
      72           1 :     OGRSpatialReference *spatialRef = m_poFlatGeobufLayer->GetSpatialRef();
      73           1 :     auto gType = m_poFlatGeobufLayer->getOGRwkbGeometryType();
      74           1 :     auto createIndex = m_poFlatGeobufLayer->GetIndexNodeSize() > 0;
      75             : 
      76           2 :     OGRFlatGeobufLayer *poFlatGeobufTmpLayer = OGRFlatGeobufLayer::Create(
      77           1 :         m_poFlatGeobufLayer->GetDataset(), osLayerName.c_str(),
      78             :         osTmpFilename.c_str(), spatialRef, gType, createIndex,
      79           1 :         m_papszOpenOptions);
      80           1 :     if (poFlatGeobufTmpLayer == nullptr)
      81           0 :         return OGRERR_FAILURE;
      82             : 
      83           1 :     OGRErr eErr = OGRERR_NONE;
      84           1 :     OGRFeatureDefn *poEditableFDefn = poEditableLayer->GetLayerDefn();
      85           2 :     for (int i = 0; eErr == OGRERR_NONE && i < poEditableFDefn->GetFieldCount();
      86             :          i++)
      87             :     {
      88           1 :         OGRFieldDefn oFieldDefn(poEditableFDefn->GetFieldDefn(i));
      89           1 :         eErr = poFlatGeobufTmpLayer->CreateField(&oFieldDefn);
      90             :     }
      91             : 
      92           1 :     poEditableLayer->ResetReading();
      93             : 
      94             :     // Disable all filters.
      95           1 :     const char *pszQueryStringConst = poEditableLayer->GetAttrQueryString();
      96             :     char *pszQueryStringBak =
      97           1 :         pszQueryStringConst ? CPLStrdup(pszQueryStringConst) : nullptr;
      98           1 :     poEditableLayer->SetAttributeFilter(nullptr);
      99             : 
     100           1 :     const int iFilterGeomIndexBak = poEditableLayer->GetGeomFieldFilter();
     101           1 :     OGRGeometry *poFilterGeomBak = poEditableLayer->GetSpatialFilter();
     102           1 :     if (poFilterGeomBak)
     103           0 :         poFilterGeomBak = poFilterGeomBak->clone();
     104           1 :     poEditableLayer->SetSpatialFilter(nullptr);
     105             : 
     106             :     auto aoMapSrcToTargetIdx =
     107             :         poFlatGeobufTmpLayer->GetLayerDefn()->ComputeMapForSetFrom(
     108           2 :             poEditableLayer->GetLayerDefn(), true);
     109           1 :     aoMapSrcToTargetIdx.push_back(
     110           1 :         -1);  // add dummy entry to be sure that .data() is valid
     111             : 
     112           3 :     for (auto &&poFeature : poEditableLayer)
     113             :     {
     114           2 :         if (eErr != OGRERR_NONE)
     115           0 :             break;
     116             :         OGRFeature *poNewFeature =
     117           2 :             new OGRFeature(poFlatGeobufTmpLayer->GetLayerDefn());
     118           2 :         poNewFeature->SetFrom(poFeature.get(), aoMapSrcToTargetIdx.data(),
     119             :                               true);
     120           2 :         eErr = poFlatGeobufTmpLayer->CreateFeature(poNewFeature);
     121           2 :         delete poNewFeature;
     122             :     }
     123           1 :     delete poFlatGeobufTmpLayer;
     124             : 
     125             :     // Restore filters.
     126           1 :     poEditableLayer->SetAttributeFilter(pszQueryStringBak);
     127           1 :     CPLFree(pszQueryStringBak);
     128           1 :     poEditableLayer->SetSpatialFilter(iFilterGeomIndexBak, poFilterGeomBak);
     129           1 :     delete poFilterGeomBak;
     130             : 
     131           1 :     if (eErr != OGRERR_NONE)
     132             :     {
     133           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Error while creating %s",
     134             :                  osTmpFilename.c_str());
     135           0 :         VSIUnlink(osTmpFilename);
     136           0 :         return eErr;
     137             :     }
     138             : 
     139           1 :     delete m_poFlatGeobufLayer;
     140           1 :     *ppoDecoratedLayer = nullptr;
     141           1 :     m_poFlatGeobufLayer = nullptr;
     142             : 
     143           1 :     if (osFilename != osTmpFilename)
     144             :     {
     145           1 :         const CPLString osTmpOriFilename(osFilename + ".ogr_bak");
     146           2 :         if (VSIRename(osFilename, osTmpOriFilename) != 0 ||
     147           1 :             VSIRename(osTmpFilename, osFilename) != 0)
     148             :         {
     149           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename files");
     150           0 :             return OGRERR_FAILURE;
     151             :         }
     152           1 :         VSIUnlink(osTmpOriFilename);
     153             :     }
     154             : 
     155           1 :     VSILFILE *fp = VSIFOpenL(osFilename, "rb+");
     156           1 :     if (fp == nullptr)
     157             :     {
     158           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot reopen updated %s",
     159             :                  osFilename.c_str());
     160           0 :         return OGRERR_FAILURE;
     161             :     }
     162             : 
     163           1 :     m_poFlatGeobufLayer =
     164           1 :         OGRFlatGeobufLayer::Open(osFilename.c_str(), fp, false);
     165           1 :     *ppoDecoratedLayer = m_poFlatGeobufLayer;
     166             : 
     167           1 :     return OGRERR_NONE;
     168             : }
     169             : 
     170           1 : OGRFlatGeobufEditableLayer::OGRFlatGeobufEditableLayer(
     171           1 :     OGRFlatGeobufLayer *poFlatGeobufLayer, char **papszOpenOptions)
     172             :     : OGREditableLayer(poFlatGeobufLayer, true,
     173             :                        new OGRFlatGeobufEditableLayerSynchronizer(
     174           1 :                            poFlatGeobufLayer, papszOpenOptions),
     175           2 :                        true)
     176             : {
     177           1 : }
     178             : 
     179           0 : GIntBig OGRFlatGeobufEditableLayer::GetFeatureCount(int bForce)
     180             : {
     181           0 :     const GIntBig nRet = OGREditableLayer::GetFeatureCount(bForce);
     182           0 :     if (m_poDecoratedLayer != nullptr && m_nNextFID <= 0)
     183             :     {
     184             :         const GIntBig nTotalFeatureCount =
     185           0 :             static_cast<OGRFlatGeobufLayer *>(m_poDecoratedLayer)
     186           0 :                 ->GetFeatureCount(false);
     187           0 :         if (nTotalFeatureCount >= 0)
     188           0 :             SetNextFID(nTotalFeatureCount + 1);
     189             :     }
     190           0 :     return nRet;
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                            TestCapability()                          */
     195             : /************************************************************************/
     196             : 
     197           4 : int OGRFlatGeobufEditableLayer::TestCapability(const char *pszCap)
     198             : {
     199           4 :     if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite) ||
     200           4 :         EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCDeleteField) ||
     201           4 :         EQUAL(pszCap, OLCReorderFields) || EQUAL(pszCap, OLCAlterFieldDefn) ||
     202           3 :         EQUAL(pszCap, OLCDeleteFeature))
     203             :     {
     204           2 :         return TRUE;
     205             :     }
     206             : 
     207           2 :     return OGREditableLayer::TestCapability(pszCap);
     208             : }

Generated by: LCOV version 1.14