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 : }