/src/gdal/ogr/ogrfeaturequery.cpp
Line | Count | Source |
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(const 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(const OGRFeatureDefn *poDefn, |
85 | | const char *pszExpression, 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(const OGRLayer *poLayer, const 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 = const_cast<OGRLayer *>(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 | const 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 | const 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 | const_cast<OGRLayer *>(poLayer)->GetMetadataItem(OLMD_FID64) != |
212 | 0 | nullptr && |
213 | 0 | EQUAL(const_cast<OGRLayer *>(poLayer)->GetMetadataItem(OLMD_FID64), |
214 | 0 | "YES")) |
215 | 0 | ? SWQ_INTEGER64 |
216 | 0 | : SWQ_INTEGER; |
217 | 0 | } |
218 | | |
219 | | // Try to parse. |
220 | 0 | poTargetDefn = poDefn; |
221 | 0 | const CPLErr eCPLErr = swq_expr_compile( |
222 | 0 | pszExpression, nFieldCount, papszFieldNames, paeFieldTypes, bCheck, |
223 | 0 | poCustomFuncRegistrar, reinterpret_cast<swq_expr_node **>(&pSWQExpr)); |
224 | |
|
225 | 0 | OGRErr eErr = OGRERR_NONE; |
226 | 0 | if (eCPLErr != CE_None) |
227 | 0 | { |
228 | 0 | eErr = OGRERR_CORRUPT_DATA; |
229 | 0 | pSWQExpr = nullptr; |
230 | 0 | } |
231 | |
|
232 | 0 | CPLFree(papszFieldNames); |
233 | 0 | CPLFree(paeFieldTypes); |
234 | |
|
235 | 0 | return eErr; |
236 | 0 | } |
237 | | |
238 | | /************************************************************************/ |
239 | | /* OGRFeatureFetcherFixFieldIndex() */ |
240 | | /************************************************************************/ |
241 | | |
242 | | static int OGRFeatureFetcherFixFieldIndex(const OGRFeatureDefn *poFDefn, |
243 | | int nIdx) |
244 | 0 | { |
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 | 0 | if (nIdx == poFDefn->GetFieldCount() + SPECIAL_FIELD_COUNT + |
248 | 0 | poFDefn->GetGeomFieldCount()) |
249 | 0 | { |
250 | 0 | return poFDefn->GetFieldCount() + SPF_FID; |
251 | 0 | } |
252 | 0 | return nIdx; |
253 | 0 | } |
254 | | |
255 | | /************************************************************************/ |
256 | | /* OGRFeatureFetcher() */ |
257 | | /************************************************************************/ |
258 | | |
259 | | static swq_expr_node *OGRFeatureFetcher(swq_expr_node *op, void *pFeatureIn) |
260 | | |
261 | 0 | { |
262 | 0 | OGRFeature *poFeature = static_cast<OGRFeature *>(pFeatureIn); |
263 | |
|
264 | 0 | if (op->field_type == SWQ_GEOMETRY) |
265 | 0 | { |
266 | 0 | const int iField = op->field_index - |
267 | 0 | (poFeature->GetFieldCount() + SPECIAL_FIELD_COUNT); |
268 | 0 | swq_expr_node *poRetNode = |
269 | 0 | new swq_expr_node(poFeature->GetGeomFieldRef(iField)); |
270 | 0 | return poRetNode; |
271 | 0 | } |
272 | | |
273 | 0 | const int idx = OGRFeatureFetcherFixFieldIndex(poFeature->GetDefnRef(), |
274 | 0 | op->field_index); |
275 | |
|
276 | 0 | swq_expr_node *poRetNode = nullptr; |
277 | 0 | switch (op->field_type) |
278 | 0 | { |
279 | 0 | case SWQ_INTEGER: |
280 | 0 | case SWQ_BOOLEAN: |
281 | 0 | poRetNode = new swq_expr_node(poFeature->GetFieldAsInteger(idx)); |
282 | 0 | break; |
283 | | |
284 | 0 | case SWQ_INTEGER64: |
285 | 0 | poRetNode = new swq_expr_node(poFeature->GetFieldAsInteger64(idx)); |
286 | 0 | break; |
287 | | |
288 | 0 | case SWQ_FLOAT: |
289 | 0 | poRetNode = new swq_expr_node(poFeature->GetFieldAsDouble(idx)); |
290 | 0 | break; |
291 | | |
292 | 0 | case SWQ_TIMESTAMP: |
293 | 0 | poRetNode = new swq_expr_node(poFeature->GetFieldAsString(idx)); |
294 | 0 | poRetNode->MarkAsTimestamp(); |
295 | 0 | break; |
296 | | |
297 | 0 | default: |
298 | 0 | poRetNode = new swq_expr_node(poFeature->GetFieldAsString(idx)); |
299 | 0 | break; |
300 | 0 | } |
301 | | |
302 | 0 | poRetNode->is_null = !(poFeature->IsFieldSetAndNotNull(idx)); |
303 | |
|
304 | 0 | return poRetNode; |
305 | 0 | } |
306 | | |
307 | | /************************************************************************/ |
308 | | /* Evaluate() */ |
309 | | /************************************************************************/ |
310 | | |
311 | | int OGRFeatureQuery::Evaluate(OGRFeature *poFeature) |
312 | | |
313 | 0 | { |
314 | 0 | if (pSWQExpr == nullptr) |
315 | 0 | return FALSE; |
316 | | |
317 | 0 | swq_expr_node *poResult = static_cast<swq_expr_node *>(pSWQExpr)->Evaluate( |
318 | 0 | OGRFeatureFetcher, poFeature, *m_psContext); |
319 | |
|
320 | 0 | if (poResult == nullptr) |
321 | 0 | return FALSE; |
322 | | |
323 | 0 | bool bLogicalResult = false; |
324 | 0 | if (poResult->field_type == SWQ_INTEGER || |
325 | 0 | poResult->field_type == SWQ_INTEGER64 || |
326 | 0 | poResult->field_type == SWQ_BOOLEAN) |
327 | 0 | bLogicalResult = CPL_TO_BOOL(static_cast<int>(poResult->int_value)); |
328 | |
|
329 | 0 | delete poResult; |
330 | |
|
331 | 0 | return bLogicalResult; |
332 | 0 | } |
333 | | |
334 | | /************************************************************************/ |
335 | | /* CanUseIndex() */ |
336 | | /************************************************************************/ |
337 | | |
338 | | int OGRFeatureQuery::CanUseIndex(OGRLayer *poLayer) |
339 | 0 | { |
340 | 0 | swq_expr_node *psExpr = static_cast<swq_expr_node *>(pSWQExpr); |
341 | | |
342 | | // Do we have an index on the targeted layer? |
343 | 0 | if (poLayer->GetIndex() == nullptr) |
344 | 0 | return FALSE; |
345 | | |
346 | 0 | return CanUseIndex(psExpr, poLayer); |
347 | 0 | } |
348 | | |
349 | | int OGRFeatureQuery::CanUseIndex(const swq_expr_node *psExpr, OGRLayer *poLayer) |
350 | 0 | { |
351 | | // Does the expression meet our requirements? |
352 | 0 | if (psExpr == nullptr || psExpr->eNodeType != SNT_OPERATION) |
353 | 0 | return FALSE; |
354 | | |
355 | 0 | if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) && |
356 | 0 | psExpr->nSubExprCount == 2) |
357 | 0 | { |
358 | 0 | return CanUseIndex(psExpr->papoSubExpr[0], poLayer) && |
359 | 0 | CanUseIndex(psExpr->papoSubExpr[1], poLayer); |
360 | 0 | } |
361 | | |
362 | 0 | if (!(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN) || |
363 | 0 | psExpr->nSubExprCount < 2) |
364 | 0 | return FALSE; |
365 | | |
366 | 0 | swq_expr_node *poColumn = psExpr->papoSubExpr[0]; |
367 | 0 | swq_expr_node *poValue = psExpr->papoSubExpr[1]; |
368 | |
|
369 | 0 | if (poColumn->eNodeType != SNT_COLUMN || poValue->eNodeType != SNT_CONSTANT) |
370 | 0 | return FALSE; |
371 | | |
372 | 0 | OGRAttrIndex *poIndex = |
373 | 0 | poLayer->GetIndex()->GetFieldIndex(OGRFeatureFetcherFixFieldIndex( |
374 | 0 | poLayer->GetLayerDefn(), poColumn->field_index)); |
375 | 0 | if (poIndex == nullptr) |
376 | 0 | return FALSE; |
377 | | |
378 | | // Have an index. |
379 | 0 | return TRUE; |
380 | 0 | } |
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 | | GIntBig *OGRFeatureQuery::EvaluateAgainstIndices(OGRLayer *poLayer, |
397 | | OGRErr *peErr) |
398 | | |
399 | 0 | { |
400 | 0 | swq_expr_node *psExpr = static_cast<swq_expr_node *>(pSWQExpr); |
401 | |
|
402 | 0 | if (peErr != nullptr) |
403 | 0 | *peErr = OGRERR_NONE; |
404 | | |
405 | | // Do we have an index on the targeted layer? |
406 | 0 | if (poLayer->GetIndex() == nullptr) |
407 | 0 | return nullptr; |
408 | | |
409 | 0 | GIntBig nFIDCount = 0; |
410 | 0 | return EvaluateAgainstIndices(psExpr, poLayer, nFIDCount); |
411 | 0 | } |
412 | | |
413 | | // The input arrays must be sorted. |
414 | | static GIntBig *OGRORGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1, |
415 | | GIntBig panFIDList2[], GIntBig nFIDCount2, |
416 | | GIntBig &nFIDCount) |
417 | 0 | { |
418 | 0 | const GIntBig nMaxCount = nFIDCount1 + nFIDCount2; |
419 | 0 | GIntBig *panFIDList = static_cast<GIntBig *>( |
420 | 0 | CPLMalloc(static_cast<size_t>(nMaxCount + 1) * sizeof(GIntBig))); |
421 | 0 | nFIDCount = 0; |
422 | |
|
423 | 0 | for (GIntBig i1 = 0, i2 = 0; i1 < nFIDCount1 || i2 < nFIDCount2;) |
424 | 0 | { |
425 | 0 | if (i1 < nFIDCount1 && i2 < nFIDCount2) |
426 | 0 | { |
427 | 0 | const GIntBig nVal1 = panFIDList1[i1]; |
428 | 0 | const GIntBig nVal2 = panFIDList2[i2]; |
429 | 0 | if (nVal1 < nVal2) |
430 | 0 | { |
431 | 0 | if (i1 + 1 < nFIDCount1 && panFIDList1[i1 + 1] <= nVal2) |
432 | 0 | { |
433 | 0 | panFIDList[nFIDCount++] = nVal1; |
434 | 0 | i1++; |
435 | 0 | } |
436 | 0 | else |
437 | 0 | { |
438 | 0 | panFIDList[nFIDCount++] = nVal1; |
439 | 0 | panFIDList[nFIDCount++] = nVal2; |
440 | 0 | i1++; |
441 | 0 | i2++; |
442 | 0 | } |
443 | 0 | } |
444 | 0 | else if (nVal1 == nVal2) |
445 | 0 | { |
446 | 0 | panFIDList[nFIDCount++] = nVal1; |
447 | 0 | i1++; |
448 | 0 | i2++; |
449 | 0 | } |
450 | 0 | else |
451 | 0 | { |
452 | 0 | if (i2 + 1 < nFIDCount2 && panFIDList2[i2 + 1] <= nVal1) |
453 | 0 | { |
454 | 0 | panFIDList[nFIDCount++] = nVal2; |
455 | 0 | i2++; |
456 | 0 | } |
457 | 0 | else |
458 | 0 | { |
459 | 0 | panFIDList[nFIDCount++] = nVal2; |
460 | 0 | panFIDList[nFIDCount++] = nVal1; |
461 | 0 | i1++; |
462 | 0 | i2++; |
463 | 0 | } |
464 | 0 | } |
465 | 0 | } |
466 | 0 | else if (i1 < nFIDCount1) |
467 | 0 | { |
468 | 0 | const GIntBig nVal1 = panFIDList1[i1]; |
469 | 0 | panFIDList[nFIDCount++] = nVal1; |
470 | 0 | i1++; |
471 | 0 | } |
472 | 0 | else if (i2 < nFIDCount2) |
473 | 0 | { |
474 | 0 | const GIntBig nVal2 = panFIDList2[i2]; |
475 | 0 | panFIDList[nFIDCount++] = nVal2; |
476 | 0 | i2++; |
477 | 0 | } |
478 | 0 | } |
479 | |
|
480 | 0 | panFIDList[nFIDCount] = OGRNullFID; |
481 | |
|
482 | 0 | return panFIDList; |
483 | 0 | } |
484 | | |
485 | | // The input arrays must be sorted. |
486 | | static GIntBig *OGRANDGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1, |
487 | | GIntBig panFIDList2[], GIntBig nFIDCount2, |
488 | | GIntBig &nFIDCount) |
489 | 0 | { |
490 | 0 | GIntBig nMaxCount = std::max(nFIDCount1, nFIDCount2); |
491 | 0 | GIntBig *panFIDList = static_cast<GIntBig *>( |
492 | 0 | CPLMalloc(static_cast<size_t>(nMaxCount + 1) * sizeof(GIntBig))); |
493 | 0 | nFIDCount = 0; |
494 | |
|
495 | 0 | for (GIntBig i1 = 0, i2 = 0; i1 < nFIDCount1 && i2 < nFIDCount2;) |
496 | 0 | { |
497 | 0 | const GIntBig nVal1 = panFIDList1[i1]; |
498 | 0 | const GIntBig nVal2 = panFIDList2[i2]; |
499 | 0 | if (nVal1 < nVal2) |
500 | 0 | { |
501 | 0 | if (i1 + 1 < nFIDCount1 && panFIDList1[i1 + 1] <= nVal2) |
502 | 0 | { |
503 | 0 | i1++; |
504 | 0 | } |
505 | 0 | else |
506 | 0 | { |
507 | 0 | i1++; |
508 | 0 | i2++; |
509 | 0 | } |
510 | 0 | } |
511 | 0 | else if (nVal1 == nVal2) |
512 | 0 | { |
513 | 0 | panFIDList[nFIDCount++] = nVal1; |
514 | 0 | i1++; |
515 | 0 | i2++; |
516 | 0 | } |
517 | 0 | else |
518 | 0 | { |
519 | 0 | if (i2 + 1 < nFIDCount2 && panFIDList2[i2 + 1] <= nVal1) |
520 | 0 | { |
521 | 0 | i2++; |
522 | 0 | } |
523 | 0 | else |
524 | 0 | { |
525 | 0 | i1++; |
526 | 0 | i2++; |
527 | 0 | } |
528 | 0 | } |
529 | 0 | } |
530 | |
|
531 | 0 | panFIDList[nFIDCount] = OGRNullFID; |
532 | |
|
533 | 0 | return panFIDList; |
534 | 0 | } |
535 | | |
536 | | GIntBig *OGRFeatureQuery::EvaluateAgainstIndices(const swq_expr_node *psExpr, |
537 | | OGRLayer *poLayer, |
538 | | GIntBig &nFIDCount) |
539 | 0 | { |
540 | | // Does the expression meet our requirements? |
541 | 0 | if (psExpr == nullptr || psExpr->eNodeType != SNT_OPERATION) |
542 | 0 | return nullptr; |
543 | | |
544 | 0 | if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) && |
545 | 0 | psExpr->nSubExprCount == 2) |
546 | 0 | { |
547 | 0 | GIntBig nFIDCount1 = 0; |
548 | 0 | GIntBig nFIDCount2 = 0; |
549 | 0 | GIntBig *panFIDList1 = |
550 | 0 | EvaluateAgainstIndices(psExpr->papoSubExpr[0], poLayer, nFIDCount1); |
551 | 0 | GIntBig *panFIDList2 = |
552 | 0 | panFIDList1 == nullptr |
553 | 0 | ? nullptr |
554 | 0 | : EvaluateAgainstIndices(psExpr->papoSubExpr[1], poLayer, |
555 | 0 | nFIDCount2); |
556 | 0 | GIntBig *panFIDList = nullptr; |
557 | 0 | if (panFIDList1 != nullptr && panFIDList2 != nullptr) |
558 | 0 | { |
559 | 0 | if (psExpr->nOperation == SWQ_OR) |
560 | 0 | panFIDList = |
561 | 0 | OGRORGIntBigArray(panFIDList1, nFIDCount1, panFIDList2, |
562 | 0 | nFIDCount2, nFIDCount); |
563 | 0 | else if (psExpr->nOperation == SWQ_AND) |
564 | 0 | panFIDList = |
565 | 0 | OGRANDGIntBigArray(panFIDList1, nFIDCount1, panFIDList2, |
566 | 0 | nFIDCount2, nFIDCount); |
567 | 0 | } |
568 | 0 | CPLFree(panFIDList1); |
569 | 0 | CPLFree(panFIDList2); |
570 | 0 | return panFIDList; |
571 | 0 | } |
572 | | |
573 | 0 | if (!(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN) || |
574 | 0 | psExpr->nSubExprCount < 2) |
575 | 0 | return nullptr; |
576 | | |
577 | 0 | const swq_expr_node *poColumn = psExpr->papoSubExpr[0]; |
578 | 0 | const swq_expr_node *poValue = psExpr->papoSubExpr[1]; |
579 | |
|
580 | 0 | if (poColumn->eNodeType != SNT_COLUMN || poValue->eNodeType != SNT_CONSTANT) |
581 | 0 | return nullptr; |
582 | | |
583 | 0 | const int nIdx = OGRFeatureFetcherFixFieldIndex(poLayer->GetLayerDefn(), |
584 | 0 | poColumn->field_index); |
585 | |
|
586 | 0 | OGRAttrIndex *poIndex = poLayer->GetIndex()->GetFieldIndex(nIdx); |
587 | 0 | if (poIndex == nullptr) |
588 | 0 | return nullptr; |
589 | | |
590 | | // Have an index, now we need to query it. |
591 | 0 | OGRField sValue; |
592 | 0 | const OGRFieldDefn *poFieldDefn = |
593 | 0 | poLayer->GetLayerDefn()->GetFieldDefn(nIdx); |
594 | | |
595 | | // Handle the case of an IN operation. |
596 | 0 | if (psExpr->nOperation == SWQ_IN) |
597 | 0 | { |
598 | 0 | int nLength = 0; |
599 | 0 | GIntBig *panFIDs = nullptr; |
600 | 0 | nFIDCount = 0; |
601 | |
|
602 | 0 | for (int iIN = 1; iIN < psExpr->nSubExprCount; iIN++) |
603 | 0 | { |
604 | 0 | switch (poFieldDefn->GetType()) |
605 | 0 | { |
606 | 0 | case OFTInteger: |
607 | 0 | if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT) |
608 | 0 | sValue.Integer = static_cast<int>( |
609 | 0 | psExpr->papoSubExpr[iIN]->float_value); |
610 | 0 | else |
611 | 0 | sValue.Integer = static_cast<int>( |
612 | 0 | psExpr->papoSubExpr[iIN]->int_value); |
613 | 0 | 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 | 0 | else |
620 | 0 | sValue.Integer64 = psExpr->papoSubExpr[iIN]->int_value; |
621 | 0 | break; |
622 | | |
623 | 0 | case OFTReal: |
624 | 0 | sValue.Real = psExpr->papoSubExpr[iIN]->float_value; |
625 | 0 | 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 | 0 | return nullptr; |
634 | 0 | } |
635 | | |
636 | 0 | int nFIDCount32 = static_cast<int>(nFIDCount); |
637 | 0 | panFIDs = poIndex->GetAllMatches(&sValue, panFIDs, &nFIDCount32, |
638 | 0 | &nLength); |
639 | 0 | nFIDCount = nFIDCount32; |
640 | 0 | } |
641 | | |
642 | 0 | if (nFIDCount > 1) |
643 | 0 | { |
644 | | // The returned FIDs are expected to be in sorted order. |
645 | 0 | std::sort(panFIDs, panFIDs + nFIDCount); |
646 | 0 | } |
647 | 0 | return panFIDs; |
648 | 0 | } |
649 | | |
650 | | // Handle equality test. |
651 | 0 | switch (poFieldDefn->GetType()) |
652 | 0 | { |
653 | 0 | case OFTInteger: |
654 | 0 | if (poValue->field_type == SWQ_FLOAT) |
655 | 0 | sValue.Integer = static_cast<int>(poValue->float_value); |
656 | 0 | else |
657 | 0 | sValue.Integer = static_cast<int>(poValue->int_value); |
658 | 0 | break; |
659 | | |
660 | 0 | case OFTInteger64: |
661 | 0 | if (poValue->field_type == SWQ_FLOAT) |
662 | 0 | sValue.Integer64 = static_cast<GIntBig>(poValue->float_value); |
663 | 0 | else |
664 | 0 | sValue.Integer64 = poValue->int_value; |
665 | 0 | break; |
666 | | |
667 | 0 | case OFTReal: |
668 | 0 | sValue.Real = poValue->float_value; |
669 | 0 | break; |
670 | | |
671 | 0 | case OFTString: |
672 | 0 | sValue.String = poValue->string_value; |
673 | 0 | break; |
674 | | |
675 | 0 | default: |
676 | 0 | CPLAssert(false); |
677 | 0 | return nullptr; |
678 | 0 | } |
679 | | |
680 | 0 | int nLength = 0; |
681 | 0 | int nFIDCount32 = 0; |
682 | 0 | GIntBig *panFIDs = |
683 | 0 | poIndex->GetAllMatches(&sValue, nullptr, &nFIDCount32, &nLength); |
684 | 0 | nFIDCount = nFIDCount32; |
685 | 0 | if (nFIDCount > 1) |
686 | 0 | { |
687 | | // The returned FIDs are expected to be sorted. |
688 | 0 | std::sort(panFIDs, panFIDs + nFIDCount); |
689 | 0 | } |
690 | 0 | return panFIDs; |
691 | 0 | } |
692 | | |
693 | | /************************************************************************/ |
694 | | /* OGRFieldCollector() */ |
695 | | /* */ |
696 | | /* Helper function for recursing through tree to satisfy */ |
697 | | /* GetUsedFields(). */ |
698 | | /************************************************************************/ |
699 | | |
700 | | char **OGRFeatureQuery::FieldCollector(void *pBareOp, char **papszList) |
701 | | |
702 | 0 | { |
703 | 0 | 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 | 0 | if (op->eNodeType == SNT_COLUMN) |
708 | 0 | { |
709 | 0 | if (op->table_index != 0) |
710 | 0 | { |
711 | 0 | CSLDestroy(papszList); |
712 | 0 | return nullptr; |
713 | 0 | } |
714 | | |
715 | | // Add the field name into our list if it is not already there. |
716 | 0 | const char *pszFieldName = nullptr; |
717 | 0 | const int nIdx = |
718 | 0 | OGRFeatureFetcherFixFieldIndex(poTargetDefn, op->field_index); |
719 | |
|
720 | 0 | if (nIdx >= poTargetDefn->GetFieldCount() && |
721 | 0 | nIdx < poTargetDefn->GetFieldCount() + SPECIAL_FIELD_COUNT) |
722 | 0 | { |
723 | 0 | pszFieldName = |
724 | 0 | SpecialFieldNames[nIdx - poTargetDefn->GetFieldCount()]; |
725 | 0 | } |
726 | 0 | else if (nIdx >= 0 && nIdx < poTargetDefn->GetFieldCount()) |
727 | 0 | { |
728 | 0 | auto poFieldDefn = poTargetDefn->GetFieldDefn(nIdx); |
729 | 0 | if (!poFieldDefn) |
730 | 0 | { |
731 | 0 | CPLAssert(false); |
732 | 0 | CSLDestroy(papszList); |
733 | 0 | return nullptr; |
734 | 0 | } |
735 | 0 | pszFieldName = poFieldDefn->GetNameRef(); |
736 | 0 | } |
737 | 0 | else |
738 | 0 | { |
739 | 0 | CSLDestroy(papszList); |
740 | 0 | return nullptr; |
741 | 0 | } |
742 | | |
743 | 0 | if (CSLFindString(papszList, pszFieldName) == -1) |
744 | 0 | papszList = CSLAddString(papszList, pszFieldName); |
745 | 0 | } |
746 | | |
747 | | // Add in fields from subexpressions. |
748 | 0 | if (op->eNodeType == SNT_OPERATION) |
749 | 0 | { |
750 | 0 | for (int iSubExpr = 0; iSubExpr < op->nSubExprCount; iSubExpr++) |
751 | 0 | { |
752 | 0 | papszList = FieldCollector(op->papoSubExpr[iSubExpr], papszList); |
753 | 0 | } |
754 | 0 | } |
755 | |
|
756 | 0 | return papszList; |
757 | 0 | } |
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 | | char **OGRFeatureQuery::GetUsedFields() |
781 | | |
782 | 0 | { |
783 | 0 | if (pSWQExpr == nullptr) |
784 | 0 | return nullptr; |
785 | | |
786 | 0 | return FieldCollector(pSWQExpr, nullptr); |
787 | 0 | } |
788 | | |
789 | | //! @endcond |