Coverage Report

Created: 2025-06-13 06:29

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