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

Generated by: LCOV version 1.14