1 /**********************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: OGC Filter Encoding implementation
6 * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca)
7 *
8 **********************************************************************
9 * Copyright (c) 2003, Y. Assefa, DM Solutions Group Inc
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies of this Software or works derived from this Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 ****************************************************************************/
28
29 #include "mapogcfilter.h"
30 #include "mapserver.h"
31 #include "mapows.h"
32 #include "mapowscommon.h"
33 #include "cpl_minixml.h"
34
35 #include <string>
36
FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode * psFilterNode)37 static std::string FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)
38 {
39 /* From http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04 */
40 /* also add double quote because we are within a string */
41 const char* pszRegexSpecialCharsAndDoubleQuote = "\\^${[().*+?|\"";
42
43 if (!psFilterNode || !psFilterNode->pOther || !psFilterNode->psLeftNode || !psFilterNode->psRightNode || !psFilterNode->psRightNode->pszValue)
44 return std::string();
45
46 const FEPropertyIsLike* propIsLike = (const FEPropertyIsLike *)psFilterNode->pOther;
47 const char* pszWild = propIsLike->pszWildCard;
48 const char* pszSingle = propIsLike->pszSingleChar;
49 const char* pszEscape = propIsLike->pszEscapeChar;
50 const bool bCaseInsensitive = propIsLike->bCaseInsensitive != 0;
51
52 if (!pszWild || strlen(pszWild) == 0 || !pszSingle || strlen(pszSingle) == 0 || !pszEscape || strlen(pszEscape) == 0)
53 return std::string();
54
55 /* -------------------------------------------------------------------- */
56 /* Use operand with regular expressions. */
57 /* -------------------------------------------------------------------- */
58 std::string expr("(\"[");
59
60 /* attribute */
61 expr += psFilterNode->psLeftNode->pszValue;
62
63 /* #3521 */
64 if (bCaseInsensitive )
65 expr += "]\" ~* \"";
66 else
67 expr += "]\" ~ \"";
68
69 const char* pszValue = psFilterNode->psRightNode->pszValue;
70 const size_t nLength = strlen(pszValue);
71
72 if (nLength > 0) {
73 expr += '^';
74 }
75 for (size_t i=0; i<nLength; i++) {
76 if (pszValue[i] == pszSingle[0]) {
77 expr += '.';
78 /* The Filter escape character is supposed to only escape the single, wildcard and escape character */
79 } else if (pszValue[i] == pszEscape[0] && (
80 pszValue[i+1] == pszSingle[0] ||
81 pszValue[i+1] == pszWild[0] ||
82 pszValue[i+1] == pszEscape[0])) {
83 if( pszValue[i+1] == '\\' )
84 {
85 /* Tricky case: \ must be escaped ncce in the regular expression context
86 so that the regexp matches it as an ordinary character.
87 But as \ is also the escape character for MapServer string, we
88 must escape it again. */
89 expr += "\\" "\\" "\\" "\\";
90 }
91 else
92 {
93 /* If the escaped character is itself a regular expression special character */
94 /* we need to regular-expression-escape-it ! */
95 if( strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i+1]) )
96 {
97 expr += '\\';
98 }
99 expr += pszValue[i+1];
100 }
101 i++;
102 } else if (pszValue[i] == pszWild[0]) {
103 expr += ".*";
104 }
105 /* Escape regular expressions special characters and double quote */
106 else if (strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i]))
107 {
108 if( pszValue[i] == '\\' )
109 {
110 /* See above explantation */
111 expr += "\\" "\\" "\\" "\\";
112 }
113 else
114 {
115 expr += '\\';
116 expr += pszValue[i];
117 }
118 }
119 else {
120 expr += pszValue[i];
121 }
122 }
123 if (nLength > 0) {
124 expr += '$';
125 }
126 expr += "\")";
127 return expr;
128 }
129
FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode * psFilterNode,layerObj * lp)130 static std::string FLTGetIsBetweenComparisonCommonExpresssion(FilterEncodingNode *psFilterNode, layerObj *lp)
131 {
132 if (!psFilterNode || !(strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0))
133 return std::string();
134
135 if (psFilterNode->psLeftNode == NULL || psFilterNode->psRightNode == NULL )
136 return std::string();
137
138 /* -------------------------------------------------------------------- */
139 /* Get the bounds value which are stored like boundmin;boundmax */
140 /* -------------------------------------------------------------------- */
141 int nBounds = 0;
142 char** aszBounds = msStringSplit(psFilterNode->psRightNode->pszValue, ';', &nBounds);
143 if (nBounds != 2) {
144 msFreeCharArray(aszBounds, nBounds);
145 return std::string();
146 }
147
148 /* -------------------------------------------------------------------- */
149 /* check if the value is a numeric value or alphanumeric. If it */
150 /* is alphanumeric, add quotes around attribute and values. */
151 /* -------------------------------------------------------------------- */
152 bool bString = false;
153 bool bDateTime = false;
154 if (aszBounds[0]) {
155 const char* pszType = msOWSLookupMetadata(&(lp->metadata), "OFG",
156 (std::string(psFilterNode->psLeftNode->pszValue)+ "_type").c_str());
157 if (pszType != NULL && (strcasecmp(pszType, "Character") == 0))
158 bString = true;
159 else if (pszType != NULL && (strcasecmp(pszType, "Date") == 0))
160 bDateTime = true;
161 else if (FLTIsNumeric(aszBounds[0]) == MS_FALSE)
162 bString = true;
163 }
164 if (!bString && !bDateTime) {
165 if (aszBounds[1]) {
166 if (FLTIsNumeric(aszBounds[1]) == MS_FALSE)
167 bString = true;
168 }
169 }
170
171 std::string expr;
172 /* -------------------------------------------------------------------- */
173 /* build expresssion. */
174 /* -------------------------------------------------------------------- */
175 /* attribute */
176 if (bString)
177 expr += "(\"[";
178 else
179 expr += "([";
180
181 expr += psFilterNode->psLeftNode->pszValue;
182
183 if (bString)
184 expr += "]\" ";
185 else
186 expr += "] ";
187
188 expr += " >= ";
189
190 if (bString) {
191 expr += '\"';
192 }
193 else if (bDateTime) {
194 expr += '`';
195 }
196
197 {
198 char* pszTmpEscaped = msStringEscape(aszBounds[0]);
199 expr += pszTmpEscaped;
200 if(pszTmpEscaped != aszBounds[0] ) msFree(pszTmpEscaped);
201 }
202
203 if (bString) {
204 expr += '\"';
205 }
206 else if (bDateTime) {
207 expr += '`';
208 }
209
210 expr += " AND ";
211
212 if (bString)
213 expr += " \"[";
214 else
215 expr += " [";
216
217 /* attribute */
218 expr += psFilterNode->psLeftNode->pszValue;
219
220 if (bString)
221 expr += "]\" ";
222 else
223 expr += "] ";
224
225 expr += " <= ";
226
227 if (bString) {
228 expr += '\"';
229 }
230 else if (bDateTime) {
231 expr += '`';
232 }
233
234 {
235 char* pszTmpEscaped = msStringEscape(aszBounds[1]);
236 expr += pszTmpEscaped;
237 if(pszTmpEscaped != aszBounds[1] ) msFree(pszTmpEscaped);
238 }
239
240 if (bString) {
241 expr += '\"';
242 }
243 else if (bDateTime) {
244 expr += '`';
245 }
246 expr += ')';
247
248 msFreeCharArray(aszBounds, nBounds);
249
250 return expr;
251 }
252
FLTGetBinaryComparisonCommonExpression(FilterEncodingNode * psFilterNode,layerObj * lp)253 char *FLTGetBinaryComparisonCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
254 {
255 char szTmp[1024];
256 char *pszExpression = NULL, *pszTmpEscaped;
257 int bString;
258 int bDateTime;
259
260 if (psFilterNode == NULL)
261 return NULL;
262
263 /* -------------------------------------------------------------------- */
264 /* check if the value is a numeric value or alphanumeric. If it */
265 /* is alphanumeric, add quotes around attribute and values. */
266 /* -------------------------------------------------------------------- */
267 bString = 0;
268 bDateTime = 0;
269 if (psFilterNode->psRightNode->pszValue) {
270 const char* pszType;
271 snprintf(szTmp, sizeof(szTmp), "%s_type", psFilterNode->psLeftNode->pszValue);
272 pszType = msOWSLookupMetadata(&(lp->metadata), "OFG", szTmp);
273 if (pszType!= NULL && (strcasecmp(pszType, "Character") == 0))
274 bString = 1;
275 else if (pszType!= NULL && (strcasecmp(pszType, "Date") == 0))
276 bDateTime = 1;
277 else if (FLTIsNumeric(psFilterNode->psRightNode->pszValue) == MS_FALSE)
278 bString = 1;
279 }
280
281 /* specical case to be able to have empty strings in the expression. */
282 /* propertyislike is always treated as string */
283 if (psFilterNode->psRightNode->pszValue == NULL || strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0)
284 bString = 1;
285
286 /* attribute */
287 if (bString)
288 sprintf(szTmp, "%s", "(\"[");
289 else
290 sprintf(szTmp, "%s","([");
291 pszExpression = msStringConcatenate(pszExpression, szTmp);
292 pszExpression = msStringConcatenate(pszExpression, psFilterNode->psLeftNode->pszValue);
293
294 if (bString)
295 sprintf(szTmp, "%s","]\" ");
296 else
297 sprintf(szTmp, "%s", "] ");
298 pszExpression = msStringConcatenate(pszExpression, szTmp);
299
300 if (strcasecmp(psFilterNode->pszValue, "PropertyIsEqualTo") == 0) {
301 /* case insensitive set ? */
302 if (psFilterNode->psRightNode->pOther && (*(int *)psFilterNode->psRightNode->pOther) == 1)
303 sprintf(szTmp, "%s", "=*");
304 else
305 sprintf(szTmp, "%s", "=");
306 } else if (strcasecmp(psFilterNode->pszValue, "PropertyIsNotEqualTo") == 0)
307 sprintf(szTmp, "%s", "!=");
308 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLessThan") == 0)
309 sprintf(szTmp, "%s", "<");
310 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsGreaterThan") == 0)
311 sprintf(szTmp, "%s", ">");
312 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLessThanOrEqualTo") == 0)
313 sprintf(szTmp, "%s", "<=");
314 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsGreaterThanOrEqualTo") == 0)
315 sprintf(szTmp, "%s", ">=");
316 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0)
317 sprintf(szTmp, "%s", "~");
318
319 pszExpression = msStringConcatenate(pszExpression, szTmp);
320 pszExpression = msStringConcatenate(pszExpression, " ");
321
322 /* value */
323 if (bString) {
324 sprintf(szTmp, "%s", "\"");
325 pszExpression = msStringConcatenate(pszExpression, szTmp);
326 }
327 else if (bDateTime) {
328 sprintf(szTmp, "%s", "`");
329 pszExpression = msStringConcatenate(pszExpression, szTmp);
330 }
331
332 if (psFilterNode->psRightNode->pszValue) {
333 pszTmpEscaped = msStringEscape(psFilterNode->psRightNode->pszValue);
334 pszExpression = msStringConcatenate(pszExpression, pszTmpEscaped);
335 if(pszTmpEscaped != psFilterNode->psRightNode->pszValue ) msFree(pszTmpEscaped);
336 }
337
338 if (bString) {
339 sprintf(szTmp, "%s", "\"");
340 pszExpression = msStringConcatenate(pszExpression, szTmp);
341 }
342 else if (bDateTime) {
343 sprintf(szTmp, "%s", "`");
344 pszExpression = msStringConcatenate(pszExpression, szTmp);
345 }
346
347 sprintf(szTmp, "%s", ")");
348 pszExpression = msStringConcatenate(pszExpression, szTmp);
349
350 return pszExpression;
351 }
352
FLTGetLogicalComparisonCommonExpression(FilterEncodingNode * psFilterNode,layerObj * lp)353 char *FLTGetLogicalComparisonCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
354 {
355 char *pszExpression = NULL;
356 char *pszTmp = NULL;
357
358 if (!psFilterNode || !FLTIsLogicalFilterType(psFilterNode->pszValue))
359 return NULL;
360
361 /* -------------------------------------------------------------------- */
362 /* OR and AND */
363 /* -------------------------------------------------------------------- */
364 if (psFilterNode->psLeftNode && psFilterNode->psRightNode) {
365 pszTmp = FLTGetCommonExpression(psFilterNode->psLeftNode, lp);
366 if (!pszTmp)
367 return NULL;
368
369 pszExpression = msStringConcatenate(pszExpression, "(");
370
371 pszExpression = msStringConcatenate(pszExpression, pszTmp);
372 msFree(pszTmp);
373
374 pszExpression = msStringConcatenate(pszExpression, " ");
375
376 pszExpression = msStringConcatenate(pszExpression, psFilterNode->pszValue);
377
378 pszExpression = msStringConcatenate(pszExpression, " ");
379
380 pszTmp = FLTGetCommonExpression(psFilterNode->psRightNode, lp);
381 if (!pszTmp) {
382 msFree(pszExpression);
383 return NULL;
384 }
385
386 pszExpression = msStringConcatenate(pszExpression, pszTmp);
387 msFree(pszTmp);
388
389 pszExpression = msStringConcatenate(pszExpression, ")");
390 }
391 /* -------------------------------------------------------------------- */
392 /* NOT */
393 /* -------------------------------------------------------------------- */
394 else if (psFilterNode->psLeftNode && strcasecmp(psFilterNode->pszValue, "NOT") == 0) {
395 pszTmp = FLTGetCommonExpression(psFilterNode->psLeftNode, lp);
396 if (!pszTmp)
397 return NULL;
398
399 pszExpression = msStringConcatenate(pszExpression, "(NOT ");
400
401 pszExpression = msStringConcatenate(pszExpression, pszTmp);
402 msFree(pszTmp);
403
404 pszExpression = msStringConcatenate(pszExpression, ")");
405 }
406
407 return pszExpression;
408 }
409
FLTGetSpatialComparisonCommonExpression(FilterEncodingNode * psNode,layerObj * lp)410 char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerObj *lp)
411 {
412 char *pszExpression = NULL;
413 shapeObj *psQueryShape = NULL;
414 double dfDistance = -1;
415 int nUnit = -1, nLayerUnit = -1;
416 char *pszWktText = NULL;
417 char szBuffer[256];
418 char *pszTmp=NULL;
419 projectionObj sProjTmp;
420 rectObj sQueryRect;
421 shapeObj *psTmpShape=NULL;
422 int bBBoxQuery = 0;
423 int bAlreadyReprojected = 0;
424
425 if (psNode == NULL || lp == NULL)
426 return NULL;
427
428 if (psNode->eType != FILTER_NODE_TYPE_SPATIAL)
429 return NULL;
430
431 /* get the shape */
432 if (FLTIsBBoxFilter(psNode)) {
433 char szPolygon[512];
434 FLTGetBBOX(psNode, &sQueryRect);
435
436 snprintf(szPolygon, sizeof(szPolygon),
437 "POLYGON((%.18f %.18f,%.18f %.18f,%.18f %.18f,%.18f %.18f,%.18f %.18f))",
438 sQueryRect.minx, sQueryRect.miny,
439 sQueryRect.minx, sQueryRect.maxy,
440 sQueryRect.maxx, sQueryRect.maxy,
441 sQueryRect.maxx, sQueryRect.miny,
442 sQueryRect.minx, sQueryRect.miny);
443
444 psTmpShape = msShapeFromWKT(szPolygon);
445
446 /*
447 ** This is a horrible hack to deal with world-extent requests and
448 ** reprojection. msProjectRect() detects if reprojection from longlat to
449 ** projected SRS, and in that case it transforms the bbox to -1e-15,-1e-15,1e15,1e15
450 ** to ensure that all features are returned.
451 **
452 ** Make wfs_200_cite_filter_bbox_world.xml and wfs_200_cite_postgis_bbox_world.xml pass
453 */
454 if (fabs(sQueryRect.minx - -180.0) < 1e-5 &&
455 fabs(sQueryRect.miny - -90.0) < 1e-5 &&
456 fabs(sQueryRect.maxx - 180.0) < 1e-5 &&
457 fabs(sQueryRect.maxy - 90.0) < 1e-5)
458 {
459 if (lp->projection.numargs > 0) {
460 if (psNode->pszSRS) {
461 msInitProjection(&sProjTmp);
462 msProjectionInheritContextFrom(&sProjTmp, &lp->projection);
463 }
464 if (psNode->pszSRS) {
465 /* Use the non EPSG variant since axis swapping is done in FLTDoAxisSwappingIfNecessary */
466 if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) {
467 msProjectRect(&sProjTmp, &lp->projection, &sQueryRect);
468 }
469 } else if (lp->map->projection.numargs > 0)
470 msProjectRect(&lp->map->projection, &lp->projection, &sQueryRect);
471 if (psNode->pszSRS)
472 msFreeProjection(&sProjTmp);
473 }
474 if (sQueryRect.minx <= -1e14) {
475 msFreeShape(psTmpShape);
476 msFree(psTmpShape);
477 psTmpShape = (shapeObj*) msSmallMalloc(sizeof(shapeObj));
478 msInitShape(psTmpShape);
479 msRectToPolygon(sQueryRect, psTmpShape);
480 bAlreadyReprojected = 1;
481 }
482 }
483
484 bBBoxQuery = 1;
485 } else {
486 /* other geos type operations */
487
488 /* project shape to layer projection. If the proj is not part of the filter query,
489 assume that the cooredinates are in the map projection */
490
491 psQueryShape = FLTGetShape(psNode, &dfDistance, &nUnit);
492
493 if ((strcasecmp(psNode->pszValue, "DWithin") == 0 || strcasecmp(psNode->pszValue, "Beyond") == 0 ) && dfDistance > 0) {
494 nLayerUnit = lp->units;
495 if(nLayerUnit == -1) nLayerUnit = GetMapserverUnitUsingProj(&lp->projection);
496 if(nLayerUnit == -1) nLayerUnit = lp->map->units;
497 if(nLayerUnit == -1) nLayerUnit = GetMapserverUnitUsingProj(&lp->map->projection);
498
499 if (nUnit >= 0 && nUnit != nLayerUnit)
500 dfDistance *= msInchesPerUnit(nUnit,0)/msInchesPerUnit(nLayerUnit,0); /* target is layer units */
501 }
502
503 psTmpShape = psQueryShape;
504 }
505
506 if (psTmpShape) {
507
508 /*
509 ** target is layer projection
510 */
511 if (!bAlreadyReprojected && lp->projection.numargs > 0) {
512 if (psNode->pszSRS) {
513 msInitProjection(&sProjTmp);
514 msProjectionInheritContextFrom(&sProjTmp, &lp->projection);
515 }
516 if (psNode->pszSRS) {
517 /* Use the non EPSG variant since axis swapping is done in FLTDoAxisSwappingIfNecessary */
518 if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) {
519 msProjectShape(&sProjTmp, &lp->projection, psTmpShape);
520 }
521 } else if (lp->map->projection.numargs > 0)
522 msProjectShape(&lp->map->projection, &lp->projection, psTmpShape);
523 if (psNode->pszSRS)
524 msFreeProjection(&sProjTmp);
525 }
526
527 /* function name */
528 if (bBBoxQuery) {
529 sprintf(szBuffer, "%s", "intersects");
530 } else {
531 if (strncasecmp(psNode->pszValue, "intersect", 9) == 0)
532 sprintf(szBuffer, "%s", "intersects");
533 else {
534 pszTmp = msStrdup(psNode->pszValue);
535 msStringToLower(pszTmp);
536 sprintf(szBuffer, "%s", pszTmp);
537 msFree(pszTmp);
538 }
539 }
540 pszExpression = msStringConcatenate(pszExpression, szBuffer);
541 pszExpression = msStringConcatenate(pszExpression, "(");
542
543 /* geometry binding */
544 sprintf(szBuffer, "%s", "[shape]");
545 pszExpression = msStringConcatenate(pszExpression, szBuffer);
546 pszExpression = msStringConcatenate(pszExpression, ",");
547
548 /* filter geometry */
549 pszWktText = msGEOSShapeToWKT(psTmpShape);
550 sprintf(szBuffer, "%s", "fromText('");
551 pszExpression = msStringConcatenate(pszExpression, szBuffer);
552 pszExpression = msStringConcatenate(pszExpression, pszWktText);
553 sprintf(szBuffer, "%s", "')");
554 pszExpression = msStringConcatenate(pszExpression, szBuffer);
555 msGEOSFreeWKT(pszWktText);
556
557 /* (optional) beyond/dwithin distance, always 0.0 since we apply the distance as a buffer earlier */
558 if ((strcasecmp(psNode->pszValue, "DWithin") == 0 || strcasecmp(psNode->pszValue, "Beyond") == 0)) {
559 // pszExpression = msStringConcatenate(pszExpression, ",0.0");
560 sprintf(szBuffer, ",%g", dfDistance);
561 pszExpression = msStringConcatenate(pszExpression, szBuffer);
562 }
563
564 /* terminate the function */
565 pszExpression = msStringConcatenate(pszExpression, ") = TRUE");
566 }
567
568 /*
569 ** Cleanup
570 */
571 if (bBBoxQuery) {
572 msFreeShape(psTmpShape);
573 msFree(psTmpShape);
574 }
575
576 return pszExpression;
577 }
578
FLTGetFeatureIdCommonExpression(FilterEncodingNode * psFilterNode,layerObj * lp)579 char *FLTGetFeatureIdCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
580 {
581 char *pszExpression = NULL;
582 int nTokens = 0, i=0, bString=0;
583 char **tokens = NULL;
584 const char *pszAttribute=NULL;
585
586 #if defined(USE_WMS_SVR) || defined(USE_WFS_SVR) || defined(USE_WCS_SVR) || defined(USE_SOS_SVR)
587 if (psFilterNode->pszValue) {
588 pszAttribute = msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid");
589 if (pszAttribute) {
590 tokens = msStringSplit(psFilterNode->pszValue,',', &nTokens);
591 if (tokens && nTokens > 0) {
592 for (i=0; i<nTokens; i++) {
593 char *pszTmp = NULL;
594 int bufferSize = 0;
595 const char* pszId = tokens[i];
596 const char* pszDot = strrchr(pszId, '.');
597 if( pszDot )
598 pszId = pszDot + 1;
599
600 if (i == 0) {
601 if(FLTIsNumeric(pszId) == MS_FALSE)
602 bString = 1;
603 }
604
605 if (bString) {
606 bufferSize = 11+strlen(pszId)+strlen(pszAttribute)+1;
607 pszTmp = (char *)msSmallMalloc(bufferSize);
608 snprintf(pszTmp, bufferSize, "(\"[%s]\" ==\"%s\")" , pszAttribute, pszId);
609 } else {
610 bufferSize = 8+strlen(pszId)+strlen(pszAttribute)+1;
611 pszTmp = (char *)msSmallMalloc(bufferSize);
612 snprintf(pszTmp, bufferSize, "([%s] == %s)" , pszAttribute, pszId);
613 }
614
615 if (pszExpression != NULL)
616 pszExpression = msStringConcatenate(pszExpression, " OR ");
617 else
618 pszExpression = msStringConcatenate(pszExpression, "(");
619 pszExpression = msStringConcatenate(pszExpression, pszTmp);
620 msFree(pszTmp);
621 }
622
623 msFreeCharArray(tokens, nTokens);
624 }
625 }
626
627 /* opening and closing brackets are needed for mapserver expressions */
628 if (pszExpression)
629 pszExpression = msStringConcatenate(pszExpression, ")");
630 }
631 #endif
632
633 return pszExpression;
634 }
635
FLTGetTimeExpression(FilterEncodingNode * psFilterNode,layerObj * lp)636 char* FLTGetTimeExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
637 {
638 char* pszExpression = NULL;
639 const char* pszTimeField;
640 const char* pszTimeValue;
641
642 if (psFilterNode == NULL || lp == NULL)
643 return NULL;
644
645 if (psFilterNode->eType != FILTER_NODE_TYPE_TEMPORAL)
646 return NULL;
647
648 pszTimeValue = FLTGetDuring(psFilterNode, &pszTimeField);
649 if (pszTimeField && pszTimeValue) {
650 expressionObj old_filter;
651 msInitExpression(&old_filter);
652 msCopyExpression(&old_filter, &lp->filter); /* save existing filter */
653 msFreeExpression(&lp->filter);
654 if (msLayerSetTimeFilter(lp, pszTimeValue, pszTimeField) == MS_TRUE) {
655 pszExpression = msStrdup(lp->filter.string);
656 }
657 msCopyExpression(&lp->filter, &old_filter); /* restore old filter */
658 msFreeExpression(&old_filter);
659 }
660 return pszExpression;
661 }
662
FLTGetCommonExpression(FilterEncodingNode * psFilterNode,layerObj * lp)663 char *FLTGetCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
664 {
665 char *pszExpression = NULL;
666
667 if (!psFilterNode)
668 return NULL;
669
670 if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON) {
671 if ( psFilterNode->psLeftNode && psFilterNode->psRightNode) {
672 if (FLTIsBinaryComparisonFilterType(psFilterNode->pszValue))
673 pszExpression = FLTGetBinaryComparisonCommonExpression(psFilterNode, lp);
674 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0)
675 pszExpression = msStrdup(FLTGetIsLikeComparisonCommonExpression(psFilterNode).c_str());
676 else if (strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0)
677 pszExpression = msStrdup(FLTGetIsBetweenComparisonCommonExpresssion(psFilterNode, lp).c_str());
678 }
679 } else if (psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL) {
680 pszExpression = FLTGetLogicalComparisonCommonExpression(psFilterNode, lp);
681 } else if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL) {
682 pszExpression = FLTGetSpatialComparisonCommonExpression(psFilterNode, lp);
683 } else if (psFilterNode->eType == FILTER_NODE_TYPE_FEATUREID) {
684 pszExpression = FLTGetFeatureIdCommonExpression(psFilterNode, lp);
685 } else if (psFilterNode->eType == FILTER_NODE_TYPE_TEMPORAL) {
686 pszExpression = FLTGetTimeExpression(psFilterNode, lp);
687 }
688
689 return pszExpression;
690 }
691
FLTApplyFilterToLayerCommonExpression(mapObj * map,int iLayerIndex,const char * pszExpression)692 int FLTApplyFilterToLayerCommonExpression(mapObj *map, int iLayerIndex, const char *pszExpression)
693 {
694 return FLTApplyFilterToLayerCommonExpressionWithRect(map, iLayerIndex, pszExpression, map->extent);
695 }
696
697 /* rect must be in map->projection */
FLTApplyFilterToLayerCommonExpressionWithRect(mapObj * map,int iLayerIndex,const char * pszExpression,rectObj rect)698 int FLTApplyFilterToLayerCommonExpressionWithRect(mapObj *map, int iLayerIndex, const char *pszExpression, rectObj rect)
699 {
700 int retval;
701 int save_startindex;
702 int save_maxfeatures;
703 int save_only_cache_result_count;
704 int save_cache_shapes;
705 int save_max_cached_shape_count;
706 int save_max_cached_shape_ram_amount;
707
708 save_startindex = map->query.startindex;
709 save_maxfeatures = map->query.maxfeatures;
710 save_only_cache_result_count = map->query.only_cache_result_count;
711 save_cache_shapes = map->query.cache_shapes;
712 save_max_cached_shape_count = map->query.max_cached_shape_count;
713 save_max_cached_shape_ram_amount = map->query.max_cached_shape_ram_amount;
714 msInitQuery(&(map->query));
715 map->query.startindex = save_startindex;
716 map->query.maxfeatures = save_maxfeatures;
717 map->query.only_cache_result_count = save_only_cache_result_count;
718 map->query.cache_shapes = save_cache_shapes;
719 map->query.max_cached_shape_count = save_max_cached_shape_count;
720 map->query.max_cached_shape_ram_amount = save_max_cached_shape_ram_amount;
721
722 map->query.mode = MS_QUERY_MULTIPLE;
723 map->query.layer = iLayerIndex;
724
725 map->query.rect = rect;
726
727 if( pszExpression )
728 {
729 map->query.type = MS_QUERY_BY_FILTER;
730 msInitExpression(&map->query.filter);
731 map->query.filter.string = msStrdup(pszExpression);
732 map->query.filter.type = MS_EXPRESSION; /* a logical expression */
733
734 retval = msQueryByFilter(map);
735 }
736 else
737 {
738 map->query.type = MS_QUERY_BY_RECT;
739 retval = msQueryByRect(map);
740 }
741
742 return retval;
743 }
744