LCOV - code coverage report
Current view: top level - ogr - swq_expr_node.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 486 543 89.5 %
Date: 2025-03-28 11:40:40 Functions: 29 31 93.5 %

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

Generated by: LCOV version 1.14