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