tinyows 1.2.2
fe_comparison_ops.c
Go to the documentation of this file.
1/*
2 Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 IN THE SOFTWARE.
21*/
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <assert.h>
28
29#include "../ows/ows.h"
30
31
32/*
33 * Return expression matching the comparison operators following :
34 * PropertyIsEqualTo, PropertyIsNotEqualTo, PropertyIsLessThan
35 * PropertyIsGreaterThan, PropertyIsLessThanOrEqualTo, PropertyIsGreaterThanOrEqualTo
36 */
37static buffer *fe_binary_comparison_op(ows * o, buffer * typename, filter_encoding * fe, xmlNodePtr n)
38{
39 buffer *tmp, *type, *name;
40 xmlChar *matchcase;
41 bool bool_type = false;
42 bool sensitive_case = true;
43
44 assert(o && typename && fe && n);
45
46 tmp = buffer_init();
47 name = buffer_init();
48
49 buffer_add_str(name, (char *) n->name);
50
51 /* By default, comparison is case sensitive */
52 matchcase = xmlGetProp(n, (xmlChar *) "matchCase");
53 if (matchcase && !strcmp((char *) matchcase, "false")) sensitive_case = false;
54 xmlFree(matchcase);
55
56 n = n->children;
57
58 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
59
60 /* If comparison are explicitly not case sensitive */
61 if (!sensitive_case) buffer_add_str(fe->sql, "lower(");
62
63 tmp = fe_expression(o, typename, fe, tmp, n);
64 if (fe->error_code) {
65 buffer_free(tmp);
66 buffer_free(name);
67 return fe->sql;
68 }
69
70 buffer_copy(fe->sql, tmp);
71
72 if (buffer_cmp(name, "PropertyIsEqualTo") || buffer_cmp(name, "PropertyIsNotEqualTo")) {
73 /* remove brackets (if any) and quotation marks */
74 if (tmp->buf[0] == '(') {
75 if (tmp->use < 3) {
76 buffer_free(tmp);
77 buffer_free(name);
79 return fe->sql;
80 }
81 buffer_pop(tmp, 2);
82 buffer_shift(tmp, 2);
83 } else {
84 if (tmp->use < 1) {
85 buffer_free(tmp);
86 buffer_free(name);
88 return fe->sql;
89 }
90 buffer_pop(tmp, 1);
91 buffer_shift(tmp, 1);
92 }
93
94 type = ows_psql_type(o, ows_layer_prefix_to_uri(o->layers, typename), tmp);
95
96 if (buffer_cmp(type, "bool")) bool_type = true;
97 }
98
99 if (!sensitive_case) buffer_add_str(fe->sql, ")");
100
101 if (buffer_cmp(name, "PropertyIsEqualTo"))
102 buffer_add_str(fe->sql, " = ");
103
104 if (buffer_cmp(name, "PropertyIsNotEqualTo"))
105 buffer_add_str(fe->sql, " != ");
106
107 if (buffer_cmp(name, "PropertyIsLessThan"))
108 buffer_add_str(fe->sql, " < ");
109
110 if (buffer_cmp(name, "PropertyIsGreaterThan"))
111 buffer_add_str(fe->sql, " > ");
112
113 if (buffer_cmp(name, "PropertyIsLessThanOrEqualTo"))
114 buffer_add_str(fe->sql, " <= ");
115
116 if (buffer_cmp(name, "PropertyIsGreaterThanOrEqualTo"))
117 buffer_add_str(fe->sql, " >= ");
118
119 buffer_empty(tmp);
120
121 n = n->next;
122
123 while (n->type != XML_ELEMENT_NODE) n = n->next;
124
125 if (!sensitive_case) buffer_add_str(fe->sql, "lower(");
126
127 tmp = fe_expression(o, typename, fe, tmp, n);
128 if (fe->error_code) {
129 buffer_free(tmp);
130 buffer_free(name);
131 return fe->sql;
132 }
133
134 /* If property is a boolean, XML content transformation */
135 if (bool_type) {
136 if (buffer_cmp(tmp, "'1'")) buffer_add_str(fe->sql, "'t'");
137 if (buffer_cmp(tmp, "'0'")) buffer_add_str(fe->sql, "'f'");
138 } else buffer_copy(fe->sql, tmp);
139
140 if (!sensitive_case) buffer_add_str(fe->sql, ")");
141
142 buffer_free(tmp);
143 buffer_free(name);
144
145 return fe->sql;
146}
147
148
149/*
150 * String comparison operator with pattern matching
151 * FIXME : remains a problem when escaping \* -> \%
152 */
153static buffer *fe_property_is_like(ows * o, buffer * typename, filter_encoding * fe, xmlNodePtr n)
154{
155 xmlChar *content, *wildcard, *singlechar, *escape, *matchcase;
156 buffer *pg_string;
157 char *escaped;
158 bool sensitive_case = true;
159
160 assert(o && typename && fe && n);
161
162 wildcard = xmlGetProp(n, (xmlChar *) "wildCard");
163 singlechar = xmlGetProp(n, (xmlChar *) "singleChar");
164 matchcase = xmlGetProp(n, (xmlChar *) "matchCase");
165
166 if (ows_version_get(o->request->version) == 100)
167 escape = xmlGetProp(n, (xmlChar *) "escape");
168 else
169 escape = xmlGetProp(n, (xmlChar *) "escapeChar");
170
171 /* By default, comparison is case sensitive */
172 if (matchcase && !strcmp((char *) matchcase, "false")) sensitive_case = false;
173
174 n = n->children;
175
176 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
177
178 /* If comparison are explicitly not case sensitive */
179 if (!sensitive_case) buffer_add_str(fe->sql, "LOWER(");
180
181 /* We need to cast as varchar at least for timestamp PostgreSQL data type */
182 buffer_add_str(fe->sql, " CAST(\"");
183 fe->sql = fe_property_name(o, typename, fe, fe->sql, n, false, true);
184 buffer_add_str(fe->sql, "\" AS varchar)");
185
186 if (!sensitive_case) {
187 buffer_add_str(fe->sql, ") LIKE LOWER(E");
188 } else {
189 buffer_add_str(fe->sql, " LIKE E");
190 }
191
192 n = n->next;
193
194 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
195
196 content = xmlNodeGetContent(n->children);
197
198 pg_string = buffer_init();
199 buffer_add_str(pg_string, (char *) content);
200
201 /* Replace the wildcard,singlechar and escapechar */
202 if ((char *) wildcard && (char *) singlechar && (char *) escape) {
203 if (strlen((char *) escape)) pg_string = buffer_replace(pg_string, (char *) escape, "\\\\");
204 if (strlen((char *) wildcard)) pg_string = buffer_replace(pg_string, (char *) wildcard, "%");
205 if (strlen((char *) singlechar)) pg_string = buffer_replace(pg_string, (char *) singlechar, "_");
206 } else fe->error_code = FE_ERROR_FILTER;
207
208 buffer_add_str(fe->sql, "'");
209 escaped = ows_psql_escape_string(o, pg_string->buf);
210 if (escaped) {
211 buffer_add_str(fe->sql, escaped);
212 free(escaped);
213 }
214 buffer_add_str(fe->sql, "'");
215
216 if (!sensitive_case) buffer_add_str(fe->sql, ")");
217
218 xmlFree(content);
219 xmlFree(wildcard);
220 xmlFree(singlechar);
221 xmlFree(matchcase);
222 xmlFree(escape);
223 buffer_free(pg_string);
224
225 return fe->sql;
226}
227
228
229/*
230 * Check if the value of a property is null
231 */
232static buffer *fe_property_is_null(ows * o, buffer * typename, filter_encoding * fe, xmlNodePtr n)
233{
234 assert(o && typename && fe && n);
235
236 n = n->children;
237 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
238 buffer_add(fe->sql, '"');
239 fe->sql = fe_property_name(o, typename, fe, fe->sql, n, false, true);
240 buffer_add_str(fe->sql, "\" isnull");
241
242 return fe->sql;
243}
244
245
246/*
247 * Check if property is between two boundary values
248 */
249static buffer *fe_property_is_between(ows * o, buffer * typename, filter_encoding * fe, xmlNodePtr n)
250{
251 buffer *tmp;
252
253 assert(o && typename && fe && n);
254
255 tmp = buffer_init();
256
257 n = n->children;
258
259 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
260
261 tmp = fe_expression(o, typename, fe, tmp, n);
262
263 buffer_copy(fe->sql, tmp);
264 buffer_empty(tmp);
265
266 buffer_add_str(fe->sql, " Between ");
267
268 n = n->next;
269
270 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
271
272 tmp = fe_expression(o, typename, fe, tmp, n->children);
273
274 buffer_copy(fe->sql, tmp);
275 buffer_empty(tmp);
276
277 buffer_add_str(fe->sql, " And ");
278
279 n = n->next;
280
281 while (n->type != XML_ELEMENT_NODE) n = n->next; /* eat spaces */
282
283 tmp = fe_expression(o, typename, fe, tmp, n->children);
284
285 buffer_copy(fe->sql, tmp);
286 buffer_free(tmp);
287
288 return fe->sql;
289}
290
291
292/*
293 * Check if the string is a comparison operator
294 */
295bool fe_is_comparison_op(char *name)
296{
297 assert(name);
298
299 /* Case sensitive comparison as specified in GML standard */
300 if ( !strcmp(name, "PropertyIsEqualTo")
301 || !strcmp(name, "PropertyIsNotEqualTo")
302 || !strcmp(name, "PropertyIsLessThan")
303 || !strcmp(name, "PropertyIsGreaterThan")
304 || !strcmp(name, "PropertyIsLessThanOrEqualTo")
305 || !strcmp(name, "PropertyIsGreaterThanOrEqualTo")
306 || !strcmp(name, "PropertyIsLike")
307 || !strcmp(name, "PropertyIsNull")
308 || !strcmp(name, "PropertyIsBetween"))
309 return true;
310
311 return false;
312}
313
314
315/*
316 * Execute the matching comparison function
317 * CAUTION : call fe_is_comparison_op before calling this function,
318 */
319buffer *fe_comparison_op(ows * o, buffer * typename, filter_encoding * fe, xmlNodePtr n)
320{
321 assert(o && typename && fe && n);
322
323 /* Case sensitive comparison as specified in GML standard */
324 if ( !strcmp((char *) n->name, "PropertyIsEqualTo")
325 || !strcmp((char *) n->name, "PropertyIsNotEqualTo")
326 || !strcmp((char *) n->name, "PropertyIsLessThan")
327 || !strcmp((char *) n->name, "PropertyIsGreaterThan")
328 || !strcmp((char *) n->name, "PropertyIsLessThanOrEqualTo")
329 || !strcmp((char *) n->name, "PropertyIsGreaterThanOrEqualTo"))
330 fe->sql = fe_binary_comparison_op(o, typename, fe, n);
331 else if (!strcmp((char *) n->name, "PropertyIsLike"))
332 fe->sql = fe_property_is_like(o, typename, fe, n);
333 else if (!strcmp((char *) n->name, "PropertyIsNull"))
334 fe->sql = fe_property_is_null(o, typename, fe, n);
335 else if (!strcmp((char *) n->name, "PropertyIsBetween"))
336 fe->sql = fe_property_is_between(o, typename, fe, n);
337 else
339
340 return fe->sql;
341}
static buffer * fe_property_is_like(ows *o, buffer *typename, filter_encoding *fe, xmlNodePtr n)
bool fe_is_comparison_op(char *name)
static buffer * fe_property_is_null(ows *o, buffer *typename, filter_encoding *fe, xmlNodePtr n)
static buffer * fe_property_is_between(ows *o, buffer *typename, filter_encoding *fe, xmlNodePtr n)
buffer * fe_comparison_op(ows *o, buffer *typename, filter_encoding *fe, xmlNodePtr n)
static buffer * fe_binary_comparison_op(ows *o, buffer *typename, filter_encoding *fe, xmlNodePtr n)
void buffer_add(buffer *buf, char c)
Definition buffer.c:123
int ows_version_get(ows_version *v)
void buffer_empty(buffer *buf)
Definition buffer.c:100
void buffer_copy(buffer *dest, const buffer *src)
Definition buffer.c:350
bool buffer_cmp(const buffer *buf, const char *str)
Definition buffer.c:290
buffer * ows_psql_type(ows *o, buffer *layer_name, buffer *property)
Definition ows_psql.c:513
void buffer_add_str(buffer *buf, const char *str)
Definition buffer.c:254
buffer * fe_expression(ows *o, buffer *typename, filter_encoding *fe, buffer *sql, xmlNodePtr n)
Definition fe_filter.c:119
char * ows_psql_escape_string(ows *o, const char *content)
Definition ows_psql.c:840
buffer * buffer_replace(buffer *buf, char *before, char *after)
Definition buffer.c:412
void buffer_free(buffer *buf)
Definition buffer.c:83
void buffer_shift(buffer *buf, size_t len)
Definition buffer.c:392
void buffer_pop(buffer *buf, size_t len)
Definition buffer.c:379
buffer * buffer_init()
Definition buffer.c:61
buffer * fe_property_name(ows *o, buffer *typename, filter_encoding *fe, buffer *sql, xmlNodePtr n, bool check_geom_column, bool mandatory)
Definition fe_filter.c:210
buffer * ows_layer_prefix_to_uri(ows_layer_list *ll, buffer *layer_name_prefix)
Definition ows_layer.c:343
@ FE_ERROR_FILTER
Definition ows_struct.h:330
char * buf
size to next realloc
Definition ows_struct.h:39
size_t use
Definition ows_struct.h:36
enum fe_error_code error_code
Definition ows_struct.h:346
ows_version * version
Definition ows_struct.h:353
ows_request * request
Definition ows_struct.h:403
ows_layer_list * layers
Definition ows_struct.h:402

Generated for tinyows by doxygen 1.10.0