1 : /******************************************************************************
2 : * $Id: ogrfeaturequery.cpp 24849 2012-08-25 12:22:05Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implementation of simple SQL WHERE style attributes queries
6 : * for OGRFeatures.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.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 <assert.h>
32 : #include "swq.h"
33 : #include "ogr_feature.h"
34 : #include "ogr_p.h"
35 : #include "ogr_attrind.h"
36 :
37 : CPL_CVSID("$Id: ogrfeaturequery.cpp 24849 2012-08-25 12:22:05Z rouault $");
38 :
39 : /************************************************************************/
40 : /* Support for special attributes (feature query and selection) */
41 : /************************************************************************/
42 :
43 : const char* SpecialFieldNames[SPECIAL_FIELD_COUNT]
44 : = {"FID", "OGR_GEOMETRY", "OGR_STYLE", "OGR_GEOM_WKT", "OGR_GEOM_AREA"};
45 : const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT]
46 : = {SWQ_INTEGER, SWQ_STRING, SWQ_STRING, SWQ_STRING, SWQ_FLOAT};
47 :
48 : /************************************************************************/
49 : /* OGRFeatureQuery() */
50 : /************************************************************************/
51 :
52 446 : OGRFeatureQuery::OGRFeatureQuery()
53 :
54 : {
55 446 : poTargetDefn = NULL;
56 446 : pSWQExpr = NULL;
57 446 : }
58 :
59 : /************************************************************************/
60 : /* ~OGRFeatureQuery() */
61 : /************************************************************************/
62 :
63 446 : OGRFeatureQuery::~OGRFeatureQuery()
64 :
65 : {
66 446 : delete (swq_expr_node *) pSWQExpr;
67 446 : }
68 :
69 : /************************************************************************/
70 : /* Parse */
71 : /************************************************************************/
72 :
73 849 : OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn,
74 : const char * pszExpression )
75 :
76 : {
77 : /* -------------------------------------------------------------------- */
78 : /* Clear any existing expression. */
79 : /* -------------------------------------------------------------------- */
80 849 : if( pSWQExpr != NULL )
81 : {
82 403 : delete (swq_expr_node *) pSWQExpr;
83 403 : pSWQExpr = NULL;
84 : }
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* Build list of fields. */
88 : /* -------------------------------------------------------------------- */
89 : char **papszFieldNames;
90 : swq_field_type *paeFieldTypes;
91 : int iField;
92 849 : int nFieldCount = poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT;
93 :
94 : papszFieldNames = (char **)
95 849 : CPLMalloc(sizeof(char *) * nFieldCount );
96 : paeFieldTypes = (swq_field_type *)
97 849 : CPLMalloc(sizeof(swq_field_type) * nFieldCount );
98 :
99 5751 : for( iField = 0; iField < poDefn->GetFieldCount(); iField++ )
100 : {
101 4902 : OGRFieldDefn *poField = poDefn->GetFieldDefn( iField );
102 :
103 4902 : papszFieldNames[iField] = (char *) poField->GetNameRef();
104 :
105 4902 : switch( poField->GetType() )
106 : {
107 : case OFTInteger:
108 1290 : paeFieldTypes[iField] = SWQ_INTEGER;
109 1290 : break;
110 :
111 : case OFTReal:
112 885 : paeFieldTypes[iField] = SWQ_FLOAT;
113 885 : break;
114 :
115 : case OFTString:
116 1967 : paeFieldTypes[iField] = SWQ_STRING;
117 1967 : break;
118 :
119 : case OFTDate:
120 : case OFTTime:
121 : case OFTDateTime:
122 597 : paeFieldTypes[iField] = SWQ_TIMESTAMP;
123 597 : break;
124 :
125 : default:
126 163 : paeFieldTypes[iField] = SWQ_OTHER;
127 : break;
128 : }
129 : }
130 :
131 849 : iField = 0;
132 5943 : while (iField < SPECIAL_FIELD_COUNT)
133 : {
134 4245 : papszFieldNames[poDefn->GetFieldCount() + iField] = (char *) SpecialFieldNames[iField];
135 4245 : paeFieldTypes[poDefn->GetFieldCount() + iField] = SpecialFieldTypes[iField];
136 4245 : ++iField;
137 : }
138 :
139 : /* -------------------------------------------------------------------- */
140 : /* Try to parse. */
141 : /* -------------------------------------------------------------------- */
142 849 : OGRErr eErr = OGRERR_NONE;
143 : CPLErr eCPLErr;
144 :
145 849 : poTargetDefn = poDefn;
146 : eCPLErr = swq_expr_compile( pszExpression, nFieldCount,
147 : papszFieldNames, paeFieldTypes,
148 849 : (swq_expr_node **) &pSWQExpr );
149 849 : if( eCPLErr != CE_None )
150 : {
151 0 : eErr = OGRERR_CORRUPT_DATA;
152 0 : pSWQExpr = NULL;
153 : }
154 :
155 849 : CPLFree( papszFieldNames );
156 849 : CPLFree( paeFieldTypes );
157 :
158 :
159 849 : return eErr;
160 : }
161 :
162 : /************************************************************************/
163 : /* OGRFeatureFetcher() */
164 : /************************************************************************/
165 :
166 458549 : static swq_expr_node *OGRFeatureFetcher( swq_expr_node *op, void *pFeatureIn )
167 :
168 : {
169 458549 : OGRFeature *poFeature = (OGRFeature *) pFeatureIn;
170 458549 : swq_expr_node *poRetNode = NULL;
171 :
172 458549 : switch( op->field_type )
173 : {
174 : case SWQ_INTEGER:
175 : case SWQ_BOOLEAN:
176 : poRetNode = new swq_expr_node(
177 80189 : poFeature->GetFieldAsInteger(op->field_index) );
178 80189 : break;
179 :
180 : case SWQ_FLOAT:
181 : poRetNode = new swq_expr_node(
182 2735 : poFeature->GetFieldAsDouble(op->field_index) );
183 2735 : break;
184 :
185 : default:
186 : poRetNode = new swq_expr_node(
187 375625 : poFeature->GetFieldAsString(op->field_index) );
188 : break;
189 : }
190 :
191 458549 : poRetNode->is_null = !(poFeature->IsFieldSet(op->field_index));
192 :
193 458549 : return poRetNode;
194 : }
195 :
196 : /************************************************************************/
197 : /* Evaluate() */
198 : /************************************************************************/
199 :
200 594175 : int OGRFeatureQuery::Evaluate( OGRFeature *poFeature )
201 :
202 : {
203 594175 : if( pSWQExpr == NULL )
204 0 : return FALSE;
205 :
206 : swq_expr_node *poResult;
207 :
208 : poResult = ((swq_expr_node *) pSWQExpr)->Evaluate( OGRFeatureFetcher,
209 594175 : (void *) poFeature );
210 :
211 594175 : if( poResult == NULL )
212 0 : return FALSE;
213 :
214 594175 : CPLAssert( poResult->field_type == SWQ_BOOLEAN );
215 :
216 594175 : int bLogicalResult = poResult->int_value;
217 :
218 594175 : delete poResult;
219 :
220 594175 : return bLogicalResult;
221 : }
222 :
223 : /************************************************************************/
224 : /* CanUseIndex() */
225 : /************************************************************************/
226 :
227 67 : int OGRFeatureQuery::CanUseIndex( OGRLayer *poLayer )
228 : {
229 67 : swq_expr_node *psExpr = (swq_expr_node *) pSWQExpr;
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* Do we have an index on the targetted layer? */
233 : /* -------------------------------------------------------------------- */
234 67 : if ( poLayer->GetIndex() == FALSE )
235 0 : return FALSE;
236 :
237 67 : return CanUseIndex( psExpr, poLayer );
238 : }
239 :
240 67 : int OGRFeatureQuery::CanUseIndex( swq_expr_node *psExpr,
241 : OGRLayer *poLayer )
242 : {
243 : OGRAttrIndex *poIndex;
244 :
245 : /* -------------------------------------------------------------------- */
246 : /* Does the expression meet our requirements? */
247 : /* -------------------------------------------------------------------- */
248 67 : if( psExpr == NULL ||
249 : psExpr->eNodeType != SNT_OPERATION )
250 0 : return FALSE;
251 :
252 67 : if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
253 : psExpr->nSubExprCount == 2)
254 : {
255 : return CanUseIndex( psExpr->papoSubExpr[0], poLayer ) &&
256 0 : CanUseIndex( psExpr->papoSubExpr[1], poLayer );
257 : }
258 :
259 67 : if( !(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN)
260 : || psExpr->nSubExprCount < 2 )
261 1 : return FALSE;
262 :
263 66 : swq_expr_node *poColumn = psExpr->papoSubExpr[0];
264 66 : swq_expr_node *poValue = psExpr->papoSubExpr[1];
265 :
266 66 : if( poColumn->eNodeType != SNT_COLUMN
267 : || poValue->eNodeType != SNT_CONSTANT )
268 0 : return FALSE;
269 :
270 66 : poIndex = poLayer->GetIndex()->GetFieldIndex( poColumn->field_index );
271 66 : if( poIndex == NULL )
272 66 : return FALSE;
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* OK, we have an index */
276 : /* -------------------------------------------------------------------- */
277 0 : return TRUE;
278 : }
279 :
280 : /************************************************************************/
281 : /* EvaluateAgainstIndices() */
282 : /* */
283 : /* Attempt to return a list of FIDs matching the given */
284 : /* attribute query conditions utilizing attribute indices. */
285 : /* Returns NULL if the result cannot be computed from the */
286 : /* available indices, or an "OGRNullFID" terminated list of */
287 : /* FIDs if it can. */
288 : /* */
289 : /* For now we only support equality tests on a single indexed */
290 : /* attribute field. Eventually we should make this support */
291 : /* multi-part queries with ranges. */
292 : /************************************************************************/
293 :
294 10 : static int CompareLong(const void *a, const void *b)
295 : {
296 10 : return (*(const long *)a) - (*(const long *)b);
297 : }
298 :
299 432 : long *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer,
300 : OGRErr *peErr )
301 :
302 : {
303 432 : swq_expr_node *psExpr = (swq_expr_node *) pSWQExpr;
304 :
305 432 : if( peErr != NULL )
306 0 : *peErr = OGRERR_NONE;
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Do we have an index on the targetted layer? */
310 : /* -------------------------------------------------------------------- */
311 432 : if ( poLayer->GetIndex() == NULL )
312 32 : return NULL;
313 :
314 400 : int nFIDCount = 0;
315 400 : return EvaluateAgainstIndices(psExpr, poLayer, nFIDCount);
316 : }
317 :
318 : /* The input arrays must be sorted ! */
319 : static
320 1 : long* OGRORLongArray(long panFIDList1[], int nFIDCount1,
321 : long panFIDList2[], int nFIDCount2, int& nFIDCount)
322 : {
323 1 : int nMaxCount = nFIDCount1 + nFIDCount2;
324 1 : long* panFIDList = (long*) CPLMalloc((nMaxCount+1) * sizeof(long));
325 1 : nFIDCount = 0;
326 :
327 1 : int i1 = 0, i2 =0;
328 6 : for(;i1<nFIDCount1 || i2<nFIDCount2;)
329 : {
330 6 : if (i1 < nFIDCount1 && i2 < nFIDCount2)
331 : {
332 2 : long nVal1 = panFIDList1[i1];
333 2 : long nVal2 = panFIDList2[i2];
334 2 : if (nVal1 < nVal2)
335 : {
336 2 : if (i1+1 < nFIDCount1 && panFIDList1[i1+1] <= nVal2)
337 : {
338 1 : panFIDList[nFIDCount ++] = nVal1;
339 1 : i1 ++;
340 : }
341 : else
342 : {
343 0 : panFIDList[nFIDCount ++] = nVal1;
344 0 : panFIDList[nFIDCount ++] = nVal2;
345 0 : i1 ++;
346 0 : i2 ++;
347 : }
348 : }
349 1 : else if (nVal1 == nVal2)
350 : {
351 1 : panFIDList[nFIDCount ++] = nVal1;
352 1 : i1 ++;
353 1 : i2 ++;
354 : }
355 : else
356 : {
357 0 : if (i2+1 < nFIDCount2 && panFIDList2[i2+1] <= nVal1)
358 : {
359 0 : panFIDList[nFIDCount ++] = nVal2;
360 0 : i2 ++;
361 : }
362 : else
363 : {
364 0 : panFIDList[nFIDCount ++] = nVal2;
365 0 : panFIDList[nFIDCount ++] = nVal1;
366 0 : i1 ++;
367 0 : i2 ++;
368 : }
369 : }
370 : }
371 2 : else if (i1 < nFIDCount1)
372 : {
373 0 : long nVal1 = panFIDList1[i1];
374 0 : panFIDList[nFIDCount ++] = nVal1;
375 0 : i1 ++;
376 : }
377 2 : else if (i2 < nFIDCount2)
378 : {
379 2 : long nVal2 = panFIDList2[i2];
380 2 : panFIDList[nFIDCount ++] = nVal2;
381 2 : i2 ++;
382 : }
383 : }
384 :
385 1 : panFIDList[nFIDCount] = OGRNullFID;
386 :
387 1 : return panFIDList;
388 : }
389 :
390 : /* The input arrays must be sorted ! */
391 : static
392 2 : long* OGRANDLongArray(long panFIDList1[], int nFIDCount1,
393 : long panFIDList2[], int nFIDCount2, int& nFIDCount)
394 : {
395 2 : int nMaxCount = MAX(nFIDCount1, nFIDCount2);
396 2 : long* panFIDList = (long*) CPLMalloc((nMaxCount+1) * sizeof(long));
397 2 : nFIDCount = 0;
398 :
399 2 : int i1 = 0, i2 =0;
400 8 : for(;i1<nFIDCount1 && i2<nFIDCount2;)
401 : {
402 4 : long nVal1 = panFIDList1[i1];
403 4 : long nVal2 = panFIDList2[i2];
404 4 : if (nVal1 < nVal2)
405 : {
406 3 : if (i1+1 < nFIDCount1 && panFIDList1[i1+1] <= nVal2)
407 : {
408 1 : i1 ++;
409 : }
410 : else
411 : {
412 1 : i1 ++;
413 1 : i2 ++;
414 : }
415 : }
416 2 : else if (nVal1 == nVal2)
417 : {
418 2 : panFIDList[nFIDCount ++] = nVal1;
419 2 : i1 ++;
420 2 : i2 ++;
421 : }
422 : else
423 : {
424 0 : if (i2+1 < nFIDCount2 && panFIDList2[i2+1] <= nVal1)
425 : {
426 0 : i2 ++;
427 : }
428 : else
429 : {
430 0 : i1 ++;
431 0 : i2 ++;
432 : }
433 : }
434 : }
435 :
436 2 : panFIDList[nFIDCount] = OGRNullFID;
437 :
438 2 : return panFIDList;
439 : }
440 :
441 514 : long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
442 : OGRLayer *poLayer,
443 : int& nFIDCount )
444 : {
445 : OGRAttrIndex *poIndex;
446 :
447 : /* -------------------------------------------------------------------- */
448 : /* Does the expression meet our requirements? */
449 : /* -------------------------------------------------------------------- */
450 514 : if( psExpr == NULL ||
451 : psExpr->eNodeType != SNT_OPERATION )
452 0 : return NULL;
453 :
454 514 : if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
455 : psExpr->nSubExprCount == 2)
456 : {
457 111 : int nFIDCount1 = 0, nFIDCount2 = 0;
458 111 : long* panFIDList1 = EvaluateAgainstIndices( psExpr->papoSubExpr[0], poLayer, nFIDCount1 );
459 : long* panFIDList2 = panFIDList1 == NULL ? NULL :
460 111 : EvaluateAgainstIndices( psExpr->papoSubExpr[1], poLayer, nFIDCount2 );
461 111 : long* panFIDList = NULL;
462 111 : if (panFIDList1 != NULL && panFIDList2 != NULL)
463 : {
464 3 : if (psExpr->nOperation == SWQ_OR )
465 : panFIDList = OGRORLongArray(panFIDList1, nFIDCount1,
466 1 : panFIDList2, nFIDCount2, nFIDCount);
467 2 : else if (psExpr->nOperation == SWQ_AND )
468 : panFIDList = OGRANDLongArray(panFIDList1, nFIDCount1,
469 2 : panFIDList2, nFIDCount2, nFIDCount);
470 :
471 : }
472 111 : CPLFree(panFIDList1);
473 111 : CPLFree(panFIDList2);
474 111 : return panFIDList;
475 : }
476 :
477 403 : if( !(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN)
478 : || psExpr->nSubExprCount < 2 )
479 39 : return NULL;
480 :
481 364 : swq_expr_node *poColumn = psExpr->papoSubExpr[0];
482 364 : swq_expr_node *poValue = psExpr->papoSubExpr[1];
483 :
484 364 : if( poColumn->eNodeType != SNT_COLUMN
485 : || poValue->eNodeType != SNT_CONSTANT )
486 33 : return NULL;
487 :
488 331 : poIndex = poLayer->GetIndex()->GetFieldIndex( poColumn->field_index );
489 331 : if( poIndex == NULL )
490 301 : return NULL;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* OK, we have an index, now we need to query it. */
494 : /* -------------------------------------------------------------------- */
495 : OGRField sValue;
496 : OGRFieldDefn *poFieldDefn;
497 :
498 30 : poFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(poColumn->field_index);
499 :
500 : /* -------------------------------------------------------------------- */
501 : /* Handle the case of an IN operation. */
502 : /* -------------------------------------------------------------------- */
503 30 : if (psExpr->nOperation == SWQ_IN)
504 : {
505 : int nLength;
506 10 : long *panFIDs = NULL;
507 : int iIN;
508 :
509 20 : for( iIN = 1; iIN < psExpr->nSubExprCount; iIN++ )
510 : {
511 10 : switch( poFieldDefn->GetType() )
512 : {
513 : case OFTInteger:
514 5 : if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
515 3 : sValue.Integer = (int) psExpr->papoSubExpr[iIN]->float_value;
516 : else
517 2 : sValue.Integer = psExpr->papoSubExpr[iIN]->int_value;
518 5 : break;
519 :
520 : case OFTReal:
521 5 : sValue.Real = psExpr->papoSubExpr[iIN]->float_value;
522 5 : break;
523 :
524 : case OFTString:
525 0 : sValue.String = psExpr->papoSubExpr[iIN]->string_value;
526 0 : break;
527 :
528 : default:
529 0 : CPLAssert( FALSE );
530 0 : return NULL;
531 : }
532 :
533 10 : panFIDs = poIndex->GetAllMatches( &sValue, panFIDs, &nFIDCount, &nLength );
534 : }
535 :
536 10 : if (nFIDCount > 1)
537 : {
538 : /* the returned FIDs are expected to be in sorted order */
539 0 : qsort(panFIDs, nFIDCount, sizeof(long), CompareLong);
540 : }
541 10 : return panFIDs;
542 : }
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Handle equality test. */
546 : /* -------------------------------------------------------------------- */
547 20 : switch( poFieldDefn->GetType() )
548 : {
549 : case OFTInteger:
550 14 : if (poValue->field_type == SWQ_FLOAT)
551 1 : sValue.Integer = (int) poValue->float_value;
552 : else
553 13 : sValue.Integer = poValue->int_value;
554 14 : break;
555 :
556 : case OFTReal:
557 2 : sValue.Real = poValue->float_value;
558 2 : break;
559 :
560 : case OFTString:
561 4 : sValue.String = poValue->string_value;
562 4 : break;
563 :
564 : default:
565 0 : CPLAssert( FALSE );
566 0 : return NULL;
567 : }
568 :
569 20 : int nLength = 0;
570 20 : long *panFIDs = poIndex->GetAllMatches( &sValue, NULL, &nFIDCount, &nLength );
571 20 : if (nFIDCount > 1)
572 : {
573 : /* the returned FIDs are expected to be in sorted order */
574 6 : qsort(panFIDs, nFIDCount, sizeof(long), CompareLong);
575 : }
576 20 : return panFIDs;
577 : }
578 :
579 : /************************************************************************/
580 : /* OGRFieldCollector() */
581 : /* */
582 : /* Helper function for recursing through tree to satisfy */
583 : /* GetUsedFields(). */
584 : /************************************************************************/
585 :
586 50 : char **OGRFeatureQuery::FieldCollector( void *pBareOp,
587 : char **papszList )
588 :
589 : {
590 50 : swq_expr_node *op = (swq_expr_node *) pBareOp;
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* References to tables other than the primarily are currently */
594 : /* unsupported. Error out. */
595 : /* -------------------------------------------------------------------- */
596 50 : if( op->eNodeType == SNT_COLUMN )
597 : {
598 14 : if( op->table_index != 0 )
599 : {
600 0 : CSLDestroy( papszList );
601 0 : return NULL;
602 : }
603 :
604 : /* -------------------------------------------------------------------- */
605 : /* Add the field name into our list if it is not already there. */
606 : /* -------------------------------------------------------------------- */
607 : const char *pszFieldName;
608 :
609 14 : if( op->field_index >= poTargetDefn->GetFieldCount()
610 : && op->field_index < poTargetDefn->GetFieldCount() + SPECIAL_FIELD_COUNT)
611 3 : pszFieldName = SpecialFieldNames[op->field_index - poTargetDefn->GetFieldCount()];
612 11 : else if( op->field_index >= 0
613 : && op->field_index < poTargetDefn->GetFieldCount() )
614 : pszFieldName =
615 11 : poTargetDefn->GetFieldDefn(op->field_index)->GetNameRef();
616 : else
617 : {
618 0 : CSLDestroy( papszList );
619 0 : return NULL;
620 : }
621 :
622 14 : if( CSLFindString( papszList, pszFieldName ) == -1 )
623 13 : papszList = CSLAddString( papszList, pszFieldName );
624 : }
625 :
626 : /* -------------------------------------------------------------------- */
627 : /* Add in fields from subexpressions. */
628 : /* -------------------------------------------------------------------- */
629 50 : if( op->eNodeType == SNT_OPERATION )
630 : {
631 58 : for( int iSubExpr = 0; iSubExpr < op->nSubExprCount; iSubExpr++ )
632 : {
633 38 : papszList = FieldCollector( op->papoSubExpr[iSubExpr], papszList );
634 : }
635 : }
636 :
637 50 : return papszList;
638 : }
639 :
640 : /************************************************************************/
641 : /* GetUsedFields() */
642 : /************************************************************************/
643 :
644 : /**
645 : * Returns lists of fields in expression.
646 : *
647 : * All attribute fields are used in the expression of this feature
648 : * query are returned as a StringList of field names. This function would
649 : * primarily be used within drivers to recognise special case conditions
650 : * depending only on attribute fields that can be very efficiently
651 : * fetched.
652 : *
653 : * NOTE: If any fields in the expression are from tables other than the
654 : * primary table then NULL is returned indicating an error. In succesful
655 : * use, no non-empty expression should return an empty list.
656 : *
657 : * @return list of field names. Free list with CSLDestroy() when no longer
658 : * required.
659 : */
660 :
661 12 : char **OGRFeatureQuery::GetUsedFields( )
662 :
663 : {
664 12 : if( pSWQExpr == NULL )
665 0 : return NULL;
666 :
667 :
668 12 : return FieldCollector( pSWQExpr, NULL );
669 : }
670 :
671 :
672 :
|