Ticket #1438: ogrfeaturequery.2.cpp

File ogrfeaturequery.2.cpp, 18.2 kB (added by szekerest, 3 years ago)

simple patch to support filtering by geometry (ver 2.)

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