Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL/OGR Geography Network support (Geographic Network Model)
4 : * Purpose: GNM db based generic driver.
5 : * Authors: Mikhail Gusev (gusevmihs at gmail dot com)
6 : * Dmitry Baryshnikov, polimax@mail.ru
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2014, Mikhail Gusev
10 : * Copyright (c) 2014-2015, NextGIS <info@nextgis.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gnmdb.h"
32 : #include "gnm_priv.h"
33 :
34 0 : GNMDatabaseNetwork::GNMDatabaseNetwork() : GNMGenericNetwork()
35 : {
36 0 : m_poDS = nullptr;
37 0 : }
38 :
39 0 : GNMDatabaseNetwork::~GNMDatabaseNetwork()
40 : {
41 0 : FlushCache(true);
42 :
43 0 : GDALClose(m_poDS);
44 0 : }
45 :
46 0 : CPLErr GNMDatabaseNetwork::Open(GDALOpenInfo *poOpenInfo)
47 : {
48 0 : FormName(poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions);
49 :
50 0 : if (CSLFindName(poOpenInfo->papszOpenOptions, "LIST_ALL_TABLES") == -1)
51 0 : poOpenInfo->papszOpenOptions = CSLAddNameValue(
52 : poOpenInfo->papszOpenOptions, "LIST_ALL_TABLES", "YES");
53 :
54 0 : m_poDS = (GDALDataset *)GDALOpenEx(m_soNetworkFullName,
55 : GDAL_OF_VECTOR | GDAL_OF_UPDATE, nullptr,
56 0 : nullptr, poOpenInfo->papszOpenOptions);
57 :
58 0 : if (nullptr == m_poDS)
59 : {
60 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' failed",
61 : m_soNetworkFullName.c_str());
62 0 : return CE_Failure;
63 : }
64 :
65 : // There should be only one schema so no schema name can be in table name
66 0 : if (LoadMetadataLayer(m_poDS) != CE_None)
67 : {
68 0 : return CE_Failure;
69 : }
70 :
71 0 : if (LoadGraphLayer(m_poDS) != CE_None)
72 : {
73 0 : return CE_Failure;
74 : }
75 :
76 0 : if (LoadFeaturesLayer(m_poDS) != CE_None)
77 : {
78 0 : return CE_Failure;
79 : }
80 :
81 0 : return CE_None;
82 : }
83 :
84 0 : CPLErr GNMDatabaseNetwork::Create(const char *pszFilename,
85 : CSLConstList papszOptions)
86 : {
87 0 : FormName(pszFilename, papszOptions);
88 :
89 0 : if (m_soName.empty() || m_soNetworkFullName.empty())
90 : {
91 0 : CPLError(CE_Failure, CPLE_IllegalArg,
92 : "The network name should be present");
93 0 : return CE_Failure;
94 : }
95 :
96 0 : if (nullptr == m_poDS)
97 : {
98 0 : m_poDS = (GDALDataset *)GDALOpenEx(m_soNetworkFullName,
99 : GDAL_OF_VECTOR | GDAL_OF_UPDATE,
100 : nullptr, nullptr, papszOptions);
101 : }
102 :
103 0 : if (nullptr == m_poDS)
104 : {
105 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' failed",
106 : m_soNetworkFullName.c_str());
107 0 : return CE_Failure;
108 : }
109 :
110 0 : GDALDriver *l_poDriver = m_poDS->GetDriver();
111 0 : if (nullptr == l_poDriver)
112 : {
113 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Get dataset driver failed");
114 0 : return CE_Failure;
115 : }
116 :
117 0 : if (!CheckStorageDriverSupport(l_poDriver->GetDescription()))
118 : {
119 0 : return CE_Failure;
120 : }
121 :
122 : // check required options
123 :
124 : const char *pszNetworkDescription =
125 0 : CSLFetchNameValue(papszOptions, GNM_MD_DESCR);
126 0 : if (nullptr != pszNetworkDescription)
127 0 : sDescription = pszNetworkDescription;
128 :
129 : // check Spatial reference
130 0 : const char *pszSRS = CSLFetchNameValue(papszOptions, GNM_MD_SRS);
131 0 : if (nullptr == pszSRS)
132 : {
133 0 : CPLError(CE_Failure, CPLE_IllegalArg,
134 : "The network spatial reference should be present");
135 0 : return CE_Failure;
136 : }
137 : else
138 : {
139 0 : OGRSpatialReference spatialRef;
140 0 : spatialRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
141 0 : if (spatialRef.SetFromUserInput(pszSRS) != OGRERR_NONE)
142 : {
143 0 : CPLError(CE_Failure, CPLE_IllegalArg,
144 : "The network spatial reference should be present");
145 0 : return CE_Failure;
146 : }
147 :
148 0 : m_oSRS = std::move(spatialRef);
149 : }
150 :
151 0 : int nResult = CheckNetworkExist(pszFilename, papszOptions);
152 :
153 0 : if (TRUE == nResult)
154 : {
155 0 : CPLError(CE_Failure, CPLE_IllegalArg, "The network already exist");
156 0 : return CE_Failure;
157 : }
158 :
159 : // Create the necessary system layers and fields
160 :
161 : // Create meta layer
162 :
163 0 : CPLErr eResult = CreateMetadataLayer(m_poDS, GNM_VERSION_NUM);
164 :
165 0 : if (CE_None != eResult)
166 : {
167 : // an error message should come from function
168 0 : return CE_Failure;
169 : }
170 :
171 : // Create graph layer
172 :
173 0 : eResult = CreateGraphLayer(m_poDS);
174 :
175 0 : if (CE_None != eResult)
176 : {
177 0 : DeleteMetadataLayer();
178 0 : return CE_Failure;
179 : }
180 :
181 : // Create features layer
182 :
183 0 : eResult = CreateFeaturesLayer(m_poDS);
184 :
185 0 : if (CE_None != eResult)
186 : {
187 0 : DeleteMetadataLayer();
188 0 : DeleteGraphLayer();
189 0 : return CE_Failure;
190 : }
191 :
192 0 : return CE_None;
193 : }
194 :
195 0 : int GNMDatabaseNetwork::CheckNetworkExist(const char *pszFilename,
196 : CSLConstList papszOptions)
197 : {
198 : // check if path exist
199 : // if path exist check if network already present and OVERWRITE option
200 : // else create the path
201 :
202 0 : if (FormName(pszFilename, papszOptions) != CE_None)
203 : {
204 0 : return TRUE;
205 : }
206 :
207 0 : if (nullptr == m_poDS)
208 : {
209 0 : m_poDS = (GDALDataset *)GDALOpenEx(m_soNetworkFullName,
210 : GDAL_OF_VECTOR | GDAL_OF_UPDATE,
211 : nullptr, nullptr, papszOptions);
212 : }
213 :
214 0 : const bool bOverwrite = CPLFetchBool(papszOptions, "OVERWRITE", false);
215 :
216 0 : std::vector<int> anDeleteLayers;
217 : int i;
218 0 : for (i = 0; i < m_poDS->GetLayerCount(); ++i)
219 : {
220 0 : OGRLayer *poLayer = m_poDS->GetLayer(i);
221 0 : if (nullptr == poLayer)
222 0 : continue;
223 :
224 0 : if (EQUAL(poLayer->GetName(), GNM_SYSLAYER_META) ||
225 0 : EQUAL(poLayer->GetName(), GNM_SYSLAYER_GRAPH) ||
226 0 : EQUAL(poLayer->GetName(), GNM_SYSLAYER_FEATURES))
227 : {
228 0 : anDeleteLayers.push_back(i);
229 : }
230 : }
231 :
232 0 : if (anDeleteLayers.empty())
233 0 : return FALSE;
234 :
235 0 : if (bOverwrite)
236 : {
237 0 : for (i = (int)anDeleteLayers.size(); i > 0; i--)
238 : {
239 0 : CPLDebug("GNM", "Delete layer: %d", i);
240 0 : if (m_poDS->DeleteLayer(anDeleteLayers[i - 1]) != OGRERR_NONE)
241 0 : return TRUE;
242 : }
243 0 : return FALSE;
244 : }
245 : else
246 : {
247 0 : return TRUE;
248 : }
249 : }
250 :
251 0 : CPLErr GNMDatabaseNetwork::DeleteMetadataLayer()
252 : {
253 0 : return DeleteLayerByName(GNM_SYSLAYER_META);
254 : }
255 :
256 0 : CPLErr GNMDatabaseNetwork::DeleteGraphLayer()
257 : {
258 0 : return DeleteLayerByName(GNM_SYSLAYER_GRAPH);
259 : }
260 :
261 0 : CPLErr GNMDatabaseNetwork::DeleteFeaturesLayer()
262 : {
263 0 : return DeleteLayerByName(GNM_SYSLAYER_FEATURES);
264 : }
265 :
266 0 : CPLErr GNMDatabaseNetwork::DeleteLayerByName(const char *pszLayerName)
267 : {
268 0 : if (nullptr == m_poDS)
269 0 : return CE_Failure;
270 :
271 0 : for (int i = 0; i < m_poDS->GetLayerCount(); ++i)
272 : {
273 0 : OGRLayer *poLayer = m_poDS->GetLayer(i);
274 0 : if (nullptr == poLayer)
275 0 : continue;
276 :
277 0 : if (EQUAL(poLayer->GetName(), pszLayerName))
278 0 : return m_poDS->DeleteLayer(i) == OGRERR_NONE ? CE_None : CE_Failure;
279 : }
280 :
281 0 : CPLError(CE_Failure, CPLE_IllegalArg, "The layer %s not exist",
282 : pszLayerName);
283 0 : return CE_Failure;
284 : }
285 :
286 0 : CPLErr GNMDatabaseNetwork::DeleteNetworkLayers()
287 : {
288 0 : while (GetLayerCount() > 0)
289 : {
290 0 : OGRErr eErr = DeleteLayer(0);
291 0 : if (eErr != OGRERR_NONE)
292 0 : return CE_Failure;
293 : }
294 0 : return CE_None;
295 : }
296 :
297 0 : CPLErr GNMDatabaseNetwork::LoadNetworkLayer(const char *pszLayername)
298 : {
299 : // check if not loaded
300 0 : for (size_t i = 0; i < m_apoLayers.size(); ++i)
301 : {
302 0 : if (EQUAL(m_apoLayers[i]->GetName(), pszLayername))
303 0 : return CE_None;
304 : }
305 :
306 0 : OGRLayer *poLayer = m_poDS->GetLayerByName(pszLayername);
307 0 : if (nullptr == poLayer)
308 : {
309 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Layer '%s' is not exist",
310 : pszLayername);
311 0 : return CE_Failure;
312 : }
313 :
314 0 : CPLDebug("GNM", "Layer '%s' loaded", poLayer->GetName());
315 :
316 0 : GNMGenericLayer *pGNMLayer = new GNMGenericLayer(poLayer, this);
317 0 : m_apoLayers.push_back(pGNMLayer);
318 :
319 0 : return CE_None;
320 : }
321 :
322 0 : bool GNMDatabaseNetwork::CheckStorageDriverSupport(const char *pszDriverName)
323 : {
324 0 : if (EQUAL(pszDriverName, "PostgreSQL"))
325 0 : return true;
326 : // TODO: expand this list with supported OGR direvers
327 0 : return false;
328 : }
329 :
330 0 : CPLErr GNMDatabaseNetwork::FormName(const char *pszFilename,
331 : CSLConstList papszOptions)
332 : {
333 0 : if (m_soNetworkFullName.empty())
334 0 : m_soNetworkFullName = pszFilename;
335 :
336 0 : if (m_soName.empty())
337 : {
338 : const char *pszNetworkName =
339 0 : CSLFetchNameValue(papszOptions, GNM_MD_NAME);
340 0 : if (nullptr != pszNetworkName)
341 : {
342 0 : m_soName = pszNetworkName;
343 : }
344 :
345 : char *pszActiveSchemaStart;
346 0 : pszActiveSchemaStart = (char *)strstr(pszFilename, "active_schema=");
347 0 : if (pszActiveSchemaStart == nullptr)
348 : pszActiveSchemaStart =
349 0 : (char *)strstr(pszFilename, "ACTIVE_SCHEMA=");
350 0 : if (pszActiveSchemaStart != nullptr)
351 : {
352 : char *pszActiveSchema;
353 :
354 : pszActiveSchema =
355 0 : CPLStrdup(pszActiveSchemaStart + strlen("active_schema="));
356 :
357 0 : const char *pszEnd = strchr(pszActiveSchemaStart, ' ');
358 0 : if (pszEnd == nullptr)
359 0 : pszEnd = pszFilename + strlen(pszFilename);
360 :
361 0 : pszActiveSchema[pszEnd - pszActiveSchemaStart -
362 0 : strlen("active_schema=")] = '\0';
363 :
364 0 : m_soName = pszActiveSchema;
365 0 : CPLFree(pszActiveSchema);
366 : }
367 : else
368 : {
369 0 : if (!m_soName.empty())
370 : {
371 : // add active schema
372 0 : m_soNetworkFullName += "ACTIVE_SCHEMA=" + m_soName;
373 : }
374 : else
375 : {
376 0 : m_soName = "public";
377 : }
378 : }
379 :
380 0 : CPLDebug("GNM", "Network name: %s", m_soName.c_str());
381 : }
382 0 : return CE_None;
383 : }
384 :
385 0 : OGRErr GNMDatabaseNetwork::DeleteLayer(int nIndex)
386 : {
387 0 : if (nullptr == m_poDS)
388 : {
389 0 : CPLError(CE_Failure, CPLE_FileIO, "Network not opened.");
390 0 : return OGRERR_FAILURE;
391 : }
392 :
393 0 : OGRLayer *poNetworkLayer = GetLayer(nIndex);
394 :
395 0 : CPLDebug("GNM", "Delete network layer '%s'", poNetworkLayer->GetName());
396 :
397 0 : int nDeleteIndex = -1;
398 0 : for (int i = 0; i < m_poDS->GetLayerCount(); ++i)
399 : {
400 0 : OGRLayer *poLayer = m_poDS->GetLayer(i);
401 0 : if (EQUAL(poNetworkLayer->GetName(), poLayer->GetName()))
402 : {
403 0 : nDeleteIndex = i;
404 0 : break;
405 : }
406 : }
407 :
408 0 : if (m_poDS->DeleteLayer(nDeleteIndex) != OGRERR_NONE)
409 : {
410 0 : return OGRERR_FAILURE;
411 : }
412 :
413 0 : return GNMGenericNetwork::DeleteLayer(nIndex);
414 : }
415 :
416 : OGRLayer *
417 0 : GNMDatabaseNetwork::ICreateLayer(const char *pszName,
418 : const OGRGeomFieldDefn *poGeomFieldDefn,
419 : CSLConstList papszOptions)
420 : {
421 : // check if layer with such name exist
422 0 : for (int i = 0; i < GetLayerCount(); ++i)
423 : {
424 0 : OGRLayer *pLayer = GetLayer(i);
425 0 : if (nullptr == pLayer)
426 0 : continue;
427 0 : if (EQUAL(pLayer->GetName(), pszName))
428 : {
429 0 : CPLError(CE_Failure, CPLE_IllegalArg,
430 : "The network layer '%s' already exist.", pszName);
431 0 : return nullptr;
432 : }
433 : }
434 :
435 0 : OGRSpatialReference oSpaRef(m_oSRS);
436 :
437 0 : const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
438 : OGRLayer *poLayer =
439 0 : m_poDS->CreateLayer(pszName, &oSpaRef, eGType, papszOptions);
440 0 : if (poLayer == nullptr)
441 : {
442 0 : CPLError(CE_Failure, CPLE_FileIO, "Layer creation failed.");
443 0 : return nullptr;
444 : }
445 :
446 0 : OGRFieldDefn oField(GNM_SYSFIELD_GFID, GNMGFIDInt);
447 0 : if (poLayer->CreateField(&oField) != OGRERR_NONE)
448 : {
449 0 : CPLError(CE_Failure, CPLE_FileIO,
450 : "Creating global identificator field failed.");
451 0 : return nullptr;
452 : }
453 :
454 0 : OGRFieldDefn oFieldBlock(GNM_SYSFIELD_BLOCKED, OFTInteger);
455 0 : if (poLayer->CreateField(&oFieldBlock) != OGRERR_NONE)
456 : {
457 0 : CPLError(CE_Failure, CPLE_FileIO, "Creating is blocking field failed.");
458 0 : return nullptr;
459 : }
460 :
461 0 : GNMGenericLayer *pGNMLayer = new GNMGenericLayer(poLayer, this);
462 0 : m_apoLayers.push_back(pGNMLayer);
463 0 : return pGNMLayer;
464 : }
|