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 <cctype>
37 #include <cstdio>
38 #include <cstring>
39 #include <string>
40 #include <vector>
41 
42 #include "cpl_conv.h"
43 #include "cpl_error.h"
44 #include "cpl_multiproc.h"
45 #include "cpl_string.h"
46 #include "ogr_geometry.h"
47 
48 CPL_CVSID("$Id: swq_expr_node.cpp 6659c4d5c910df313ac451cd5ca687862eef040b 2020-10-01 15:37:53 +0200 Even Rouault $")
49 
50 /************************************************************************/
51 /*                           swq_expr_node()                            */
52 /************************************************************************/
53 
54 swq_expr_node::swq_expr_node() = default;
55 
56 /************************************************************************/
57 /*                          swq_expr_node(int)                          */
58 /************************************************************************/
59 
60 swq_expr_node::swq_expr_node( int nValueIn ):
61     int_value(nValueIn)
62 {
63 }
64 
65 /************************************************************************/
66 /*                        swq_expr_node(GIntBig)                        */
67 /************************************************************************/
68 
69 swq_expr_node::swq_expr_node( GIntBig nValueIn ):
70     field_type(SWQ_INTEGER64),
71     int_value(nValueIn)
72 {
73 }
74 
75 /************************************************************************/
76 /*                        swq_expr_node(double)                         */
77 /************************************************************************/
78 
79 swq_expr_node::swq_expr_node( double dfValueIn ):
80     field_type(SWQ_FLOAT),
81     float_value(dfValueIn)
82 {
83 }
84 
85 /************************************************************************/
86 /*                        swq_expr_node(const char*)                    */
87 /************************************************************************/
88 
89 swq_expr_node::swq_expr_node( const char *pszValueIn ):
90     field_type(SWQ_STRING),
91     is_null(pszValueIn == nullptr),
92     string_value(CPLStrdup( pszValueIn ? pszValueIn : "" ))
93 {
94 }
95 
96 /************************************************************************/
97 /*                      swq_expr_node(OGRGeometry *)                    */
98 /************************************************************************/
99 
100 swq_expr_node::swq_expr_node( OGRGeometry *poGeomIn ):
101     field_type(SWQ_GEOMETRY),
102     is_null(poGeomIn == nullptr),
103     geometry_value(poGeomIn ? poGeomIn->clone() : nullptr)
104 {
105 }
106 
107 /************************************************************************/
108 /*                        swq_expr_node(swq_op)                         */
109 /************************************************************************/
110 
111 swq_expr_node::swq_expr_node( swq_op eOp ):
112     eNodeType(SNT_OPERATION),
113     nOperation(eOp)
114 {
115 }
116 
117 /************************************************************************/
118 /*                           ~swq_expr_node()                           */
119 /************************************************************************/
120 
121 swq_expr_node::~swq_expr_node()
122 
123 {
124     CPLFree( table_name );
125     CPLFree( string_value );
126 
127     for( int i = 0; i < nSubExprCount; i++ )
128         delete papoSubExpr[i];
129     CPLFree( papoSubExpr );
130     delete geometry_value;
131 }
132 
133 /************************************************************************/
134 /*                          MarkAsTimestamp()                           */
135 /************************************************************************/
136 
137 void swq_expr_node::MarkAsTimestamp()
138 
139 {
140     CPLAssert( eNodeType == SNT_CONSTANT );
141     CPLAssert( field_type == SWQ_STRING );
142     field_type = SWQ_TIMESTAMP;
143 }
144 
145 /************************************************************************/
146 /*                         PushSubExpression()                          */
147 /************************************************************************/
148 
149 void swq_expr_node::PushSubExpression( swq_expr_node *child )
150 
151 {
152     nSubExprCount++;
153     papoSubExpr = static_cast<swq_expr_node **>(
154         CPLRealloc( papoSubExpr, sizeof(void*) * nSubExprCount ));
155 
156     papoSubExpr[nSubExprCount-1] = child;
157 }
158 
159 /************************************************************************/
160 /*                       ReverseSubExpressions()                        */
161 /************************************************************************/
162 
163 void swq_expr_node::ReverseSubExpressions()
164 
165 {
166     for( int i = 0; i < nSubExprCount / 2; i++ )
167     {
168         std::swap(papoSubExpr[i], papoSubExpr[nSubExprCount - i - 1]);
169     }
170 }
171 
172 /************************************************************************/
173 /*                               Check()                                */
174 /*                                                                      */
175 /*      Check argument types, etc.                                      */
176 /************************************************************************/
177 
178 swq_field_type
179 swq_expr_node::Check( swq_field_list *poFieldList,
180                       int bAllowFieldsInSecondaryTables,
181                       int bAllowMismatchTypeOnFieldComparison,
182                       swq_custom_func_registrar* poCustomFuncRegistrar,
183                       int nDepth )
184 
185 {
186     if( nDepth == 32 )
187     {
188         CPLError(CE_Failure, CPLE_AppDefined,
189                  "Too many recursion levels in expression");
190         return SWQ_ERROR;
191     }
192 
193 /* -------------------------------------------------------------------- */
194 /*      Otherwise we take constants literally.                          */
195 /* -------------------------------------------------------------------- */
196     if( eNodeType == SNT_CONSTANT )
197         return field_type;
198 
199 /* -------------------------------------------------------------------- */
200 /*      If this is intended to be a field definition, but has not       */
201 /*      yet been looked up, we do so now.                               */
202 /* -------------------------------------------------------------------- */
203     if( eNodeType == SNT_COLUMN && field_index == -1 )
204     {
205         field_index =
206             swq_identify_field( table_name, string_value, poFieldList,
207                                 &field_type, &table_index );
208 
209         if( field_index < 0 )
210         {
211             if( table_name )
212                 CPLError( CE_Failure, CPLE_AppDefined,
213                       R"("%s"."%s" not recognised as an available field.)",
214                       table_name, string_value );
215             else
216                 CPLError( CE_Failure, CPLE_AppDefined,
217                       "\"%s\" not recognised as an available field.",
218                       string_value );
219 
220             return SWQ_ERROR;
221         }
222 
223         if( !bAllowFieldsInSecondaryTables && table_index != 0 )
224         {
225             CPLError(
226                 CE_Failure, CPLE_AppDefined,
227                 "Cannot use field '%s' of a secondary table in this context",
228                 string_value );
229             return SWQ_ERROR;
230         }
231     }
232 
233     if( eNodeType == SNT_COLUMN )
234         return field_type;
235 
236 /* -------------------------------------------------------------------- */
237 /*      We are dealing with an operation - fetch the definition.        */
238 /* -------------------------------------------------------------------- */
239     const swq_operation *poOp =
240         (nOperation == SWQ_CUSTOM_FUNC && poCustomFuncRegistrar != nullptr ) ?
241             poCustomFuncRegistrar->GetOperator(string_value) :
242             swq_op_registrar::GetOperator(nOperation);
243 
244     if( poOp == nullptr )
245     {
246         if( nOperation == SWQ_CUSTOM_FUNC )
247             CPLError( CE_Failure, CPLE_AppDefined,
248                       "Check(): Unable to find definition for operator %s.",
249                       string_value );
250         else
251             CPLError( CE_Failure, CPLE_AppDefined,
252                       "Check(): Unable to find definition for operator %d.",
253                       nOperation );
254         return SWQ_ERROR;
255     }
256 
257 /* -------------------------------------------------------------------- */
258 /*      Check subexpressions first.                                     */
259 /* -------------------------------------------------------------------- */
260     for( int i = 0; i < nSubExprCount; i++ )
261     {
262         if( papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables,
263                                   bAllowMismatchTypeOnFieldComparison,
264                                   poCustomFuncRegistrar,
265                                   nDepth + 1) == SWQ_ERROR )
266             return SWQ_ERROR;
267     }
268 
269 /* -------------------------------------------------------------------- */
270 /*      Check this node.                                                */
271 /* -------------------------------------------------------------------- */
272     field_type = poOp->pfnChecker( this, bAllowMismatchTypeOnFieldComparison );
273 
274     return field_type;
275 }
276 
277 /************************************************************************/
278 /*                                Dump()                                */
279 /************************************************************************/
280 
281 void swq_expr_node::Dump( FILE * fp, int depth )
282 
283 {
284     char spaces[60] = {};
285 
286     {
287         int i = 0;  // Used after for.
288         for( ; i < depth*2 && i < static_cast<int>(sizeof(spaces)) - 1; i++ )
289             spaces[i] = ' ';
290         spaces[i] = '\0';
291     }
292 
293     if( eNodeType == SNT_COLUMN )
294     {
295         fprintf( fp, "%s  Field %d\n", spaces, field_index );
296         return;
297     }
298 
299     if( eNodeType == SNT_CONSTANT )
300     {
301         if( field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
302             field_type == SWQ_BOOLEAN )
303             fprintf( fp, "%s  " CPL_FRMT_GIB "\n", spaces, int_value );
304         else if( field_type == SWQ_FLOAT )
305             fprintf( fp, "%s  %.15g\n", spaces, float_value );
306         else if( field_type == SWQ_GEOMETRY )
307         {
308             if( geometry_value == nullptr )
309                 fprintf( fp, "%s  (null)\n", spaces );
310             else
311             {
312                 char* pszWKT = nullptr;
313                 geometry_value->exportToWkt(&pszWKT);
314                 fprintf( fp, "%s  %s\n", spaces, pszWKT );
315                 CPLFree(pszWKT);
316             }
317         }
318         else
319             fprintf( fp, "%s  %s\n", spaces, string_value );
320         return;
321     }
322 
323     CPLAssert( eNodeType == SNT_OPERATION );
324 
325     const swq_operation *op_def =
326         swq_op_registrar::GetOperator( nOperation );
327     if( op_def )
328         fprintf( fp, "%s%s\n", spaces, op_def->pszName );
329     else
330         fprintf( fp, "%s%s\n", spaces, string_value );
331 
332     for( int i = 0; i < nSubExprCount; i++ )
333         papoSubExpr[i]->Dump( fp, depth+1 );
334 }
335 
336 /************************************************************************/
337 /*                       QuoteIfNecessary()                             */
338 /*                                                                      */
339 /*      Add quoting if necessary to unparse a string.                   */
340 /************************************************************************/
341 
342 CPLString swq_expr_node::QuoteIfNecessary( const CPLString &osExpr,
343                                            char chQuote )
344 
345 {
346     if( osExpr[0] == '_' )
347         return Quote(osExpr, chQuote);
348     if( osExpr == "*" )
349         return osExpr;
350 
351     for( int i = 0; i < static_cast<int>(osExpr.size()); i++ )
352     {
353         char ch = osExpr[i];
354         if( (!(isalnum(static_cast<int>(ch)) || ch == '_')) || ch == '.' )
355         {
356             return Quote(osExpr, chQuote);
357         }
358     }
359 
360     if( swq_is_reserved_keyword(osExpr) )
361     {
362         return Quote(osExpr, chQuote);
363     }
364 
365     return osExpr;
366 }
367 
368 /************************************************************************/
369 /*                               Quote()                                */
370 /*                                                                      */
371 /*      Add quoting necessary to unparse a string.                      */
372 /************************************************************************/
373 
374 CPLString swq_expr_node::Quote( const CPLString &osTarget, char chQuote )
375 
376 {
377     CPLString osNew;
378 
379     osNew += chQuote;
380 
381     for( int i = 0; i < static_cast<int>(osTarget.size()); i++ )
382     {
383         if( osTarget[i] == chQuote )
384         {
385             osNew += chQuote;
386             osNew += chQuote;
387         }
388         else
389             osNew += osTarget[i];
390     }
391     osNew += chQuote;
392 
393     return osNew;
394 }
395 
396 /************************************************************************/
397 /*                              Unparse()                               */
398 /************************************************************************/
399 
400 char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
401 
402 {
403     CPLString osExpr;
404 
405 /* -------------------------------------------------------------------- */
406 /*      Handle constants.                                               */
407 /* -------------------------------------------------------------------- */
408     if( eNodeType == SNT_CONSTANT )
409     {
410         if( is_null )
411             return CPLStrdup("NULL");
412 
413         if( field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
414             field_type == SWQ_BOOLEAN )
415             osExpr.Printf( CPL_FRMT_GIB, int_value );
416         else if( field_type == SWQ_FLOAT )
417         {
418             osExpr.Printf( "%.15g", float_value );
419             // Make sure this is interpreted as a floating point value
420             // and not as an integer later.
421             if( strchr(osExpr, '.') == nullptr && strchr(osExpr, 'e') == nullptr &&
422                 strchr(osExpr, 'E') == nullptr )
423                 osExpr += '.';
424         }
425         else
426         {
427             osExpr = Quote( string_value );
428         }
429 
430         return CPLStrdup(osExpr);
431     }
432 
433 /* -------------------------------------------------------------------- */
434 /*      Handle columns.                                                 */
435 /* -------------------------------------------------------------------- */
436     if( eNodeType == SNT_COLUMN )
437     {
438         if( field_list == nullptr )
439         {
440             if( table_name )
441                 osExpr.Printf(
442                     "%s.%s",
443                     QuoteIfNecessary(table_name, chColumnQuote).c_str(),
444                     QuoteIfNecessary(string_value, chColumnQuote).c_str() );
445             else
446                 osExpr.Printf(
447                     "%s",
448                     QuoteIfNecessary(string_value, chColumnQuote).c_str() );
449         }
450         else if( field_index != -1
451             && table_index < field_list->table_count
452             && table_index > 0 )
453         {
454             // We deliberately browse through the list starting from the end
455             // This is for the case where the FID column exists both as
456             // FID and then real_fid_name. We want real_fid_name to be used
457             for( int i = field_list->count - 1; i >= 0; i-- )
458             {
459                 if( field_list->table_ids[i] == table_index &&
460                     field_list->ids[i] == field_index )
461                 {
462                     osExpr.Printf( "%s.%s",
463                                    QuoteIfNecessary(field_list->table_defs[table_index].table_name, chColumnQuote).c_str(),
464                                    QuoteIfNecessary(field_list->names[i], chColumnQuote).c_str() );
465                     break;
466                 }
467             }
468         }
469         else if( field_index != -1 )
470         {
471             // We deliberately browse through the list starting from the end
472             // This is for the case where the FID column exists both as
473             // FID and then real_fid_name. We want real_fid_name to be used
474             for( int i = field_list->count - 1; i >= 0; i-- )
475             {
476                 if( field_list->table_ids[i] == table_index &&
477                     field_list->ids[i] == field_index )
478                 {
479                     osExpr.Printf( "%s", QuoteIfNecessary(field_list->names[i], chColumnQuote).c_str() );
480                     break;
481                 }
482             }
483         }
484 
485         if( osExpr.empty() )
486         {
487             return CPLStrdup(CPLSPrintf("%c%c", chColumnQuote, chColumnQuote));
488         }
489 
490         // The string is just alphanum and not a reserved SQL keyword,
491         // no needs to quote and escape.
492         return CPLStrdup(osExpr.c_str());
493     }
494 
495 /* -------------------------------------------------------------------- */
496 /*      Operation - start by unparsing all the subexpressions.          */
497 /* -------------------------------------------------------------------- */
498     std::vector<char*> apszSubExpr;
499     apszSubExpr.reserve(nSubExprCount);
500     for( int i = 0; i < nSubExprCount; i++ )
501         apszSubExpr.push_back( papoSubExpr[i]->Unparse(field_list, chColumnQuote) );
502 
503     osExpr = UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
504 
505 /* -------------------------------------------------------------------- */
506 /*      cleanup subexpressions.                                         */
507 /* -------------------------------------------------------------------- */
508     for( int i = 0; i < nSubExprCount; i++ )
509         CPLFree( apszSubExpr[i] );
510 
511     return CPLStrdup( osExpr.c_str() );
512 }
513 
514 /************************************************************************/
515 /*                  UnparseOperationFromUnparsedSubExpr()               */
516 /************************************************************************/
517 
518 CPLString swq_expr_node::UnparseOperationFromUnparsedSubExpr(char** apszSubExpr)
519 {
520     CPLString osExpr;
521 
522 /* -------------------------------------------------------------------- */
523 /*      Put things together in a fashion depending on the operator.     */
524 /* -------------------------------------------------------------------- */
525     const swq_operation *poOp =
526         swq_op_registrar::GetOperator( nOperation );
527 
528     if( poOp == nullptr && nOperation != SWQ_CUSTOM_FUNC )
529     {
530         CPLAssert( false );
531         return osExpr;
532     }
533 
534     switch( nOperation )
535     {
536       // Binary infix operators.
537       case SWQ_OR:
538       case SWQ_AND:
539       case SWQ_EQ:
540       case SWQ_NE:
541       case SWQ_GT:
542       case SWQ_LT:
543       case SWQ_GE:
544       case SWQ_LE:
545       case SWQ_LIKE:
546       case SWQ_ILIKE:
547       case SWQ_ADD:
548       case SWQ_SUBTRACT:
549       case SWQ_MULTIPLY:
550       case SWQ_DIVIDE:
551       case SWQ_MODULUS:
552         CPLAssert( nSubExprCount >= 2 );
553         if( papoSubExpr[0]->eNodeType == SNT_COLUMN ||
554             papoSubExpr[0]->eNodeType == SNT_CONSTANT )
555         {
556             osExpr += apszSubExpr[0];
557         }
558         else
559         {
560             osExpr += "(";
561             osExpr += apszSubExpr[0];
562             osExpr += ")";
563         }
564         osExpr += " ";
565         osExpr += poOp->pszName;
566         osExpr += " ";
567         if( papoSubExpr[1]->eNodeType == SNT_COLUMN ||
568             papoSubExpr[1]->eNodeType == SNT_CONSTANT )
569         {
570             osExpr += apszSubExpr[1];
571         }
572         else
573         {
574             osExpr += "(";
575             osExpr += apszSubExpr[1];
576             osExpr += ")";
577         }
578         if( (nOperation == SWQ_LIKE || nOperation == SWQ_ILIKE) && nSubExprCount == 3 )
579             osExpr += CPLSPrintf( " ESCAPE (%s)", apszSubExpr[2] );
580         break;
581 
582       case SWQ_NOT:
583         CPLAssert( nSubExprCount == 1 );
584         osExpr.Printf( "NOT (%s)", apszSubExpr[0] );
585         break;
586 
587       case SWQ_ISNULL:
588         CPLAssert( nSubExprCount == 1 );
589         osExpr.Printf( "%s IS NULL", apszSubExpr[0] );
590         break;
591 
592       case SWQ_IN:
593         osExpr.Printf( "%s IN (", apszSubExpr[0] );
594         for( int i = 1; i < nSubExprCount; i++ )
595         {
596             if( i > 1 )
597                 osExpr += ",";
598             osExpr += "(";
599             osExpr += apszSubExpr[i];
600             osExpr += ")";
601         }
602         osExpr += ")";
603         break;
604 
605       case SWQ_BETWEEN:
606         CPLAssert( nSubExprCount == 3 );
607         osExpr.Printf( "%s %s (%s) AND (%s)",
608                        apszSubExpr[0],
609                        poOp->pszName,
610                        apszSubExpr[1],
611                        apszSubExpr[2] );
612         break;
613 
614       case SWQ_CAST:
615         osExpr = "CAST(";
616         for( int i = 0; i < nSubExprCount; i++ )
617         {
618             if( i == 1 )
619                 osExpr += " AS ";
620             else if( i > 2 )
621                 osExpr += ", ";
622 
623             const int nLen = static_cast<int>(strlen(apszSubExpr[i]));
624             if( (i == 1 &&
625                 (apszSubExpr[i][0] == '\'' &&
626                  nLen > 2 && apszSubExpr[i][nLen-1] == '\'')) ||
627                 (i == 2 && EQUAL(apszSubExpr[1], "'GEOMETRY")) )
628             {
629                 apszSubExpr[i][nLen-1] = '\0';
630                 osExpr += apszSubExpr[i] + 1;
631             }
632             else
633                 osExpr += apszSubExpr[i];
634 
635             if( i == 1 && nSubExprCount > 2)
636                 osExpr += "(";
637             else if( i > 1 && i == nSubExprCount - 1 )
638                 osExpr += ")";
639         }
640         osExpr += ")";
641         break;
642 
643       default: // function style.
644         if( nOperation != SWQ_CUSTOM_FUNC )
645             osExpr.Printf( "%s(", poOp->pszName );
646         else
647             osExpr.Printf( "%s(", string_value );
648         for( int i = 0; i < nSubExprCount; i++ )
649         {
650             if( i > 0 )
651                 osExpr += ",";
652             osExpr += "(";
653             osExpr += apszSubExpr[i];
654             osExpr += ")";
655         }
656         osExpr += ")";
657         break;
658     }
659 
660     return osExpr;
661 }
662 
663 /************************************************************************/
664 /*                               Clone()                                */
665 /************************************************************************/
666 
667 swq_expr_node *swq_expr_node::Clone()
668 {
669     swq_expr_node* poRetNode = new swq_expr_node();
670 
671     poRetNode->eNodeType = eNodeType;
672     poRetNode->field_type = field_type;
673     if( eNodeType == SNT_OPERATION )
674     {
675         poRetNode->nOperation = nOperation;
676         poRetNode->nSubExprCount = nSubExprCount;
677         poRetNode->papoSubExpr = static_cast<swq_expr_node **>(
678                 CPLMalloc( sizeof(void*) * nSubExprCount ));
679         for( int i = 0; i < nSubExprCount; i++ )
680             poRetNode->papoSubExpr[i] = papoSubExpr[i]->Clone();
681     }
682     else if( eNodeType == SNT_COLUMN )
683     {
684         poRetNode->field_index = field_index;
685         poRetNode->table_index = table_index;
686         poRetNode->table_name = table_name ? CPLStrdup(table_name) : nullptr;
687     }
688     else if( eNodeType == SNT_CONSTANT )
689     {
690         poRetNode->is_null = is_null;
691         poRetNode->int_value = int_value;
692         poRetNode->float_value = float_value;
693         if( geometry_value )
694             poRetNode->geometry_value = geometry_value->clone();
695         else
696             poRetNode->geometry_value = nullptr;
697     }
698     poRetNode->string_value = string_value ? CPLStrdup(string_value) : nullptr;
699     return poRetNode;
700 }
701 
702 /************************************************************************/
703 /*                              Evaluate()                              */
704 /************************************************************************/
705 
706 swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
707                                         void *pRecord )
708 
709 {
710     return Evaluate(pfnFetcher, pRecord, 0);
711 }
712 
713 swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
714                                         void *pRecord, int nRecLevel )
715 
716 {
717     swq_expr_node *poRetNode = nullptr;
718     if( nRecLevel == 32 )
719     {
720         CPLError(CE_Failure, CPLE_AppDefined,
721                  "Too many recursion levels in expression");
722         return nullptr;
723     }
724 
725 /* -------------------------------------------------------------------- */
726 /*      Duplicate ourselves if we are already a constant.               */
727 /* -------------------------------------------------------------------- */
728     if( eNodeType == SNT_CONSTANT )
729     {
730         return Clone();
731     }
732 
733 /* -------------------------------------------------------------------- */
734 /*      If this is a field value from a record, fetch and return it.    */
735 /* -------------------------------------------------------------------- */
736     if( eNodeType == SNT_COLUMN )
737     {
738         return pfnFetcher( this, pRecord );
739     }
740 
741 /* -------------------------------------------------------------------- */
742 /*      This is an operation, collect the arguments keeping track of    */
743 /*      which we will need to free.                                     */
744 /* -------------------------------------------------------------------- */
745     std::vector<swq_expr_node*> apoValues;
746     std::vector<int> anValueNeedsFree;
747     bool bError = false;
748     apoValues.reserve(nSubExprCount);
749     for( int i = 0; i < nSubExprCount && !bError; i++ )
750     {
751         if( papoSubExpr[i]->eNodeType == SNT_CONSTANT )
752         {
753             // avoid duplication.
754             apoValues.push_back( papoSubExpr[i] );
755             anValueNeedsFree.push_back( FALSE );
756         }
757         else
758         {
759             swq_expr_node* poSubExprVal =
760                 papoSubExpr[i]->Evaluate(pfnFetcher, pRecord, nRecLevel + 1);
761             if( poSubExprVal == nullptr )
762                 bError = true;
763             else
764             {
765                 apoValues.push_back(poSubExprVal);
766                 anValueNeedsFree.push_back( TRUE );
767             }
768         }
769     }
770 
771 /* -------------------------------------------------------------------- */
772 /*      Fetch the operator definition and function.                     */
773 /* -------------------------------------------------------------------- */
774     if( !bError )
775     {
776         const swq_operation *poOp =
777             swq_op_registrar::GetOperator( nOperation );
778         if( poOp == nullptr )
779         {
780             if( nOperation == SWQ_CUSTOM_FUNC )
781                 CPLError( CE_Failure, CPLE_AppDefined,
782                         "Evaluate(): Unable to find definition for operator %s.",
783                         string_value );
784             else
785                 CPLError(
786                     CE_Failure, CPLE_AppDefined,
787                     "Evaluate(): Unable to find definition for operator %d.",
788                     nOperation );
789             poRetNode = nullptr;
790         }
791         else
792             poRetNode = poOp->pfnEvaluator( this, &(apoValues[0]) );
793     }
794 
795 /* -------------------------------------------------------------------- */
796 /*      Cleanup                                                         */
797 /* -------------------------------------------------------------------- */
798     for( int i = 0; i < static_cast<int>(apoValues.size()); i++ )
799     {
800         if( anValueNeedsFree[i] )
801             delete apoValues[i];
802     }
803 
804     return poRetNode;
805 }
806 
807 /************************************************************************/
808 /*                      ReplaceBetweenByGEAndLERecurse()                */
809 /************************************************************************/
810 
811 void swq_expr_node::ReplaceBetweenByGEAndLERecurse()
812 {
813     if( eNodeType != SNT_OPERATION )
814         return;
815 
816     if( nOperation != SWQ_BETWEEN )
817     {
818         for( int i = 0; i < nSubExprCount; i++ )
819             papoSubExpr[i]->ReplaceBetweenByGEAndLERecurse();
820         return;
821     }
822 
823     if( nSubExprCount != 3 )
824         return;
825 
826     swq_expr_node* poExpr0 = papoSubExpr[0];
827     swq_expr_node* poExpr1 = papoSubExpr[1];
828     swq_expr_node* poExpr2 = papoSubExpr[2];
829 
830     nSubExprCount = 2;
831     nOperation = SWQ_AND;
832     papoSubExpr[0] = new swq_expr_node(SWQ_GE);
833     papoSubExpr[0]->PushSubExpression(poExpr0);
834     papoSubExpr[0]->PushSubExpression(poExpr1);
835     papoSubExpr[1] = new swq_expr_node(SWQ_LE);
836     papoSubExpr[1]->PushSubExpression(poExpr0->Clone());
837     papoSubExpr[1]->PushSubExpression(poExpr2);
838 }
839 
840 #endif  // #ifndef DOXYGEN_SKIP
841