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