LCOV - code coverage report
Current view: top level - ogr - ogrfeaturequery.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 301 351 85.8 %
Date: 2025-09-10 17:48:50 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of simple SQL WHERE style attributes queries
       5             :  *           for OGRFeatures.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2008-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_feature.h"
      17             : #include "ogr_swq.h"
      18             : 
      19             : #include <cstddef>
      20             : #include <algorithm>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_string.h"
      25             : #include "ogr_attrind.h"
      26             : #include "ogr_core.h"
      27             : #include "ogr_p.h"
      28             : #include "ogrsf_frmts.h"
      29             : 
      30             : //! @cond Doxygen_Suppress
      31             : 
      32             : /************************************************************************/
      33             : /*     Support for special attributes (feature query and selection)     */
      34             : /************************************************************************/
      35             : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
      36             : 
      37             : const char *const SpecialFieldNames[SPECIAL_FIELD_COUNT] = {
      38             :     "FID", "OGR_GEOMETRY", "OGR_STYLE", "OGR_GEOM_WKT", "OGR_GEOM_AREA"};
      39             : const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT] = {
      40             :     SWQ_INTEGER, SWQ_STRING, SWQ_STRING, SWQ_STRING, SWQ_FLOAT};
      41             : 
      42             : /************************************************************************/
      43             : /*                          OGRFeatureQuery()                           */
      44             : /************************************************************************/
      45             : 
      46        3822 : OGRFeatureQuery::OGRFeatureQuery()
      47             :     : poTargetDefn(nullptr), pSWQExpr(nullptr),
      48        3822 :       m_psContext(new swq_evaluation_context())
      49             : {
      50        3822 : }
      51             : 
      52             : /************************************************************************/
      53             : /*                          ~OGRFeatureQuery()                          */
      54             : /************************************************************************/
      55             : 
      56        7640 : OGRFeatureQuery::~OGRFeatureQuery()
      57             : 
      58             : {
      59        3820 :     delete m_psContext;
      60        3820 :     delete static_cast<swq_expr_node *>(pSWQExpr);
      61        3820 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                             Compile()                                */
      65             : /************************************************************************/
      66             : 
      67             : OGRErr
      68        5063 : OGRFeatureQuery::Compile(const OGRLayer *poLayer, const char *pszExpression,
      69             :                          int bCheck,
      70             :                          swq_custom_func_registrar *poCustomFuncRegistrar)
      71             : 
      72             : {
      73        5063 :     if (poLayer->TestCapability(OLCStringsAsUTF8))
      74        3296 :         m_psContext->bUTF8Strings = true;
      75        5063 :     return Compile(poLayer, poLayer->GetLayerDefn(), pszExpression, bCheck,
      76        5063 :                    poCustomFuncRegistrar);
      77             : }
      78             : 
      79             : /************************************************************************/
      80             : /*                             Compile()                                */
      81             : /************************************************************************/
      82             : 
      83             : OGRErr
      84         166 : OGRFeatureQuery::Compile(const OGRFeatureDefn *poDefn,
      85             :                          const char *pszExpression, int bCheck,
      86             :                          swq_custom_func_registrar *poCustomFuncRegistrar)
      87             : 
      88             : {
      89         166 :     return Compile(nullptr, poDefn, pszExpression, bCheck,
      90         166 :                    poCustomFuncRegistrar);
      91             : }
      92             : 
      93             : /************************************************************************/
      94             : /*                             Compile()                                */
      95             : /************************************************************************/
      96             : 
      97             : OGRErr
      98        5229 : OGRFeatureQuery::Compile(const OGRLayer *poLayer, const OGRFeatureDefn *poDefn,
      99             :                          const char *pszExpression, int bCheck,
     100             :                          swq_custom_func_registrar *poCustomFuncRegistrar)
     101             : {
     102             :     // Clear any existing expression.
     103        5229 :     if (pSWQExpr != nullptr)
     104             :     {
     105        1495 :         delete static_cast<swq_expr_node *>(pSWQExpr);
     106        1495 :         pSWQExpr = nullptr;
     107             :     }
     108             : 
     109        5229 :     const char *pszFIDColumn = nullptr;
     110        5229 :     bool bMustAddFID = false;
     111        5229 :     if (poLayer != nullptr)
     112             :     {
     113        5063 :         pszFIDColumn = const_cast<OGRLayer *>(poLayer)->GetFIDColumn();
     114        5063 :         if (pszFIDColumn != nullptr)
     115             :         {
     116        5063 :             if (!EQUAL(pszFIDColumn, "") && !EQUAL(pszFIDColumn, "FID"))
     117             :             {
     118        1354 :                 bMustAddFID = true;
     119             :             }
     120             :         }
     121             :     }
     122             : 
     123             :     // Build list of fields.
     124        5229 :     const int nFieldCount = poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT +
     125        5229 :                             poDefn->GetGeomFieldCount() + (bMustAddFID ? 1 : 0);
     126             : 
     127             :     char **papszFieldNames =
     128        5229 :         static_cast<char **>(CPLMalloc(sizeof(char *) * nFieldCount));
     129             :     swq_field_type *paeFieldTypes = static_cast<swq_field_type *>(
     130        5229 :         CPLMalloc(sizeof(swq_field_type) * nFieldCount));
     131             : 
     132       76213 :     for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
     133             :     {
     134       70984 :         const OGRFieldDefn *poField = poDefn->GetFieldDefn(iField);
     135       70984 :         if (!poField)
     136             :         {
     137           0 :             CPLAssert(0);
     138             :             break;
     139             :         }
     140             : 
     141       70984 :         papszFieldNames[iField] = const_cast<char *>(poField->GetNameRef());
     142             : 
     143       70984 :         switch (poField->GetType())
     144             :         {
     145       13462 :             case OFTInteger:
     146             :             {
     147       13462 :                 if (poField->GetSubType() == OFSTBoolean)
     148        1131 :                     paeFieldTypes[iField] = SWQ_BOOLEAN;
     149             :                 else
     150       12331 :                     paeFieldTypes[iField] = SWQ_INTEGER;
     151       13462 :                 break;
     152             :             }
     153             : 
     154        3922 :             case OFTInteger64:
     155             :             {
     156        3922 :                 if (poField->GetSubType() == OFSTBoolean)
     157           0 :                     paeFieldTypes[iField] = SWQ_BOOLEAN;
     158             :                 else
     159        3922 :                     paeFieldTypes[iField] = SWQ_INTEGER64;
     160        3922 :                 break;
     161             :             }
     162             : 
     163        8692 :             case OFTReal:
     164        8692 :                 paeFieldTypes[iField] = SWQ_FLOAT;
     165        8692 :                 break;
     166             : 
     167       20861 :             case OFTString:
     168       20861 :                 paeFieldTypes[iField] = SWQ_STRING;
     169       20861 :                 break;
     170             : 
     171        7152 :             case OFTDate:
     172             :             case OFTTime:
     173             :             case OFTDateTime:
     174        7152 :                 paeFieldTypes[iField] = SWQ_TIMESTAMP;
     175        7152 :                 break;
     176             : 
     177       16895 :             default:
     178       16895 :                 paeFieldTypes[iField] = SWQ_OTHER;
     179       16895 :                 break;
     180             :         }
     181             :     }
     182             : 
     183        5229 :     int iField = 0;
     184       31374 :     while (iField < SPECIAL_FIELD_COUNT)
     185             :     {
     186       52290 :         papszFieldNames[poDefn->GetFieldCount() + iField] =
     187       26145 :             const_cast<char *>(SpecialFieldNames[iField]);
     188       26145 :         paeFieldTypes[poDefn->GetFieldCount() + iField] =
     189       26145 :             (iField == SPF_FID) ? SWQ_INTEGER64 : SpecialFieldTypes[iField];
     190       26145 :         ++iField;
     191             :     }
     192             : 
     193        9853 :     for (iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
     194             :     {
     195        4624 :         const OGRGeomFieldDefn *poField = poDefn->GetGeomFieldDefn(iField);
     196             :         const int iDstField =
     197        4624 :             poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT + iField;
     198             : 
     199        4624 :         papszFieldNames[iDstField] = const_cast<char *>(poField->GetNameRef());
     200        4624 :         if (*papszFieldNames[iDstField] == '\0')
     201        1911 :             papszFieldNames[iDstField] =
     202             :                 const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
     203        4624 :         paeFieldTypes[iDstField] = SWQ_GEOMETRY;
     204             :     }
     205             : 
     206        5229 :     if (bMustAddFID)
     207             :     {
     208        1354 :         papszFieldNames[nFieldCount - 1] = const_cast<char *>(pszFIDColumn);
     209        1354 :         paeFieldTypes[nFieldCount - 1] =
     210        1354 :             (poLayer != nullptr &&
     211        1354 :              const_cast<OGRLayer *>(poLayer)->GetMetadataItem(OLMD_FID64) !=
     212           0 :                  nullptr &&
     213           0 :              EQUAL(const_cast<OGRLayer *>(poLayer)->GetMetadataItem(OLMD_FID64),
     214             :                    "YES"))
     215        2708 :                 ? SWQ_INTEGER64
     216             :                 : SWQ_INTEGER;
     217             :     }
     218             : 
     219             :     // Try to parse.
     220        5229 :     poTargetDefn = poDefn;
     221       10458 :     const CPLErr eCPLErr = swq_expr_compile(
     222             :         pszExpression, nFieldCount, papszFieldNames, paeFieldTypes, bCheck,
     223        5229 :         poCustomFuncRegistrar, reinterpret_cast<swq_expr_node **>(&pSWQExpr));
     224             : 
     225        5229 :     OGRErr eErr = OGRERR_NONE;
     226        5229 :     if (eCPLErr != CE_None)
     227             :     {
     228          35 :         eErr = OGRERR_CORRUPT_DATA;
     229          35 :         pSWQExpr = nullptr;
     230             :     }
     231             : 
     232        5229 :     CPLFree(papszFieldNames);
     233        5229 :     CPLFree(paeFieldTypes);
     234             : 
     235        5229 :     return eErr;
     236             : }
     237             : 
     238             : /************************************************************************/
     239             : /*                    OGRFeatureFetcherFixFieldIndex()                  */
     240             : /************************************************************************/
     241             : 
     242       41561 : static int OGRFeatureFetcherFixFieldIndex(const OGRFeatureDefn *poFDefn,
     243             :                                           int nIdx)
     244             : {
     245             :     /* Nastry trick: if we inserted the FID column as an extra column, it is */
     246             :     /* after regular fields, special fields and geometry fields */
     247       41561 :     if (nIdx == poFDefn->GetFieldCount() + SPECIAL_FIELD_COUNT +
     248       41561 :                     poFDefn->GetGeomFieldCount())
     249             :     {
     250          17 :         return poFDefn->GetFieldCount() + SPF_FID;
     251             :     }
     252       41544 :     return nIdx;
     253             : }
     254             : 
     255             : /************************************************************************/
     256             : /*                         OGRFeatureFetcher()                          */
     257             : /************************************************************************/
     258             : 
     259       40898 : static swq_expr_node *OGRFeatureFetcher(swq_expr_node *op, void *pFeatureIn)
     260             : 
     261             : {
     262       40898 :     OGRFeature *poFeature = static_cast<OGRFeature *>(pFeatureIn);
     263             : 
     264       40898 :     if (op->field_type == SWQ_GEOMETRY)
     265             :     {
     266          13 :         const int iField = op->field_index -
     267          13 :                            (poFeature->GetFieldCount() + SPECIAL_FIELD_COUNT);
     268             :         swq_expr_node *poRetNode =
     269          13 :             new swq_expr_node(poFeature->GetGeomFieldRef(iField));
     270          13 :         return poRetNode;
     271             :     }
     272             : 
     273       40885 :     const int idx = OGRFeatureFetcherFixFieldIndex(poFeature->GetDefnRef(),
     274             :                                                    op->field_index);
     275             : 
     276       40885 :     swq_expr_node *poRetNode = nullptr;
     277       40885 :     switch (op->field_type)
     278             :     {
     279       15569 :         case SWQ_INTEGER:
     280             :         case SWQ_BOOLEAN:
     281       15569 :             poRetNode = new swq_expr_node(poFeature->GetFieldAsInteger(idx));
     282       15569 :             break;
     283             : 
     284        4849 :         case SWQ_INTEGER64:
     285        4849 :             poRetNode = new swq_expr_node(poFeature->GetFieldAsInteger64(idx));
     286        4849 :             break;
     287             : 
     288        6531 :         case SWQ_FLOAT:
     289        6531 :             poRetNode = new swq_expr_node(poFeature->GetFieldAsDouble(idx));
     290        6531 :             break;
     291             : 
     292         312 :         case SWQ_TIMESTAMP:
     293         312 :             poRetNode = new swq_expr_node(poFeature->GetFieldAsString(idx));
     294         312 :             poRetNode->MarkAsTimestamp();
     295         312 :             break;
     296             : 
     297       13624 :         default:
     298       13624 :             poRetNode = new swq_expr_node(poFeature->GetFieldAsString(idx));
     299       13624 :             break;
     300             :     }
     301             : 
     302       40885 :     poRetNode->is_null = !(poFeature->IsFieldSetAndNotNull(idx));
     303             : 
     304       40885 :     return poRetNode;
     305             : }
     306             : 
     307             : /************************************************************************/
     308             : /*                              Evaluate()                              */
     309             : /************************************************************************/
     310             : 
     311       66209 : int OGRFeatureQuery::Evaluate(OGRFeature *poFeature)
     312             : 
     313             : {
     314       66209 :     if (pSWQExpr == nullptr)
     315           0 :         return FALSE;
     316             : 
     317      132418 :     swq_expr_node *poResult = static_cast<swq_expr_node *>(pSWQExpr)->Evaluate(
     318       66209 :         OGRFeatureFetcher, poFeature, *m_psContext);
     319             : 
     320       66209 :     if (poResult == nullptr)
     321           5 :         return FALSE;
     322             : 
     323       66204 :     bool bLogicalResult = false;
     324       66204 :     if (poResult->field_type == SWQ_INTEGER ||
     325       66190 :         poResult->field_type == SWQ_INTEGER64 ||
     326       66190 :         poResult->field_type == SWQ_BOOLEAN)
     327       66204 :         bLogicalResult = CPL_TO_BOOL(static_cast<int>(poResult->int_value));
     328             : 
     329       66204 :     delete poResult;
     330             : 
     331       66204 :     return bLogicalResult;
     332             : }
     333             : 
     334             : /************************************************************************/
     335             : /*                            CanUseIndex()                             */
     336             : /************************************************************************/
     337             : 
     338          36 : int OGRFeatureQuery::CanUseIndex(OGRLayer *poLayer)
     339             : {
     340          36 :     swq_expr_node *psExpr = static_cast<swq_expr_node *>(pSWQExpr);
     341             : 
     342             :     // Do we have an index on the targeted layer?
     343          36 :     if (poLayer->GetIndex() == nullptr)
     344           0 :         return FALSE;
     345             : 
     346          36 :     return CanUseIndex(psExpr, poLayer);
     347             : }
     348             : 
     349          36 : int OGRFeatureQuery::CanUseIndex(const swq_expr_node *psExpr, OGRLayer *poLayer)
     350             : {
     351             :     // Does the expression meet our requirements?
     352          36 :     if (psExpr == nullptr || psExpr->eNodeType != SNT_OPERATION)
     353           0 :         return FALSE;
     354             : 
     355          36 :     if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
     356           0 :         psExpr->nSubExprCount == 2)
     357             :     {
     358           0 :         return CanUseIndex(psExpr->papoSubExpr[0], poLayer) &&
     359           0 :                CanUseIndex(psExpr->papoSubExpr[1], poLayer);
     360             :     }
     361             : 
     362          36 :     if (!(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN) ||
     363          29 :         psExpr->nSubExprCount < 2)
     364           7 :         return FALSE;
     365             : 
     366          29 :     swq_expr_node *poColumn = psExpr->papoSubExpr[0];
     367          29 :     swq_expr_node *poValue = psExpr->papoSubExpr[1];
     368             : 
     369          29 :     if (poColumn->eNodeType != SNT_COLUMN || poValue->eNodeType != SNT_CONSTANT)
     370           2 :         return FALSE;
     371             : 
     372             :     OGRAttrIndex *poIndex =
     373          54 :         poLayer->GetIndex()->GetFieldIndex(OGRFeatureFetcherFixFieldIndex(
     374          27 :             poLayer->GetLayerDefn(), poColumn->field_index));
     375          27 :     if (poIndex == nullptr)
     376          27 :         return FALSE;
     377             : 
     378             :     // Have an index.
     379           0 :     return TRUE;
     380             : }
     381             : 
     382             : /************************************************************************/
     383             : /*                       EvaluateAgainstIndices()                       */
     384             : /*                                                                      */
     385             : /*      Attempt to return a list of FIDs matching the given             */
     386             : /*      attribute query conditions utilizing attribute indices.         */
     387             : /*      Returns NULL if the result cannot be computed from the          */
     388             : /*      available indices, or an "OGRNullFID" terminated list of        */
     389             : /*      FIDs if it can.                                                 */
     390             : /*                                                                      */
     391             : /*      For now we only support equality tests on a single indexed      */
     392             : /*      attribute field.  Eventually we should make this support        */
     393             : /*      multi-part queries with ranges.                                 */
     394             : /************************************************************************/
     395             : 
     396        5265 : GIntBig *OGRFeatureQuery::EvaluateAgainstIndices(OGRLayer *poLayer,
     397             :                                                  OGRErr *peErr)
     398             : 
     399             : {
     400        5265 :     swq_expr_node *psExpr = static_cast<swq_expr_node *>(pSWQExpr);
     401             : 
     402        5265 :     if (peErr != nullptr)
     403           0 :         *peErr = OGRERR_NONE;
     404             : 
     405             :     // Do we have an index on the targeted layer?
     406        5265 :     if (poLayer->GetIndex() == nullptr)
     407        4678 :         return nullptr;
     408             : 
     409         587 :     GIntBig nFIDCount = 0;
     410         587 :     return EvaluateAgainstIndices(psExpr, poLayer, nFIDCount);
     411             : }
     412             : 
     413             : // The input arrays must be sorted.
     414           1 : static GIntBig *OGRORGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1,
     415             :                                   GIntBig panFIDList2[], GIntBig nFIDCount2,
     416             :                                   GIntBig &nFIDCount)
     417             : {
     418           1 :     const GIntBig nMaxCount = nFIDCount1 + nFIDCount2;
     419             :     GIntBig *panFIDList = static_cast<GIntBig *>(
     420           1 :         CPLMalloc(static_cast<size_t>(nMaxCount + 1) * sizeof(GIntBig)));
     421           1 :     nFIDCount = 0;
     422             : 
     423           5 :     for (GIntBig i1 = 0, i2 = 0; i1 < nFIDCount1 || i2 < nFIDCount2;)
     424             :     {
     425           4 :         if (i1 < nFIDCount1 && i2 < nFIDCount2)
     426             :         {
     427           2 :             const GIntBig nVal1 = panFIDList1[i1];
     428           2 :             const GIntBig nVal2 = panFIDList2[i2];
     429           2 :             if (nVal1 < nVal2)
     430             :             {
     431           1 :                 if (i1 + 1 < nFIDCount1 && panFIDList1[i1 + 1] <= nVal2)
     432             :                 {
     433           1 :                     panFIDList[nFIDCount++] = nVal1;
     434           1 :                     i1++;
     435             :                 }
     436             :                 else
     437             :                 {
     438           0 :                     panFIDList[nFIDCount++] = nVal1;
     439           0 :                     panFIDList[nFIDCount++] = nVal2;
     440           0 :                     i1++;
     441           0 :                     i2++;
     442             :                 }
     443             :             }
     444           1 :             else if (nVal1 == nVal2)
     445             :             {
     446           1 :                 panFIDList[nFIDCount++] = nVal1;
     447           1 :                 i1++;
     448           1 :                 i2++;
     449             :             }
     450             :             else
     451             :             {
     452           0 :                 if (i2 + 1 < nFIDCount2 && panFIDList2[i2 + 1] <= nVal1)
     453             :                 {
     454           0 :                     panFIDList[nFIDCount++] = nVal2;
     455           0 :                     i2++;
     456             :                 }
     457             :                 else
     458             :                 {
     459           0 :                     panFIDList[nFIDCount++] = nVal2;
     460           0 :                     panFIDList[nFIDCount++] = nVal1;
     461           0 :                     i1++;
     462           0 :                     i2++;
     463             :                 }
     464           2 :             }
     465             :         }
     466           2 :         else if (i1 < nFIDCount1)
     467             :         {
     468           0 :             const GIntBig nVal1 = panFIDList1[i1];
     469           0 :             panFIDList[nFIDCount++] = nVal1;
     470           0 :             i1++;
     471             :         }
     472           2 :         else if (i2 < nFIDCount2)
     473             :         {
     474           2 :             const GIntBig nVal2 = panFIDList2[i2];
     475           2 :             panFIDList[nFIDCount++] = nVal2;
     476           2 :             i2++;
     477             :         }
     478             :     }
     479             : 
     480           1 :     panFIDList[nFIDCount] = OGRNullFID;
     481             : 
     482           1 :     return panFIDList;
     483             : }
     484             : 
     485             : // The input arrays must be sorted.
     486           2 : static GIntBig *OGRANDGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1,
     487             :                                    GIntBig panFIDList2[], GIntBig nFIDCount2,
     488             :                                    GIntBig &nFIDCount)
     489             : {
     490           2 :     GIntBig nMaxCount = std::max(nFIDCount1, nFIDCount2);
     491             :     GIntBig *panFIDList = static_cast<GIntBig *>(
     492           2 :         CPLMalloc(static_cast<size_t>(nMaxCount + 1) * sizeof(GIntBig)));
     493           2 :     nFIDCount = 0;
     494             : 
     495           6 :     for (GIntBig i1 = 0, i2 = 0; i1 < nFIDCount1 && i2 < nFIDCount2;)
     496             :     {
     497           4 :         const GIntBig nVal1 = panFIDList1[i1];
     498           4 :         const GIntBig nVal2 = panFIDList2[i2];
     499           4 :         if (nVal1 < nVal2)
     500             :         {
     501           2 :             if (i1 + 1 < nFIDCount1 && panFIDList1[i1 + 1] <= nVal2)
     502             :             {
     503           1 :                 i1++;
     504             :             }
     505             :             else
     506             :             {
     507           1 :                 i1++;
     508           1 :                 i2++;
     509             :             }
     510             :         }
     511           2 :         else if (nVal1 == nVal2)
     512             :         {
     513           2 :             panFIDList[nFIDCount++] = nVal1;
     514           2 :             i1++;
     515           2 :             i2++;
     516             :         }
     517             :         else
     518             :         {
     519           0 :             if (i2 + 1 < nFIDCount2 && panFIDList2[i2 + 1] <= nVal1)
     520             :             {
     521           0 :                 i2++;
     522             :             }
     523             :             else
     524             :             {
     525           0 :                 i1++;
     526           0 :                 i2++;
     527             :             }
     528             :         }
     529             :     }
     530             : 
     531           2 :     panFIDList[nFIDCount] = OGRNullFID;
     532             : 
     533           2 :     return panFIDList;
     534             : }
     535             : 
     536         743 : GIntBig *OGRFeatureQuery::EvaluateAgainstIndices(const swq_expr_node *psExpr,
     537             :                                                  OGRLayer *poLayer,
     538             :                                                  GIntBig &nFIDCount)
     539             : {
     540             :     // Does the expression meet our requirements?
     541         743 :     if (psExpr == nullptr || psExpr->eNodeType != SNT_OPERATION)
     542           3 :         return nullptr;
     543             : 
     544         740 :     if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
     545         153 :         psExpr->nSubExprCount == 2)
     546             :     {
     547         153 :         GIntBig nFIDCount1 = 0;
     548         153 :         GIntBig nFIDCount2 = 0;
     549             :         GIntBig *panFIDList1 =
     550         153 :             EvaluateAgainstIndices(psExpr->papoSubExpr[0], poLayer, nFIDCount1);
     551             :         GIntBig *panFIDList2 =
     552             :             panFIDList1 == nullptr
     553         153 :                 ? nullptr
     554           3 :                 : EvaluateAgainstIndices(psExpr->papoSubExpr[1], poLayer,
     555         153 :                                          nFIDCount2);
     556         153 :         GIntBig *panFIDList = nullptr;
     557         153 :         if (panFIDList1 != nullptr && panFIDList2 != nullptr)
     558             :         {
     559           3 :             if (psExpr->nOperation == SWQ_OR)
     560             :                 panFIDList =
     561           1 :                     OGRORGIntBigArray(panFIDList1, nFIDCount1, panFIDList2,
     562             :                                       nFIDCount2, nFIDCount);
     563           2 :             else if (psExpr->nOperation == SWQ_AND)
     564             :                 panFIDList =
     565           2 :                     OGRANDGIntBigArray(panFIDList1, nFIDCount1, panFIDList2,
     566             :                                        nFIDCount2, nFIDCount);
     567             :         }
     568         153 :         CPLFree(panFIDList1);
     569         153 :         CPLFree(panFIDList2);
     570         153 :         return panFIDList;
     571             :     }
     572             : 
     573         587 :     if (!(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN) ||
     574         523 :         psExpr->nSubExprCount < 2)
     575          64 :         return nullptr;
     576             : 
     577         523 :     const swq_expr_node *poColumn = psExpr->papoSubExpr[0];
     578         523 :     const swq_expr_node *poValue = psExpr->papoSubExpr[1];
     579             : 
     580         523 :     if (poColumn->eNodeType != SNT_COLUMN || poValue->eNodeType != SNT_CONSTANT)
     581         156 :         return nullptr;
     582             : 
     583         367 :     const int nIdx = OGRFeatureFetcherFixFieldIndex(poLayer->GetLayerDefn(),
     584         367 :                                                     poColumn->field_index);
     585             : 
     586         367 :     OGRAttrIndex *poIndex = poLayer->GetIndex()->GetFieldIndex(nIdx);
     587         367 :     if (poIndex == nullptr)
     588         340 :         return nullptr;
     589             : 
     590             :     // Have an index, now we need to query it.
     591             :     OGRField sValue;
     592             :     const OGRFieldDefn *poFieldDefn =
     593          27 :         poLayer->GetLayerDefn()->GetFieldDefn(nIdx);
     594             : 
     595             :     // Handle the case of an IN operation.
     596          27 :     if (psExpr->nOperation == SWQ_IN)
     597             :     {
     598          11 :         int nLength = 0;
     599          11 :         GIntBig *panFIDs = nullptr;
     600          11 :         nFIDCount = 0;
     601             : 
     602          24 :         for (int iIN = 1; iIN < psExpr->nSubExprCount; iIN++)
     603             :         {
     604          13 :             switch (poFieldDefn->GetType())
     605             :             {
     606           8 :                 case OFTInteger:
     607           8 :                     if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
     608           3 :                         sValue.Integer = static_cast<int>(
     609           3 :                             psExpr->papoSubExpr[iIN]->float_value);
     610             :                     else
     611           5 :                         sValue.Integer = static_cast<int>(
     612           5 :                             psExpr->papoSubExpr[iIN]->int_value);
     613           8 :                     break;
     614             : 
     615           0 :                 case OFTInteger64:
     616           0 :                     if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
     617           0 :                         sValue.Integer64 = static_cast<GIntBig>(
     618           0 :                             psExpr->papoSubExpr[iIN]->float_value);
     619             :                     else
     620           0 :                         sValue.Integer64 = psExpr->papoSubExpr[iIN]->int_value;
     621           0 :                     break;
     622             : 
     623           5 :                 case OFTReal:
     624           5 :                     sValue.Real = psExpr->papoSubExpr[iIN]->float_value;
     625           5 :                     break;
     626             : 
     627           0 :                 case OFTString:
     628           0 :                     sValue.String = psExpr->papoSubExpr[iIN]->string_value;
     629           0 :                     break;
     630             : 
     631           0 :                 default:
     632           0 :                     CPLAssert(false);
     633             :                     return nullptr;
     634             :             }
     635             : 
     636          13 :             int nFIDCount32 = static_cast<int>(nFIDCount);
     637          26 :             panFIDs = poIndex->GetAllMatches(&sValue, panFIDs, &nFIDCount32,
     638          13 :                                              &nLength);
     639          13 :             nFIDCount = nFIDCount32;
     640             :         }
     641             : 
     642          11 :         if (nFIDCount > 1)
     643             :         {
     644             :             // The returned FIDs are expected to be in sorted order.
     645           1 :             std::sort(panFIDs, panFIDs + nFIDCount);
     646             :         }
     647          11 :         return panFIDs;
     648             :     }
     649             : 
     650             :     // Handle equality test.
     651          16 :     switch (poFieldDefn->GetType())
     652             :     {
     653           7 :         case OFTInteger:
     654           7 :             if (poValue->field_type == SWQ_FLOAT)
     655           1 :                 sValue.Integer = static_cast<int>(poValue->float_value);
     656             :             else
     657           6 :                 sValue.Integer = static_cast<int>(poValue->int_value);
     658           7 :             break;
     659             : 
     660           2 :         case OFTInteger64:
     661           2 :             if (poValue->field_type == SWQ_FLOAT)
     662           0 :                 sValue.Integer64 = static_cast<GIntBig>(poValue->float_value);
     663             :             else
     664           2 :                 sValue.Integer64 = poValue->int_value;
     665           2 :             break;
     666             : 
     667           2 :         case OFTReal:
     668           2 :             sValue.Real = poValue->float_value;
     669           2 :             break;
     670             : 
     671           5 :         case OFTString:
     672           5 :             sValue.String = poValue->string_value;
     673           5 :             break;
     674             : 
     675           0 :         default:
     676           0 :             CPLAssert(false);
     677             :             return nullptr;
     678             :     }
     679             : 
     680          16 :     int nLength = 0;
     681          16 :     int nFIDCount32 = 0;
     682             :     GIntBig *panFIDs =
     683          16 :         poIndex->GetAllMatches(&sValue, nullptr, &nFIDCount32, &nLength);
     684          16 :     nFIDCount = nFIDCount32;
     685          16 :     if (nFIDCount > 1)
     686             :     {
     687             :         // The returned FIDs are expected to be sorted.
     688           6 :         std::sort(panFIDs, panFIDs + nFIDCount);
     689             :     }
     690          16 :     return panFIDs;
     691             : }
     692             : 
     693             : /************************************************************************/
     694             : /*                         OGRFieldCollector()                          */
     695             : /*                                                                      */
     696             : /*      Helper function for recursing through tree to satisfy           */
     697             : /*      GetUsedFields().                                                */
     698             : /************************************************************************/
     699             : 
     700        1146 : char **OGRFeatureQuery::FieldCollector(void *pBareOp, char **papszList)
     701             : 
     702             : {
     703        1146 :     swq_expr_node *op = static_cast<swq_expr_node *>(pBareOp);
     704             : 
     705             :     // References to tables other than the primarily are currently unsupported.
     706             :     // Error out.
     707        1146 :     if (op->eNodeType == SNT_COLUMN)
     708             :     {
     709         282 :         if (op->table_index != 0)
     710             :         {
     711           0 :             CSLDestroy(papszList);
     712           0 :             return nullptr;
     713             :         }
     714             : 
     715             :         // Add the field name into our list if it is not already there.
     716         282 :         const char *pszFieldName = nullptr;
     717             :         const int nIdx =
     718         282 :             OGRFeatureFetcherFixFieldIndex(poTargetDefn, op->field_index);
     719             : 
     720         295 :         if (nIdx >= poTargetDefn->GetFieldCount() &&
     721          13 :             nIdx < poTargetDefn->GetFieldCount() + SPECIAL_FIELD_COUNT)
     722             :         {
     723          13 :             pszFieldName =
     724          13 :                 SpecialFieldNames[nIdx - poTargetDefn->GetFieldCount()];
     725             :         }
     726         269 :         else if (nIdx >= 0 && nIdx < poTargetDefn->GetFieldCount())
     727             :         {
     728         269 :             auto poFieldDefn = poTargetDefn->GetFieldDefn(nIdx);
     729         269 :             if (!poFieldDefn)
     730             :             {
     731           0 :                 CPLAssert(false);
     732             :                 CSLDestroy(papszList);
     733             :                 return nullptr;
     734             :             }
     735         269 :             pszFieldName = poFieldDefn->GetNameRef();
     736             :         }
     737             :         else
     738             :         {
     739           0 :             CSLDestroy(papszList);
     740           0 :             return nullptr;
     741             :         }
     742             : 
     743         282 :         if (CSLFindString(papszList, pszFieldName) == -1)
     744         277 :             papszList = CSLAddString(papszList, pszFieldName);
     745             :     }
     746             : 
     747             :     // Add in fields from subexpressions.
     748        1146 :     if (op->eNodeType == SNT_OPERATION)
     749             :     {
     750        1166 :         for (int iSubExpr = 0; iSubExpr < op->nSubExprCount; iSubExpr++)
     751             :         {
     752         776 :             papszList = FieldCollector(op->papoSubExpr[iSubExpr], papszList);
     753             :         }
     754             :     }
     755             : 
     756        1146 :     return papszList;
     757             : }
     758             : 
     759             : /************************************************************************/
     760             : /*                           GetUsedFields()                            */
     761             : /************************************************************************/
     762             : 
     763             : /**
     764             :  * Returns lists of fields in expression.
     765             :  *
     766             :  * All attribute fields are used in the expression of this feature
     767             :  * query are returned as a StringList of field names.  This function would
     768             :  * primarily be used within drivers to recognise special case conditions
     769             :  * depending only on attribute fields that can be very efficiently
     770             :  * fetched.
     771             :  *
     772             :  * NOTE: If any fields in the expression are from tables other than the
     773             :  * primary table then NULL is returned indicating an error.  In successful
     774             :  * use, no non-empty expression should return an empty list.
     775             :  *
     776             :  * @return list of field names.  Free list with CSLDestroy() when no longer
     777             :  * required.
     778             :  */
     779             : 
     780         370 : char **OGRFeatureQuery::GetUsedFields()
     781             : 
     782             : {
     783         370 :     if (pSWQExpr == nullptr)
     784           0 :         return nullptr;
     785             : 
     786         370 :     return FieldCollector(pSWQExpr, nullptr);
     787             : }
     788             : 
     789             : //! @endcond

Generated by: LCOV version 1.14