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

Generated by: LCOV version 1.14