GDAL
ogr_swq.h
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#define SZ_OGR_NULL "__OGR_NULL__"
41
42typedef 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
83typedef 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#define SWQ_IS_INTEGER(x) ((x) == SWQ_INTEGER || (x) == SWQ_INTEGER64)
100
101typedef enum
102{
103 SNT_CONSTANT,
104 SNT_COLUMN,
105 SNT_OPERATION
106} swq_node_type;
107
108class swq_field_list;
109class swq_expr_node;
110class swq_select;
111class OGRGeometry;
112
113struct CPL_UNSTABLE_API swq_evaluation_context
114{
115 bool bUTF8Strings = false;
116};
117
118typedef swq_expr_node *(*swq_field_fetcher)(swq_expr_node *op,
119 void *record_handle);
120typedef swq_expr_node *(*swq_op_evaluator)(
121 swq_expr_node *op, swq_expr_node **sub_field_values,
122 const swq_evaluation_context &sContext);
123typedef swq_field_type (*swq_op_checker)(
124 swq_expr_node *op, int bAllowMismatchTypeOnFieldComparison);
125
126class swq_custom_func_registrar;
127
128class 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
210typedef struct
211{
212 const char *pszName;
213 swq_op eOperation;
214 swq_op_evaluator pfnEvaluator;
215 swq_op_checker pfnChecker;
216} swq_operation;
217
218class 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
225class 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
233typedef struct
234{
235 char *data_source;
236 char *table_name;
237 char *table_alias;
238} swq_table_def;
239
240class 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
253class CPL_UNSTABLE_API swq_parse_context
254{
255 public:
256 swq_parse_context()
257 : nStartToken(0), pszInput(nullptr), pszNext(nullptr),
258 pszLastValid(nullptr), bAcceptCustomFuncs(FALSE), poRoot(nullptr),
259 poCurSelect(nullptr)
260 {
261 }
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*/
278int CPL_UNSTABLE_API swqparse(swq_parse_context *context);
279int CPL_UNSTABLE_API swqlex(swq_expr_node **ppNode, swq_parse_context *context);
280void CPL_UNSTABLE_API swqerror(swq_parse_context *context, const char *msg);
281
282int 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
288CPLErr CPL_UNSTABLE_API
289swq_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
294CPLErr CPL_UNSTABLE_API
295swq_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*/
302int CPL_UNSTABLE_API swq_test_like(const char *input, const char *pattern);
303
304swq_expr_node CPL_UNSTABLE_API *
305SWQGeneralEvaluator(swq_expr_node *, swq_expr_node **,
306 const swq_evaluation_context &sContext);
307swq_field_type CPL_UNSTABLE_API
308SWQGeneralChecker(swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison);
309swq_expr_node CPL_UNSTABLE_API *
310SWQCastEvaluator(swq_expr_node *, swq_expr_node **,
311 const swq_evaluation_context &sContext);
312swq_field_type CPL_UNSTABLE_API
313SWQCastChecker(swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison);
314const char CPL_UNSTABLE_API *SWQFieldTypeToString(swq_field_type field_type);
315
316/****************************************************************************/
317
318#define SWQP_ALLOW_UNDEFINED_COL_FUNCS 0x01
319
320#define SWQM_SUMMARY_RECORD 1
321#define SWQM_RECORDSET 2
322#define SWQM_DISTINCT_LIST 3
323
324typedef 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
337typedef 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
357class CPL_UNSTABLE_API swq_summary
358{
359 public:
360 struct Comparator
361 {
362 bool bSortAsc;
363 swq_field_type eType;
364
365 Comparator() : bSortAsc(true), eType(SWQ_STRING)
366 {
367 }
368
369 bool operator()(const CPLString &, const CPLString &) const;
370 };
371
373 // Cf cf KahanBabushkaNeumaierSum of https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
374 double sum() const
375 {
376 return sum_only_finite_terms ? sum_acc + sum_correction : sum_acc;
377 }
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
400typedef 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
409typedef struct
410{
411 int secondary_table;
412 swq_expr_node *poExpr;
413} swq_join_def;
414
415class 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 {
433 }
434};
435
436class 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 {
457 return static_cast<int>(column_defs.size());
458 }
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 */
514const char CPL_UNSTABLE_API *swq_select_summarize(swq_select *select_info,
515 int dest_column,
516 const char *pszValue,
517 const double *pdfValue);
518
519int CPL_UNSTABLE_API swq_is_reserved_keyword(const char *pszStr);
520
521char CPL_UNSTABLE_API *OGRHStoreGetValue(const char *pszHStore,
522 const char *pszSearchedKey);
523
524#ifdef GDAL_COMPILATION
525void swq_fixup(swq_parse_context *psParseContext);
526swq_expr_node *swq_create_and_or_or(swq_op op, swq_expr_node *left,
527 swq_expr_node *right);
528int 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_ */
Abstract base class for all geometry classes.
Definition ogr_geometry.h:357
Various convenience functions for CPL.
CPLErr
Error category.
Definition cpl_error.h:37
#define CPL_DISALLOW_COPY_ASSIGN(ClassName)
Helper to remove the copy and assignment constructors so that the compiler will not generate the defa...
Definition cpl_port.h:936
long long GIntBig
Large signed integer type (generally 64-bit integer type).
Definition cpl_port.h:205
Various convenience functions for working with strings and string lists.
Core portability services for cross-platform OGR code.
OGRFieldSubType
List of field subtypes.
Definition ogr_core.h:799
OGRwkbGeometryType
List of well known binary geometry types.
Definition ogr_core.h:405