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