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