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