1 /******************************************************************************
2 * $Id: ogrfeaturequery.cpp 14288 2008-04-13 15:56:22Z 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 "ogr_feature.h"
33 #include "ogr_p.h"
34 #include "ogrsf_frmts/ogr_attrind.h"
35
36 CPL_CVSID("$Id: ogrfeaturequery.cpp 14288 2008-04-13 15:56:22Z rouault $");
37
38 /************************************************************************/
39 /* Support for special attributes (feature query and selection) */
40 /************************************************************************/
41
42 const char* SpecialFieldNames[SPECIAL_FIELD_COUNT]
43 = {"FID", "OGR_GEOMETRY", "OGR_STYLE", "OGR_GEOM_WKT"};
44 const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT]
45 = {SWQ_INTEGER, SWQ_STRING, SWQ_STRING, SWQ_STRING};
46
47 /************************************************************************/
48 /* OGRFeatureQuery() */
49 /************************************************************************/
50
OGRFeatureQuery()51 OGRFeatureQuery::OGRFeatureQuery()
52
53 {
54 poTargetDefn = NULL;
55 pSWQExpr = NULL;
56 }
57
58 /************************************************************************/
59 /* ~OGRFeatureQuery() */
60 /************************************************************************/
61
~OGRFeatureQuery()62 OGRFeatureQuery::~OGRFeatureQuery()
63
64 {
65 if( pSWQExpr != NULL )
66 swq_expr_free( (swq_expr *) pSWQExpr );
67 }
68
69 /************************************************************************/
70 /* Parse */
71 /************************************************************************/
72
Compile(OGRFeatureDefn * poDefn,const char * pszExpression)73 OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn,
74 const char * pszExpression )
75
76 {
77 /* -------------------------------------------------------------------- */
78 /* Clear any existing expression. */
79 /* -------------------------------------------------------------------- */
80 if( pSWQExpr != NULL )
81 swq_expr_free( (swq_expr *) pSWQExpr );
82
83 /* -------------------------------------------------------------------- */
84 /* Build list of fields. */
85 /* -------------------------------------------------------------------- */
86 char **papszFieldNames;
87 swq_field_type *paeFieldTypes;
88 int iField;
89 int nFieldCount = poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT;
90
91 papszFieldNames = (char **)
92 CPLMalloc(sizeof(char *) * nFieldCount );
93 paeFieldTypes = (swq_field_type *)
94 CPLMalloc(sizeof(swq_field_type) * nFieldCount );
95
96 for( iField = 0; iField < poDefn->GetFieldCount(); iField++ )
97 {
98 OGRFieldDefn *poField = poDefn->GetFieldDefn( iField );
99
100 papszFieldNames[iField] = (char *) poField->GetNameRef();
101
102 switch( poField->GetType() )
103 {
104 case OFTInteger:
105 paeFieldTypes[iField] = SWQ_INTEGER;
106 break;
107
108 case OFTReal:
109 paeFieldTypes[iField] = SWQ_FLOAT;
110 break;
111
112 case OFTString:
113 paeFieldTypes[iField] = SWQ_STRING;
114 break;
115
116 default:
117 paeFieldTypes[iField] = SWQ_OTHER;
118 break;
119 }
120 }
121
122 iField = 0;
123 while (iField < SPECIAL_FIELD_COUNT)
124 {
125 papszFieldNames[poDefn->GetFieldCount() + iField] = (char *) SpecialFieldNames[iField];
126 paeFieldTypes[poDefn->GetFieldCount() + iField] = SpecialFieldTypes[iField];
127 ++iField;
128 }
129
130 /* -------------------------------------------------------------------- */
131 /* Try to parse. */
132 /* -------------------------------------------------------------------- */
133 const char *pszError;
134 OGRErr eErr = OGRERR_NONE;
135
136 poTargetDefn = poDefn;
137 pszError = swq_expr_compile( pszExpression, nFieldCount,
138 papszFieldNames, paeFieldTypes,
139 (swq_expr **) &pSWQExpr );
140 if( pszError != NULL )
141 {
142 CPLError( CE_Failure, CPLE_AppDefined,
143 "%s", pszError );
144 eErr = OGRERR_CORRUPT_DATA;
145 pSWQExpr = NULL;
146 }
147
148 CPLFree( papszFieldNames );
149 CPLFree( paeFieldTypes );
150
151
152 return eErr;
153 }
154
155 /************************************************************************/
156 /* OGRFeatureQueryEvaluator() */
157 /************************************************************************/
158
OGRFeatureQueryEvaluator(swq_field_op * op,OGRFeature * poFeature)159 static int OGRFeatureQueryEvaluator( swq_field_op *op, OGRFeature *poFeature )
160
161 {
162 OGRField sField;
163 OGRField *psField;
164
165 int iSpecialField = op->field_index - poFeature->GetDefnRef()->GetFieldCount();
166 if( iSpecialField >= 0 )
167 {
168 if ( iSpecialField < SPECIAL_FIELD_COUNT )
169 {
170 switch ( SpecialFieldTypes[iSpecialField] )
171 {
172 case SWQ_INTEGER:
173 sField.Integer = poFeature->GetFieldAsInteger(op->field_index);
174 break;
175
176 case SWQ_STRING:
177 sField.String = (char*)
178 poFeature->GetFieldAsString( op->field_index );
179 break;
180
181 default:
182 CPLAssert( FALSE );
183 break;
184 }
185 }
186 else
187 {
188 CPLDebug( "OGRFeatureQuery", "Illegal special field index.");
189 return FALSE;
190 }
191 psField = &sField;
192 }
193 else
194 psField = poFeature->GetRawFieldRef( op->field_index );
195
196 switch( op->field_type )
197 {
198 case SWQ_INTEGER:
199 switch( op->operation )
200 {
201 case SWQ_EQ:
202 return psField->Integer == op->int_value;
203 case SWQ_NE:
204 return psField->Integer != op->int_value;
205 case SWQ_LT:
206 return psField->Integer < op->int_value;
207 case SWQ_GT:
208 return psField->Integer > op->int_value;
209 case SWQ_LE:
210 return psField->Integer <= op->int_value;
211 case SWQ_GE:
212 return psField->Integer >= op->int_value;
213 case SWQ_ISNULL:
214 return !poFeature->IsFieldSet( op->field_index );
215
216 case SWQ_IN:
217 {
218 const char *pszSrc;
219
220 pszSrc = op->string_value;
221 while( *pszSrc != '\0' )
222 {
223 if( atoi(pszSrc) == psField->Integer )
224 return TRUE;
225 pszSrc += strlen(pszSrc) + 1;
226 }
227
228 return FALSE;
229 }
230
231 default:
232 CPLDebug( "OGRFeatureQuery",
233 "Illegal operation (%d) on integer field.",
234 op->operation );
235 return FALSE;
236 }
237
238 case SWQ_FLOAT:
239 switch( op->operation )
240 {
241 case SWQ_EQ:
242 return psField->Real == op->float_value;
243 case SWQ_NE:
244 return psField->Real != op->float_value;
245 case SWQ_LT:
246 return psField->Real < op->float_value;
247 case SWQ_GT:
248 return psField->Real > op->float_value;
249 case SWQ_LE:
250 return psField->Real <= op->float_value;
251 case SWQ_GE:
252 return psField->Real >= op->float_value;
253 case SWQ_ISNULL:
254 return !poFeature->IsFieldSet( op->field_index );
255 case SWQ_IN:
256 {
257 const char *pszSrc;
258
259 pszSrc = op->string_value;
260 while( *pszSrc != '\0' )
261 {
262 if( atof(pszSrc) == psField->Real )
263 return TRUE;
264 pszSrc += strlen(pszSrc) + 1;
265 }
266
267 return FALSE;
268 }
269
270 default:
271 CPLDebug( "OGRFeatureQuery",
272 "Illegal operation (%d) on float field.",
273 op->operation );
274 return FALSE;
275 }
276
277 case SWQ_STRING:
278 switch( op->operation )
279 {
280 case SWQ_EQ:
281 if (psField->Set.nMarker1 == OGRUnsetMarker
282 && psField->Set.nMarker2 == OGRUnsetMarker )
283 {
284 return (op->string_value[0] == '\0');
285 }
286 else
287 {
288 return EQUAL(psField->String,op->string_value);
289 }
290 case SWQ_NE:
291 if (psField->Set.nMarker1 == OGRUnsetMarker
292 && psField->Set.nMarker2 == OGRUnsetMarker )
293 {
294 return (op->string_value[0] != '\0');
295 }
296 else
297 {
298 return !EQUAL(psField->String,op->string_value);
299 }
300
301 case SWQ_LT:
302 if (psField->Set.nMarker1 == OGRUnsetMarker
303 && psField->Set.nMarker2 == OGRUnsetMarker )
304 {
305 return (op->string_value[0] != '\0');
306 }
307 else
308 {
309 return strcmp(psField->String,op->string_value) < 0;
310 }
311 case SWQ_GT:
312 if (psField->Set.nMarker1 == OGRUnsetMarker
313 && psField->Set.nMarker2 == OGRUnsetMarker )
314 {
315 return (op->string_value[0] != '\0');
316 }
317 else
318 {
319 return strcmp(psField->String,op->string_value) > 0;
320 }
321 case SWQ_LE:
322 if (psField->Set.nMarker1 == OGRUnsetMarker
323 && psField->Set.nMarker2 == OGRUnsetMarker )
324 {
325 return (op->string_value[0] != '\0');
326 }
327 else
328 {
329 return strcmp(psField->String,op->string_value) <= 0;
330 }
331 case SWQ_GE:
332 if (psField->Set.nMarker1 == OGRUnsetMarker
333 && psField->Set.nMarker2 == OGRUnsetMarker )
334 {
335 return (op->string_value[0] != '\0');
336 }
337 else
338 {
339 return strcmp(psField->String,op->string_value) >= 0;
340 }
341
342 case SWQ_ISNULL:
343 return !poFeature->IsFieldSet( op->field_index );
344
345 case SWQ_LIKE:
346 if (psField->Set.nMarker1 != OGRUnsetMarker
347 || psField->Set.nMarker2 != OGRUnsetMarker )
348 return swq_test_like(psField->String, op->string_value);
349 else
350 return FALSE;
351
352 case SWQ_IN:
353 {
354 const char *pszSrc;
355
356 if( !poFeature->IsFieldSet(op->field_index) )
357 return FALSE;
358
359 pszSrc = op->string_value;
360 while( *pszSrc != '\0' )
361 {
362 if( EQUAL(pszSrc,psField->String) )
363 return TRUE;
364 pszSrc += strlen(pszSrc) + 1;
365 }
366
367 return FALSE;
368 }
369
370 default:
371 CPLDebug( "OGRFeatureQuery",
372 "Illegal operation (%d) on string field.",
373 op->operation );
374 return FALSE;
375 }
376
377 case SWQ_OTHER:
378 switch( op->operation )
379 {
380 case SWQ_ISNULL:
381 return !poFeature->IsFieldSet( op->field_index );
382
383 default:
384 CPLDebug( "OGRFeatureQuery",
385 "Illegal operation (%d) on list or binary field.",
386 op->operation );
387 return FALSE;
388 }
389
390 default:
391 assert( FALSE );
392 return FALSE;
393 }
394 }
395
396 /************************************************************************/
397 /* Evaluate() */
398 /************************************************************************/
399
Evaluate(OGRFeature * poFeature)400 int OGRFeatureQuery::Evaluate( OGRFeature *poFeature )
401
402 {
403 if( pSWQExpr == NULL )
404 return FALSE;
405
406 return swq_expr_evaluate( (swq_expr *) pSWQExpr,
407 (swq_op_evaluator) OGRFeatureQueryEvaluator,
408 (void *) poFeature );
409 }
410
411 /************************************************************************/
412 /* EvaluateAgainstIndices() */
413 /* */
414 /* Attempt to return a list of FIDs matching the given */
415 /* attribute query conditions utilizing attribute indices. */
416 /* Returns NULL if the result cannot be computed from the */
417 /* available indices, or an "OGRNullFID" terminated list of */
418 /* FIDs if it can. */
419 /* */
420 /* For now we only support equality tests on a single indexed */
421 /* attribute field. Eventually we should make this support */
422 /* multi-part queries with ranges. */
423 /************************************************************************/
424
EvaluateAgainstIndices(OGRLayer * poLayer,OGRErr * peErr)425 long *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer,
426 OGRErr *peErr )
427
428 {
429 swq_expr *psExpr = (swq_expr *) pSWQExpr;
430 OGRAttrIndex *poIndex;
431
432 if( peErr != NULL )
433 *peErr = OGRERR_NONE;
434
435 /* -------------------------------------------------------------------- */
436 /* Does the expression meet our requirements? Do we have an */
437 /* index on the targetted field? */
438 /* -------------------------------------------------------------------- */
439 if( psExpr == NULL || psExpr->operation != SWQ_EQ
440 || poLayer->GetIndex() == NULL )
441 return NULL;
442
443 poIndex = poLayer->GetIndex()->GetFieldIndex( psExpr->field_index );
444 if( poIndex == NULL )
445 return NULL;
446
447 /* -------------------------------------------------------------------- */
448 /* OK, we have an index, now we need to query it. */
449 /* -------------------------------------------------------------------- */
450 OGRField sValue;
451 OGRFieldDefn *poFieldDefn;
452
453 poFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(psExpr->field_index);
454
455 switch( poFieldDefn->GetType() )
456 {
457 case OFTInteger:
458 sValue.Integer = psExpr->int_value;
459 break;
460
461 case OFTReal:
462 sValue.Real = psExpr->float_value;
463 break;
464
465 case OFTString:
466 sValue.String = psExpr->string_value;
467 break;
468
469 default:
470 CPLAssert( FALSE );
471 return NULL;
472 }
473
474 return poIndex->GetAllMatches( &sValue );
475 }
476
477 /************************************************************************/
478 /* OGRFieldCollector() */
479 /* */
480 /* Helper function for recursing through tree to satisfy */
481 /* GetUsedFields(). */
482 /************************************************************************/
483
FieldCollector(void * pBareOp,char ** papszList)484 char **OGRFeatureQuery::FieldCollector( void *pBareOp,
485 char **papszList )
486
487 {
488 swq_field_op *op = (swq_field_op *) pBareOp;
489
490 /* -------------------------------------------------------------------- */
491 /* References to tables other than the primarily are currently */
492 /* unsupported. Error out. */
493 /* -------------------------------------------------------------------- */
494 if( op->table_index != 0 )
495 {
496 CSLDestroy( papszList );
497 return NULL;
498 }
499
500 /* -------------------------------------------------------------------- */
501 /* Add the field name into our list if it is not already there. */
502 /* -------------------------------------------------------------------- */
503 const char *pszFieldName;
504
505 if( op->field_index >= poTargetDefn->GetFieldCount()
506 && op->field_index < poTargetDefn->GetFieldCount() + SPECIAL_FIELD_COUNT)
507 pszFieldName = SpecialFieldNames[op->field_index];
508 else if( op->field_index >= 0
509 && op->field_index < poTargetDefn->GetFieldCount() )
510 pszFieldName =
511 poTargetDefn->GetFieldDefn(op->field_index)->GetNameRef();
512 else
513 {
514 CSLDestroy( papszList );
515 return NULL;
516 }
517
518 if( CSLFindString( papszList, pszFieldName ) == -1 )
519 papszList = CSLAddString( papszList, pszFieldName );
520
521 /* -------------------------------------------------------------------- */
522 /* Add in fields from subexpressions. */
523 /* -------------------------------------------------------------------- */
524 if( op->first_sub_expr != NULL )
525 papszList = FieldCollector( op->first_sub_expr, papszList );
526 if( op->second_sub_expr != NULL )
527 papszList = FieldCollector( op->second_sub_expr, papszList );
528
529 return papszList;
530 }
531
532 /************************************************************************/
533 /* GetUsedFields() */
534 /************************************************************************/
535
536 /**
537 * Returns lists of fields in expression.
538 *
539 * All attribute fields are used in the expression of this feature
540 * query are returned as a StringList of field names. This function would
541 * primarily be used within drivers to recognise special case conditions
542 * depending only on attribute fields that can be very efficiently
543 * fetched.
544 *
545 * NOTE: If any fields in the expression are from tables other than the
546 * primary table then NULL is returned indicating an error. In succesful
547 * use, no non-empty expression should return an empty list.
548 *
549 * @return list of field names. Free list with CSLDestroy() when no longer
550 * required.
551 */
552
GetUsedFields()553 char **OGRFeatureQuery::GetUsedFields( )
554
555 {
556 if( pSWQExpr == NULL )
557 return NULL;
558
559
560 return FieldCollector( pSWQExpr, NULL );
561 }
562
563
564
565