LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqliteviewlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 173 215 80.5 %
Date: 2025-09-10 17:48:50 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 :         if (m_eGeomFormat != OSGF_None)
     247           4 :             poGeomFieldDefn->m_eGeomFormat = m_eGeomFormat;
     248             :     }
     249             : 
     250           4 :     return CE_None;
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                           ResetStatement()                           */
     255             : /************************************************************************/
     256             : 
     257           4 : OGRErr OGRSQLiteViewLayer::ResetStatement()
     258             : 
     259             : {
     260           8 :     CPLString osSQL;
     261             : 
     262           4 :     ClearStatement();
     263             : 
     264           4 :     m_iNextShapeId = 0;
     265             : 
     266             :     osSQL.Printf("SELECT \"%s\", * FROM '%s' %s",
     267           4 :                  SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
     268           4 :                  m_osWHERE.c_str());
     269             : 
     270             :     const int rc =
     271           4 :         sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
     272           4 :                            static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
     273             : 
     274           4 :     if (rc == SQLITE_OK)
     275             :     {
     276           4 :         return OGRERR_NONE;
     277             :     }
     278             : 
     279           0 :     CPLError(CE_Failure, CPLE_AppDefined,
     280             :              "In ResetStatement(): sqlite3_prepare_v2(%s):\n  %s",
     281           0 :              osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
     282           0 :     m_hStmt = nullptr;
     283           0 :     return OGRERR_FAILURE;
     284             : }
     285             : 
     286             : /************************************************************************/
     287             : /*                           GetNextFeature()                           */
     288             : /************************************************************************/
     289             : 
     290           4 : OGRFeature *OGRSQLiteViewLayer::GetNextFeature()
     291             : 
     292             : {
     293           4 :     if (HasLayerDefnError())
     294           0 :         return nullptr;
     295             : 
     296           4 :     return OGRSQLiteLayer::GetNextFeature();
     297             : }
     298             : 
     299             : /************************************************************************/
     300             : /*                             GetFeature()                             */
     301             : /************************************************************************/
     302             : 
     303           3 : OGRFeature *OGRSQLiteViewLayer::GetFeature(GIntBig nFeatureId)
     304             : 
     305             : {
     306           3 :     if (HasLayerDefnError())
     307           0 :         return nullptr;
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      If we don't have an explicit FID column, just read through      */
     311             :     /*      the result set iteratively to find our target.                  */
     312             :     /* -------------------------------------------------------------------- */
     313           3 :     if (m_pszFIDColumn == nullptr)
     314           0 :         return OGRSQLiteLayer::GetFeature(nFeatureId);
     315             : 
     316             :     /* -------------------------------------------------------------------- */
     317             :     /*      Setup explicit query statement to fetch the record we want.     */
     318             :     /* -------------------------------------------------------------------- */
     319           6 :     CPLString osSQL;
     320             : 
     321           3 :     ClearStatement();
     322             : 
     323           3 :     m_iNextShapeId = nFeatureId;
     324             : 
     325             :     osSQL.Printf("SELECT \"%s\", * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
     326           3 :                  SQLEscapeName(m_pszFIDColumn).c_str(), m_pszEscapedTableName,
     327           6 :                  SQLEscapeName(m_pszFIDColumn).c_str(), nFeatureId);
     328             : 
     329           3 :     CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
     330             : 
     331             :     const int rc =
     332           3 :         sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
     333           3 :                            static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
     334           3 :     if (rc != SQLITE_OK)
     335             :     {
     336           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     337             :                  "In GetFeature(): sqlite3_prepare_v2(%s):\n  %s",
     338           0 :                  osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
     339             : 
     340           0 :         return nullptr;
     341             :     }
     342             :     /* -------------------------------------------------------------------- */
     343             :     /*      Get the feature if possible.                                    */
     344             :     /* -------------------------------------------------------------------- */
     345           3 :     OGRFeature *poFeature = GetNextRawFeature();
     346             : 
     347           3 :     ResetReading();
     348             : 
     349           3 :     return poFeature;
     350             : }
     351             : 
     352             : /************************************************************************/
     353             : /*                         SetAttributeFilter()                         */
     354             : /************************************************************************/
     355             : 
     356           2 : OGRErr OGRSQLiteViewLayer::SetAttributeFilter(const char *pszQuery)
     357             : 
     358             : {
     359           2 :     if (pszQuery == nullptr)
     360           0 :         m_osQuery = "";
     361             :     else
     362           2 :         m_osQuery = pszQuery;
     363             : 
     364           2 :     BuildWhere();
     365             : 
     366           2 :     ResetReading();
     367             : 
     368           2 :     return OGRERR_NONE;
     369             : }
     370             : 
     371             : /************************************************************************/
     372             : /*                         ISetSpatialFilter()                          */
     373             : /************************************************************************/
     374             : 
     375           4 : OGRErr OGRSQLiteViewLayer::ISetSpatialFilter(int, const OGRGeometry *poGeomIn)
     376             : 
     377             : {
     378           4 :     if (InstallFilter(poGeomIn))
     379             :     {
     380           4 :         BuildWhere();
     381             : 
     382           4 :         ResetReading();
     383             :     }
     384           4 :     return OGRERR_NONE;
     385             : }
     386             : 
     387             : /************************************************************************/
     388             : /*                           GetSpatialWhere()                          */
     389             : /************************************************************************/
     390             : 
     391           6 : CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
     392             :                                               OGRGeometry *poFilterGeom)
     393             : {
     394          12 :     if (HasLayerDefnError() || m_poFeatureDefn == nullptr || iGeomCol < 0 ||
     395           6 :         iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
     396           0 :         return "";
     397             : 
     398           6 :     if (poFilterGeom != nullptr && m_bHasSpatialIndex)
     399             :     {
     400           3 :         OGREnvelope sEnvelope;
     401             : 
     402           3 :         poFilterGeom->getEnvelope(&sEnvelope);
     403             : 
     404             :         /* We first check that the spatial index table exists */
     405           3 :         if (!m_bHasCheckedSpatialIndexTable)
     406             :         {
     407           3 :             m_bHasCheckedSpatialIndexTable = true;
     408           3 :             char **papszResult = nullptr;
     409           3 :             int nRowCount = 0;
     410           3 :             int nColCount = 0;
     411           3 :             char *pszErrMsg = nullptr;
     412             : 
     413           6 :             CPLString osSQL;
     414             :             osSQL.Printf(
     415             :                 "SELECT name FROM sqlite_master "
     416             :                 "WHERE name='idx_%s_%s'",
     417             :                 m_pszEscapedUnderlyingTableName,
     418           3 :                 SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
     419             : 
     420             :             int rc =
     421           3 :                 sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult,
     422             :                                   &nRowCount, &nColCount, &pszErrMsg);
     423             : 
     424           3 :             if (rc != SQLITE_OK)
     425             :             {
     426           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", pszErrMsg);
     427           0 :                 sqlite3_free(pszErrMsg);
     428           0 :                 m_bHasSpatialIndex = false;
     429             :             }
     430             :             else
     431             :             {
     432           3 :                 if (nRowCount != 1)
     433             :                 {
     434           1 :                     m_bHasSpatialIndex = false;
     435             :                 }
     436             : 
     437           3 :                 sqlite3_free_table(papszResult);
     438             :             }
     439             :         }
     440             : 
     441           3 :         if (m_bHasSpatialIndex)
     442             :         {
     443             :             return FormatSpatialFilterFromRTree(
     444             :                 poFilterGeom,
     445           2 :                 CPLSPrintf("\"%s\"", SQLEscapeName(m_pszFIDColumn).c_str()),
     446           2 :                 m_pszEscapedUnderlyingTableName,
     447           6 :                 SQLEscapeLiteral(m_osUnderlyingGeometryColumn).c_str());
     448             :         }
     449             :         else
     450             :         {
     451           1 :             CPLDebug("SQLITE",
     452             :                      "Count not find idx_%s_%s layer. Disabling spatial index",
     453             :                      m_pszEscapedUnderlyingTableName,
     454             :                      m_osUnderlyingGeometryColumn.c_str());
     455             :         }
     456             :     }
     457             : 
     458           4 :     if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded())
     459             :     {
     460             :         return FormatSpatialFilterFromMBR(
     461             :             poFilterGeom,
     462           4 :             SQLEscapeName(
     463           2 :                 m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef())
     464           2 :                 .c_str());
     465             :     }
     466             : 
     467           2 :     return "";
     468             : }
     469             : 
     470             : /************************************************************************/
     471             : /*                             BuildWhere()                             */
     472             : /*                                                                      */
     473             : /*      Build the WHERE statement appropriate to the current set of     */
     474             : /*      criteria (spatial and attribute queries).                       */
     475             : /************************************************************************/
     476             : 
     477           6 : void OGRSQLiteViewLayer::BuildWhere()
     478             : 
     479             : {
     480           6 :     m_osWHERE = "";
     481             : 
     482             :     CPLString osSpatialWHERE =
     483          12 :         GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom);
     484           6 :     if (!osSpatialWHERE.empty())
     485             :     {
     486           4 :         m_osWHERE = "WHERE ";
     487           4 :         m_osWHERE += osSpatialWHERE;
     488             :     }
     489             : 
     490           6 :     if (!m_osQuery.empty())
     491             :     {
     492           4 :         if (m_osWHERE.empty())
     493             :         {
     494           2 :             m_osWHERE = "WHERE ";
     495           2 :             m_osWHERE += m_osQuery;
     496             :         }
     497             :         else
     498             :         {
     499           2 :             m_osWHERE += " AND (";
     500           2 :             m_osWHERE += m_osQuery;
     501           2 :             m_osWHERE += ")";
     502             :         }
     503             :     }
     504           6 : }
     505             : 
     506             : /************************************************************************/
     507             : /*                           TestCapability()                           */
     508             : /************************************************************************/
     509             : 
     510           3 : int OGRSQLiteViewLayer::TestCapability(const char *pszCap) const
     511             : 
     512             : {
     513           3 :     if (HasLayerDefnError())
     514           0 :         return FALSE;
     515             : 
     516           3 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     517           3 :         return m_poFilterGeom == nullptr || m_osGeomColumn.empty() ||
     518           3 :                m_bHasSpatialIndex;
     519             : 
     520           0 :     else if (EQUAL(pszCap, OLCFastSpatialFilter))
     521           0 :         return m_bHasSpatialIndex;
     522             : 
     523             :     else
     524           0 :         return OGRSQLiteLayer::TestCapability(pszCap);
     525             : }
     526             : 
     527             : /************************************************************************/
     528             : /*                          GetFeatureCount()                           */
     529             : /*                                                                      */
     530             : /*      If a spatial filter is in effect, we turn control over to       */
     531             : /*      the generic counter.  Otherwise we return the total count.      */
     532             : /*      Eventually we should consider implementing a more efficient     */
     533             : /*      way of counting features matching a spatial query.              */
     534             : /************************************************************************/
     535             : 
     536           3 : GIntBig OGRSQLiteViewLayer::GetFeatureCount(int bForce)
     537             : 
     538             : {
     539           3 :     if (HasLayerDefnError())
     540           0 :         return 0;
     541             : 
     542           3 :     if (!TestCapability(OLCFastFeatureCount))
     543           0 :         return OGRSQLiteLayer::GetFeatureCount(bForce);
     544             : 
     545             :     /* -------------------------------------------------------------------- */
     546             :     /*      Form count SQL.                                                 */
     547             :     /* -------------------------------------------------------------------- */
     548           3 :     const char *pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s",
     549             :                                     m_pszEscapedTableName, m_osWHERE.c_str());
     550             : 
     551             :     /* -------------------------------------------------------------------- */
     552             :     /*      Execute.                                                        */
     553             :     /* -------------------------------------------------------------------- */
     554             :     char **papszResult, *pszErrMsg;
     555             :     int nRowCount, nColCount;
     556           3 :     int nResult = -1;
     557             : 
     558           3 :     if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nColCount,
     559           3 :                           &nRowCount, &pszErrMsg) != SQLITE_OK)
     560           0 :         return -1;
     561             : 
     562           3 :     if (nRowCount == 1 && nColCount == 1)
     563           3 :         nResult = atoi(papszResult[1]);
     564             : 
     565           3 :     sqlite3_free_table(papszResult);
     566             : 
     567           3 :     return nResult;
     568             : }

Generated by: LCOV version 1.14