1 : /******************************************************************************
2 : * $Id: ogrwfsfilter.cpp 23161 2011-10-02 15:14:07Z 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 23161 2011-10-02 15:14:07Z 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 54 : static int WFS_ExprGetPriority(const Expr* expr)
67 : {
68 54 : if (expr->eType == TOKEN_NOT)
69 0 : return 9;
70 54 : 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 8 : return 6;
75 46 : else if (expr->eType == TOKEN_EQUAL ||
76 : expr->eType == TOKEN_LIKE ||
77 : expr->eType == TOKEN_NOT_EQUAL)
78 14 : return 5;
79 32 : else if (expr->eType == TOKEN_AND)
80 18 : return 4;
81 14 : else if (expr->eType == TOKEN_OR)
82 14 : return 3;
83 : else
84 0 : return 0;
85 : }
86 :
87 : /************************************************************************/
88 : /* WFS_ExprFree() */
89 : /************************************************************************/
90 :
91 120 : static void WFS_ExprFree(Expr* expr)
92 : {
93 120 : if (expr == NULL) return;
94 120 : if (expr->expr1)
95 36 : WFS_ExprFree(expr->expr1);
96 120 : if (expr->expr2)
97 36 : WFS_ExprFree(expr->expr2);
98 120 : CPLFree(expr->pszVal);
99 120 : 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 24 : static Expr* WFS_ExprBuildVarName(const char* pszVal)
122 : {
123 24 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
124 24 : expr->eType = TOKEN_VAR_NAME;
125 24 : expr->pszVal = CPLStrdup(pszVal);
126 24 : return expr;
127 : }
128 :
129 : /************************************************************************/
130 : /* WFS_ExprBuildValue() */
131 : /************************************************************************/
132 :
133 24 : static Expr* WFS_ExprBuildValue(const char* pszVal)
134 : {
135 24 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
136 24 : expr->eType = TOKEN_LITERAL;
137 24 : expr->pszVal = CPLStrdup(pszVal);
138 24 : return expr;
139 : }
140 :
141 : /************************************************************************/
142 : /* WFS_ExprBuildOperator() */
143 : /************************************************************************/
144 :
145 36 : static Expr* WFS_ExprBuildOperator(TokenType eType)
146 : {
147 36 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
148 36 : expr->eType = eType;
149 36 : return expr;
150 : }
151 :
152 : /************************************************************************/
153 : /* WFS_ExprBuildBinary() */
154 : /************************************************************************/
155 :
156 36 : static Expr* WFS_ExprBuildBinary(TokenType eType, Expr* expr1, Expr* expr2)
157 : {
158 36 : Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
159 36 : expr->eType = eType;
160 36 : expr->expr1 = expr1;
161 36 : expr->expr2 = expr2;
162 36 : 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 19 : static int WFS_ExprDumpGmlObjectIdFilter(CPLString& osFilter,
214 : const Expr* expr,
215 : int bUseFeatureId,
216 : int bGmlObjectIdNeedsGMLPrefix,
217 : int nVersion)
218 : {
219 19 : 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 6 : if (bUseFeatureId)
225 1 : osFilter += "<FeatureId fid=\"";
226 5 : else if (nVersion >= 200)
227 1 : osFilter += "<ResourceId rid=\"";
228 4 : else if (!bGmlObjectIdNeedsGMLPrefix)
229 1 : osFilter += "<GmlObjectId id=\"";
230 : else
231 3 : osFilter += "<GmlObjectId gml:id=\"";
232 12 : if (expr->expr2->pszVal[0] == '\'' || expr->expr2->pszVal[0] == '"')
233 : {
234 6 : CPLString osVal(expr->expr2->pszVal + 1);
235 6 : osVal.resize(osVal.size() - 1);
236 6 : osFilter += osVal;
237 : }
238 : else
239 0 : osFilter += expr->expr2->pszVal;
240 6 : osFilter += "\"/>";
241 6 : return TRUE;
242 : }
243 13 : 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 6 : bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion);
249 : }
250 7 : return FALSE;
251 : }
252 :
253 : /************************************************************************/
254 : /* WFS_ExprDumpAsOGCFilter() */
255 : /************************************************************************/
256 :
257 : typedef struct
258 : {
259 : int nVersion;
260 : int bPropertyIsNotEqualToSupported;
261 : int bOutNeedsNullCheck;
262 : } ExprDumpFilterOptions;
263 :
264 62 : static int WFS_ExprDumpAsOGCFilter(CPLString& osFilter,
265 : const Expr* expr,
266 : int bExpectBinary,
267 : ExprDumpFilterOptions* psOptions)
268 : {
269 62 : switch(expr->eType)
270 : {
271 : case TOKEN_VAR_NAME:
272 18 : if (bExpectBinary)
273 0 : return FALSE;
274 :
275 : /* Special fields not understood by server */
276 18 : if (EQUAL(expr->pszVal, "gml_id") ||
277 : EQUAL(expr->pszVal, "FID") ||
278 : EQUAL(expr->pszVal, "OGR_GEOMETRY") ||
279 : EQUAL(expr->pszVal, "OGR_GEOM_WKT") ||
280 : EQUAL(expr->pszVal, "OGR_GEOM_AREA") ||
281 : EQUAL(expr->pszVal, "OGR_STYLE"))
282 1 : return FALSE;
283 :
284 17 : if (psOptions->nVersion >= 200)
285 1 : osFilter += "<ValueReference>";
286 : else
287 16 : osFilter += "<PropertyName>";
288 17 : if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"')
289 : {
290 0 : CPLString osVal(expr->pszVal + 1);
291 0 : osVal.resize(osVal.size() - 1);
292 0 : osFilter += osVal;
293 : }
294 : else
295 17 : osFilter += expr->pszVal;
296 17 : if (psOptions->nVersion >= 200)
297 1 : osFilter += "</ValueReference>";
298 : else
299 16 : osFilter += "</PropertyName>";
300 17 : break;
301 :
302 : case TOKEN_LITERAL:
303 15 : if (bExpectBinary)
304 0 : return FALSE;
305 15 : osFilter += "<Literal>";
306 18 : if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"')
307 : {
308 3 : CPLString osVal(expr->pszVal + 1);
309 3 : osVal.resize(osVal.size() - 1);
310 3 : osFilter += osVal;
311 : }
312 : else
313 12 : osFilter += expr->pszVal;
314 15 : osFilter += "</Literal>";
315 15 : break;
316 :
317 : case TOKEN_NOT:
318 0 : osFilter += "<Not>";
319 0 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions))
320 0 : return FALSE;
321 0 : osFilter += "</Not>";
322 0 : break;
323 :
324 : case TOKEN_LIKE:
325 : {
326 1 : CPLString osVal;
327 : char ch;
328 1 : char firstCh = 0;
329 : int i;
330 1 : if (psOptions->nVersion == 100)
331 0 : osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escape='!'>";
332 : else
333 1 : osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escapeChar='!'>";
334 1 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
335 0 : return FALSE;
336 1 : if (expr->expr2->eType != TOKEN_LITERAL)
337 0 : return FALSE;
338 1 : osFilter += "<Literal>";
339 :
340 : /* Escape value according to above special characters */
341 : /* For URL compatibility reason, we remap the OGR SQL '%' wildchard into '*' */
342 1 : i = 0;
343 1 : ch = expr->expr2->pszVal[i];
344 1 : if (ch == '\'' || ch == '"')
345 : {
346 1 : firstCh = ch;
347 1 : i ++;
348 : }
349 8 : for(;(ch = expr->expr2->pszVal[i]) != '\0';i++)
350 : {
351 8 : if (ch == '%')
352 2 : osVal += "*";
353 6 : else if (ch == '!')
354 0 : osVal += "!!";
355 6 : else if (ch == '*')
356 0 : osVal += "!*";
357 6 : else if (ch == firstCh && expr->expr2->pszVal[i + 1] == 0)
358 1 : break;
359 : else
360 : {
361 : char ach[2];
362 5 : ach[0] = ch;
363 5 : ach[1] = 0;
364 5 : osVal += ach;
365 : }
366 : }
367 1 : osFilter += osVal;
368 1 : osFilter += "</Literal>";
369 1 : osFilter += "</PropertyIsLike>";
370 0 : break;
371 : }
372 :
373 : case TOKEN_EQUAL:
374 : case TOKEN_NOT_EQUAL:
375 : case TOKEN_LESSER_OR_EQUAL:
376 : case TOKEN_LESSER:
377 : case TOKEN_GREATER_OR_EQUAL:
378 : case TOKEN_GREATER:
379 : {
380 17 : if (expr->eType == TOKEN_EQUAL && expr->expr2->eType == TOKEN_LITERAL &&
381 : EQUAL(expr->expr2->pszVal, "NULL"))
382 : {
383 0 : osFilter += "<PropertyIsNull>";
384 0 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
385 0 : return FALSE;
386 0 : osFilter += "</PropertyIsNull>";
387 0 : psOptions->bOutNeedsNullCheck = TRUE;
388 0 : break;
389 : }
390 17 : if (expr->eType == TOKEN_NOT_EQUAL && expr->expr2->eType == TOKEN_LITERAL &&
391 : EQUAL(expr->expr2->pszVal, "NULL"))
392 : {
393 1 : osFilter += "<Not><PropertyIsNull>";
394 1 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
395 0 : return FALSE;
396 1 : osFilter += "</PropertyIsNull></Not>";
397 1 : psOptions->bOutNeedsNullCheck = TRUE;
398 1 : break;
399 : }
400 16 : TokenType eType = expr->eType;
401 16 : int bAddClosingNot = FALSE;
402 16 : if (!psOptions->bPropertyIsNotEqualToSupported && eType == TOKEN_NOT_EQUAL)
403 : {
404 1 : osFilter += "<Not>";
405 1 : eType = TOKEN_EQUAL;
406 1 : bAddClosingNot = TRUE;
407 : }
408 :
409 16 : const char* pszName = NULL;
410 16 : switch(eType)
411 : {
412 9 : case TOKEN_EQUAL: pszName = "PropertyIsEqualTo"; break;
413 2 : case TOKEN_NOT_EQUAL: pszName = "PropertyIsNotEqualTo"; break;
414 2 : case TOKEN_LESSER_OR_EQUAL: pszName = "PropertyIsLessThanOrEqualTo"; break;
415 0 : case TOKEN_LESSER: pszName = "PropertyIsLessThan"; break;
416 3 : case TOKEN_GREATER_OR_EQUAL:pszName = "PropertyIsGreaterThanOrEqualTo"; break;
417 0 : case TOKEN_GREATER: pszName = "PropertyIsGreaterThan"; break;
418 : default: break;
419 : }
420 16 : osFilter += "<";
421 16 : osFilter += pszName;
422 16 : osFilter += ">";
423 16 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
424 1 : return FALSE;
425 15 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, FALSE, psOptions))
426 0 : return FALSE;
427 15 : osFilter += "</";
428 15 : osFilter += pszName;
429 15 : osFilter += ">";
430 15 : if (bAddClosingNot)
431 1 : osFilter += "</Not>";
432 15 : break;
433 : }
434 :
435 : case TOKEN_AND:
436 : case TOKEN_OR:
437 : {
438 11 : const char* pszName = (expr->eType == TOKEN_AND) ? "And" : "Or";
439 11 : osFilter += "<";
440 11 : osFilter += pszName;
441 11 : osFilter += ">";
442 11 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions))
443 0 : return FALSE;
444 11 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, TRUE, psOptions))
445 0 : return FALSE;
446 11 : osFilter += "</";
447 11 : osFilter += pszName;
448 11 : osFilter += ">";
449 :
450 11 : break;
451 : }
452 :
453 : default:
454 0 : return FALSE;
455 : }
456 :
457 60 : return TRUE;
458 : }
459 :
460 : /************************************************************************/
461 : /* WFS_ExprBuildInternal() */
462 : /************************************************************************/
463 :
464 : typedef struct
465 : {
466 : int bExpectVarName;
467 : int bExpectComparisonOperator;
468 : int bExpectLogicalOperator;
469 : int bExpectValue;
470 : int nParenthesisLevel;
471 : } ExprBuildContext;
472 :
473 14 : static Expr* WFS_ExprBuildInternal(char*** ppapszTokens,
474 : ExprBuildContext* psBuildContext)
475 : {
476 14 : Expr* expr = NULL;
477 14 : Expr* op = NULL;
478 14 : Expr* val1 = NULL;
479 14 : Expr* val2 = NULL;
480 14 : CPLList* psValExprList = NULL;
481 14 : CPLList* psOpExprList = NULL;
482 14 : char** papszTokens = *ppapszTokens;
483 14 : char* pszToken = NULL;
484 :
485 : #define PEEK_OP(my_op) my_op = (Expr*)CPLListGetData(psOpExprList)
486 : #define PUSH_OP(my_op) psOpExprList = CPLListInsert(psOpExprList, my_op, 0)
487 : #define POP_OP(my_op) do { my_op = (Expr*)CPLListGetData(psOpExprList); \
488 : if (my_op != NULL) { \
489 : CPLList* psNext = psOpExprList->psNext; \
490 : CPLFree(psOpExprList); \
491 : psOpExprList = psNext; \
492 : } \
493 : } while(0)
494 : #define PUSH_VAL(my_val) psValExprList = CPLListInsert(psValExprList, my_val, 0)
495 : #define POP_VAL(my_val) do { my_val = (Expr*)CPLListGetData(psValExprList); \
496 : if (my_val != NULL) { \
497 : CPLList* psNext = psValExprList->psNext; \
498 : CPLFree(psValExprList); \
499 : psValExprList = psNext; \
500 : } \
501 : } while(0)
502 84 : while(TRUE)
503 : {
504 98 : pszToken = *papszTokens;
505 98 : if (pszToken == NULL)
506 10 : break;
507 88 : papszTokens ++;
508 :
509 88 : if (EQUAL(pszToken, "("))
510 : {
511 2 : char** papszSub = papszTokens;
512 2 : psBuildContext->nParenthesisLevel ++;
513 2 : Expr* expr = WFS_ExprBuildInternal(&papszSub, psBuildContext);
514 2 : psBuildContext->nParenthesisLevel --;
515 2 : if (expr == NULL)
516 0 : goto invalid_expr;
517 2 : PUSH_VAL(expr);
518 2 : papszTokens = papszSub;
519 2 : if (*papszTokens == NULL)
520 2 : break;
521 :
522 0 : continue;
523 : }
524 86 : else if (EQUAL(pszToken, ")"))
525 : {
526 2 : if (psBuildContext->nParenthesisLevel > 0)
527 2 : break;
528 : else
529 0 : goto invalid_expr;
530 : }
531 :
532 84 : if (psBuildContext->bExpectVarName)
533 : {
534 24 : if (EQUAL(pszToken, "NOT"))
535 0 : op = WFS_ExprBuildOperator(TOKEN_NOT);
536 : else
537 : {
538 24 : PUSH_VAL(WFS_ExprBuildVarName(pszToken));
539 24 : psBuildContext->bExpectVarName = FALSE;
540 24 : psBuildContext->bExpectComparisonOperator = TRUE;
541 : }
542 : }
543 60 : else if (psBuildContext->bExpectComparisonOperator)
544 : {
545 24 : psBuildContext->bExpectComparisonOperator = FALSE;
546 24 : psBuildContext->bExpectValue = TRUE;
547 24 : if (EQUAL(pszToken, "IS"))
548 : {
549 2 : if (*papszTokens != NULL && EQUAL(*papszTokens, "NOT"))
550 : {
551 1 : op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL);
552 1 : papszTokens ++;
553 : }
554 : else
555 0 : op = WFS_ExprBuildOperator(TOKEN_EQUAL);
556 : }
557 23 : else if (EQUAL(pszToken, "="))
558 14 : op = WFS_ExprBuildOperator(TOKEN_EQUAL);
559 10 : else if (EQUAL(pszToken, "LIKE") || EQUAL(pszToken, "ILIKE"))
560 1 : op = WFS_ExprBuildOperator(TOKEN_LIKE);
561 11 : else if (EQUAL(pszToken, "!=") || EQUAL(pszToken, "<>"))
562 3 : op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL);
563 5 : else if (EQUAL(pszToken, "<"))
564 0 : op = WFS_ExprBuildOperator(TOKEN_LESSER);
565 5 : else if (EQUAL(pszToken, "<="))
566 2 : op = WFS_ExprBuildOperator(TOKEN_LESSER_OR_EQUAL);
567 3 : else if (EQUAL(pszToken, ">"))
568 0 : op = WFS_ExprBuildOperator(TOKEN_GREATER);
569 3 : else if (EQUAL(pszToken, ">="))
570 3 : op = WFS_ExprBuildOperator(TOKEN_GREATER_OR_EQUAL);
571 : else
572 0 : goto invalid_expr;
573 : }
574 36 : else if (psBuildContext->bExpectLogicalOperator)
575 : {
576 12 : psBuildContext->bExpectLogicalOperator = FALSE;
577 12 : psBuildContext->bExpectVarName = TRUE;
578 12 : if (EQUAL(pszToken, "AND"))
579 6 : op = WFS_ExprBuildOperator(TOKEN_AND);
580 6 : else if (EQUAL(pszToken, "OR"))
581 6 : op = WFS_ExprBuildOperator(TOKEN_OR);
582 0 : else if (EQUAL(pszToken, "NOT"))
583 0 : op = WFS_ExprBuildOperator(TOKEN_NOT);
584 : else
585 0 : goto invalid_expr;
586 : }
587 24 : else if (psBuildContext->bExpectValue)
588 : {
589 24 : PUSH_VAL(WFS_ExprBuildValue(pszToken));
590 24 : psBuildContext->bExpectValue = FALSE;
591 24 : psBuildContext->bExpectLogicalOperator = TRUE;
592 : }
593 : else
594 0 : goto invalid_expr;
595 :
596 84 : if (op != NULL)
597 : {
598 : Expr* prevOp;
599 :
600 17 : while(TRUE)
601 : {
602 53 : PEEK_OP(prevOp);
603 :
604 53 : if (prevOp != NULL &&
605 : (WFS_ExprGetPriority(op) <= WFS_ExprGetPriority(prevOp)))
606 : {
607 17 : if (prevOp->eType != TOKEN_NOT)
608 : {
609 17 : POP_VAL(val2);
610 17 : if (val2 == NULL) goto invalid_expr;
611 : }
612 17 : POP_VAL(val1);
613 17 : if (val1 == NULL) goto invalid_expr;
614 :
615 17 : PUSH_VAL(WFS_ExprBuildBinary(prevOp->eType, val1, val2));
616 17 : POP_OP(prevOp);
617 17 : WFS_ExprFree(prevOp);
618 17 : val1 = val2 = NULL;
619 : }
620 : else
621 : break;
622 : }
623 :
624 36 : PUSH_OP(op);
625 36 : op = NULL;
626 : }
627 :
628 : }
629 :
630 14 : *ppapszTokens = papszTokens;
631 :
632 19 : while(TRUE)
633 : {
634 33 : POP_OP(op);
635 33 : if (op == NULL)
636 : break;
637 19 : if (op->eType != TOKEN_NOT)
638 : {
639 19 : POP_VAL(val2);
640 19 : if (val2 == NULL) goto invalid_expr;
641 : }
642 19 : POP_VAL(val1);
643 19 : if (val1 == NULL) goto invalid_expr;
644 19 : PUSH_VAL(WFS_ExprBuildBinary(op->eType, val1, val2));
645 19 : val1 = val2 = NULL;
646 :
647 19 : WFS_ExprFree(op);
648 19 : op = NULL;
649 : }
650 :
651 28 : POP_VAL(expr);
652 14 : return expr;
653 :
654 : invalid_expr:
655 0 : WFS_ExprFree(op);
656 0 : WFS_ExprFree(val1);
657 0 : WFS_ExprFree(val2);
658 0 : WFS_ExprFreeList(psValExprList);
659 0 : WFS_ExprFreeList(psOpExprList);
660 :
661 0 : return NULL;
662 : }
663 :
664 : /************************************************************************/
665 : /* WFS_ExprTokenize() */
666 : /************************************************************************/
667 :
668 12 : static char** WFS_ExprTokenize(const char* pszFilter)
669 : {
670 12 : const char* pszIter = pszFilter;
671 12 : CPLString osToken;
672 12 : char** papszTokens = NULL;
673 12 : int bLastCharWasSep = TRUE;
674 12 : char prevCh = 0;
675 : char ch;
676 12 : int bInQuote = FALSE;
677 12 : char chQuoteChar = 0;
678 :
679 12 : if (pszFilter == NULL)
680 0 : return NULL;
681 :
682 592 : while((ch = *pszIter) != '\0')
683 : {
684 568 : if (bInQuote)
685 : {
686 212 : osToken += ch;
687 212 : if (ch == chQuoteChar)
688 : {
689 11 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
690 11 : osToken = "";
691 11 : bInQuote = FALSE;
692 : }
693 :
694 212 : prevCh = ch;
695 212 : pszIter ++;
696 212 : continue;
697 : }
698 :
699 356 : if (ch == ' ')
700 : {
701 75 : if (!bLastCharWasSep)
702 : {
703 73 : if (osToken.size())
704 69 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
705 73 : osToken = "";
706 : }
707 75 : bLastCharWasSep = TRUE;
708 : }
709 285 : else if (ch == '(' || ch == ')' )
710 : {
711 4 : if (osToken.size())
712 2 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
713 : char ach[2];
714 4 : ach[0] = ch;
715 4 : ach[1] = 0;
716 4 : papszTokens = CSLAddString(papszTokens, ach);
717 4 : osToken = "";
718 : }
719 286 : else if (ch == '<' || ch == '>' || ch == '!')
720 : {
721 10 : if (ch == '>' && prevCh == '<')
722 : {
723 1 : osToken += ch;
724 1 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
725 1 : osToken = "";
726 : }
727 : else
728 : {
729 8 : if (osToken.size())
730 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
731 : char ach[2];
732 8 : ach[0] = ch;
733 8 : ach[1] = 0;
734 8 : osToken = ach;
735 : }
736 : }
737 268 : else if (ch == '=')
738 : {
739 28 : if (prevCh == '<' || prevCh == '>' || prevCh == '!')
740 7 : osToken += ch;
741 14 : else if (prevCh == '=')
742 : ;
743 : else
744 : {
745 14 : if (osToken.size())
746 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
747 14 : osToken = "=";
748 : }
749 : }
750 258 : else if (ch == '\'' || ch == '"')
751 : {
752 11 : if (osToken.size())
753 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
754 11 : osToken = "'";
755 11 : bInQuote = TRUE;
756 11 : chQuoteChar = ch;
757 : }
758 : else
759 : {
760 236 : if (prevCh == '<' || prevCh == '>' || prevCh == '!' || prevCh == '=')
761 : {
762 0 : if (osToken.size())
763 0 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
764 0 : osToken = "";
765 : }
766 236 : osToken += ch;
767 : }
768 :
769 356 : bLastCharWasSep = (ch == ' ');
770 :
771 356 : prevCh = ch;
772 356 : pszIter ++;
773 : }
774 12 : if (osToken.size())
775 2 : papszTokens = CSLAddString(papszTokens, osToken.c_str());
776 :
777 12 : if (bInQuote)
778 : {
779 0 : CSLDestroy(papszTokens);
780 0 : papszTokens = NULL;
781 : }
782 :
783 12 : return papszTokens;
784 : }
785 :
786 : /************************************************************************/
787 : /* WFS_TurnSQLFilterToOGCFilter() */
788 : /************************************************************************/
789 :
790 12 : CPLString WFS_TurnSQLFilterToOGCFilter( const char * pszFilter,
791 : int nVersion,
792 : int bPropertyIsNotEqualToSupported,
793 : int bUseFeatureId,
794 : int bGmlObjectIdNeedsGMLPrefix,
795 : int* pbOutNeedsNullCheck )
796 : {
797 12 : char** papszTokens = WFS_ExprTokenize(pszFilter);
798 :
799 12 : if (papszTokens == NULL)
800 0 : return "";
801 :
802 12 : char** papszTokens2 = papszTokens;
803 :
804 : ExprBuildContext sBuildContext;
805 12 : sBuildContext.bExpectVarName = TRUE;
806 12 : sBuildContext.bExpectComparisonOperator = FALSE;
807 12 : sBuildContext.bExpectLogicalOperator = FALSE;
808 12 : sBuildContext.bExpectValue = FALSE;
809 12 : sBuildContext.nParenthesisLevel = 0;
810 12 : Expr* expr = WFS_ExprBuildInternal(&papszTokens2, &sBuildContext);
811 12 : CSLDestroy(papszTokens);
812 :
813 12 : if (expr == NULL)
814 0 : return "";
815 :
816 12 : CPLString osFilter;
817 : /* If the filter is only made of querying one or several gml_id */
818 : /* (with OR operator), we turn this to <GmlObjectId> list */
819 12 : if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, expr, bUseFeatureId,
820 : bGmlObjectIdNeedsGMLPrefix, nVersion))
821 : {
822 : ExprDumpFilterOptions sOptions;
823 7 : sOptions.nVersion = nVersion;
824 7 : sOptions.bPropertyIsNotEqualToSupported = bPropertyIsNotEqualToSupported;
825 7 : sOptions.bOutNeedsNullCheck = FALSE;
826 7 : osFilter = "";
827 7 : if (!WFS_ExprDumpAsOGCFilter(osFilter, expr, TRUE, &sOptions))
828 1 : osFilter = "";
829 7 : *pbOutNeedsNullCheck = sOptions.bOutNeedsNullCheck;
830 : }
831 :
832 12 : WFS_ExprFree(expr);
833 :
834 12 : return osFilter;
835 : }
|