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