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
swq_expr_node(int nValueIn)60 swq_expr_node::swq_expr_node( int nValueIn ):
61 int_value(nValueIn)
62 {
63 }
64
65 /************************************************************************/
66 /* swq_expr_node(GIntBig) */
67 /************************************************************************/
68
swq_expr_node(GIntBig nValueIn)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
swq_expr_node(double dfValueIn)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
swq_expr_node(const char * pszValueIn)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
swq_expr_node(OGRGeometry * poGeomIn)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
swq_expr_node(swq_op eOp)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
~swq_expr_node()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
MarkAsTimestamp()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
PushSubExpression(swq_expr_node * child)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
ReverseSubExpressions()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
Check(swq_field_list * poFieldList,int bAllowFieldsInSecondaryTables,int bAllowMismatchTypeOnFieldComparison,swq_custom_func_registrar * poCustomFuncRegistrar,int nDepth)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
Dump(FILE * fp,int depth)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
QuoteIfNecessary(const CPLString & osExpr,char chQuote)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
Quote(const CPLString & osTarget,char chQuote)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
Unparse(swq_field_list * field_list,char chColumnQuote)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
UnparseOperationFromUnparsedSubExpr(char ** apszSubExpr)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
Clone()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
Evaluate(swq_field_fetcher pfnFetcher,void * pRecord)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
Evaluate(swq_field_fetcher pfnFetcher,void * pRecord,int nRecLevel)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
ReplaceBetweenByGEAndLERecurse()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