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