Coverage Report

Created: 2025-06-22 06:59

/src/gdal/ogr/ogr_swq.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Component: OGDI Driver Support Library
4
 * Purpose: Generic SQL WHERE Expression Evaluator Declarations.
5
 * Author: Frank Warmerdam <warmerdam@pobox.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (C) 2001 Information Interoperability Institute (3i)
9
 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10
 * Permission to use, copy, modify and distribute this software and
11
 * its documentation for any purpose and without fee is hereby granted,
12
 * provided that the above copyright notice appear in all copies, that
13
 * both the copyright notice and this permission notice appear in
14
 * supporting documentation, and that the name of 3i not be used
15
 * in advertising or publicity pertaining to distribution of the software
16
 * without specific, written prior permission.  3i makes no
17
 * representations about the suitability of this software for any purpose.
18
 * It is provided "as is" without express or implied warranty.
19
 ****************************************************************************/
20
21
#ifndef SWQ_H_INCLUDED_
22
#define SWQ_H_INCLUDED_
23
24
#ifndef DOXYGEN_SKIP
25
26
#include "cpl_conv.h"
27
#include "cpl_string.h"
28
#include "ogr_core.h"
29
30
#include <list>
31
#include <map>
32
#include <vector>
33
#include <set>
34
35
#if defined(_WIN32) && !defined(strcasecmp)
36
#define strcasecmp stricmp
37
#endif
38
39
// Used for swq_summary.oSetDistinctValues and oVectorDistinctValues
40
0
#define SZ_OGR_NULL "__OGR_NULL__"
41
42
typedef enum
43
{
44
    SWQ_OR,
45
    SWQ_AND,
46
    SWQ_NOT,
47
    SWQ_EQ,
48
    SWQ_NE,
49
    SWQ_GE,
50
    SWQ_LE,
51
    SWQ_LT,
52
    SWQ_GT,
53
    SWQ_LIKE,
54
    SWQ_ILIKE,
55
    SWQ_ISNULL,
56
    SWQ_IN,
57
    SWQ_BETWEEN,
58
    SWQ_ADD,
59
    SWQ_SUBTRACT,
60
    SWQ_MULTIPLY,
61
    SWQ_DIVIDE,
62
    SWQ_MODULUS,
63
    SWQ_CONCAT,
64
    SWQ_SUBSTR,
65
    SWQ_HSTORE_GET_VALUE,
66
67
    SWQ_AVG,
68
    SWQ_AGGREGATE_BEGIN = SWQ_AVG,
69
    SWQ_MIN,
70
    SWQ_MAX,
71
    SWQ_COUNT,
72
    SWQ_SUM,
73
    SWQ_STDDEV_POP,
74
    SWQ_STDDEV_SAMP,
75
    SWQ_AGGREGATE_END = SWQ_STDDEV_SAMP,
76
77
    SWQ_CAST,
78
    SWQ_CUSTOM_FUNC,  /* only if parsing done in bAcceptCustomFuncs mode */
79
    SWQ_ARGUMENT_LIST /* temporary value only set during parsing and replaced by
80
                         something else at the end */
81
} swq_op;
82
83
typedef enum
84
{
85
    SWQ_INTEGER,
86
    SWQ_INTEGER64,
87
    SWQ_FLOAT,
88
    SWQ_STRING,
89
    SWQ_BOOLEAN,    // integer
90
    SWQ_DATE,       // string
91
    SWQ_TIME,       // string
92
    SWQ_TIMESTAMP,  // string
93
    SWQ_GEOMETRY,
94
    SWQ_NULL,
95
    SWQ_OTHER,
96
    SWQ_ERROR
97
} swq_field_type;
98
99
0
#define SWQ_IS_INTEGER(x) ((x) == SWQ_INTEGER || (x) == SWQ_INTEGER64)
100
101
typedef enum
102
{
103
    SNT_CONSTANT,
104
    SNT_COLUMN,
105
    SNT_OPERATION
106
} swq_node_type;
107
108
class swq_field_list;
109
class swq_expr_node;
110
class swq_select;
111
class OGRGeometry;
112
113
struct CPL_UNSTABLE_API swq_evaluation_context
114
{
115
    bool bUTF8Strings = false;
116
};
117
118
typedef swq_expr_node *(*swq_field_fetcher)(swq_expr_node *op,
119
                                            void *record_handle);
120
typedef swq_expr_node *(*swq_op_evaluator)(
121
    swq_expr_node *op, swq_expr_node **sub_field_values,
122
    const swq_evaluation_context &sContext);
123
typedef swq_field_type (*swq_op_checker)(
124
    swq_expr_node *op, int bAllowMismatchTypeOnFieldComparison);
125
126
class swq_custom_func_registrar;
127
128
class CPL_UNSTABLE_API swq_expr_node
129
{
130
    swq_expr_node *Evaluate(swq_field_fetcher pfnFetcher, void *record,
131
                            const swq_evaluation_context &sContext,
132
                            int nRecLevel);
133
    void reset();
134
135
  public:
136
    swq_expr_node();
137
    swq_expr_node(const swq_expr_node &);
138
    swq_expr_node(swq_expr_node &&);
139
140
    swq_expr_node &operator=(const swq_expr_node &);
141
    swq_expr_node &operator=(swq_expr_node &&);
142
143
    bool operator==(const swq_expr_node &) const;
144
145
    explicit swq_expr_node(const char *);
146
    explicit swq_expr_node(int);
147
    explicit swq_expr_node(GIntBig);
148
    explicit swq_expr_node(double);
149
    explicit swq_expr_node(OGRGeometry *);
150
    explicit swq_expr_node(swq_op);
151
152
    ~swq_expr_node();
153
154
    void MarkAsTimestamp();
155
    CPLString UnparseOperationFromUnparsedSubExpr(char **apszSubExpr);
156
    char *Unparse(swq_field_list *, char chColumnQuote);
157
    void Dump(FILE *fp, int depth);
158
    swq_field_type Check(swq_field_list *, int bAllowFieldsInSecondaryTables,
159
                         int bAllowMismatchTypeOnFieldComparison,
160
                         swq_custom_func_registrar *poCustomFuncRegistrar);
161
    swq_expr_node *Evaluate(swq_field_fetcher pfnFetcher, void *record,
162
                            const swq_evaluation_context &sContext);
163
    swq_expr_node *Clone();
164
165
    void ReplaceBetweenByGEAndLERecurse();
166
    void ReplaceInByOrRecurse();
167
    void PushNotOperationDownToStack();
168
169
    void RebalanceAndOr();
170
171
    bool HasReachedMaxDepth() const;
172
173
    swq_node_type eNodeType = SNT_CONSTANT;
174
    swq_field_type field_type = SWQ_INTEGER;
175
176
    /* only for SNT_OPERATION */
177
    void PushSubExpression(swq_expr_node *);
178
    void ReverseSubExpressions();
179
    swq_op nOperation = SWQ_OR;
180
    int nSubExprCount = 0;
181
    swq_expr_node **papoSubExpr = nullptr;
182
183
    /* only for SNT_COLUMN */
184
    int field_index = 0;
185
    int table_index = 0;
186
    char *table_name = nullptr;
187
188
    /* only for SNT_CONSTANT */
189
    int is_null = false;
190
    int64_t int_value = 0;
191
    double float_value = 0.0;
192
    OGRGeometry *geometry_value = nullptr;
193
194
    /* shared by SNT_COLUMN, SNT_CONSTANT and also possibly SNT_OPERATION when
195
     */
196
    /* nOperation == SWQ_CUSTOM_FUNC */
197
    char *string_value = nullptr; /* column name when SNT_COLUMN */
198
199
    // May be transiently used by swq_parser.h, but should not be relied upon
200
    // after parsing. swq_col_def.bHidden captures it afterwards.
201
    bool bHidden = false;
202
203
    // Recursive depth of this expression, taking into account papoSubExpr.
204
    int nDepth = 1;
205
206
    static CPLString QuoteIfNecessary(const CPLString &, char chQuote = '\'');
207
    static CPLString Quote(const CPLString &, char chQuote = '\'');
208
};
209
210
typedef struct
211
{
212
    const char *pszName;
213
    swq_op eOperation;
214
    swq_op_evaluator pfnEvaluator;
215
    swq_op_checker pfnChecker;
216
} swq_operation;
217
218
class CPL_UNSTABLE_API swq_op_registrar
219
{
220
  public:
221
    static const swq_operation *GetOperator(const char *);
222
    static const swq_operation *GetOperator(swq_op eOperation);
223
};
224
225
class CPL_UNSTABLE_API swq_custom_func_registrar
226
{
227
  public:
228
    virtual ~swq_custom_func_registrar();
229
230
    virtual const swq_operation *GetOperator(const char *) = 0;
231
};
232
233
typedef struct
234
{
235
    char *data_source;
236
    char *table_name;
237
    char *table_alias;
238
} swq_table_def;
239
240
class CPL_UNSTABLE_API swq_field_list
241
{
242
  public:
243
    int count;
244
    char **names;
245
    swq_field_type *types;
246
    int *table_ids;
247
    int *ids;
248
249
    int table_count;
250
    swq_table_def *table_defs;
251
};
252
253
class CPL_UNSTABLE_API swq_parse_context
254
{
255
  public:
256
    swq_parse_context()
257
0
        : nStartToken(0), pszInput(nullptr), pszNext(nullptr),
258
0
          pszLastValid(nullptr), bAcceptCustomFuncs(FALSE), poRoot(nullptr),
259
0
          poCurSelect(nullptr)
260
0
    {
261
0
    }
262
263
    int nStartToken;
264
    const char *pszInput;
265
    const char *pszNext;
266
    const char *pszLastValid;
267
    int bAcceptCustomFuncs;
268
269
    swq_expr_node *poRoot;
270
271
    swq_select *poCurSelect;
272
};
273
274
/* Compile an SQL WHERE clause into an internal form.  The field_list is
275
** the list of fields in the target 'table', used to render where into
276
** field numbers instead of names.
277
*/
278
int CPL_UNSTABLE_API swqparse(swq_parse_context *context);
279
int CPL_UNSTABLE_API swqlex(swq_expr_node **ppNode, swq_parse_context *context);
280
void CPL_UNSTABLE_API swqerror(swq_parse_context *context, const char *msg);
281
282
int CPL_UNSTABLE_API swq_identify_field(const char *table_name,
283
                                        const char *token,
284
                                        swq_field_list *field_list,
285
                                        swq_field_type *this_type,
286
                                        int *table_id);
287
288
CPLErr CPL_UNSTABLE_API
289
swq_expr_compile(const char *where_clause, int field_count, char **field_list,
290
                 swq_field_type *field_types, int bCheck,
291
                 swq_custom_func_registrar *poCustomFuncRegistrar,
292
                 swq_expr_node **expr_root);
293
294
CPLErr CPL_UNSTABLE_API
295
swq_expr_compile2(const char *where_clause, swq_field_list *field_list,
296
                  int bCheck, swq_custom_func_registrar *poCustomFuncRegistrar,
297
                  swq_expr_node **expr_root);
298
299
/*
300
** Evaluation related.
301
*/
302
int CPL_UNSTABLE_API swq_test_like(const char *input, const char *pattern);
303
304
swq_expr_node CPL_UNSTABLE_API *
305
SWQGeneralEvaluator(swq_expr_node *, swq_expr_node **,
306
                    const swq_evaluation_context &sContext);
307
swq_field_type CPL_UNSTABLE_API
308
SWQGeneralChecker(swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison);
309
swq_expr_node CPL_UNSTABLE_API *
310
SWQCastEvaluator(swq_expr_node *, swq_expr_node **,
311
                 const swq_evaluation_context &sContext);
312
swq_field_type CPL_UNSTABLE_API
313
SWQCastChecker(swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison);
314
const char CPL_UNSTABLE_API *SWQFieldTypeToString(swq_field_type field_type);
315
316
/****************************************************************************/
317
318
#define SWQP_ALLOW_UNDEFINED_COL_FUNCS 0x01
319
320
0
#define SWQM_SUMMARY_RECORD 1
321
0
#define SWQM_RECORDSET 2
322
0
#define SWQM_DISTINCT_LIST 3
323
324
typedef enum
325
{
326
    SWQCF_NONE = 0,
327
    SWQCF_AVG = SWQ_AVG,
328
    SWQCF_MIN = SWQ_MIN,
329
    SWQCF_MAX = SWQ_MAX,
330
    SWQCF_COUNT = SWQ_COUNT,
331
    SWQCF_SUM = SWQ_SUM,
332
    SWQCF_STDDEV_POP = SWQ_STDDEV_POP,
333
    SWQCF_STDDEV_SAMP = SWQ_STDDEV_SAMP,
334
    SWQCF_CUSTOM
335
} swq_col_func;
336
337
typedef struct
338
{
339
    swq_col_func col_func;
340
    char *table_name;
341
    char *field_name;
342
    char *field_alias;
343
    int table_index;
344
    int field_index;
345
    swq_field_type field_type;
346
    swq_field_type target_type;
347
    OGRFieldSubType target_subtype;
348
    int field_length;
349
    int field_precision;
350
    int distinct_flag;
351
    bool bHidden;
352
    OGRwkbGeometryType eGeomType;
353
    int nSRID;
354
    swq_expr_node *expr;
355
} swq_col_def;
356
357
class CPL_UNSTABLE_API swq_summary
358
{
359
  public:
360
    struct Comparator
361
    {
362
        bool bSortAsc;
363
        swq_field_type eType;
364
365
0
        Comparator() : bSortAsc(true), eType(SWQ_STRING)
366
0
        {
367
0
        }
368
369
        bool operator()(const CPLString &, const CPLString &) const;
370
    };
371
372
    //! Return the sum, using Kahan-Babuska-Neumaier algorithm.
373
    // Cf cf KahanBabushkaNeumaierSum of https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
374
    double sum() const
375
0
    {
376
0
        return sum_only_finite_terms ? sum_acc + sum_correction : sum_acc;
377
0
    }
378
379
    GIntBig count = 0;
380
381
    std::vector<CPLString> oVectorDistinctValues{};
382
    std::set<CPLString, Comparator> oSetDistinctValues{};
383
    bool sum_only_finite_terms = true;
384
    // Sum accumulator. To get the accurate sum, use the sum() method
385
    double sum_acc = 0.0;
386
    // Sum correction term.
387
    double sum_correction = 0.0;
388
    double min = 0.0;
389
    double max = 0.0;
390
391
    // Welford's online algorithm for variance:
392
    // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
393
    double mean_for_variance = 0.0;
394
    double sq_dist_from_mean_acc = 0.0;  // "M2"
395
396
    CPLString osMin{};
397
    CPLString osMax{};
398
};
399
400
typedef struct
401
{
402
    char *table_name;
403
    char *field_name;
404
    int table_index;
405
    int field_index;
406
    int ascending_flag;
407
} swq_order_def;
408
409
typedef struct
410
{
411
    int secondary_table;
412
    swq_expr_node *poExpr;
413
} swq_join_def;
414
415
class CPL_UNSTABLE_API swq_select_parse_options
416
{
417
  public:
418
    swq_custom_func_registrar *poCustomFuncRegistrar;
419
    int bAllowFieldsInSecondaryTablesInWhere;
420
    int bAddSecondaryTablesGeometryFields;
421
    int bAlwaysPrefixWithTableName;
422
    int bAllowDistinctOnGeometryField;
423
    int bAllowDistinctOnMultipleFields;
424
425
    swq_select_parse_options()
426
        : poCustomFuncRegistrar(nullptr),
427
          bAllowFieldsInSecondaryTablesInWhere(FALSE),
428
          bAddSecondaryTablesGeometryFields(FALSE),
429
          bAlwaysPrefixWithTableName(FALSE),
430
          bAllowDistinctOnGeometryField(FALSE),
431
          bAllowDistinctOnMultipleFields(FALSE)
432
0
    {
433
0
    }
434
};
435
436
class CPL_UNSTABLE_API swq_select
437
{
438
    void postpreparse();
439
440
    CPL_DISALLOW_COPY_ASSIGN(swq_select)
441
442
  public:
443
    swq_select();
444
    ~swq_select();
445
446
    int query_mode = 0;
447
448
    char *raw_select = nullptr;
449
450
    int PushField(swq_expr_node *poExpr, const char *pszAlias,
451
                  bool distinct_flag, bool bHidden);
452
453
    int PushExcludeField(swq_expr_node *poExpr);
454
455
    int result_columns() const
456
0
    {
457
0
        return static_cast<int>(column_defs.size());
458
0
    }
459
460
    std::vector<swq_col_def> column_defs{};
461
    std::vector<swq_summary> column_summary{};
462
463
    int PushTableDef(const char *pszDataSource, const char *pszTableName,
464
                     const char *pszAlias);
465
    int table_count = 0;
466
    swq_table_def *table_defs = nullptr;
467
468
    void PushJoin(int iSecondaryTable, swq_expr_node *poExpr);
469
    int join_count = 0;
470
    swq_join_def *join_defs = nullptr;
471
472
    swq_expr_node *where_expr = nullptr;
473
474
    void PushOrderBy(const char *pszTableName, const char *pszFieldName,
475
                     int bAscending);
476
    int order_specs = 0;
477
    swq_order_def *order_defs = nullptr;
478
479
    void SetLimit(GIntBig nLimit);
480
    GIntBig limit = -1;
481
482
    void SetOffset(GIntBig nOffset);
483
    GIntBig offset = 0;
484
485
    swq_select *poOtherSelect = nullptr;
486
    void PushUnionAll(swq_select *poOtherSelectIn);
487
488
    CPLErr preparse(const char *select_statement,
489
                    int bAcceptCustomFuncs = FALSE);
490
    CPLErr expand_wildcard(swq_field_list *field_list,
491
                           int bAlwaysPrefixWithTableName);
492
    CPLErr parse(swq_field_list *field_list,
493
                 swq_select_parse_options *poParseOptions);
494
495
    char *Unparse();
496
497
    bool bExcludedGeometry = false;
498
499
  private:
500
    bool IsFieldExcluded(int src_index, const char *table, const char *field);
501
502
    // map of EXCLUDE columns keyed according to the index of the
503
    // asterisk with which it should be associated. key of -1 is
504
    // used for column lists that have not yet been associated with
505
    // an asterisk.
506
    std::map<int, std::list<swq_col_def>> m_exclude_fields{};
507
};
508
509
/* This method should generally be invoked with pszValue set, except when
510
 * called on a non-DISTINCT column definition of numeric type (SWQ_BOOLEAN,
511
 * SWQ_INTEGER, SWQ_INTEGER64, SWQ_FLOAT), in which case pdfValue should
512
 * rather be set.
513
 */
514
const char CPL_UNSTABLE_API *swq_select_summarize(swq_select *select_info,
515
                                                  int dest_column,
516
                                                  const char *pszValue,
517
                                                  const double *pdfValue);
518
519
int CPL_UNSTABLE_API swq_is_reserved_keyword(const char *pszStr);
520
521
char CPL_UNSTABLE_API *OGRHStoreGetValue(const char *pszHStore,
522
                                         const char *pszSearchedKey);
523
524
#ifdef GDAL_COMPILATION
525
void swq_fixup(swq_parse_context *psParseContext);
526
swq_expr_node *swq_create_and_or_or(swq_op op, swq_expr_node *left,
527
                                    swq_expr_node *right);
528
int swq_test_like(const char *input, const char *pattern, char chEscape,
529
                  bool insensitive, bool bUTF8Strings);
530
#endif
531
532
#endif /* #ifndef DOXYGEN_SKIP */
533
534
#endif /* def SWQ_H_INCLUDED_ */