Line data Source code
1 : /******************************************************************************
2 : *
3 : * Component: OGR SQL Engine
4 : * Purpose: Implementation of the swq_expr_node class used to represent a
5 : * node in an SQL expression.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
10 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #ifndef DOXYGEN_SKIP
16 :
17 : #include "cpl_port.h"
18 : #include "ogr_swq.h"
19 :
20 : #include <algorithm>
21 : #include <cctype>
22 : #include <cinttypes>
23 : #include <cstdio>
24 : #include <cstring>
25 : #include <string>
26 : #include <vector>
27 :
28 : #include "cpl_conv.h"
29 : #include "cpl_error.h"
30 : #include "cpl_multiproc.h"
31 : #include "cpl_string.h"
32 : #include "ogr_geometry.h"
33 :
34 : /************************************************************************/
35 : /* swq_expr_node() */
36 : /************************************************************************/
37 :
38 : swq_expr_node::swq_expr_node() = default;
39 :
40 : /************************************************************************/
41 : /* swq_expr_node(int) */
42 : /************************************************************************/
43 :
44 111765 : swq_expr_node::swq_expr_node(int nValueIn) : int_value(nValueIn)
45 : {
46 111765 : }
47 :
48 : /************************************************************************/
49 : /* swq_expr_node(GIntBig) */
50 : /************************************************************************/
51 :
52 4910 : swq_expr_node::swq_expr_node(GIntBig nValueIn)
53 4910 : : field_type(SWQ_INTEGER64), int_value(nValueIn)
54 : {
55 4910 : }
56 :
57 : /************************************************************************/
58 : /* swq_expr_node(double) */
59 : /************************************************************************/
60 :
61 6687 : swq_expr_node::swq_expr_node(double dfValueIn)
62 6687 : : field_type(SWQ_FLOAT), float_value(dfValueIn)
63 : {
64 6687 : }
65 :
66 : /************************************************************************/
67 : /* swq_expr_node(const char*) */
68 : /************************************************************************/
69 :
70 29923 : swq_expr_node::swq_expr_node(const char *pszValueIn)
71 29923 : : field_type(SWQ_STRING), is_null(pszValueIn == nullptr),
72 29923 : string_value(CPLStrdup(pszValueIn ? pszValueIn : ""))
73 : {
74 29923 : }
75 :
76 : /************************************************************************/
77 : /* swq_expr_node(OGRGeometry *) */
78 : /************************************************************************/
79 :
80 35 : swq_expr_node::swq_expr_node(OGRGeometry *poGeomIn)
81 35 : : field_type(SWQ_GEOMETRY), is_null(poGeomIn == nullptr),
82 35 : geometry_value(poGeomIn ? poGeomIn->clone() : nullptr)
83 : {
84 35 : }
85 :
86 : /************************************************************************/
87 : /* swq_expr_node(swq_op) */
88 : /************************************************************************/
89 :
90 21493 : swq_expr_node::swq_expr_node(swq_op eOp)
91 21493 : : eNodeType(SNT_OPERATION), nOperation(eOp)
92 : {
93 21493 : }
94 :
95 : /************************************************************************/
96 : /* ~swq_expr_node() */
97 : /************************************************************************/
98 :
99 357802 : swq_expr_node::~swq_expr_node()
100 :
101 : {
102 178901 : reset();
103 178901 : }
104 :
105 : /************************************************************************/
106 : /* reset() */
107 : /************************************************************************/
108 :
109 181569 : void swq_expr_node::reset()
110 : {
111 181569 : CPLFree(table_name);
112 181569 : table_name = nullptr;
113 181569 : CPLFree(string_value);
114 181569 : string_value = nullptr;
115 :
116 214600 : for (int i = 0; i < nSubExprCount; i++)
117 33031 : delete papoSubExpr[i];
118 181569 : CPLFree(papoSubExpr);
119 181569 : nSubExprCount = 0;
120 181569 : papoSubExpr = nullptr;
121 181569 : delete geometry_value;
122 181569 : geometry_value = nullptr;
123 181569 : }
124 :
125 : /************************************************************************/
126 : /* operator==() */
127 : /************************************************************************/
128 :
129 1984 : bool swq_expr_node::operator==(const swq_expr_node &other) const
130 : {
131 1984 : if (eNodeType != other.eNodeType || field_type != other.field_type ||
132 1168 : nOperation != other.nOperation || field_index != other.field_index ||
133 1140 : table_index != other.table_index ||
134 1128 : nSubExprCount != other.nSubExprCount || is_null != other.is_null ||
135 1104 : int_value != other.int_value || float_value != other.float_value ||
136 1080 : bHidden != other.bHidden)
137 : {
138 904 : return false;
139 : }
140 1168 : for (int i = 0; i < nSubExprCount; ++i)
141 : {
142 92 : if (!(*(papoSubExpr[i]) == *(other.papoSubExpr[i])))
143 : {
144 4 : return false;
145 : }
146 : }
147 1076 : if (table_name && !other.table_name)
148 : {
149 4 : return false;
150 : }
151 1072 : if (!table_name && other.table_name)
152 : {
153 4 : return false;
154 : }
155 1068 : if (table_name && other.table_name &&
156 92 : strcmp(table_name, other.table_name) != 0)
157 : {
158 4 : return false;
159 : }
160 1064 : if (string_value && !other.string_value)
161 : {
162 0 : return false;
163 : }
164 1064 : if (!string_value && other.string_value)
165 : {
166 0 : return false;
167 : }
168 1064 : if (string_value && other.string_value &&
169 136 : strcmp(string_value, other.string_value) != 0)
170 : {
171 4 : return false;
172 : }
173 1060 : if (geometry_value && !other.geometry_value)
174 : {
175 0 : return false;
176 : }
177 1060 : if (!geometry_value && other.geometry_value)
178 : {
179 0 : return false;
180 : }
181 1152 : if (geometry_value && other.geometry_value &&
182 92 : !geometry_value->Equals(other.geometry_value))
183 : {
184 4 : return false;
185 : }
186 1056 : return true;
187 : }
188 :
189 : /************************************************************************/
190 : /* swq_expr_node(const swq_expr_node& other) */
191 : /************************************************************************/
192 :
193 1730 : swq_expr_node::swq_expr_node(const swq_expr_node &other)
194 : {
195 1730 : *this = other;
196 1730 : }
197 :
198 : /************************************************************************/
199 : /* operator= (const swq_expr_node& other) */
200 : /************************************************************************/
201 :
202 2192 : swq_expr_node &swq_expr_node::operator=(const swq_expr_node &other)
203 : {
204 2192 : if (this != &other)
205 : {
206 2192 : reset();
207 2192 : eNodeType = other.eNodeType;
208 2192 : field_type = other.field_type;
209 2192 : nOperation = other.nOperation;
210 2192 : field_index = other.field_index;
211 2192 : table_index = other.table_index;
212 2192 : if (other.table_name)
213 172 : table_name = CPLStrdup(other.table_name);
214 2401 : for (int i = 0; i < other.nSubExprCount; ++i)
215 209 : PushSubExpression(new swq_expr_node(*(other.papoSubExpr[i])));
216 2192 : is_null = other.is_null;
217 2192 : int_value = other.int_value;
218 2192 : float_value = other.float_value;
219 2192 : if (other.geometry_value)
220 174 : geometry_value = other.geometry_value->clone();
221 2192 : if (other.string_value)
222 326 : string_value = CPLStrdup(other.string_value);
223 2192 : bHidden = other.bHidden;
224 : }
225 2192 : return *this;
226 : }
227 :
228 : /************************************************************************/
229 : /* swq_expr_node(swq_expr_node&& other) */
230 : /************************************************************************/
231 :
232 0 : swq_expr_node::swq_expr_node(swq_expr_node &&other)
233 : {
234 0 : *this = std::move(other);
235 0 : }
236 :
237 : /************************************************************************/
238 : /* operator= (swq_expr_node&& other) */
239 : /************************************************************************/
240 :
241 476 : swq_expr_node &swq_expr_node::operator=(swq_expr_node &&other)
242 : {
243 476 : if (this != &other)
244 : {
245 476 : reset();
246 476 : eNodeType = other.eNodeType;
247 476 : field_type = other.field_type;
248 476 : nOperation = other.nOperation;
249 476 : field_index = other.field_index;
250 476 : table_index = other.table_index;
251 476 : std::swap(table_name, other.table_name);
252 476 : std::swap(nSubExprCount, other.nSubExprCount);
253 476 : std::swap(papoSubExpr, other.papoSubExpr);
254 476 : is_null = other.is_null;
255 476 : int_value = other.int_value;
256 476 : float_value = other.float_value;
257 476 : std::swap(geometry_value, other.geometry_value);
258 476 : std::swap(string_value, other.string_value);
259 476 : bHidden = other.bHidden;
260 : }
261 476 : return *this;
262 : }
263 :
264 : /************************************************************************/
265 : /* MarkAsTimestamp() */
266 : /************************************************************************/
267 :
268 312 : void swq_expr_node::MarkAsTimestamp()
269 :
270 : {
271 312 : CPLAssert(eNodeType == SNT_CONSTANT);
272 312 : CPLAssert(field_type == SWQ_STRING);
273 312 : field_type = SWQ_TIMESTAMP;
274 312 : }
275 :
276 : /************************************************************************/
277 : /* PushSubExpression() */
278 : /************************************************************************/
279 :
280 38284 : void swq_expr_node::PushSubExpression(swq_expr_node *child)
281 :
282 : {
283 38284 : nSubExprCount++;
284 38284 : papoSubExpr = static_cast<swq_expr_node **>(
285 38284 : CPLRealloc(papoSubExpr, sizeof(void *) * nSubExprCount));
286 :
287 38284 : papoSubExpr[nSubExprCount - 1] = child;
288 38284 : }
289 :
290 : /************************************************************************/
291 : /* ReverseSubExpressions() */
292 : /************************************************************************/
293 :
294 583 : void swq_expr_node::ReverseSubExpressions()
295 :
296 : {
297 995 : for (int i = 0; i < nSubExprCount / 2; i++)
298 : {
299 412 : std::swap(papoSubExpr[i], papoSubExpr[nSubExprCount - i - 1]);
300 : }
301 583 : }
302 :
303 : /************************************************************************/
304 : /* Check() */
305 : /* */
306 : /* Check argument types, etc. */
307 : /************************************************************************/
308 :
309 38793 : swq_field_type swq_expr_node::Check(
310 : swq_field_list *poFieldList, int bAllowFieldsInSecondaryTables,
311 : int bAllowMismatchTypeOnFieldComparison,
312 : swq_custom_func_registrar *poCustomFuncRegistrar, int nDepth)
313 :
314 : {
315 38793 : if (nDepth == 32)
316 : {
317 0 : CPLError(CE_Failure, CPLE_AppDefined,
318 : "Too many recursion levels in expression");
319 0 : return SWQ_ERROR;
320 : }
321 :
322 : /* -------------------------------------------------------------------- */
323 : /* Otherwise we take constants literally. */
324 : /* -------------------------------------------------------------------- */
325 38793 : if (eNodeType == SNT_CONSTANT)
326 14041 : return field_type;
327 :
328 : /* -------------------------------------------------------------------- */
329 : /* If this is intended to be a field definition, but has not */
330 : /* yet been looked up, we do so now. */
331 : /* -------------------------------------------------------------------- */
332 24752 : if (eNodeType == SNT_COLUMN && field_index == -1)
333 : {
334 8448 : field_index = swq_identify_field(table_name, string_value, poFieldList,
335 : &field_type, &table_index);
336 :
337 8448 : if (field_index < 0)
338 : {
339 4 : if (table_name)
340 3 : CPLError(CE_Failure, CPLE_AppDefined,
341 : R"("%s"."%s" not recognised as an available field.)",
342 : table_name, string_value);
343 : else
344 1 : CPLError(CE_Failure, CPLE_AppDefined,
345 : "\"%s\" not recognised as an available field.",
346 : string_value);
347 :
348 4 : return SWQ_ERROR;
349 : }
350 :
351 8444 : if (!bAllowFieldsInSecondaryTables && table_index != 0)
352 : {
353 1 : CPLError(
354 : CE_Failure, CPLE_AppDefined,
355 : "Cannot use field '%s' of a secondary table in this context",
356 : string_value);
357 1 : return SWQ_ERROR;
358 : }
359 : }
360 :
361 24747 : if (eNodeType == SNT_COLUMN)
362 8443 : return field_type;
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* We are dealing with an operation - fetch the definition. */
366 : /* -------------------------------------------------------------------- */
367 : const swq_operation *poOp =
368 112 : (nOperation == SWQ_CUSTOM_FUNC && poCustomFuncRegistrar != nullptr)
369 16416 : ? poCustomFuncRegistrar->GetOperator(string_value)
370 16192 : : swq_op_registrar::GetOperator(nOperation);
371 :
372 16304 : if (poOp == nullptr)
373 : {
374 0 : if (nOperation == SWQ_CUSTOM_FUNC)
375 0 : CPLError(CE_Failure, CPLE_AppDefined,
376 : "Check(): Unable to find definition for operator %s.",
377 : string_value);
378 : else
379 0 : CPLError(CE_Failure, CPLE_AppDefined,
380 : "Check(): Unable to find definition for operator %d.",
381 0 : nOperation);
382 0 : return SWQ_ERROR;
383 : }
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Check subexpressions first. */
387 : /* -------------------------------------------------------------------- */
388 48604 : for (int i = 0; i < nSubExprCount; i++)
389 : {
390 32322 : if (papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables,
391 : bAllowMismatchTypeOnFieldComparison,
392 : poCustomFuncRegistrar,
393 32322 : nDepth + 1) == SWQ_ERROR)
394 22 : return SWQ_ERROR;
395 : }
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Check this node. */
399 : /* -------------------------------------------------------------------- */
400 16282 : field_type = poOp->pfnChecker(this, bAllowMismatchTypeOnFieldComparison);
401 :
402 16282 : return field_type;
403 : }
404 :
405 : /************************************************************************/
406 : /* Dump() */
407 : /************************************************************************/
408 :
409 0 : void swq_expr_node::Dump(FILE *fp, int depth)
410 :
411 : {
412 0 : char spaces[60] = {};
413 :
414 : {
415 0 : int i = 0; // Used after for.
416 0 : for (; i < depth * 2 && i < static_cast<int>(sizeof(spaces)) - 1; i++)
417 0 : spaces[i] = ' ';
418 0 : spaces[i] = '\0';
419 : }
420 :
421 0 : if (eNodeType == SNT_COLUMN)
422 : {
423 0 : fprintf(fp, "%s Field %d\n", spaces, field_index);
424 0 : return;
425 : }
426 :
427 0 : if (eNodeType == SNT_CONSTANT)
428 : {
429 0 : if (field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
430 0 : field_type == SWQ_BOOLEAN)
431 0 : fprintf(fp, "%s %" PRId64 "\n", spaces, int_value);
432 0 : else if (field_type == SWQ_FLOAT)
433 0 : fprintf(fp, "%s %.15g\n", spaces, float_value);
434 0 : else if (field_type == SWQ_GEOMETRY)
435 : {
436 0 : if (geometry_value == nullptr)
437 0 : fprintf(fp, "%s (null)\n", spaces);
438 : else
439 : {
440 0 : char *pszWKT = nullptr;
441 0 : geometry_value->exportToWkt(&pszWKT);
442 0 : fprintf(fp, "%s %s\n", spaces, pszWKT);
443 0 : CPLFree(pszWKT);
444 : }
445 : }
446 : else
447 0 : fprintf(fp, "%s %s\n", spaces, string_value);
448 0 : return;
449 : }
450 :
451 0 : CPLAssert(eNodeType == SNT_OPERATION);
452 :
453 0 : const swq_operation *op_def = swq_op_registrar::GetOperator(nOperation);
454 0 : if (op_def)
455 0 : fprintf(fp, "%s%s\n", spaces, op_def->pszName);
456 : else
457 0 : fprintf(fp, "%s%s\n", spaces, string_value);
458 :
459 0 : for (int i = 0; i < nSubExprCount; i++)
460 0 : papoSubExpr[i]->Dump(fp, depth + 1);
461 : }
462 :
463 : /************************************************************************/
464 : /* QuoteIfNecessary() */
465 : /* */
466 : /* Add quoting if necessary to unparse a string. */
467 : /************************************************************************/
468 :
469 414 : CPLString swq_expr_node::QuoteIfNecessary(const CPLString &osExpr, char chQuote)
470 :
471 : {
472 414 : if (osExpr[0] == '_')
473 0 : return Quote(osExpr, chQuote);
474 414 : if (osExpr == "*")
475 3 : return osExpr;
476 :
477 2719 : for (int i = 0; i < static_cast<int>(osExpr.size()); i++)
478 : {
479 2316 : char ch = osExpr[i];
480 2316 : if ((!(isalnum(static_cast<unsigned char>(ch)) || ch == '_')) ||
481 : ch == '.')
482 : {
483 8 : return Quote(osExpr, chQuote);
484 : }
485 : }
486 :
487 403 : if (swq_is_reserved_keyword(osExpr))
488 : {
489 1 : return Quote(osExpr, chQuote);
490 : }
491 :
492 402 : return osExpr;
493 : }
494 :
495 : /************************************************************************/
496 : /* Quote() */
497 : /* */
498 : /* Add quoting necessary to unparse a string. */
499 : /************************************************************************/
500 :
501 122 : CPLString swq_expr_node::Quote(const CPLString &osTarget, char chQuote)
502 :
503 : {
504 122 : CPLString osNew;
505 :
506 122 : osNew += chQuote;
507 :
508 1237 : for (int i = 0; i < static_cast<int>(osTarget.size()); i++)
509 : {
510 1115 : if (osTarget[i] == chQuote)
511 : {
512 0 : osNew += chQuote;
513 0 : osNew += chQuote;
514 : }
515 : else
516 1115 : osNew += osTarget[i];
517 : }
518 122 : osNew += chQuote;
519 :
520 122 : return osNew;
521 : }
522 :
523 : /************************************************************************/
524 : /* Unparse() */
525 : /************************************************************************/
526 :
527 3228 : char *swq_expr_node::Unparse(swq_field_list *field_list, char chColumnQuote)
528 :
529 : {
530 6456 : CPLString osExpr;
531 :
532 : /* -------------------------------------------------------------------- */
533 : /* Handle constants. */
534 : /* -------------------------------------------------------------------- */
535 3228 : if (eNodeType == SNT_CONSTANT)
536 : {
537 1689 : if (is_null)
538 37 : return CPLStrdup("NULL");
539 :
540 1652 : if (field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
541 147 : field_type == SWQ_BOOLEAN)
542 1505 : osExpr.Printf("%" PRId64, int_value);
543 147 : else if (field_type == SWQ_FLOAT)
544 : {
545 34 : osExpr.Printf("%.15g", float_value);
546 : // Make sure this is interpreted as a floating point value
547 : // and not as an integer later.
548 34 : if (strchr(osExpr, '.') == nullptr &&
549 66 : strchr(osExpr, 'e') == nullptr &&
550 32 : strchr(osExpr, 'E') == nullptr)
551 32 : osExpr += '.';
552 : }
553 : else
554 : {
555 113 : osExpr = Quote(string_value);
556 : }
557 :
558 1652 : return CPLStrdup(osExpr);
559 : }
560 :
561 : /* -------------------------------------------------------------------- */
562 : /* Handle columns. */
563 : /* -------------------------------------------------------------------- */
564 1539 : if (eNodeType == SNT_COLUMN)
565 : {
566 386 : if (field_list == nullptr)
567 : {
568 9 : if (table_name)
569 : osExpr.Printf(
570 : "%s.%s",
571 4 : QuoteIfNecessary(table_name, chColumnQuote).c_str(),
572 6 : QuoteIfNecessary(string_value, chColumnQuote).c_str());
573 : else
574 : osExpr.Printf(
575 : "%s",
576 7 : QuoteIfNecessary(string_value, chColumnQuote).c_str());
577 : }
578 377 : else if (field_index != -1 && table_index < field_list->table_count &&
579 377 : table_index > 0)
580 : {
581 : // We deliberately browse through the list starting from the end
582 : // This is for the case where the FID column exists both as
583 : // FID and then real_fid_name. We want real_fid_name to be used
584 26 : for (int i = field_list->count - 1; i >= 0; i--)
585 : {
586 26 : if (field_list->table_ids[i] == table_index &&
587 6 : field_list->ids[i] == field_index)
588 : {
589 : osExpr.Printf(
590 : "%s.%s",
591 8 : QuoteIfNecessary(
592 4 : field_list->table_defs[table_index].table_name,
593 : chColumnQuote)
594 : .c_str(),
595 8 : QuoteIfNecessary(field_list->names[i], chColumnQuote)
596 8 : .c_str());
597 4 : break;
598 : }
599 4 : }
600 : }
601 373 : else if (field_index != -1)
602 : {
603 : // We deliberately browse through the list starting from the end
604 : // This is for the case where the FID column exists both as
605 : // FID and then real_fid_name. We want real_fid_name to be used
606 2709 : for (int i = field_list->count - 1; i >= 0; i--)
607 : {
608 2709 : if (field_list->table_ids[i] == table_index &&
609 2691 : field_list->ids[i] == field_index)
610 : {
611 746 : osExpr.Printf("%s", QuoteIfNecessary(field_list->names[i],
612 : chColumnQuote)
613 373 : .c_str());
614 373 : break;
615 : }
616 : }
617 : }
618 :
619 386 : if (osExpr.empty())
620 : {
621 0 : return CPLStrdup(CPLSPrintf("%c%c", chColumnQuote, chColumnQuote));
622 : }
623 :
624 : // The string is just alphanum and not a reserved SQL keyword,
625 : // no needs to quote and escape.
626 386 : return CPLStrdup(osExpr.c_str());
627 : }
628 :
629 : /* -------------------------------------------------------------------- */
630 : /* Operation - start by unparsing all the subexpressions. */
631 : /* -------------------------------------------------------------------- */
632 2306 : std::vector<char *> apszSubExpr;
633 1153 : apszSubExpr.reserve(nSubExprCount);
634 3379 : for (int i = 0; i < nSubExprCount; i++)
635 2226 : apszSubExpr.push_back(
636 2226 : papoSubExpr[i]->Unparse(field_list, chColumnQuote));
637 :
638 1153 : osExpr = UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
639 :
640 : /* -------------------------------------------------------------------- */
641 : /* cleanup subexpressions. */
642 : /* -------------------------------------------------------------------- */
643 3379 : for (int i = 0; i < nSubExprCount; i++)
644 2226 : CPLFree(apszSubExpr[i]);
645 :
646 1153 : return CPLStrdup(osExpr.c_str());
647 : }
648 :
649 : /************************************************************************/
650 : /* UnparseOperationFromUnparsedSubExpr() */
651 : /************************************************************************/
652 :
653 1272 : CPLString swq_expr_node::UnparseOperationFromUnparsedSubExpr(char **apszSubExpr)
654 : {
655 1272 : CPLString osExpr;
656 :
657 : /* -------------------------------------------------------------------- */
658 : /* Put things together in a fashion depending on the operator. */
659 : /* -------------------------------------------------------------------- */
660 1272 : const swq_operation *poOp = swq_op_registrar::GetOperator(nOperation);
661 :
662 1272 : if (poOp == nullptr && nOperation != SWQ_CUSTOM_FUNC)
663 : {
664 0 : CPLAssert(false);
665 : return osExpr;
666 : }
667 :
668 7156 : const auto AddSubExpr = [this, apszSubExpr, &osExpr](int idx)
669 : {
670 2426 : if (papoSubExpr[idx]->eNodeType == SNT_COLUMN ||
671 1866 : papoSubExpr[idx]->eNodeType == SNT_CONSTANT)
672 : {
673 2207 : osExpr += apszSubExpr[idx];
674 : }
675 : else
676 : {
677 219 : osExpr += '(';
678 219 : osExpr += apszSubExpr[idx];
679 219 : osExpr += ')';
680 : }
681 3698 : };
682 :
683 1272 : switch (nOperation)
684 : {
685 : // Binary infix operators.
686 1058 : case SWQ_OR:
687 : case SWQ_AND:
688 : case SWQ_EQ:
689 : case SWQ_NE:
690 : case SWQ_GT:
691 : case SWQ_LT:
692 : case SWQ_GE:
693 : case SWQ_LE:
694 : case SWQ_LIKE:
695 : case SWQ_ILIKE:
696 : case SWQ_ADD:
697 : case SWQ_SUBTRACT:
698 : case SWQ_MULTIPLY:
699 : case SWQ_DIVIDE:
700 : case SWQ_MODULUS:
701 1058 : CPLAssert(nSubExprCount >= 2);
702 1058 : AddSubExpr(0);
703 1058 : osExpr += " ";
704 1058 : osExpr += poOp->pszName;
705 1058 : osExpr += " ";
706 1058 : AddSubExpr(1);
707 1058 : if ((nOperation == SWQ_LIKE || nOperation == SWQ_ILIKE) &&
708 11 : nSubExprCount == 3)
709 : {
710 1 : osExpr += " ESCAPE ";
711 1 : AddSubExpr(2);
712 : }
713 1058 : break;
714 :
715 81 : case SWQ_NOT:
716 81 : CPLAssert(nSubExprCount == 1);
717 81 : osExpr = "NOT ";
718 81 : AddSubExpr(0);
719 81 : break;
720 :
721 36 : case SWQ_ISNULL:
722 36 : CPLAssert(nSubExprCount == 1);
723 36 : AddSubExpr(0);
724 36 : osExpr += " IS NULL";
725 36 : break;
726 :
727 42 : case SWQ_IN:
728 42 : AddSubExpr(0);
729 42 : osExpr += " IN(";
730 112 : for (int i = 1; i < nSubExprCount; i++)
731 : {
732 70 : if (i > 1)
733 28 : osExpr += ",";
734 70 : AddSubExpr(i);
735 : }
736 42 : osExpr += ")";
737 42 : break;
738 :
739 2 : case SWQ_BETWEEN:
740 2 : CPLAssert(nSubExprCount == 3);
741 2 : AddSubExpr(0);
742 2 : osExpr += ' ';
743 2 : osExpr += poOp->pszName;
744 2 : osExpr += ' ';
745 2 : AddSubExpr(1);
746 2 : osExpr += " AND ";
747 2 : AddSubExpr(2);
748 2 : break;
749 :
750 36 : case SWQ_CAST:
751 36 : osExpr = "CAST(";
752 112 : for (int i = 0; i < nSubExprCount; i++)
753 : {
754 76 : if (i == 1)
755 36 : osExpr += " AS ";
756 40 : else if (i > 2)
757 1 : osExpr += ", ";
758 :
759 76 : const int nLen = static_cast<int>(strlen(apszSubExpr[i]));
760 76 : if ((i == 1 && (apszSubExpr[i][0] == '\'' && nLen > 2 &&
761 76 : apszSubExpr[i][nLen - 1] == '\'')) ||
762 3 : (i == 2 && EQUAL(apszSubExpr[1], "'GEOMETRY")))
763 : {
764 38 : apszSubExpr[i][nLen - 1] = '\0';
765 38 : osExpr += apszSubExpr[i] + 1;
766 : }
767 : else
768 38 : AddSubExpr(i);
769 :
770 76 : if (i == 1 && nSubExprCount > 2)
771 3 : osExpr += "(";
772 73 : else if (i > 1 && i == nSubExprCount - 1)
773 3 : osExpr += ")";
774 : }
775 36 : osExpr += ")";
776 36 : break;
777 :
778 17 : default: // function style.
779 17 : if (nOperation != SWQ_CUSTOM_FUNC)
780 1 : osExpr.Printf("%s(", poOp->pszName);
781 : else
782 16 : osExpr.Printf("%s(", string_value);
783 53 : for (int i = 0; i < nSubExprCount; i++)
784 : {
785 36 : if (i > 0)
786 19 : osExpr += ",";
787 36 : AddSubExpr(i);
788 : }
789 17 : osExpr += ")";
790 17 : break;
791 : }
792 :
793 2544 : return osExpr;
794 : }
795 :
796 : /************************************************************************/
797 : /* Clone() */
798 : /************************************************************************/
799 :
800 76 : swq_expr_node *swq_expr_node::Clone()
801 : {
802 76 : return new swq_expr_node(*this);
803 : }
804 :
805 : /************************************************************************/
806 : /* Evaluate() */
807 : /************************************************************************/
808 :
809 66103 : swq_expr_node *swq_expr_node::Evaluate(swq_field_fetcher pfnFetcher,
810 : void *pRecord,
811 : const swq_evaluation_context &sContext)
812 :
813 : {
814 66103 : return Evaluate(pfnFetcher, pRecord, sContext, 0);
815 : }
816 :
817 121889 : swq_expr_node *swq_expr_node::Evaluate(swq_field_fetcher pfnFetcher,
818 : void *pRecord,
819 : const swq_evaluation_context &sContext,
820 : int nRecLevel)
821 :
822 : {
823 121889 : swq_expr_node *poRetNode = nullptr;
824 121889 : if (nRecLevel == 32)
825 : {
826 0 : CPLError(CE_Failure, CPLE_AppDefined,
827 : "Too many recursion levels in expression");
828 0 : return nullptr;
829 : }
830 :
831 : /* -------------------------------------------------------------------- */
832 : /* Duplicate ourselves if we are already a constant. */
833 : /* -------------------------------------------------------------------- */
834 121889 : if (eNodeType == SNT_CONSTANT)
835 : {
836 71 : return Clone();
837 : }
838 :
839 : /* -------------------------------------------------------------------- */
840 : /* If this is a field value from a record, fetch and return it. */
841 : /* -------------------------------------------------------------------- */
842 121818 : if (eNodeType == SNT_COLUMN)
843 : {
844 40618 : return pfnFetcher(this, pRecord);
845 : }
846 :
847 : /* -------------------------------------------------------------------- */
848 : /* This is an operation, collect the arguments keeping track of */
849 : /* which we will need to free. */
850 : /* -------------------------------------------------------------------- */
851 162400 : std::vector<swq_expr_node *> apoValues;
852 81200 : std::vector<int> anValueNeedsFree;
853 81200 : bool bError = false;
854 81200 : apoValues.reserve(nSubExprCount);
855 242878 : for (int i = 0; i < nSubExprCount && !bError; i++)
856 : {
857 161678 : if (papoSubExpr[i]->eNodeType == SNT_CONSTANT)
858 : {
859 : // avoid duplication.
860 105892 : apoValues.push_back(papoSubExpr[i]);
861 105892 : anValueNeedsFree.push_back(FALSE);
862 : }
863 : else
864 : {
865 55786 : swq_expr_node *poSubExprVal = papoSubExpr[i]->Evaluate(
866 55786 : pfnFetcher, pRecord, sContext, nRecLevel + 1);
867 55786 : if (poSubExprVal == nullptr)
868 0 : bError = true;
869 : else
870 : {
871 55786 : apoValues.push_back(poSubExprVal);
872 55786 : anValueNeedsFree.push_back(TRUE);
873 : }
874 : }
875 : }
876 :
877 : /* -------------------------------------------------------------------- */
878 : /* Fetch the operator definition and function. */
879 : /* -------------------------------------------------------------------- */
880 81200 : if (!bError)
881 : {
882 81200 : const swq_operation *poOp = swq_op_registrar::GetOperator(nOperation);
883 81200 : if (poOp == nullptr)
884 : {
885 0 : if (nOperation == SWQ_CUSTOM_FUNC)
886 0 : CPLError(
887 : CE_Failure, CPLE_AppDefined,
888 : "Evaluate(): Unable to find definition for operator %s.",
889 : string_value);
890 : else
891 0 : CPLError(
892 : CE_Failure, CPLE_AppDefined,
893 : "Evaluate(): Unable to find definition for operator %d.",
894 0 : nOperation);
895 0 : poRetNode = nullptr;
896 : }
897 : else
898 81200 : poRetNode = poOp->pfnEvaluator(this, &(apoValues[0]), sContext);
899 : }
900 :
901 : /* -------------------------------------------------------------------- */
902 : /* Cleanup */
903 : /* -------------------------------------------------------------------- */
904 242878 : for (int i = 0; i < static_cast<int>(apoValues.size()); i++)
905 : {
906 161678 : if (anValueNeedsFree[i])
907 55786 : delete apoValues[i];
908 : }
909 :
910 : // cppcheck-suppress returnDanglingLifetime
911 81200 : return poRetNode;
912 : }
913 :
914 : /************************************************************************/
915 : /* ReplaceBetweenByGEAndLERecurse() */
916 : /************************************************************************/
917 :
918 6050 : void swq_expr_node::ReplaceBetweenByGEAndLERecurse()
919 : {
920 6050 : if (eNodeType != SNT_OPERATION)
921 3827 : return;
922 :
923 2223 : if (nOperation != SWQ_BETWEEN)
924 : {
925 6538 : for (int i = 0; i < nSubExprCount; i++)
926 4318 : papoSubExpr[i]->ReplaceBetweenByGEAndLERecurse();
927 2220 : return;
928 : }
929 :
930 3 : if (nSubExprCount != 3)
931 0 : return;
932 :
933 3 : swq_expr_node *poExpr0 = papoSubExpr[0];
934 3 : swq_expr_node *poExpr1 = papoSubExpr[1];
935 3 : swq_expr_node *poExpr2 = papoSubExpr[2];
936 :
937 3 : nSubExprCount = 2;
938 3 : nOperation = SWQ_AND;
939 3 : papoSubExpr[0] = new swq_expr_node(SWQ_GE);
940 3 : papoSubExpr[0]->PushSubExpression(poExpr0);
941 3 : papoSubExpr[0]->PushSubExpression(poExpr1);
942 3 : papoSubExpr[1] = new swq_expr_node(SWQ_LE);
943 3 : papoSubExpr[1]->PushSubExpression(poExpr0->Clone());
944 3 : papoSubExpr[1]->PushSubExpression(poExpr2);
945 : }
946 :
947 : /************************************************************************/
948 : /* PushNotOperationDownToStack() */
949 : /************************************************************************/
950 :
951 : // Do things like:
952 : // NOT(A AND B) ==> (NOT A) OR (NOT B)
953 : // NOT(A OR B) ==> (NOT A) AND (NOT B)
954 : // NOT(NOT A) ==> A
955 : // NOT(A == B) ==> A <> B
956 : // NOT(A != B) ==> A == B
957 : // NOT(A >= B) ==> A < B
958 : // NOT(A > B) ==> A <= B
959 : // NOT(A <= B) ==> A > B
960 : // NOT(A < B) ==> A >= B
961 846 : void swq_expr_node::PushNotOperationDownToStack()
962 : {
963 846 : if (eNodeType != SNT_OPERATION)
964 474 : return;
965 :
966 372 : if (nOperation == SWQ_NOT && papoSubExpr[0]->eNodeType == SNT_OPERATION)
967 : {
968 42 : if (papoSubExpr[0]->nOperation == SWQ_NOT)
969 : {
970 2 : auto poChild = papoSubExpr[0]->papoSubExpr[0];
971 2 : poChild->PushNotOperationDownToStack();
972 2 : papoSubExpr[0]->papoSubExpr[0] = nullptr;
973 2 : *this = std::move(*poChild);
974 2 : delete poChild;
975 2 : return;
976 : }
977 :
978 40 : else if (papoSubExpr[0]->nOperation == SWQ_AND)
979 : {
980 3 : for (int i = 0; i < papoSubExpr[0]->nSubExprCount; i++)
981 : {
982 2 : auto notOp = new swq_expr_node(SWQ_NOT);
983 2 : notOp->PushSubExpression(papoSubExpr[0]->papoSubExpr[i]);
984 2 : notOp->PushNotOperationDownToStack();
985 2 : papoSubExpr[0]->papoSubExpr[i] = notOp;
986 : }
987 1 : papoSubExpr[0]->nOperation = SWQ_OR;
988 1 : auto poChild = papoSubExpr[0];
989 1 : papoSubExpr[0] = nullptr;
990 1 : *this = std::move(*poChild);
991 1 : delete poChild;
992 1 : return;
993 : }
994 :
995 39 : else if (papoSubExpr[0]->nOperation == SWQ_OR)
996 : {
997 9 : for (int i = 0; i < papoSubExpr[0]->nSubExprCount; i++)
998 : {
999 6 : auto notOp = new swq_expr_node(SWQ_NOT);
1000 6 : notOp->PushSubExpression(papoSubExpr[0]->papoSubExpr[i]);
1001 6 : notOp->PushNotOperationDownToStack();
1002 6 : papoSubExpr[0]->papoSubExpr[i] = notOp;
1003 : }
1004 3 : papoSubExpr[0]->nOperation = SWQ_AND;
1005 3 : auto poChild = papoSubExpr[0];
1006 3 : papoSubExpr[0] = nullptr;
1007 3 : *this = std::move(*poChild);
1008 3 : delete poChild;
1009 3 : return;
1010 : }
1011 :
1012 36 : else if (papoSubExpr[0]->nOperation == SWQ_EQ)
1013 : {
1014 3 : auto poChild = papoSubExpr[0];
1015 3 : papoSubExpr[0] = nullptr;
1016 3 : poChild->nOperation = SWQ_NE;
1017 3 : *this = std::move(*poChild);
1018 3 : delete poChild;
1019 3 : return;
1020 : }
1021 33 : else if (papoSubExpr[0]->nOperation == SWQ_NE)
1022 : {
1023 1 : auto poChild = papoSubExpr[0];
1024 1 : papoSubExpr[0] = nullptr;
1025 1 : poChild->nOperation = SWQ_EQ;
1026 1 : *this = std::move(*poChild);
1027 1 : delete poChild;
1028 1 : return;
1029 : }
1030 32 : else if (papoSubExpr[0]->nOperation == SWQ_GT)
1031 : {
1032 1 : auto poChild = papoSubExpr[0];
1033 1 : papoSubExpr[0] = nullptr;
1034 1 : poChild->nOperation = SWQ_LE;
1035 1 : *this = std::move(*poChild);
1036 1 : delete poChild;
1037 1 : return;
1038 : }
1039 31 : else if (papoSubExpr[0]->nOperation == SWQ_GE)
1040 : {
1041 1 : auto poChild = papoSubExpr[0];
1042 1 : papoSubExpr[0] = nullptr;
1043 1 : poChild->nOperation = SWQ_LT;
1044 1 : *this = std::move(*poChild);
1045 1 : delete poChild;
1046 1 : return;
1047 : }
1048 30 : else if (papoSubExpr[0]->nOperation == SWQ_LT)
1049 : {
1050 1 : auto poChild = papoSubExpr[0];
1051 1 : papoSubExpr[0] = nullptr;
1052 1 : poChild->nOperation = SWQ_GE;
1053 1 : *this = std::move(*poChild);
1054 1 : delete poChild;
1055 1 : return;
1056 : }
1057 29 : else if (papoSubExpr[0]->nOperation == SWQ_LE)
1058 : {
1059 1 : auto poChild = papoSubExpr[0];
1060 1 : papoSubExpr[0] = nullptr;
1061 1 : poChild->nOperation = SWQ_GT;
1062 1 : *this = std::move(*poChild);
1063 1 : delete poChild;
1064 1 : return;
1065 : }
1066 : }
1067 :
1068 987 : for (int i = 0; i < nSubExprCount; i++)
1069 629 : papoSubExpr[i]->PushNotOperationDownToStack();
1070 : }
1071 :
1072 : #endif // #ifndef DOXYGEN_SKIP
|