LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqliteselectlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 315 335 94.0 %
Date: 2025-07-03 09:54:33 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRSQLiteSelectLayer class, layer access to the results
       5             :  *           of a SELECT statement executed via ExecuteSQL().
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2004, Frank Warmerdam
      10             :  * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "ogr_sqlite.h"
      17             : 
      18             : #include <cstddef>
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : #include <set>
      22             : #include <string>
      23             : #include <utility>
      24             : 
      25             : #include "cpl_conv.h"
      26             : #include "cpl_error.h"
      27             : #include "cpl_string.h"
      28             : #include "ogr_core.h"
      29             : #include "ogr_feature.h"
      30             : #include "ogr_geometry.h"
      31             : #include "ogr_p.h"
      32             : #include "ogr_spatialref.h"
      33             : #include "ogrsf_frmts.h"
      34             : #include "sqlite3.h"
      35             : #include "ogr_swq.h"
      36             : 
      37             : IOGRSQLiteSelectLayer::~IOGRSQLiteSelectLayer() = default;
      38             : 
      39             : /************************************************************************/
      40             : /*                   OGRSQLiteSelectLayerCommonBehaviour()              */
      41             : /************************************************************************/
      42             : 
      43        2217 : OGRSQLiteSelectLayerCommonBehaviour::OGRSQLiteSelectLayerCommonBehaviour(
      44             :     OGRSQLiteBaseDataSource *poDSIn, IOGRSQLiteSelectLayer *m_poLayerIn,
      45        2217 :     const CPLString &osSQLIn, bool bEmptyLayerIn)
      46             :     : m_poDS(poDSIn), m_poLayer(m_poLayerIn), m_osSQLBase(osSQLIn),
      47        2217 :       m_bEmptyLayer(bEmptyLayerIn), m_osSQLCurrent(osSQLIn)
      48             : {
      49        2217 : }
      50             : 
      51             : /************************************************************************/
      52             : /*                        OGRSQLiteSelectLayer()                        */
      53             : /************************************************************************/
      54             : 
      55        1444 : OGRSQLiteSelectLayer::OGRSQLiteSelectLayer(
      56             :     OGRSQLiteDataSource *poDSIn, const CPLString &osSQLIn,
      57             :     sqlite3_stmt *m_hStmtIn, bool bUseStatementForGetNextFeature,
      58        1444 :     bool bEmptyLayer, bool bAllowMultipleGeomFieldsIn, bool bCanReopenBaseDS)
      59             :     : OGRSQLiteLayer(poDSIn),
      60             :       m_poBehavior(new OGRSQLiteSelectLayerCommonBehaviour(
      61        1444 :           poDSIn, this, osSQLIn, bEmptyLayer)),
      62        1444 :       m_bCanReopenBaseDS(bCanReopenBaseDS)
      63             : {
      64        1444 :     m_bAllowMultipleGeomFields = bAllowMultipleGeomFieldsIn;
      65             : 
      66        2888 :     std::set<CPLString> aosEmpty;
      67        1444 :     BuildFeatureDefn("SELECT", true, m_hStmtIn, nullptr, aosEmpty);
      68        1444 :     SetDescription("SELECT");
      69             : 
      70        1444 :     if (bUseStatementForGetNextFeature)
      71             :     {
      72        1146 :         m_hStmt = m_hStmtIn;
      73        1146 :         m_bDoStep = false;
      74             : 
      75             :         // Try to extract SRS from first geometry
      76        1386 :         for (int iField = 0;
      77        1386 :              !bEmptyLayer && iField < m_poFeatureDefn->GetGeomFieldCount();
      78             :              iField++)
      79             :         {
      80             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
      81         240 :                 m_poFeatureDefn->myGetGeomFieldDefn(iField);
      82         240 :             if (wkbFlatten(poGeomFieldDefn->GetType()) != wkbUnknown)
      83          18 :                 continue;
      84             :             const auto nColType =
      85         222 :                 sqlite3_column_type(m_hStmt, poGeomFieldDefn->m_iCol);
      86         222 :             if (nColType == SQLITE_BLOB)
      87             :             {
      88             :                 // Is it a Spatialite geometry ?
      89             :                 const GByte *pabyBlob = reinterpret_cast<const GByte *>(
      90         108 :                     sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol));
      91         108 :                 if (sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol) >
      92         100 :                         39 &&
      93         100 :                     pabyBlob[0] == 0x00 &&
      94         303 :                     (pabyBlob[1] == wkbNDR || pabyBlob[1] == wkbXDR) &&
      95          95 :                     pabyBlob[38] == 0x7C)
      96             :                 {
      97          95 :                     const int eByteOrder = pabyBlob[1];
      98          95 :                     int nSRSId = 0;
      99          95 :                     memcpy(&nSRSId, pabyBlob + 2, 4);
     100             : #ifdef CPL_LSB
     101          95 :                     if (eByteOrder != wkbNDR)
     102           0 :                         CPL_SWAP32PTR(&nSRSId);
     103             : #else
     104             :                     if (eByteOrder == wkbNDR)
     105             :                         CPL_SWAP32PTR(&nSRSId);
     106             : #endif
     107          95 :                     CPLPushErrorHandler(CPLQuietErrorHandler);
     108          95 :                     OGRSpatialReference *poSRS = m_poDS->FetchSRS(nSRSId);
     109          95 :                     CPLPopErrorHandler();
     110          95 :                     if (poSRS != nullptr)
     111             :                     {
     112          55 :                         poGeomFieldDefn->m_nSRSId = nSRSId;
     113          55 :                         poGeomFieldDefn->SetSpatialRef(poSRS);
     114             :                     }
     115             :                     else
     116          40 :                         CPLErrorReset();
     117             : 
     118          95 :                     continue;
     119             :                 }
     120             :             }
     121             : 
     122             : #ifdef SQLITE_HAS_COLUMN_METADATA
     123         127 :             if (iField == 0 &&
     124          14 :                 (nColType == SQLITE_NULL || nColType == SQLITE_BLOB))
     125             :             {
     126             :                 const char *pszTableName =
     127         126 :                     sqlite3_column_table_name(m_hStmt, poGeomFieldDefn->m_iCol);
     128         126 :                 if (pszTableName != nullptr)
     129             :                 {
     130             :                     CPLErrorStateBackuper oErrorStateBackuper(
     131         236 :                         CPLQuietErrorHandler);
     132             :                     OGRSQLiteLayer *m_poLayer =
     133         118 :                         cpl::down_cast<OGRSQLiteLayer *>(
     134         118 :                             m_poDS->GetLayerByName(pszTableName));
     135         236 :                     if (m_poLayer != nullptr &&
     136         118 :                         m_poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
     137             :                     {
     138             :                         OGRSQLiteGeomFieldDefn *poSrcGFldDefn =
     139          16 :                             m_poLayer->myGetLayerDefn()->myGetGeomFieldDefn(0);
     140          16 :                         poGeomFieldDefn->m_nSRSId = poSrcGFldDefn->m_nSRSId;
     141          16 :                         poGeomFieldDefn->SetSpatialRef(
     142          16 :                             poSrcGFldDefn->GetSpatialRef());
     143             :                     }
     144             :                 }
     145             :             }
     146             : #endif
     147             :         }
     148             :     }
     149             :     else
     150         298 :         sqlite3_finalize(m_hStmtIn);
     151        1444 : }
     152             : 
     153             : /************************************************************************/
     154             : /*                       ~OGRSQLiteSelectLayer()                        */
     155             : /************************************************************************/
     156             : 
     157        2286 : OGRSQLiteSelectLayer::~OGRSQLiteSelectLayer()
     158             : {
     159        1444 :     delete m_poBehavior;
     160        2286 : }
     161             : 
     162             : /************************************************************************/
     163             : /*                            ResetReading()                            */
     164             : /************************************************************************/
     165             : 
     166         345 : void OGRSQLiteSelectLayer::ResetReading()
     167             : {
     168         345 :     return m_poBehavior->ResetReading();
     169             : }
     170             : 
     171         808 : void OGRSQLiteSelectLayerCommonBehaviour::ResetReading()
     172             : {
     173         808 :     if (m_poLayer->HasReadFeature() || m_bAllowResetReadingEvenIfIndexAtZero)
     174             :     {
     175         490 :         m_poLayer->BaseResetReading();
     176         490 :         m_bAllowResetReadingEvenIfIndexAtZero = false;
     177             :     }
     178         808 : }
     179             : 
     180             : /************************************************************************/
     181             : /*                           GetNextFeature()                           */
     182             : /************************************************************************/
     183             : 
     184        3302 : OGRFeature *OGRSQLiteSelectLayer::GetNextFeature()
     185             : {
     186        3302 :     return m_poBehavior->GetNextFeature();
     187             : }
     188             : 
     189        5311 : OGRFeature *OGRSQLiteSelectLayerCommonBehaviour::GetNextFeature()
     190             : {
     191        5311 :     if (m_bEmptyLayer)
     192         284 :         return nullptr;
     193             : 
     194        5027 :     return m_poLayer->BaseGetNextFeature();
     195             : }
     196             : 
     197             : /************************************************************************/
     198             : /*               OGRGenSQLResultsLayerHasSpecialField()                 */
     199             : /************************************************************************/
     200             : 
     201         287 : static int HasSpecialFields(swq_expr_node *expr, int nMinIndexForSpecialField)
     202             : {
     203         287 :     if (expr->eNodeType == SNT_COLUMN)
     204             :     {
     205          84 :         if (expr->table_index == 0)
     206             :         {
     207          85 :             return expr->field_index >= nMinIndexForSpecialField &&
     208           1 :                    expr->field_index <
     209          85 :                        nMinIndexForSpecialField + SPECIAL_FIELD_COUNT;
     210             :         }
     211             :     }
     212         203 :     else if (expr->eNodeType == SNT_OPERATION)
     213             :     {
     214         286 :         for (int i = 0; i < expr->nSubExprCount; i++)
     215             :         {
     216         191 :             if (HasSpecialFields(expr->papoSubExpr[i],
     217         191 :                                  nMinIndexForSpecialField))
     218           1 :                 return TRUE;
     219             :         }
     220             :     }
     221         202 :     return FALSE;
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                         SetAttributeFilter()                         */
     226             : /************************************************************************/
     227             : 
     228         205 : OGRErr OGRSQLiteSelectLayer::SetAttributeFilter(const char *pszQuery)
     229             : {
     230         205 :     return m_poBehavior->SetAttributeFilter(pszQuery);
     231             : }
     232             : 
     233             : OGRErr
     234         239 : OGRSQLiteSelectLayerCommonBehaviour::SetAttributeFilter(const char *pszQuery)
     235             : 
     236             : {
     237         239 :     char *&m_pszAttrQuertyString = m_poLayer->GetAttrQueryString();
     238         239 :     if (m_pszAttrQuertyString == nullptr && pszQuery == nullptr)
     239          55 :         return OGRERR_NONE;
     240             : 
     241         184 :     CPLFree(m_pszAttrQuertyString);
     242         184 :     m_pszAttrQuertyString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
     243             : 
     244         184 :     m_bAllowResetReadingEvenIfIndexAtZero = true;
     245             : 
     246         368 :     OGRFeatureQuery oQuery;
     247             : 
     248         184 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     249             :     const bool bHasSpecialFields =
     250          96 :         (pszQuery != nullptr && pszQuery[0] != '\0' &&
     251         376 :          oQuery.Compile(m_poLayer->GetLayerDefn(), pszQuery) == OGRERR_NONE &&
     252          96 :          HasSpecialFields(static_cast<swq_expr_node *>(oQuery.GetSWQExpr()),
     253          96 :                           m_poLayer->GetLayerDefn()->GetFieldCount()));
     254         184 :     CPLPopErrorHandler();
     255             : 
     256         184 :     if (bHasSpecialFields || !BuildSQL())
     257             :     {
     258           2 :         return m_poLayer->BaseSetAttributeFilter(pszQuery);
     259             :     }
     260             : 
     261         182 :     ResetReading();
     262             : 
     263         182 :     return OGRERR_NONE;
     264             : }
     265             : 
     266             : /************************************************************************/
     267             : /*                           GetNextFeature()                           */
     268             : /************************************************************************/
     269             : 
     270         142 : GIntBig OGRSQLiteSelectLayer::GetFeatureCount(int bForce)
     271             : {
     272         142 :     return m_poBehavior->GetFeatureCount(bForce);
     273             : }
     274             : 
     275         410 : GIntBig OGRSQLiteSelectLayerCommonBehaviour::GetFeatureCount(int bForce)
     276             : {
     277         410 :     if (m_bEmptyLayer)
     278         121 :         return 0;
     279             : 
     280         289 :     if (m_poLayer->GetFeatureQuery() == nullptr &&
     281         289 :         STARTS_WITH_CI(m_osSQLCurrent, "SELECT COUNT(*) FROM") &&
     282           2 :         m_osSQLCurrent.ifind(" GROUP BY ") == std::string::npos &&
     283           2 :         m_osSQLCurrent.ifind(" UNION ") == std::string::npos &&
     284         580 :         m_osSQLCurrent.ifind(" INTERSECT ") == std::string::npos &&
     285           2 :         m_osSQLCurrent.ifind(" EXCEPT ") == std::string::npos)
     286           2 :         return 1;
     287             : 
     288         287 :     if (m_poLayer->GetFeatureQuery() != nullptr ||
     289         570 :         (m_poLayer->GetFilterGeom() != nullptr && !m_bSpatialFilterInSQL) ||
     290         283 :         STARTS_WITH_CI(m_osSQLCurrent.c_str(), "PRAGMA table_info("))
     291             :     {
     292           5 :         return m_poLayer->BaseGetFeatureCount(bForce);
     293             :     }
     294             : 
     295         564 :     CPLString osFeatureCountSQL("SELECT COUNT(*) FROM (");
     296         282 :     osFeatureCountSQL += m_osSQLCurrent;
     297         282 :     osFeatureCountSQL += ")";
     298             : 
     299         282 :     CPLDebug("SQLITE", "Running %s", osFeatureCountSQL.c_str());
     300             : 
     301             :     /* -------------------------------------------------------------------- */
     302             :     /*      Execute.                                                        */
     303             :     /* -------------------------------------------------------------------- */
     304         282 :     char *pszErrMsg = nullptr;
     305         282 :     char **papszResult = nullptr;
     306         282 :     int nRowCount = 0;
     307         282 :     int nColCount = 0;
     308         282 :     int nResult = -1;
     309             : 
     310         282 :     if (sqlite3_get_table(m_poDS->GetDB(), osFeatureCountSQL, &papszResult,
     311         282 :                           &nRowCount, &nColCount, &pszErrMsg) != SQLITE_OK)
     312             :     {
     313          43 :         CPLDebug("SQLITE", "Error: %s", pszErrMsg);
     314          43 :         sqlite3_free(pszErrMsg);
     315          43 :         return m_poLayer->BaseGetFeatureCount(bForce);
     316             :     }
     317             : 
     318         239 :     if (nRowCount == 1 && nColCount == 1)
     319             :     {
     320         239 :         nResult = atoi(papszResult[1]);
     321             :     }
     322             : 
     323         239 :     sqlite3_free_table(papszResult);
     324             : 
     325         239 :     return nResult;
     326             : }
     327             : 
     328             : /************************************************************************/
     329             : /*                           ResetStatement()                           */
     330             : /************************************************************************/
     331             : 
     332         191 : OGRErr OGRSQLiteSelectLayer::ResetStatement()
     333             : 
     334             : {
     335         191 :     ClearStatement();
     336             : 
     337         191 :     m_iNextShapeId = 0;
     338         191 :     m_bDoStep = true;
     339             : 
     340             : #ifdef DEBUG
     341         191 :     CPLDebug("OGR_SQLITE", "prepare_v2(%s)",
     342         191 :              m_poBehavior->m_osSQLCurrent.c_str());
     343             : #endif
     344             : 
     345         191 :     const int rc = sqlite3_prepare_v2(
     346         191 :         m_poDS->GetDB(), m_poBehavior->m_osSQLCurrent,
     347         191 :         static_cast<int>(m_poBehavior->m_osSQLCurrent.size()), &m_hStmt,
     348             :         nullptr);
     349             : 
     350         191 :     if (rc == SQLITE_OK)
     351         191 :         return OGRERR_NONE;
     352             : 
     353           0 :     CPLError(CE_Failure, CPLE_AppDefined,
     354             :              "In ResetStatement(): sqlite3_prepare_v2(%s):\n  %s",
     355           0 :              m_poBehavior->m_osSQLCurrent.c_str(),
     356           0 :              sqlite3_errmsg(m_poDS->GetDB()));
     357           0 :     m_hStmt = nullptr;
     358           0 :     return OGRERR_FAILURE;
     359             : }
     360             : 
     361             : /************************************************************************/
     362             : /*                          ISetSpatialFilter()                         */
     363             : /************************************************************************/
     364             : 
     365         165 : OGRErr OGRSQLiteSelectLayer::ISetSpatialFilter(int iGeomField,
     366             :                                                const OGRGeometry *poGeomIn)
     367             : 
     368             : {
     369         165 :     if (!m_bCanReopenBaseDS && iGeomField == 0)
     370             :     {
     371           2 :         if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField, poGeomIn,
     372           2 :                                                            true))
     373           0 :             return OGRERR_FAILURE;
     374             :         // For a Memory datasource, short-circuit
     375             :         // OGRSQLiteExecuteSQL::SetSpatialFilter()
     376             :         // that would try to re-open the Memory datasource, which would fail.
     377           2 :         return OGRLayer::ISetSpatialFilter(iGeomField, poGeomIn);
     378             :     }
     379             :     else
     380             :     {
     381         163 :         return m_poBehavior->SetSpatialFilter(iGeomField, poGeomIn);
     382             :     }
     383             : }
     384             : 
     385         208 : OGRErr OGRSQLiteSelectLayerCommonBehaviour::SetSpatialFilter(
     386             :     int iGeomField, const OGRGeometry *poGeomIn)
     387             : 
     388             : {
     389         208 :     m_bAllowResetReadingEvenIfIndexAtZero = true;
     390             : 
     391         208 :     int &iGeomFieldFilter = m_poLayer->GetIGeomFieldFilter();
     392         208 :     iGeomFieldFilter = iGeomField;
     393         208 :     if (m_poLayer->InstallFilter(poGeomIn))
     394             :     {
     395         147 :         BuildSQL();
     396             : 
     397         147 :         ResetReading();
     398             :     }
     399             : 
     400         208 :     return OGRERR_NONE;
     401             : }
     402             : 
     403             : /************************************************************************/
     404             : /*                            GetBaseLayer()                            */
     405             : /************************************************************************/
     406             : 
     407             : std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>
     408         340 : OGRSQLiteSelectLayerCommonBehaviour::GetBaseLayer(size_t &i)
     409             : {
     410         340 :     char **papszTokens = CSLTokenizeString(m_osSQLBase.c_str());
     411         340 :     bool bCanInsertFilter = true;
     412         340 :     int nCountSelect = 0, nCountFrom = 0, nCountWhere = 0;
     413             : 
     414        2427 :     for (int iToken = 0; papszTokens[iToken] != nullptr; iToken++)
     415             :     {
     416        2087 :         if (EQUAL(papszTokens[iToken], "SELECT"))
     417         341 :             nCountSelect++;
     418        1746 :         else if (EQUAL(papszTokens[iToken], "FROM"))
     419         341 :             nCountFrom++;
     420        1405 :         else if (EQUAL(papszTokens[iToken], "WHERE"))
     421         121 :             nCountWhere++;
     422        1284 :         else if (EQUAL(papszTokens[iToken], "UNION") ||
     423        1283 :                  EQUAL(papszTokens[iToken], "JOIN") ||
     424        1283 :                  EQUAL(papszTokens[iToken], "INTERSECT") ||
     425        1283 :                  EQUAL(papszTokens[iToken], "EXCEPT"))
     426             :         {
     427           1 :             bCanInsertFilter = false;
     428             :         }
     429             :     }
     430         340 :     CSLDestroy(papszTokens);
     431             : 
     432         340 :     if (!(bCanInsertFilter && nCountSelect == 1 && nCountFrom == 1 &&
     433             :           nCountWhere <= 1))
     434             :     {
     435           1 :         CPLDebug("SQLITE", "SQL expression too complex to analyse");
     436           1 :         return std::pair(nullptr, nullptr);
     437             :     }
     438             : 
     439         339 :     size_t nFromPos = m_osSQLBase.ifind(" from ");
     440         339 :     if (nFromPos == std::string::npos)
     441             :     {
     442           0 :         return std::pair(nullptr, nullptr);
     443             :     }
     444             : 
     445             :     /* Remove potential quotes around layer name */
     446         339 :     char chFirst = m_osSQLBase[nFromPos + 6];
     447         339 :     bool bInQuotes = (chFirst == '\'' || chFirst == '"');
     448         678 :     CPLString osBaseLayerName;
     449        2184 :     for (i = nFromPos + 6 + (bInQuotes ? 1 : 0); i < m_osSQLBase.size(); i++)
     450             :     {
     451        2060 :         if (m_osSQLBase[i] == chFirst && bInQuotes)
     452             :         {
     453           9 :             if (i + 1 < m_osSQLBase.size() && m_osSQLBase[i + 1] == chFirst)
     454             :             {
     455           1 :                 osBaseLayerName += m_osSQLBase[i];
     456           1 :                 i++;
     457             :             }
     458             :             else
     459             :             {
     460           8 :                 i++;
     461           8 :                 break;
     462             :             }
     463             :         }
     464        2051 :         else if (m_osSQLBase[i] == ' ' && !bInQuotes)
     465         207 :             break;
     466             :         else
     467        1844 :             osBaseLayerName += m_osSQLBase[i];
     468             :     }
     469             : 
     470         339 :     std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *> oPair;
     471         678 :     if (strchr(osBaseLayerName, '(') == nullptr &&
     472         339 :         m_poLayer->GetLayerDefn()->GetGeomFieldCount() != 0)
     473             :     {
     474         336 :         CPLString osNewUnderlyingTableName;
     475             :         osNewUnderlyingTableName.Printf(
     476             :             "%s(%s)", osBaseLayerName.c_str(),
     477         336 :             m_poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef());
     478             :         oPair =
     479         336 :             m_poDS->GetLayerWithGetSpatialWhereByName(osNewUnderlyingTableName);
     480             :     }
     481         339 :     if (oPair.first == nullptr)
     482         338 :         oPair = m_poDS->GetLayerWithGetSpatialWhereByName(osBaseLayerName);
     483             : 
     484         339 :     if (oPair.first != nullptr && m_poLayer->GetSpatialRef() != nullptr &&
     485          63 :         oPair.first->GetSpatialRef() != nullptr &&
     486         708 :         m_poLayer->GetSpatialRef() != oPair.first->GetSpatialRef() &&
     487          30 :         !m_poLayer->GetSpatialRef()->IsSame(oPair.first->GetSpatialRef()))
     488             :     {
     489           0 :         CPLDebug("SQLITE",
     490             :                  "Result layer and base layer don't have the same SRS.");
     491           0 :         return std::pair(nullptr, nullptr);
     492             :     }
     493             : 
     494         339 :     return oPair;
     495             : }
     496             : 
     497             : /************************************************************************/
     498             : /*                             BuildSQL()                               */
     499             : /************************************************************************/
     500             : 
     501         330 : int OGRSQLiteSelectLayerCommonBehaviour::BuildSQL()
     502             : 
     503             : {
     504         330 :     m_osSQLCurrent = m_osSQLBase;
     505         330 :     m_bSpatialFilterInSQL = true;
     506             : 
     507         330 :     size_t i = 0;
     508         330 :     std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *> oPair = GetBaseLayer(i);
     509         330 :     OGRLayer *poBaseLayer = oPair.first;
     510         330 :     if (poBaseLayer == nullptr)
     511             :     {
     512           1 :         CPLDebug("SQLITE", "Cannot find base layer");
     513           1 :         m_bSpatialFilterInSQL = false;
     514           1 :         return FALSE;
     515             :     }
     516             : 
     517         658 :     CPLString osSpatialWhere;
     518         329 :     if (m_poLayer->GetFilterGeom() != nullptr)
     519             :     {
     520             :         const char *pszGeomCol =
     521         127 :             m_poLayer->GetLayerDefn()
     522         127 :                 ->GetGeomFieldDefn(m_poLayer->GetIGeomFieldFilter())
     523         127 :                 ->GetNameRef();
     524         127 :         int nIdx = poBaseLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomCol);
     525         127 :         if (nIdx < 0)
     526             :         {
     527           0 :             CPLDebug("SQLITE", "Cannot find field %s in base layer",
     528             :                      pszGeomCol);
     529           0 :             m_bSpatialFilterInSQL = false;
     530             :         }
     531             :         else
     532             :         {
     533             :             osSpatialWhere =
     534         127 :                 oPair.second->GetSpatialWhere(nIdx, m_poLayer->GetFilterGeom());
     535         127 :             if (osSpatialWhere.empty())
     536             :             {
     537          51 :                 CPLDebug("SQLITE", "Cannot get spatial where clause");
     538          51 :                 m_bSpatialFilterInSQL = false;
     539             :             }
     540             :         }
     541             :     }
     542             : 
     543         658 :     CPLString osCustomWhere;
     544         329 :     if (!osSpatialWhere.empty())
     545             :     {
     546          76 :         osCustomWhere = osSpatialWhere;
     547             :     }
     548         455 :     if (m_poLayer->GetAttrQueryString() != nullptr &&
     549         126 :         m_poLayer->GetAttrQueryString()[0] != '\0')
     550             :     {
     551         126 :         if (!osSpatialWhere.empty())
     552          20 :             osCustomWhere += " AND (";
     553         126 :         osCustomWhere += m_poLayer->GetAttrQueryString();
     554         126 :         if (!osSpatialWhere.empty())
     555          20 :             osCustomWhere += ")";
     556             :     }
     557             : 
     558             :     /* Nothing to do */
     559         329 :     if (osCustomWhere.empty())
     560         147 :         return TRUE;
     561             : 
     562         293 :     while (i < m_osSQLBase.size() && m_osSQLBase[i] == ' ')
     563         111 :         i++;
     564             : 
     565         293 :     if (i < m_osSQLBase.size() &&
     566         111 :         STARTS_WITH_CI(m_osSQLBase.c_str() + i, "WHERE "))
     567             :     {
     568          65 :         m_osSQLCurrent = m_osSQLBase.substr(0, i + 6);
     569          65 :         m_osSQLCurrent += osCustomWhere;
     570          65 :         m_osSQLCurrent += " AND (";
     571             : 
     572          65 :         size_t nEndOfWhere = m_osSQLBase.ifind(" GROUP ");
     573          65 :         if (nEndOfWhere == std::string::npos)
     574          50 :             nEndOfWhere = m_osSQLBase.ifind(" ORDER ");
     575          65 :         if (nEndOfWhere == std::string::npos)
     576          34 :             nEndOfWhere = m_osSQLBase.ifind(" LIMIT ");
     577             : 
     578          65 :         if (nEndOfWhere == std::string::npos)
     579             :         {
     580          19 :             m_osSQLCurrent += m_osSQLBase.substr(i + 6);
     581          19 :             m_osSQLCurrent += ")";
     582             :         }
     583             :         else
     584             :         {
     585          46 :             m_osSQLCurrent += m_osSQLBase.substr(i + 6, nEndOfWhere - (i + 6));
     586          46 :             m_osSQLCurrent += ")";
     587          46 :             m_osSQLCurrent += m_osSQLBase.substr(nEndOfWhere);
     588             :         }
     589             :     }
     590         163 :     else if (i < m_osSQLBase.size() &&
     591          46 :              (STARTS_WITH_CI(m_osSQLBase.c_str() + i, "GROUP ") ||
     592          31 :               STARTS_WITH_CI(m_osSQLBase.c_str() + i, "ORDER ") ||
     593          15 :               STARTS_WITH_CI(m_osSQLBase.c_str() + i, "LIMIT ")))
     594             :     {
     595          46 :         m_osSQLCurrent = m_osSQLBase.substr(0, i);
     596          46 :         m_osSQLCurrent += " WHERE ";
     597          46 :         m_osSQLCurrent += osCustomWhere;
     598          46 :         m_osSQLCurrent += " ";
     599          46 :         m_osSQLCurrent += m_osSQLBase.substr(i);
     600             :     }
     601          71 :     else if (i == m_osSQLBase.size())
     602             :     {
     603          71 :         m_osSQLCurrent = m_osSQLBase.substr(0, i);
     604          71 :         m_osSQLCurrent += " WHERE ";
     605          71 :         m_osSQLCurrent += osCustomWhere;
     606             :     }
     607             :     else
     608             :     {
     609           0 :         CPLDebug("SQLITE", "SQL expression too complex for the driver to "
     610             :                            "insert attribute and/or spatial filter in it");
     611           0 :         m_bSpatialFilterInSQL = false;
     612           0 :         return FALSE;
     613             :     }
     614             : 
     615         182 :     return TRUE;
     616             : }
     617             : 
     618             : /************************************************************************/
     619             : /*                           TestCapability()                           */
     620             : /************************************************************************/
     621             : 
     622          60 : int OGRSQLiteSelectLayer::TestCapability(const char *pszCap)
     623             : {
     624          60 :     return m_poBehavior->TestCapability(pszCap);
     625             : }
     626             : 
     627          86 : int OGRSQLiteSelectLayerCommonBehaviour::TestCapability(const char *pszCap)
     628             : 
     629             : {
     630          86 :     if (EQUAL(pszCap, OLCFastSpatialFilter))
     631             :     {
     632          10 :         size_t i = 0;
     633          10 :         const auto oPair = GetBaseLayer(i);
     634          10 :         if (oPair.first == nullptr)
     635             :         {
     636           0 :             CPLDebug("SQLITE", "Cannot find base layer");
     637           0 :             return FALSE;
     638             :         }
     639             : 
     640          10 :         return oPair.second->HasFastSpatialFilter(0);
     641             :     }
     642             :     else
     643          76 :         return m_poLayer->BaseTestCapability(pszCap);
     644             : }
     645             : 
     646             : /************************************************************************/
     647             : /*                             GetExtent()                              */
     648             : /************************************************************************/
     649             : 
     650          14 : OGRErr OGRSQLiteSelectLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     651             :                                         bool bForce)
     652             : {
     653          14 :     return m_poBehavior->GetExtent(iGeomField, psExtent, bForce);
     654             : }
     655             : 
     656          16 : OGRErr OGRSQLiteSelectLayerCommonBehaviour::GetExtent(int iGeomField,
     657             :                                                       OGREnvelope *psExtent,
     658             :                                                       bool bForce)
     659             : {
     660          32 :     if (iGeomField < 0 ||
     661          32 :         iGeomField >= m_poLayer->GetLayerDefn()->GetGeomFieldCount() ||
     662          16 :         m_poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() ==
     663             :             wkbNone)
     664             :     {
     665           0 :         if (iGeomField != 0)
     666             :         {
     667           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     668             :                      "Invalid geometry field index : %d", iGeomField);
     669             :         }
     670           0 :         return OGRERR_FAILURE;
     671             :     }
     672             : 
     673             :     /* Caching of extent by SQL string is interesting to speed-up the */
     674             :     /* establishment of the WFS GetCapabilities document for a MapServer mapfile
     675             :      */
     676             :     /* which has several layers, only differing by scale rules */
     677          16 :     if (iGeomField == 0)
     678             :     {
     679             :         const OGREnvelope *psCachedExtent =
     680          16 :             m_poDS->GetEnvelopeFromSQL(m_osSQLBase);
     681          16 :         if (psCachedExtent)
     682             :         {
     683           5 :             *psExtent = *psCachedExtent;
     684           5 :             return OGRERR_NONE;
     685             :         }
     686             :     }
     687             : 
     688          22 :     CPLString osSQLCommand = m_osSQLBase;
     689             : 
     690             :     /* ORDER BY are costly to evaluate and are not necessary to establish */
     691             :     /* the layer extent. */
     692          11 :     size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
     693          11 :     if (osSQLCommand.ifind("SELECT ") == 0 &&
     694          11 :         osSQLCommand.ifind("SELECT ", 1) ==
     695          11 :             std::string::npos && /* Ensure there's no sub SELECT that could
     696             :                                     confuse our heuristics */
     697           4 :         nOrderByPos != std::string::npos &&
     698           4 :         osSQLCommand.ifind(" LIMIT ") == std::string::npos &&
     699           4 :         osSQLCommand.ifind(" UNION ") == std::string::npos &&
     700          26 :         osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
     701           4 :         osSQLCommand.ifind(" EXCEPT ") == std::string::npos)
     702             :     {
     703           4 :         osSQLCommand.resize(nOrderByPos);
     704             : 
     705             :         OGRLayer *poTmpLayer =
     706           4 :             m_poDS->ExecuteSQL(osSQLCommand.c_str(), nullptr, nullptr);
     707           4 :         if (poTmpLayer)
     708             :         {
     709           4 :             OGRErr eErr = poTmpLayer->GetExtent(iGeomField, psExtent, bForce);
     710           4 :             m_poDS->ReleaseResultSet(poTmpLayer);
     711           4 :             return eErr;
     712             :         }
     713             :     }
     714             : 
     715           7 :     OGRErr eErr = m_poLayer->BaseGetExtent(iGeomField, psExtent, bForce);
     716           7 :     if (iGeomField == 0 && eErr == OGRERR_NONE && m_poDS->GetUpdate() == false)
     717           5 :         m_poDS->SetEnvelopeForSQL(m_osSQLBase, *psExtent);
     718           7 :     return eErr;
     719             : }

Generated by: LCOV version 1.14