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

Generated by: LCOV version 1.14