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_ */ |