LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vfk - vfkdatablocksqlite.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 393 500 78.6 %
Date: 2026-02-10 10:01:39 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        1037 : VFKDataBlockSQLite::VFKDataBlockSQLite(const char *pszName,
      29        1037 :                                        const IVFKReader *poReader)
      30        1037 :     : IVFKDataBlock(pszName, poReader), m_hStmt(nullptr)
      31             : {
      32        1037 : }
      33             : 
      34             : /*!
      35             :   \brief Load geometry (point layers)
      36             : 
      37             :   \return number of invalid features
      38             : */
      39          96 : int VFKDataBlockSQLite::LoadGeometryPoint()
      40             : {
      41          96 :     if (LoadGeometryFromDB()) /* try to load geometry from DB */
      42           1 :         return 0;
      43             : 
      44         269 :     const bool bSkipInvalid = EQUAL(m_pszName, "OB") ||
      45         158 :                               EQUAL(m_pszName, "OP") ||
      46          63 :                               EQUAL(m_pszName, "OBBP");
      47             : 
      48          95 :     CPLString osSQL;
      49             :     osSQL.Printf("SELECT SOURADNICE_Y,SOURADNICE_X,%s,rowid FROM %s",
      50          95 :                  FID_COLUMN, m_pszName);
      51             : 
      52          95 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
      53          95 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
      54             : 
      55          95 :     if (poReader->IsSpatial())
      56          95 :         poReader->ExecuteSQL("BEGIN");
      57             : 
      58          95 :     int nGeometries = 0;
      59          95 :     int nInvalid = 0;
      60         498 :     while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
      61             :     {
      62             :         /* read values */
      63             :         const double x =
      64         403 :             -1.0 * sqlite3_column_double(
      65         403 :                        hStmt, 0); /* S-JTSK coordinate system expected */
      66         403 :         const double y = -1.0 * sqlite3_column_double(hStmt, 1);
      67         403 :         const GIntBig iFID = sqlite3_column_int64(hStmt, 2);
      68         403 :         const int rowId = sqlite3_column_int(hStmt, 3);
      69             : 
      70             :         VFKFeatureSQLite *poFeature =
      71         403 :             dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
      72         403 :         if (poFeature == nullptr || poFeature->GetFID() != iFID)
      73             :         {
      74         208 :             continue;
      75             :         }
      76             : 
      77             :         /* create geometry */
      78         403 :         OGRPoint pt(x, y);
      79         403 :         if (!poFeature->SetGeometry(&pt))
      80             :         {
      81         208 :             nInvalid++;
      82         208 :             continue;
      83             :         }
      84             : 
      85             :         /* store also geometry in DB */
      86         390 :         if (poReader->IsSpatial() &&
      87         195 :             SaveGeometryToDB(&pt, rowId) != OGRERR_FAILURE)
      88         195 :             nGeometries++;
      89             :     }
      90             : 
      91             :     /* update number of geometries in VFK_DB_TABLE table */
      92          95 :     UpdateVfkBlocks(nGeometries);
      93             : 
      94          95 :     if (poReader->IsSpatial())
      95          95 :         poReader->ExecuteSQL("COMMIT");
      96             : 
      97          95 :     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         210 : bool VFKDataBlockSQLite::SetGeometryLineString(VFKFeatureSQLite *poLine,
     111             :                                                OGRLineString *oOGRLine,
     112             :                                                bool &bValid, const char *ftype,
     113             :                                                std::vector<int> &rowIdFeat,
     114             :                                                int &nGeometries)
     115             : {
     116         210 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     117             : 
     118         210 :     oOGRLine->setCoordinateDimension(2); /* force 2D */
     119             : 
     120             :     /* check also VFK validity */
     121         210 :     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         210 :         const int npoints = oOGRLine->getNumPoints();
     134         210 :         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         210 :         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         210 :         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         210 :         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         210 :         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         210 :     if (bValid)
     183             :     {
     184         210 :         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         210 :     UpdateFID(poLine->GetFID(), rowIdFeat);
     196             : 
     197             :     /* store also geometry in DB */
     198         210 :     CPLAssert(!rowIdFeat.empty());
     199         420 :     if (bValid && poReader->IsSpatial() &&
     200         210 :         SaveGeometryToDB(poLine->GetGeometry(), rowIdFeat[0]) != OGRERR_FAILURE)
     201             :     {
     202         210 :         nGeometries++;
     203             :     }
     204             : 
     205         210 :     rowIdFeat.clear();
     206         210 :     oOGRLine->empty(); /* restore line */
     207             : 
     208         210 :     return bValid;
     209             : }
     210             : 
     211             : /*!
     212             :   \brief Load geometry (linestring SBP layer)
     213             : 
     214             :   \return number of invalid features
     215             : */
     216          16 : int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
     217             : {
     218          16 :     int nInvalid = 0;
     219             : 
     220             :     VFKDataBlockSQLite *poDataBlockPoints =
     221          16 :         cpl::down_cast<VFKDataBlockSQLite *>(m_poReader->GetDataBlock("SOBR"));
     222          16 :     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          16 :     int nGeometries = 0;
     230          16 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     231             : 
     232          16 :     poDataBlockPoints->LoadGeometry();
     233             : 
     234          16 :     if (LoadGeometryFromDB()) /* try to load geometry from DB */
     235           1 :         return 0;
     236             : 
     237          15 :     CPLString osSQL;
     238          15 :     osSQL.Printf("UPDATE %s SET %s = -1", m_pszName, FID_COLUMN);
     239          15 :     poReader->ExecuteSQL(osSQL.c_str());
     240          15 :     bool bValid = true;
     241          15 :     int iIdx = 0;
     242             : 
     243          15 :     VFKFeatureSQLite *poLine = nullptr;
     244             : 
     245          45 :     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          30 :         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          15 :                 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          15 :                 m_pszName);
     265             : 
     266          30 :         sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     267             : 
     268          30 :         if (poReader->IsSpatial())
     269          30 :             poReader->ExecuteSQL("BEGIN");
     270             : 
     271          60 :         std::vector<int> rowIdFeat;
     272          60 :         CPLString osFType;
     273          60 :         OGRLineString oOGRLine;
     274             : 
     275         465 :         while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
     276             :         {
     277             :             // read values
     278         435 :             const GUIntBig id = sqlite3_column_int64(hStmt, 0);
     279         435 :             const GUIntBig ipcb = sqlite3_column_int64(hStmt, 1);
     280             :             const char *pszFType =
     281         435 :                 reinterpret_cast<const char *>(sqlite3_column_text(hStmt, 2));
     282         435 :             int rowId = sqlite3_column_int(hStmt, 3);
     283             : 
     284         435 :             if (ipcb == 1)
     285             :             {
     286             :                 VFKFeatureSQLite *poFeature =
     287         210 :                     cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iIdx));
     288         210 :                 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         210 :                 poFeature->SetRowId(rowId);
     296             : 
     297             :                 /* set geometry & reset */
     298         210 :                 if (poLine && !SetGeometryLineString(poLine, &oOGRLine, bValid,
     299             :                                                      osFType.c_str(), rowIdFeat,
     300             :                                                      nGeometries))
     301             :                 {
     302           0 :                     nInvalid++;
     303             :                 }
     304             : 
     305         210 :                 bValid = true;
     306         210 :                 poLine = poFeature;
     307         210 :                 osFType = pszFType ? pszFType : "";
     308         210 :                 iIdx++;
     309             :             }
     310             : 
     311         435 :             VFKFeatureSQLite *poPoint = cpl::down_cast<VFKFeatureSQLite *>(
     312             :                 poDataBlockPoints->GetFeature("ID", id));
     313         435 :             if (poPoint)
     314             :             {
     315         435 :                 const OGRGeometry *pt = poPoint->GetGeometry();
     316         435 :                 if (pt)
     317             :                 {
     318         435 :                     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         435 :             rowIdFeat.push_back(rowId);
     339             :         }
     340             : 
     341             :         /* add last line */
     342          45 :         if (poLine &&
     343          15 :             !SetGeometryLineString(poLine, &oOGRLine, bValid, osFType.c_str(),
     344             :                                    rowIdFeat, nGeometries))
     345             :         {
     346           0 :             nInvalid++;
     347             :         }
     348          30 :         poLine = nullptr;
     349             : 
     350          30 :         if (poReader->IsSpatial())
     351          30 :             poReader->ExecuteSQL("COMMIT");
     352             :     }
     353             : 
     354             :     /* update number of geometries in VFK_DB_TABLE table */
     355          15 :     UpdateVfkBlocks(nGeometries);
     356             : 
     357          15 :     return nInvalid;
     358             : }
     359             : 
     360             : /*!
     361             :   \brief Load geometry (linestring HP/DPM/ZVB layer)
     362             : 
     363             :   \return number of invalid features
     364             : */
     365          48 : int VFKDataBlockSQLite::LoadGeometryLineStringHP()
     366             : {
     367          48 :     int nInvalid = 0;
     368          48 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     369             : 
     370             :     VFKDataBlockSQLite *poDataBlockLines =
     371          48 :         cpl::down_cast<VFKDataBlockSQLite *>(m_poReader->GetDataBlock("SBP"));
     372          48 :     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          48 :     poDataBlockLines->LoadGeometry();
     380             : 
     381          48 :     if (LoadGeometryFromDB()) /* try to load geometry from DB */
     382           1 :         return 0;
     383             : 
     384          94 :     CPLString osColumn;
     385          47 :     osColumn.Printf("%s_ID", m_pszName);
     386          47 :     const char *vrColumn[2] = {osColumn.c_str(), "PORADOVE_CISLO_BODU"};
     387             : 
     388          47 :     GUIntBig vrValue[2] = {0, 1};  // Reduce to first segment.
     389             : 
     390          47 :     CPLString osSQL;
     391          47 :     osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
     392             :     /* TODO: handle points in DPM */
     393          47 :     if (EQUAL(m_pszName, "DPM"))
     394          16 :         osSQL += " WHERE SOURADNICE_X IS NULL";
     395          47 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     396             : 
     397          47 :     if (poReader->IsSpatial())
     398          47 :         poReader->ExecuteSQL("BEGIN");
     399             : 
     400          47 :     int nGeometries = 0;
     401             : 
     402         242 :     while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
     403             :     {
     404             :         /* read values */
     405         195 :         vrValue[0] = sqlite3_column_int64(hStmt, 0);
     406         195 :         const GIntBig iFID = sqlite3_column_int64(hStmt, 1);
     407         195 :         const int rowId = sqlite3_column_int(hStmt, 2);
     408             : 
     409             :         VFKFeatureSQLite *poFeature =
     410         195 :             cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
     411         195 :         if (poFeature == nullptr || poFeature->GetFID() != iFID)
     412             :         {
     413           0 :             continue;
     414             :         }
     415             : 
     416             :         VFKFeatureSQLite *poLine =
     417         195 :             poDataBlockLines->GetFeature(vrColumn, vrValue, 2, TRUE);
     418             : 
     419             :         const OGRGeometry *poOgrGeometry =
     420         195 :             poLine ? poLine->GetGeometry() : nullptr;
     421         195 :         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         390 :         if (poReader->IsSpatial() &&
     435         195 :             SaveGeometryToDB(poOgrGeometry, rowId) != OGRERR_FAILURE)
     436         195 :             nGeometries++;
     437             :     }
     438             : 
     439             :     /* update number of geometries in VFK_DB_TABLE table */
     440          47 :     UpdateVfkBlocks(nGeometries);
     441             : 
     442          47 :     if (poReader->IsSpatial())
     443          47 :         poReader->ExecuteSQL("COMMIT");
     444             : 
     445          47 :     return nInvalid;
     446             : }
     447             : 
     448             : /*!
     449             :   \brief Load geometry (polygon BUD/PAR layers)
     450             : 
     451             :   \return number of invalid features
     452             : */
     453          32 : 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          32 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     465             : 
     466          32 :     VFKDataBlockSQLite *poDataBlockLines1 = nullptr;
     467          32 :     VFKDataBlockSQLite *poDataBlockLines2 = nullptr;
     468          32 :     bool bIsPar = false;
     469          32 :     if (EQUAL(m_pszName, "PAR"))
     470             :     {
     471          16 :         poDataBlockLines1 = cpl::down_cast<VFKDataBlockSQLite *>(
     472          16 :             m_poReader->GetDataBlock("HP"));
     473          16 :         poDataBlockLines2 = poDataBlockLines1;
     474          16 :         bIsPar = true;
     475             :     }
     476             :     else
     477             :     {
     478          16 :         poDataBlockLines1 = cpl::down_cast<VFKDataBlockSQLite *>(
     479          16 :             m_poReader->GetDataBlock("OB"));
     480          16 :         poDataBlockLines2 = cpl::down_cast<VFKDataBlockSQLite *>(
     481          16 :             m_poReader->GetDataBlock("SBP"));
     482          16 :         bIsPar = false;
     483             :     }
     484          32 :     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          32 :     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          32 :     poDataBlockLines1->LoadGeometry();
     500          32 :     poDataBlockLines2->LoadGeometry();
     501             : 
     502          32 :     if (LoadGeometryFromDB())  // Try to load geometry from DB.
     503           2 :         return 0;
     504             : 
     505          30 :     const char *vrColumn[2] = {nullptr, nullptr};
     506          30 :     GUIntBig vrValue[2] = {0, 0};
     507          30 :     if (bIsPar)
     508             :     {
     509          15 :         vrColumn[0] = "PAR_ID_1";
     510          15 :         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          30 :     CPLString osSQL;
     520          30 :     osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
     521          30 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     522             : 
     523          30 :     if (poReader->IsSpatial())
     524          30 :         poReader->ExecuteSQL("BEGIN");
     525             : 
     526          30 :     int nInvalidNoLines = 0;
     527          30 :     int nInvalidNoRings = 0;
     528          30 :     int nGeometries = 0;
     529             : 
     530          60 :     while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
     531             :     {
     532             :         /* read values */
     533          30 :         const GUIntBig id = sqlite3_column_int64(hStmt, 0);
     534          30 :         const long iFID = static_cast<long>(sqlite3_column_int64(hStmt, 1));
     535          30 :         const int rowId = sqlite3_column_int(hStmt, 2);
     536             : 
     537             :         VFKFeatureSQLite *poFeature =
     538          30 :             cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
     539          30 :         if (poFeature == nullptr || poFeature->GetFID() != iFID)
     540             :         {
     541           0 :             continue;
     542             :         }
     543             : 
     544             :         /* collect boundary lines */
     545          30 :         VFKFeatureSQLiteList poLineList;
     546          30 :         if (bIsPar)
     547             :         {
     548          15 :             vrValue[0] = vrValue[1] = id;
     549          15 :             poLineList = poDataBlockLines1->GetFeatures(vrColumn, vrValue, 2);
     550             :         }
     551             :         else
     552             :         {
     553             :             osSQL.Printf("SELECT ID FROM %s WHERE BUD_ID = " CPL_FRMT_GUIB,
     554          15 :                          poDataBlockLines1->GetName(), id);
     555          15 :             if (poReader->IsSpatial())
     556             :             {
     557          30 :                 CPLString osColumn;
     558             : 
     559          15 :                 osColumn.Printf(" AND %s IS NULL", GEOM_COLUMN);
     560          15 :                 osSQL += osColumn;
     561             :             }
     562          15 :             sqlite3_stmt *hStmtOb = poReader->PrepareStatement(osSQL.c_str());
     563             : 
     564         210 :             while (poReader->ExecuteSQL(hStmtOb) == OGRERR_NONE)
     565             :             {
     566         195 :                 const GUIntBig idOb = sqlite3_column_int64(hStmtOb, 0);
     567         195 :                 vrValue[0] = idOb;
     568             :                 VFKFeatureSQLite *poLineSbp =
     569         195 :                     poDataBlockLines2->GetFeature(vrColumn, vrValue, 2);
     570         195 :                 if (poLineSbp)
     571         195 :                     poLineList.push_back(poLineSbp);
     572             :             }
     573             :         }
     574          30 :         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          30 :         OGRMultiLineString oMultiLine;
     583         420 :         for (VFKFeatureSQLite *poLineFeature : poLineList)
     584             :         {
     585         390 :             const OGRGeometry *poLineGeom = poLineFeature->GetGeometry();
     586         390 :             if (poLineGeom)
     587             :             {
     588         390 :                 oMultiLine.addGeometry(poLineGeom);
     589             :             }
     590             :         }
     591             : 
     592             :         /* polygonize using GEOSBuildArea() */
     593             :         auto poPolygonGeom =
     594          30 :             std::unique_ptr<OGRGeometry>(oMultiLine.BuildArea());
     595          30 :         if (!poPolygonGeom || poPolygonGeom->IsEmpty())
     596             :         {
     597           0 :             CPLDebug("OGR-VFK", "%s: unable to polygonize (fid = %ld)",
     598             :                      m_pszName, iFID);
     599           0 :             nInvalidNoRings++;
     600           0 :             continue;
     601             :         }
     602             : 
     603             :         /* coerce to MultiPolygon if needed and check the geometry type */
     604          30 :         const auto eGeomType = wkbFlatten(poPolygonGeom->getGeometryType());
     605          30 :         if ((eGeomType == wkbPolygon) && (m_nGeometryType == wkbMultiPolygon))
     606             :         {
     607          30 :             auto poMP = std::make_unique<OGRMultiPolygon>();
     608          15 :             poMP->addGeometryDirectly(poPolygonGeom.release());
     609          30 :             poPolygonGeom = std::move(poMP);
     610             :         }
     611          15 :         else if (eGeomType != m_nGeometryType)
     612             :         {
     613           0 :             CPLDebug("OGR-VFK", "%s: invalid geometry type %d (fid = %ld)",
     614             :                      m_pszName, (int)eGeomType, iFID);
     615           0 :             nInvalidNoRings++;
     616           0 :             continue;
     617             :         }
     618             : 
     619             :         /* set geometry */
     620          30 :         poPolygonGeom->setCoordinateDimension(2); /* force 2D */
     621          30 :         if (!poFeature->SetGeometry(poPolygonGeom.get()))
     622             :         {
     623           0 :             nInvalidNoRings++;
     624           0 :             continue;
     625             :         }
     626             : 
     627             :         /* store also geometry in DB */
     628          60 :         if (poReader->IsSpatial() &&
     629          30 :             SaveGeometryToDB(poPolygonGeom.get(), rowId) != OGRERR_FAILURE)
     630          30 :             nGeometries++;
     631             :     }
     632             : 
     633          30 :     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          30 :     UpdateVfkBlocks(nGeometries);
     638             : 
     639          30 :     if (poReader->IsSpatial())
     640          30 :         poReader->ExecuteSQL("COMMIT");
     641             : 
     642          30 :     return nInvalidNoLines + nInvalidNoRings;
     643             : #endif  // HAVE_GEOS
     644             : }
     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           0 : IVFKFeature *VFKDataBlockSQLite::GetFeature(GIntBig nFID)
     656             : {
     657           0 :     if (m_nFeatureCount < 0)
     658             :     {
     659           0 :         m_poReader->ReadDataRecords(this);
     660             :     }
     661             : 
     662           0 :     if (nFID < 1 || nFID > m_nFeatureCount)
     663           0 :         return nullptr;
     664             : 
     665           0 :     if (m_bGeometryPerBlock && !m_bGeometry)
     666             :     {
     667           0 :         LoadGeometry();
     668             :     }
     669             : 
     670           0 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     671             : 
     672           0 :     CPLString osSQL;
     673             :     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             :     {
     677           0 :         osSQL += " AND PORADOVE_CISLO_BODU = 1";
     678             :     }
     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             :     {
     684           0 :         rowId = sqlite3_column_int(hStmt, 0);
     685             :     }
     686           0 :     sqlite3_finalize(hStmt);
     687             : 
     688           0 :     return GetFeatureByIndex(rowId - 1);
     689             : }
     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         435 : VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char *column,
     701             :                                                  GUIntBig value, bool bGeom)
     702             : {
     703         435 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     704             : 
     705         870 :     CPLString osSQL;
     706             :     osSQL.Printf("SELECT %s from %s WHERE %s = " CPL_FRMT_GUIB, FID_COLUMN,
     707         435 :                  m_pszName, column, value);
     708         435 :     if (bGeom)
     709             :     {
     710           0 :         CPLString osColumn;
     711             : 
     712           0 :         osColumn.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
     713           0 :         osSQL += osColumn;
     714             :     }
     715             : 
     716         435 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     717         435 :     if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
     718           0 :         return nullptr;
     719             : 
     720         435 :     const int idx = sqlite3_column_int(hStmt, 0) - 1;
     721         435 :     sqlite3_finalize(hStmt);
     722             : 
     723         435 :     if (idx < 0 || idx >= m_nFeatureCount)  // ? assert
     724           0 :         return nullptr;
     725             : 
     726         435 :     return cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(idx));
     727             : }
     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         390 : VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char **column,
     740             :                                                  GUIntBig *value, int num,
     741             :                                                  bool bGeom)
     742             : {
     743         390 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     744             : 
     745         780 :     CPLString osSQL;
     746         390 :     osSQL.Printf("SELECT %s FROM %s WHERE ", FID_COLUMN, m_pszName);
     747             : 
     748         780 :     CPLString osItem;
     749        1170 :     for (int i = 0; i < num; i++)
     750             :     {
     751         780 :         if (i > 0)
     752         390 :             osItem.Printf(" AND %s = " CPL_FRMT_GUIB, column[i], value[i]);
     753             :         else
     754         390 :             osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
     755         780 :         osSQL += osItem;
     756             :     }
     757         390 :     if (bGeom)
     758             :     {
     759         195 :         osItem.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
     760         195 :         osSQL += osItem;
     761             :     }
     762             : 
     763         390 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     764         390 :     if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
     765           0 :         return nullptr;
     766             : 
     767         390 :     int idx = sqlite3_column_int(hStmt, 0) - 1; /* rowid starts at 1 */
     768         390 :     sqlite3_finalize(hStmt);
     769             : 
     770         390 :     if (idx < 0 || idx >= m_nFeatureCount)  // ? assert
     771           0 :         return nullptr;
     772             : 
     773         390 :     return cpl::down_cast<VFKFeatureSQLite *>(GetFeatureByIndex(idx));
     774             : }
     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          15 : VFKFeatureSQLiteList VFKDataBlockSQLite::GetFeatures(const char **column,
     786             :                                                      GUIntBig *value, int num)
     787             : {
     788          15 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     789             : 
     790          30 :     CPLString osItem;
     791          30 :     CPLString osSQL;
     792          15 :     osSQL.Printf("SELECT rowid from %s WHERE ", m_pszName);
     793          45 :     for (int i = 0; i < num; i++)
     794             :     {
     795          30 :         if (i > 0)
     796          15 :             osItem.Printf(" OR %s = " CPL_FRMT_GUIB, column[i], value[i]);
     797             :         else
     798          15 :             osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
     799          30 :         osSQL += osItem;
     800             :     }
     801          15 :     osSQL += " ORDER BY ";
     802          15 :     osSQL += FID_COLUMN;
     803             : 
     804          30 :     VFKFeatureSQLiteList fList;
     805             : 
     806          15 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     807         210 :     while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
     808             :     {
     809         195 :         const int iRowId = sqlite3_column_int(hStmt, 0);
     810             :         VFKFeatureSQLite *poFeature =
     811         195 :             dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(iRowId - 1));
     812         195 :         if (poFeature == nullptr)
     813             :         {
     814           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot retrieve feature %d",
     815             :                      iRowId);
     816           0 :             sqlite3_finalize(hStmt);
     817           0 :             return VFKFeatureSQLiteList();
     818             :         }
     819         195 :         fList.push_back(poFeature);
     820             :     }
     821             : 
     822          15 :     return fList;
     823             : }
     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         630 : OGRErr VFKDataBlockSQLite::SaveGeometryToDB(const OGRGeometry *poGeom,
     834             :                                             int iRowId)
     835             : {
     836             :     int rc;
     837        1260 :     CPLString osSQL;
     838             : 
     839         630 :     sqlite3_stmt *hStmt = nullptr;
     840             : 
     841         630 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     842             : 
     843             :     /* check if geometry column exists (see SUPPRESS_GEOMETRY open
     844             :        option) */
     845         630 :     if (AddGeometryColumn() != OGRERR_NONE)
     846           0 :         return OGRERR_FAILURE;
     847             : 
     848         630 :     if (poGeom)
     849             :     {
     850         630 :         const size_t nWKBLen = poGeom->WkbSize();
     851         630 :         if (nWKBLen > static_cast<size_t>(std::numeric_limits<int>::max()))
     852             :         {
     853           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Too large geometry");
     854           0 :             return OGRERR_FAILURE;
     855             :         }
     856         630 :         GByte *pabyWKB = (GByte *)VSI_MALLOC_VERBOSE(nWKBLen);
     857         630 :         if (pabyWKB)
     858             :         {
     859         630 :             poGeom->exportToWkb(wkbNDR, pabyWKB);
     860             : 
     861             :             osSQL.Printf("UPDATE %s SET %s = ? WHERE rowid = %d", m_pszName,
     862         630 :                          GEOM_COLUMN, iRowId);
     863         630 :             hStmt = poReader->PrepareStatement(osSQL.c_str());
     864             : 
     865         630 :             rc = sqlite3_bind_blob(hStmt, 1, pabyWKB, static_cast<int>(nWKBLen),
     866             :                                    CPLFree);
     867         630 :             if (rc != SQLITE_OK)
     868             :             {
     869           0 :                 sqlite3_finalize(hStmt);
     870           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     871             :                          "Storing geometry in DB failed");
     872           0 :                 return OGRERR_FAILURE;
     873             :             }
     874             :         }
     875             :     }
     876             :     else
     877             :     { /* invalid */
     878             :         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             :     }
     882             : 
     883         630 :     return poReader->ExecuteSQL(hStmt); /* calls sqlite3_finalize() */
     884             : }
     885             : 
     886             : /*!
     887             :   \brief Load geometry from DB
     888             : 
     889             :   \return true if geometry successfully loaded otherwise false
     890             : */
     891         192 : bool VFKDataBlockSQLite::LoadGeometryFromDB()
     892             : {
     893         192 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     894             : 
     895         192 :     if (!poReader->IsSpatial()) /* check if DB is spatial */
     896           0 :         return false;
     897             : 
     898         384 :     CPLString osSQL;
     899             :     osSQL.Printf("SELECT num_geometries FROM %s WHERE table_name = '%s'",
     900         192 :                  VFK_DB_TABLE, m_pszName);
     901         192 :     sqlite3_stmt *hStmt = poReader->PrepareStatement(osSQL.c_str());
     902         192 :     if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
     903           0 :         return false;
     904         192 :     const int nGeometries = sqlite3_column_int(hStmt, 0);
     905         192 :     sqlite3_finalize(hStmt);
     906             : 
     907         192 :     if (nGeometries < 1)
     908         187 :         return false;
     909             : 
     910          15 :     const bool bSkipInvalid = EQUAL(m_pszName, "OB") ||
     911          10 :                               EQUAL(m_pszName, "OP") ||
     912           5 :                               EQUAL(m_pszName, "OBBP");
     913             : 
     914             :     /* load geometry from DB */
     915             :     osSQL.Printf("SELECT %s,rowid,%s FROM %s ", GEOM_COLUMN, FID_COLUMN,
     916           5 :                  m_pszName);
     917           5 :     if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
     918           1 :         osSQL += "WHERE PORADOVE_CISLO_BODU = 1 ";
     919           5 :     osSQL += "ORDER BY ";
     920           5 :     osSQL += FID_COLUMN;
     921           5 :     hStmt = poReader->PrepareStatement(osSQL.c_str());
     922             : 
     923           5 :     int rowId = 0;
     924           5 :     int nInvalid = 0;
     925           5 :     int nGeometriesCount = 0;
     926             : 
     927          47 :     while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE)
     928             :     {
     929          42 :         rowId++;  // =sqlite3_column_int(hStmt, 1);
     930          42 :         const GIntBig iFID = sqlite3_column_int64(hStmt, 2);
     931             :         VFKFeatureSQLite *poFeature =
     932          42 :             dynamic_cast<VFKFeatureSQLite *>(GetFeatureByIndex(rowId - 1));
     933          42 :         if (poFeature == nullptr || poFeature->GetFID() != iFID)
     934             :         {
     935           0 :             continue;
     936             :         }
     937             : 
     938             :         // read geometry from DB
     939          42 :         const int nBytes = sqlite3_column_bytes(hStmt, 0);
     940          42 :         OGRGeometry *poGeometry = nullptr;
     941          42 :         if (nBytes > 0 && OGRGeometryFactory::createFromWkb(
     942             :                               sqlite3_column_blob(hStmt, 0), nullptr,
     943             :                               &poGeometry, nBytes) == OGRERR_NONE)
     944             :         {
     945          42 :             nGeometriesCount++;
     946          42 :             if (!poFeature->SetGeometry(poGeometry))
     947             :             {
     948           0 :                 nInvalid++;
     949             :             }
     950          42 :             delete poGeometry;
     951             :         }
     952             :         else
     953             :         {
     954           0 :             nInvalid++;
     955             :         }
     956             :     }
     957             : 
     958           5 :     CPLDebug("OGR-VFK", "%s: %d geometries loaded from DB", m_pszName,
     959             :              nGeometriesCount);
     960             : 
     961           5 :     if (nGeometriesCount != nGeometries)
     962             :     {
     963           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     964             :                  "%s: %d geometries loaded (should be %d)", m_pszName,
     965             :                  nGeometriesCount, nGeometries);
     966             :     }
     967             : 
     968           5 :     if (nInvalid > 0 && !bSkipInvalid)
     969             :     {
     970           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     971             :                  "%s: %d features with invalid or empty geometry", m_pszName,
     972             :                  nInvalid);
     973             :     }
     974             : 
     975           5 :     return true;
     976             : }
     977             : 
     978             : /*!
     979             :   \brief Update VFK_DB_TABLE table
     980             : 
     981             :   \param nGeometries number of geometries to update
     982             : */
     983         187 : void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries)
     984             : {
     985         374 :     CPLString osSQL;
     986             : 
     987         187 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
     988             : 
     989             :     /* update number of features in VFK_DB_TABLE table */
     990         187 :     const int nFeatCount = (int)GetFeatureCount();
     991         187 :     if (nFeatCount > 0)
     992             :     {
     993             :         osSQL.Printf("UPDATE %s SET num_features = %d WHERE table_name = '%s'",
     994          91 :                      VFK_DB_TABLE, nFeatCount, m_pszName);
     995          91 :         poReader->ExecuteSQL(osSQL.c_str());
     996             :     }
     997             : 
     998             :     /* update number of geometries in VFK_DB_TABLE table */
     999         187 :     if (nGeometries > 0)
    1000             :     {
    1001          75 :         CPLDebug("OGR-VFK",
    1002             :                  "VFKDataBlockSQLite::UpdateVfkBlocks(): name=%s -> "
    1003             :                  "%d geometries saved to internal DB",
    1004             :                  m_pszName, nGeometries);
    1005             : 
    1006             :         osSQL.Printf(
    1007             :             "UPDATE %s SET num_geometries = %d WHERE table_name = '%s'",
    1008          75 :             VFK_DB_TABLE, nGeometries, m_pszName);
    1009          75 :         poReader->ExecuteSQL(osSQL.c_str());
    1010             :     }
    1011         187 : }
    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         210 : void VFKDataBlockSQLite::UpdateFID(GIntBig iFID, const std::vector<int> &rowId)
    1020             : {
    1021         420 :     CPLString osSQL, osValue;
    1022         210 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
    1023             : 
    1024             :     /* update number of geometries in VFK_DB_TABLE table */
    1025             :     osSQL.Printf("UPDATE %s SET %s = " CPL_FRMT_GIB " WHERE rowid IN (",
    1026         210 :                  m_pszName, FID_COLUMN, iFID);
    1027         645 :     for (size_t i = 0; i < rowId.size(); i++)
    1028             :     {
    1029         435 :         if (i > 0)
    1030         225 :             osValue.Printf(",%d", rowId[i]);
    1031             :         else
    1032         210 :             osValue.Printf("%d", rowId[i]);
    1033         435 :         osSQL += osValue;
    1034             :     }
    1035         210 :     osSQL += ")";
    1036             : 
    1037         210 :     poReader->ExecuteSQL(osSQL.c_str());
    1038         210 : }
    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           0 : bool VFKDataBlockSQLite::IsRingClosed(const OGRLinearRing *poRing)
    1048             : {
    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             : }
    1059             : 
    1060             : /*!
    1061             :   \brief Get primary key
    1062             : 
    1063             :   \return property name or NULL
    1064             : */
    1065         180 : const char *VFKDataBlockSQLite::GetKey() const
    1066             : {
    1067         180 :     if (GetPropertyCount() > 1)
    1068             :     {
    1069         180 :         const VFKPropertyDefn *poPropDefn = GetProperty(0);
    1070         180 :         const char *pszKey = poPropDefn->GetName();
    1071         180 :         if (EQUAL(pszKey, "ID"))
    1072         180 :             return pszKey;
    1073             :     }
    1074             : 
    1075           0 :     return nullptr;
    1076             : }
    1077             : 
    1078             : /*!
    1079             :   \brief Get geometry SQL type (for geometry_columns table)
    1080             : 
    1081             :   \return geometry_type as integer
    1082             : */
    1083         976 : int VFKDataBlockSQLite::GetGeometrySQLType() const
    1084             : {
    1085         976 :     if (m_nGeometryType == wkbMultiPolygon)
    1086          15 :         return 6;
    1087         961 :     else if (m_nGeometryType == wkbPolygon)
    1088          15 :         return 3;
    1089         946 :     else if (m_nGeometryType == wkbLineString)
    1090          60 :         return 2;
    1091         886 :     else if (m_nGeometryType == wkbPoint)
    1092          90 :         return 1;
    1093             : 
    1094         796 :     return 0; /* unknown geometry type */
    1095             : }
    1096             : 
    1097             : /*!
    1098             :   \brief Add geometry column into table if not exists
    1099             : 
    1100             :   \return OGRERR_NONE on success otherwise OGRERR_FAILURE
    1101             :  */
    1102         642 : OGRErr VFKDataBlockSQLite::AddGeometryColumn() const
    1103             : {
    1104        1284 :     CPLString osSQL;
    1105             : 
    1106         642 :     VFKReaderSQLite *poReader = cpl::down_cast<VFKReaderSQLite *>(m_poReader);
    1107             : 
    1108         642 :     osSQL.Printf("SELECT %s FROM %s LIMIT 0", GEOM_COLUMN, m_pszName);
    1109         642 :     if (poReader->ExecuteSQL(osSQL.c_str(), CE_None) == OGRERR_FAILURE)
    1110             :     {
    1111             :         /* query failed, we assume that geometry column not exists */
    1112           0 :         osSQL.Printf("ALTER TABLE %s ADD COLUMN %s blob", m_pszName,
    1113           0 :                      GEOM_COLUMN);
    1114           0 :         return poReader->ExecuteSQL(osSQL.c_str());
    1115             :     }
    1116             : 
    1117         642 :     return OGRERR_NONE;
    1118             : }
    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           5 : OGRErr VFKDataBlockSQLite::LoadProperties()
    1128             : {
    1129          10 :     CPLString osSQL;
    1130             : 
    1131           5 :     if (m_hStmt)
    1132           0 :         sqlite3_finalize(m_hStmt);
    1133             : 
    1134             :     osSQL.Printf("SELECT * FROM %s",  // TODO: where
    1135           5 :                  m_pszName);
    1136           5 :     if (EQUAL(m_pszName, "SBP") || EQUAL(m_pszName, "SBPG"))
    1137           0 :         osSQL += " WHERE PORADOVE_CISLO_BODU = 1";
    1138             : 
    1139           5 :     m_hStmt = cpl::down_cast<VFKReaderSQLite *>(m_poReader)
    1140           5 :                   ->PrepareStatement(osSQL.c_str());
    1141             : 
    1142           5 :     if (m_hStmt == nullptr)
    1143           0 :         return OGRERR_FAILURE;
    1144             : 
    1145           5 :     return OGRERR_NONE;
    1146             : }
    1147             : 
    1148             : /*
    1149             :   \brief Clean feature properties for a next run
    1150             : 
    1151             :   \return OGRERR_NONE on success otherwise OGRERR_FAILURE
    1152             : */
    1153        1040 : OGRErr VFKDataBlockSQLite::CleanProperties()
    1154             : {
    1155        1040 :     if (m_hStmt)
    1156             :     {
    1157           5 :         if (sqlite3_finalize(m_hStmt) != SQLITE_OK)
    1158             :         {
    1159           0 :             m_hStmt = nullptr;
    1160           0 :             return OGRERR_FAILURE;
    1161             :         }
    1162           5 :         m_hStmt = nullptr;
    1163             :     }
    1164             : 
    1165        1040 :     return OGRERR_NONE;
    1166             : }

Generated by: LCOV version 1.14