1 : /******************************************************************************
2 : * $Id: ogrfeaturequery.cpp 23309 2011-11-03 20:58:33Z 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 23309 2011-11-03 20:58:33Z 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 171 : OGRFeatureQuery::OGRFeatureQuery()
53 :
54 : {
55 171 : poTargetDefn = NULL;
56 171 : pSWQExpr = NULL;
57 171 : }
58 :
59 : /************************************************************************/
60 : /* ~OGRFeatureQuery() */
61 : /************************************************************************/
62 :
63 171 : OGRFeatureQuery::~OGRFeatureQuery()
64 :
65 : {
66 171 : delete (swq_expr_node *) pSWQExpr;
67 171 : }
68 :
69 : /************************************************************************/
70 : /* Parse */
71 : /************************************************************************/
72 :
73 338 : OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn,
74 : const char * pszExpression )
75 :
76 : {
77 : /* -------------------------------------------------------------------- */
78 : /* Clear any existing expression. */
79 : /* -------------------------------------------------------------------- */
80 338 : if( pSWQExpr != NULL )
81 : {
82 167 : delete (swq_expr_node *) pSWQExpr;
83 167 : pSWQExpr = NULL;
84 : }
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* Build list of fields. */
88 : /* -------------------------------------------------------------------- */
89 : char **papszFieldNames;
90 : swq_field_type *paeFieldTypes;
91 : int iField;
92 338 : int nFieldCount = poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT;
93 :
94 : papszFieldNames = (char **)
95 338 : CPLMalloc(sizeof(char *) * nFieldCount );
96 : paeFieldTypes = (swq_field_type *)
97 338 : CPLMalloc(sizeof(swq_field_type) * nFieldCount );
98 :
99 2232 : for( iField = 0; iField < poDefn->GetFieldCount(); iField++ )
100 : {
101 1894 : OGRFieldDefn *poField = poDefn->GetFieldDefn( iField );
102 :
103 1894 : papszFieldNames[iField] = (char *) poField->GetNameRef();
104 :
105 1894 : switch( poField->GetType() )
106 : {
107 : case OFTInteger:
108 567 : paeFieldTypes[iField] = SWQ_INTEGER;
109 567 : break;
110 :
111 : case OFTReal:
112 321 : paeFieldTypes[iField] = SWQ_FLOAT;
113 321 : break;
114 :
115 : case OFTString:
116 940 : paeFieldTypes[iField] = SWQ_STRING;
117 940 : break;
118 :
119 : case OFTDate:
120 : case OFTTime:
121 : case OFTDateTime:
122 60 : paeFieldTypes[iField] = SWQ_TIMESTAMP;
123 60 : break;
124 :
125 : default:
126 6 : paeFieldTypes[iField] = SWQ_OTHER;
127 : break;
128 : }
129 : }
130 :
131 338 : iField = 0;
132 2366 : while (iField < SPECIAL_FIELD_COUNT)
133 : {
134 1690 : papszFieldNames[poDefn->GetFieldCount() + iField] = (char *) SpecialFieldNames[iField];
135 1690 : paeFieldTypes[poDefn->GetFieldCount() + iField] = SpecialFieldTypes[iField];
136 1690 : ++iField;
137 : }
138 :
139 : /* -------------------------------------------------------------------- */
140 : /* Try to parse. */
141 : /* -------------------------------------------------------------------- */
142 338 : OGRErr eErr = OGRERR_NONE;
143 : CPLErr eCPLErr;
144 :
145 338 : poTargetDefn = poDefn;
146 : eCPLErr = swq_expr_compile( pszExpression, nFieldCount,
147 : papszFieldNames, paeFieldTypes,
148 338 : (swq_expr_node **) &pSWQExpr );
149 338 : if( eCPLErr != CE_None )
150 : {
151 0 : eErr = OGRERR_CORRUPT_DATA;
152 0 : pSWQExpr = NULL;
153 : }
154 :
155 338 : CPLFree( papszFieldNames );
156 338 : CPLFree( paeFieldTypes );
157 :
158 :
159 338 : return eErr;
160 : }
161 :
162 : /************************************************************************/
163 : /* OGRFeatureFetcher() */
164 : /************************************************************************/
165 :
166 455398 : static swq_expr_node *OGRFeatureFetcher( swq_expr_node *op, void *pFeatureIn )
167 :
168 : {
169 455398 : OGRFeature *poFeature = (OGRFeature *) pFeatureIn;
170 455398 : swq_expr_node *poRetNode = NULL;
171 :
172 455398 : switch( op->field_type )
173 : {
174 : case SWQ_INTEGER:
175 : case SWQ_BOOLEAN:
176 : poRetNode = new swq_expr_node(
177 77943 : poFeature->GetFieldAsInteger(op->field_index) );
178 77943 : break;
179 :
180 : case SWQ_FLOAT:
181 : poRetNode = new swq_expr_node(
182 2334 : poFeature->GetFieldAsDouble(op->field_index) );
183 2334 : break;
184 :
185 : default:
186 : poRetNode = new swq_expr_node(
187 375121 : poFeature->GetFieldAsString(op->field_index) );
188 : break;
189 : }
190 :
191 455398 : poRetNode->is_null = !(poFeature->IsFieldSet(op->field_index));
192 :
193 455398 : return poRetNode;
194 : }
195 :
196 : /************************************************************************/
197 : /* Evaluate() */
198 : /************************************************************************/
199 :
200 455259 : int OGRFeatureQuery::Evaluate( OGRFeature *poFeature )
201 :
202 : {
203 455259 : if( pSWQExpr == NULL )
204 0 : return FALSE;
205 :
206 : swq_expr_node *poResult;
207 :
208 : poResult = ((swq_expr_node *) pSWQExpr)->Evaluate( OGRFeatureFetcher,
209 455259 : (void *) poFeature );
210 :
211 455259 : if( poResult == NULL )
212 0 : return FALSE;
213 :
214 455259 : CPLAssert( poResult->field_type == SWQ_BOOLEAN );
215 :
216 455259 : int bLogicalResult = poResult->int_value;
217 :
218 455259 : delete poResult;
219 :
220 455259 : return bLogicalResult;
221 : }
222 :
223 : /************************************************************************/
224 : /* EvaluateAgainstIndices() */
225 : /* */
226 : /* Attempt to return a list of FIDs matching the given */
227 : /* attribute query conditions utilizing attribute indices. */
228 : /* Returns NULL if the result cannot be computed from the */
229 : /* available indices, or an "OGRNullFID" terminated list of */
230 : /* FIDs if it can. */
231 : /* */
232 : /* For now we only support equality tests on a single indexed */
233 : /* attribute field. Eventually we should make this support */
234 : /* multi-part queries with ranges. */
235 : /************************************************************************/
236 :
237 0 : static int CompareLong(const void *a, const void *b)
238 : {
239 0 : return (*(const long *)a) - (*(const long *)b);
240 : }
241 :
242 222 : long *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer,
243 : OGRErr *peErr )
244 :
245 : {
246 222 : swq_expr_node *psExpr = (swq_expr_node *) pSWQExpr;
247 : OGRAttrIndex *poIndex;
248 :
249 222 : if( peErr != NULL )
250 0 : *peErr = OGRERR_NONE;
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Does the expression meet our requirements? Do we have an */
254 : /* index on the targetted field? */
255 : /* -------------------------------------------------------------------- */
256 222 : if( psExpr == NULL
257 : || psExpr->eNodeType != SNT_OPERATION
258 : || !(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN)
259 : || poLayer->GetIndex() == NULL
260 : || psExpr->nSubExprCount < 2 )
261 66 : return NULL;
262 :
263 156 : swq_expr_node *poColumn = psExpr->papoSubExpr[0];
264 156 : swq_expr_node *poValue = psExpr->papoSubExpr[1];
265 :
266 156 : if( poColumn->eNodeType != SNT_COLUMN
267 : || poValue->eNodeType != SNT_CONSTANT )
268 25 : return NULL;
269 :
270 131 : poIndex = poLayer->GetIndex()->GetFieldIndex( poColumn->field_index );
271 131 : if( poIndex == NULL )
272 107 : return NULL;
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* OK, we have an index, now we need to query it. */
276 : /* -------------------------------------------------------------------- */
277 : OGRField sValue;
278 : OGRFieldDefn *poFieldDefn;
279 :
280 24 : poFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(poColumn->field_index);
281 :
282 : /* -------------------------------------------------------------------- */
283 : /* Handle the case of an IN operation. */
284 : /* -------------------------------------------------------------------- */
285 24 : if (psExpr->nOperation == SWQ_IN)
286 : {
287 10 : int nFIDCount = 0, nLength;
288 10 : long *panFIDs = NULL;
289 : int iIN;
290 :
291 20 : for( iIN = 1; iIN < psExpr->nSubExprCount; iIN++ )
292 : {
293 10 : switch( poFieldDefn->GetType() )
294 : {
295 : case OFTInteger:
296 5 : if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
297 3 : sValue.Integer = (int) psExpr->papoSubExpr[iIN]->float_value;
298 : else
299 2 : sValue.Integer = psExpr->papoSubExpr[iIN]->int_value;
300 5 : break;
301 :
302 : case OFTReal:
303 5 : sValue.Real = psExpr->papoSubExpr[iIN]->float_value;
304 5 : break;
305 :
306 : case OFTString:
307 0 : sValue.String = psExpr->papoSubExpr[iIN]->string_value;
308 0 : break;
309 :
310 : default:
311 0 : CPLAssert( FALSE );
312 0 : return NULL;
313 : }
314 :
315 10 : panFIDs = poIndex->GetAllMatches( &sValue, panFIDs, &nFIDCount, &nLength );
316 : }
317 :
318 10 : if (nFIDCount > 1)
319 : {
320 : /* the returned FIDs are expected to be in sorted order */
321 0 : qsort(panFIDs, nFIDCount, sizeof(long), CompareLong);
322 : }
323 10 : return panFIDs;
324 : }
325 :
326 : /* -------------------------------------------------------------------- */
327 : /* Handle equality test. */
328 : /* -------------------------------------------------------------------- */
329 14 : switch( poFieldDefn->GetType() )
330 : {
331 : case OFTInteger:
332 11 : if (poValue->field_type == SWQ_FLOAT)
333 1 : sValue.Integer = (int) poValue->float_value;
334 : else
335 10 : sValue.Integer = poValue->int_value;
336 11 : break;
337 :
338 : case OFTReal:
339 2 : sValue.Real = poValue->float_value;
340 2 : break;
341 :
342 : case OFTString:
343 1 : sValue.String = poValue->string_value;
344 1 : break;
345 :
346 : default:
347 0 : CPLAssert( FALSE );
348 0 : return NULL;
349 : }
350 :
351 14 : int nFIDCount = 0, nLength = 0;
352 14 : long *panFIDs = poIndex->GetAllMatches( &sValue, NULL, &nFIDCount, &nLength );
353 14 : if (nFIDCount > 1)
354 : {
355 : /* the returned FIDs are expected to be in sorted order */
356 0 : qsort(panFIDs, nFIDCount, sizeof(long), CompareLong);
357 : }
358 14 : return panFIDs;
359 : }
360 :
361 : /************************************************************************/
362 : /* OGRFieldCollector() */
363 : /* */
364 : /* Helper function for recursing through tree to satisfy */
365 : /* GetUsedFields(). */
366 : /************************************************************************/
367 :
368 3 : char **OGRFeatureQuery::FieldCollector( void *pBareOp,
369 : char **papszList )
370 :
371 : {
372 3 : swq_expr_node *op = (swq_expr_node *) pBareOp;
373 :
374 : /* -------------------------------------------------------------------- */
375 : /* References to tables other than the primarily are currently */
376 : /* unsupported. Error out. */
377 : /* -------------------------------------------------------------------- */
378 3 : if( op->eNodeType == SNT_COLUMN )
379 : {
380 1 : if( op->table_index != 0 )
381 : {
382 0 : CSLDestroy( papszList );
383 0 : return NULL;
384 : }
385 :
386 : /* -------------------------------------------------------------------- */
387 : /* Add the field name into our list if it is not already there. */
388 : /* -------------------------------------------------------------------- */
389 : const char *pszFieldName;
390 :
391 1 : if( op->field_index >= poTargetDefn->GetFieldCount()
392 : && op->field_index < poTargetDefn->GetFieldCount() + SPECIAL_FIELD_COUNT)
393 0 : pszFieldName = SpecialFieldNames[op->field_index];
394 1 : else if( op->field_index >= 0
395 : && op->field_index < poTargetDefn->GetFieldCount() )
396 : pszFieldName =
397 1 : poTargetDefn->GetFieldDefn(op->field_index)->GetNameRef();
398 : else
399 : {
400 0 : CSLDestroy( papszList );
401 0 : return NULL;
402 : }
403 :
404 1 : if( CSLFindString( papszList, pszFieldName ) == -1 )
405 1 : papszList = CSLAddString( papszList, pszFieldName );
406 : }
407 :
408 : /* -------------------------------------------------------------------- */
409 : /* Add in fields from subexpressions. */
410 : /* -------------------------------------------------------------------- */
411 3 : if( op->eNodeType == SNT_OPERATION )
412 : {
413 3 : for( int iSubExpr = 0; iSubExpr < op->nSubExprCount; iSubExpr++ )
414 : {
415 2 : papszList = FieldCollector( op->papoSubExpr[iSubExpr], papszList );
416 : }
417 : }
418 :
419 3 : return papszList;
420 : }
421 :
422 : /************************************************************************/
423 : /* GetUsedFields() */
424 : /************************************************************************/
425 :
426 : /**
427 : * Returns lists of fields in expression.
428 : *
429 : * All attribute fields are used in the expression of this feature
430 : * query are returned as a StringList of field names. This function would
431 : * primarily be used within drivers to recognise special case conditions
432 : * depending only on attribute fields that can be very efficiently
433 : * fetched.
434 : *
435 : * NOTE: If any fields in the expression are from tables other than the
436 : * primary table then NULL is returned indicating an error. In succesful
437 : * use, no non-empty expression should return an empty list.
438 : *
439 : * @return list of field names. Free list with CSLDestroy() when no longer
440 : * required.
441 : */
442 :
443 1 : char **OGRFeatureQuery::GetUsedFields( )
444 :
445 : {
446 1 : if( pSWQExpr == NULL )
447 0 : return NULL;
448 :
449 :
450 1 : return FieldCollector( pSWQExpr, NULL );
451 : }
452 :
453 :
454 :
|