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