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