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 : ~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 : const OGRSpatialReference *spatialRef = 73 1 : m_poFlatGeobufLayer->GetSpatialRef(); 74 1 : auto gType = m_poFlatGeobufLayer->getOGRwkbGeometryType(); 75 1 : auto createIndex = m_poFlatGeobufLayer->GetIndexNodeSize() > 0; 76 : 77 2 : OGRFlatGeobufLayer *poFlatGeobufTmpLayer = OGRFlatGeobufLayer::Create( 78 1 : m_poFlatGeobufLayer->GetDataset(), osLayerName.c_str(), 79 : osTmpFilename.c_str(), spatialRef, gType, createIndex, 80 1 : m_papszOpenOptions); 81 1 : if (poFlatGeobufTmpLayer == nullptr) 82 0 : return OGRERR_FAILURE; 83 : 84 1 : OGRErr eErr = OGRERR_NONE; 85 1 : OGRFeatureDefn *poEditableFDefn = poEditableLayer->GetLayerDefn(); 86 2 : for (int i = 0; eErr == OGRERR_NONE && i < poEditableFDefn->GetFieldCount(); 87 : i++) 88 : { 89 1 : OGRFieldDefn oFieldDefn(poEditableFDefn->GetFieldDefn(i)); 90 1 : eErr = poFlatGeobufTmpLayer->CreateField(&oFieldDefn); 91 : } 92 : 93 1 : poEditableLayer->ResetReading(); 94 : 95 : // Disable all filters. 96 1 : const char *pszQueryStringConst = poEditableLayer->GetAttrQueryString(); 97 : char *pszQueryStringBak = 98 1 : pszQueryStringConst ? CPLStrdup(pszQueryStringConst) : nullptr; 99 1 : poEditableLayer->SetAttributeFilter(nullptr); 100 : 101 1 : const int iFilterGeomIndexBak = poEditableLayer->GetGeomFieldFilter(); 102 1 : OGRGeometry *poFilterGeomBak = poEditableLayer->GetSpatialFilter(); 103 1 : if (poFilterGeomBak) 104 0 : poFilterGeomBak = poFilterGeomBak->clone(); 105 1 : poEditableLayer->SetSpatialFilter(nullptr); 106 : 107 : auto aoMapSrcToTargetIdx = 108 : poFlatGeobufTmpLayer->GetLayerDefn()->ComputeMapForSetFrom( 109 2 : poEditableLayer->GetLayerDefn(), true); 110 1 : aoMapSrcToTargetIdx.push_back( 111 1 : -1); // add dummy entry to be sure that .data() is valid 112 : 113 3 : for (auto &&poFeature : poEditableLayer) 114 : { 115 2 : if (eErr != OGRERR_NONE) 116 0 : break; 117 : OGRFeature *poNewFeature = 118 2 : new OGRFeature(poFlatGeobufTmpLayer->GetLayerDefn()); 119 2 : poNewFeature->SetFrom(poFeature.get(), aoMapSrcToTargetIdx.data(), 120 : true); 121 2 : eErr = poFlatGeobufTmpLayer->CreateFeature(poNewFeature); 122 2 : delete poNewFeature; 123 : } 124 1 : delete poFlatGeobufTmpLayer; 125 : 126 : // Restore filters. 127 1 : poEditableLayer->SetAttributeFilter(pszQueryStringBak); 128 1 : CPLFree(pszQueryStringBak); 129 1 : poEditableLayer->SetSpatialFilter(iFilterGeomIndexBak, poFilterGeomBak); 130 1 : delete poFilterGeomBak; 131 : 132 1 : if (eErr != OGRERR_NONE) 133 : { 134 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error while creating %s", 135 : osTmpFilename.c_str()); 136 0 : VSIUnlink(osTmpFilename); 137 0 : return eErr; 138 : } 139 : 140 1 : delete m_poFlatGeobufLayer; 141 1 : *ppoDecoratedLayer = nullptr; 142 1 : m_poFlatGeobufLayer = nullptr; 143 : 144 1 : if (osFilename != osTmpFilename) 145 : { 146 1 : const CPLString osTmpOriFilename(osFilename + ".ogr_bak"); 147 2 : if (VSIRename(osFilename, osTmpOriFilename) != 0 || 148 1 : VSIRename(osTmpFilename, osFilename) != 0) 149 : { 150 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename files"); 151 0 : return OGRERR_FAILURE; 152 : } 153 1 : VSIUnlink(osTmpOriFilename); 154 : } 155 : 156 1 : VSILFILE *fp = VSIFOpenL(osFilename, "rb+"); 157 1 : if (fp == nullptr) 158 : { 159 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot reopen updated %s", 160 : osFilename.c_str()); 161 0 : return OGRERR_FAILURE; 162 : } 163 : 164 1 : m_poFlatGeobufLayer = 165 1 : OGRFlatGeobufLayer::Open(osFilename.c_str(), fp, false); 166 1 : *ppoDecoratedLayer = m_poFlatGeobufLayer; 167 : 168 1 : return OGRERR_NONE; 169 : } 170 : 171 1 : OGRFlatGeobufEditableLayer::OGRFlatGeobufEditableLayer( 172 1 : OGRFlatGeobufLayer *poFlatGeobufLayer, char **papszOpenOptions) 173 : : OGREditableLayer(poFlatGeobufLayer, true, 174 : new OGRFlatGeobufEditableLayerSynchronizer( 175 1 : poFlatGeobufLayer, papszOpenOptions), 176 2 : true) 177 : { 178 1 : } 179 : 180 0 : GIntBig OGRFlatGeobufEditableLayer::GetFeatureCount(int bForce) 181 : { 182 0 : const GIntBig nRet = OGREditableLayer::GetFeatureCount(bForce); 183 0 : if (m_poDecoratedLayer != nullptr && m_nNextFID <= 0) 184 : { 185 : const GIntBig nTotalFeatureCount = 186 0 : static_cast<OGRFlatGeobufLayer *>(m_poDecoratedLayer) 187 0 : ->GetFeatureCount(false); 188 0 : if (nTotalFeatureCount >= 0) 189 0 : SetNextFID(nTotalFeatureCount + 1); 190 : } 191 0 : return nRet; 192 : } 193 : 194 : /************************************************************************/ 195 : /* TestCapability() */ 196 : /************************************************************************/ 197 : 198 4 : int OGRFlatGeobufEditableLayer::TestCapability(const char *pszCap) const 199 : { 200 4 : if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite) || 201 4 : EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCDeleteField) || 202 4 : EQUAL(pszCap, OLCReorderFields) || EQUAL(pszCap, OLCAlterFieldDefn) || 203 3 : EQUAL(pszCap, OLCDeleteFeature)) 204 : { 205 2 : return TRUE; 206 : } 207 : 208 2 : return OGREditableLayer::TestCapability(pszCap); 209 : }