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 CPL_CVSID("$Id: gnmdbnetwork.cpp 4b92a13c594df8c488d24a2299c64a31bb14668b 2019-03-23 13:03:10 +0100 Even Rouault $")
35
36 GNMDatabaseNetwork::GNMDatabaseNetwork() : GNMGenericNetwork()
GNMDBDriverIdentify(GDALOpenInfo * poOpenInfo)37 {
38 m_poDS = nullptr;
39 }
40
41 GNMDatabaseNetwork::~GNMDatabaseNetwork()
42 {
43 FlushCache();
44
45 GDALClose(m_poDS);
46 }
47
48 CPLErr GNMDatabaseNetwork::Open(GDALOpenInfo *poOpenInfo)
49 {
50 FormName(poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions);
GNMDBDriverOpen(GDALOpenInfo * poOpenInfo)51
52 if(CSLFindName(poOpenInfo->papszOpenOptions, "LIST_ALL_TABLES") == -1)
53 poOpenInfo->papszOpenOptions = CSLAddNameValue(
54 poOpenInfo->papszOpenOptions, "LIST_ALL_TABLES", "YES");
55
56 m_poDS = (GDALDataset*) GDALOpenEx( m_soNetworkFullName, GDAL_OF_VECTOR |
57 GDAL_OF_UPDATE, nullptr, nullptr, poOpenInfo->papszOpenOptions );
58
59 if( nullptr == m_poDS )
60 {
61 CPLError( CE_Failure, CPLE_OpenFailed, "Open '%s' failed",
62 m_soNetworkFullName.c_str() );
63 return CE_Failure;
64 }
65
66 // There should be only one schema so no schema name can be in table name
67 if(LoadMetadataLayer(m_poDS) != CE_None)
GNMDBDriverCreate(const char * pszName,CPL_UNUSED int nBands,CPL_UNUSED int nXSize,CPL_UNUSED int nYSize,CPL_UNUSED GDALDataType eDT,char ** papszOptions)68 {
69 return CE_Failure;
70 }
71
72 if(LoadGraphLayer(m_poDS) != CE_None)
73 {
74 return CE_Failure;
75 }
76
77 if(LoadFeaturesLayer(m_poDS) != CE_None)
78 {
79 return CE_Failure;
80 }
81
82 return CE_None;
83 }
84
85 CPLErr GNMDatabaseNetwork::Create( const char* pszFilename, char** papszOptions )
86 {
87 FormName(pszFilename, papszOptions);
88
GNMDBDriverDelete(const char * pszDataSource)89 if(m_soName.empty() || m_soNetworkFullName.empty())
90 {
91 CPLError( CE_Failure, CPLE_IllegalArg,
92 "The network name should be present" );
93 return CE_Failure;
94 }
95
96 if(nullptr == m_poDS)
97 {
98 m_poDS = (GDALDataset*) GDALOpenEx( m_soNetworkFullName, GDAL_OF_VECTOR |
99 GDAL_OF_UPDATE, nullptr, nullptr, papszOptions );
100 }
101
102 if( nullptr == m_poDS )
103 {
104 CPLError( CE_Failure, CPLE_OpenFailed, "Open '%s' failed",
105 m_soNetworkFullName.c_str() );
RegisterGNMDatabase()106 return CE_Failure;
107 }
108
109 GDALDriver *l_poDriver = m_poDS->GetDriver();
110 if(nullptr == l_poDriver)
111 {
112 CPLError( CE_Failure, CPLE_OpenFailed, "Get dataset driver failed");
113 return CE_Failure;
114 }
115
116 if(!CheckStorageDriverSupport(l_poDriver->GetDescription()))
117 {
118 return CE_Failure;
119 }
120
121 // check required options
122
123 const char* pszNetworkDescription = CSLFetchNameValue(papszOptions,
124 GNM_MD_DESCR);
125 if(nullptr != pszNetworkDescription)
126 sDescription = pszNetworkDescription;
127
128 // check Spatial reference
129 const char* pszSRS = CSLFetchNameValue(papszOptions, GNM_MD_SRS);
130 if( nullptr == pszSRS )
131 {
132 CPLError( CE_Failure, CPLE_IllegalArg,
133 "The network spatial reference should be present" );
134 return CE_Failure;
135 }
136 else
137 {
138 OGRSpatialReference spatialRef;
139 if (spatialRef.SetFromUserInput(pszSRS) != OGRERR_NONE)
140 {
141 CPLError( CE_Failure, CPLE_IllegalArg,
142 "The network spatial reference should be present" );
143 return CE_Failure;
144 }
145
146 char *wktSrs = nullptr;
147 if (spatialRef.exportToWkt(&wktSrs) != OGRERR_NONE)
148 {
149 CPLError( CE_Failure, CPLE_IllegalArg,
150 "The network spatial reference should be present" );
151 CPLFree(wktSrs);
152 return CE_Failure;
153 }
154 m_soSRS = wktSrs;
155
156 CPLFree(wktSrs);
157 }
158
159 int nResult = CheckNetworkExist(pszFilename, papszOptions);
160
161 if(TRUE == nResult)
162 {
163 CPLError( CE_Failure, CPLE_IllegalArg, "The network already exist" );
164 return CE_Failure;
165 }
166
167 // Create the necessary system layers and fields
168
169 // Create meta layer
170
171 CPLErr eResult = CreateMetadataLayer(m_poDS, GNM_VERSION_NUM);
172
173 if(CE_None != eResult)
174 {
175 //an error message should come from function
176 return CE_Failure; }
177
178 // Create graph layer
179
180 eResult = CreateGraphLayer(m_poDS);
181
182 if(CE_None != eResult)
183 {
184 DeleteMetadataLayer();
185 return CE_Failure;
186 }
187
188 // Create features layer
189
190 eResult = CreateFeaturesLayer(m_poDS);
191
192 if(CE_None != eResult)
193 {
194 DeleteMetadataLayer();
195 DeleteGraphLayer();
196 return CE_Failure;
197 }
198
199 return CE_None;
200 }
201
202 int GNMDatabaseNetwork::CheckNetworkExist(const char *pszFilename, char **papszOptions)
203 {
204 // check if path exist
205 // if path exist check if network already present and OVERWRITE option
206 // else create the path
207
208 if(FormName(pszFilename, papszOptions) != CE_None)
209 {
210 return TRUE;
211 }
212
213 if(nullptr == m_poDS)
214 {
215 m_poDS = (GDALDataset*) GDALOpenEx( m_soNetworkFullName, GDAL_OF_VECTOR |
216 GDAL_OF_UPDATE, nullptr, nullptr, papszOptions );
217 }
218
219 const bool bOverwrite = CPLFetchBool(papszOptions, "OVERWRITE", false);
220
221 std::vector<int> anDeleteLayers;
222 int i;
223 for(i = 0; i < m_poDS->GetLayerCount(); ++i)
224 {
225 OGRLayer* poLayer = m_poDS->GetLayer(i);
226 if(nullptr == poLayer)
227 continue;
228
229 if(EQUAL(poLayer->GetName(), GNM_SYSLAYER_META) ||
230 EQUAL(poLayer->GetName(), GNM_SYSLAYER_GRAPH) ||
231 EQUAL(poLayer->GetName(), GNM_SYSLAYER_FEATURES) )
232 {
233 anDeleteLayers.push_back(i);
234 }
235 }
236
237 if(anDeleteLayers.empty())
238 return FALSE;
239
240 if( bOverwrite )
241 {
242 for(i = (int)anDeleteLayers.size(); i > 0; i--)
243 {
244 CPLDebug("GNM", "Delete layer: %d", i);
245 if(m_poDS->DeleteLayer(anDeleteLayers[i - 1]) != OGRERR_NONE)
246 return TRUE;
247 }
248 return FALSE;
249 }
250 else
251 {
252 return TRUE;
253 }
254 }
255
256 CPLErr GNMDatabaseNetwork::DeleteMetadataLayer()
257 {
258 return DeleteLayerByName(GNM_SYSLAYER_META);
259 }
260
261 CPLErr GNMDatabaseNetwork::DeleteGraphLayer()
262 {
263 return DeleteLayerByName(GNM_SYSLAYER_GRAPH);
264 }
265
266 CPLErr GNMDatabaseNetwork::DeleteFeaturesLayer()
267 {
268 return DeleteLayerByName(GNM_SYSLAYER_FEATURES);
269 }
270
271 CPLErr GNMDatabaseNetwork::DeleteLayerByName(const char* pszLayerName)
272 {
273 if(nullptr == m_poDS)
274 return CE_Failure;
275
276 for(int i = 0; i < m_poDS->GetLayerCount(); ++i)
277 {
278 OGRLayer* poLayer = m_poDS->GetLayer(i);
279 if(nullptr == poLayer)
280 continue;
281
282 if(EQUAL(poLayer->GetName(), pszLayerName))
283 return m_poDS->DeleteLayer(i) == OGRERR_NONE ? CE_None : CE_Failure;
284 }
285
286 CPLError(CE_Failure, CPLE_IllegalArg, "The layer %s not exist",
287 pszLayerName );
288 return CE_Failure;
289 }
290
291 CPLErr GNMDatabaseNetwork::DeleteNetworkLayers()
292 {
293 while(GetLayerCount() > 0)
294 {
295 OGRErr eErr = DeleteLayer(0);
296 if(eErr != OGRERR_NONE)
297 return CE_Failure;
298 }
299 return CE_None;
300 }
301
302 CPLErr GNMDatabaseNetwork::LoadNetworkLayer(const char *pszLayername)
303 {
304 // check if not loaded
305 for(size_t i = 0; i < m_apoLayers.size(); ++i)
306 {
307 if(EQUAL(m_apoLayers[i]->GetName(), pszLayername))
308 return CE_None;
309 }
310
311 OGRLayer* poLayer = m_poDS->GetLayerByName(pszLayername);
312 if(nullptr == poLayer)
313 {
314 CPLError( CE_Failure, CPLE_OpenFailed, "Layer '%s' is not exist",
315 pszLayername );
316 return CE_Failure;
317 }
318
319 CPLDebug("GNM", "Layer '%s' loaded", poLayer->GetName());
320
321 GNMGenericLayer* pGNMLayer = new GNMGenericLayer(poLayer, this);
322 m_apoLayers.push_back(pGNMLayer);
323
324 return CE_None;
325 }
326
327 bool GNMDatabaseNetwork::CheckStorageDriverSupport(const char *pszDriverName)
328 {
329 if(EQUAL(pszDriverName, "PostgreSQL"))
330 return true;
331 //TODO: expand this list with supported OGR direvers
332 return false;
333 }
334
335 CPLErr GNMDatabaseNetwork::FormName(const char *pszFilename, char **papszOptions)
336 {
337 if(m_soNetworkFullName.empty())
338 m_soNetworkFullName = pszFilename;
339
340 if(m_soName.empty())
341 {
342 const char* pszNetworkName = CSLFetchNameValue(papszOptions, GNM_MD_NAME);
343 if(nullptr != pszNetworkName)
344 {
345 m_soName = pszNetworkName;
346 }
347
348 char *pszActiveSchemaStart;
349 pszActiveSchemaStart = (char *)strstr(pszFilename, "active_schema=");
350 if (pszActiveSchemaStart == nullptr)
351 pszActiveSchemaStart = (char *)strstr(pszFilename, "ACTIVE_SCHEMA=");
352 if (pszActiveSchemaStart != nullptr)
353 {
354 char *pszActiveSchema;
355
356 pszActiveSchema = CPLStrdup( pszActiveSchemaStart + strlen("active_schema=") );
357
358 const char* pszEnd = strchr(pszActiveSchemaStart, ' ');
359 if( pszEnd == nullptr )
360 pszEnd = pszFilename + strlen(pszFilename);
361
362 pszActiveSchema[pszEnd - pszActiveSchemaStart - strlen("active_schema=")] = '\0';
363
364 m_soName = pszActiveSchema;
365 CPLFree(pszActiveSchema);
366 }
367 else
368 {
369 if(!m_soName.empty())
370 {
371 //add active schema
372 m_soNetworkFullName += "ACTIVE_SCHEMA=" + m_soName;
373 }
374 else
375 {
376 m_soName = "public";
377 }
378 }
379
380 CPLDebug( "GNM", "Network name: %s", m_soName.c_str() );
381 }
382 return CE_None;
383 }
384
385 OGRErr GNMDatabaseNetwork::DeleteLayer(int nIndex)
386 {
387 if(nullptr == m_poDS)
388 {
389 CPLError(CE_Failure, CPLE_FileIO, "Network not opened." );
390 return OGRERR_FAILURE;
391 }
392
393 OGRLayer* poNetworkLayer = GetLayer(nIndex);
394
395 CPLDebug("GNM", "Delete network layer '%s'", poNetworkLayer->GetName());
396
397 int nDeleteIndex = -1;
398 for(int i = 0; i < m_poDS->GetLayerCount(); ++i)
399 {
400 OGRLayer* poLayer = m_poDS->GetLayer(i);
401 if(EQUAL(poNetworkLayer->GetName(), poLayer->GetName()))
402 {
403 nDeleteIndex = i;
404 break;
405 }
406 }
407
408 if(m_poDS->DeleteLayer(nDeleteIndex) != OGRERR_NONE)
409 {
410 return OGRERR_FAILURE;
411 }
412
413 return GNMGenericNetwork::DeleteLayer(nIndex);
414 }
415
416 OGRLayer *GNMDatabaseNetwork::ICreateLayer(const char *pszName,
417 OGRSpatialReference * /*poSpatialRef*/,
418 OGRwkbGeometryType eGType, char **papszOptions)
419 {
420 //check if layer with such name exist
421 for(int i = 0; i < GetLayerCount(); ++i)
422 {
423 OGRLayer* pLayer = GetLayer(i);
424 if(nullptr == pLayer)
425 continue;
426 if(EQUAL(pLayer->GetName(), pszName))
427 {
428 CPLError( CE_Failure, CPLE_IllegalArg,
429 "The network layer '%s' already exist.", pszName );
430 return nullptr;
431 }
432 }
433
434 OGRSpatialReference oSpaRef(m_soSRS);
435
436 OGRLayer *poLayer = m_poDS->CreateLayer( pszName, &oSpaRef, eGType, papszOptions );
437 if( poLayer == nullptr )
438 {
439 CPLError( CE_Failure, CPLE_FileIO, "Layer creation failed." );
440 return nullptr;
441 }
442
443 OGRFieldDefn oField( GNM_SYSFIELD_GFID, GNMGFIDInt );
444 if( poLayer->CreateField( &oField ) != OGRERR_NONE )
445 {
446 CPLError( CE_Failure, CPLE_FileIO, "Creating global identificator field failed." );
447 return nullptr;
448 }
449
450 OGRFieldDefn oFieldBlock(GNM_SYSFIELD_BLOCKED, OFTInteger);
451 if( poLayer->CreateField( &oFieldBlock ) != OGRERR_NONE )
452 {
453 CPLError( CE_Failure, CPLE_FileIO, "Creating is blocking field failed." );
454 return nullptr;
455 }
456
457 GNMGenericLayer* pGNMLayer = new GNMGenericLayer(poLayer, this);
458 m_apoLayers.push_back(pGNMLayer);
459 return pGNMLayer;
460 }
461