Line data Source code
1 : /******************************************************************************
2 : *
3 : * Component: OGR SQL Engine
4 : * Purpose: Implementation of SWQGeneralEvaluator and SWQGeneralChecker
5 : * functions used to represent functions during evaluation and
6 : * parsing.
7 : * Author: Frank Warmerdam <warmerdam@pobox.com>
8 : *
9 : ******************************************************************************
10 : * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
11 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "cpl_port.h"
33 : #include "ogr_swq.h"
34 :
35 : #include <cctype>
36 : #include <climits>
37 : #include <cstdlib>
38 : #include <cstring>
39 : #include <string>
40 :
41 : #include "cpl_conv.h"
42 : #include "cpl_error.h"
43 : #include "cpl_safemaths.hpp"
44 : #include "cpl_string.h"
45 : #include "ogr_geometry.h"
46 : #include "ogr_p.h"
47 : #include "utf8.h"
48 :
49 : /************************************************************************/
50 : /* swq_test_like() */
51 : /* */
52 : /* Does input match pattern? */
53 : /************************************************************************/
54 :
55 68383100 : int swq_test_like(const char *input, const char *pattern, char chEscape,
56 : bool insensitive, bool bUTF8Strings)
57 :
58 : {
59 68383100 : if (input == nullptr || pattern == nullptr)
60 0 : return 0;
61 :
62 73377000 : while (*input != '\0')
63 : {
64 73375900 : if (*pattern == '\0')
65 2 : return 0;
66 :
67 73375900 : else if (*pattern == chEscape)
68 : {
69 17 : pattern++;
70 17 : if (*pattern == '\0')
71 0 : return 0;
72 17 : if (*pattern != *input)
73 : {
74 0 : return 0;
75 : }
76 : else
77 : {
78 17 : input++;
79 17 : pattern++;
80 : }
81 : }
82 :
83 73375900 : else if (*pattern == '_')
84 : {
85 41388 : pattern++;
86 41388 : if (bUTF8Strings && static_cast<unsigned int>(*input) > 127)
87 : {
88 : // Continuation bytes of such characters are of the form
89 : // 10xxxxxx (0x80), whereas single-byte are 0xxxxxxx
90 : // and the start of a multi-byte is 11xxxxxx
91 8 : do
92 : {
93 16 : input++;
94 16 : } while (static_cast<unsigned int>(*input) > 127);
95 : }
96 : else
97 : {
98 41380 : input++;
99 : }
100 : }
101 73334500 : else if (*pattern == '%')
102 : {
103 141578 : if (pattern[1] == '\0')
104 12732 : return 1;
105 :
106 : // Try eating varying amounts of the input till we get a positive.
107 68252900 : for (int eat = 0; input[eat] != '\0'; eat++)
108 : {
109 68125500 : if (swq_test_like(input + eat, pattern + 1, chEscape,
110 68125500 : insensitive, bUTF8Strings))
111 1444 : return 1;
112 : }
113 :
114 127402 : return 0;
115 : }
116 : else
117 : {
118 73192900 : if (bUTF8Strings && insensitive)
119 : {
120 : const auto IsStringLongEnough =
121 146385000 : [](const char *str, size_t nReqSize)
122 : {
123 146385000 : while (nReqSize >= 2)
124 : {
125 41 : if (str[1] == 0)
126 0 : return false;
127 41 : str++;
128 41 : nReqSize--;
129 : }
130 146385000 : return true;
131 : };
132 :
133 : const auto pattern_codepoint_size =
134 73192500 : utf8codepointcalcsize(pattern);
135 73192500 : if (!IsStringLongEnough(pattern, pattern_codepoint_size))
136 68240300 : return 0;
137 73192500 : utf8_int32_t pattern_codepoint = 0;
138 73192500 : utf8codepoint(pattern, &pattern_codepoint);
139 :
140 73192500 : const auto input_codepoint_size = utf8codepointcalcsize(input);
141 73192500 : if (!IsStringLongEnough(input, input_codepoint_size))
142 0 : return 0;
143 73192500 : utf8_int32_t input_codepoint = 0;
144 73192500 : utf8codepoint(input, &input_codepoint);
145 :
146 212320000 : if (!(input_codepoint == pattern_codepoint ||
147 70886900 : utf8uprcodepoint(input_codepoint) ==
148 70886900 : utf8uprcodepoint(pattern_codepoint) ||
149 68240300 : utf8lwrcodepoint(input_codepoint) ==
150 68240300 : utf8lwrcodepoint(pattern_codepoint)))
151 : {
152 68240300 : return 0;
153 : }
154 :
155 4952200 : pattern += pattern_codepoint_size;
156 4952200 : input += input_codepoint_size;
157 : }
158 411 : else if ((!insensitive && *pattern != *input) ||
159 46 : (insensitive &&
160 46 : CPLTolower(static_cast<unsigned char>(*pattern)) !=
161 46 : CPLTolower(static_cast<unsigned char>(*input))))
162 : {
163 108 : return 0;
164 : }
165 : else
166 : {
167 257 : input++;
168 257 : pattern++;
169 : }
170 : }
171 : }
172 :
173 1062 : if (*pattern != '\0' && strcmp(pattern, "%") != 0)
174 778 : return 0;
175 : else
176 284 : return 1;
177 : }
178 :
179 : /************************************************************************/
180 : /* OGRHStoreGetValue() */
181 : /************************************************************************/
182 :
183 20 : static char *OGRHStoreCheckEnd(char *pszIter, int bIsKey)
184 : {
185 20 : pszIter++;
186 31 : for (; *pszIter != '\0'; pszIter++)
187 : {
188 24 : if (bIsKey)
189 : {
190 19 : if (*pszIter == ' ')
191 : {
192 : ;
193 : }
194 12 : else if (*pszIter == '=' && pszIter[1] == '>')
195 : {
196 11 : return pszIter + 2;
197 : }
198 : else
199 : {
200 1 : return nullptr;
201 : }
202 : }
203 : else
204 : {
205 5 : if (*pszIter == ' ')
206 : {
207 : ;
208 : }
209 1 : else if (*pszIter == ',')
210 : {
211 0 : return pszIter + 1;
212 : }
213 : else
214 : {
215 1 : return nullptr;
216 : }
217 : }
218 : }
219 7 : return pszIter;
220 : }
221 :
222 46 : static char *OGRHStoreGetNextString(char *pszIter, char **ppszOut, int bIsKey)
223 : {
224 : char ch;
225 46 : bool bInString = false;
226 46 : char *pszOut = nullptr;
227 46 : *ppszOut = nullptr;
228 124 : for (; (ch = *pszIter) != '\0'; pszIter++)
229 : {
230 110 : if (bInString)
231 : {
232 36 : if (ch == '"')
233 : {
234 17 : *pszOut = '\0';
235 17 : return OGRHStoreCheckEnd(pszIter, bIsKey);
236 : }
237 19 : else if (ch == '\\')
238 : {
239 1 : pszIter++;
240 1 : if ((ch = *pszIter) == '\0')
241 0 : return nullptr;
242 : }
243 19 : *pszOut = ch;
244 19 : pszOut++;
245 : }
246 : else
247 : {
248 74 : if (ch == ' ')
249 : {
250 16 : if (pszOut != nullptr)
251 : {
252 3 : *pszIter = '\0';
253 3 : return OGRHStoreCheckEnd(pszIter, bIsKey);
254 : }
255 : }
256 58 : else if (bIsKey && ch == '=' && pszIter[1] == '>')
257 : {
258 11 : if (pszOut != nullptr)
259 : {
260 11 : *pszIter = '\0';
261 11 : return pszIter + 2;
262 : }
263 : }
264 47 : else if (!bIsKey && ch == ',')
265 : {
266 1 : if (pszOut != nullptr)
267 : {
268 1 : *pszIter = '\0';
269 1 : return pszIter + 1;
270 : }
271 : }
272 46 : else if (ch == '"')
273 : {
274 19 : pszOut = pszIter + 1;
275 19 : *ppszOut = pszOut;
276 19 : bInString = true;
277 : }
278 27 : else if (pszOut == nullptr)
279 : {
280 25 : pszOut = pszIter;
281 25 : *ppszOut = pszIter;
282 : }
283 : }
284 : }
285 :
286 14 : if (!bInString && pszOut != nullptr)
287 : {
288 10 : return pszIter;
289 : }
290 4 : return nullptr;
291 : }
292 :
293 26 : static char *OGRHStoreGetNextKeyValue(char *pszHStore, char **ppszKey,
294 : char **ppszValue)
295 : {
296 26 : char *pszNext = OGRHStoreGetNextString(pszHStore, ppszKey, TRUE);
297 26 : if (pszNext == nullptr || *pszNext == '\0')
298 6 : return nullptr;
299 20 : return OGRHStoreGetNextString(pszNext, ppszValue, FALSE);
300 : }
301 :
302 25 : char *OGRHStoreGetValue(const char *pszHStore, const char *pszSearchedKey)
303 : {
304 25 : char *pszHStoreDup = CPLStrdup(pszHStore);
305 25 : char *pszHStoreIter = pszHStoreDup;
306 25 : char *pszRet = nullptr;
307 :
308 : while (true)
309 : {
310 : char *pszKey, *pszValue;
311 : pszHStoreIter =
312 26 : OGRHStoreGetNextKeyValue(pszHStoreIter, &pszKey, &pszValue);
313 26 : if (pszHStoreIter == nullptr)
314 : {
315 10 : break;
316 : }
317 16 : if (strcmp(pszKey, pszSearchedKey) == 0)
318 : {
319 11 : pszRet = CPLStrdup(pszValue);
320 11 : break;
321 : }
322 5 : if (*pszHStoreIter == '\0')
323 : {
324 4 : break;
325 : }
326 1 : }
327 25 : CPLFree(pszHStoreDup);
328 25 : return pszRet;
329 : }
330 :
331 : #ifdef DEBUG_VERBOSE
332 : /************************************************************************/
333 : /* OGRFormatDate() */
334 : /************************************************************************/
335 :
336 : #ifdef __GNUC__
337 : #pragma GCC diagnostic push
338 : #pragma GCC diagnostic ignored "-Wunused-function"
339 : #endif
340 : static const char *OGRFormatDate(const OGRField *psField)
341 : {
342 : return CPLSPrintf("%04d/%02d/%02d %02d:%02d:%06.3f", psField->Date.Year,
343 : psField->Date.Month, psField->Date.Day,
344 : psField->Date.Hour, psField->Date.Minute,
345 : psField->Date.Second);
346 : }
347 :
348 : #ifdef __GNUC__
349 : #pragma GCC diagnostic pop
350 : #endif
351 :
352 : #endif
353 :
354 : /************************************************************************/
355 : /* SWQGeneralEvaluator() */
356 : /************************************************************************/
357 :
358 67858 : swq_expr_node *SWQGeneralEvaluator(swq_expr_node *node,
359 : swq_expr_node **sub_node_values,
360 : const swq_evaluation_context &sContext)
361 :
362 : {
363 67858 : swq_expr_node *poRet = nullptr;
364 :
365 : /* -------------------------------------------------------------------- */
366 : /* Floating point operations. */
367 : /* -------------------------------------------------------------------- */
368 67858 : if (sub_node_values[0]->field_type == SWQ_FLOAT ||
369 61880 : (node->nSubExprCount > 1 &&
370 61375 : sub_node_values[1]->field_type == SWQ_FLOAT))
371 : {
372 6032 : poRet = new swq_expr_node(0);
373 6032 : poRet->field_type = node->field_type;
374 :
375 6032 : if (SWQ_IS_INTEGER(sub_node_values[0]->field_type))
376 54 : sub_node_values[0]->float_value =
377 54 : static_cast<double>(sub_node_values[0]->int_value);
378 6032 : if (node->nSubExprCount > 1 &&
379 6024 : SWQ_IS_INTEGER(sub_node_values[1]->field_type))
380 41 : sub_node_values[1]->float_value =
381 41 : static_cast<double>(sub_node_values[1]->int_value);
382 :
383 6032 : if (node->nOperation != SWQ_ISNULL)
384 : {
385 18026 : for (int i = 0; i < node->nSubExprCount; i++)
386 : {
387 12039 : if (sub_node_values[i]->is_null)
388 : {
389 37 : if (poRet->field_type == SWQ_BOOLEAN)
390 : {
391 23 : poRet->int_value = FALSE;
392 23 : return poRet;
393 : }
394 14 : else if (poRet->field_type == SWQ_FLOAT)
395 : {
396 14 : poRet->float_value = 0;
397 14 : poRet->is_null = 1;
398 14 : return poRet;
399 : }
400 0 : else if (SWQ_IS_INTEGER(poRet->field_type))
401 : {
402 0 : poRet->field_type = SWQ_INTEGER;
403 0 : poRet->int_value = 0;
404 0 : poRet->is_null = 1;
405 0 : return poRet;
406 : }
407 : }
408 : }
409 : }
410 :
411 5995 : switch (node->nOperation)
412 : {
413 2094 : case SWQ_EQ:
414 2094 : poRet->int_value = sub_node_values[0]->float_value ==
415 2094 : sub_node_values[1]->float_value;
416 2094 : break;
417 :
418 3528 : case SWQ_NE:
419 3528 : poRet->int_value = sub_node_values[0]->float_value !=
420 3528 : sub_node_values[1]->float_value;
421 3528 : break;
422 :
423 125 : case SWQ_GT:
424 125 : poRet->int_value = sub_node_values[0]->float_value >
425 125 : sub_node_values[1]->float_value;
426 125 : break;
427 :
428 114 : case SWQ_LT:
429 114 : poRet->int_value = sub_node_values[0]->float_value <
430 114 : sub_node_values[1]->float_value;
431 114 : break;
432 :
433 31 : case SWQ_GE:
434 31 : poRet->int_value = sub_node_values[0]->float_value >=
435 31 : sub_node_values[1]->float_value;
436 31 : break;
437 :
438 31 : case SWQ_LE:
439 31 : poRet->int_value = sub_node_values[0]->float_value <=
440 31 : sub_node_values[1]->float_value;
441 31 : break;
442 :
443 18 : case SWQ_IN:
444 : {
445 18 : poRet->int_value = 0;
446 30 : for (int i = 1; i < node->nSubExprCount; i++)
447 : {
448 19 : if (sub_node_values[0]->float_value ==
449 19 : sub_node_values[i]->float_value)
450 : {
451 7 : poRet->int_value = 1;
452 7 : break;
453 : }
454 : }
455 : }
456 18 : break;
457 :
458 5 : case SWQ_BETWEEN:
459 10 : poRet->int_value = sub_node_values[0]->float_value >=
460 9 : sub_node_values[1]->float_value &&
461 4 : sub_node_values[0]->float_value <=
462 4 : sub_node_values[2]->float_value;
463 5 : break;
464 :
465 8 : case SWQ_ISNULL:
466 8 : poRet->int_value = sub_node_values[0]->is_null;
467 8 : break;
468 :
469 7 : case SWQ_ADD:
470 7 : poRet->float_value = sub_node_values[0]->float_value +
471 7 : sub_node_values[1]->float_value;
472 7 : break;
473 :
474 5 : case SWQ_SUBTRACT:
475 5 : poRet->float_value = sub_node_values[0]->float_value -
476 5 : sub_node_values[1]->float_value;
477 5 : break;
478 :
479 5 : case SWQ_MULTIPLY:
480 5 : poRet->float_value = sub_node_values[0]->float_value *
481 5 : sub_node_values[1]->float_value;
482 5 : break;
483 :
484 19 : case SWQ_DIVIDE:
485 19 : if (sub_node_values[1]->float_value == 0)
486 0 : poRet->float_value = INT_MAX;
487 : else
488 19 : poRet->float_value = sub_node_values[0]->float_value /
489 19 : sub_node_values[1]->float_value;
490 19 : break;
491 :
492 5 : case SWQ_MODULUS:
493 : {
494 5 : if (sub_node_values[1]->float_value == 0)
495 0 : poRet->float_value = INT_MAX;
496 : else
497 5 : poRet->float_value = fmod(sub_node_values[0]->float_value,
498 5 : sub_node_values[1]->float_value);
499 5 : break;
500 : }
501 :
502 0 : default:
503 0 : CPLAssert(false);
504 : delete poRet;
505 : poRet = nullptr;
506 : break;
507 5995 : }
508 : }
509 : /* -------------------------------------------------------------------- */
510 : /* integer/boolean operations. */
511 : /* -------------------------------------------------------------------- */
512 61826 : else if (SWQ_IS_INTEGER(sub_node_values[0]->field_type) ||
513 15153 : sub_node_values[0]->field_type == SWQ_BOOLEAN)
514 : {
515 53806 : poRet = new swq_expr_node(0);
516 53806 : poRet->field_type = node->field_type;
517 :
518 53806 : if (node->nOperation != SWQ_ISNULL)
519 : {
520 160015 : for (int i = 0; i < node->nSubExprCount; i++)
521 : {
522 106824 : if (sub_node_values[i]->is_null)
523 : {
524 467 : if (poRet->field_type == SWQ_BOOLEAN)
525 : {
526 451 : poRet->int_value = FALSE;
527 451 : return poRet;
528 : }
529 16 : else if (SWQ_IS_INTEGER(poRet->field_type))
530 : {
531 16 : poRet->int_value = 0;
532 16 : poRet->is_null = 1;
533 16 : return poRet;
534 : }
535 : }
536 : }
537 : }
538 :
539 53339 : switch (node->nOperation)
540 : {
541 4638 : case SWQ_AND:
542 5937 : poRet->int_value = sub_node_values[0]->int_value &&
543 1299 : sub_node_values[1]->int_value;
544 4638 : break;
545 :
546 2311 : case SWQ_OR:
547 4548 : poRet->int_value = sub_node_values[0]->int_value ||
548 2237 : sub_node_values[1]->int_value;
549 2311 : break;
550 :
551 200 : case SWQ_NOT:
552 200 : poRet->int_value = !sub_node_values[0]->int_value;
553 200 : break;
554 :
555 40879 : case SWQ_EQ:
556 40879 : poRet->int_value = sub_node_values[0]->int_value ==
557 40879 : sub_node_values[1]->int_value;
558 40879 : break;
559 :
560 4414 : case SWQ_NE:
561 4414 : poRet->int_value = sub_node_values[0]->int_value !=
562 4414 : sub_node_values[1]->int_value;
563 4414 : break;
564 :
565 127 : case SWQ_GT:
566 127 : poRet->int_value = sub_node_values[0]->int_value >
567 127 : sub_node_values[1]->int_value;
568 127 : break;
569 :
570 201 : case SWQ_LT:
571 201 : poRet->int_value = sub_node_values[0]->int_value <
572 201 : sub_node_values[1]->int_value;
573 201 : break;
574 :
575 88 : case SWQ_GE:
576 88 : poRet->int_value = sub_node_values[0]->int_value >=
577 88 : sub_node_values[1]->int_value;
578 88 : break;
579 :
580 71 : case SWQ_LE:
581 71 : poRet->int_value = sub_node_values[0]->int_value <=
582 71 : sub_node_values[1]->int_value;
583 71 : break;
584 :
585 125 : case SWQ_IN:
586 : {
587 125 : poRet->int_value = 0;
588 310 : for (int i = 1; i < node->nSubExprCount; i++)
589 : {
590 223 : if (sub_node_values[0]->int_value ==
591 223 : sub_node_values[i]->int_value)
592 : {
593 38 : poRet->int_value = 1;
594 38 : break;
595 : }
596 : }
597 : }
598 125 : break;
599 :
600 25 : case SWQ_BETWEEN:
601 50 : poRet->int_value = sub_node_values[0]->int_value >=
602 47 : sub_node_values[1]->int_value &&
603 22 : sub_node_values[0]->int_value <=
604 22 : sub_node_values[2]->int_value;
605 25 : break;
606 :
607 148 : case SWQ_ISNULL:
608 148 : poRet->int_value = sub_node_values[0]->is_null;
609 148 : break;
610 :
611 35 : case SWQ_ADD:
612 : try
613 : {
614 37 : poRet->int_value = (CPLSM(sub_node_values[0]->int_value) +
615 105 : CPLSM(sub_node_values[1]->int_value))
616 33 : .v();
617 : }
618 2 : catch (const std::exception &)
619 : {
620 2 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
621 2 : poRet->is_null = true;
622 : }
623 35 : break;
624 :
625 17 : case SWQ_SUBTRACT:
626 : try
627 : {
628 19 : poRet->int_value = (CPLSM(sub_node_values[0]->int_value) -
629 51 : CPLSM(sub_node_values[1]->int_value))
630 15 : .v();
631 : }
632 2 : catch (const std::exception &)
633 : {
634 2 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
635 2 : poRet->is_null = true;
636 : }
637 17 : break;
638 :
639 25 : case SWQ_MULTIPLY:
640 : try
641 : {
642 32 : poRet->int_value = (CPLSM(sub_node_values[0]->int_value) *
643 75 : CPLSM(sub_node_values[1]->int_value))
644 18 : .v();
645 : }
646 7 : catch (const std::exception &)
647 : {
648 7 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
649 7 : poRet->is_null = true;
650 : }
651 25 : break;
652 :
653 12 : case SWQ_DIVIDE:
654 12 : if (sub_node_values[1]->int_value == 0)
655 1 : poRet->int_value = INT_MAX;
656 : else
657 : {
658 : try
659 : {
660 10 : poRet->int_value =
661 12 : (CPLSM(sub_node_values[0]->int_value) /
662 33 : CPLSM(sub_node_values[1]->int_value))
663 10 : .v();
664 : }
665 1 : catch (const std::exception &)
666 : {
667 1 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
668 1 : poRet->is_null = true;
669 : }
670 : }
671 12 : break;
672 :
673 23 : case SWQ_MODULUS:
674 23 : if (sub_node_values[1]->int_value == 0)
675 0 : poRet->int_value = INT_MAX;
676 : else
677 23 : poRet->int_value = sub_node_values[0]->int_value %
678 23 : sub_node_values[1]->int_value;
679 23 : break;
680 :
681 0 : default:
682 0 : CPLAssert(false);
683 : delete poRet;
684 : poRet = nullptr;
685 : break;
686 53339 : }
687 : }
688 :
689 : /* -------------------------------------------------------------------- */
690 : /* datetime */
691 : /* -------------------------------------------------------------------- */
692 8020 : else if (sub_node_values[0]->field_type == SWQ_TIMESTAMP &&
693 211 : (node->nOperation == SWQ_EQ || node->nOperation == SWQ_GT ||
694 97 : node->nOperation == SWQ_GE || node->nOperation == SWQ_LT ||
695 83 : node->nOperation == SWQ_LE || node->nOperation == SWQ_IN ||
696 64 : node->nOperation == SWQ_BETWEEN))
697 : {
698 152 : if (node->field_type == SWQ_BOOLEAN)
699 : {
700 461 : for (int i = 0; i < node->nSubExprCount; i++)
701 : {
702 313 : if (sub_node_values[i]->is_null)
703 : {
704 4 : poRet = new swq_expr_node(FALSE);
705 4 : poRet->field_type = node->field_type;
706 7 : return poRet;
707 : }
708 : }
709 : }
710 :
711 : OGRField sField0, sField1;
712 148 : poRet = new swq_expr_node(0);
713 148 : poRet->field_type = node->field_type;
714 :
715 148 : if (!OGRParseDate(sub_node_values[0]->string_value, &sField0, 0))
716 : {
717 1 : CPLError(
718 : CE_Failure, CPLE_AppDefined,
719 : "Failed to parse date '%s' evaluating OGR WHERE expression",
720 1 : sub_node_values[0]->string_value);
721 1 : delete poRet;
722 1 : return nullptr;
723 : }
724 147 : if (!OGRParseDate(sub_node_values[1]->string_value, &sField1, 0))
725 : {
726 1 : CPLError(
727 : CE_Failure, CPLE_AppDefined,
728 : "Failed to parse date '%s' evaluating OGR WHERE expression",
729 1 : sub_node_values[1]->string_value);
730 1 : delete poRet;
731 1 : return nullptr;
732 : }
733 :
734 146 : switch (node->nOperation)
735 : {
736 10 : case SWQ_GT:
737 10 : poRet->int_value = OGRCompareDate(&sField0, &sField1) > 0;
738 10 : break;
739 :
740 3 : case SWQ_GE:
741 3 : poRet->int_value = OGRCompareDate(&sField0, &sField1) >= 0;
742 3 : break;
743 :
744 10 : case SWQ_LT:
745 10 : poRet->int_value = OGRCompareDate(&sField0, &sField1) < 0;
746 10 : break;
747 :
748 2 : case SWQ_LE:
749 2 : poRet->int_value = OGRCompareDate(&sField0, &sField1) <= 0;
750 2 : break;
751 :
752 100 : case SWQ_EQ:
753 100 : poRet->int_value = OGRCompareDate(&sField0, &sField1) == 0;
754 100 : break;
755 :
756 5 : case SWQ_BETWEEN:
757 : {
758 : OGRField sField2;
759 5 : if (!OGRParseDate(sub_node_values[2]->string_value, &sField2,
760 : 0))
761 : {
762 1 : CPLError(CE_Failure, CPLE_AppDefined,
763 : "Failed to parse date '%s' evaluating OGR WHERE "
764 : "expression",
765 1 : sub_node_values[2]->string_value);
766 1 : delete poRet;
767 1 : return nullptr;
768 : }
769 :
770 7 : poRet->int_value = (OGRCompareDate(&sField0, &sField1) >= 0) &&
771 3 : (OGRCompareDate(&sField0, &sField2) <= 0);
772 : }
773 4 : break;
774 :
775 16 : case SWQ_IN:
776 : {
777 : OGRField sFieldIn;
778 16 : bool bFound = false;
779 24 : for (int i = 1; i < node->nSubExprCount; ++i)
780 : {
781 20 : if (!OGRParseDate(sub_node_values[i]->string_value,
782 : &sFieldIn, 0))
783 : {
784 0 : CPLError(CE_Failure, CPLE_AppDefined,
785 : "Failed to parse date '%s' evaluating OGR "
786 : "WHERE expression",
787 0 : sub_node_values[i]->string_value);
788 0 : delete poRet;
789 0 : return nullptr;
790 : }
791 20 : if (OGRCompareDate(&sField0, &sFieldIn) == 0)
792 : {
793 12 : bFound = true;
794 12 : break;
795 : }
796 : }
797 16 : poRet->int_value = bFound;
798 : }
799 16 : break;
800 :
801 0 : default:
802 0 : CPLAssert(false);
803 : delete poRet;
804 : poRet = nullptr;
805 : break;
806 145 : }
807 : }
808 :
809 : /* -------------------------------------------------------------------- */
810 : /* String operations. */
811 : /* -------------------------------------------------------------------- */
812 : else
813 : {
814 7868 : poRet = new swq_expr_node(0);
815 7868 : poRet->field_type = node->field_type;
816 :
817 7868 : if (node->nOperation != SWQ_ISNULL)
818 : {
819 22713 : for (int i = 0; i < node->nSubExprCount; i++)
820 : {
821 15238 : if (sub_node_values[i]->is_null)
822 : {
823 236 : if (poRet->field_type == SWQ_BOOLEAN)
824 : {
825 227 : poRet->int_value = FALSE;
826 227 : return poRet;
827 : }
828 9 : else if (poRet->field_type == SWQ_STRING)
829 : {
830 9 : poRet->string_value = CPLStrdup("");
831 9 : poRet->is_null = 1;
832 9 : return poRet;
833 : }
834 : }
835 : }
836 : }
837 :
838 7632 : switch (node->nOperation)
839 : {
840 3553 : case SWQ_EQ:
841 : {
842 : // When comparing timestamps, the +00 at the end might be
843 : // discarded if the other member has no explicit timezone.
844 3553 : if ((sub_node_values[0]->field_type == SWQ_TIMESTAMP ||
845 3553 : sub_node_values[0]->field_type == SWQ_STRING) &&
846 3553 : (sub_node_values[1]->field_type == SWQ_TIMESTAMP ||
847 3553 : sub_node_values[1]->field_type == SWQ_STRING) &&
848 3552 : strlen(sub_node_values[0]->string_value) > 3 &&
849 3081 : strlen(sub_node_values[1]->string_value) > 3 &&
850 2963 : (strcmp(sub_node_values[0]->string_value +
851 2963 : strlen(sub_node_values[0]->string_value) - 3,
852 0 : "+00") == 0 &&
853 0 : sub_node_values[1]->string_value
854 0 : [strlen(sub_node_values[1]->string_value) - 3] ==
855 : ':'))
856 : {
857 0 : if (!sub_node_values[1]->string_value)
858 : {
859 0 : poRet->int_value = false;
860 : }
861 : else
862 : {
863 0 : poRet->int_value =
864 0 : EQUALN(sub_node_values[0]->string_value,
865 : sub_node_values[1]->string_value,
866 : strlen(sub_node_values[1]->string_value));
867 : }
868 : }
869 3553 : else if ((sub_node_values[0]->field_type == SWQ_TIMESTAMP ||
870 3553 : sub_node_values[0]->field_type == SWQ_STRING) &&
871 3553 : (sub_node_values[1]->field_type == SWQ_TIMESTAMP ||
872 3553 : sub_node_values[1]->field_type == SWQ_STRING) &&
873 3552 : strlen(sub_node_values[0]->string_value) > 3 &&
874 3081 : strlen(sub_node_values[1]->string_value) > 3 &&
875 2963 : (sub_node_values[0]->string_value
876 2963 : [strlen(sub_node_values[0]->string_value) - 3] ==
877 0 : ':') &&
878 0 : strcmp(sub_node_values[1]->string_value +
879 0 : strlen(sub_node_values[1]->string_value) -
880 : 3,
881 : "+00") == 0)
882 : {
883 0 : if (!sub_node_values[1]->string_value)
884 : {
885 0 : poRet->int_value = false;
886 : }
887 : else
888 : {
889 0 : poRet->int_value =
890 0 : EQUALN(sub_node_values[0]->string_value,
891 : sub_node_values[1]->string_value,
892 : strlen(sub_node_values[0]->string_value));
893 : }
894 : }
895 : else
896 : {
897 3553 : if (!sub_node_values[1]->string_value)
898 : {
899 1 : poRet->int_value = false;
900 : }
901 : else
902 : {
903 3552 : poRet->int_value =
904 3552 : strcasecmp(sub_node_values[0]->string_value,
905 3552 : sub_node_values[1]->string_value) == 0;
906 : }
907 : }
908 3553 : break;
909 : }
910 :
911 3578 : case SWQ_NE:
912 : {
913 3578 : if (!sub_node_values[1]->string_value)
914 : {
915 1 : poRet->int_value = false;
916 : }
917 : else
918 : {
919 3577 : poRet->int_value =
920 3577 : strcasecmp(sub_node_values[0]->string_value,
921 3577 : sub_node_values[1]->string_value) != 0;
922 : }
923 3578 : break;
924 : }
925 :
926 46 : case SWQ_GT:
927 : {
928 46 : if (!sub_node_values[1]->string_value)
929 : {
930 1 : poRet->int_value = false;
931 : }
932 : else
933 : {
934 45 : poRet->int_value =
935 45 : strcasecmp(sub_node_values[0]->string_value,
936 45 : sub_node_values[1]->string_value) > 0;
937 : }
938 46 : break;
939 : }
940 :
941 42 : case SWQ_LT:
942 : {
943 42 : if (!sub_node_values[1]->string_value)
944 : {
945 1 : poRet->int_value = false;
946 : }
947 : else
948 : {
949 41 : poRet->int_value =
950 41 : strcasecmp(sub_node_values[0]->string_value,
951 41 : sub_node_values[1]->string_value) < 0;
952 : }
953 42 : break;
954 : }
955 :
956 28 : case SWQ_GE:
957 : {
958 28 : if (!sub_node_values[1]->string_value)
959 : {
960 1 : poRet->int_value = false;
961 : }
962 : else
963 : {
964 27 : poRet->int_value =
965 27 : strcasecmp(sub_node_values[0]->string_value,
966 27 : sub_node_values[1]->string_value) >= 0;
967 : }
968 28 : break;
969 : }
970 :
971 39 : case SWQ_LE:
972 : {
973 39 : if (!sub_node_values[1]->string_value)
974 : {
975 1 : poRet->int_value = false;
976 : }
977 : else
978 : {
979 38 : poRet->int_value =
980 38 : strcasecmp(sub_node_values[0]->string_value,
981 38 : sub_node_values[1]->string_value) <= 0;
982 : }
983 39 : break;
984 : }
985 :
986 23 : case SWQ_IN:
987 : {
988 23 : poRet->int_value = 0;
989 46 : for (int i = 1; i < node->nSubExprCount; i++)
990 : {
991 34 : if (sub_node_values[i]->string_value &&
992 32 : strcasecmp(sub_node_values[0]->string_value,
993 32 : sub_node_values[i]->string_value) == 0)
994 : {
995 11 : poRet->int_value = 1;
996 11 : break;
997 : }
998 : }
999 : }
1000 23 : break;
1001 :
1002 7 : case SWQ_BETWEEN:
1003 : {
1004 7 : if (!sub_node_values[1]->string_value)
1005 : {
1006 1 : poRet->int_value = false;
1007 : }
1008 : else
1009 : {
1010 6 : poRet->int_value =
1011 6 : strcasecmp(sub_node_values[0]->string_value,
1012 11 : sub_node_values[1]->string_value) >= 0 &&
1013 5 : strcasecmp(sub_node_values[0]->string_value,
1014 5 : sub_node_values[2]->string_value) <= 0;
1015 : }
1016 7 : break;
1017 : }
1018 :
1019 73 : case SWQ_LIKE:
1020 : {
1021 73 : if (!sub_node_values[1]->string_value)
1022 : {
1023 0 : poRet->int_value = false;
1024 : }
1025 : else
1026 : {
1027 73 : char chEscape = '\0';
1028 73 : if (node->nSubExprCount == 3)
1029 11 : chEscape = sub_node_values[2]->string_value[0];
1030 73 : const bool bInsensitive = CPLTestBool(
1031 : CPLGetConfigOption("OGR_SQL_LIKE_AS_ILIKE", "FALSE"));
1032 73 : poRet->int_value = swq_test_like(
1033 73 : sub_node_values[0]->string_value,
1034 73 : sub_node_values[1]->string_value, chEscape,
1035 73 : bInsensitive, sContext.bUTF8Strings);
1036 : }
1037 73 : break;
1038 : }
1039 :
1040 28 : case SWQ_ILIKE:
1041 : {
1042 28 : if (!sub_node_values[1]->string_value)
1043 : {
1044 0 : poRet->int_value = false;
1045 : }
1046 : else
1047 : {
1048 28 : char chEscape = '\0';
1049 28 : if (node->nSubExprCount == 3)
1050 0 : chEscape = sub_node_values[2]->string_value[0];
1051 28 : poRet->int_value =
1052 28 : swq_test_like(sub_node_values[0]->string_value,
1053 28 : sub_node_values[1]->string_value,
1054 28 : chEscape, true, sContext.bUTF8Strings);
1055 : }
1056 28 : break;
1057 : }
1058 :
1059 157 : case SWQ_ISNULL:
1060 157 : poRet->int_value = sub_node_values[0]->is_null;
1061 157 : break;
1062 :
1063 23 : case SWQ_CONCAT:
1064 : case SWQ_ADD:
1065 : {
1066 46 : CPLString osResult = sub_node_values[0]->string_value;
1067 :
1068 48 : for (int i = 1; i < node->nSubExprCount; i++)
1069 25 : osResult += sub_node_values[i]->string_value;
1070 :
1071 23 : poRet->string_value = CPLStrdup(osResult);
1072 23 : poRet->is_null = sub_node_values[0]->is_null;
1073 23 : break;
1074 : }
1075 :
1076 14 : case SWQ_SUBSTR:
1077 : {
1078 14 : const char *pszSrcStr = sub_node_values[0]->string_value;
1079 :
1080 14 : int nOffset = 0;
1081 14 : if (SWQ_IS_INTEGER(sub_node_values[1]->field_type))
1082 14 : nOffset = static_cast<int>(sub_node_values[1]->int_value);
1083 0 : else if (sub_node_values[1]->field_type == SWQ_FLOAT)
1084 0 : nOffset = static_cast<int>(sub_node_values[1]->float_value);
1085 : // else
1086 : // nOffset = 0;
1087 :
1088 14 : int nSize = 0;
1089 14 : if (node->nSubExprCount < 3)
1090 2 : nSize = 100000;
1091 12 : else if (SWQ_IS_INTEGER(sub_node_values[2]->field_type))
1092 12 : nSize = static_cast<int>(sub_node_values[2]->int_value);
1093 0 : else if (sub_node_values[2]->field_type == SWQ_FLOAT)
1094 0 : nSize = static_cast<int>(sub_node_values[2]->float_value);
1095 : // else
1096 : // nSize = 0;
1097 :
1098 14 : const int nSrcStrLen = static_cast<int>(strlen(pszSrcStr));
1099 :
1100 : // In SQL, the first character is at offset 1.
1101 : // 0 is considered as 1.
1102 14 : if (nOffset > 0)
1103 12 : nOffset--;
1104 : // Some implementations allow negative offsets, to start
1105 : // from the end of the string.
1106 2 : else if (nOffset < 0)
1107 : {
1108 2 : if (nSrcStrLen + nOffset >= 0)
1109 2 : nOffset = nSrcStrLen + nOffset;
1110 : else
1111 0 : nOffset = 0;
1112 : }
1113 :
1114 14 : if (nSize < 0 || nOffset > nSrcStrLen)
1115 : {
1116 0 : nOffset = 0;
1117 0 : nSize = 0;
1118 : }
1119 14 : else if (nOffset + nSize > nSrcStrLen)
1120 2 : nSize = nSrcStrLen - nOffset;
1121 :
1122 28 : CPLString osResult = pszSrcStr + nOffset;
1123 14 : if (static_cast<int>(osResult.size()) > nSize)
1124 0 : osResult.resize(nSize);
1125 :
1126 14 : poRet->string_value = CPLStrdup(osResult);
1127 14 : poRet->is_null = sub_node_values[0]->is_null;
1128 14 : break;
1129 : }
1130 :
1131 21 : case SWQ_HSTORE_GET_VALUE:
1132 : {
1133 21 : if (!sub_node_values[1]->string_value)
1134 : {
1135 0 : poRet->int_value = false;
1136 : }
1137 : else
1138 : {
1139 21 : const char *pszHStore = sub_node_values[0]->string_value;
1140 21 : const char *pszSearchedKey =
1141 21 : sub_node_values[1]->string_value;
1142 21 : char *pszRet = OGRHStoreGetValue(pszHStore, pszSearchedKey);
1143 21 : poRet->string_value = pszRet ? pszRet : CPLStrdup("");
1144 21 : poRet->is_null = (pszRet == nullptr);
1145 : }
1146 21 : break;
1147 : }
1148 :
1149 0 : default:
1150 0 : CPLAssert(false);
1151 : delete poRet;
1152 : poRet = nullptr;
1153 : break;
1154 : }
1155 : }
1156 :
1157 67111 : return poRet;
1158 : }
1159 :
1160 : /************************************************************************/
1161 : /* SWQAutoPromoteIntegerToInteger64OrFloat() */
1162 : /************************************************************************/
1163 :
1164 10129 : static void SWQAutoPromoteIntegerToInteger64OrFloat(swq_expr_node *poNode)
1165 :
1166 : {
1167 10129 : if (poNode->nSubExprCount < 2)
1168 0 : return;
1169 :
1170 10129 : swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
1171 :
1172 : // We allow mixes of integer, integer64 and float, and string and dates.
1173 : // When encountered, we promote integers/integer64 to floats,
1174 : // integer to integer64 and strings to dates. We do that now.
1175 20345 : for (int i = 1; i < poNode->nSubExprCount; i++)
1176 : {
1177 10216 : swq_expr_node *poSubNode = poNode->papoSubExpr[i];
1178 10216 : if (SWQ_IS_INTEGER(eArgType) && poSubNode->field_type == SWQ_FLOAT)
1179 62 : eArgType = SWQ_FLOAT;
1180 10154 : else if (eArgType == SWQ_INTEGER &&
1181 7668 : poSubNode->field_type == SWQ_INTEGER64)
1182 21 : eArgType = SWQ_INTEGER64;
1183 : }
1184 :
1185 30474 : for (int i = 0; i < poNode->nSubExprCount; i++)
1186 : {
1187 20345 : swq_expr_node *poSubNode = poNode->papoSubExpr[i];
1188 :
1189 20345 : if (eArgType == SWQ_FLOAT && SWQ_IS_INTEGER(poSubNode->field_type))
1190 : {
1191 229 : if (poSubNode->eNodeType == SNT_CONSTANT)
1192 : {
1193 203 : poSubNode->float_value =
1194 203 : static_cast<double>(poSubNode->int_value);
1195 203 : poSubNode->field_type = SWQ_FLOAT;
1196 : }
1197 : }
1198 20116 : else if (eArgType == SWQ_INTEGER64 &&
1199 1263 : poSubNode->field_type == SWQ_INTEGER)
1200 : {
1201 610 : if (poSubNode->eNodeType == SNT_CONSTANT)
1202 : {
1203 591 : poSubNode->field_type = SWQ_INTEGER64;
1204 : }
1205 : }
1206 : }
1207 : }
1208 :
1209 : /************************************************************************/
1210 : /* SWQAutoPromoteStringToDateTime() */
1211 : /************************************************************************/
1212 :
1213 10026 : static void SWQAutoPromoteStringToDateTime(swq_expr_node *poNode)
1214 :
1215 : {
1216 10026 : if (poNode->nSubExprCount < 2)
1217 0 : return;
1218 :
1219 10026 : swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
1220 :
1221 : // We allow mixes of integer and float, and string and dates.
1222 : // When encountered, we promote integers to floats, and strings to
1223 : // dates. We do that now.
1224 20139 : for (int i = 1; i < poNode->nSubExprCount; i++)
1225 : {
1226 10113 : swq_expr_node *poSubNode = poNode->papoSubExpr[i];
1227 :
1228 10113 : if (eArgType == SWQ_STRING && (poSubNode->field_type == SWQ_DATE ||
1229 1226 : poSubNode->field_type == SWQ_TIME ||
1230 1226 : poSubNode->field_type == SWQ_TIMESTAMP))
1231 1 : eArgType = SWQ_TIMESTAMP;
1232 : }
1233 :
1234 30165 : for (int i = 0; i < poNode->nSubExprCount; i++)
1235 : {
1236 20139 : swq_expr_node *poSubNode = poNode->papoSubExpr[i];
1237 :
1238 20139 : if (eArgType == SWQ_TIMESTAMP && (poSubNode->field_type == SWQ_STRING ||
1239 97 : poSubNode->field_type == SWQ_DATE ||
1240 97 : poSubNode->field_type == SWQ_TIME))
1241 : {
1242 99 : if (poSubNode->eNodeType == SNT_CONSTANT)
1243 : {
1244 99 : poSubNode->field_type = SWQ_TIMESTAMP;
1245 : }
1246 : }
1247 : }
1248 : }
1249 :
1250 : /************************************************************************/
1251 : /* SWQAutoConvertStringToNumeric() */
1252 : /* */
1253 : /* Convert string constants to integer or float constants */
1254 : /* when there is a mix of arguments of type numeric and string */
1255 : /************************************************************************/
1256 :
1257 10026 : static void SWQAutoConvertStringToNumeric(swq_expr_node *poNode)
1258 :
1259 : {
1260 10026 : if (poNode->nSubExprCount < 2)
1261 0 : return;
1262 :
1263 10026 : swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
1264 :
1265 20130 : for (int i = 1; i < poNode->nSubExprCount; i++)
1266 : {
1267 10113 : swq_expr_node *poSubNode = poNode->papoSubExpr[i];
1268 :
1269 : // Identify the mixture of the argument type.
1270 10113 : if ((eArgType == SWQ_STRING && (SWQ_IS_INTEGER(poSubNode->field_type) ||
1271 10110 : poSubNode->field_type == SWQ_FLOAT)) ||
1272 10110 : (SWQ_IS_INTEGER(eArgType) && poSubNode->field_type == SWQ_STRING))
1273 : {
1274 9 : eArgType = SWQ_FLOAT;
1275 9 : break;
1276 : }
1277 : }
1278 :
1279 30165 : for (int i = 0; i < poNode->nSubExprCount; i++)
1280 : {
1281 20139 : swq_expr_node *poSubNode = poNode->papoSubExpr[i];
1282 :
1283 20139 : if (eArgType == SWQ_FLOAT && poSubNode->field_type == SWQ_STRING)
1284 : {
1285 10 : if (poSubNode->eNodeType == SNT_CONSTANT)
1286 : {
1287 : // Apply the string to numeric conversion.
1288 5 : char *endPtr = nullptr;
1289 5 : poSubNode->float_value =
1290 5 : CPLStrtod(poSubNode->string_value, &endPtr);
1291 5 : if (!(endPtr == nullptr || *endPtr == '\0'))
1292 : {
1293 1 : CPLError(CE_Warning, CPLE_NotSupported,
1294 : "Conversion failed when converting the string "
1295 : "value '%s' to data type float.",
1296 : poSubNode->string_value);
1297 1 : continue;
1298 : }
1299 :
1300 : // Should also fill the integer value in this case.
1301 4 : poSubNode->int_value =
1302 4 : static_cast<GIntBig>(poSubNode->float_value);
1303 4 : poSubNode->field_type = SWQ_FLOAT;
1304 : }
1305 : }
1306 : }
1307 : }
1308 :
1309 : /************************************************************************/
1310 : /* SWQCheckSubExprAreNotGeometries() */
1311 : /************************************************************************/
1312 :
1313 14995 : static bool SWQCheckSubExprAreNotGeometries(swq_expr_node *poNode)
1314 : {
1315 44952 : for (int i = 0; i < poNode->nSubExprCount; i++)
1316 : {
1317 29967 : if (poNode->papoSubExpr[i]->field_type == SWQ_GEOMETRY)
1318 : {
1319 10 : CPLError(CE_Failure, CPLE_AppDefined,
1320 : "Cannot use geometry field in this operation.");
1321 10 : return false;
1322 : }
1323 : }
1324 14985 : return true;
1325 : }
1326 :
1327 : /************************************************************************/
1328 : /* SWQGeneralChecker() */
1329 : /* */
1330 : /* Check the general purpose functions have appropriate types, */
1331 : /* and count and indicate the function return type under the */
1332 : /* circumstances. */
1333 : /************************************************************************/
1334 :
1335 15129 : swq_field_type SWQGeneralChecker(swq_expr_node *poNode,
1336 : int bAllowMismatchTypeOnFieldComparison)
1337 :
1338 : {
1339 15129 : swq_field_type eRetType = SWQ_ERROR;
1340 15129 : swq_field_type eArgType = SWQ_OTHER;
1341 : // int nArgCount = -1;
1342 :
1343 15129 : switch (poNode->nOperation)
1344 : {
1345 4758 : case SWQ_AND:
1346 : case SWQ_OR:
1347 : case SWQ_NOT:
1348 4758 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1349 0 : return SWQ_ERROR;
1350 4758 : eRetType = SWQ_BOOLEAN;
1351 4758 : break;
1352 :
1353 10028 : case SWQ_EQ:
1354 : case SWQ_NE:
1355 : case SWQ_GT:
1356 : case SWQ_LT:
1357 : case SWQ_GE:
1358 : case SWQ_LE:
1359 : case SWQ_IN:
1360 : case SWQ_BETWEEN:
1361 10028 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1362 2 : return SWQ_ERROR;
1363 10026 : eRetType = SWQ_BOOLEAN;
1364 10026 : SWQAutoConvertStringToNumeric(poNode);
1365 10026 : SWQAutoPromoteIntegerToInteger64OrFloat(poNode);
1366 10026 : SWQAutoPromoteStringToDateTime(poNode);
1367 10026 : eArgType = poNode->papoSubExpr[0]->field_type;
1368 10026 : break;
1369 :
1370 134 : case SWQ_ISNULL:
1371 134 : eRetType = SWQ_BOOLEAN;
1372 134 : break;
1373 :
1374 64 : case SWQ_LIKE:
1375 : case SWQ_ILIKE:
1376 64 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1377 1 : return SWQ_ERROR;
1378 63 : eRetType = SWQ_BOOLEAN;
1379 63 : eArgType = SWQ_STRING;
1380 63 : break;
1381 :
1382 36 : case SWQ_ADD:
1383 36 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1384 2 : return SWQ_ERROR;
1385 34 : SWQAutoPromoteIntegerToInteger64OrFloat(poNode);
1386 34 : if (poNode->papoSubExpr[0]->field_type == SWQ_STRING)
1387 : {
1388 2 : eRetType = SWQ_STRING;
1389 2 : eArgType = SWQ_STRING;
1390 : }
1391 32 : else if (poNode->papoSubExpr[0]->field_type == SWQ_FLOAT ||
1392 24 : poNode->papoSubExpr[1]->field_type == SWQ_FLOAT)
1393 : {
1394 11 : eRetType = SWQ_FLOAT;
1395 11 : eArgType = SWQ_FLOAT;
1396 : }
1397 21 : else if (poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 ||
1398 16 : poNode->papoSubExpr[1]->field_type == SWQ_INTEGER64)
1399 : {
1400 6 : eRetType = SWQ_INTEGER64;
1401 6 : eArgType = SWQ_INTEGER64;
1402 : }
1403 : else
1404 : {
1405 15 : eRetType = SWQ_INTEGER;
1406 15 : eArgType = SWQ_INTEGER;
1407 : }
1408 34 : break;
1409 :
1410 72 : case SWQ_SUBTRACT:
1411 : case SWQ_MULTIPLY:
1412 : case SWQ_DIVIDE:
1413 : case SWQ_MODULUS:
1414 72 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1415 3 : return SWQ_ERROR;
1416 69 : SWQAutoPromoteIntegerToInteger64OrFloat(poNode);
1417 69 : if (poNode->papoSubExpr[0]->field_type == SWQ_FLOAT ||
1418 45 : poNode->papoSubExpr[1]->field_type == SWQ_FLOAT)
1419 : {
1420 25 : eRetType = SWQ_FLOAT;
1421 25 : eArgType = SWQ_FLOAT;
1422 : }
1423 44 : else if (poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 ||
1424 16 : poNode->papoSubExpr[1]->field_type == SWQ_INTEGER64)
1425 : {
1426 29 : eRetType = SWQ_INTEGER64;
1427 29 : eArgType = SWQ_INTEGER64;
1428 : }
1429 : else
1430 : {
1431 15 : eRetType = SWQ_INTEGER;
1432 15 : eArgType = SWQ_INTEGER;
1433 : }
1434 69 : break;
1435 :
1436 6 : case SWQ_CONCAT:
1437 6 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1438 1 : return SWQ_ERROR;
1439 5 : eRetType = SWQ_STRING;
1440 5 : eArgType = SWQ_STRING;
1441 5 : break;
1442 :
1443 6 : case SWQ_SUBSTR:
1444 6 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1445 1 : return SWQ_ERROR;
1446 5 : eRetType = SWQ_STRING;
1447 5 : if (poNode->nSubExprCount > 3 || poNode->nSubExprCount < 2)
1448 : {
1449 1 : CPLError(CE_Failure, CPLE_AppDefined,
1450 : "Expected 2 or 3 arguments to SUBSTR(), but got %d.",
1451 : poNode->nSubExprCount);
1452 1 : return SWQ_ERROR;
1453 : }
1454 4 : if (poNode->papoSubExpr[0]->field_type != SWQ_STRING ||
1455 3 : poNode->papoSubExpr[1]->field_type != SWQ_INTEGER ||
1456 3 : (poNode->nSubExprCount > 2 &&
1457 2 : poNode->papoSubExpr[2]->field_type != SWQ_INTEGER))
1458 : {
1459 1 : CPLError(
1460 : CE_Failure, CPLE_AppDefined,
1461 : "Wrong argument type for SUBSTR(), "
1462 : "expected SUBSTR(string,int,int) or SUBSTR(string,int).");
1463 1 : return SWQ_ERROR;
1464 : }
1465 3 : break;
1466 :
1467 25 : case SWQ_HSTORE_GET_VALUE:
1468 25 : if (!SWQCheckSubExprAreNotGeometries(poNode))
1469 0 : return SWQ_ERROR;
1470 25 : eRetType = SWQ_STRING;
1471 25 : if (poNode->nSubExprCount != 2)
1472 : {
1473 1 : CPLError(
1474 : CE_Failure, CPLE_AppDefined,
1475 : "Expected 2 arguments to hstore_get_value(), but got %d.",
1476 : poNode->nSubExprCount);
1477 1 : return SWQ_ERROR;
1478 : }
1479 24 : if (poNode->papoSubExpr[0]->field_type != SWQ_STRING ||
1480 23 : poNode->papoSubExpr[1]->field_type != SWQ_STRING)
1481 : {
1482 1 : CPLError(CE_Failure, CPLE_AppDefined,
1483 : "Wrong argument type for hstore_get_value(), "
1484 : "expected hstore_get_value(string,string).");
1485 1 : return SWQ_ERROR;
1486 : }
1487 23 : break;
1488 :
1489 0 : default:
1490 : {
1491 : const swq_operation *poOp =
1492 0 : swq_op_registrar::GetOperator(poNode->nOperation);
1493 :
1494 0 : CPLError(CE_Failure, CPLE_AppDefined,
1495 : "SWQGeneralChecker() called on unsupported operation %s.",
1496 0 : poOp->pszName);
1497 0 : return SWQ_ERROR;
1498 : }
1499 : }
1500 : /* -------------------------------------------------------------------- */
1501 : /* Check argument types. */
1502 : /* -------------------------------------------------------------------- */
1503 15115 : if (eArgType != SWQ_OTHER)
1504 : {
1505 10180 : if (SWQ_IS_INTEGER(eArgType) || eArgType == SWQ_BOOLEAN)
1506 8314 : eArgType = SWQ_FLOAT;
1507 :
1508 30619 : for (int i = 0; i < poNode->nSubExprCount; i++)
1509 : {
1510 20449 : swq_field_type eThisArgType = poNode->papoSubExpr[i]->field_type;
1511 20449 : if (SWQ_IS_INTEGER(eThisArgType) || eThisArgType == SWQ_BOOLEAN)
1512 16674 : eThisArgType = SWQ_FLOAT;
1513 :
1514 20449 : if (eArgType != eThisArgType)
1515 : {
1516 : // Convenience for join. We allow comparing numeric columns
1517 : // and string columns, by casting string columns to numeric.
1518 10 : if (bAllowMismatchTypeOnFieldComparison &&
1519 3 : poNode->nSubExprCount == 2 &&
1520 3 : poNode->nOperation == SWQ_EQ &&
1521 3 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
1522 3 : poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN &&
1523 2 : eArgType == SWQ_FLOAT && eThisArgType == SWQ_STRING)
1524 : {
1525 2 : swq_expr_node *poNewNode = new swq_expr_node(SWQ_CAST);
1526 2 : poNewNode->PushSubExpression(poNode->papoSubExpr[i]);
1527 2 : poNewNode->PushSubExpression(new swq_expr_node("FLOAT"));
1528 2 : SWQCastChecker(poNewNode, FALSE);
1529 2 : poNode->papoSubExpr[i] = poNewNode;
1530 2 : break;
1531 : }
1532 8 : if (bAllowMismatchTypeOnFieldComparison &&
1533 1 : poNode->nSubExprCount == 2 &&
1534 1 : poNode->nOperation == SWQ_EQ &&
1535 1 : poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
1536 1 : poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN &&
1537 1 : eThisArgType == SWQ_FLOAT && eArgType == SWQ_STRING)
1538 : {
1539 1 : swq_expr_node *poNewNode = new swq_expr_node(SWQ_CAST);
1540 1 : poNewNode->PushSubExpression(poNode->papoSubExpr[0]);
1541 1 : poNewNode->PushSubExpression(new swq_expr_node("FLOAT"));
1542 1 : SWQCastChecker(poNewNode, FALSE);
1543 1 : poNode->papoSubExpr[0] = poNewNode;
1544 1 : break;
1545 : }
1546 :
1547 : const swq_operation *poOp =
1548 7 : swq_op_registrar::GetOperator(poNode->nOperation);
1549 :
1550 7 : CPLError(CE_Failure, CPLE_AppDefined,
1551 : "Type mismatch or improper type of arguments "
1552 : "to %s operator.",
1553 7 : poOp->pszName);
1554 7 : return SWQ_ERROR;
1555 : }
1556 : }
1557 : }
1558 :
1559 : /* -------------------------------------------------------------------- */
1560 : /* Validate the arg count if requested. */
1561 : /* -------------------------------------------------------------------- */
1562 : #if 0
1563 : // nArgCount was always -1, so this block was never executed.
1564 : if( nArgCount != -1
1565 : && nArgCount != poNode->nSubExprCount )
1566 : {
1567 : const swq_operation *poOp =
1568 : swq_op_registrar::GetOperator(poNode->nOperation);
1569 :
1570 : CPLError( CE_Failure, CPLE_AppDefined,
1571 : "Expected %d arguments to %s, but got %d arguments.",
1572 : nArgCount,
1573 : poOp->pszName,
1574 : poNode->nSubExprCount );
1575 : return SWQ_ERROR;
1576 : }
1577 : #endif
1578 :
1579 15108 : return eRetType;
1580 : }
1581 :
1582 : /************************************************************************/
1583 : /* SWQCastEvaluator() */
1584 : /************************************************************************/
1585 :
1586 234 : swq_expr_node *SWQCastEvaluator(swq_expr_node *node,
1587 : swq_expr_node **sub_node_values,
1588 : const swq_evaluation_context &)
1589 :
1590 : {
1591 234 : swq_expr_node *poRetNode = nullptr;
1592 234 : swq_expr_node *poSrcNode = sub_node_values[0];
1593 :
1594 234 : switch (node->field_type)
1595 : {
1596 22 : case SWQ_INTEGER:
1597 : {
1598 22 : poRetNode = new swq_expr_node(0);
1599 22 : poRetNode->is_null = poSrcNode->is_null;
1600 :
1601 22 : switch (poSrcNode->field_type)
1602 : {
1603 6 : case SWQ_INTEGER:
1604 : case SWQ_BOOLEAN:
1605 6 : poRetNode->int_value = poSrcNode->int_value;
1606 6 : break;
1607 :
1608 0 : case SWQ_INTEGER64:
1609 : // TODO: Warn in case of overflow?
1610 0 : poRetNode->int_value =
1611 0 : static_cast<int>(poSrcNode->int_value);
1612 0 : break;
1613 :
1614 1 : case SWQ_FLOAT:
1615 : // TODO: Warn in case of overflow?
1616 1 : poRetNode->int_value =
1617 1 : static_cast<int>(poSrcNode->float_value);
1618 1 : break;
1619 :
1620 15 : default:
1621 15 : poRetNode->int_value = atoi(poSrcNode->string_value);
1622 15 : break;
1623 : }
1624 : }
1625 22 : break;
1626 :
1627 4 : case SWQ_INTEGER64:
1628 : {
1629 4 : poRetNode = new swq_expr_node(0);
1630 4 : poRetNode->is_null = poSrcNode->is_null;
1631 4 : poRetNode->field_type = SWQ_INTEGER64;
1632 :
1633 4 : switch (poSrcNode->field_type)
1634 : {
1635 4 : case SWQ_INTEGER:
1636 : case SWQ_INTEGER64:
1637 : case SWQ_BOOLEAN:
1638 4 : poRetNode->int_value = poSrcNode->int_value;
1639 4 : break;
1640 :
1641 0 : case SWQ_FLOAT:
1642 0 : poRetNode->int_value =
1643 0 : static_cast<GIntBig>(poSrcNode->float_value);
1644 0 : break;
1645 :
1646 0 : default:
1647 0 : poRetNode->int_value =
1648 0 : CPLAtoGIntBig(poSrcNode->string_value);
1649 0 : break;
1650 : }
1651 : }
1652 4 : break;
1653 :
1654 176 : case SWQ_FLOAT:
1655 : {
1656 176 : poRetNode = new swq_expr_node(0.0);
1657 176 : poRetNode->is_null = poSrcNode->is_null;
1658 :
1659 176 : switch (poSrcNode->field_type)
1660 : {
1661 3 : case SWQ_INTEGER:
1662 : case SWQ_INTEGER64:
1663 : case SWQ_BOOLEAN:
1664 3 : poRetNode->float_value =
1665 3 : static_cast<double>(poSrcNode->int_value);
1666 3 : break;
1667 :
1668 0 : case SWQ_FLOAT:
1669 0 : poRetNode->float_value = poSrcNode->float_value;
1670 0 : break;
1671 :
1672 173 : default:
1673 173 : poRetNode->float_value = CPLAtof(poSrcNode->string_value);
1674 173 : break;
1675 : }
1676 : }
1677 176 : break;
1678 :
1679 15 : case SWQ_GEOMETRY:
1680 : {
1681 15 : poRetNode = new swq_expr_node(static_cast<OGRGeometry *>(nullptr));
1682 15 : if (!poSrcNode->is_null)
1683 : {
1684 13 : switch (poSrcNode->field_type)
1685 : {
1686 6 : case SWQ_GEOMETRY:
1687 : {
1688 6 : poRetNode->geometry_value =
1689 6 : poSrcNode->geometry_value->clone();
1690 6 : poRetNode->is_null = FALSE;
1691 6 : break;
1692 : }
1693 :
1694 7 : case SWQ_STRING:
1695 : {
1696 7 : OGRGeometryFactory::createFromWkt(
1697 7 : poSrcNode->string_value, nullptr,
1698 : &(poRetNode->geometry_value));
1699 7 : if (poRetNode->geometry_value != nullptr)
1700 7 : poRetNode->is_null = FALSE;
1701 7 : break;
1702 : }
1703 :
1704 0 : default:
1705 0 : break;
1706 : }
1707 : }
1708 15 : break;
1709 : }
1710 :
1711 : // Everything else is a string.
1712 17 : default:
1713 : {
1714 17 : CPLString osRet;
1715 :
1716 17 : switch (poSrcNode->field_type)
1717 : {
1718 6 : case SWQ_INTEGER:
1719 : case SWQ_BOOLEAN:
1720 : case SWQ_INTEGER64:
1721 6 : osRet.Printf(CPL_FRMT_GIB, poSrcNode->int_value);
1722 6 : break;
1723 :
1724 0 : case SWQ_FLOAT:
1725 0 : osRet.Printf("%.15g", poSrcNode->float_value);
1726 0 : break;
1727 :
1728 3 : case SWQ_GEOMETRY:
1729 : {
1730 3 : if (poSrcNode->geometry_value != nullptr)
1731 : {
1732 2 : char *pszWKT = nullptr;
1733 2 : poSrcNode->geometry_value->exportToWkt(&pszWKT);
1734 2 : osRet = pszWKT;
1735 2 : CPLFree(pszWKT);
1736 : }
1737 : else
1738 1 : osRet = "";
1739 3 : break;
1740 : }
1741 :
1742 8 : default:
1743 8 : osRet = poSrcNode->string_value;
1744 8 : break;
1745 : }
1746 :
1747 17 : if (node->nSubExprCount > 2)
1748 : {
1749 11 : int nWidth = static_cast<int>(sub_node_values[2]->int_value);
1750 11 : if (nWidth > 0 && static_cast<int>(osRet.size()) > nWidth)
1751 0 : osRet.resize(nWidth);
1752 : }
1753 :
1754 17 : poRetNode = new swq_expr_node(osRet.c_str());
1755 17 : poRetNode->is_null = poSrcNode->is_null;
1756 : }
1757 : }
1758 :
1759 234 : return poRetNode;
1760 : }
1761 :
1762 : /************************************************************************/
1763 : /* SWQCastChecker() */
1764 : /************************************************************************/
1765 :
1766 87 : swq_field_type SWQCastChecker(swq_expr_node *poNode,
1767 : int /* bAllowMismatchTypeOnFieldComparison */)
1768 :
1769 : {
1770 87 : swq_field_type eType = SWQ_ERROR;
1771 87 : const char *pszTypeName = poNode->papoSubExpr[1]->string_value;
1772 :
1773 87 : if (poNode->papoSubExpr[0]->field_type == SWQ_GEOMETRY &&
1774 13 : !(EQUAL(pszTypeName, "character") || EQUAL(pszTypeName, "geometry")))
1775 : {
1776 1 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot cast geometry to %s",
1777 : pszTypeName);
1778 : }
1779 86 : else if (EQUAL(pszTypeName, "boolean"))
1780 : {
1781 1 : eType = SWQ_BOOLEAN;
1782 : }
1783 85 : else if (EQUAL(pszTypeName, "character"))
1784 : {
1785 8 : eType = SWQ_STRING;
1786 : }
1787 77 : else if (EQUAL(pszTypeName, "integer"))
1788 : {
1789 12 : eType = SWQ_INTEGER;
1790 : }
1791 65 : else if (EQUAL(pszTypeName, "bigint"))
1792 : {
1793 : // Handle CAST(fid AS bigint) by changing the field_type of fid to
1794 : // Integer64. A bit of a hack.
1795 5 : if (poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
1796 3 : poNode->papoSubExpr[0]->field_type == SWQ_INTEGER &&
1797 1 : strcmp(poNode->papoSubExpr[0]->string_value, "fid") == 0)
1798 : {
1799 1 : poNode->papoSubExpr[0]->field_type = SWQ_INTEGER64;
1800 : }
1801 5 : eType = SWQ_INTEGER64;
1802 : }
1803 60 : else if (EQUAL(pszTypeName, "smallint"))
1804 : {
1805 1 : eType = SWQ_INTEGER;
1806 : }
1807 59 : else if (EQUAL(pszTypeName, "float"))
1808 : {
1809 37 : eType = SWQ_FLOAT;
1810 : }
1811 22 : else if (EQUAL(pszTypeName, "numeric"))
1812 : {
1813 2 : eType = SWQ_FLOAT;
1814 : }
1815 20 : else if (EQUAL(pszTypeName, "timestamp"))
1816 : {
1817 0 : eType = SWQ_TIMESTAMP;
1818 : }
1819 20 : else if (EQUAL(pszTypeName, "date"))
1820 : {
1821 0 : eType = SWQ_DATE;
1822 : }
1823 20 : else if (EQUAL(pszTypeName, "time"))
1824 : {
1825 0 : eType = SWQ_TIME;
1826 : }
1827 20 : else if (EQUAL(pszTypeName, "geometry"))
1828 : {
1829 20 : if (!(poNode->papoSubExpr[0]->field_type == SWQ_GEOMETRY ||
1830 11 : poNode->papoSubExpr[0]->field_type == SWQ_STRING))
1831 : {
1832 1 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot cast %s to geometry",
1833 1 : SWQFieldTypeToString(poNode->papoSubExpr[0]->field_type));
1834 : }
1835 : else
1836 19 : eType = SWQ_GEOMETRY;
1837 : }
1838 : else
1839 : {
1840 0 : CPLError(CE_Failure, CPLE_AppDefined,
1841 : "Unrecognized typename %s in CAST operator.", pszTypeName);
1842 : }
1843 :
1844 87 : poNode->field_type = eType;
1845 :
1846 87 : return eType;
1847 : }
|