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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "ogrsf_frmts.h"
30 : #include "cpl_vsi_virtual.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_json.h"
33 : #include "cpl_http.h"
34 : #include "ogr_p.h"
35 :
36 : #include "ogr_flatgeobuf.h"
37 : #include "geometryreader.h"
38 : #include "geometrywriter.h"
39 :
40 : #include <algorithm>
41 : #include <stdexcept>
42 :
43 : using namespace flatbuffers;
44 : using namespace FlatGeobuf;
45 : using namespace ogr_flatgeobuf;
46 :
47 : class OGRFlatGeobufEditableLayerSynchronizer final
48 : : public IOGREditableLayerSynchronizer
49 : {
50 : OGRFlatGeobufLayer *m_poFlatGeobufLayer;
51 : char **m_papszOpenOptions;
52 :
53 : public:
54 1 : OGRFlatGeobufEditableLayerSynchronizer(
55 : OGRFlatGeobufLayer *poFlatGeobufLayer, char **papszOpenOptions)
56 1 : : m_poFlatGeobufLayer(poFlatGeobufLayer),
57 1 : m_papszOpenOptions(CSLDuplicate(papszOpenOptions))
58 : {
59 1 : }
60 :
61 : virtual ~OGRFlatGeobufEditableLayerSynchronizer() override;
62 :
63 : virtual OGRErr EditableSyncToDisk(OGRLayer *poEditableLayer,
64 : OGRLayer **ppoDecoratedLayer) override;
65 : };
66 :
67 2 : OGRFlatGeobufEditableLayerSynchronizer::
68 1 : ~OGRFlatGeobufEditableLayerSynchronizer()
69 : {
70 1 : CSLDestroy(m_papszOpenOptions);
71 2 : }
72 :
73 1 : OGRErr OGRFlatGeobufEditableLayerSynchronizer::EditableSyncToDisk(
74 : OGRLayer *poEditableLayer, OGRLayer **ppoDecoratedLayer)
75 : {
76 1 : CPLDebugOnly("FlatGeobuf", "EditableSyncToDisk called");
77 :
78 1 : CPLAssert(m_poFlatGeobufLayer == *ppoDecoratedLayer);
79 :
80 2 : const CPLString osLayerName(m_poFlatGeobufLayer->GetName());
81 2 : const CPLString osFilename(m_poFlatGeobufLayer->GetFilename());
82 : VSIStatBufL sStatBuf;
83 2 : CPLString osTmpFilename(osFilename);
84 1 : if (VSIStatL(osFilename, &sStatBuf) == 0)
85 : {
86 1 : osTmpFilename += "_ogr_tmp.fgb";
87 : }
88 1 : OGRSpatialReference *spatialRef = m_poFlatGeobufLayer->GetSpatialRef();
89 1 : auto gType = m_poFlatGeobufLayer->getOGRwkbGeometryType();
90 1 : auto createIndex = m_poFlatGeobufLayer->GetIndexNodeSize() > 0;
91 :
92 2 : OGRFlatGeobufLayer *poFlatGeobufTmpLayer = OGRFlatGeobufLayer::Create(
93 1 : m_poFlatGeobufLayer->GetDataset(), osLayerName.c_str(),
94 : osTmpFilename.c_str(), spatialRef, gType, createIndex,
95 1 : m_papszOpenOptions);
96 1 : if (poFlatGeobufTmpLayer == nullptr)
97 0 : return OGRERR_FAILURE;
98 :
99 1 : OGRErr eErr = OGRERR_NONE;
100 1 : OGRFeatureDefn *poEditableFDefn = poEditableLayer->GetLayerDefn();
101 2 : for (int i = 0; eErr == OGRERR_NONE && i < poEditableFDefn->GetFieldCount();
102 : i++)
103 : {
104 1 : OGRFieldDefn oFieldDefn(poEditableFDefn->GetFieldDefn(i));
105 1 : eErr = poFlatGeobufTmpLayer->CreateField(&oFieldDefn);
106 : }
107 :
108 1 : poEditableLayer->ResetReading();
109 :
110 : // Disable all filters.
111 1 : const char *pszQueryStringConst = poEditableLayer->GetAttrQueryString();
112 : char *pszQueryStringBak =
113 1 : pszQueryStringConst ? CPLStrdup(pszQueryStringConst) : nullptr;
114 1 : poEditableLayer->SetAttributeFilter(nullptr);
115 :
116 1 : const int iFilterGeomIndexBak = poEditableLayer->GetGeomFieldFilter();
117 1 : OGRGeometry *poFilterGeomBak = poEditableLayer->GetSpatialFilter();
118 1 : if (poFilterGeomBak)
119 0 : poFilterGeomBak = poFilterGeomBak->clone();
120 1 : poEditableLayer->SetSpatialFilter(nullptr);
121 :
122 : auto aoMapSrcToTargetIdx =
123 : poFlatGeobufTmpLayer->GetLayerDefn()->ComputeMapForSetFrom(
124 2 : poEditableLayer->GetLayerDefn(), true);
125 1 : aoMapSrcToTargetIdx.push_back(
126 1 : -1); // add dummy entry to be sure that .data() is valid
127 :
128 3 : for (auto &&poFeature : poEditableLayer)
129 : {
130 2 : if (eErr != OGRERR_NONE)
131 0 : break;
132 : OGRFeature *poNewFeature =
133 2 : new OGRFeature(poFlatGeobufTmpLayer->GetLayerDefn());
134 2 : poNewFeature->SetFrom(poFeature.get(), aoMapSrcToTargetIdx.data(),
135 : true);
136 2 : eErr = poFlatGeobufTmpLayer->CreateFeature(poNewFeature);
137 2 : delete poNewFeature;
138 : }
139 1 : delete poFlatGeobufTmpLayer;
140 :
141 : // Restore filters.
142 1 : poEditableLayer->SetAttributeFilter(pszQueryStringBak);
143 1 : CPLFree(pszQueryStringBak);
144 1 : poEditableLayer->SetSpatialFilter(iFilterGeomIndexBak, poFilterGeomBak);
145 1 : delete poFilterGeomBak;
146 :
147 1 : if (eErr != OGRERR_NONE)
148 : {
149 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error while creating %s",
150 : osTmpFilename.c_str());
151 0 : VSIUnlink(osTmpFilename);
152 0 : return eErr;
153 : }
154 :
155 1 : delete m_poFlatGeobufLayer;
156 1 : *ppoDecoratedLayer = nullptr;
157 1 : m_poFlatGeobufLayer = nullptr;
158 :
159 1 : if (osFilename != osTmpFilename)
160 : {
161 1 : const CPLString osTmpOriFilename(osFilename + ".ogr_bak");
162 2 : if (VSIRename(osFilename, osTmpOriFilename) != 0 ||
163 1 : VSIRename(osTmpFilename, osFilename) != 0)
164 : {
165 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename files");
166 0 : return OGRERR_FAILURE;
167 : }
168 1 : VSIUnlink(osTmpOriFilename);
169 : }
170 :
171 1 : VSILFILE *fp = VSIFOpenL(osFilename, "rb+");
172 1 : if (fp == nullptr)
173 : {
174 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot reopen updated %s",
175 : osFilename.c_str());
176 0 : return OGRERR_FAILURE;
177 : }
178 :
179 1 : m_poFlatGeobufLayer =
180 1 : OGRFlatGeobufLayer::Open(osFilename.c_str(), fp, false);
181 1 : *ppoDecoratedLayer = m_poFlatGeobufLayer;
182 :
183 1 : return OGRERR_NONE;
184 : }
185 :
186 1 : OGRFlatGeobufEditableLayer::OGRFlatGeobufEditableLayer(
187 1 : OGRFlatGeobufLayer *poFlatGeobufLayer, char **papszOpenOptions)
188 : : OGREditableLayer(poFlatGeobufLayer, true,
189 : new OGRFlatGeobufEditableLayerSynchronizer(
190 1 : poFlatGeobufLayer, papszOpenOptions),
191 2 : true)
192 : {
193 1 : }
194 :
195 0 : GIntBig OGRFlatGeobufEditableLayer::GetFeatureCount(int bForce)
196 : {
197 0 : const GIntBig nRet = OGREditableLayer::GetFeatureCount(bForce);
198 0 : if (m_poDecoratedLayer != nullptr && m_nNextFID <= 0)
199 : {
200 : const GIntBig nTotalFeatureCount =
201 0 : static_cast<OGRFlatGeobufLayer *>(m_poDecoratedLayer)
202 0 : ->GetFeatureCount(false);
203 0 : if (nTotalFeatureCount >= 0)
204 0 : SetNextFID(nTotalFeatureCount + 1);
205 : }
206 0 : return nRet;
207 : }
208 :
209 : /************************************************************************/
210 : /* TestCapability() */
211 : /************************************************************************/
212 :
213 4 : int OGRFlatGeobufEditableLayer::TestCapability(const char *pszCap)
214 : {
215 4 : if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite) ||
216 4 : EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCDeleteField) ||
217 4 : EQUAL(pszCap, OLCReorderFields) || EQUAL(pszCap, OLCAlterFieldDefn) ||
218 3 : EQUAL(pszCap, OLCDeleteFeature))
219 : {
220 2 : return TRUE;
221 : }
222 :
223 2 : return OGREditableLayer::TestCapability(pszCap);
224 : }
|