LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkdatablocksqlite.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 367 486 75.5 %
Date: 2025-03-28 11:40:40 Functions: 18 20 90.0 %

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

Generated by: LCOV version 1.14