LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfsfilter.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 390 322 82.6 %
Date: 2011-12-18 Functions: 12 11 91.7 %

       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                 : }

Generated by: LCOV version 1.7