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

Generated by: LCOV version 1.14