Coverage Report

Created: 2025-06-09 07:43

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