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

Generated by: LCOV version 1.14