LCOV - code coverage report
Current view: top level - ogr - swq_expr_node.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 426 485 87.8 %
Date: 2024-05-03 15:49:35 Functions: 25 27 92.6 %

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

Generated by: LCOV version 1.14