1 : /******************************************************************************
2 : * $Id: ogrwfsfilter.cpp 24791 2012-08-15 20:48:55Z rouault $
3 : *
4 : * Project: WFS Translator
5 : * Purpose: Implements OGR SQL into OGC Filter translation.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash paris dot org>
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
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR 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 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_wfs.h"
31 :
32 : #include "cpl_list.h"
33 :
34 : CPL_CVSID("$Id: ogrwfsfilter.cpp 24791 2012-08-15 20:48:55Z rouault $");
35 :
36 : typedef enum
37 : {
38 : TOKEN_GREATER_OR_EQUAL,
39 : TOKEN_GREATER,
40 : TOKEN_LESSER_OR_EQUAL,
41 : TOKEN_LESSER,
42 : TOKEN_LIKE,
43 : TOKEN_EQUAL,
44 : TOKEN_NOT_EQUAL,
45 : TOKEN_NOT,
46 : TOKEN_AND,
47 : TOKEN_OR,
48 : TOKEN_VAR_NAME,
49 : TOKEN_LITERAL
50 : } TokenType;
51 :
52 : typedef struct _Expr Expr;
53 :
54 : struct _Expr
55 : {
56 : TokenType eType;
57 : char* pszVal;
58 : Expr* expr1;
59 : Expr* expr2;
60 : };
61 :
62 : /************************************************************************/
63 : /* WFS_ExprGetPriority() */
64 : /************************************************************************/
65 :
66 94 : static int WFS_ExprGetPriority(const Expr* expr)
67 : {
68 94 : if (expr->eType == TOKEN_NOT)
69 0 : return 9;
70 94 : else if (expr->eType == TOKEN_GREATER_OR_EQUAL ||
71 : expr->eType == TOKEN_GREATER ||
72 : expr->eType == TOKEN_LESSER_OR_EQUAL ||
73 : expr->eType == TOKEN_LESSER)
74 14 : return 6;
75 80 : else if (expr->eType == TOKEN_EQUAL ||
76 : expr->eType == TOKEN_LIKE ||
77 : expr->eType == TOKEN_NOT_EQUAL)
78 24 : return 5;
79 56 : else if (expr->eType == TOKEN_AND)
80 30 : return 4;
81 26 : else if (expr->eType == TOKEN_OR)
82 26 : return 3;
83 : else
84 0 : return 0;
85 : }
86 :
87 : /************************************************************************/
88 : /* WFS_ExprFree() */
89 : /************************************************************************/
90 :
91 198 : static void WFS_ExprFree(Expr* expr)
92 : {
93 198 : if (expr == NULL) return;
94 198 : if (expr->expr1)
95 60 : WFS_ExprFree(expr->expr1);
96 198 : if (expr->expr2)
97 60 : WFS_ExprFree(expr->expr2);
98 198 : CPLFree(expr->pszVal);
99 198 : CPLFree(expr);
100 : }
101 :
102 : /************************************************************************/
103 : /* WFS_ExprFreeList() */
104 : /************************************************************************/
105 :
106 0 : static void WFS_ExprFreeList(CPLList* psExprList)
107 : {
108 0 : CPLList* psIterList = psExprList;
109 0 : while(psIterList)
110 : {
111 0 : WFS_ExprFree((Expr*)psIterList->pData);
112 0 : psIterList = psIterList->psNext;
113 : }
114 0 : CPLListDestroy(psExprList);
115 0 : }
116 :
117 : /************************************************************************/
118 : /* WFS_ExprBuildVarName() */
119 : /************************************************************************/
120 :
121 39 : static Expr* WFS_ExprBuildVarName(const char* pszVal)
122 : {
123 39 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
124 39 : expr->eType = TOKEN_VAR_NAME;
125 39 : expr->pszVal = CPLStrdup(pszVal);
126 39 : return expr;
127 : }
128 :
129 : /************************************************************************/
130 : /* WFS_ExprBuildValue() */
131 : /************************************************************************/
132 :
133 39 : static Expr* WFS_ExprBuildValue(const char* pszVal)
134 : {
135 39 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
136 39 : expr->eType = TOKEN_LITERAL;
137 39 : expr->pszVal = CPLStrdup(pszVal);
138 39 : return expr;
139 : }
140 :
141 : /************************************************************************/
142 : /* WFS_ExprBuildOperator() */
143 : /************************************************************************/
144 :
145 60 : static Expr* WFS_ExprBuildOperator(TokenType eType)
146 : {
147 60 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
148 60 : expr->eType = eType;
149 60 : return expr;
150 : }
151 :
152 : /************************************************************************/
153 : /* WFS_ExprBuildBinary() */
154 : /************************************************************************/
155 :
156 60 : static Expr* WFS_ExprBuildBinary(TokenType eType, Expr* expr1, Expr* expr2)
157 : {
158 60 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
159 60 : expr->eType = eType;
160 60 : expr->expr1 = expr1;
161 60 : expr->expr2 = expr2;
162 60 : return expr;
163 : }
164 :
165 : #ifdef notdef
166 :
167 : /************************************************************************/
168 : /* WFS_ExprDump() */
169 : /************************************************************************/
170 :
171 : static void WFS_ExprDump(FILE* fp, const Expr* expr)
172 : {
173 : switch(expr->eType)
174 : {
175 : case TOKEN_VAR_NAME:
176 : case TOKEN_LITERAL:
177 : fprintf(fp, "%s", expr->pszVal);
178 : break;
179 :
180 : case TOKEN_NOT:
181 : fprintf(fp, "NOT (");
182 : WFS_ExprDump(fp, expr->expr1);
183 : fprintf(fp, ")");
184 : break;
185 :
186 : default:
187 : fprintf(fp, "(");
188 : WFS_ExprDump(fp, expr->expr1);
189 : switch(expr->eType)
190 : {
191 : case TOKEN_EQUAL: fprintf(fp, " = "); break;
192 : case TOKEN_LIKE: fprintf(fp, " LIKE "); break;
193 : case TOKEN_NOT_EQUAL: fprintf(fp, " != "); break;
194 : case TOKEN_LESSER_OR_EQUAL: fprintf(fp, " <= "); break;
195 : case TOKEN_LESSER: fprintf(fp, " < "); break;
196 : case TOKEN_GREATER_OR_EQUAL:fprintf(fp, " >= "); break;
197 : case TOKEN_GREATER: fprintf(fp, " > "); break;
198 : case TOKEN_AND: fprintf(fp, " AND "); break;
199 : case TOKEN_OR: fprintf(fp, " OR "); break;
200 : default: break;
201 : }
202 : WFS_ExprDump(fp, expr->expr2);
203 : fprintf(fp, ")");
204 : break;
205 : }
206 : }
207 : #endif
208 :
209 : /************************************************************************/
210 : /* WFS_ExprDumpGmlObjectIdFilter() */
211 : /************************************************************************/
212 :
213 31 : static int WFS_ExprDumpGmlObjectIdFilter(CPLString& osFilter,
214 : const Expr* expr,
215 : int bUseFeatureId,
216 : int bGmlObjectIdNeedsGMLPrefix,
217 : int nVersion)
218 : {
219 31 : if (expr->eType == TOKEN_EQUAL &&
220 : expr->expr1->eType == TOKEN_VAR_NAME &&
221 : EQUAL(expr->expr1->pszVal, "gml_id") &&
222 : expr->expr2->eType == TOKEN_LITERAL)
223 : {
224 9 : if (bUseFeatureId)
225 0 : osFilter += "<FeatureId fid=\"";
226 9 : else if (nVersion >= 200)
227 2 : osFilter += "<ResourceId rid=\"";
228 7 : else if (!bGmlObjectIdNeedsGMLPrefix)
229 1 : osFilter += "<GmlObjectId id=\"";
230 : else
231 6 : osFilter += "<GmlObjectId gml:id=\"";
232 18 : if (expr->expr2->pszVal[0] == '\'' || expr->expr2->pszVal[0] == '"')
233 : {
234 9 : CPLString osVal(expr->expr2->pszVal + 1);
235 9 : osVal.resize(osVal.size() - 1);
236 9 : osFilter += osVal;
237 : }
238 : else
239 0 : osFilter += expr->expr2->pszVal;
240 9 : osFilter += "\"/>";
241 9 : return TRUE;
242 : }
243 22 : else if (expr->eType == TOKEN_OR)
244 : {
245 : return WFS_ExprDumpGmlObjectIdFilter(osFilter, expr->expr1,
246 : bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion) &&
247 : WFS_ExprDumpGmlObjectIdFilter(osFilter, expr->expr2,
248 11 : bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion);
249 : }
250 11 : return FALSE;
251 : }
252 :
253 : /************************************************************************/
254 : /* WFS_ExprDumpAsOGCFilter() */
255 : /************************************************************************/
256 :
257 : typedef struct
258 : {
259 : int nVersion;
260 : int bPropertyIsNotEqualToSupported;
261 : int bOutNeedsNullCheck;
262 : OGRFeatureDefn* poFDefn;
263 : } ExprDumpFilterOptions;
264 :
265 103 : static int WFS_ExprDumpAsOGCFilter(CPLString& osFilter,
266 : const Expr* expr,
267 : int bExpectBinary,
268 : ExprDumpFilterOptions* psOptions)
269 : {
270 103 : switch(expr->eType)
271 : {
272 : case TOKEN_VAR_NAME:
273 : {
274 30 : if (bExpectBinary)
275 0 : return FALSE;
276 :
277 : /* Special fields not understood by server */
278 30 : if (EQUAL(expr->pszVal, "gml_id") ||
279 : EQUAL(expr->pszVal, "FID") ||
280 : EQUAL(expr->pszVal, "OGR_GEOMETRY") ||
281 : EQUAL(expr->pszVal, "OGR_GEOM_WKT") ||
282 : EQUAL(expr->pszVal, "OGR_GEOM_AREA") ||
283 : EQUAL(expr->pszVal, "OGR_STYLE"))
284 : {
285 2 : CPLDebug("WFS", "Attribute refers to a OGR special field. Cannot use server-side filtering");
286 2 : return FALSE;
287 : }
288 :
289 : const char* pszFieldname;
290 28 : CPLString osVal;
291 28 : if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"')
292 : {
293 0 : osVal = expr->pszVal + 1;
294 0 : osVal.resize(osVal.size() - 1);
295 0 : pszFieldname = osVal.c_str();
296 : }
297 : else
298 28 : pszFieldname = expr->pszVal;
299 :
300 28 : if (psOptions->poFDefn->GetFieldIndex(pszFieldname) == -1)
301 : {
302 : CPLDebug("WFS", "Field '%s' unknown. Cannot use server-side filtering",
303 2 : pszFieldname);
304 2 : return FALSE;
305 : }
306 :
307 26 : if (psOptions->nVersion >= 200)
308 4 : osFilter += "<ValueReference>";
309 : else
310 22 : osFilter += "<PropertyName>";
311 26 : char* pszFieldnameXML = CPLEscapeString(pszFieldname, -1, CPLES_XML);
312 26 : osFilter += pszFieldnameXML;
313 26 : CPLFree(pszFieldnameXML);
314 26 : if (psOptions->nVersion >= 200)
315 4 : osFilter += "</ValueReference>";
316 : else
317 22 : osFilter += "</PropertyName>";
318 0 : break;
319 : }
320 :
321 : case TOKEN_LITERAL:
322 : {
323 24 : if (bExpectBinary)
324 0 : return FALSE;
325 :
326 : const char* pszLiteral;
327 24 : CPLString osVal;
328 27 : if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"')
329 : {
330 3 : osVal = expr->pszVal + 1;
331 3 : osVal.resize(osVal.size() - 1);
332 3 : pszLiteral = osVal.c_str();
333 : }
334 : else
335 21 : pszLiteral = expr->pszVal;
336 :
337 24 : osFilter += "<Literal>";
338 24 : char* pszLiteralXML = CPLEscapeString(pszLiteral, -1, CPLES_XML);
339 24 : osFilter += pszLiteralXML;
340 24 : CPLFree(pszLiteralXML);
341 24 : osFilter += "</Literal>";
342 :
343 24 : break;
344 : }
345 :
346 : case TOKEN_NOT:
347 0 : osFilter += "<Not>";
348 0 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions))
349 0 : return FALSE;
350 0 : osFilter += "</Not>";
351 0 : break;
352 :
353 : case TOKEN_LIKE:
354 : {
355 1 : CPLString osVal;
356 : char ch;
357 1 : char firstCh = 0;
358 : int i;
359 1 : if (psOptions->nVersion == 100)
360 0 : osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escape='!'>";
361 : else
362 1 : osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escapeChar='!'>";
363 1 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
364 0 : return FALSE;
365 1 : if (expr->expr2->eType != TOKEN_LITERAL)
366 0 : return FALSE;
367 1 : osFilter += "<Literal>";
368 :
369 : /* Escape value according to above special characters */
370 : /* For URL compatibility reason, we remap the OGR SQL '%' wildchard into '*' */
371 1 : i = 0;
372 1 : ch = expr->expr2->pszVal[i];
373 1 : if (ch == '\'' || ch == '"')
374 : {
375 1 : firstCh = ch;
376 1 : i ++;
377 : }
378 8 : for(;(ch = expr->expr2->pszVal[i]) != '\0';i++)
379 : {
380 8 : if (ch == '%')
381 2 : osVal += "*";
382 6 : else if (ch == '!')
383 0 : osVal += "!!";
384 6 : else if (ch == '*')
385 0 : osVal += "!*";
386 6 : else if (ch == firstCh && expr->expr2->pszVal[i + 1] == 0)
387 1 : break;
388 : else
389 : {
390 : char ach[2];
391 5 : ach[0] = ch;
392 5 : ach[1] = 0;
393 5 : osVal += ach;
394 : }
395 : }
396 1 : osFilter += osVal;
397 1 : osFilter += "</Literal>";
398 1 : osFilter += "</PropertyIsLike>";
399 0 : break;
400 : }
401 :
402 : case TOKEN_EQUAL:
403 : case TOKEN_NOT_EQUAL:
404 : case TOKEN_LESSER_OR_EQUAL:
405 : case TOKEN_LESSER:
406 : case TOKEN_GREATER_OR_EQUAL:
407 : case TOKEN_GREATER:
408 : {
409 29 : if (expr->eType == TOKEN_EQUAL && expr->expr2->eType == TOKEN_LITERAL &&
410 : EQUAL(expr->expr2->pszVal, "NULL"))
411 : {
412 0 : osFilter += "<PropertyIsNull>";
413 0 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
414 0 : return FALSE;
415 0 : osFilter += "</PropertyIsNull>";
416 0 : psOptions->bOutNeedsNullCheck = TRUE;
417 0 : break;
418 : }
419 29 : if (expr->eType == TOKEN_NOT_EQUAL && expr->expr2->eType == TOKEN_LITERAL &&
420 : EQUAL(expr->expr2->pszVal, "NULL"))
421 : {
422 1 : osFilter += "<Not><PropertyIsNull>";
423 1 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
424 0 : return FALSE;
425 1 : osFilter += "</PropertyIsNull></Not>";
426 1 : psOptions->bOutNeedsNullCheck = TRUE;
427 1 : break;
428 : }
429 28 : TokenType eType = expr->eType;
430 28 : int bAddClosingNot = FALSE;
431 28 : if (!psOptions->bPropertyIsNotEqualToSupported && eType == TOKEN_NOT_EQUAL)
432 : {
433 2 : osFilter += "<Not>";
434 2 : eType = TOKEN_EQUAL;
435 2 : bAddClosingNot = TRUE;
436 : }
437 :
438 28 : const char* pszName = NULL;
439 28 : switch(eType)
440 : {
441 15 : case TOKEN_EQUAL: pszName = "PropertyIsEqualTo"; break;
442 4 : case TOKEN_NOT_EQUAL: pszName = "PropertyIsNotEqualTo"; break;
443 4 : case TOKEN_LESSER_OR_EQUAL: pszName = "PropertyIsLessThanOrEqualTo"; break;
444 0 : case TOKEN_LESSER: pszName = "PropertyIsLessThan"; break;
445 5 : case TOKEN_GREATER_OR_EQUAL:pszName = "PropertyIsGreaterThanOrEqualTo"; break;
446 0 : case TOKEN_GREATER: pszName = "PropertyIsGreaterThan"; break;
447 : default: break;
448 : }
449 28 : osFilter += "<";
450 28 : osFilter += pszName;
451 28 : osFilter += ">";
452 28 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
453 4 : return FALSE;
454 24 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, FALSE, psOptions))
455 0 : return FALSE;
456 24 : osFilter += "</";
457 24 : osFilter += pszName;
458 24 : osFilter += ">";
459 24 : if (bAddClosingNot)
460 2 : osFilter += "</Not>";
461 24 : break;
462 : }
463 :
464 : case TOKEN_AND:
465 : case TOKEN_OR:
466 : {
467 19 : const char* pszName = (expr->eType == TOKEN_AND) ? "And" : "Or";
468 19 : osFilter += "<";
469 19 : osFilter += pszName;
470 19 : osFilter += ">";
471 19 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions))
472 0 : return FALSE;
473 19 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, TRUE, psOptions))
474 0 : return FALSE;
475 19 : osFilter += "</";
476 19 : osFilter += pszName;
477 19 : osFilter += ">";
478 :
479 19 : break;
480 : }
481 :
482 : default:
483 0 : return FALSE;
484 : }
485 :
486 95 : return TRUE;
487 : }
488 :
489 : /************************************************************************/
490 : /* WFS_ExprBuildInternal() */
491 : /************************************************************************/
492 :
493 : typedef struct
494 : {
495 : int bExpectVarName;
496 : int bExpectComparisonOperator;
497 : int bExpectLogicalOperator;
498 : int bExpectValue;
499 : int nParenthesisLevel;
500 : } ExprBuildContext;
501 :
502 22 : static Expr* WFS_ExprBuildInternal(char*** ppapszTokens,
503 : ExprBuildContext* psBuildContext)
504 : {
505 22 : Expr* expr = NULL;
506 22 : Expr* op = NULL;
507 22 : Expr* val1 = NULL;
508 22 : Expr* val2 = NULL;
509 22 : CPLList* psValExprList = NULL;
510 22 : CPLList* psOpExprList = NULL;
511 22 : char** papszTokens = *ppapszTokens;
512 22 : char* pszToken = NULL;
513 :
514 : #define PEEK_OP(my_op) my_op = (Expr*)CPLListGetData(psOpExprList)
515 : #define PUSH_OP(my_op) psOpExprList = CPLListInsert(psOpExprList, my_op, 0)
516 : #define POP_OP(my_op) do { my_op = (Expr*)CPLListGetData(psOpExprList); \
517 : if (my_op != NULL) { \
518 : CPLList* psNext = psOpExprList->psNext; \
519 : CPLFree(psOpExprList); \
520 : psOpExprList = psNext; \
521 : } \
522 : } while(0)
523 : #define PUSH_VAL(my_val) psValExprList = CPLListInsert(psValExprList, my_val, 0)
524 : #define POP_VAL(my_val) do { my_val = (Expr*)CPLListGetData(psValExprList); \
525 : if (my_val != NULL) { \
526 : CPLList* psNext = psValExprList->psNext; \
527 : CPLFree(psValExprList); \
528 : psValExprList = psNext; \
529 : } \
530 : } while(0)
531 138 : while(TRUE)
532 : {
533 160 : pszToken = *papszTokens;
534 160 : if (pszToken == NULL)
535 14 : break;
536 146 : papszTokens ++;
537 :
538 146 : if (EQUAL(pszToken, "("))
539 : {
540 4 : char** papszSub = papszTokens;
541 4 : psBuildContext->nParenthesisLevel ++;
542 4 : Expr* expr = WFS_ExprBuildInternal(&papszSub, psBuildContext);
543 4 : psBuildContext->nParenthesisLevel --;
544 4 : if (expr == NULL)
545 0 : goto invalid_expr;
546 4 : PUSH_VAL(expr);
547 4 : papszTokens = papszSub;
548 4 : if (*papszTokens == NULL)
549 4 : break;
550 :
551 0 : continue;
552 : }
553 142 : else if (EQUAL(pszToken, ")"))
554 : {
555 4 : if (psBuildContext->nParenthesisLevel > 0)
556 4 : break;
557 : else
558 0 : goto invalid_expr;
559 : }
560 :
561 138 : if (psBuildContext->bExpectVarName)
562 : {
563 39 : if (EQUAL(pszToken, "NOT"))
564 0 : op = WFS_ExprBuildOperator(TOKEN_NOT);
565 : else
566 : {
567 39 : PUSH_VAL(WFS_ExprBuildVarName(pszToken));
568 39 : psBuildContext->bExpectVarName = FALSE;
569 39 : psBuildContext->bExpectComparisonOperator = TRUE;
570 : }
571 : }
572 99 : else if (psBuildContext->bExpectComparisonOperator)
573 : {
574 39 : psBuildContext->bExpectComparisonOperator = FALSE;
575 39 : psBuildContext->bExpectValue = TRUE;
576 39 : if (EQUAL(pszToken, "IS"))
577 : {
578 2 : if (*papszTokens != NULL && EQUAL(*papszTokens, "NOT"))
579 : {
580 1 : op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL);
581 1 : papszTokens ++;
582 : }
583 : else
584 0 : op = WFS_ExprBuildOperator(TOKEN_EQUAL);
585 : }
586 38 : else if (EQUAL(pszToken, "="))
587 22 : op = WFS_ExprBuildOperator(TOKEN_EQUAL);
588 17 : else if (EQUAL(pszToken, "LIKE") || EQUAL(pszToken, "ILIKE"))
589 1 : op = WFS_ExprBuildOperator(TOKEN_LIKE);
590 21 : else if (EQUAL(pszToken, "!=") || EQUAL(pszToken, "<>"))
591 6 : op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL);
592 9 : else if (EQUAL(pszToken, "<"))
593 0 : op = WFS_ExprBuildOperator(TOKEN_LESSER);
594 9 : else if (EQUAL(pszToken, "<="))
595 4 : op = WFS_ExprBuildOperator(TOKEN_LESSER_OR_EQUAL);
596 5 : else if (EQUAL(pszToken, ">"))
597 0 : op = WFS_ExprBuildOperator(TOKEN_GREATER);
598 5 : else if (EQUAL(pszToken, ">="))
599 5 : op = WFS_ExprBuildOperator(TOKEN_GREATER_OR_EQUAL);
600 : else
601 0 : goto invalid_expr;
602 : }
603 60 : else if (psBuildContext->bExpectLogicalOperator)
604 : {
605 21 : psBuildContext->bExpectLogicalOperator = FALSE;
606 21 : psBuildContext->bExpectVarName = TRUE;
607 21 : if (EQUAL(pszToken, "AND"))
608 10 : op = WFS_ExprBuildOperator(TOKEN_AND);
609 11 : else if (EQUAL(pszToken, "OR"))
610 11 : op = WFS_ExprBuildOperator(TOKEN_OR);
611 0 : else if (EQUAL(pszToken, "NOT"))
612 0 : op = WFS_ExprBuildOperator(TOKEN_NOT);
613 : else
614 0 : goto invalid_expr;
615 : }
616 39 : else if (psBuildContext->bExpectValue)
617 : {
618 39 : PUSH_VAL(WFS_ExprBuildValue(pszToken));
619 39 : psBuildContext->bExpectValue = FALSE;
620 39 : psBuildContext->bExpectLogicalOperator = TRUE;
621 : }
622 : else
623 0 : goto invalid_expr;
624 :
625 138 : if (op != NULL)
626 : {
627 : Expr* prevOp;
628 :
629 30 : while(TRUE)
630 : {
631 90 : PEEK_OP(prevOp);
632 :
633 90 : if (prevOp != NULL &&
634 : (WFS_ExprGetPriority(op) <= WFS_ExprGetPriority(prevOp)))
635 : {
636 30 : if (prevOp->eType != TOKEN_NOT)
637 : {
638 30 : POP_VAL(val2);
639 30 : if (val2 == NULL) goto invalid_expr;
640 : }
641 30 : POP_VAL(val1);
642 30 : if (val1 == NULL) goto invalid_expr;
643 :
644 30 : PUSH_VAL(WFS_ExprBuildBinary(prevOp->eType, val1, val2));
645 30 : POP_OP(prevOp);
646 30 : WFS_ExprFree(prevOp);
647 30 : val1 = val2 = NULL;
648 : }
649 : else
650 : break;
651 : }
652 :
653 60 : PUSH_OP(op);
654 60 : op = NULL;
655 : }
656 :
657 : }
658 :
659 22 : *ppapszTokens = papszTokens;
660 :
661 30 : while(TRUE)
662 : {
663 52 : POP_OP(op);
664 52 : if (op == NULL)
665 : break;
666 30 : if (op->eType != TOKEN_NOT)
667 : {
668 30 : POP_VAL(val2);
669 30 : if (val2 == NULL) goto invalid_expr;
670 : }
671 30 : POP_VAL(val1);
672 30 : if (val1 == NULL) goto invalid_expr;
673 30 : PUSH_VAL(WFS_ExprBuildBinary(op->eType, val1, val2));
674 30 : val1 = val2 = NULL;
675 :
676 30 : WFS_ExprFree(op);
677 30 : op = NULL;
678 : }
679 :
680 44 : POP_VAL(expr);
681 22 : return expr;
682 :
683 : invalid_expr:
684 0 : WFS_ExprFree(op);
685 0 : WFS_ExprFree(val1);
686 0 : WFS_ExprFree(val2);
687 0 : WFS_ExprFreeList(psValExprList);
688 0 : WFS_ExprFreeList(psOpExprList);
689 :
690 0 : return NULL;
691 : }
692 :
693 : /************************************************************************/
694 : /* WFS_ExprTokenize() */
695 : /************************************************************************/
696 :
697 18 : static char** WFS_ExprTokenize(const char* pszFilter)
698 : {
699 18 : const char* pszIter = pszFilter;
700 18 : CPLString osToken;
701 18 : char** papszTokens = NULL;
702 18 : int bLastCharWasSep = TRUE;
703 18 : char prevCh = 0;
704 : char ch;
705 18 : int bInQuote = FALSE;
706 18 : char chQuoteChar = 0;
707 :
708 18 : if (pszFilter == NULL)
709 0 : return NULL;
710 :
711 899 : while((ch = *pszIter) != '\0')
712 : {
713 863 : if (bInQuote)
714 : {
715 298 : osToken += ch;
716 298 : if (ch == chQuoteChar)
717 : {
718 15 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
719 15 : osToken = "";
720 15 : bInQuote = FALSE;
721 : }
722 :
723 298 : prevCh = ch;
724 298 : pszIter ++;
725 298 : continue;
726 : }
727 :
728 565 : if (ch == ' ')
729 : {
730 122 : if (!bLastCharWasSep)
731 : {
732 121 : if (osToken.size())
733 115 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
734 121 : osToken = "";
735 : }
736 122 : bLastCharWasSep = TRUE;
737 : }
738 451 : else if (ch == '(' || ch == ')' )
739 : {
740 8 : if (osToken.size())
741 4 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
742 : char ach[2];
743 8 : ach[0] = ch;
744 8 : ach[1] = 0;
745 8 : papszTokens = CSLAddString(papszTokens, ach);
746 8 : osToken = "";
747 : }
748 452 : else if (ch == '<' || ch == '>' || ch == '!')
749 : {
750 19 : if (ch == '>' && prevCh == '<')
751 : {
752 2 : osToken += ch;
753 2 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
754 2 : osToken = "";
755 : }
756 : else
757 : {
758 15 : if (osToken.size())
759 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
760 : char ach[2];
761 15 : ach[0] = ch;
762 15 : ach[1] = 0;
763 15 : osToken = ach;
764 : }
765 : }
766 418 : else if (ch == '=')
767 : {
768 48 : if (prevCh == '<' || prevCh == '>' || prevCh == '!')
769 13 : osToken += ch;
770 22 : else if (prevCh == '=')
771 : ;
772 : else
773 : {
774 22 : if (osToken.size())
775 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
776 22 : osToken = "=";
777 : }
778 : }
779 398 : else if (ch == '\'' || ch == '"')
780 : {
781 15 : if (osToken.size())
782 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
783 15 : osToken = "'";
784 15 : bInQuote = TRUE;
785 15 : chQuoteChar = ch;
786 : }
787 : else
788 : {
789 368 : if (prevCh == '<' || prevCh == '>' || prevCh == '!' || prevCh == '=')
790 : {
791 0 : if (osToken.size())
792 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
793 0 : osToken = "";
794 : }
795 368 : osToken += ch;
796 : }
797 :
798 565 : bLastCharWasSep = (ch == ' ');
799 :
800 565 : prevCh = ch;
801 565 : pszIter ++;
802 : }
803 18 : if (osToken.size())
804 3 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
805 :
806 18 : if (bInQuote)
807 : {
808 0 : CSLDestroy(papszTokens);
809 0 : papszTokens = NULL;
810 : }
811 :
812 18 : return papszTokens;
813 : }
814 :
815 : /************************************************************************/
816 : /* WFS_TurnSQLFilterToOGCFilter() */
817 : /************************************************************************/
818 :
819 18 : CPLString WFS_TurnSQLFilterToOGCFilter( const char * pszFilter,
820 : OGRFeatureDefn* poFDefn,
821 : int nVersion,
822 : int bPropertyIsNotEqualToSupported,
823 : int bUseFeatureId,
824 : int bGmlObjectIdNeedsGMLPrefix,
825 : int* pbOutNeedsNullCheck )
826 : {
827 18 : char** papszTokens = WFS_ExprTokenize(pszFilter);
828 :
829 18 : if (papszTokens == NULL)
830 0 : return "";
831 :
832 18 : char** papszTokens2 = papszTokens;
833 :
834 : ExprBuildContext sBuildContext;
835 18 : sBuildContext.bExpectVarName = TRUE;
836 18 : sBuildContext.bExpectComparisonOperator = FALSE;
837 18 : sBuildContext.bExpectLogicalOperator = FALSE;
838 18 : sBuildContext.bExpectValue = FALSE;
839 18 : sBuildContext.nParenthesisLevel = 0;
840 18 : Expr* expr = WFS_ExprBuildInternal(&papszTokens2, &sBuildContext);
841 18 : CSLDestroy(papszTokens);
842 :
843 18 : if (expr == NULL)
844 0 : return "";
845 :
846 18 : CPLString osFilter;
847 : /* If the filter is only made of querying one or several gml_id */
848 : /* (with OR operator), we turn this to <GmlObjectId> list */
849 18 : if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, expr, bUseFeatureId,
850 : bGmlObjectIdNeedsGMLPrefix, nVersion))
851 : {
852 : ExprDumpFilterOptions sOptions;
853 11 : sOptions.nVersion = nVersion;
854 11 : sOptions.bPropertyIsNotEqualToSupported = bPropertyIsNotEqualToSupported;
855 11 : sOptions.bOutNeedsNullCheck = FALSE;
856 11 : sOptions.poFDefn = poFDefn;
857 11 : osFilter = "";
858 11 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr, TRUE, &sOptions))
859 4 : osFilter = "";
860 11 : *pbOutNeedsNullCheck = sOptions.bOutNeedsNullCheck;
861 : }
862 :
863 18 : WFS_ExprFree(expr);
864 :
865 18 : return osFilter;
866 : }
|