LCOV - code coverage report
Current view: top level - ogr - swq_op_general.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 843 931 90.5 %
Date: 2024-05-04 12:52:34 Functions: 14 14 100.0 %

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

Generated by: LCOV version 1.14