LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqliteviewlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 172 214 80.4 %
Date: 2026-03-25 17:52:11 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRSQLiteViewLayer class, access to an existing
       5             :  *spatialite view. Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "ogr_sqlite.h"
      15             : #include "ogrsqliteutility.h"
      16             : 
      17             : #include <cstdlib>
      18             : #include <cstring>
      19             : #include <set>
      20             : #include <string>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_string.h"
      25             : #include "ogr_core.h"
      26             : #include "ogr_feature.h"
      27             : #include "ogr_geometry.h"
      28             : #include "sqlite3.h"
      29             : 
      30             : /************************************************************************/
      31             : /*                         OGRSQLiteViewLayer()                         */
      32             : /************************************************************************/
      33             : 
      34           5 : OGRSQLiteViewLayer::OGRSQLiteViewLayer(OGRSQLiteDataSource *poDSIn)
      35           5 :     : OGRSQLiteLayer(poDSIn)
      36             : {
      37           5 : }
      38             : 
      39             : /************************************************************************/
      40             : /*                        ~OGRSQLiteViewLayer()                         */
      41             : /************************************************************************/
      42             : 
      43          10 : OGRSQLiteViewLayer::~OGRSQLiteViewLayer()
      44             : 
      45             : {
      46           5 :     ClearStatement();
      47           5 :     CPLFree(m_pszViewName);
      48           5 :     CPLFree(m_pszEscapedTableName);
      49           5 :     CPLFree(m_pszEscapedUnderlyingTableName);
      50          10 : }
      51             : 
      52             : /************************************************************************/
      53             : /*                             Initialize()                             */
      54             : /************************************************************************/
      55             : 
      56           5 : CPLErr OGRSQLiteViewLayer::Initialize(const char *pszViewNameIn,
      57             :                                       const char *pszViewGeometry,
      58             :                                       const char *pszViewRowid,
      59             :                                       const char *pszUnderlyingTableName,
      60             :                                       const char *pszUnderlyingGeometryColumn)
      61             : 
      62             : {
      63           5 :     m_pszViewName = CPLStrdup(pszViewNameIn);
      64           5 :     SetDescription(m_pszViewName);
      65             : 
      66           5 :     m_osGeomColumn = pszViewGeometry;
      67           5 :     m_eGeomFormat = OSGF_SpatiaLite;
      68             : 
      69           5 :     CPLFree(m_pszFIDColumn);
      70           5 :     m_pszFIDColumn = CPLStrdup(pszViewRowid);
      71             : 
      72           5 :     m_osUnderlyingTableName = pszUnderlyingTableName;
      73           5 :     m_osUnderlyingGeometryColumn = pszUnderlyingGeometryColumn;
      74           5 :     m_poUnderlyingLayer = nullptr;
      75             : 
      76           5 :     m_pszEscapedTableName = CPLStrdup(SQLEscapeLiteral(m_pszViewName));
      77           5 :     m_pszEscapedUnderlyingTableName =
      78           5 :         CPLStrdup(SQLEscapeLiteral(pszUnderlyingTableName));
      79             : 
      80           5 :     return CE_None;
      81             : }
      82             : 
      83             : /************************************************************************/
      84             : /*                            GetLayerDefn()                            */
      85             : /************************************************************************/
      86             : 
      87          31 : const OGRFeatureDefn *OGRSQLiteViewLayer::GetLayerDefn() const
      88             : {
      89          31 :     if (!m_poFeatureDefn)
      90             :     {
      91           4 :         const_cast<OGRSQLiteViewLayer *>(this)->BuildLayerDefn();
      92             :     }
      93          31 :     return m_poFeatureDefn;
      94             : }
      95             : 
      96             : /************************************************************************/
      97             : /*                           BuildLayerDefn()                           */
      98             : /************************************************************************/
      99             : 
     100           4 : void OGRSQLiteViewLayer::BuildLayerDefn()
     101             : {
     102           4 :     EstablishFeatureDefn();
     103             : 
     104           4 :     if (m_poFeatureDefn == nullptr)
     105             :     {
     106           0 :         m_bLayerDefnError = true;
     107             : 
     108           0 :         m_poFeatureDefn = new OGRSQLiteFeatureDefn(m_pszViewName);
     109           0 :         m_poFeatureDefn->Reference();
     110             :     }
     111           4 : }
     112             : 
     113             : /************************************************************************/
     114             : /*                         GetUnderlyingLayer()                         */
     115             : /************************************************************************/
     116             : 
     117           4 : OGRSQLiteLayer *OGRSQLiteViewLayer::GetUnderlyingLayer()
     118             : {
     119           4 :     if (m_poUnderlyingLayer == nullptr)
     120             :     {
     121           4 :         if (strchr(m_osUnderlyingTableName, '(') == nullptr)
     122             :         {
     123           4 :             CPLString osNewUnderlyingTableName;
     124             :             osNewUnderlyingTableName.Printf(
     125             :                 "%s(%s)", m_osUnderlyingTableName.c_str(),
     126           4 :                 m_osUnderlyingGeometryColumn.c_str());
     127           4 :             m_poUnderlyingLayer = cpl::down_cast<OGRSQLiteLayer *>(
     128           4 :                 m_poDS->GetLayerByNameNotVisible(osNewUnderlyingTableName));
     129             :         }
     130           4 :         if (m_poUnderlyingLayer == nullptr)
     131           0 :             m_poUnderlyingLayer = cpl::down_cast<OGRSQLiteLayer *>(
     132           0 :                 m_poDS->GetLayerByNameNotVisible(m_osUnderlyingTableName));
     133             :     }
     134           4 :     return m_poUnderlyingLayer;
     135             : }
     136             : 
     137             : /************************************************************************/
     138             : /*                            GetGeomType()                             */
     139             : /************************************************************************/
     140             : 
     141           3 : OGRwkbGeometryType OGRSQLiteViewLayer::GetGeomType() const
     142             : {
     143           3 :     if (m_poFeatureDefn)
     144           3 :         return m_poFeatureDefn->GetGeomType();
     145             : 
     146             :     OGRSQLiteLayer *l_m_poUnderlyingLayer =
     147           0 :         const_cast<OGRSQLiteViewLayer *>(this)->GetUnderlyingLayer();
     148           0 :     if (l_m_poUnderlyingLayer)
     149           0 :         return l_m_poUnderlyingLayer->GetGeomType();
     150             : 
     151           0 :     return wkbUnknown;
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                        EstablishFeatureDefn()                        */
     156             : /************************************************************************/
     157             : 
     158           4 : CPLErr OGRSQLiteViewLayer::EstablishFeatureDefn()
     159             : {
     160           4 :     sqlite3 *hDB = m_poDS->GetDB();
     161           4 :     sqlite3_stmt *hColStmt = nullptr;
     162             : 
     163           4 :     OGRSQLiteLayer *l_m_poUnderlyingLayer = GetUnderlyingLayer();
     164           4 :     if (l_m_poUnderlyingLayer == nullptr)
     165             :     {
     166           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     167             :                  "Cannot find underlying layer %s for view %s",
     168             :                  m_osUnderlyingTableName.c_str(), m_pszViewName);
     169           0 :         return CE_Failure;
     170             :     }
     171           4 :     if (!l_m_poUnderlyingLayer->IsTableLayer())
     172             :     {
     173           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     174             :                  "Underlying layer %s for view %s is not a regular table",
     175             :                  m_osUnderlyingTableName.c_str(), m_pszViewName);
     176           0 :         return CE_Failure;
     177             :     }
     178             : 
     179             :     int nUnderlyingLayerGeomFieldIndex =
     180           8 :         l_m_poUnderlyingLayer->GetLayerDefn()->GetGeomFieldIndex(
     181           4 :             m_osUnderlyingGeometryColumn);
     182           4 :     if (nUnderlyingLayerGeomFieldIndex < 0)
     183             :     {
     184           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     185             :                  "Underlying layer %s for view %s has not expected geometry "
     186             :                  "column name %s",
     187             :                  m_osUnderlyingTableName.c_str(), m_pszViewName,
     188             :                  m_osUnderlyingGeometryColumn.c_str());
     189           0 :         return CE_Failure;
     190             :     }
     191             : 
     192           4 :     m_bHasSpatialIndex =
     193           4 :         l_m_poUnderlyingLayer->HasSpatialIndex(nUnderlyingLayerGeomFieldIndex);
     194             : 
     195             :     /* -------------------------------------------------------------------- */
     196             :     /*      Get the column definitions for this table.                      */
     197             :     /* -------------------------------------------------------------------- */
     198           4 :     hColStmt = nullptr;
     199           4 :     const char *pszSQL = CPLSPrintf("SELECT \"%s\", * FROM '%s' LIMIT 1",
     200           8 :                                     SQLEscapeName(m_pszFIDColumn).c_str(),
     201             :                                     m_pszEscapedTableName);
     202             : 
     203           4 :     int rc = sqlite3_prepare_v2(hDB, pszSQL, -1, &hColStmt, nullptr);
     204           4 :     if (rc != SQLITE_OK)
     205             :     {
     206           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     207             :                  "Unable to query table %s for column definitions : %s.",
     208             :                  m_pszViewName, sqlite3_errmsg(hDB));
     209             : 
     210           0 :         return CE_Failure;
     211             :     }
     212             : 
     213           4 :     rc = sqlite3_step(hColStmt);
     214           4 :     if (rc != SQLITE_DONE && rc != SQLITE_ROW)
     215             :     {
     216           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     217             :                  "In Initialize(): sqlite3_step(%s):\n  %s", pszSQL,
     218             :                  sqlite3_errmsg(hDB));
     219           0 :         sqlite3_finalize(hColStmt);
     220           0 :         return CE_Failure;
     221             :     }
     222             : 
     223             :     /* -------------------------------------------------------------------- */
     224             :     /*      Collect the rest of the fields.                                 */
     225             :     /* -------------------------------------------------------------------- */
     226           8 :     std::set<CPLString> aosGeomCols;
     227           4 :     std::set<CPLString> aosIgnoredCols;
     228           4 :     aosGeomCols.insert(m_osGeomColumn);
     229           4 :     BuildFeatureDefn(m_pszViewName, false, hColStmt, &aosGeomCols,
     230             :                      aosIgnoredCols);
     231           4 :     sqlite3_finalize(hColStmt);
     232             : 
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Set the properties of the geometry column.                      */
     235             :     /* -------------------------------------------------------------------- */
     236           4 :     if (m_poFeatureDefn->GetGeomFieldCount() != 0)
     237             :     {
     238             :         OGRSQLiteGeomFieldDefn *poSrcGeomFieldDefn =
     239           4 :             l_m_poUnderlyingLayer->myGetLayerDefn()->myGetGeomFieldDefn(
     240             :                 nUnderlyingLayerGeomFieldIndex);
     241             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
     242           4 :             m_poFeatureDefn->myGetGeomFieldDefn(0);
     243           4 :         poGeomFieldDefn->SetType(poSrcGeomFieldDefn->GetType());
     244           4 :         poGeomFieldDefn->SetSpatialRef(poSrcGeomFieldDefn->GetSpatialRef());
     245           4 :         poGeomFieldDefn->m_nSRSId = poSrcGeomFieldDefn->m_nSRSId;
     246           4 :         poGeomFieldDefn->m_eGeomFormat = m_eGeomFormat;
     247             :     }
     248             : 
     249           4 :     return CE_None;
     250             : }
     251             : 
     252             : /************************************************************************/
     253             : /*                           ResetStatement()                           */
     254             : /************************************************************************/
     255             : 
     256           4 : OGRErr OGRSQLiteViewLayer::ResetStatement()
     257             : 
     258             : {
     259           8 :     CPLString osSQL;
     260             : 
     261           4 :     ClearStatement();
     262             : 
     263           4 :     m_iNextShapeId = 0;
     264             : 
     265             :     osSQL.Printf("SELECT \"%s\", * FROM '%s' %s",
     266           4 :                  SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
     267           4 :                  m_osWHERE.c_str());
     268             : 
     269             :     const int rc =
     270           4 :         sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
     271           4 :                            static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
     272             : 
     273           4 :     if (rc == SQLITE_OK)
     274             :     {
     275           4 :         return OGRERR_NONE;
     276             :     }
     277             : 
     278           0 :     CPLError(CE_Failure, CPLE_AppDefined,
     279             :              "In ResetStatement(): sqlite3_prepare_v2(%s):\n  %s",
     280           0 :              osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
     281           0 :     m_hStmt = nullptr;
     282           0 :     return OGRERR_FAILURE;
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                           GetNextFeature()                           */
     287             : /************************************************************************/
     288             : 
     289           4 : OGRFeature *OGRSQLiteViewLayer::GetNextFeature()
     290             : 
     291             : {
     292           4 :     if (HasLayerDefnError())
     293           0 :         return nullptr;
     294             : 
     295           4 :     return OGRSQLiteLayer::GetNextFeature();
     296             : }
     297             : 
     298             : /************************************************************************/
     299             : /*                             GetFeature()                             */
     300             : /************************************************************************/
     301             : 
     302           3 : OGRFeature *OGRSQLiteViewLayer::GetFeature(GIntBig nFeatureId)
     303             : 
     304             : {
     305           3 :     if (HasLayerDefnError())
     306           0 :         return nullptr;
     307             : 
     308             :     /* -------------------------------------------------------------------- */
     309             :     /*      If we don't have an explicit FID column, just read through      */
     310             :     /*      the result set iteratively to find our target.                  */
     311             :     /* -------------------------------------------------------------------- */
     312           3 :     if (m_pszFIDColumn == nullptr)
     313           0 :         return OGRSQLiteLayer::GetFeature(nFeatureId);
     314             : 
     315             :     /* -------------------------------------------------------------------- */
     316             :     /*      Setup explicit query statement to fetch the record we want.     */
     317             :     /* -------------------------------------------------------------------- */
     318           6 :     CPLString osSQL;
     319             : 
     320           3 :     ClearStatement();
     321             : 
     322           3 :     m_iNextShapeId = nFeatureId;
     323             : 
     324             :     osSQL.Printf("SELECT \"%s\", * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
     325           3 :                  SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
     326           6 :                  SQLEscapeName(m_pszFIDColumn).c_str(), nFeatureId);
     327             : 
     328           3 :     CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
     329             : 
     330             :     const int rc =
     331           3 :         sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
     332           3 :                            static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
     333           3 :     if (rc != SQLITE_OK)
     334             :     {
     335           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     336             :                  "In GetFeature(): sqlite3_prepare_v2(%s):\n  %s",
     337           0 :                  osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
     338             : 
     339           0 :         return nullptr;
     340             :     }
     341             :     /* -------------------------------------------------------------------- */
     342             :     /*      Get the feature if possible.                                    */
     343             :     /* -------------------------------------------------------------------- */
     344           3 :     OGRFeature *poFeature = GetNextRawFeature();
     345             : 
     346           3 :     ResetReading();
     347             : 
     348           3 :     return poFeature;
     349             : }
     350             : 
     351             : /************************************************************************/
     352             : /*                         SetAttributeFilter()                         */
     353             : /************************************************************************/
     354             : 
     355           2 : OGRErr OGRSQLiteViewLayer::SetAttributeFilter(const char *pszQuery)
     356             : 
     357             : {
     358           2 :     if (pszQuery == nullptr)
     359           0 :         m_osQuery = "";
     360             :     else
     361           2 :         m_osQuery = pszQuery;
     362             : 
     363           2 :     BuildWhere();
     364             : 
     365           2 :     ResetReading();
     366             : 
     367           2 :     return OGRERR_NONE;
     368             : }
     369             : 
     370             : /************************************************************************/
     371             : /*                         ISetSpatialFilter()                          */
     372             : /************************************************************************/
     373             : 
     374           4 : OGRErr OGRSQLiteViewLayer::ISetSpatialFilter(int, const OGRGeometry *poGeomIn)
     375             : 
     376             : {
     377           4 :     if (InstallFilter(poGeomIn))
     378             :     {
     379           4 :         BuildWhere();
     380             : 
     381           4 :         ResetReading();
     382             :     }
     383           4 :     return OGRERR_NONE;
     384             : }
     385             : 
     386             : /************************************************************************/
     387             : /*                          GetSpatialWhere()                           */
     388             : /************************************************************************/
     389             : 
     390           6 : CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
     391             :                                               OGRGeometry *poFilterGeom)
     392             : {
     393          12 :     if (HasLayerDefnError() || m_poFeatureDefn == nullptr || iGeomCol < 0 ||
     394           6 :         iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
     395           0 :         return "";
     396             : 
     397           6 :     if (poFilterGeom != nullptr && m_bHasSpatialIndex)
     398             :     {
     399           3 :         OGREnvelope sEnvelope;
     400             : 
     401           3 :         poFilterGeom->getEnvelope(&sEnvelope);
     402             : 
     403             :         /* We first check that the spatial index table exists */
     404           3 :         if (!m_bHasCheckedSpatialIndexTable)
     405             :         {
     406           3 :             m_bHasCheckedSpatialIndexTable = true;
     407           3 :             char **papszResult = nullptr;
     408           3 :             int nRowCount = 0;
     409           3 :             int nColCount = 0;
     410           3 :             char *pszErrMsg = nullptr;
     411             : 
     412           6 :             CPLString osSQL;
     413             :             osSQL.Printf(
     414             :                 "SELECT name FROM sqlite_master "
     415             :                 "WHERE name='idx_%s_%s'",
     416             :                 m_pszEscapedUnderlyingTableName,
     417           3 :                 SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
     418             : 
     419             :             int rc =
     420           3 :                 sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult,
     421             :                                   &nRowCount, &nColCount, &pszErrMsg);
     422             : 
     423           3 :             if (rc != SQLITE_OK)
     424             :             {
     425           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", pszErrMsg);
     426           0 :                 sqlite3_free(pszErrMsg);
     427           0 :                 m_bHasSpatialIndex = false;
     428             :             }
     429             :             else
     430             :             {
     431           3 :                 if (nRowCount != 1)
     432             :                 {
     433           1 :                     m_bHasSpatialIndex = false;
     434             :                 }
     435             : 
     436           3 :                 sqlite3_free_table(papszResult);
     437             :             }
     438             :         }
     439             : 
     440           3 :         if (m_bHasSpatialIndex)
     441             :         {
     442             :             return FormatSpatialFilterFromRTree(
     443             :                 poFilterGeom,
     444           2 :                 CPLSPrintf("\"%s\"", SQLEscapeName(m_pszFIDColumn).c_str()),
     445           2 :                 m_pszEscapedUnderlyingTableName,
     446           6 :                 SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
     447             :         }
     448             :         else
     449             :         {
     450           1 :             CPLDebug("SQLITE",
     451             :                      "Count not find idx_%s_%s layer. Disabling spatial index",
     452             :                      m_pszEscapedUnderlyingTableName,
     453             :                      m_osUnderlyingGeometryColumn.c_str());
     454             :         }
     455             :     }
     456             : 
     457           4 :     if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded())
     458             :     {
     459             :         return FormatSpatialFilterFromMBR(
     460             :             poFilterGeom,
     461           4 :             SQLEscapeName(
     462           2 :                 m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef())
     463           2 :                 .c_str());
     464             :     }
     465             : 
     466           2 :     return "";
     467             : }
     468             : 
     469             : /************************************************************************/
     470             : /*                             BuildWhere()                             */
     471             : /*                                                                      */
     472             : /*      Build the WHERE statement appropriate to the current set of     */
     473             : /*      criteria (spatial and attribute queries).                       */
     474             : /************************************************************************/
     475             : 
     476           6 : void OGRSQLiteViewLayer::BuildWhere()
     477             : 
     478             : {
     479           6 :     m_osWHERE = "";
     480             : 
     481             :     CPLString osSpatialWHERE =
     482          12 :         GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom);
     483           6 :     if (!osSpatialWHERE.empty())
     484             :     {
     485           4 :         m_osWHERE = "WHERE ";
     486           4 :         m_osWHERE += osSpatialWHERE;
     487             :     }
     488             : 
     489           6 :     if (!m_osQuery.empty())
     490             :     {
     491           4 :         if (m_osWHERE.empty())
     492             :         {
     493           2 :             m_osWHERE = "WHERE ";
     494           2 :             m_osWHERE += m_osQuery;
     495             :         }
     496             :         else
     497             :         {
     498           2 :             m_osWHERE += " AND (";
     499           2 :             m_osWHERE += m_osQuery;
     500           2 :             m_osWHERE += ")";
     501             :         }
     502             :     }
     503           6 : }
     504             : 
     505             : /************************************************************************/
     506             : /*                           TestCapability()                           */
     507             : /************************************************************************/
     508             : 
     509           3 : int OGRSQLiteViewLayer::TestCapability(const char *pszCap) const
     510             : 
     511             : {
     512           3 :     if (HasLayerDefnError())
     513           0 :         return FALSE;
     514             : 
     515           3 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     516           3 :         return m_poFilterGeom == nullptr || m_osGeomColumn.empty() ||
     517           3 :                m_bHasSpatialIndex;
     518             : 
     519           0 :     else if (EQUAL(pszCap, OLCFastSpatialFilter))
     520           0 :         return m_bHasSpatialIndex;
     521             : 
     522             :     else
     523           0 :         return OGRSQLiteLayer::TestCapability(pszCap);
     524             : }
     525             : 
     526             : /************************************************************************/
     527             : /*                          GetFeatureCount()                           */
     528             : /*                                                                      */
     529             : /*      If a spatial filter is in effect, we turn control over to       */
     530             : /*      the generic counter.  Otherwise we return the total count.      */
     531             : /*      Eventually we should consider implementing a more efficient     */
     532             : /*      way of counting features matching a spatial query.              */
     533             : /************************************************************************/
     534             : 
     535           3 : GIntBig OGRSQLiteViewLayer::GetFeatureCount(int bForce)
     536             : 
     537             : {
     538           3 :     if (HasLayerDefnError())
     539           0 :         return 0;
     540             : 
     541           3 :     if (!TestCapability(OLCFastFeatureCount))
     542           0 :         return OGRSQLiteLayer::GetFeatureCount(bForce);
     543             : 
     544             :     /* -------------------------------------------------------------------- */
     545             :     /*      Form count SQL.                                                 */
     546             :     /* -------------------------------------------------------------------- */
     547           3 :     const char *pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s",
     548             :                                     m_pszEscapedTableName, m_osWHERE.c_str());
     549             : 
     550             :     /* -------------------------------------------------------------------- */
     551             :     /*      Execute.                                                        */
     552             :     /* -------------------------------------------------------------------- */
     553             :     char **papszResult, *pszErrMsg;
     554             :     int nRowCount, nColCount;
     555           3 :     int nResult = -1;
     556             : 
     557           3 :     if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nColCount,
     558           3 :                           &nRowCount, &pszErrMsg) != SQLITE_OK)
     559           0 :         return -1;
     560             : 
     561           3 :     if (nRowCount == 1 && nColCount == 1)
     562           3 :         nResult = atoi(papszResult[1]);
     563             : 
     564           3 :     sqlite3_free_table(papszResult);
     565             : 
     566           3 :     return nResult;
     567             : }

Generated by: LCOV version 1.14