Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  VFK Reader - Data block definition (SQLite)
4
 * Purpose:  Implements VFKDataBlockSQLite
5
 * Author:   Martin Landa, landa.martin gmail.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2012-2014, Martin Landa <landa.martin gmail.com>
9
 * Copyright (c) 2012-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include <algorithm>
15
#include <limits>
16
#include <map>
17
#include <utility>
18
19
#include "vfkreader.h"
20
#include "vfkreaderp.h"
21
22
#include "cpl_conv.h"
23
#include "cpl_error.h"
24
25
/*!
26
  \brief VFKDataBlockSQLite constructor
27
*/
28
VFKDataBlockSQLite::VFKDataBlockSQLite(const char *pszName,
29
                                       const IVFKReader *poReader)
30
9.67k
    : IVFKDataBlock(pszName, poReader), m_hStmt(nullptr)
31
9.67k
{
32
9.67k
}
33
34
/*!
35
  \brief Load geometry (point layers)
36
37
  \return number of invalid features
38
*/
39
int VFKDataBlockSQLite::LoadGeometryPoint()
40
313
{
41
313
    if (LoadGeometryFromDB()) /* try to load geometry from DB */
42
46
        return 0;
43
44
267
    const bool bSkipInvalid = EQUAL(m_pszName, "OB") ||
45
239
                              EQUAL(m_pszName, "OP") ||
46
212
                              EQUAL(m_pszName, "OBBP");
47
48
267
    CPLString osSQL;
49
267
    osSQL.Printf("SELECT SOURADNICE_Y,SOURADNICE_X,%s,rowid FROM %s",
50
267
                 FID_COLUMN, m_pszName);
51
52
267
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
53
267
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
54
55
267
    if (poReader->IsSpatial())
56
267
        poReader->ExecuteSQL("BEGIN");
57
58
267
    int nGeometries = 0;
59
267
    int nInvalid = 0;
60
3.02k
    while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
61
2.76k
    {
62
        /* read values */
63
2.76k
        const double x =
64
2.76k
            -1.0 * sqlite3_column_double(
65
2.76k
                       hStmt, 0); /* S-JTSK coordinate system expected */
66
2.76k
        const double y = -1.0 * sqlite3_column_double(hStmt, 1);
67
2.76k
        const GIntBig iFID = sqlite3_column_int64(hStmt, 2);
68
2.76k
        const int rowId = sqlite3_column_int(hStmt, 3);
69
70
2.76k
        VFKFeatureSQLite *poFeature =
71
2.76k
            dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
72
2.76k
        if (poFeature == nullptr || poFeature->GetFID() != iFID)
73
1
        {
74
1
            continue;
75
1
        }
76
77
        /* create geometry */
78
2.75k
        OGRPoint pt(x, y);
79
2.75k
        if (!poFeature->SetGeometry(&pt))
80
306
        {
81
306
            nInvalid++;
82
306
            continue;
83
306
        }
84
85
        /* store also geometry in DB */
86
2.45k
        if (poReader->IsSpatial() &&
87
2.45k
            SaveGeometryToDB(&pt, rowId) != OGRERR_FAILURE)
88
2.45k
            nGeometries++;
89
2.45k
    }
90
91
    /* update number of geometries in VFK_DB_TABLE table */
92
267
    UpdateVfkBlocks(nGeometries);
93
94
267
    if (poReader->IsSpatial())
95
267
        poReader->ExecuteSQL("COMMIT");
96
97
267
    return bSkipInvalid ? 0 : nInvalid;
98
313
}
99
100
/*!
101
  \brief Set geometry for linestrings
102
103
  \param poLine VFK feature
104
  \param oOGRLine line geometry
105
  \param[in,out] bValid true when feature's geometry is valid
106
  \param ftype geometry VFK type
107
  \param[in,out] rowIdFeat list of row ids which forms linestring
108
  \param[in,out] nGeometries number of features with valid geometry
109
*/
110
bool VFKDataBlockSQLite::SetGeometryLineString(VFKFeatureSQLite *poLine,
111
                                               OGRLineString *oOGRLine,
112
                                               bool &bValid, const char *ftype,
113
                                               std::vector<int> &rowIdFeat,
114
                                               int &nGeometries)
115
3.71k
{
116
3.71k
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
117
118
3.71k
    oOGRLine->setCoordinateDimension(2); /* force 2D */
119
120
    /* check also VFK validity */
121
3.71k
    if (bValid)
122
1.85k
    {
123
        /* Feature types
124
125
           - '3'    - line       (2 points)
126
           - '4'    - linestring (at least 2 points)
127
           - '11'   - curve      (at least 2 points)
128
           - '15'   - circle     (3 points)
129
           - '15 r' - circle     (center point & radius)
130
           - '16'   - arc        (3 points)
131
        */
132
133
1.85k
        const int npoints = oOGRLine->getNumPoints();
134
1.85k
        if (EQUAL(ftype, "3") && npoints > 2)
135
0
        {
136
            /* be less pedantic, just inform user about data
137
             * inconsistency
138
139
               bValid = false;
140
            */
141
0
            CPLDebug("OGR-VFK",
142
0
                     "Line (fid=" CPL_FRMT_GIB
143
0
                     ") defined by more than two vertices",
144
0
                     poLine->GetFID());
145
0
        }
146
1.85k
        else if (EQUAL(ftype, "11") && npoints < 2)
147
0
        {
148
0
            bValid = false;
149
0
            CPLError(CE_Warning, CPLE_AppDefined,
150
0
                     "Curve (fid=" CPL_FRMT_GIB
151
0
                     ") defined by less than two vertices",
152
0
                     poLine->GetFID());
153
0
        }
154
1.85k
        else if (EQUAL(ftype, "15") && npoints != 3)
155
0
        {
156
0
            bValid = false;
157
0
            CPLError(CE_Warning, CPLE_AppDefined,
158
0
                     "Circle (fid=" CPL_FRMT_GIB
159
0
                     ") defined by invalid number of vertices (%d)",
160
0
                     poLine->GetFID(), oOGRLine->getNumPoints());
161
0
        }
162
1.85k
        else if (strlen(ftype) > 2 && STARTS_WITH_CI(ftype, "15") &&
163
0
                 npoints != 1)
164
0
        {
165
0
            bValid = false;
166
0
            CPLError(CE_Warning, CPLE_AppDefined,
167
0
                     "Circle (fid=" CPL_FRMT_GIB
168
0
                     ") defined by invalid number of vertices (%d)",
169
0
                     poLine->GetFID(), oOGRLine->getNumPoints());
170
0
        }
171
1.85k
        else if (EQUAL(ftype, "16") && npoints != 3)
172
32
        {
173
32
            bValid = false;
174
32
            CPLError(CE_Warning, CPLE_AppDefined,
175
32
                     "Arc (fid=" CPL_FRMT_GIB
176
32
                     ") defined by invalid number of vertices (%d)",
177
32
                     poLine->GetFID(), oOGRLine->getNumPoints());
178
32
        }
179
1.85k
    }
180
181
    /* set geometry (NULL for invalid features) */
182
3.71k
    if (bValid)
183
1.82k
    {
184
1.82k
        if (!poLine->SetGeometry(oOGRLine, ftype))
185
1.75k
        {
186
1.75k
            bValid = false;
187
1.75k
        }
188
1.82k
    }
189
1.89k
    else
190
1.89k
    {
191
1.89k
        poLine->SetGeometry(nullptr);
192
1.89k
    }
193
194
    /* update fid column */
195
3.71k
    UpdateFID(poLine->GetFID(), rowIdFeat);
196
197
    /* store also geometry in DB */
198
3.71k
    CPLAssert(!rowIdFeat.empty());
199
3.71k
    if (bValid && poReader->IsSpatial() &&
200
67
        SaveGeometryToDB(poLine->GetGeometry(), rowIdFeat[0]) != OGRERR_FAILURE)
201
67
    {
202
67
        nGeometries++;
203
67
    }
204
205
3.71k
    rowIdFeat.clear();
206
3.71k
    oOGRLine->empty(); /* restore line */
207
208
3.71k
    return bValid;
209
3.71k
}
210
211
/*!
212
  \brief Load geometry (linestring SBP layer)
213
214
  \return number of invalid features
215
*/
216
int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
217
236
{
218
236
    int nInvalid = 0;
219
220
236
    VFKDataBlockSQLite *poDataBlockPoints =
221
236
        cpl::down_cast<VFKDataBlockSQLite *>(m_poReader->GetDataBlock("SOBR"));
222
236
    if (nullptr == poDataBlockPoints)
223
106
    {
224
106
        CPLError(CE_Failure, CPLE_FileIO, "Data block %s not found.\n",
225
106
                 m_pszName);
226
106
        return nInvalid;
227
106
    }
228
229
130
    int nGeometries = 0;
230
130
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
231
232
130
    poDataBlockPoints->LoadGeometry();
233
234
130
    if (LoadGeometryFromDB()) /* try to load geometry from DB */
235
8
        return 0;
236
237
122
    CPLString osSQL;
238
122
    osSQL.Printf("UPDATE %s SET %s = -1", m_pszName, FID_COLUMN);
239
122
    poReader->ExecuteSQL(osSQL.c_str());
240
122
    bool bValid = true;
241
122
    int iIdx = 0;
242
243
122
    VFKFeatureSQLite *poLine = nullptr;
244
245
366
    for (int i = 0; i < 2; i++)
246
244
    {
247
        /* first collect linestrings related to HP, OB, DPM and ZVB
248
           then collect rest of linestrings */
249
244
        if (i == 0)
250
122
            osSQL.Printf(
251
122
                "SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ "
252
122
                "FROM '%s' WHERE "
253
122
                "HP_ID IS NOT NULL OR OB_ID IS NOT NULL OR DPM_ID IS NOT NULL "
254
122
                "OR ZVB_ID IS NOT NULL "
255
122
                "ORDER BY HP_ID,OB_ID,DPM_ID,ZVB_ID,PORADOVE_CISLO_BODU",
256
122
                m_pszName);
257
122
        else
258
122
            osSQL.Printf(
259
122
                "SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ "
260
122
                "FROM '%s' WHERE "
261
122
                "OB_ID IS NULL AND HP_ID IS NULL AND DPM_ID IS NULL AND ZVB_ID "
262
122
                "IS NULL "
263
122
                "ORDER BY ID,PORADOVE_CISLO_BODU",
264
122
                m_pszName);
265
266
244
        sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
267
268
244
        if (poReader->IsSpatial())
269
244
            poReader->ExecuteSQL("BEGIN");
270
271
244
        std::vector<int> rowIdFeat;
272
244
        CPLString osFType;
273
244
        OGRLineString oOGRLine;
274
275
7.37k
        while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
276
7.13k
        {
277
            // read values
278
7.13k
            const GUIntBig id = sqlite3_column_int64(hStmt, 0);
279
7.13k
            const GUIntBig ipcb = sqlite3_column_int64(hStmt, 1);
280
7.13k
            const char *pszFType =
281
7.13k
                reinterpret_cast<const char *>(sqlite3_column_text(hStmt, 2));
282
7.13k
            int rowId = sqlite3_column_int(hStmt, 3);
283
284
7.13k
            if (ipcb == 1)
285
3.72k
            {
286
3.72k
                VFKFeatureSQLite *poFeature =
287
3.72k
                    cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iIdx));
288
3.72k
                if (poFeature == nullptr)
289
10
                {
290
10
                    CPLError(CE_Failure, CPLE_AppDefined,
291
10
                             "Cannot retrieve feature %d", iIdx);
292
10
                    sqlite3_finalize(hStmt);
293
10
                    break;
294
10
                }
295
3.71k
                poFeature->SetRowId(rowId);
296
297
                /* set geometry & reset */
298
3.71k
                if (poLine && !SetGeometryLineString(poLine, &oOGRLine, bValid,
299
3.66k
                                                     osFType.c_str(), rowIdFeat,
300
3.66k
                                                     nGeometries))
301
3.60k
                {
302
3.60k
                    nInvalid++;
303
3.60k
                }
304
305
3.71k
                bValid = true;
306
3.71k
                poLine = poFeature;
307
3.71k
                osFType = pszFType ? pszFType : "";
308
3.71k
                iIdx++;
309
3.71k
            }
310
311
7.12k
            VFKFeatureSQLite *poPoint = cpl::down_cast<VFKFeatureSQLite *>(
312
7.12k
                poDataBlockPoints->GetFeature("ID", id));
313
7.12k
            if (poPoint)
314
3.29k
            {
315
3.29k
                const OGRGeometry *pt = poPoint->GetGeometry();
316
3.29k
                if (pt)
317
3.10k
                {
318
3.10k
                    oOGRLine.addPoint(pt->toPoint());
319
3.10k
                }
320
191
                else
321
191
                {
322
191
                    CPLDebug("OGR-VFK",
323
191
                             "Geometry (point ID = " CPL_FRMT_GUIB
324
191
                             ") not valid",
325
191
                             id);
326
191
                    bValid = false;
327
191
                }
328
3.29k
            }
329
3.83k
            else
330
3.83k
            {
331
3.83k
                CPLDebug("OGR-VFK",
332
3.83k
                         "Point ID = " CPL_FRMT_GUIB " not found (rowid = %d)",
333
3.83k
                         id, rowId);
334
3.83k
                bValid = false;
335
3.83k
            }
336
337
            /* add vertex to the linestring */
338
7.12k
            rowIdFeat.push_back(rowId);
339
7.12k
        }
340
341
        /* add last line */
342
244
        if (poLine &&
343
53
            !SetGeometryLineString(poLine, &oOGRLine, bValid, osFType.c_str(),
344
53
                                   rowIdFeat, nGeometries))
345
44
        {
346
44
            nInvalid++;
347
44
        }
348
244
        poLine = nullptr;
349
350
244
        if (poReader->IsSpatial())
351
244
            poReader->ExecuteSQL("COMMIT");
352
244
    }
353
354
    /* update number of geometries in VFK_DB_TABLE table */
355
122
    UpdateVfkBlocks(nGeometries);
356
357
122
    return nInvalid;
358
130
}
359
360
/*!
361
  \brief Load geometry (linestring HP/DPM/ZVB layer)
362
363
  \return number of invalid features
364
*/
365
int VFKDataBlockSQLite::LoadGeometryLineStringHP()
366
388
{
367
388
    int nInvalid = 0;
368
388
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
369
370
388
    VFKDataBlockSQLite *poDataBlockLines =
371
388
        cpl::down_cast<VFKDataBlockSQLite *>(m_poReader->GetDataBlock("SBP"));
372
388
    if (nullptr == poDataBlockLines)
373
254
    {
374
254
        CPLError(CE_Failure, CPLE_FileIO, "Data block %s not found.",
375
254
                 m_pszName);
376
254
        return nInvalid;
377
254
    }
378
379
134
    poDataBlockLines->LoadGeometry();
380
381
134
    if (LoadGeometryFromDB()) /* try to load geometry from DB */
382
0
        return 0;
383
384
134
    CPLString osColumn;
385
134
    osColumn.Printf("%s_ID", m_pszName);
386
134
    const char *vrColumn[2] = {osColumn.c_str(), "PORADOVE_CISLO_BODU"};
387
388
134
    GUIntBig vrValue[2] = {0, 1};  // Reduce to first segment.
389
390
134
    CPLString osSQL;
391
134
    osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
392
    /* TODO: handle points in DPM */
393
134
    if (EQUAL(m_pszName, "DPM"))
394
33
        osSQL += " WHERE SOURADNICE_X IS NULL";
395
134
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
396
397
134
    if (poReader->IsSpatial())
398
134
        poReader->ExecuteSQL("BEGIN");
399
400
134
    int nGeometries = 0;
401
402
3.92k
    while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
403
3.78k
    {
404
        /* read values */
405
3.78k
        vrValue[0] = sqlite3_column_int64(hStmt, 0);
406
3.78k
        const GIntBig iFID = sqlite3_column_int64(hStmt, 1);
407
3.78k
        const int rowId = sqlite3_column_int(hStmt, 2);
408
409
3.78k
        VFKFeatureSQLite *poFeature =
410
3.78k
            cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
411
3.78k
        if (poFeature == nullptr || poFeature->GetFID() != iFID)
412
5
        {
413
5
            continue;
414
5
        }
415
416
3.78k
        VFKFeatureSQLite *poLine =
417
3.78k
            poDataBlockLines->GetFeature(vrColumn, vrValue, 2, TRUE);
418
419
3.78k
        const OGRGeometry *poOgrGeometry =
420
3.78k
            poLine ? poLine->GetGeometry() : nullptr;
421
3.78k
        if (!poOgrGeometry || !poFeature->SetGeometry(poOgrGeometry))
422
2.26k
        {
423
2.26k
            CPLDebug("OGR-VFK",
424
2.26k
                     "VFKDataBlockSQLite::LoadGeometryLineStringHP(): name=%s "
425
2.26k
                     "fid=" CPL_FRMT_GIB " "
426
2.26k
                     "id=" CPL_FRMT_GUIB " -> %s geometry",
427
2.26k
                     m_pszName, iFID, vrValue[0],
428
2.26k
                     poOgrGeometry ? "invalid" : "empty");
429
2.26k
            nInvalid++;
430
2.26k
            continue;
431
2.26k
        }
432
433
        /* store also geometry in DB */
434
1.51k
        if (poReader->IsSpatial() &&
435
1.51k
            SaveGeometryToDB(poOgrGeometry, rowId) != OGRERR_FAILURE)
436
1.51k
            nGeometries++;
437
1.51k
    }
438
439
    /* update number of geometries in VFK_DB_TABLE table */
440
134
    UpdateVfkBlocks(nGeometries);
441
442
134
    if (poReader->IsSpatial())
443
134
        poReader->ExecuteSQL("COMMIT");
444
445
134
    return nInvalid;
446
134
}
447
448
/*!
449
  \brief Load geometry (polygon BUD/PAR layers)
450
451
  \return number of invalid features
452
*/
453
int VFKDataBlockSQLite::LoadGeometryPolygon()
454
100
{
455
100
#ifndef HAVE_GEOS
456
457
100
    CPLError(CE_Warning, CPLE_NotSupported,
458
100
             "GEOS support not enabled. Unable to build geometry for %s.",
459
100
             m_pszName);
460
100
    return -1;
461
462
#else
463
464
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
465
466
    VFKDataBlockSQLite *poDataBlockLines1 = nullptr;
467
    VFKDataBlockSQLite *poDataBlockLines2 = nullptr;
468
    bool bIsPar = false;
469
    if (EQUAL(m_pszName, "PAR"))
470
    {
471
        poDataBlockLines1 = cpl::down_cast<VFKDataBlockSQLite *>(
472
            m_poReader->GetDataBlock("HP"));
473
        poDataBlockLines2 = poDataBlockLines1;
474
        bIsPar = true;
475
    }
476
    else
477
    {
478
        poDataBlockLines1 = cpl::down_cast<VFKDataBlockSQLite *>(
479
            m_poReader->GetDataBlock("OB"));
480
        poDataBlockLines2 = cpl::down_cast<VFKDataBlockSQLite *>(
481
            m_poReader->GetDataBlock("SBP"));
482
        bIsPar = false;
483
    }
484
    if (nullptr == poDataBlockLines1)
485
    {
486
        CPLError(CE_Warning, CPLE_FileIO,
487
                 "Data block %s not found. Unable to build geometry for %s.",
488
                 bIsPar ? "HP" : "OB", m_pszName);
489
        return -1;
490
    }
491
    if (nullptr == poDataBlockLines2)
492
    {
493
        CPLError(CE_Warning, CPLE_FileIO,
494
                 "Data block %s not found. Unable to build geometry for %s.",
495
                 "SBP", m_pszName);
496
        return -1;
497
    }
498
499
    poDataBlockLines1->LoadGeometry();
500
    poDataBlockLines2->LoadGeometry();
501
502
    if (LoadGeometryFromDB())  // Try to load geometry from DB.
503
        return 0;
504
505
    const char *vrColumn[2] = {nullptr, nullptr};
506
    GUIntBig vrValue[2] = {0, 0};
507
    if (bIsPar)
508
    {
509
        vrColumn[0] = "PAR_ID_1";
510
        vrColumn[1] = "PAR_ID_2";
511
    }
512
    else
513
    {
514
        vrColumn[0] = "OB_ID";
515
        vrColumn[1] = "PORADOVE_CISLO_BODU";
516
        vrValue[1] = 1;
517
    }
518
519
    CPLString osSQL;
520
    osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
521
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
522
523
    if (poReader->IsSpatial())
524
        poReader->ExecuteSQL("BEGIN");
525
526
    int nInvalidNoLines = 0;
527
    int nInvalidNoRings = 0;
528
    int nGeometries = 0;
529
530
    while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
531
    {
532
        /* read values */
533
        const GUIntBig id = sqlite3_column_int64(hStmt, 0);
534
        const long iFID = static_cast<long>(sqlite3_column_int64(hStmt, 1));
535
        const int rowId = sqlite3_column_int(hStmt, 2);
536
537
        VFKFeatureSQLite *poFeature =
538
            cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
539
        if (poFeature == nullptr || poFeature->GetFID() != iFID)
540
        {
541
            continue;
542
        }
543
544
        /* collect boundary lines */
545
        VFKFeatureSQLiteList poLineList;
546
        if (bIsPar)
547
        {
548
            vrValue[0] = vrValue[1] = id;
549
            poLineList = poDataBlockLines1->GetFeatures(vrColumn, vrValue, 2);
550
        }
551
        else
552
        {
553
            osSQL.Printf("SELECT ID FROM %s WHERE BUD_ID = " CPL_FRMT_GUIB,
554
                         poDataBlockLines1->GetName(), id);
555
            if (poReader->IsSpatial())
556
            {
557
                CPLString osColumn;
558
559
                osColumn.Printf(" AND %s IS NULL", GEOM_COLUMN);
560
                osSQL += osColumn;
561
            }
562
            sqlite3_stmt *hStmtOb = poReader->PrepareStatement(osSQL.c_str());
563
564
            while (poReader->ExecuteSQL(hStmtOb) == OGRERR_NONE)
565
            {
566
                const GUIntBig idOb = sqlite3_column_int64(hStmtOb, 0);
567
                vrValue[0] = idOb;
568
                VFKFeatureSQLite *poLineSbp =
569
                    poDataBlockLines2->GetFeature(vrColumn, vrValue, 2);
570
                if (poLineSbp)
571
                    poLineList.push_back(poLineSbp);
572
            }
573
        }
574
        if (poLineList.empty())
575
        {
576
            CPLDebug("OGR-VFK", "%s: no lines to polygonize (fid = %ld)",
577
                     m_pszName, iFID);
578
            nInvalidNoLines++;
579
            continue;
580
        }
581
582
        OGRMultiLineString oMultiLine;
583
        for (VFKFeatureSQLite *poLineFeature : poLineList)
584
        {
585
            const OGRGeometry *poLineGeom = poLineFeature->GetGeometry();
586
            if (poLineGeom)
587
            {
588
                oMultiLine.addGeometry(poLineGeom);
589
            }
590
        }
591
592
        /* polygonize using GEOSBuildArea() */
593
        auto poPolygonGeom =
594
            std::unique_ptr<OGRGeometry>(oMultiLine.BuildArea());
595
        if (!poPolygonGeom || poPolygonGeom->IsEmpty())
596
        {
597
            CPLDebug("OGR-VFK", "%s: unable to polygonize (fid = %ld)",
598
                     m_pszName, iFID);
599
            nInvalidNoRings++;
600
            continue;
601
        }
602
603
        /* coerce to MultiPolygon if needed and check the geometry type */
604
        const auto eGeomType = wkbFlatten(poPolygonGeom->getGeometryType());
605
        if ((eGeomType == wkbPolygon) && (m_nGeometryType == wkbMultiPolygon))
606
        {
607
            auto poMP = std::make_unique<OGRMultiPolygon>();
608
            poMP->addGeometryDirectly(poPolygonGeom.release());
609
            poPolygonGeom = std::move(poMP);
610
        }
611
        else if (eGeomType != m_nGeometryType)
612
        {
613
            CPLDebug("OGR-VFK", "%s: invalid geometry type %d (fid = %ld)",
614
                     m_pszName, (int)eGeomType, iFID);
615
            nInvalidNoRings++;
616
            continue;
617
        }
618
619
        /* set geometry */
620
        poPolygonGeom->setCoordinateDimension(2); /* force 2D */
621
        if (!poFeature->SetGeometry(poPolygonGeom.get()))
622
        {
623
            nInvalidNoRings++;
624
            continue;
625
        }
626
627
        /* store also geometry in DB */
628
        if (poReader->IsSpatial() &&
629
            SaveGeometryToDB(poPolygonGeom.get(), rowId) != OGRERR_FAILURE)
630
            nGeometries++;
631
    }
632
633
    CPLDebug("OGR-VFK", "%s: nolines = %d norings = %d", m_pszName,
634
             nInvalidNoLines, nInvalidNoRings);
635
636
    /* update number of geometries in VFK_DB_TABLE table */
637
    UpdateVfkBlocks(nGeometries);
638
639
    if (poReader->IsSpatial())
640
        poReader->ExecuteSQL("COMMIT");
641
642
    return nInvalidNoLines + nInvalidNoRings;
643
#endif  // HAVE_GEOS
644
100
}
645
646
/*!
647
  \brief Get feature by FID
648
649
  Modifies next feature id.
650
651
  \param nFID feature id
652
653
  \return pointer to feature definition or NULL on failure (not found)
654
*/
655
IVFKFeature *VFKDataBlockSQLite::GetFeature(GIntBig nFID)
656
0
{
657
0
    if (m_nFeatureCount < 0)
658
0
    {
659
0
        m_poReader->ReadDataRecords(this);
660
0
    }
661
662
0
    if (nFID < 1 || nFID > m_nFeatureCount)
663
0
        return nullptr;
664
665
0
    if (m_bGeometryPerBlock && !m_bGeometry)
666
0
    {
667
0
        LoadGeometry();
668
0
    }
669
670
0
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
671
672
0
    CPLString osSQL;
673
0
    osSQL.Printf("SELECT rowid FROM %s WHERE %s = " CPL_FRMT_GIB, m_pszName,
674
0
                 FID_COLUMN, nFID);
675
0
    if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
676
0
    {
677
0
        osSQL += " AND PORADOVE_CISLO_BODU = 1";
678
0
    }
679
0
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
680
681
0
    int rowId = -1;
682
0
    if (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
683
0
    {
684
0
        rowId = sqlite3_column_int(hStmt, 0);
685
0
    }
686
0
    sqlite3_finalize(hStmt);
687
688
0
    return GetFeatureByIndex(rowId - 1);
689
0
}
690
691
/*!
692
  \brief Get first found feature based on its property
693
694
  \param column property name
695
  \param value property value
696
  \param bGeom True to check also geometry != NULL
697
698
  \return pointer to feature definition or NULL on failure (not found)
699
*/
700
VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char *column,
701
                                                 GUIntBig value, bool bGeom)
702
7.12k
{
703
7.12k
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
704
705
7.12k
    CPLString osSQL;
706
7.12k
    osSQL.Printf("SELECT %s from %s WHERE %s = " CPL_FRMT_GUIB, FID_COLUMN,
707
7.12k
                 m_pszName, column, value);
708
7.12k
    if (bGeom)
709
0
    {
710
0
        CPLString osColumn;
711
712
0
        osColumn.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
713
0
        osSQL += osColumn;
714
0
    }
715
716
7.12k
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
717
7.12k
    if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
718
3.83k
        return nullptr;
719
720
3.29k
    const int idx = sqlite3_column_int(hStmt, 0) - 1;
721
3.29k
    sqlite3_finalize(hStmt);
722
723
3.29k
    if (idx < 0 || idx >= m_nFeatureCount)  // ? assert
724
3
        return nullptr;
725
726
3.29k
    return cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(idx));
727
3.29k
}
728
729
/*!
730
  \brief Get first found feature based on its properties (AND)
731
732
  \param column array of property names
733
  \param value array of property values
734
  \param num number of array items
735
  \param bGeom True to check also geometry != NULL
736
737
  \return pointer to feature definition or NULL on failure (not found)
738
*/
739
VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char **column,
740
                                                 GUIntBig *value, int num,
741
                                                 bool bGeom)
742
3.78k
{
743
3.78k
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
744
745
3.78k
    CPLString osSQL;
746
3.78k
    osSQL.Printf("SELECT %s FROM %s WHERE ", FID_COLUMN, m_pszName);
747
748
3.78k
    CPLString osItem;
749
11.3k
    for (int i = 0; i < num; i++)
750
7.56k
    {
751
7.56k
        if (i > 0)
752
3.78k
            osItem.Printf(" AND %s = " CPL_FRMT_GUIB, column[i], value[i]);
753
3.78k
        else
754
3.78k
            osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
755
7.56k
        osSQL += osItem;
756
7.56k
    }
757
3.78k
    if (bGeom)
758
3.78k
    {
759
3.78k
        osItem.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
760
3.78k
        osSQL += osItem;
761
3.78k
    }
762
763
3.78k
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
764
3.78k
    if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
765
2.26k
        return nullptr;
766
767
1.51k
    int idx = sqlite3_column_int(hStmt, 0) - 1; /* rowid starts at 1 */
768
1.51k
    sqlite3_finalize(hStmt);
769
770
1.51k
    if (idx < 0 || idx >= m_nFeatureCount)  // ? assert
771
0
        return nullptr;
772
773
1.51k
    return cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(idx));
774
1.51k
}
775
776
/*!
777
  \brief Get features based on properties
778
779
  \param column array of property names
780
  \param value array of property values
781
  \param num number of array items
782
783
  \return list of features
784
*/
785
VFKFeatureSQLiteList VFKDataBlockSQLite::GetFeatures(const char **column,
786
                                                     GUIntBig *value, int num)
787
0
{
788
0
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
789
790
0
    CPLString osItem;
791
0
    CPLString osSQL;
792
0
    osSQL.Printf("SELECT rowid from %s WHERE ", m_pszName);
793
0
    for (int i = 0; i < num; i++)
794
0
    {
795
0
        if (i > 0)
796
0
            osItem.Printf(" OR %s = " CPL_FRMT_GUIB, column[i], value[i]);
797
0
        else
798
0
            osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
799
0
        osSQL += osItem;
800
0
    }
801
0
    osSQL += " ORDER BY ";
802
0
    osSQL += FID_COLUMN;
803
804
0
    VFKFeatureSQLiteList fList;
805
806
0
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
807
0
    while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
808
0
    {
809
0
        const int iRowId = sqlite3_column_int(hStmt, 0);
810
0
        VFKFeatureSQLite *poFeature =
811
0
            dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iRowId - 1));
812
0
        if (poFeature == nullptr)
813
0
        {
814
0
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot retrieve feature %d",
815
0
                     iRowId);
816
0
            sqlite3_finalize(hStmt);
817
0
            return VFKFeatureSQLiteList();
818
0
        }
819
0
        fList.push_back(poFeature);
820
0
    }
821
822
0
    return fList;
823
0
}
824
825
/*!
826
  \brief Save geometry to DB (as WKB)
827
828
  \param poGeom pointer to OGRGeometry to be saved
829
  \param iRowId row id to update
830
831
  \return OGRERR_NONE on success otherwise OGRERR_FAILURE
832
*/
833
OGRErr VFKDataBlockSQLite::SaveGeometryToDB(const OGRGeometry *poGeom,
834
                                            int iRowId)
835
4.03k
{
836
4.03k
    int rc;
837
4.03k
    CPLString osSQL;
838
839
4.03k
    sqlite3_stmt *hStmt = nullptr;
840
841
4.03k
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
842
843
    /* check if geometry column exists (see SUPPRESS_GEOMETRY open
844
       option) */
845
4.03k
    if (AddGeometryColumn() != OGRERR_NONE)
846
0
        return OGRERR_FAILURE;
847
848
4.03k
    if (poGeom)
849
4.03k
    {
850
4.03k
        const size_t nWKBLen = poGeom->WkbSize();
851
4.03k
        if (nWKBLen > static_cast<size_t>(std::numeric_limits<int>::max()))
852
0
        {
853
0
            CPLError(CE_Failure, CPLE_AppDefined, "Too large geometry");
854
0
            return OGRERR_FAILURE;
855
0
        }
856
4.03k
        GByte *pabyWKB = (GByte *)VSI_MALLOC_VERBOSE(nWKBLen);
857
4.03k
        if (pabyWKB)
858
4.03k
        {
859
4.03k
            poGeom->exportToWkb(wkbNDR, pabyWKB);
860
861
4.03k
            osSQL.Printf("UPDATE %s SET %s = ? WHERE rowid = %d", m_pszName,
862
4.03k
                         GEOM_COLUMN, iRowId);
863
4.03k
            hStmt = poReader->PrepareStatement(osSQL.c_str());
864
865
4.03k
            rc = sqlite3_bind_blob(hStmt, 1, pabyWKB, static_cast<int>(nWKBLen),
866
4.03k
                                   CPLFree);
867
4.03k
            if (rc != SQLITE_OK)
868
0
            {
869
0
                sqlite3_finalize(hStmt);
870
0
                CPLError(CE_Failure, CPLE_AppDefined,
871
0
                         "Storing geometry in DB failed");
872
0
                return OGRERR_FAILURE;
873
0
            }
874
4.03k
        }
875
4.03k
    }
876
0
    else
877
0
    { /* invalid */
878
0
        osSQL.Printf("UPDATE %s SET %s = NULL WHERE rowid = %d", m_pszName,
879
0
                     GEOM_COLUMN, iRowId);
880
0
        hStmt = poReader->PrepareStatement(osSQL.c_str());
881
0
    }
882
883
4.03k
    return poReader->ExecuteSQL(hStmt); /* calls sqlite3_finalize() */
884
4.03k
}
885
886
/*!
887
  \brief Load geometry from DB
888
889
  \return true if geometry successfully loaded otherwise false
890
*/
891
bool VFKDataBlockSQLite::LoadGeometryFromDB()
892
577
{
893
577
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
894
895
577
    if (!poReader->IsSpatial()) /* check if DB is spatial */
896
0
        return false;
897
898
577
    CPLString osSQL;
899
577
    osSQL.Printf("SELECT num_geometries FROM %s WHERE table_name = '%s'",
900
577
                 VFK_DB_TABLE, m_pszName);
901
577
    sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
902
577
    if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
903
165
        return false;
904
412
    const int nGeometries = sqlite3_column_int(hStmt, 0);
905
412
    sqlite3_finalize(hStmt);
906
907
412
    if (nGeometries < 1)
908
358
        return false;
909
910
54
    const bool bSkipInvalid = EQUAL(m_pszName, "OB") ||
911
54
                              EQUAL(m_pszName, "OP") ||
912
54
                              EQUAL(m_pszName, "OBBP");
913
914
    /* load geometry from DB */
915
54
    osSQL.Printf("SELECT %s,rowid,%s FROM %s ", GEOM_COLUMN, FID_COLUMN,
916
54
                 m_pszName);
917
54
    if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
918
8
        osSQL += "WHERE PORADOVE_CISLO_BODU = 1 ";
919
54
    osSQL += "ORDER BY ";
920
54
    osSQL += FID_COLUMN;
921
54
    hStmt = poReader->PrepareStatement(osSQL.c_str());
922
923
54
    int rowId = 0;
924
54
    int nInvalid = 0;
925
54
    int nGeometriesCount = 0;
926
927
2.41k
    while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
928
2.35k
    {
929
2.35k
        rowId++;  // =sqlite3_column_int(hStmt, 1);
930
2.35k
        const GIntBig iFID = sqlite3_column_int64(hStmt, 2);
931
2.35k
        VFKFeatureSQLite *poFeature =
932
2.35k
            dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
933
2.35k
        if (poFeature == nullptr || poFeature->GetFID() != iFID)
934
158
        {
935
158
            continue;
936
158
        }
937
938
        // read geometry from DB
939
2.20k
        const int nBytes = sqlite3_column_bytes(hStmt, 0);
940
2.20k
        OGRGeometry *poGeometry = nullptr;
941
2.20k
        if (nBytes > 0 && OGRGeometryFactory::createFromWkb(
942
405
                              sqlite3_column_blob(hStmt, 0), nullptr,
943
405
                              &poGeometry, nBytes) == OGRERR_NONE)
944
405
        {
945
405
            nGeometriesCount++;
946
405
            if (!poFeature->SetGeometry(poGeometry))
947
0
            {
948
0
                nInvalid++;
949
0
            }
950
405
            delete poGeometry;
951
405
        }
952
1.79k
        else
953
1.79k
        {
954
1.79k
            nInvalid++;
955
1.79k
        }
956
2.20k
    }
957
958
54
    CPLDebug("OGR-VFK", "%s: %d geometries loaded from DB", m_pszName,
959
54
             nGeometriesCount);
960
961
54
    if (nGeometriesCount != nGeometries)
962
19
    {
963
19
        CPLError(CE_Warning, CPLE_AppDefined,
964
19
                 "%s: %d geometries loaded (should be %d)", m_pszName,
965
19
                 nGeometriesCount, nGeometries);
966
19
    }
967
968
54
    if (nInvalid > 0 && !bSkipInvalid)
969
33
    {
970
33
        CPLError(CE_Warning, CPLE_AppDefined,
971
33
                 "%s: %d features with invalid or empty geometry", m_pszName,
972
33
                 nInvalid);
973
33
    }
974
975
54
    return true;
976
412
}
977
978
/*!
979
  \brief Update VFK_DB_TABLE table
980
981
  \param nGeometries number of geometries to update
982
*/
983
void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries)
984
523
{
985
523
    CPLString osSQL;
986
987
523
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
988
989
    /* update number of features in VFK_DB_TABLE table */
990
523
    const int nFeatCount = (int)GetFeatureCount();
991
523
    if (nFeatCount > 0)
992
153
    {
993
153
        osSQL.Printf("UPDATE %s SET num_features = %d WHERE table_name = '%s'",
994
153
                     VFK_DB_TABLE, nFeatCount, m_pszName);
995
153
        poReader->ExecuteSQL(osSQL.c_str());
996
153
    }
997
998
    /* update number of geometries in VFK_DB_TABLE table */
999
523
    if (nGeometries > 0)
1000
91
    {
1001
91
        CPLDebug("OGR-VFK",
1002
91
                 "VFKDataBlockSQLite::UpdateVfkBlocks(): name=%s -> "
1003
91
                 "%d geometries saved to internal DB",
1004
91
                 m_pszName, nGeometries);
1005
1006
91
        osSQL.Printf(
1007
91
            "UPDATE %s SET num_geometries = %d WHERE table_name = '%s'",
1008
91
            VFK_DB_TABLE, nGeometries, m_pszName);
1009
91
        poReader->ExecuteSQL(osSQL.c_str());
1010
91
    }
1011
523
}
1012
1013
/*!
1014
  \brief Update feature id (see SBP)
1015
1016
  \param iFID feature id to set up
1017
  \param rowId list of rows to update
1018
*/
1019
void VFKDataBlockSQLite::UpdateFID(GIntBig iFID, const std::vector<int> &rowId)
1020
3.71k
{
1021
3.71k
    CPLString osSQL, osValue;
1022
3.71k
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
1023
1024
    /* update number of geometries in VFK_DB_TABLE table */
1025
3.71k
    osSQL.Printf("UPDATE %s SET %s = " CPL_FRMT_GIB " WHERE rowid IN (",
1026
3.71k
                 m_pszName, FID_COLUMN, iFID);
1027
10.8k
    for (size_t i = 0; i < rowId.size(); i++)
1028
7.12k
    {
1029
7.12k
        if (i > 0)
1030
3.40k
            osValue.Printf(",%d", rowId[i]);
1031
3.71k
        else
1032
3.71k
            osValue.Printf("%d", rowId[i]);
1033
7.12k
        osSQL += osValue;
1034
7.12k
    }
1035
3.71k
    osSQL += ")";
1036
1037
3.71k
    poReader->ExecuteSQL(osSQL.c_str());
1038
3.71k
}
1039
1040
/*!
1041
  \brief Check is ring is closed
1042
1043
  \param poRing pointer to OGRLinearRing to check
1044
1045
  \return true if closed otherwise false
1046
*/
1047
bool VFKDataBlockSQLite::IsRingClosed(const OGRLinearRing *poRing)
1048
0
{
1049
0
    const int nPoints = poRing->getNumPoints();
1050
0
    if (nPoints < 3)
1051
0
        return false;
1052
1053
0
    if (poRing->getX(0) == poRing->getX(nPoints - 1) &&
1054
0
        poRing->getY(0) == poRing->getY(nPoints - 1))
1055
0
        return true;
1056
1057
0
    return false;
1058
0
}
1059
1060
/*!
1061
  \brief Get primary key
1062
1063
  \return property name or NULL
1064
*/
1065
const char *VFKDataBlockSQLite::GetKey() const
1066
865
{
1067
865
    if (GetPropertyCount() > 1)
1068
657
    {
1069
657
        const VFKPropertyDefn *poPropDefn = GetProperty(0);
1070
657
        const char *pszKey = poPropDefn->GetName();
1071
657
        if (EQUAL(pszKey, "ID"))
1072
577
            return pszKey;
1073
657
    }
1074
1075
288
    return nullptr;
1076
865
}
1077
1078
/*!
1079
  \brief Get geometry SQL type (for geometry_columns table)
1080
1081
  \return geometry_type as integer
1082
*/
1083
int VFKDataBlockSQLite::GetGeometrySQLType() const
1084
1.28k
{
1085
1.28k
    if (m_nGeometryType == wkbMultiPolygon)
1086
15
        return 6;
1087
1.27k
    else if (m_nGeometryType == wkbPolygon)
1088
10
        return 3;
1089
1.26k
    else if (m_nGeometryType == wkbLineString)
1090
134
        return 2;
1091
1.12k
    else if (m_nGeometryType == wkbPoint)
1092
132
        return 1;
1093
1094
995
    return 0; /* unknown geometry type */
1095
1.28k
}
1096
1097
/*!
1098
  \brief Add geometry column into table if not exists
1099
1100
  \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1101
 */
1102
OGRErr VFKDataBlockSQLite::AddGeometryColumn() const
1103
4.25k
{
1104
4.25k
    CPLString osSQL;
1105
1106
4.25k
    VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
1107
1108
4.25k
    osSQL.Printf("SELECT %s FROM %s LIMIT 0", GEOM_COLUMN, m_pszName);
1109
4.25k
    if (poReader->ExecuteSQL(osSQL.c_str(), CE_None) == OGRERR_FAILURE)
1110
57
    {
1111
        /* query failed, we assume that geometry column not exists */
1112
57
        osSQL.Printf("ALTER TABLE %s ADD COLUMN %s blob", m_pszName,
1113
57
                     GEOM_COLUMN);
1114
57
        return poReader->ExecuteSQL(osSQL.c_str());
1115
57
    }
1116
1117
4.19k
    return OGRERR_NONE;
1118
4.25k
}
1119
1120
/*!
1121
  \brief Load feature properties
1122
1123
  Used for sequential access, see OGRVFKLayer:GetNextFeature().
1124
1125
  \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1126
*/
1127
OGRErr VFKDataBlockSQLite::LoadProperties()
1128
4.90k
{
1129
4.90k
    CPLString osSQL;
1130
1131
4.90k
    if (m_hStmt)
1132
0
        sqlite3_finalize(m_hStmt);
1133
1134
4.90k
    osSQL.Printf("SELECT * FROM %s",  // TODO: where
1135
4.90k
                 m_pszName);
1136
4.90k
    if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
1137
154
        osSQL += " WHERE PORADOVE_CISLO_BODU = 1";
1138
1139
4.90k
    m_hStmt = cpl::down_cast<VFKReaderSQLite *>(m_poReader)
1140
4.90k
                  ->PrepareStatement(osSQL.c_str());
1141
1142
4.90k
    if (m_hStmt == nullptr)
1143
4.23k
        return OGRERR_FAILURE;
1144
1145
667
    return OGRERR_NONE;
1146
4.90k
}
1147
1148
/*
1149
  \brief Clean feature properties for a next run
1150
1151
  \return OGRERR_NONE on success otherwise OGRERR_FAILURE
1152
*/
1153
OGRErr VFKDataBlockSQLite::CleanProperties()
1154
14.5k
{
1155
14.5k
    if (m_hStmt)
1156
667
    {
1157
667
        if (sqlite3_finalize(m_hStmt) != SQLITE_OK)
1158
0
        {
1159
0
            m_hStmt = nullptr;
1160
0
            return OGRERR_FAILURE;
1161
0
        }
1162
667
        m_hStmt = nullptr;
1163
667
    }
1164
1165
14.5k
    return OGRERR_NONE;
1166
14.5k
}