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

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

Generated by: LCOV version 1.7