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

Generated by: LCOV version 1.14