LCOV - code coverage report
Current view: top level - ogr - swq_expr_node.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 432 491 88.0 %
Date: 2025-01-18 12:42:00 Functions: 26 28 92.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Component: OGR SQL Engine
       4             :  * Purpose: Implementation of the swq_expr_node class used to represent a
       5             :  *          node in an SQL expression.
       6             :  * Author: Frank Warmerdam <warmerdam@pobox.com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #ifndef DOXYGEN_SKIP
      16             : 
      17             : #include "cpl_port.h"
      18             : #include "ogr_swq.h"
      19             : 
      20             : #include <algorithm>
      21             : #include <cctype>
      22             : #include <cinttypes>
      23             : #include <cstdio>
      24             : #include <cstring>
      25             : #include <string>
      26             : #include <vector>
      27             : 
      28             : #include "cpl_conv.h"
      29             : #include "cpl_error.h"
      30             : #include "cpl_multiproc.h"
      31             : #include "cpl_string.h"
      32             : #include "ogr_geometry.h"
      33             : 
      34             : /************************************************************************/
      35             : /*                           swq_expr_node()                            */
      36             : /************************************************************************/
      37             : 
      38             : swq_expr_node::swq_expr_node() = default;
      39             : 
      40             : /************************************************************************/
      41             : /*                          swq_expr_node(int)                          */
      42             : /************************************************************************/
      43             : 
      44      111765 : swq_expr_node::swq_expr_node(int nValueIn) : int_value(nValueIn)
      45             : {
      46      111765 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                        swq_expr_node(GIntBig)                        */
      50             : /************************************************************************/
      51             : 
      52        4910 : swq_expr_node::swq_expr_node(GIntBig nValueIn)
      53        4910 :     : field_type(SWQ_INTEGER64), int_value(nValueIn)
      54             : {
      55        4910 : }
      56             : 
      57             : /************************************************************************/
      58             : /*                        swq_expr_node(double)                         */
      59             : /************************************************************************/
      60             : 
      61        6687 : swq_expr_node::swq_expr_node(double dfValueIn)
      62        6687 :     : field_type(SWQ_FLOAT), float_value(dfValueIn)
      63             : {
      64        6687 : }
      65             : 
      66             : /************************************************************************/
      67             : /*                        swq_expr_node(const char*)                    */
      68             : /************************************************************************/
      69             : 
      70       29923 : swq_expr_node::swq_expr_node(const char *pszValueIn)
      71       29923 :     : field_type(SWQ_STRING), is_null(pszValueIn == nullptr),
      72       29923 :       string_value(CPLStrdup(pszValueIn ? pszValueIn : ""))
      73             : {
      74       29923 : }
      75             : 
      76             : /************************************************************************/
      77             : /*                      swq_expr_node(OGRGeometry *)                    */
      78             : /************************************************************************/
      79             : 
      80          35 : swq_expr_node::swq_expr_node(OGRGeometry *poGeomIn)
      81          35 :     : field_type(SWQ_GEOMETRY), is_null(poGeomIn == nullptr),
      82          35 :       geometry_value(poGeomIn ? poGeomIn->clone() : nullptr)
      83             : {
      84          35 : }
      85             : 
      86             : /************************************************************************/
      87             : /*                        swq_expr_node(swq_op)                         */
      88             : /************************************************************************/
      89             : 
      90       21493 : swq_expr_node::swq_expr_node(swq_op eOp)
      91       21493 :     : eNodeType(SNT_OPERATION), nOperation(eOp)
      92             : {
      93       21493 : }
      94             : 
      95             : /************************************************************************/
      96             : /*                           ~swq_expr_node()                           */
      97             : /************************************************************************/
      98             : 
      99      357802 : swq_expr_node::~swq_expr_node()
     100             : 
     101             : {
     102      178901 :     reset();
     103      178901 : }
     104             : 
     105             : /************************************************************************/
     106             : /*                              reset()                                 */
     107             : /************************************************************************/
     108             : 
     109      181569 : void swq_expr_node::reset()
     110             : {
     111      181569 :     CPLFree(table_name);
     112      181569 :     table_name = nullptr;
     113      181569 :     CPLFree(string_value);
     114      181569 :     string_value = nullptr;
     115             : 
     116      214600 :     for (int i = 0; i < nSubExprCount; i++)
     117       33031 :         delete papoSubExpr[i];
     118      181569 :     CPLFree(papoSubExpr);
     119      181569 :     nSubExprCount = 0;
     120      181569 :     papoSubExpr = nullptr;
     121      181569 :     delete geometry_value;
     122      181569 :     geometry_value = nullptr;
     123      181569 : }
     124             : 
     125             : /************************************************************************/
     126             : /*                           operator==()                               */
     127             : /************************************************************************/
     128             : 
     129        1984 : bool swq_expr_node::operator==(const swq_expr_node &other) const
     130             : {
     131        1984 :     if (eNodeType != other.eNodeType || field_type != other.field_type ||
     132        1168 :         nOperation != other.nOperation || field_index != other.field_index ||
     133        1140 :         table_index != other.table_index ||
     134        1128 :         nSubExprCount != other.nSubExprCount || is_null != other.is_null ||
     135        1104 :         int_value != other.int_value || float_value != other.float_value ||
     136        1080 :         bHidden != other.bHidden)
     137             :     {
     138         904 :         return false;
     139             :     }
     140        1168 :     for (int i = 0; i < nSubExprCount; ++i)
     141             :     {
     142          92 :         if (!(*(papoSubExpr[i]) == *(other.papoSubExpr[i])))
     143             :         {
     144           4 :             return false;
     145             :         }
     146             :     }
     147        1076 :     if (table_name && !other.table_name)
     148             :     {
     149           4 :         return false;
     150             :     }
     151        1072 :     if (!table_name && other.table_name)
     152             :     {
     153           4 :         return false;
     154             :     }
     155        1068 :     if (table_name && other.table_name &&
     156          92 :         strcmp(table_name, other.table_name) != 0)
     157             :     {
     158           4 :         return false;
     159             :     }
     160        1064 :     if (string_value && !other.string_value)
     161             :     {
     162           0 :         return false;
     163             :     }
     164        1064 :     if (!string_value && other.string_value)
     165             :     {
     166           0 :         return false;
     167             :     }
     168        1064 :     if (string_value && other.string_value &&
     169         136 :         strcmp(string_value, other.string_value) != 0)
     170             :     {
     171           4 :         return false;
     172             :     }
     173        1060 :     if (geometry_value && !other.geometry_value)
     174             :     {
     175           0 :         return false;
     176             :     }
     177        1060 :     if (!geometry_value && other.geometry_value)
     178             :     {
     179           0 :         return false;
     180             :     }
     181        1152 :     if (geometry_value && other.geometry_value &&
     182          92 :         !geometry_value->Equals(other.geometry_value))
     183             :     {
     184           4 :         return false;
     185             :     }
     186        1056 :     return true;
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*             swq_expr_node(const swq_expr_node& other)                */
     191             : /************************************************************************/
     192             : 
     193        1730 : swq_expr_node::swq_expr_node(const swq_expr_node &other)
     194             : {
     195        1730 :     *this = other;
     196        1730 : }
     197             : 
     198             : /************************************************************************/
     199             : /*                 operator= (const swq_expr_node& other)               */
     200             : /************************************************************************/
     201             : 
     202        2192 : swq_expr_node &swq_expr_node::operator=(const swq_expr_node &other)
     203             : {
     204        2192 :     if (this != &other)
     205             :     {
     206        2192 :         reset();
     207        2192 :         eNodeType = other.eNodeType;
     208        2192 :         field_type = other.field_type;
     209        2192 :         nOperation = other.nOperation;
     210        2192 :         field_index = other.field_index;
     211        2192 :         table_index = other.table_index;
     212        2192 :         if (other.table_name)
     213         172 :             table_name = CPLStrdup(other.table_name);
     214        2401 :         for (int i = 0; i < other.nSubExprCount; ++i)
     215         209 :             PushSubExpression(new swq_expr_node(*(other.papoSubExpr[i])));
     216        2192 :         is_null = other.is_null;
     217        2192 :         int_value = other.int_value;
     218        2192 :         float_value = other.float_value;
     219        2192 :         if (other.geometry_value)
     220         174 :             geometry_value = other.geometry_value->clone();
     221        2192 :         if (other.string_value)
     222         326 :             string_value = CPLStrdup(other.string_value);
     223        2192 :         bHidden = other.bHidden;
     224             :     }
     225        2192 :     return *this;
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*             swq_expr_node(swq_expr_node&& other)                     */
     230             : /************************************************************************/
     231             : 
     232           0 : swq_expr_node::swq_expr_node(swq_expr_node &&other)
     233             : {
     234           0 :     *this = std::move(other);
     235           0 : }
     236             : 
     237             : /************************************************************************/
     238             : /*                 operator= (swq_expr_node&& other)                    */
     239             : /************************************************************************/
     240             : 
     241         476 : swq_expr_node &swq_expr_node::operator=(swq_expr_node &&other)
     242             : {
     243         476 :     if (this != &other)
     244             :     {
     245         476 :         reset();
     246         476 :         eNodeType = other.eNodeType;
     247         476 :         field_type = other.field_type;
     248         476 :         nOperation = other.nOperation;
     249         476 :         field_index = other.field_index;
     250         476 :         table_index = other.table_index;
     251         476 :         std::swap(table_name, other.table_name);
     252         476 :         std::swap(nSubExprCount, other.nSubExprCount);
     253         476 :         std::swap(papoSubExpr, other.papoSubExpr);
     254         476 :         is_null = other.is_null;
     255         476 :         int_value = other.int_value;
     256         476 :         float_value = other.float_value;
     257         476 :         std::swap(geometry_value, other.geometry_value);
     258         476 :         std::swap(string_value, other.string_value);
     259         476 :         bHidden = other.bHidden;
     260             :     }
     261         476 :     return *this;
     262             : }
     263             : 
     264             : /************************************************************************/
     265             : /*                          MarkAsTimestamp()                           */
     266             : /************************************************************************/
     267             : 
     268         312 : void swq_expr_node::MarkAsTimestamp()
     269             : 
     270             : {
     271         312 :     CPLAssert(eNodeType == SNT_CONSTANT);
     272         312 :     CPLAssert(field_type == SWQ_STRING);
     273         312 :     field_type = SWQ_TIMESTAMP;
     274         312 : }
     275             : 
     276             : /************************************************************************/
     277             : /*                         PushSubExpression()                          */
     278             : /************************************************************************/
     279             : 
     280       38284 : void swq_expr_node::PushSubExpression(swq_expr_node *child)
     281             : 
     282             : {
     283       38284 :     nSubExprCount++;
     284       38284 :     papoSubExpr = static_cast<swq_expr_node **>(
     285       38284 :         CPLRealloc(papoSubExpr, sizeof(void *) * nSubExprCount));
     286             : 
     287       38284 :     papoSubExpr[nSubExprCount - 1] = child;
     288       38284 : }
     289             : 
     290             : /************************************************************************/
     291             : /*                       ReverseSubExpressions()                        */
     292             : /************************************************************************/
     293             : 
     294         583 : void swq_expr_node::ReverseSubExpressions()
     295             : 
     296             : {
     297         995 :     for (int i = 0; i < nSubExprCount / 2; i++)
     298             :     {
     299         412 :         std::swap(papoSubExpr[i], papoSubExpr[nSubExprCount - i - 1]);
     300             :     }
     301         583 : }
     302             : 
     303             : /************************************************************************/
     304             : /*                               Check()                                */
     305             : /*                                                                      */
     306             : /*      Check argument types, etc.                                      */
     307             : /************************************************************************/
     308             : 
     309       38793 : swq_field_type swq_expr_node::Check(
     310             :     swq_field_list *poFieldList, int bAllowFieldsInSecondaryTables,
     311             :     int bAllowMismatchTypeOnFieldComparison,
     312             :     swq_custom_func_registrar *poCustomFuncRegistrar, int nDepth)
     313             : 
     314             : {
     315       38793 :     if (nDepth == 32)
     316             :     {
     317           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     318             :                  "Too many recursion levels in expression");
     319           0 :         return SWQ_ERROR;
     320             :     }
     321             : 
     322             :     /* -------------------------------------------------------------------- */
     323             :     /*      Otherwise we take constants literally.                          */
     324             :     /* -------------------------------------------------------------------- */
     325       38793 :     if (eNodeType == SNT_CONSTANT)
     326       14041 :         return field_type;
     327             : 
     328             :     /* -------------------------------------------------------------------- */
     329             :     /*      If this is intended to be a field definition, but has not       */
     330             :     /*      yet been looked up, we do so now.                               */
     331             :     /* -------------------------------------------------------------------- */
     332       24752 :     if (eNodeType == SNT_COLUMN && field_index == -1)
     333             :     {
     334        8448 :         field_index = swq_identify_field(table_name, string_value, poFieldList,
     335             :                                          &field_type, &table_index);
     336             : 
     337        8448 :         if (field_index < 0)
     338             :         {
     339           4 :             if (table_name)
     340           3 :                 CPLError(CE_Failure, CPLE_AppDefined,
     341             :                          R"("%s"."%s" not recognised as an available field.)",
     342             :                          table_name, string_value);
     343             :             else
     344           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     345             :                          "\"%s\" not recognised as an available field.",
     346             :                          string_value);
     347             : 
     348           4 :             return SWQ_ERROR;
     349             :         }
     350             : 
     351        8444 :         if (!bAllowFieldsInSecondaryTables && table_index != 0)
     352             :         {
     353           1 :             CPLError(
     354             :                 CE_Failure, CPLE_AppDefined,
     355             :                 "Cannot use field '%s' of a secondary table in this context",
     356             :                 string_value);
     357           1 :             return SWQ_ERROR;
     358             :         }
     359             :     }
     360             : 
     361       24747 :     if (eNodeType == SNT_COLUMN)
     362        8443 :         return field_type;
     363             : 
     364             :     /* -------------------------------------------------------------------- */
     365             :     /*      We are dealing with an operation - fetch the definition.        */
     366             :     /* -------------------------------------------------------------------- */
     367             :     const swq_operation *poOp =
     368         112 :         (nOperation == SWQ_CUSTOM_FUNC && poCustomFuncRegistrar != nullptr)
     369       16416 :             ? poCustomFuncRegistrar->GetOperator(string_value)
     370       16192 :             : swq_op_registrar::GetOperator(nOperation);
     371             : 
     372       16304 :     if (poOp == nullptr)
     373             :     {
     374           0 :         if (nOperation == SWQ_CUSTOM_FUNC)
     375           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     376             :                      "Check(): Unable to find definition for operator %s.",
     377             :                      string_value);
     378             :         else
     379           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     380             :                      "Check(): Unable to find definition for operator %d.",
     381           0 :                      nOperation);
     382           0 :         return SWQ_ERROR;
     383             :     }
     384             : 
     385             :     /* -------------------------------------------------------------------- */
     386             :     /*      Check subexpressions first.                                     */
     387             :     /* -------------------------------------------------------------------- */
     388       48604 :     for (int i = 0; i < nSubExprCount; i++)
     389             :     {
     390       32322 :         if (papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables,
     391             :                                   bAllowMismatchTypeOnFieldComparison,
     392             :                                   poCustomFuncRegistrar,
     393       32322 :                                   nDepth + 1) == SWQ_ERROR)
     394          22 :             return SWQ_ERROR;
     395             :     }
     396             : 
     397             :     /* -------------------------------------------------------------------- */
     398             :     /*      Check this node.                                                */
     399             :     /* -------------------------------------------------------------------- */
     400       16282 :     field_type = poOp->pfnChecker(this, bAllowMismatchTypeOnFieldComparison);
     401             : 
     402       16282 :     return field_type;
     403             : }
     404             : 
     405             : /************************************************************************/
     406             : /*                                Dump()                                */
     407             : /************************************************************************/
     408             : 
     409           0 : void swq_expr_node::Dump(FILE *fp, int depth)
     410             : 
     411             : {
     412           0 :     char spaces[60] = {};
     413             : 
     414             :     {
     415           0 :         int i = 0;  // Used after for.
     416           0 :         for (; i < depth * 2 && i < static_cast<int>(sizeof(spaces)) - 1; i++)
     417           0 :             spaces[i] = ' ';
     418           0 :         spaces[i] = '\0';
     419             :     }
     420             : 
     421           0 :     if (eNodeType == SNT_COLUMN)
     422             :     {
     423           0 :         fprintf(fp, "%s  Field %d\n", spaces, field_index);
     424           0 :         return;
     425             :     }
     426             : 
     427           0 :     if (eNodeType == SNT_CONSTANT)
     428             :     {
     429           0 :         if (field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
     430           0 :             field_type == SWQ_BOOLEAN)
     431           0 :             fprintf(fp, "%s  %" PRId64 "\n", spaces, int_value);
     432           0 :         else if (field_type == SWQ_FLOAT)
     433           0 :             fprintf(fp, "%s  %.15g\n", spaces, float_value);
     434           0 :         else if (field_type == SWQ_GEOMETRY)
     435             :         {
     436           0 :             if (geometry_value == nullptr)
     437           0 :                 fprintf(fp, "%s  (null)\n", spaces);
     438             :             else
     439             :             {
     440           0 :                 char *pszWKT = nullptr;
     441           0 :                 geometry_value->exportToWkt(&pszWKT);
     442           0 :                 fprintf(fp, "%s  %s\n", spaces, pszWKT);
     443           0 :                 CPLFree(pszWKT);
     444             :             }
     445             :         }
     446             :         else
     447           0 :             fprintf(fp, "%s  %s\n", spaces, string_value);
     448           0 :         return;
     449             :     }
     450             : 
     451           0 :     CPLAssert(eNodeType == SNT_OPERATION);
     452             : 
     453           0 :     const swq_operation *op_def = swq_op_registrar::GetOperator(nOperation);
     454           0 :     if (op_def)
     455           0 :         fprintf(fp, "%s%s\n", spaces, op_def->pszName);
     456             :     else
     457           0 :         fprintf(fp, "%s%s\n", spaces, string_value);
     458             : 
     459           0 :     for (int i = 0; i < nSubExprCount; i++)
     460           0 :         papoSubExpr[i]->Dump(fp, depth + 1);
     461             : }
     462             : 
     463             : /************************************************************************/
     464             : /*                       QuoteIfNecessary()                             */
     465             : /*                                                                      */
     466             : /*      Add quoting if necessary to unparse a string.                   */
     467             : /************************************************************************/
     468             : 
     469         414 : CPLString swq_expr_node::QuoteIfNecessary(const CPLString &osExpr, char chQuote)
     470             : 
     471             : {
     472         414 :     if (osExpr[0] == '_')
     473           0 :         return Quote(osExpr, chQuote);
     474         414 :     if (osExpr == "*")
     475           3 :         return osExpr;
     476             : 
     477        2719 :     for (int i = 0; i < static_cast<int>(osExpr.size()); i++)
     478             :     {
     479        2316 :         char ch = osExpr[i];
     480        2316 :         if ((!(isalnum(static_cast<unsigned char>(ch)) || ch == '_')) ||
     481             :             ch == '.')
     482             :         {
     483           8 :             return Quote(osExpr, chQuote);
     484             :         }
     485             :     }
     486             : 
     487         403 :     if (swq_is_reserved_keyword(osExpr))
     488             :     {
     489           1 :         return Quote(osExpr, chQuote);
     490             :     }
     491             : 
     492         402 :     return osExpr;
     493             : }
     494             : 
     495             : /************************************************************************/
     496             : /*                               Quote()                                */
     497             : /*                                                                      */
     498             : /*      Add quoting necessary to unparse a string.                      */
     499             : /************************************************************************/
     500             : 
     501         122 : CPLString swq_expr_node::Quote(const CPLString &osTarget, char chQuote)
     502             : 
     503             : {
     504         122 :     CPLString osNew;
     505             : 
     506         122 :     osNew += chQuote;
     507             : 
     508        1237 :     for (int i = 0; i < static_cast<int>(osTarget.size()); i++)
     509             :     {
     510        1115 :         if (osTarget[i] == chQuote)
     511             :         {
     512           0 :             osNew += chQuote;
     513           0 :             osNew += chQuote;
     514             :         }
     515             :         else
     516        1115 :             osNew += osTarget[i];
     517             :     }
     518         122 :     osNew += chQuote;
     519             : 
     520         122 :     return osNew;
     521             : }
     522             : 
     523             : /************************************************************************/
     524             : /*                              Unparse()                               */
     525             : /************************************************************************/
     526             : 
     527        3228 : char *swq_expr_node::Unparse(swq_field_list *field_list, char chColumnQuote)
     528             : 
     529             : {
     530        6456 :     CPLString osExpr;
     531             : 
     532             :     /* -------------------------------------------------------------------- */
     533             :     /*      Handle constants.                                               */
     534             :     /* -------------------------------------------------------------------- */
     535        3228 :     if (eNodeType == SNT_CONSTANT)
     536             :     {
     537        1689 :         if (is_null)
     538          37 :             return CPLStrdup("NULL");
     539             : 
     540        1652 :         if (field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
     541         147 :             field_type == SWQ_BOOLEAN)
     542        1505 :             osExpr.Printf("%" PRId64, int_value);
     543         147 :         else if (field_type == SWQ_FLOAT)
     544             :         {
     545          34 :             osExpr.Printf("%.15g", float_value);
     546             :             // Make sure this is interpreted as a floating point value
     547             :             // and not as an integer later.
     548          34 :             if (strchr(osExpr, '.') == nullptr &&
     549          66 :                 strchr(osExpr, 'e') == nullptr &&
     550          32 :                 strchr(osExpr, 'E') == nullptr)
     551          32 :                 osExpr += '.';
     552             :         }
     553             :         else
     554             :         {
     555         113 :             osExpr = Quote(string_value);
     556             :         }
     557             : 
     558        1652 :         return CPLStrdup(osExpr);
     559             :     }
     560             : 
     561             :     /* -------------------------------------------------------------------- */
     562             :     /*      Handle columns.                                                 */
     563             :     /* -------------------------------------------------------------------- */
     564        1539 :     if (eNodeType == SNT_COLUMN)
     565             :     {
     566         386 :         if (field_list == nullptr)
     567             :         {
     568           9 :             if (table_name)
     569             :                 osExpr.Printf(
     570             :                     "%s.%s",
     571           4 :                     QuoteIfNecessary(table_name, chColumnQuote).c_str(),
     572           6 :                     QuoteIfNecessary(string_value, chColumnQuote).c_str());
     573             :             else
     574             :                 osExpr.Printf(
     575             :                     "%s",
     576           7 :                     QuoteIfNecessary(string_value, chColumnQuote).c_str());
     577             :         }
     578         377 :         else if (field_index != -1 && table_index < field_list->table_count &&
     579         377 :                  table_index > 0)
     580             :         {
     581             :             // We deliberately browse through the list starting from the end
     582             :             // This is for the case where the FID column exists both as
     583             :             // FID and then real_fid_name. We want real_fid_name to be used
     584          26 :             for (int i = field_list->count - 1; i >= 0; i--)
     585             :             {
     586          26 :                 if (field_list->table_ids[i] == table_index &&
     587           6 :                     field_list->ids[i] == field_index)
     588             :                 {
     589             :                     osExpr.Printf(
     590             :                         "%s.%s",
     591           8 :                         QuoteIfNecessary(
     592           4 :                             field_list->table_defs[table_index].table_name,
     593             :                             chColumnQuote)
     594             :                             .c_str(),
     595           8 :                         QuoteIfNecessary(field_list->names[i], chColumnQuote)
     596           8 :                             .c_str());
     597           4 :                     break;
     598             :                 }
     599           4 :             }
     600             :         }
     601         373 :         else if (field_index != -1)
     602             :         {
     603             :             // We deliberately browse through the list starting from the end
     604             :             // This is for the case where the FID column exists both as
     605             :             // FID and then real_fid_name. We want real_fid_name to be used
     606        2709 :             for (int i = field_list->count - 1; i >= 0; i--)
     607             :             {
     608        2709 :                 if (field_list->table_ids[i] == table_index &&
     609        2691 :                     field_list->ids[i] == field_index)
     610             :                 {
     611         746 :                     osExpr.Printf("%s", QuoteIfNecessary(field_list->names[i],
     612             :                                                          chColumnQuote)
     613         373 :                                             .c_str());
     614         373 :                     break;
     615             :                 }
     616             :             }
     617             :         }
     618             : 
     619         386 :         if (osExpr.empty())
     620             :         {
     621           0 :             return CPLStrdup(CPLSPrintf("%c%c", chColumnQuote, chColumnQuote));
     622             :         }
     623             : 
     624             :         // The string is just alphanum and not a reserved SQL keyword,
     625             :         // no needs to quote and escape.
     626         386 :         return CPLStrdup(osExpr.c_str());
     627             :     }
     628             : 
     629             :     /* -------------------------------------------------------------------- */
     630             :     /*      Operation - start by unparsing all the subexpressions.          */
     631             :     /* -------------------------------------------------------------------- */
     632        2306 :     std::vector<char *> apszSubExpr;
     633        1153 :     apszSubExpr.reserve(nSubExprCount);
     634        3379 :     for (int i = 0; i < nSubExprCount; i++)
     635        2226 :         apszSubExpr.push_back(
     636        2226 :             papoSubExpr[i]->Unparse(field_list, chColumnQuote));
     637             : 
     638        1153 :     osExpr = UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
     639             : 
     640             :     /* -------------------------------------------------------------------- */
     641             :     /*      cleanup subexpressions.                                         */
     642             :     /* -------------------------------------------------------------------- */
     643        3379 :     for (int i = 0; i < nSubExprCount; i++)
     644        2226 :         CPLFree(apszSubExpr[i]);
     645             : 
     646        1153 :     return CPLStrdup(osExpr.c_str());
     647             : }
     648             : 
     649             : /************************************************************************/
     650             : /*                  UnparseOperationFromUnparsedSubExpr()               */
     651             : /************************************************************************/
     652             : 
     653        1272 : CPLString swq_expr_node::UnparseOperationFromUnparsedSubExpr(char **apszSubExpr)
     654             : {
     655        1272 :     CPLString osExpr;
     656             : 
     657             :     /* -------------------------------------------------------------------- */
     658             :     /*      Put things together in a fashion depending on the operator.     */
     659             :     /* -------------------------------------------------------------------- */
     660        1272 :     const swq_operation *poOp = swq_op_registrar::GetOperator(nOperation);
     661             : 
     662        1272 :     if (poOp == nullptr && nOperation != SWQ_CUSTOM_FUNC)
     663             :     {
     664           0 :         CPLAssert(false);
     665             :         return osExpr;
     666             :     }
     667             : 
     668        7156 :     const auto AddSubExpr = [this, apszSubExpr, &osExpr](int idx)
     669             :     {
     670        2426 :         if (papoSubExpr[idx]->eNodeType == SNT_COLUMN ||
     671        1866 :             papoSubExpr[idx]->eNodeType == SNT_CONSTANT)
     672             :         {
     673        2207 :             osExpr += apszSubExpr[idx];
     674             :         }
     675             :         else
     676             :         {
     677         219 :             osExpr += '(';
     678         219 :             osExpr += apszSubExpr[idx];
     679         219 :             osExpr += ')';
     680             :         }
     681        3698 :     };
     682             : 
     683        1272 :     switch (nOperation)
     684             :     {
     685             :         // Binary infix operators.
     686        1058 :         case SWQ_OR:
     687             :         case SWQ_AND:
     688             :         case SWQ_EQ:
     689             :         case SWQ_NE:
     690             :         case SWQ_GT:
     691             :         case SWQ_LT:
     692             :         case SWQ_GE:
     693             :         case SWQ_LE:
     694             :         case SWQ_LIKE:
     695             :         case SWQ_ILIKE:
     696             :         case SWQ_ADD:
     697             :         case SWQ_SUBTRACT:
     698             :         case SWQ_MULTIPLY:
     699             :         case SWQ_DIVIDE:
     700             :         case SWQ_MODULUS:
     701        1058 :             CPLAssert(nSubExprCount >= 2);
     702        1058 :             AddSubExpr(0);
     703        1058 :             osExpr += " ";
     704        1058 :             osExpr += poOp->pszName;
     705        1058 :             osExpr += " ";
     706        1058 :             AddSubExpr(1);
     707        1058 :             if ((nOperation == SWQ_LIKE || nOperation == SWQ_ILIKE) &&
     708          11 :                 nSubExprCount == 3)
     709             :             {
     710           1 :                 osExpr += " ESCAPE ";
     711           1 :                 AddSubExpr(2);
     712             :             }
     713        1058 :             break;
     714             : 
     715          81 :         case SWQ_NOT:
     716          81 :             CPLAssert(nSubExprCount == 1);
     717          81 :             osExpr = "NOT ";
     718          81 :             AddSubExpr(0);
     719          81 :             break;
     720             : 
     721          36 :         case SWQ_ISNULL:
     722          36 :             CPLAssert(nSubExprCount == 1);
     723          36 :             AddSubExpr(0);
     724          36 :             osExpr += " IS NULL";
     725          36 :             break;
     726             : 
     727          42 :         case SWQ_IN:
     728          42 :             AddSubExpr(0);
     729          42 :             osExpr += " IN(";
     730         112 :             for (int i = 1; i < nSubExprCount; i++)
     731             :             {
     732          70 :                 if (i > 1)
     733          28 :                     osExpr += ",";
     734          70 :                 AddSubExpr(i);
     735             :             }
     736          42 :             osExpr += ")";
     737          42 :             break;
     738             : 
     739           2 :         case SWQ_BETWEEN:
     740           2 :             CPLAssert(nSubExprCount == 3);
     741           2 :             AddSubExpr(0);
     742           2 :             osExpr += ' ';
     743           2 :             osExpr += poOp->pszName;
     744           2 :             osExpr += ' ';
     745           2 :             AddSubExpr(1);
     746           2 :             osExpr += " AND ";
     747           2 :             AddSubExpr(2);
     748           2 :             break;
     749             : 
     750          36 :         case SWQ_CAST:
     751          36 :             osExpr = "CAST(";
     752         112 :             for (int i = 0; i < nSubExprCount; i++)
     753             :             {
     754          76 :                 if (i == 1)
     755          36 :                     osExpr += " AS ";
     756          40 :                 else if (i > 2)
     757           1 :                     osExpr += ", ";
     758             : 
     759          76 :                 const int nLen = static_cast<int>(strlen(apszSubExpr[i]));
     760          76 :                 if ((i == 1 && (apszSubExpr[i][0] == '\'' && nLen > 2 &&
     761          76 :                                 apszSubExpr[i][nLen - 1] == '\'')) ||
     762           3 :                     (i == 2 && EQUAL(apszSubExpr[1], "'GEOMETRY")))
     763             :                 {
     764          38 :                     apszSubExpr[i][nLen - 1] = '\0';
     765          38 :                     osExpr += apszSubExpr[i] + 1;
     766             :                 }
     767             :                 else
     768          38 :                     AddSubExpr(i);
     769             : 
     770          76 :                 if (i == 1 && nSubExprCount > 2)
     771           3 :                     osExpr += "(";
     772          73 :                 else if (i > 1 && i == nSubExprCount - 1)
     773           3 :                     osExpr += ")";
     774             :             }
     775          36 :             osExpr += ")";
     776          36 :             break;
     777             : 
     778          17 :         default:  // function style.
     779          17 :             if (nOperation != SWQ_CUSTOM_FUNC)
     780           1 :                 osExpr.Printf("%s(", poOp->pszName);
     781             :             else
     782          16 :                 osExpr.Printf("%s(", string_value);
     783          53 :             for (int i = 0; i < nSubExprCount; i++)
     784             :             {
     785          36 :                 if (i > 0)
     786          19 :                     osExpr += ",";
     787          36 :                 AddSubExpr(i);
     788             :             }
     789          17 :             osExpr += ")";
     790          17 :             break;
     791             :     }
     792             : 
     793        2544 :     return osExpr;
     794             : }
     795             : 
     796             : /************************************************************************/
     797             : /*                               Clone()                                */
     798             : /************************************************************************/
     799             : 
     800          76 : swq_expr_node *swq_expr_node::Clone()
     801             : {
     802          76 :     return new swq_expr_node(*this);
     803             : }
     804             : 
     805             : /************************************************************************/
     806             : /*                              Evaluate()                              */
     807             : /************************************************************************/
     808             : 
     809       66103 : swq_expr_node *swq_expr_node::Evaluate(swq_field_fetcher pfnFetcher,
     810             :                                        void *pRecord,
     811             :                                        const swq_evaluation_context &sContext)
     812             : 
     813             : {
     814       66103 :     return Evaluate(pfnFetcher, pRecord, sContext, 0);
     815             : }
     816             : 
     817      121889 : swq_expr_node *swq_expr_node::Evaluate(swq_field_fetcher pfnFetcher,
     818             :                                        void *pRecord,
     819             :                                        const swq_evaluation_context &sContext,
     820             :                                        int nRecLevel)
     821             : 
     822             : {
     823      121889 :     swq_expr_node *poRetNode = nullptr;
     824      121889 :     if (nRecLevel == 32)
     825             :     {
     826           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     827             :                  "Too many recursion levels in expression");
     828           0 :         return nullptr;
     829             :     }
     830             : 
     831             :     /* -------------------------------------------------------------------- */
     832             :     /*      Duplicate ourselves if we are already a constant.               */
     833             :     /* -------------------------------------------------------------------- */
     834      121889 :     if (eNodeType == SNT_CONSTANT)
     835             :     {
     836          71 :         return Clone();
     837             :     }
     838             : 
     839             :     /* -------------------------------------------------------------------- */
     840             :     /*      If this is a field value from a record, fetch and return it.    */
     841             :     /* -------------------------------------------------------------------- */
     842      121818 :     if (eNodeType == SNT_COLUMN)
     843             :     {
     844       40618 :         return pfnFetcher(this, pRecord);
     845             :     }
     846             : 
     847             :     /* -------------------------------------------------------------------- */
     848             :     /*      This is an operation, collect the arguments keeping track of    */
     849             :     /*      which we will need to free.                                     */
     850             :     /* -------------------------------------------------------------------- */
     851      162400 :     std::vector<swq_expr_node *> apoValues;
     852       81200 :     std::vector<int> anValueNeedsFree;
     853       81200 :     bool bError = false;
     854       81200 :     apoValues.reserve(nSubExprCount);
     855      242878 :     for (int i = 0; i < nSubExprCount && !bError; i++)
     856             :     {
     857      161678 :         if (papoSubExpr[i]->eNodeType == SNT_CONSTANT)
     858             :         {
     859             :             // avoid duplication.
     860      105892 :             apoValues.push_back(papoSubExpr[i]);
     861      105892 :             anValueNeedsFree.push_back(FALSE);
     862             :         }
     863             :         else
     864             :         {
     865       55786 :             swq_expr_node *poSubExprVal = papoSubExpr[i]->Evaluate(
     866       55786 :                 pfnFetcher, pRecord, sContext, nRecLevel + 1);
     867       55786 :             if (poSubExprVal == nullptr)
     868           0 :                 bError = true;
     869             :             else
     870             :             {
     871       55786 :                 apoValues.push_back(poSubExprVal);
     872       55786 :                 anValueNeedsFree.push_back(TRUE);
     873             :             }
     874             :         }
     875             :     }
     876             : 
     877             :     /* -------------------------------------------------------------------- */
     878             :     /*      Fetch the operator definition and function.                     */
     879             :     /* -------------------------------------------------------------------- */
     880       81200 :     if (!bError)
     881             :     {
     882       81200 :         const swq_operation *poOp = swq_op_registrar::GetOperator(nOperation);
     883       81200 :         if (poOp == nullptr)
     884             :         {
     885           0 :             if (nOperation == SWQ_CUSTOM_FUNC)
     886           0 :                 CPLError(
     887             :                     CE_Failure, CPLE_AppDefined,
     888             :                     "Evaluate(): Unable to find definition for operator %s.",
     889             :                     string_value);
     890             :             else
     891           0 :                 CPLError(
     892             :                     CE_Failure, CPLE_AppDefined,
     893             :                     "Evaluate(): Unable to find definition for operator %d.",
     894           0 :                     nOperation);
     895           0 :             poRetNode = nullptr;
     896             :         }
     897             :         else
     898       81200 :             poRetNode = poOp->pfnEvaluator(this, &(apoValues[0]), sContext);
     899             :     }
     900             : 
     901             :     /* -------------------------------------------------------------------- */
     902             :     /*      Cleanup                                                         */
     903             :     /* -------------------------------------------------------------------- */
     904      242878 :     for (int i = 0; i < static_cast<int>(apoValues.size()); i++)
     905             :     {
     906      161678 :         if (anValueNeedsFree[i])
     907       55786 :             delete apoValues[i];
     908             :     }
     909             : 
     910             :     // cppcheck-suppress returnDanglingLifetime
     911       81200 :     return poRetNode;
     912             : }
     913             : 
     914             : /************************************************************************/
     915             : /*                      ReplaceBetweenByGEAndLERecurse()                */
     916             : /************************************************************************/
     917             : 
     918        6050 : void swq_expr_node::ReplaceBetweenByGEAndLERecurse()
     919             : {
     920        6050 :     if (eNodeType != SNT_OPERATION)
     921        3827 :         return;
     922             : 
     923        2223 :     if (nOperation != SWQ_BETWEEN)
     924             :     {
     925        6538 :         for (int i = 0; i < nSubExprCount; i++)
     926        4318 :             papoSubExpr[i]->ReplaceBetweenByGEAndLERecurse();
     927        2220 :         return;
     928             :     }
     929             : 
     930           3 :     if (nSubExprCount != 3)
     931           0 :         return;
     932             : 
     933           3 :     swq_expr_node *poExpr0 = papoSubExpr[0];
     934           3 :     swq_expr_node *poExpr1 = papoSubExpr[1];
     935           3 :     swq_expr_node *poExpr2 = papoSubExpr[2];
     936             : 
     937           3 :     nSubExprCount = 2;
     938           3 :     nOperation = SWQ_AND;
     939           3 :     papoSubExpr[0] = new swq_expr_node(SWQ_GE);
     940           3 :     papoSubExpr[0]->PushSubExpression(poExpr0);
     941           3 :     papoSubExpr[0]->PushSubExpression(poExpr1);
     942           3 :     papoSubExpr[1] = new swq_expr_node(SWQ_LE);
     943           3 :     papoSubExpr[1]->PushSubExpression(poExpr0->Clone());
     944           3 :     papoSubExpr[1]->PushSubExpression(poExpr2);
     945             : }
     946             : 
     947             : /************************************************************************/
     948             : /*                   PushNotOperationDownToStack()                      */
     949             : /************************************************************************/
     950             : 
     951             : // Do things like:
     952             : // NOT(A AND B) ==> (NOT A) OR (NOT B)
     953             : // NOT(A OR B)  ==> (NOT A) AND (NOT B)
     954             : // NOT(NOT A)   ==> A
     955             : // NOT(A == B)  ==> A <> B
     956             : // NOT(A != B)  ==> A == B
     957             : // NOT(A >= B)  ==> A < B
     958             : // NOT(A >  B)  ==> A <= B
     959             : // NOT(A <= B)  ==> A > B
     960             : // NOT(A <  B)  ==> A >= B
     961         846 : void swq_expr_node::PushNotOperationDownToStack()
     962             : {
     963         846 :     if (eNodeType != SNT_OPERATION)
     964         474 :         return;
     965             : 
     966         372 :     if (nOperation == SWQ_NOT && papoSubExpr[0]->eNodeType == SNT_OPERATION)
     967             :     {
     968          42 :         if (papoSubExpr[0]->nOperation == SWQ_NOT)
     969             :         {
     970           2 :             auto poChild = papoSubExpr[0]->papoSubExpr[0];
     971           2 :             poChild->PushNotOperationDownToStack();
     972           2 :             papoSubExpr[0]->papoSubExpr[0] = nullptr;
     973           2 :             *this = std::move(*poChild);
     974           2 :             delete poChild;
     975           2 :             return;
     976             :         }
     977             : 
     978          40 :         else if (papoSubExpr[0]->nOperation == SWQ_AND)
     979             :         {
     980           3 :             for (int i = 0; i < papoSubExpr[0]->nSubExprCount; i++)
     981             :             {
     982           2 :                 auto notOp = new swq_expr_node(SWQ_NOT);
     983           2 :                 notOp->PushSubExpression(papoSubExpr[0]->papoSubExpr[i]);
     984           2 :                 notOp->PushNotOperationDownToStack();
     985           2 :                 papoSubExpr[0]->papoSubExpr[i] = notOp;
     986             :             }
     987           1 :             papoSubExpr[0]->nOperation = SWQ_OR;
     988           1 :             auto poChild = papoSubExpr[0];
     989           1 :             papoSubExpr[0] = nullptr;
     990           1 :             *this = std::move(*poChild);
     991           1 :             delete poChild;
     992           1 :             return;
     993             :         }
     994             : 
     995          39 :         else if (papoSubExpr[0]->nOperation == SWQ_OR)
     996             :         {
     997           9 :             for (int i = 0; i < papoSubExpr[0]->nSubExprCount; i++)
     998             :             {
     999           6 :                 auto notOp = new swq_expr_node(SWQ_NOT);
    1000           6 :                 notOp->PushSubExpression(papoSubExpr[0]->papoSubExpr[i]);
    1001           6 :                 notOp->PushNotOperationDownToStack();
    1002           6 :                 papoSubExpr[0]->papoSubExpr[i] = notOp;
    1003             :             }
    1004           3 :             papoSubExpr[0]->nOperation = SWQ_AND;
    1005           3 :             auto poChild = papoSubExpr[0];
    1006           3 :             papoSubExpr[0] = nullptr;
    1007           3 :             *this = std::move(*poChild);
    1008           3 :             delete poChild;
    1009           3 :             return;
    1010             :         }
    1011             : 
    1012          36 :         else if (papoSubExpr[0]->nOperation == SWQ_EQ)
    1013             :         {
    1014           3 :             auto poChild = papoSubExpr[0];
    1015           3 :             papoSubExpr[0] = nullptr;
    1016           3 :             poChild->nOperation = SWQ_NE;
    1017           3 :             *this = std::move(*poChild);
    1018           3 :             delete poChild;
    1019           3 :             return;
    1020             :         }
    1021          33 :         else if (papoSubExpr[0]->nOperation == SWQ_NE)
    1022             :         {
    1023           1 :             auto poChild = papoSubExpr[0];
    1024           1 :             papoSubExpr[0] = nullptr;
    1025           1 :             poChild->nOperation = SWQ_EQ;
    1026           1 :             *this = std::move(*poChild);
    1027           1 :             delete poChild;
    1028           1 :             return;
    1029             :         }
    1030          32 :         else if (papoSubExpr[0]->nOperation == SWQ_GT)
    1031             :         {
    1032           1 :             auto poChild = papoSubExpr[0];
    1033           1 :             papoSubExpr[0] = nullptr;
    1034           1 :             poChild->nOperation = SWQ_LE;
    1035           1 :             *this = std::move(*poChild);
    1036           1 :             delete poChild;
    1037           1 :             return;
    1038             :         }
    1039          31 :         else if (papoSubExpr[0]->nOperation == SWQ_GE)
    1040             :         {
    1041           1 :             auto poChild = papoSubExpr[0];
    1042           1 :             papoSubExpr[0] = nullptr;
    1043           1 :             poChild->nOperation = SWQ_LT;
    1044           1 :             *this = std::move(*poChild);
    1045           1 :             delete poChild;
    1046           1 :             return;
    1047             :         }
    1048          30 :         else if (papoSubExpr[0]->nOperation == SWQ_LT)
    1049             :         {
    1050           1 :             auto poChild = papoSubExpr[0];
    1051           1 :             papoSubExpr[0] = nullptr;
    1052           1 :             poChild->nOperation = SWQ_GE;
    1053           1 :             *this = std::move(*poChild);
    1054           1 :             delete poChild;
    1055           1 :             return;
    1056             :         }
    1057          29 :         else if (papoSubExpr[0]->nOperation == SWQ_LE)
    1058             :         {
    1059           1 :             auto poChild = papoSubExpr[0];
    1060           1 :             papoSubExpr[0] = nullptr;
    1061           1 :             poChild->nOperation = SWQ_GT;
    1062           1 :             *this = std::move(*poChild);
    1063           1 :             delete poChild;
    1064           1 :             return;
    1065             :         }
    1066             :     }
    1067             : 
    1068         987 :     for (int i = 0; i < nSubExprCount; i++)
    1069         629 :         papoSubExpr[i]->PushNotOperationDownToStack();
    1070             : }
    1071             : 
    1072             : #endif  // #ifndef DOXYGEN_SKIP

Generated by: LCOV version 1.14