Line data Source code
1 : /******************************************************************************
2 : *
3 : * Component: OGDI Driver Support Library
4 : * Purpose: Generic SQL WHERE Expression Implementation.
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 : *
11 : * Permission to use, copy, modify and distribute this software and
12 : * its documentation for any purpose and without fee is hereby granted,
13 : * provided that the above copyright notice appear in all copies, that
14 : * both the copyright notice and this permission notice appear in
15 : * supporting documentation, and that the name of 3i not be used
16 : * in advertising or publicity pertaining to distribution of the software
17 : * without specific, written prior permission. 3i makes no
18 : * representations about the suitability of this software for any purpose.
19 : * It is provided "as is" without express or implied warranty.
20 : ****************************************************************************/
21 :
22 : #include "cpl_port.h"
23 : #include "ogr_swq.h"
24 :
25 : #include <cassert>
26 : #include <cctype>
27 : #include <cmath>
28 : #include <cstddef>
29 : #include <cstdlib>
30 : #include <cstring>
31 : #include <ctime>
32 :
33 : #include <algorithm>
34 : #include <limits>
35 : #include <queue>
36 : #include <string>
37 :
38 : #include "cpl_error.h"
39 : #include "cpl_multiproc.h"
40 : #include "cpl_time.h"
41 : #include "swq_parser.hpp"
42 :
43 : #define YYSTYPE swq_expr_node *
44 :
45 : /************************************************************************/
46 : /* swqlex() */
47 : /************************************************************************/
48 :
49 112 : void swqerror(swq_parse_context *context, const char *msg)
50 : {
51 224 : CPLString osMsg;
52 112 : osMsg.Printf("SQL Expression Parsing Error: %s. Occurred around :\n", msg);
53 :
54 112 : int n = static_cast<int>(context->pszLastValid - context->pszInput);
55 :
56 2264 : for (int i = std::max(0, n - 40);
57 2264 : i < n + 40 && context->pszInput[i] != '\0'; i++)
58 2152 : osMsg += context->pszInput[i];
59 112 : osMsg += "\n";
60 427 : for (int i = 0; i < std::min(n, 40); i++)
61 315 : osMsg += " ";
62 112 : osMsg += "^";
63 :
64 112 : CPLError(CE_Failure, CPLE_AppDefined, "%s", osMsg.c_str());
65 112 : }
66 :
67 : /************************************************************************/
68 : /* swqlex() */
69 : /* */
70 : /* Read back a token from the input. */
71 : /************************************************************************/
72 :
73 78952 : int swqlex(YYSTYPE *ppNode, swq_parse_context *context)
74 : {
75 78952 : const char *pszInput = context->pszNext;
76 :
77 78952 : *ppNode = nullptr;
78 :
79 : /* -------------------------------------------------------------------- */
80 : /* Do we have a start symbol to return? */
81 : /* -------------------------------------------------------------------- */
82 78952 : if (context->nStartToken != 0)
83 : {
84 8043 : int nRet = context->nStartToken;
85 8043 : context->nStartToken = 0;
86 8043 : return nRet;
87 : }
88 :
89 : /* -------------------------------------------------------------------- */
90 : /* Skip white space. */
91 : /* -------------------------------------------------------------------- */
92 113242 : while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 ||
93 70909 : *pszInput == 13)
94 42333 : pszInput++;
95 :
96 70909 : context->pszLastValid = pszInput;
97 :
98 70909 : if (*pszInput == '\0')
99 : {
100 7932 : context->pszNext = pszInput;
101 7932 : return EOF;
102 : }
103 :
104 : /* -------------------------------------------------------------------- */
105 : /* Handle string constants. */
106 : /* -------------------------------------------------------------------- */
107 62977 : if (*pszInput == '"' || *pszInput == '\'')
108 : {
109 3172 : char chQuote = *pszInput;
110 3172 : bool bFoundEndQuote = false;
111 :
112 3172 : int nRet = *pszInput == '"' ? SWQT_IDENTIFIER : SWQT_STRING;
113 :
114 3172 : pszInput++;
115 :
116 3172 : char *token = static_cast<char *>(CPLMalloc(strlen(pszInput) + 1));
117 3172 : int i_token = 0;
118 :
119 43050 : while (*pszInput != '\0')
120 : {
121 : // Not totally sure we need to preserve this way of escaping for
122 : // strings between double-quotes
123 43049 : if (chQuote == '"' && *pszInput == '\\')
124 : {
125 0 : pszInput++;
126 0 : if (*pszInput == '\0')
127 0 : break;
128 : }
129 43049 : else if (chQuote == '\'' && *pszInput == '\'' &&
130 1717 : pszInput[1] == '\'')
131 3 : pszInput++;
132 43046 : else if (*pszInput == chQuote)
133 : {
134 3171 : pszInput++;
135 3171 : bFoundEndQuote = true;
136 3171 : break;
137 : }
138 :
139 39878 : token[i_token++] = *(pszInput++);
140 : }
141 3172 : token[i_token] = '\0';
142 :
143 3172 : if (!bFoundEndQuote)
144 : {
145 1 : CPLError(CE_Failure, CPLE_AppDefined,
146 : "Did not find end-of-string character");
147 1 : CPLFree(token);
148 1 : return YYerror;
149 : }
150 :
151 3171 : *ppNode = new swq_expr_node(token);
152 3171 : CPLFree(token);
153 :
154 3171 : context->pszNext = pszInput;
155 :
156 3171 : return nRet;
157 : }
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Handle numbers. */
161 : /* -------------------------------------------------------------------- */
162 59805 : else if (*pszInput >= '0' && *pszInput <= '9')
163 : {
164 25252 : CPLString osToken;
165 12626 : const char *pszNext = pszInput + 1;
166 :
167 12626 : osToken += *pszInput;
168 :
169 : // collect non-decimal part of number
170 21577 : while (*pszNext >= '0' && *pszNext <= '9')
171 8951 : osToken += *(pszNext++);
172 :
173 : // collect decimal places.
174 12626 : if (*pszNext == '.')
175 : {
176 473 : osToken += *(pszNext++);
177 2092 : while (*pszNext >= '0' && *pszNext <= '9')
178 1619 : osToken += *(pszNext++);
179 : }
180 :
181 : // collect exponent
182 12626 : if (*pszNext == 'e' || *pszNext == 'E')
183 : {
184 9 : osToken += *(pszNext++);
185 9 : if (*pszNext == '-' || *pszNext == '+')
186 9 : osToken += *(pszNext++);
187 34 : while (*pszNext >= '0' && *pszNext <= '9')
188 25 : osToken += *(pszNext++);
189 : }
190 :
191 12626 : context->pszNext = pszNext;
192 :
193 24770 : if (strstr(osToken, ".") || strstr(osToken, "e") ||
194 12144 : strstr(osToken, "E"))
195 : {
196 482 : *ppNode = new swq_expr_node(CPLAtof(osToken));
197 482 : return SWQT_FLOAT_NUMBER;
198 : }
199 : else
200 : {
201 24315 : if (osToken.size() > 19 ||
202 12171 : (osToken.size() >= 19 && osToken > "9223372036854775807"))
203 : {
204 12 : *ppNode = new swq_expr_node(CPLAtof(osToken));
205 12 : if (osToken == "9223372036854775808")
206 11 : (*ppNode)->string_value = CPLStrdup(osToken);
207 12 : return SWQT_FLOAT_NUMBER;
208 : }
209 :
210 12132 : GIntBig nVal = CPLAtoGIntBig(osToken);
211 12132 : if (CPL_INT64_FITS_ON_INT32(nVal))
212 12035 : *ppNode = new swq_expr_node(static_cast<int>(nVal));
213 : else
214 97 : *ppNode = new swq_expr_node(nVal);
215 12132 : return SWQT_INTEGER_NUMBER;
216 : }
217 : }
218 :
219 : /* -------------------------------------------------------------------- */
220 : /* Handle alpha-numerics. */
221 : /* -------------------------------------------------------------------- */
222 47179 : else if (isalnum(static_cast<unsigned char>(*pszInput)))
223 : {
224 26130 : int nReturn = SWQT_IDENTIFIER;
225 26130 : CPLString osToken;
226 26130 : const char *pszNext = pszInput + 1;
227 :
228 26130 : osToken += *pszInput;
229 :
230 : // collect text characters
231 90185 : while (isalnum(static_cast<unsigned char>(*pszNext)) ||
232 116315 : *pszNext == '_' || static_cast<unsigned char>(*pszNext) > 127)
233 90185 : osToken += *(pszNext++);
234 :
235 26130 : context->pszNext = pszNext;
236 :
237 26130 : if (EQUAL(osToken, "IN"))
238 150 : nReturn = SWQT_IN;
239 25980 : else if (EQUAL(osToken, "LIKE"))
240 53 : nReturn = SWQT_LIKE;
241 25927 : else if (EQUAL(osToken, "ILIKE"))
242 31 : nReturn = SWQT_ILIKE;
243 25896 : else if (EQUAL(osToken, "ESCAPE"))
244 3 : nReturn = SWQT_ESCAPE;
245 25893 : else if (EQUAL(osToken, "EXCEPT"))
246 14 : nReturn = SWQT_EXCEPT;
247 25879 : else if (EQUAL(osToken, "EXCLUDE"))
248 2 : nReturn = SWQT_EXCLUDE;
249 25877 : else if (EQUAL(osToken, "NULL"))
250 303 : nReturn = SWQT_NULL;
251 25574 : else if (EQUAL(osToken, "IS"))
252 219 : nReturn = SWQT_IS;
253 25355 : else if (EQUAL(osToken, "NOT"))
254 265 : nReturn = SWQT_NOT;
255 25090 : else if (EQUAL(osToken, "AND"))
256 2502 : nReturn = SWQT_AND;
257 22588 : else if (EQUAL(osToken, "OR"))
258 2277 : nReturn = SWQT_OR;
259 20311 : else if (EQUAL(osToken, "BETWEEN"))
260 29 : nReturn = SWQT_BETWEEN;
261 20282 : else if (EQUAL(osToken, "SELECT"))
262 2817 : nReturn = SWQT_SELECT;
263 17465 : else if (EQUAL(osToken, "LEFT"))
264 27 : nReturn = SWQT_LEFT;
265 17438 : else if (EQUAL(osToken, "JOIN"))
266 72 : nReturn = SWQT_JOIN;
267 17366 : else if (EQUAL(osToken, "WHERE"))
268 1170 : nReturn = SWQT_WHERE;
269 16196 : else if (EQUAL(osToken, "ON"))
270 72 : nReturn = SWQT_ON;
271 16124 : else if (EQUAL(osToken, "ORDER"))
272 105 : nReturn = SWQT_ORDER;
273 16019 : else if (EQUAL(osToken, "BY"))
274 105 : nReturn = SWQT_BY;
275 15914 : else if (EQUAL(osToken, "FROM"))
276 2806 : nReturn = SWQT_FROM;
277 13108 : else if (EQUAL(osToken, "AS"))
278 158 : nReturn = SWQT_AS;
279 12950 : else if (EQUAL(osToken, "ASC"))
280 27 : nReturn = SWQT_ASC;
281 12923 : else if (EQUAL(osToken, "DESC"))
282 20 : nReturn = SWQT_DESC;
283 12903 : else if (EQUAL(osToken, "DISTINCT"))
284 47 : nReturn = SWQT_DISTINCT;
285 12856 : else if (EQUAL(osToken, "CAST"))
286 90 : nReturn = SWQT_CAST;
287 12766 : else if (EQUAL(osToken, "UNION"))
288 5 : nReturn = SWQT_UNION;
289 12761 : else if (EQUAL(osToken, "ALL"))
290 5 : nReturn = SWQT_ALL;
291 12756 : else if (EQUAL(osToken, "LIMIT"))
292 35 : nReturn = SWQT_LIMIT;
293 12721 : else if (EQUAL(osToken, "OFFSET"))
294 19 : nReturn = SWQT_OFFSET;
295 12702 : else if (EQUAL(osToken, "HIDDEN"))
296 : {
297 21 : *ppNode = new swq_expr_node(osToken);
298 21 : nReturn = SWQT_HIDDEN;
299 : }
300 :
301 : // Unhandled by OGR SQL.
302 12681 : else if (EQUAL(osToken, "OUTER") || EQUAL(osToken, "INNER"))
303 0 : nReturn = SWQT_RESERVED_KEYWORD;
304 :
305 : else
306 : {
307 12681 : *ppNode = new swq_expr_node(osToken);
308 12681 : nReturn = SWQT_IDENTIFIER;
309 : }
310 :
311 26130 : return nReturn;
312 : }
313 :
314 : /* -------------------------------------------------------------------- */
315 : /* Handle special tokens. */
316 : /* -------------------------------------------------------------------- */
317 : else
318 : {
319 21049 : context->pszNext = pszInput + 1;
320 21049 : return *pszInput;
321 : }
322 : }
323 :
324 : /************************************************************************/
325 : /* swq_select_summarize() */
326 : /************************************************************************/
327 :
328 527 : const char *swq_select_summarize(swq_select *select_info, int dest_column,
329 : const char *pszValue, const double *pdfValue)
330 :
331 : {
332 : /* -------------------------------------------------------------------- */
333 : /* Do various checking. */
334 : /* -------------------------------------------------------------------- */
335 527 : if (select_info->query_mode == SWQM_RECORDSET)
336 0 : return "swq_select_summarize() called on non-summary query.";
337 :
338 1054 : if (dest_column < 0 ||
339 527 : dest_column >= static_cast<int>(select_info->column_defs.size()))
340 0 : return "dest_column out of range in swq_select_summarize().";
341 :
342 527 : const swq_col_def *def = &select_info->column_defs[dest_column];
343 527 : if (def->col_func == SWQCF_NONE && !def->distinct_flag)
344 0 : return nullptr;
345 :
346 527 : if (select_info->query_mode == SWQM_DISTINCT_LIST &&
347 290 : select_info->order_specs > 0)
348 : {
349 275 : if (select_info->order_specs > 1)
350 1 : return "Can't ORDER BY a DISTINCT list by more than one key.";
351 :
352 548 : if (select_info->order_defs[0].field_index !=
353 274 : select_info->column_defs[0].field_index)
354 1 : return "Only selected DISTINCT field can be used for ORDER BY.";
355 : }
356 :
357 : /* -------------------------------------------------------------------- */
358 : /* Create the summary information if this is the first row */
359 : /* being processed. */
360 : /* -------------------------------------------------------------------- */
361 525 : if (select_info->column_summary.empty())
362 : {
363 51 : select_info->column_summary.resize(select_info->column_defs.size());
364 138 : for (std::size_t i = 0; i < select_info->column_defs.size(); i++)
365 : {
366 87 : if (def->distinct_flag)
367 : {
368 26 : swq_summary::Comparator oComparator;
369 26 : if (select_info->order_specs > 0)
370 : {
371 18 : CPLAssert(select_info->order_specs == 1);
372 18 : CPLAssert(select_info->column_defs.size() == 1);
373 18 : oComparator.bSortAsc =
374 18 : CPL_TO_BOOL(select_info->order_defs[0].ascending_flag);
375 : }
376 45 : if (select_info->column_defs[i].field_type == SWQ_INTEGER ||
377 19 : -select_info->column_defs[i].field_type == SWQ_INTEGER64)
378 : {
379 7 : oComparator.eType = SWQ_INTEGER64;
380 : }
381 19 : else if (select_info->column_defs[i].field_type == SWQ_FLOAT)
382 : {
383 4 : oComparator.eType = SWQ_FLOAT;
384 : }
385 : else
386 : {
387 15 : oComparator.eType = SWQ_STRING;
388 : }
389 26 : select_info->column_summary[i].oSetDistinctValues =
390 52 : std::set<CPLString, swq_summary::Comparator>(oComparator);
391 : }
392 87 : select_info->column_summary[i].min =
393 87 : std::numeric_limits<double>::infinity();
394 174 : select_info->column_summary[i].max =
395 87 : -std::numeric_limits<double>::infinity();
396 87 : select_info->column_summary[i].osMin = "9999/99/99 99:99:99";
397 87 : select_info->column_summary[i].osMax = "0000/00/00 00:00:00";
398 : }
399 51 : assert(!select_info->column_summary.empty());
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* If distinct processing is on, process that now. */
404 : /* -------------------------------------------------------------------- */
405 525 : swq_summary &summary = select_info->column_summary[dest_column];
406 :
407 525 : if (def->distinct_flag)
408 : {
409 310 : if (pszValue == nullptr)
410 19 : pszValue = SZ_OGR_NULL;
411 : try
412 : {
413 310 : if (!cpl::contains(summary.oSetDistinctValues, pszValue))
414 : {
415 115 : summary.oSetDistinctValues.insert(pszValue);
416 115 : if (select_info->order_specs == 0)
417 : {
418 : // If not sorted, keep values in their original order
419 25 : summary.oVectorDistinctValues.emplace_back(pszValue);
420 : }
421 115 : summary.count++;
422 : }
423 : }
424 0 : catch (std::bad_alloc &)
425 : {
426 0 : return "Out of memory";
427 : }
428 :
429 310 : return nullptr;
430 : }
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Process various options. */
434 : /* -------------------------------------------------------------------- */
435 :
436 215 : switch (def->col_func)
437 : {
438 47 : case SWQCF_MIN:
439 47 : if (pdfValue)
440 : {
441 26 : if (*pdfValue < summary.min)
442 9 : summary.min = *pdfValue;
443 26 : summary.count++;
444 : }
445 21 : else if (pszValue && pszValue[0] != '\0')
446 : {
447 17 : if (summary.count == 0 || strcmp(pszValue, summary.osMin) < 0)
448 : {
449 13 : summary.osMin = pszValue;
450 : }
451 17 : summary.count++;
452 : }
453 47 : break;
454 46 : case SWQCF_MAX:
455 46 : if (pdfValue)
456 : {
457 25 : if (*pdfValue > summary.max)
458 15 : summary.max = *pdfValue;
459 25 : summary.count++;
460 : }
461 21 : else if (pszValue && pszValue[0] != '\0')
462 : {
463 17 : if (summary.count == 0 || strcmp(pszValue, summary.osMax) > 0)
464 : {
465 9 : summary.osMax = pszValue;
466 : }
467 17 : summary.count++;
468 : }
469 46 : break;
470 52 : case SWQCF_AVG:
471 : case SWQCF_SUM:
472 52 : if (pdfValue)
473 : {
474 39 : summary.count++;
475 :
476 : // Cf KahanBabushkaNeumaierSum of
477 : // https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
478 : // We set a number of temporary variables as volatile, to
479 : // prevent potential undesired compiler optimizations.
480 :
481 39 : const double dfNewVal = *pdfValue;
482 39 : const volatile double new_sum_acc = summary.sum_acc + dfNewVal;
483 39 : if (summary.sum_only_finite_terms && std::isfinite(dfNewVal))
484 : {
485 33 : if (std::fabs(summary.sum_acc) >= std::fabs(dfNewVal))
486 : {
487 : const volatile double diff =
488 18 : (summary.sum_acc - new_sum_acc);
489 18 : summary.sum_correction += (diff + dfNewVal);
490 : }
491 : else
492 : {
493 15 : const volatile double diff = (dfNewVal - new_sum_acc);
494 15 : summary.sum_correction += (diff + summary.sum_acc);
495 : }
496 : }
497 : else
498 : {
499 6 : summary.sum_only_finite_terms = false;
500 : }
501 39 : summary.sum_acc = new_sum_acc;
502 : }
503 13 : else if (pszValue && pszValue[0] != '\0')
504 : {
505 2 : if (def->field_type == SWQ_DATE ||
506 2 : def->field_type == SWQ_TIME ||
507 2 : def->field_type == SWQ_TIMESTAMP)
508 : {
509 : OGRField sField;
510 2 : if (OGRParseDate(pszValue, &sField, 0))
511 : {
512 : struct tm brokendowntime;
513 2 : brokendowntime.tm_year = sField.Date.Year - 1900;
514 2 : brokendowntime.tm_mon = sField.Date.Month - 1;
515 2 : brokendowntime.tm_mday = sField.Date.Day;
516 2 : brokendowntime.tm_hour = sField.Date.Hour;
517 2 : brokendowntime.tm_min = sField.Date.Minute;
518 2 : brokendowntime.tm_sec =
519 2 : static_cast<int>(sField.Date.Second);
520 2 : summary.count++;
521 2 : summary.sum_acc += CPLYMDHMSToUnixTime(&brokendowntime);
522 2 : summary.sum_acc +=
523 2 : fmod(static_cast<double>(sField.Date.Second), 1.0);
524 2 : }
525 : }
526 : else
527 : {
528 : return "swq_select_summarize() - AVG()/SUM() called on "
529 0 : "unexpected field type";
530 : }
531 : }
532 52 : break;
533 :
534 50 : case SWQCF_COUNT:
535 50 : if (pdfValue || pszValue)
536 50 : summary.count++;
537 50 : break;
538 :
539 20 : case SWQCF_STDDEV_POP:
540 : case SWQCF_STDDEV_SAMP:
541 : {
542 18 : const auto UpdateVariance = [&summary](double dfValue)
543 : {
544 : // Welford's online algorithm for variance:
545 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
546 18 : summary.count++;
547 18 : const double dfDelta = dfValue - summary.mean_for_variance;
548 18 : summary.mean_for_variance += dfDelta / summary.count;
549 18 : const double dfDelta2 = dfValue - summary.mean_for_variance;
550 18 : summary.sq_dist_from_mean_acc += dfDelta * dfDelta2;
551 38 : };
552 :
553 20 : if (pdfValue)
554 : {
555 14 : UpdateVariance(*pdfValue);
556 : }
557 6 : else if (pszValue && pszValue[0] != '\0')
558 : {
559 4 : if (def->field_type == SWQ_DATE ||
560 4 : def->field_type == SWQ_TIME ||
561 4 : def->field_type == SWQ_TIMESTAMP)
562 : {
563 : OGRField sField;
564 4 : if (OGRParseDate(pszValue, &sField, 0))
565 : {
566 : struct tm brokendowntime;
567 4 : brokendowntime.tm_year = sField.Date.Year - 1900;
568 4 : brokendowntime.tm_mon = sField.Date.Month - 1;
569 4 : brokendowntime.tm_mday = sField.Date.Day;
570 4 : brokendowntime.tm_hour = sField.Date.Hour;
571 4 : brokendowntime.tm_min = sField.Date.Minute;
572 4 : brokendowntime.tm_sec =
573 4 : static_cast<int>(sField.Date.Second);
574 :
575 4 : UpdateVariance(static_cast<double>(
576 4 : CPLYMDHMSToUnixTime(&brokendowntime)));
577 4 : }
578 : }
579 : else
580 : {
581 : return "swq_select_summarize() - STDDEV() called on "
582 0 : "unexpected field type";
583 : }
584 : }
585 :
586 20 : break;
587 : }
588 :
589 0 : case SWQCF_NONE:
590 0 : break;
591 :
592 0 : case SWQCF_CUSTOM:
593 0 : return "swq_select_summarize() called on custom field function.";
594 : }
595 :
596 215 : return nullptr;
597 : }
598 :
599 : /************************************************************************/
600 : /* sort comparison functions. */
601 : /************************************************************************/
602 :
603 1333 : static bool Compare(swq_field_type eType, const CPLString &a,
604 : const CPLString &b)
605 : {
606 1333 : if (a == SZ_OGR_NULL)
607 52 : return b != SZ_OGR_NULL;
608 1281 : else if (b == SZ_OGR_NULL)
609 24 : return false;
610 : else
611 : {
612 1257 : if (eType == SWQ_INTEGER64)
613 160 : return CPLAtoGIntBig(a) < CPLAtoGIntBig(b);
614 1097 : else if (eType == SWQ_FLOAT)
615 802 : return CPLAtof(a) < CPLAtof(b);
616 295 : else if (eType == SWQ_STRING)
617 295 : return a < b;
618 : else
619 : {
620 0 : CPLAssert(false);
621 : return false;
622 : }
623 : }
624 : }
625 :
626 : #ifndef DOXYGEN_SKIP
627 1333 : bool swq_summary::Comparator::operator()(const CPLString &a,
628 : const CPLString &b) const
629 : {
630 1333 : if (bSortAsc)
631 : {
632 992 : return Compare(eType, a, b);
633 : }
634 : else
635 : {
636 341 : return Compare(eType, b, a);
637 : }
638 : }
639 : #endif
640 :
641 : /************************************************************************/
642 : /* swq_identify_field() */
643 : /************************************************************************/
644 : int swq_identify_field_internal(const char *table_name, const char *field_token,
645 : swq_field_list *field_list,
646 : swq_field_type *this_type, int *table_id,
647 : int bOneMoreTimeOK);
648 :
649 23293 : int swq_identify_field(const char *table_name, const char *field_token,
650 : swq_field_list *field_list, swq_field_type *this_type,
651 : int *table_id)
652 :
653 : {
654 23293 : return swq_identify_field_internal(table_name, field_token, field_list,
655 23293 : this_type, table_id, TRUE);
656 : }
657 :
658 23298 : int swq_identify_field_internal(const char *table_name, const char *field_token,
659 : swq_field_list *field_list,
660 : swq_field_type *this_type, int *table_id,
661 : int bOneMoreTimeOK)
662 :
663 : {
664 23298 : if (table_name == nullptr)
665 8292 : table_name = "";
666 :
667 : int tables_enabled;
668 :
669 23298 : if (field_list->table_count > 0 && field_list->table_ids != nullptr)
670 15412 : tables_enabled = TRUE;
671 : else
672 7886 : tables_enabled = FALSE;
673 :
674 : /* -------------------------------------------------------------------- */
675 : /* Search for matching field. */
676 : /* -------------------------------------------------------------------- */
677 25326 : for (int pass = 0; pass < 2; ++pass)
678 : {
679 202856 : for (int i = 0; i < field_list->count; i++)
680 : {
681 200828 : if ((pass == 0 && strcmp(field_list->names[i], field_token) != 0) ||
682 7594 : (pass == 1 && !EQUAL(field_list->names[i], field_token)))
683 : {
684 177769 : continue;
685 : }
686 :
687 23059 : int t_id = 0;
688 :
689 : // Do the table specifications match?/
690 23059 : if (tables_enabled)
691 : {
692 15174 : t_id = field_list->table_ids[i];
693 15174 : if (table_name[0] != '\0' &&
694 13476 : !EQUAL(table_name,
695 : field_list->table_defs[t_id].table_alias))
696 83 : continue;
697 :
698 : // if( t_id != 0 && table_name[0] == '\0' )
699 : // continue;
700 : }
701 7885 : else if (table_name[0] != '\0')
702 0 : break;
703 :
704 : // We have a match, return various information.
705 22976 : if (this_type != nullptr)
706 : {
707 22976 : if (field_list->types != nullptr)
708 22976 : *this_type = field_list->types[i];
709 : else
710 0 : *this_type = SWQ_OTHER;
711 : }
712 :
713 22976 : if (table_id != nullptr)
714 22976 : *table_id = t_id;
715 :
716 22976 : if (field_list->ids == nullptr)
717 7885 : return i;
718 : else
719 15091 : return field_list->ids[i];
720 : }
721 : }
722 :
723 : /* -------------------------------------------------------------------- */
724 : /* When there is no ambiguity, try to accept quoting errors... */
725 : /* -------------------------------------------------------------------- */
726 644 : if (bOneMoreTimeOK &&
727 322 : !CPLTestBool(CPLGetConfigOption("OGR_SQL_STRICT", "FALSE")))
728 : {
729 322 : if (table_name[0])
730 : {
731 : CPLString osAggregatedName(
732 4 : CPLSPrintf("%s.%s", table_name, field_token));
733 :
734 : // Check there's no table called table_name, or a field called with
735 : // the aggregated name.
736 4 : int i = 0; // Used after for.
737 19 : for (; i < field_list->count; i++)
738 : {
739 18 : if (tables_enabled)
740 : {
741 18 : int t_id = field_list->table_ids[i];
742 18 : if (EQUAL(table_name,
743 : field_list->table_defs[t_id].table_alias))
744 3 : break;
745 : }
746 : }
747 4 : if (i == field_list->count)
748 : {
749 1 : int ret = swq_identify_field_internal(nullptr, osAggregatedName,
750 : field_list, this_type,
751 : table_id, FALSE);
752 1 : if (ret >= 0)
753 : {
754 1 : CPLError(CE_Warning, CPLE_AppDefined,
755 : "Passed field name %s.%s should have been "
756 : "surrounded by double quotes. "
757 : "Accepted since there is no ambiguity...",
758 : table_name, field_token);
759 : }
760 1 : return ret;
761 : }
762 : }
763 : else
764 : {
765 : // If the fieldname is a.b (and there's no . in b), then
766 : // it might be an error in providing it as being quoted where it
767 : // should not have been quoted.
768 318 : const char *pszDot = strchr(field_token, '.');
769 318 : if (pszDot && strchr(pszDot + 1, '.') == nullptr)
770 : {
771 8 : CPLString osTableName(field_token);
772 4 : osTableName.resize(pszDot - field_token);
773 4 : CPLString osFieldName(pszDot + 1);
774 :
775 4 : int ret = swq_identify_field_internal(osTableName, osFieldName,
776 : field_list, this_type,
777 : table_id, FALSE);
778 4 : if (ret >= 0)
779 : {
780 4 : CPLError(CE_Warning, CPLE_AppDefined,
781 : "Passed field name %s should NOT have been "
782 : "surrounded by double quotes. "
783 : "Accepted since there is no ambiguity...",
784 : field_token);
785 : }
786 4 : return ret;
787 : }
788 : }
789 : }
790 :
791 : /* -------------------------------------------------------------------- */
792 : /* No match, return failure. */
793 : /* -------------------------------------------------------------------- */
794 317 : if (this_type != nullptr)
795 317 : *this_type = SWQ_OTHER;
796 :
797 317 : if (table_id != nullptr)
798 317 : *table_id = 0;
799 :
800 317 : return -1;
801 : }
802 :
803 : /************************************************************************/
804 : /* swq_expr_compile() */
805 : /************************************************************************/
806 :
807 5135 : CPLErr swq_expr_compile(const char *where_clause, int field_count,
808 : char **field_names, swq_field_type *field_types,
809 : int bCheck,
810 : swq_custom_func_registrar *poCustomFuncRegistrar,
811 : swq_expr_node **expr_out)
812 :
813 : {
814 : swq_field_list field_list;
815 :
816 5135 : field_list.count = field_count;
817 5135 : field_list.names = field_names;
818 5135 : field_list.types = field_types;
819 5135 : field_list.table_ids = nullptr;
820 5135 : field_list.ids = nullptr;
821 :
822 5135 : field_list.table_count = 0;
823 5135 : field_list.table_defs = nullptr;
824 :
825 5135 : return swq_expr_compile2(where_clause, &field_list, bCheck,
826 10270 : poCustomFuncRegistrar, expr_out);
827 : }
828 :
829 : /************************************************************************/
830 : /* swq_fixup_expression() */
831 : /************************************************************************/
832 :
833 10958 : static void swq_fixup_expression(swq_expr_node *node)
834 : {
835 21916 : std::queue<swq_expr_node *> nodes;
836 10958 : nodes.push(node);
837 44944 : while (!nodes.empty())
838 : {
839 33986 : node = nodes.front();
840 33986 : nodes.pop();
841 33986 : if (node->eNodeType == SNT_OPERATION)
842 : {
843 11829 : const swq_op eOp = node->nOperation;
844 11829 : if ((eOp == SWQ_OR || eOp == SWQ_AND) && node->nSubExprCount > 2)
845 : {
846 320 : std::vector<swq_expr_node *> exprs;
847 4815 : for (int i = 0; i < node->nSubExprCount; i++)
848 : {
849 4655 : swq_fixup_expression(node->papoSubExpr[i]);
850 4655 : exprs.push_back(node->papoSubExpr[i]);
851 : }
852 160 : node->nSubExprCount = 0;
853 160 : CPLFree(node->papoSubExpr);
854 160 : node->papoSubExpr = nullptr;
855 :
856 374 : while (exprs.size() > 2)
857 : {
858 428 : std::vector<swq_expr_node *> new_exprs;
859 4706 : for (size_t i = 0; i < exprs.size(); i++)
860 : {
861 4492 : if (i + 1 < exprs.size())
862 : {
863 4335 : auto cur_expr = new swq_expr_node(eOp);
864 4335 : cur_expr->field_type = SWQ_BOOLEAN;
865 4335 : cur_expr->PushSubExpression(exprs[i]);
866 4335 : cur_expr->PushSubExpression(exprs[i + 1]);
867 4335 : i++;
868 4335 : new_exprs.push_back(cur_expr);
869 : }
870 : else
871 : {
872 157 : new_exprs.push_back(exprs[i]);
873 : }
874 : }
875 214 : exprs = std::move(new_exprs);
876 : }
877 160 : CPLAssert(exprs.size() == 2);
878 160 : node->PushSubExpression(exprs[0]);
879 320 : node->PushSubExpression(exprs[1]);
880 : }
881 : else
882 : {
883 34697 : for (int i = 0; i < node->nSubExprCount; i++)
884 : {
885 23028 : nodes.push(node->papoSubExpr[i]);
886 : }
887 : }
888 : }
889 : }
890 10958 : }
891 :
892 : /************************************************************************/
893 : /* swq_fixup_expression() */
894 : /************************************************************************/
895 :
896 7926 : void swq_fixup(swq_parse_context *psParseContext)
897 : {
898 7926 : if (psParseContext->poRoot)
899 : {
900 5133 : swq_fixup_expression(psParseContext->poRoot);
901 : }
902 7926 : auto psSelect = psParseContext->poCurSelect;
903 10724 : while (psSelect)
904 : {
905 2798 : if (psSelect->where_expr)
906 : {
907 1170 : swq_fixup_expression(psSelect->where_expr);
908 : }
909 2798 : psSelect = psSelect->poOtherSelect;
910 : }
911 7926 : }
912 :
913 : /************************************************************************/
914 : /* swq_create_and_or_or() */
915 : /************************************************************************/
916 :
917 4750 : swq_expr_node *swq_create_and_or_or(swq_op op, swq_expr_node *left,
918 : swq_expr_node *right)
919 : {
920 4750 : auto poNode = new swq_expr_node(op);
921 4750 : poNode->field_type = SWQ_BOOLEAN;
922 :
923 4750 : if (left->eNodeType == SNT_OPERATION && left->nOperation == op)
924 : {
925 : // Temporary non-binary formulation
926 4320 : if (right->eNodeType == SNT_OPERATION && right->nOperation == op)
927 : {
928 7 : poNode->nSubExprCount = left->nSubExprCount + right->nSubExprCount;
929 7 : poNode->papoSubExpr = static_cast<swq_expr_node **>(
930 14 : CPLRealloc(left->papoSubExpr,
931 7 : sizeof(swq_expr_node *) * poNode->nSubExprCount));
932 7 : memcpy(poNode->papoSubExpr + left->nSubExprCount,
933 7 : right->papoSubExpr,
934 7 : right->nSubExprCount * sizeof(swq_expr_node *));
935 :
936 7 : right->nSubExprCount = 0;
937 7 : CPLFree(right->papoSubExpr);
938 7 : right->papoSubExpr = nullptr;
939 7 : delete right;
940 : }
941 : else
942 : {
943 4313 : poNode->nSubExprCount = left->nSubExprCount;
944 4313 : poNode->papoSubExpr = left->papoSubExpr;
945 4313 : poNode->PushSubExpression(right);
946 : }
947 :
948 4320 : left->nSubExprCount = 0;
949 4320 : left->papoSubExpr = nullptr;
950 4320 : delete left;
951 : }
952 430 : else if (right->eNodeType == SNT_OPERATION && right->nOperation == op)
953 : {
954 : // Temporary non-binary formulation
955 8 : poNode->nSubExprCount = right->nSubExprCount;
956 8 : poNode->papoSubExpr = right->papoSubExpr;
957 8 : poNode->PushSubExpression(left);
958 :
959 8 : right->nSubExprCount = 0;
960 8 : right->papoSubExpr = nullptr;
961 8 : delete right;
962 : }
963 : else
964 : {
965 422 : poNode->PushSubExpression(left);
966 422 : poNode->PushSubExpression(right);
967 : }
968 :
969 4750 : return poNode;
970 : }
971 :
972 : /************************************************************************/
973 : /* swq_expr_compile2() */
974 : /************************************************************************/
975 :
976 5135 : CPLErr swq_expr_compile2(const char *where_clause, swq_field_list *field_list,
977 : int bCheck,
978 : swq_custom_func_registrar *poCustomFuncRegistrar,
979 : swq_expr_node **expr_out)
980 :
981 : {
982 5135 : swq_parse_context context;
983 :
984 5135 : context.pszInput = where_clause;
985 5135 : context.pszNext = where_clause;
986 5135 : context.pszLastValid = where_clause;
987 5135 : context.nStartToken = SWQT_VALUE_START;
988 5135 : context.bAcceptCustomFuncs = poCustomFuncRegistrar != nullptr;
989 :
990 10266 : if (swqparse(&context) == 0 && bCheck &&
991 5131 : context.poRoot->Check(field_list, FALSE, FALSE,
992 : poCustomFuncRegistrar) != SWQ_ERROR)
993 : {
994 5101 : *expr_out = context.poRoot;
995 :
996 5101 : return CE_None;
997 : }
998 : else
999 : {
1000 34 : delete context.poRoot;
1001 34 : *expr_out = nullptr;
1002 34 : return CE_Failure;
1003 : }
1004 : }
1005 :
1006 : /************************************************************************/
1007 : /* swq_is_reserved_keyword() */
1008 : /************************************************************************/
1009 :
1010 : static const char *const apszSQLReservedKeywords[] = {
1011 : "OR", "AND", "NOT", "LIKE", "IS", "NULL", "IN", "BETWEEN",
1012 : "CAST", "DISTINCT", "ESCAPE", "SELECT", "LEFT", "JOIN", "WHERE", "ON",
1013 : "ORDER", "BY", "FROM", "AS", "ASC", "DESC", "UNION", "ALL"};
1014 :
1015 1400 : int swq_is_reserved_keyword(const char *pszStr)
1016 : {
1017 34946 : for (const auto &pszKeyword : apszSQLReservedKeywords)
1018 : {
1019 33555 : if (EQUAL(pszStr, pszKeyword))
1020 9 : return TRUE;
1021 : }
1022 1391 : return FALSE;
1023 : }
1024 :
1025 : /************************************************************************/
1026 : /* SWQFieldTypeToString() */
1027 : /************************************************************************/
1028 :
1029 2 : const char *SWQFieldTypeToString(swq_field_type field_type)
1030 : {
1031 2 : switch (field_type)
1032 : {
1033 1 : case SWQ_INTEGER:
1034 1 : return "integer";
1035 0 : case SWQ_INTEGER64:
1036 0 : return "bigint";
1037 0 : case SWQ_FLOAT:
1038 0 : return "float";
1039 0 : case SWQ_STRING:
1040 0 : return "string";
1041 0 : case SWQ_BOOLEAN:
1042 0 : return "boolean";
1043 0 : case SWQ_DATE:
1044 0 : return "date";
1045 0 : case SWQ_TIME:
1046 0 : return "time";
1047 0 : case SWQ_TIMESTAMP:
1048 0 : return "timestamp";
1049 1 : case SWQ_GEOMETRY:
1050 1 : return "geometry";
1051 0 : case SWQ_NULL:
1052 0 : return "null";
1053 0 : default:
1054 0 : return "unknown";
1055 : }
1056 : }
|