LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/wfs - ogrwfsfilter.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 410 461 88.9 %
Date: 2024-05-03 15:49:35 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  WFS Translator
       4             :  * Purpose:  Implements OGR SQL into OGC Filter translation.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "ogr_wfs.h"
      30             : #include "ogr_p.h"
      31             : 
      32             : typedef struct
      33             : {
      34             :     int nVersion;
      35             :     bool bPropertyIsNotEqualToSupported;
      36             :     int bOutNeedsNullCheck;
      37             :     OGRDataSource *poDS;
      38             :     OGRFeatureDefn *poFDefn;
      39             :     int nUniqueGeomGMLId;
      40             :     const OGRSpatialReference *poSRS;
      41             :     const char *pszNSPrefix;
      42             : } ExprDumpFilterOptions;
      43             : 
      44             : /************************************************************************/
      45             : /*                WFS_ExprDumpGmlObjectIdFilter()                       */
      46             : /************************************************************************/
      47             : 
      48          96 : static bool WFS_ExprDumpGmlObjectIdFilter(CPLString &osFilter,
      49             :                                           const swq_expr_node *poExpr,
      50             :                                           int bUseFeatureId,
      51             :                                           int bGmlObjectIdNeedsGMLPrefix,
      52             :                                           int nVersion)
      53             : {
      54          96 :     if (poExpr->eNodeType == SNT_OPERATION && poExpr->nOperation == SWQ_EQ &&
      55          59 :         poExpr->nSubExprCount == 2 &&
      56          59 :         poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
      57          59 :         strcmp(poExpr->papoSubExpr[0]->string_value, "gml_id") == 0 &&
      58          22 :         poExpr->papoSubExpr[1]->eNodeType == SNT_CONSTANT)
      59             :     {
      60          22 :         if (bUseFeatureId)
      61           0 :             osFilter += "<FeatureId fid=\"";
      62          22 :         else if (nVersion >= 200)
      63           0 :             osFilter += "<ResourceId rid=\"";
      64          22 :         else if (!bGmlObjectIdNeedsGMLPrefix)
      65          22 :             osFilter += "<GmlObjectId id=\"";
      66             :         else
      67           0 :             osFilter += "<GmlObjectId gml:id=\"";
      68          22 :         if (poExpr->papoSubExpr[1]->field_type == SWQ_INTEGER ||
      69          22 :             poExpr->papoSubExpr[1]->field_type == SWQ_INTEGER64)
      70             :         {
      71           0 :             osFilter +=
      72           0 :                 CPLSPrintf(CPL_FRMT_GIB, poExpr->papoSubExpr[1]->int_value);
      73             :         }
      74          22 :         else if (poExpr->papoSubExpr[1]->field_type == SWQ_STRING)
      75             :         {
      76          22 :             char *pszXML = CPLEscapeString(poExpr->papoSubExpr[1]->string_value,
      77             :                                            -1, CPLES_XML);
      78          22 :             osFilter += pszXML;
      79          22 :             CPLFree(pszXML);
      80             :         }
      81             :         else
      82             :         {
      83           0 :             return false;
      84             :         }
      85          22 :         osFilter += "\"/>";
      86          22 :         return true;
      87             :     }
      88          74 :     else if (poExpr->eNodeType == SNT_OPERATION &&
      89          74 :              poExpr->nOperation == SWQ_OR && poExpr->nSubExprCount == 2)
      90             :     {
      91          40 :         return WFS_ExprDumpGmlObjectIdFilter(
      92          20 :                    osFilter, poExpr->papoSubExpr[0], bUseFeatureId,
      93          22 :                    bGmlObjectIdNeedsGMLPrefix, nVersion) &&
      94           2 :                WFS_ExprDumpGmlObjectIdFilter(
      95           2 :                    osFilter, poExpr->papoSubExpr[1], bUseFeatureId,
      96          20 :                    bGmlObjectIdNeedsGMLPrefix, nVersion);
      97             :     }
      98             : 
      99          54 :     return false;
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                     WFS_ExprDumpRawLitteral()                        */
     104             : /************************************************************************/
     105             : 
     106          81 : static bool WFS_ExprDumpRawLitteral(CPLString &osFilter,
     107             :                                     const swq_expr_node *poExpr)
     108             : {
     109          81 :     if (poExpr->field_type == SWQ_INTEGER ||
     110          47 :         poExpr->field_type == SWQ_INTEGER64)
     111          34 :         osFilter += CPLSPrintf(CPL_FRMT_GIB, poExpr->int_value);
     112          47 :     else if (poExpr->field_type == SWQ_FLOAT)
     113          34 :         osFilter += CPLSPrintf("%.16g", poExpr->float_value);
     114          13 :     else if (poExpr->field_type == SWQ_STRING)
     115             :     {
     116          13 :         char *pszXML = CPLEscapeString(poExpr->string_value, -1, CPLES_XML);
     117          13 :         osFilter += pszXML;
     118          13 :         CPLFree(pszXML);
     119             :     }
     120           0 :     else if (poExpr->field_type == SWQ_TIMESTAMP)
     121             :     {
     122             :         OGRField sDate;
     123           0 :         if (!OGRParseDate(poExpr->string_value, &sDate, 0))
     124           0 :             return false;
     125           0 :         char *pszDate = OGRGetXMLDateTime(&sDate);
     126           0 :         osFilter += pszDate;
     127           0 :         CPLFree(pszDate);
     128             :     }
     129             :     else
     130             :     {
     131           0 :         return false;
     132             :     }
     133          81 :     return true;
     134             : }
     135             : 
     136             : /************************************************************************/
     137             : /*                       WFS_ExprGetSRSName()                          */
     138             : /************************************************************************/
     139             : 
     140          25 : static const char *WFS_ExprGetSRSName(const swq_expr_node *poExpr,
     141             :                                       int iSubArgIndex,
     142             :                                       ExprDumpFilterOptions *psOptions,
     143             :                                       OGRSpatialReference &oSRS)
     144             : {
     145          25 :     if (poExpr->nSubExprCount == iSubArgIndex + 1 &&
     146          15 :         poExpr->papoSubExpr[iSubArgIndex]->field_type == SWQ_STRING)
     147             :     {
     148          12 :         if (oSRS.SetFromUserInput(
     149           6 :                 poExpr->papoSubExpr[iSubArgIndex]->string_value) == OGRERR_NONE)
     150             :         {
     151           6 :             return poExpr->papoSubExpr[iSubArgIndex]->string_value;
     152             :         }
     153             :     }
     154          19 :     else if (poExpr->nSubExprCount == iSubArgIndex + 1 &&
     155           9 :              poExpr->papoSubExpr[iSubArgIndex]->field_type == SWQ_INTEGER)
     156             :     {
     157          18 :         if (oSRS.importFromEPSGA(
     158           9 :                 (int)poExpr->papoSubExpr[iSubArgIndex]->int_value) ==
     159             :             OGRERR_NONE)
     160             :         {
     161          18 :             return CPLSPrintf(
     162             :                 "urn:ogc:def:crs:EPSG::%d",
     163           9 :                 (int)poExpr->papoSubExpr[iSubArgIndex]->int_value);
     164             :         }
     165             :     }
     166          10 :     else if (poExpr->nSubExprCount == iSubArgIndex &&
     167          10 :              psOptions->poSRS != nullptr)
     168             :     {
     169          10 :         if (psOptions->poSRS->GetAuthorityName(nullptr) &&
     170          10 :             EQUAL(psOptions->poSRS->GetAuthorityName(nullptr), "EPSG") &&
     171          30 :             psOptions->poSRS->GetAuthorityCode(nullptr) &&
     172          10 :             oSRS.importFromEPSGA(atoi(
     173          10 :                 psOptions->poSRS->GetAuthorityCode(nullptr))) == OGRERR_NONE)
     174             :         {
     175          10 :             return CPLSPrintf("urn:ogc:def:crs:EPSG::%s",
     176          20 :                               psOptions->poSRS->GetAuthorityCode(nullptr));
     177             :         }
     178             :     }
     179           0 :     return nullptr;
     180             : }
     181             : 
     182             : /************************************************************************/
     183             : /*                     WFS_ExprDumpAsOGCFilter()                        */
     184             : /************************************************************************/
     185             : 
     186         313 : static bool WFS_ExprDumpAsOGCFilter(CPLString &osFilter,
     187             :                                     const swq_expr_node *poExpr,
     188             :                                     int bExpectBinary,
     189             :                                     ExprDumpFilterOptions *psOptions)
     190             : {
     191         313 :     if (poExpr->eNodeType == SNT_COLUMN)
     192             :     {
     193         123 :         if (bExpectBinary)
     194           0 :             return false;
     195             : 
     196             :         /* Special fields not understood by server */
     197         123 :         if (EQUAL(poExpr->string_value, "gml_id") ||
     198         123 :             EQUAL(poExpr->string_value, "FID") ||
     199         123 :             EQUAL(poExpr->string_value, "OGR_GEOMETRY") ||
     200         117 :             EQUAL(poExpr->string_value, "OGR_GEOM_WKT") ||
     201         117 :             EQUAL(poExpr->string_value, "OGR_GEOM_AREA") ||
     202         117 :             EQUAL(poExpr->string_value, "OGR_STYLE"))
     203             :         {
     204           6 :             CPLDebug("WFS", "Attribute refers to a OGR special field. Cannot "
     205             :                             "use server-side filtering");
     206           6 :             return false;
     207             :         }
     208             : 
     209         117 :         const char *pszFieldname = nullptr;
     210             :         const bool bSameTable =
     211         161 :             psOptions->poFDefn != nullptr &&
     212          44 :             (poExpr->table_name == nullptr ||
     213           0 :              EQUAL(poExpr->table_name, psOptions->poFDefn->GetName()));
     214         117 :         if (bSameTable)
     215             :         {
     216             :             int nIndex;
     217          88 :             if ((nIndex = psOptions->poFDefn->GetFieldIndex(
     218          44 :                      poExpr->string_value)) >= 0)
     219             :             {
     220             :                 pszFieldname =
     221          22 :                     psOptions->poFDefn->GetFieldDefn(nIndex)->GetNameRef();
     222             :             }
     223          44 :             else if ((nIndex = psOptions->poFDefn->GetGeomFieldIndex(
     224          22 :                           poExpr->string_value)) >= 0)
     225             :             {
     226             :                 pszFieldname =
     227          22 :                     psOptions->poFDefn->GetGeomFieldDefn(nIndex)->GetNameRef();
     228             :             }
     229             :         }
     230          73 :         else if (psOptions->poDS != nullptr)
     231             :         {
     232             :             OGRLayer *poLayer =
     233          64 :                 psOptions->poDS->GetLayerByName(poExpr->table_name);
     234          64 :             if (poLayer)
     235             :             {
     236          64 :                 OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
     237             :                 int nIndex;
     238          64 :                 if ((nIndex = poFDefn->GetFieldIndex(poExpr->string_value)) >=
     239             :                     0)
     240             :                 {
     241             :                     pszFieldname =
     242          62 :                         CPLSPrintf("%s/%s", poLayer->GetName(),
     243          62 :                                    poFDefn->GetFieldDefn(nIndex)->GetNameRef());
     244             :                 }
     245           4 :                 else if ((nIndex = poFDefn->GetGeomFieldIndex(
     246           2 :                               poExpr->string_value)) >= 0)
     247             :                 {
     248           4 :                     pszFieldname = CPLSPrintf(
     249           2 :                         "%s/%s", poLayer->GetName(),
     250           2 :                         poFDefn->GetGeomFieldDefn(nIndex)->GetNameRef());
     251             :                 }
     252             :             }
     253             :         }
     254             : 
     255         117 :         if (psOptions->poFDefn == nullptr && psOptions->poDS == nullptr)
     256           9 :             pszFieldname = poExpr->string_value;
     257             : 
     258         117 :         if (pszFieldname == nullptr)
     259             :         {
     260           0 :             if (poExpr->table_name != nullptr)
     261           0 :                 CPLDebug("WFS",
     262             :                          "Field \"%s\".\"%s\" unknown. Cannot use server-side "
     263             :                          "filtering",
     264           0 :                          poExpr->table_name, poExpr->string_value);
     265             :             else
     266           0 :                 CPLDebug(
     267             :                     "WFS",
     268             :                     "Field \"%s\" unknown. Cannot use server-side filtering",
     269           0 :                     poExpr->string_value);
     270           0 :             return false;
     271             :         }
     272             : 
     273         117 :         if (psOptions->nVersion >= 200)
     274             :             osFilter +=
     275          64 :                 CPLSPrintf("<%sValueReference>", psOptions->pszNSPrefix);
     276             :         else
     277          53 :             osFilter += CPLSPrintf("<%sPropertyName>", psOptions->pszNSPrefix);
     278         117 :         char *pszFieldnameXML = CPLEscapeString(pszFieldname, -1, CPLES_XML);
     279         117 :         osFilter += pszFieldnameXML;
     280         117 :         CPLFree(pszFieldnameXML);
     281         117 :         if (psOptions->nVersion >= 200)
     282             :             osFilter +=
     283          64 :                 CPLSPrintf("</%sValueReference>", psOptions->pszNSPrefix);
     284             :         else
     285          53 :             osFilter += CPLSPrintf("</%sPropertyName>", psOptions->pszNSPrefix);
     286             : 
     287         117 :         return true;
     288             :     }
     289             : 
     290         190 :     if (poExpr->eNodeType == SNT_CONSTANT)
     291             :     {
     292          27 :         if (bExpectBinary)
     293           0 :             return false;
     294             : 
     295          27 :         osFilter += CPLSPrintf("<%sLiteral>", psOptions->pszNSPrefix);
     296          27 :         if (!WFS_ExprDumpRawLitteral(osFilter, poExpr))
     297           0 :             return false;
     298          27 :         osFilter += CPLSPrintf("</%sLiteral>", psOptions->pszNSPrefix);
     299             : 
     300          27 :         return true;
     301             :     }
     302             : 
     303         163 :     if (poExpr->eNodeType != SNT_OPERATION)
     304           0 :         return false;  // Should not happen.
     305             : 
     306         163 :     if (poExpr->nOperation == SWQ_NOT)
     307             :     {
     308           6 :         osFilter += CPLSPrintf("<%sNot>", psOptions->pszNSPrefix);
     309           6 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], TRUE,
     310             :                                      psOptions))
     311           4 :             return false;
     312           2 :         osFilter += CPLSPrintf("</%sNot>", psOptions->pszNSPrefix);
     313           2 :         return true;
     314             :     }
     315             : 
     316         157 :     if (poExpr->nOperation == SWQ_LIKE || poExpr->nOperation == SWQ_ILIKE)
     317             :     {
     318           6 :         CPLString osVal;
     319             :         const char *pszMatchCase =
     320           6 :             poExpr->nOperation == SWQ_LIKE &&
     321           3 :                     !CPLTestBool(
     322             :                         CPLGetConfigOption("OGR_SQL_LIKE_AS_ILIKE", "FALSE"))
     323           6 :                 ? "true"
     324           3 :                 : "false";
     325           3 :         if (psOptions->nVersion == 100)
     326             :             osFilter +=
     327             :                 CPLSPrintf("<%sPropertyIsLike wildCard=\"*\" singleChar=\"_\" "
     328             :                            "escape=\"!\" matchCase=\"%s\">",
     329           0 :                            psOptions->pszNSPrefix, pszMatchCase);
     330             :         else
     331             :             osFilter +=
     332             :                 CPLSPrintf("<%sPropertyIsLike wildCard=\"*\" singleChar=\"_\" "
     333             :                            "escapeChar=\"!\" matchCase=\"%s\">",
     334           3 :                            psOptions->pszNSPrefix, pszMatchCase);
     335           3 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE,
     336             :                                      psOptions))
     337           0 :             return false;
     338           3 :         if (poExpr->papoSubExpr[1]->eNodeType != SNT_CONSTANT &&
     339           0 :             poExpr->papoSubExpr[1]->field_type != SWQ_STRING)
     340           0 :             return false;
     341           3 :         osFilter += CPLSPrintf("<%sLiteral>", psOptions->pszNSPrefix);
     342             : 
     343             :         // Escape value according to above special characters.  For URL
     344             :         // compatibility reason, we remap the OGR SQL '%' wildcard into '*'.
     345             :         char ch;
     346          16 :         for (int i = 0; (ch = poExpr->papoSubExpr[1]->string_value[i]) != '\0';
     347             :              i++)
     348             :         {
     349          13 :             if (ch == '%')
     350           6 :                 osVal += "*";
     351           7 :             else if (ch == '!')
     352           0 :                 osVal += "!!";
     353           7 :             else if (ch == '*')
     354           0 :                 osVal += "!*";
     355             :             else
     356             :             {
     357             :                 char ach[2];
     358           7 :                 ach[0] = ch;
     359           7 :                 ach[1] = 0;
     360           7 :                 osVal += ach;
     361             :             }
     362             :         }
     363           3 :         char *pszXML = CPLEscapeString(osVal, -1, CPLES_XML);
     364           3 :         osFilter += pszXML;
     365           3 :         CPLFree(pszXML);
     366           3 :         osFilter += CPLSPrintf("</%sLiteral>", psOptions->pszNSPrefix);
     367           3 :         osFilter += CPLSPrintf("</%sPropertyIsLike>", psOptions->pszNSPrefix);
     368           3 :         return true;
     369             :     }
     370             : 
     371         154 :     if (poExpr->nOperation == SWQ_ISNULL)
     372             :     {
     373           6 :         osFilter += CPLSPrintf("<%sPropertyIsNull>", psOptions->pszNSPrefix);
     374           6 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE,
     375             :                                      psOptions))
     376           4 :             return false;
     377           2 :         osFilter += CPLSPrintf("</%sPropertyIsNull>", psOptions->pszNSPrefix);
     378           2 :         psOptions->bOutNeedsNullCheck = TRUE;
     379           2 :         return true;
     380             :     }
     381             : 
     382         148 :     if (poExpr->nOperation == SWQ_EQ || poExpr->nOperation == SWQ_NE ||
     383          97 :         poExpr->nOperation == SWQ_LE || poExpr->nOperation == SWQ_LT ||
     384          93 :         poExpr->nOperation == SWQ_GE || poExpr->nOperation == SWQ_GT)
     385             :     {
     386          59 :         int nOperation = poExpr->nOperation;
     387          59 :         bool bAddClosingNot = false;
     388          59 :         if (!psOptions->bPropertyIsNotEqualToSupported && nOperation == SWQ_NE)
     389             :         {
     390           0 :             osFilter += CPLSPrintf("<%sNot>", psOptions->pszNSPrefix);
     391           0 :             nOperation = SWQ_EQ;
     392           0 :             bAddClosingNot = true;
     393             :         }
     394             : 
     395          59 :         const char *pszName = nullptr;
     396          59 :         switch (nOperation)
     397             :         {
     398          49 :             case SWQ_EQ:
     399          49 :                 pszName = "PropertyIsEqualTo";
     400          49 :                 break;
     401           2 :             case SWQ_NE:
     402           2 :                 pszName = "PropertyIsNotEqualTo";
     403           2 :                 break;
     404           2 :             case SWQ_LE:
     405           2 :                 pszName = "PropertyIsLessThanOrEqualTo";
     406           2 :                 break;
     407           2 :             case SWQ_LT:
     408           2 :                 pszName = "PropertyIsLessThan";
     409           2 :                 break;
     410           2 :             case SWQ_GE:
     411           2 :                 pszName = "PropertyIsGreaterThanOrEqualTo";
     412           2 :                 break;
     413           2 :             case SWQ_GT:
     414           2 :                 pszName = "PropertyIsGreaterThan";
     415           2 :                 break;
     416           0 :             default:
     417           0 :                 break;
     418             :         }
     419          59 :         osFilter += "<";
     420          59 :         osFilter += psOptions->pszNSPrefix;
     421          59 :         osFilter += pszName;
     422          59 :         osFilter += ">";
     423          59 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE,
     424             :                                      psOptions))
     425           2 :             return false;
     426          57 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[1], FALSE,
     427             :                                      psOptions))
     428           0 :             return false;
     429          57 :         osFilter += "</";
     430          57 :         osFilter += psOptions->pszNSPrefix;
     431          57 :         osFilter += pszName;
     432          57 :         osFilter += ">";
     433          57 :         if (bAddClosingNot)
     434           0 :             osFilter += CPLSPrintf("</%sNot>", psOptions->pszNSPrefix);
     435          57 :         return true;
     436             :     }
     437             : 
     438          89 :     if (poExpr->nOperation == SWQ_AND || poExpr->nOperation == SWQ_OR)
     439             :     {
     440          39 :         const char *pszName = (poExpr->nOperation == SWQ_AND) ? "And" : "Or";
     441          39 :         osFilter += "<";
     442          39 :         osFilter += psOptions->pszNSPrefix;
     443          39 :         osFilter += pszName;
     444          39 :         osFilter += ">";
     445          39 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], TRUE,
     446             :                                      psOptions))
     447           0 :             return false;
     448          39 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[1], TRUE,
     449             :                                      psOptions))
     450           0 :             return false;
     451          39 :         osFilter += "</";
     452          39 :         osFilter += psOptions->pszNSPrefix;
     453          39 :         osFilter += pszName;
     454          39 :         osFilter += ">";
     455          39 :         return true;
     456             :     }
     457             : 
     458          50 :     if (poExpr->nOperation == SWQ_CUSTOM_FUNC &&
     459          50 :         EQUAL(poExpr->string_value, "ST_MakeEnvelope"))
     460             :     {
     461          26 :         OGRSpatialReference oSRS;
     462          13 :         const char *pszSRSName = WFS_ExprGetSRSName(poExpr, 4, psOptions, oSRS);
     463          13 :         bool bAxisSwap = false;
     464             : 
     465          13 :         osFilter += "<gml:Envelope";
     466          13 :         if (pszSRSName)
     467             :         {
     468          13 :             osFilter += " srsName=\"";
     469          13 :             osFilter += pszSRSName;
     470          13 :             osFilter += "\"";
     471          24 :             if (!STARTS_WITH_CI(pszSRSName, "EPSG:") &&
     472          11 :                 (oSRS.EPSGTreatsAsLatLong() ||
     473           2 :                  oSRS.EPSGTreatsAsNorthingEasting()))
     474           9 :                 bAxisSwap = true;
     475             :         }
     476          13 :         osFilter += ">";
     477          13 :         osFilter += "<gml:lowerCorner>";
     478          13 :         if (!WFS_ExprDumpRawLitteral(osFilter,
     479          13 :                                      poExpr->papoSubExpr[bAxisSwap ? 1 : 0]))
     480           0 :             return false;
     481          13 :         osFilter += " ";
     482          13 :         if (!WFS_ExprDumpRawLitteral(osFilter,
     483          13 :                                      poExpr->papoSubExpr[bAxisSwap ? 0 : 1]))
     484           0 :             return false;
     485          13 :         osFilter += "</gml:lowerCorner>";
     486          13 :         osFilter += "<gml:upperCorner>";
     487          13 :         if (!WFS_ExprDumpRawLitteral(osFilter,
     488          13 :                                      poExpr->papoSubExpr[bAxisSwap ? 3 : 2]))
     489           0 :             return false;
     490          13 :         osFilter += " ";
     491          13 :         if (!WFS_ExprDumpRawLitteral(osFilter,
     492          13 :                                      poExpr->papoSubExpr[bAxisSwap ? 2 : 3]))
     493           0 :             return false;
     494          13 :         osFilter += "</gml:upperCorner>";
     495          13 :         osFilter += "</gml:Envelope>";
     496          13 :         return true;
     497             :     }
     498             : 
     499          37 :     if (poExpr->nOperation == SWQ_CUSTOM_FUNC &&
     500          37 :         EQUAL(poExpr->string_value, "ST_GeomFromText"))
     501             :     {
     502          12 :         OGRSpatialReference oSRS;
     503          12 :         const char *pszSRSName = WFS_ExprGetSRSName(poExpr, 1, psOptions, oSRS);
     504          12 :         OGRGeometry *poGeom = nullptr;
     505          12 :         const char *pszWKT = poExpr->papoSubExpr[0]->string_value;
     506          12 :         OGRGeometryFactory::createFromWkt(pszWKT, nullptr, &poGeom);
     507          12 :         char **papszOptions = nullptr;
     508          12 :         papszOptions = CSLSetNameValue(papszOptions, "FORMAT", "GML3");
     509          12 :         if (pszSRSName != nullptr)
     510             :         {
     511          12 :             oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     512             : 
     513          12 :             if (STARTS_WITH_CI(pszSRSName, "urn:ogc:def:crs:EPSG::"))
     514             :                 papszOptions =
     515           8 :                     CSLSetNameValue(papszOptions, "GML3_LONGSRS", "YES");
     516             :             else
     517             :                 papszOptions =
     518           4 :                     CSLSetNameValue(papszOptions, "GML3_LONGSRS", "NO");
     519             : 
     520          12 :             poGeom->assignSpatialReference(&oSRS);
     521             :         }
     522             :         papszOptions =
     523          12 :             CSLSetNameValue(papszOptions, "GMLID",
     524          12 :                             CPLSPrintf("id%d", psOptions->nUniqueGeomGMLId++));
     525          12 :         char *pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
     526          12 :         osFilter += pszGML;
     527          12 :         CSLDestroy(papszOptions);
     528          12 :         delete poGeom;
     529          12 :         CPLFree(pszGML);
     530          12 :         return true;
     531             :     }
     532             : 
     533          25 :     if (poExpr->nOperation == SWQ_CUSTOM_FUNC)
     534             :     {
     535          25 :         const char *pszName =
     536          50 :             EQUAL(poExpr->string_value, "ST_Equals")       ? "Equals"
     537          50 :             : EQUAL(poExpr->string_value, "ST_Disjoint")   ? "Disjoint"
     538          50 :             : EQUAL(poExpr->string_value, "ST_Touches")    ? "Touches"
     539          50 :             : EQUAL(poExpr->string_value, "ST_Contains")   ? "Contains"
     540          29 :             : EQUAL(poExpr->string_value, "ST_Intersects") ? "Intersects"
     541           6 :             : EQUAL(poExpr->string_value, "ST_Within")     ? "Within"
     542           4 :             : EQUAL(poExpr->string_value, "ST_Crosses")    ? "Crosses"
     543           4 :             : EQUAL(poExpr->string_value, "ST_Overlaps")   ? "Overlaps"
     544           2 :             : EQUAL(poExpr->string_value, "ST_DWithin")    ? "DWithin"
     545           0 :             : EQUAL(poExpr->string_value, "ST_Beyond")     ? "Beyond"
     546             :                                                            : nullptr;
     547          25 :         if (pszName == nullptr)
     548           0 :             return false;
     549          25 :         osFilter += "<";
     550          25 :         osFilter += psOptions->pszNSPrefix;
     551          25 :         osFilter += pszName;
     552          25 :         osFilter += ">";
     553          75 :         for (int i = 0; i < 2; i++)
     554             :         {
     555          50 :             if (i == 1 && poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
     556          25 :                 poExpr->papoSubExpr[1]->eNodeType == SNT_OPERATION &&
     557          25 :                 poExpr->papoSubExpr[1]->nOperation == SWQ_CUSTOM_FUNC &&
     558          25 :                 (EQUAL(poExpr->papoSubExpr[1]->string_value,
     559          13 :                        "ST_GeomFromText") ||
     560          13 :                  EQUAL(poExpr->papoSubExpr[1]->string_value,
     561             :                        "ST_MakeEnvelope")))
     562             :             {
     563             :                 int bSameTable =
     564          47 :                     psOptions->poFDefn != nullptr &&
     565          22 :                     (poExpr->papoSubExpr[0]->table_name == nullptr ||
     566           0 :                      EQUAL(poExpr->papoSubExpr[0]->table_name,
     567          25 :                            psOptions->poFDefn->GetName()));
     568          25 :                 if (bSameTable)
     569             :                 {
     570          44 :                     const int nIndex = psOptions->poFDefn->GetGeomFieldIndex(
     571          22 :                         poExpr->papoSubExpr[0]->string_value);
     572          22 :                     if (nIndex >= 0)
     573             :                     {
     574          22 :                         psOptions->poSRS =
     575          22 :                             psOptions->poFDefn->GetGeomFieldDefn(nIndex)
     576          22 :                                 ->GetSpatialRef();
     577             :                     }
     578             :                 }
     579           3 :                 else if (psOptions->poDS != nullptr)
     580             :                 {
     581           4 :                     OGRLayer *poLayer = psOptions->poDS->GetLayerByName(
     582           2 :                         poExpr->papoSubExpr[0]->table_name);
     583           2 :                     if (poLayer)
     584             :                     {
     585           2 :                         OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
     586           4 :                         const int nIndex = poFDefn->GetGeomFieldIndex(
     587           2 :                             poExpr->papoSubExpr[0]->string_value);
     588           2 :                         if (nIndex >= 0)
     589             :                         {
     590           2 :                             psOptions->poSRS = poFDefn->GetGeomFieldDefn(nIndex)
     591           2 :                                                    ->GetSpatialRef();
     592             :                         }
     593             :                     }
     594             :                 }
     595             :             }
     596         100 :             const bool bRet = WFS_ExprDumpAsOGCFilter(
     597          50 :                 osFilter, poExpr->papoSubExpr[i], FALSE, psOptions);
     598          50 :             psOptions->poSRS = nullptr;
     599          50 :             if (!bRet)
     600           0 :                 return false;
     601             :         }
     602          25 :         if (poExpr->nSubExprCount > 2)
     603             :         {
     604             :             osFilter +=
     605           2 :                 CPLSPrintf("<%sDistance unit=\"m\">", psOptions->pszNSPrefix);
     606           2 :             if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[2]))
     607           0 :                 return false;
     608           2 :             osFilter += CPLSPrintf("</%sDistance>", psOptions->pszNSPrefix);
     609             :         }
     610          25 :         osFilter += "</";
     611          25 :         osFilter += psOptions->pszNSPrefix;
     612          25 :         osFilter += pszName;
     613          25 :         osFilter += ">";
     614          25 :         return true;
     615             :     }
     616             : 
     617           0 :     return false;
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*               WFS_TurnSQLFilterToOGCFilter()                         */
     622             : /************************************************************************/
     623             : 
     624             : CPLString
     625          74 : WFS_TurnSQLFilterToOGCFilter(const swq_expr_node *poExpr, OGRDataSource *poDS,
     626             :                              OGRFeatureDefn *poFDefn, int nVersion,
     627             :                              int bPropertyIsNotEqualToSupported,
     628             :                              int bUseFeatureId, int bGmlObjectIdNeedsGMLPrefix,
     629             :                              const char *pszNSPrefix, int *pbOutNeedsNullCheck)
     630             : {
     631          74 :     CPLString osFilter;
     632             :     /* If the filter is only made of querying one or several gml_id */
     633             :     /* (with OR operator), we turn this to <GmlObjectId> list */
     634          74 :     if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, poExpr, bUseFeatureId,
     635             :                                        bGmlObjectIdNeedsGMLPrefix, nVersion))
     636             :     {
     637             :         ExprDumpFilterOptions sOptions;
     638          54 :         sOptions.nVersion = nVersion;
     639          54 :         sOptions.bPropertyIsNotEqualToSupported =
     640          54 :             CPL_TO_BOOL(bPropertyIsNotEqualToSupported);
     641          54 :         sOptions.bOutNeedsNullCheck = FALSE;
     642          54 :         sOptions.poDS = poDS;
     643          54 :         sOptions.poFDefn = poFDefn;
     644          54 :         sOptions.nUniqueGeomGMLId = 1;
     645          54 :         sOptions.poSRS = nullptr;
     646          54 :         sOptions.pszNSPrefix = pszNSPrefix;
     647          54 :         osFilter = "";
     648          54 :         if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr, TRUE, &sOptions))
     649           6 :             osFilter = "";
     650             :         /*else
     651             :             CPLDebug("WFS", "Filter %s", osFilter.c_str());*/
     652          54 :         *pbOutNeedsNullCheck = sOptions.bOutNeedsNullCheck;
     653             :     }
     654             : 
     655          74 :     return osFilter;
     656             : }
     657             : 
     658             : /************************************************************************/
     659             : /*                  OGRWFSSpatialBooleanPredicateChecker()              */
     660             : /************************************************************************/
     661             : 
     662          35 : static swq_field_type OGRWFSSpatialBooleanPredicateChecker(
     663             :     swq_expr_node *op, CPL_UNUSED int bAllowMismatchTypeOnFieldComparison)
     664             : {
     665          35 :     if (op->nSubExprCount != 2)
     666             :     {
     667           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     668             :                  "Wrong number of arguments for %s", op->string_value);
     669           2 :         return SWQ_ERROR;
     670             :     }
     671          97 :     for (int i = 0; i < op->nSubExprCount; i++)
     672             :     {
     673          66 :         if (op->papoSubExpr[i]->field_type != SWQ_GEOMETRY)
     674             :         {
     675           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     676             :                      "Wrong field type for argument %d of %s", i + 1,
     677             :                      op->string_value);
     678           2 :             return SWQ_ERROR;
     679             :         }
     680             :     }
     681          31 :     return SWQ_BOOLEAN;
     682             : }
     683             : 
     684             : /************************************************************************/
     685             : /*                           OGRWFSCheckSRIDArg()                       */
     686             : /************************************************************************/
     687             : 
     688          27 : static bool OGRWFSCheckSRIDArg(swq_expr_node *op, int iSubArgIndex)
     689             : {
     690          27 :     if (op->papoSubExpr[iSubArgIndex]->field_type == SWQ_INTEGER)
     691             :     {
     692          13 :         OGRSpatialReference oSRS;
     693          26 :         if (oSRS.importFromEPSGA(
     694          13 :                 (int)op->papoSubExpr[iSubArgIndex]->int_value) != OGRERR_NONE)
     695             :         {
     696           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     697             :                      "Wrong value for argument %d of %s", iSubArgIndex + 1,
     698             :                      op->string_value);
     699           2 :             return false;
     700             :         }
     701             :     }
     702          14 :     else if (op->papoSubExpr[iSubArgIndex]->field_type == SWQ_STRING)
     703             :     {
     704          12 :         OGRSpatialReference oSRS;
     705          24 :         if (oSRS.SetFromUserInput(
     706          12 :                 op->papoSubExpr[iSubArgIndex]->string_value) != OGRERR_NONE)
     707             :         {
     708           4 :             CPLError(CE_Failure, CPLE_AppDefined,
     709             :                      "Wrong value for argument %d of %s", iSubArgIndex + 1,
     710             :                      op->string_value);
     711           4 :             return false;
     712             :         }
     713             :     }
     714             :     else
     715             :     {
     716           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     717             :                  "Wrong field type for argument %d of %s", iSubArgIndex + 1,
     718             :                  op->string_value);
     719           2 :         return false;
     720             :     }
     721          19 :     return true;
     722             : }
     723             : 
     724             : /************************************************************************/
     725             : /*                   OGRWFSMakeEnvelopeChecker()                        */
     726             : /************************************************************************/
     727             : 
     728             : static swq_field_type
     729          23 : OGRWFSMakeEnvelopeChecker(swq_expr_node *op,
     730             :                           CPL_UNUSED int bAllowMismatchTypeOnFieldComparison)
     731             : {
     732          23 :     if (op->nSubExprCount != 4 && op->nSubExprCount != 5)
     733             :     {
     734           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     735             :                  "Wrong number of arguments for %s", op->string_value);
     736           2 :         return SWQ_ERROR;
     737             :     }
     738         103 :     for (int i = 0; i < 4; i++)
     739             :     {
     740          84 :         if (op->papoSubExpr[i]->field_type != SWQ_INTEGER &&
     741          34 :             op->papoSubExpr[i]->field_type != SWQ_INTEGER64 &&
     742          34 :             op->papoSubExpr[i]->field_type != SWQ_FLOAT)
     743             :         {
     744           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     745             :                      "Wrong field type for argument %d of %s", i + 1,
     746             :                      op->string_value);
     747           2 :             return SWQ_ERROR;
     748             :         }
     749             :     }
     750          19 :     if (op->nSubExprCount == 5)
     751             :     {
     752          13 :         if (!OGRWFSCheckSRIDArg(op, 4))
     753           6 :             return SWQ_ERROR;
     754             :     }
     755          13 :     return SWQ_GEOMETRY;
     756             : }
     757             : 
     758             : /************************************************************************/
     759             : /*                   OGRWFSGeomFromTextChecker()                        */
     760             : /************************************************************************/
     761             : 
     762             : static swq_field_type
     763          28 : OGRWFSGeomFromTextChecker(swq_expr_node *op,
     764             :                           CPL_UNUSED int bAllowMismatchTypeOnFieldComparison)
     765             : {
     766          28 :     if (op->nSubExprCount != 1 && op->nSubExprCount != 2)
     767             :     {
     768           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     769             :                  "Wrong number of arguments for %s", op->string_value);
     770           2 :         return SWQ_ERROR;
     771             :     }
     772          26 :     if (op->papoSubExpr[0]->field_type != SWQ_STRING)
     773             :     {
     774           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     775             :                  "Wrong field type for argument %d of %s", 1, op->string_value);
     776           2 :         return SWQ_ERROR;
     777             :     }
     778          24 :     OGRGeometry *poGeom = nullptr;
     779          24 :     const char *pszWKT = op->papoSubExpr[0]->string_value;
     780          24 :     if (OGRGeometryFactory::createFromWkt(pszWKT, nullptr, &poGeom) !=
     781             :         OGRERR_NONE)
     782             :     {
     783           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     784             :                  "Wrong value for argument %d of %s", 1, op->string_value);
     785           2 :         return SWQ_ERROR;
     786             :     }
     787          22 :     delete poGeom;
     788          22 :     if (op->nSubExprCount == 2)
     789             :     {
     790          14 :         if (!OGRWFSCheckSRIDArg(op, 1))
     791           2 :             return SWQ_ERROR;
     792             :     }
     793          20 :     return SWQ_GEOMETRY;
     794             : }
     795             : 
     796             : /************************************************************************/
     797             : /*                      OGRWFSDWithinBeyondChecker()                    */
     798             : /************************************************************************/
     799             : 
     800             : static swq_field_type
     801           8 : OGRWFSDWithinBeyondChecker(swq_expr_node *op,
     802             :                            CPL_UNUSED int bAllowMismatchTypeOnFieldComparison)
     803             : {
     804           8 :     if (op->nSubExprCount != 3)
     805             :     {
     806           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     807             :                  "Wrong number of arguments for %s", op->string_value);
     808           2 :         return SWQ_ERROR;
     809             :     }
     810          16 :     for (int i = 0; i < 2; i++)
     811             :     {
     812          12 :         if (op->papoSubExpr[i]->field_type != SWQ_GEOMETRY)
     813             :         {
     814           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     815             :                      "Wrong field type for argument %d of %s", i + 1,
     816             :                      op->string_value);
     817           2 :             return SWQ_ERROR;
     818             :         }
     819             :     }
     820           4 :     if (op->papoSubExpr[2]->field_type != SWQ_INTEGER &&
     821           2 :         op->papoSubExpr[2]->field_type != SWQ_INTEGER64 &&
     822           2 :         op->papoSubExpr[2]->field_type != SWQ_FLOAT)
     823             :     {
     824           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     825             :                  "Wrong field type for argument %d of %s", 2 + 1,
     826             :                  op->string_value);
     827           2 :         return SWQ_ERROR;
     828             :     }
     829           2 :     return SWQ_BOOLEAN;
     830             : }
     831             : 
     832             : /************************************************************************/
     833             : /*                   OGRWFSCustomFuncRegistrar                          */
     834             : /************************************************************************/
     835             : 
     836             : class OGRWFSCustomFuncRegistrar : public swq_custom_func_registrar
     837             : {
     838             :   public:
     839           1 :     OGRWFSCustomFuncRegistrar()
     840           1 :     {
     841           1 :     }
     842             : 
     843             :     virtual const swq_operation *GetOperator(const char *) override;
     844             : };
     845             : 
     846             : /************************************************************************/
     847             : /*                  WFSGetCustomFuncRegistrar()                         */
     848             : /************************************************************************/
     849             : 
     850         120 : swq_custom_func_registrar *WFSGetCustomFuncRegistrar()
     851             : {
     852         120 :     static OGRWFSCustomFuncRegistrar obj;
     853         120 :     return &obj;
     854             : }
     855             : 
     856             : /************************************************************************/
     857             : /*                           GetOperator()                              */
     858             : /************************************************************************/
     859             : 
     860             : static const swq_operation OGRWFSSpatialOps[] = {
     861             :     {"ST_Equals", SWQ_CUSTOM_FUNC, nullptr,
     862             :      OGRWFSSpatialBooleanPredicateChecker},
     863             :     {"ST_Disjoint", SWQ_CUSTOM_FUNC, nullptr,
     864             :      OGRWFSSpatialBooleanPredicateChecker},
     865             :     {"ST_Touches", SWQ_CUSTOM_FUNC, nullptr,
     866             :      OGRWFSSpatialBooleanPredicateChecker},
     867             :     {"ST_Contains", SWQ_CUSTOM_FUNC, nullptr,
     868             :      OGRWFSSpatialBooleanPredicateChecker},
     869             :     /*{ "ST_Covers", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker
     870             :        },*/
     871             :     {"ST_Intersects", SWQ_CUSTOM_FUNC, nullptr,
     872             :      OGRWFSSpatialBooleanPredicateChecker},
     873             :     {"ST_Within", SWQ_CUSTOM_FUNC, nullptr,
     874             :      OGRWFSSpatialBooleanPredicateChecker},
     875             :     /*{ "ST_CoveredBy", SWQ_CUSTOM_FUNC, NULL,
     876             :        OGRWFSSpatialBooleanPredicateChecker },*/
     877             :     {"ST_Crosses", SWQ_CUSTOM_FUNC, nullptr,
     878             :      OGRWFSSpatialBooleanPredicateChecker},
     879             :     {"ST_Overlaps", SWQ_CUSTOM_FUNC, nullptr,
     880             :      OGRWFSSpatialBooleanPredicateChecker},
     881             :     {"ST_DWithin", SWQ_CUSTOM_FUNC, nullptr, OGRWFSDWithinBeyondChecker},
     882             :     {"ST_Beyond", SWQ_CUSTOM_FUNC, nullptr, OGRWFSDWithinBeyondChecker},
     883             :     {"ST_MakeEnvelope", SWQ_CUSTOM_FUNC, nullptr, OGRWFSMakeEnvelopeChecker},
     884             :     {"ST_GeomFromText", SWQ_CUSTOM_FUNC, nullptr, OGRWFSGeomFromTextChecker}};
     885             : 
     886         112 : const swq_operation *OGRWFSCustomFuncRegistrar::GetOperator(const char *pszName)
     887             : {
     888         928 :     for (int i = 0;
     889         928 :          i < (int)(sizeof(OGRWFSSpatialOps) / sizeof(OGRWFSSpatialOps[0])); i++)
     890             :     {
     891         928 :         if (EQUAL(OGRWFSSpatialOps[i].pszName, pszName))
     892         112 :             return &OGRWFSSpatialOps[i];
     893             :     }
     894           0 :     return nullptr;
     895             : }

Generated by: LCOV version 1.14