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

Generated by: LCOV version 1.14