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