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