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