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