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