Line data Source code
1 : /******************************************************************************
2 : *
3 : * Component: OGR SQL Engine
4 : * Purpose: swq_select class implementation.
5 : * Author: Frank Warmerdam <warmerdam@pobox.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "ogr_swq.h"
32 :
33 : #include <algorithm>
34 : #include <cstdio>
35 : #include <cstring>
36 : #include <string>
37 :
38 : #include "cpl_conv.h"
39 : #include "cpl_error.h"
40 : #include "cpl_string.h"
41 : #include "ogr_core.h"
42 : #include "ogr_geometry.h"
43 : #include "swq_parser.hpp"
44 :
45 : //! @cond Doxygen_Suppress
46 : /************************************************************************/
47 : /* swq_select() */
48 : /************************************************************************/
49 :
50 : swq_select::swq_select() = default;
51 :
52 : /************************************************************************/
53 : /* ~swq_select() */
54 : /************************************************************************/
55 :
56 2767 : swq_select::~swq_select()
57 :
58 : {
59 2767 : delete where_expr;
60 2767 : CPLFree(raw_select);
61 :
62 5432 : for (int i = 0; i < table_count; i++)
63 : {
64 2665 : swq_table_def *table_def = table_defs + i;
65 :
66 2665 : CPLFree(table_def->data_source);
67 2665 : CPLFree(table_def->table_name);
68 2665 : CPLFree(table_def->table_alias);
69 : }
70 2767 : CPLFree(table_defs);
71 :
72 18030 : for (auto &col : column_defs)
73 : {
74 15263 : CPLFree(col.table_name);
75 15263 : CPLFree(col.field_name);
76 15263 : CPLFree(col.field_alias);
77 :
78 15263 : delete col.expr;
79 : }
80 :
81 : // cppcheck-suppress constVariableReference
82 2778 : for (auto &entry : m_exclude_fields)
83 : {
84 : // cppcheck-suppress constVariableReference
85 16 : for (auto &col : entry.second)
86 : {
87 5 : CPLFree(col.table_name);
88 5 : CPLFree(col.field_name);
89 5 : CPLFree(col.field_alias);
90 :
91 5 : delete col.expr;
92 : }
93 : }
94 :
95 2875 : for (int i = 0; i < order_specs; i++)
96 : {
97 108 : CPLFree(order_defs[i].table_name);
98 108 : CPLFree(order_defs[i].field_name);
99 : }
100 :
101 2767 : CPLFree(order_defs);
102 :
103 2839 : for (int i = 0; i < join_count; i++)
104 : {
105 72 : delete join_defs[i].poExpr;
106 : }
107 2767 : CPLFree(join_defs);
108 :
109 2767 : delete poOtherSelect;
110 2767 : }
111 :
112 : /************************************************************************/
113 : /* preparse() */
114 : /* */
115 : /* Parse the expression but without knowing the available */
116 : /* tables and fields. */
117 : /************************************************************************/
118 :
119 2760 : CPLErr swq_select::preparse(const char *select_statement,
120 : int bAcceptCustomFuncs)
121 :
122 : {
123 : /* -------------------------------------------------------------------- */
124 : /* Prepare a parser context. */
125 : /* -------------------------------------------------------------------- */
126 2760 : swq_parse_context context;
127 :
128 2760 : context.pszInput = select_statement;
129 2760 : context.pszNext = select_statement;
130 2760 : context.pszLastValid = select_statement;
131 2760 : context.nStartToken = SWQT_SELECT_START;
132 2760 : context.bAcceptCustomFuncs = bAcceptCustomFuncs;
133 2760 : context.poCurSelect = this;
134 :
135 : /* -------------------------------------------------------------------- */
136 : /* Do the parse. */
137 : /* -------------------------------------------------------------------- */
138 2760 : if (swqparse(&context) != 0)
139 : {
140 200 : delete context.poRoot;
141 200 : return CE_Failure;
142 : }
143 :
144 : // Restore poCurSelect as it might have been modified by UNION ALL
145 2560 : context.poCurSelect = this;
146 2560 : swq_fixup(&context);
147 :
148 2560 : postpreparse();
149 :
150 2560 : return CE_None;
151 : }
152 :
153 : /************************************************************************/
154 : /* postpreparse() */
155 : /************************************************************************/
156 :
157 2565 : void swq_select::postpreparse()
158 : {
159 : /* -------------------------------------------------------------------- */
160 : /* Reorder the joins in the order they appear in the SQL string. */
161 : /* -------------------------------------------------------------------- */
162 2568 : for (int i = 0; i < join_count / 2; i++)
163 : {
164 : swq_join_def sTmp;
165 3 : memcpy(&sTmp, &join_defs[i], sizeof(swq_join_def));
166 3 : memcpy(&join_defs[i], &join_defs[join_count - 1 - i],
167 : sizeof(swq_join_def));
168 3 : memcpy(&join_defs[join_count - 1 - i], &sTmp, sizeof(swq_join_def));
169 : }
170 :
171 : // We make that strong assumption in ogr_gensql.
172 2637 : for (int i = 0; i < join_count; i++)
173 : {
174 72 : CPLAssert(join_defs[i].secondary_table == i + 1);
175 : }
176 :
177 2565 : if (poOtherSelect != nullptr)
178 5 : poOtherSelect->postpreparse();
179 2565 : }
180 :
181 : /************************************************************************/
182 : /* Unparse() */
183 : /************************************************************************/
184 :
185 5 : char *swq_select::Unparse()
186 : {
187 10 : CPLString osSelect("SELECT ");
188 5 : if (query_mode == SWQM_DISTINCT_LIST)
189 1 : osSelect += "DISTINCT ";
190 :
191 18 : for (int i = 0; i < result_columns(); i++)
192 : {
193 13 : swq_col_def *def = &column_defs[i];
194 :
195 13 : if (i > 0)
196 8 : osSelect += ", ";
197 :
198 13 : if (def->expr != nullptr && def->col_func == SWQCF_NONE)
199 : {
200 6 : char *pszTmp = def->expr->Unparse(nullptr, '"');
201 6 : osSelect += pszTmp;
202 6 : CPLFree(pszTmp);
203 : }
204 : else
205 : {
206 7 : if (def->col_func == SWQCF_AVG)
207 2 : osSelect += "AVG(";
208 5 : else if (def->col_func == SWQCF_MIN)
209 1 : osSelect += "MIN(";
210 4 : else if (def->col_func == SWQCF_MAX)
211 1 : osSelect += "MAX(";
212 3 : else if (def->col_func == SWQCF_COUNT)
213 2 : osSelect += "COUNT(";
214 1 : else if (def->col_func == SWQCF_SUM)
215 1 : osSelect += "SUM(";
216 :
217 7 : if (def->distinct_flag && def->col_func == SWQCF_COUNT)
218 1 : osSelect += "DISTINCT ";
219 :
220 7 : if ((def->field_alias == nullptr || table_count > 1) &&
221 7 : def->table_name != nullptr && def->table_name[0] != '\0')
222 : {
223 : osSelect +=
224 1 : swq_expr_node::QuoteIfNecessary(def->table_name, '"');
225 1 : osSelect += ".";
226 : }
227 7 : osSelect += swq_expr_node::QuoteIfNecessary(def->field_name, '"');
228 7 : osSelect += ")";
229 : }
230 :
231 13 : if (def->field_alias != nullptr &&
232 2 : strcmp(def->field_name, def->field_alias) != 0)
233 : {
234 2 : osSelect += " AS ";
235 2 : osSelect += swq_expr_node::QuoteIfNecessary(def->field_alias, '"');
236 : }
237 : }
238 :
239 5 : osSelect += " FROM ";
240 5 : if (table_defs[0].data_source != nullptr)
241 : {
242 1 : osSelect += "'";
243 1 : osSelect += table_defs[0].data_source;
244 1 : osSelect += "'.";
245 : }
246 5 : osSelect += swq_expr_node::QuoteIfNecessary(table_defs[0].table_name, '"');
247 5 : if (table_defs[0].table_alias != nullptr &&
248 5 : strcmp(table_defs[0].table_name, table_defs[0].table_alias) != 0)
249 : {
250 1 : osSelect += " AS ";
251 : osSelect +=
252 1 : swq_expr_node::QuoteIfNecessary(table_defs[0].table_alias, '"');
253 : }
254 :
255 6 : for (int i = 0; i < join_count; i++)
256 : {
257 1 : int iTable = join_defs[i].secondary_table;
258 1 : osSelect += " JOIN ";
259 1 : if (table_defs[iTable].data_source != nullptr)
260 : {
261 1 : osSelect += "'";
262 1 : osSelect += table_defs[iTable].data_source;
263 1 : osSelect += "'.";
264 : }
265 : osSelect +=
266 1 : swq_expr_node::QuoteIfNecessary(table_defs[iTable].table_name, '"');
267 1 : if (table_defs[iTable].table_alias != nullptr &&
268 1 : strcmp(table_defs[iTable].table_name,
269 1 : table_defs[iTable].table_alias) != 0)
270 : {
271 1 : osSelect += " AS ";
272 2 : osSelect += swq_expr_node::QuoteIfNecessary(
273 2 : table_defs[iTable].table_alias, '"');
274 : }
275 1 : osSelect += " ON ";
276 1 : char *pszTmp = join_defs[i].poExpr->Unparse(nullptr, '"');
277 1 : osSelect += pszTmp;
278 1 : CPLFree(pszTmp);
279 : }
280 :
281 5 : if (where_expr != nullptr)
282 : {
283 2 : osSelect += " WHERE ";
284 2 : char *pszTmp = where_expr->Unparse(nullptr, '"');
285 2 : osSelect += pszTmp;
286 2 : CPLFree(pszTmp);
287 : }
288 :
289 5 : if (order_specs > 0)
290 : {
291 1 : osSelect += " ORDER BY ";
292 3 : for (int i = 0; i < order_specs; i++)
293 : {
294 2 : if (i > 0)
295 1 : osSelect += ", ";
296 : osSelect +=
297 2 : swq_expr_node::QuoteIfNecessary(order_defs[i].field_name, '"');
298 2 : if (!order_defs[i].ascending_flag)
299 1 : osSelect += " DESC";
300 : }
301 : }
302 :
303 5 : if (limit >= 0)
304 : {
305 1 : osSelect += " LIMIT ";
306 1 : osSelect += CPLSPrintf(CPL_FRMT_GIB, limit);
307 : }
308 :
309 5 : if (offset > 0)
310 : {
311 1 : osSelect += " OFFSET ";
312 1 : osSelect += CPLSPrintf(CPL_FRMT_GIB, offset);
313 : }
314 :
315 10 : return CPLStrdup(osSelect);
316 : }
317 :
318 : /************************************************************************/
319 : /* PushField() */
320 : /* */
321 : /* Create a new field definition by name and possibly alias. */
322 : /************************************************************************/
323 :
324 3853 : int swq_select::PushField(swq_expr_node *poExpr, const char *pszAlias,
325 : int distinct_flag)
326 :
327 : {
328 3853 : if (query_mode == SWQM_DISTINCT_LIST && distinct_flag)
329 : {
330 0 : CPLError(CE_Failure, CPLE_NotSupported,
331 : "SELECT DISTINCT and COUNT(DISTINCT...) "
332 : "not supported together");
333 0 : return FALSE;
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Grow the array. */
338 : /* -------------------------------------------------------------------- */
339 :
340 3853 : column_defs.emplace_back();
341 3853 : swq_col_def *col_def = &column_defs.back();
342 :
343 3853 : memset(col_def, 0, sizeof(swq_col_def));
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Try to capture a field name. */
347 : /* -------------------------------------------------------------------- */
348 3853 : if (poExpr->eNodeType == SNT_COLUMN)
349 : {
350 2968 : col_def->table_name =
351 2968 : CPLStrdup(poExpr->table_name ? poExpr->table_name : "");
352 2968 : col_def->field_name = CPLStrdup(poExpr->string_value);
353 :
354 : // Associate a column list from an EXCEPT () clause with its associated
355 : // wildcard
356 2968 : if (EQUAL(col_def->field_name, "*"))
357 : {
358 1795 : auto it = m_exclude_fields.find(-1);
359 :
360 1795 : if (it != m_exclude_fields.end())
361 : {
362 : int curr_asterisk_pos =
363 8 : static_cast<int>(column_defs.size() - 1);
364 8 : m_exclude_fields[curr_asterisk_pos] = std::move(it->second);
365 8 : m_exclude_fields.erase(it);
366 : }
367 : }
368 : }
369 885 : else if (poExpr->eNodeType == SNT_OPERATION &&
370 855 : (poExpr->nOperation == SWQ_CAST ||
371 813 : (poExpr->nOperation >= SWQ_AVG &&
372 569 : poExpr->nOperation <= SWQ_SUM)) &&
373 607 : poExpr->nSubExprCount >= 1 &&
374 607 : poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN)
375 : {
376 598 : col_def->table_name = CPLStrdup(poExpr->papoSubExpr[0]->table_name
377 7 : ? poExpr->papoSubExpr[0]->table_name
378 : : "");
379 591 : col_def->field_name = CPLStrdup(poExpr->papoSubExpr[0]->string_value);
380 : }
381 : else
382 : {
383 294 : col_def->table_name = CPLStrdup("");
384 294 : col_def->field_name = CPLStrdup("");
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Initialize fields. */
389 : /* -------------------------------------------------------------------- */
390 3853 : if (pszAlias != nullptr)
391 57 : col_def->field_alias = CPLStrdup(pszAlias);
392 3796 : else if (poExpr->eNodeType == SNT_OPERATION && poExpr->nSubExprCount >= 1 &&
393 824 : (static_cast<swq_op>(poExpr->nOperation) == SWQ_CONCAT ||
394 820 : static_cast<swq_op>(poExpr->nOperation) == SWQ_SUBSTR) &&
395 9 : poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN)
396 : {
397 14 : const swq_operation *op = swq_op_registrar::GetOperator(
398 7 : static_cast<swq_op>(poExpr->nOperation));
399 :
400 7 : col_def->field_alias = CPLStrdup(CPLSPrintf(
401 7 : "%s_%s", op->pszName, poExpr->papoSubExpr[0]->string_value));
402 : }
403 :
404 3853 : col_def->table_index = -1;
405 3853 : col_def->field_index = -1;
406 3853 : col_def->field_type = SWQ_OTHER;
407 3853 : col_def->field_precision = -1;
408 3853 : col_def->target_type = SWQ_OTHER;
409 3853 : col_def->target_subtype = OFSTNone;
410 3853 : col_def->col_func = SWQCF_NONE;
411 3853 : col_def->distinct_flag = distinct_flag;
412 :
413 : /* -------------------------------------------------------------------- */
414 : /* Do we have a CAST operator in play? */
415 : /* -------------------------------------------------------------------- */
416 3853 : if (poExpr->eNodeType == SNT_OPERATION && poExpr->nOperation == SWQ_CAST)
417 : {
418 42 : const char *pszTypeName = poExpr->papoSubExpr[1]->string_value;
419 42 : int parse_precision = 0;
420 :
421 42 : if (EQUAL(pszTypeName, "character"))
422 : {
423 7 : col_def->target_type = SWQ_STRING;
424 7 : col_def->field_length = 1;
425 : }
426 35 : else if (strcasecmp(pszTypeName, "boolean") == 0)
427 : {
428 1 : col_def->target_type = SWQ_BOOLEAN;
429 : }
430 34 : else if (strcasecmp(pszTypeName, "integer") == 0)
431 : {
432 5 : col_def->target_type = SWQ_INTEGER;
433 : }
434 29 : else if (strcasecmp(pszTypeName, "bigint") == 0)
435 : {
436 5 : col_def->target_type = SWQ_INTEGER64;
437 : }
438 24 : else if (strcasecmp(pszTypeName, "smallint") == 0)
439 : {
440 1 : col_def->target_type = SWQ_INTEGER;
441 1 : col_def->target_subtype = OFSTInt16;
442 : }
443 23 : else if (strcasecmp(pszTypeName, "float") == 0)
444 : {
445 4 : col_def->target_type = SWQ_FLOAT;
446 : }
447 19 : else if (strcasecmp(pszTypeName, "numeric") == 0)
448 : {
449 2 : col_def->target_type = SWQ_FLOAT;
450 2 : parse_precision = 1;
451 : }
452 17 : else if (strcasecmp(pszTypeName, "timestamp") == 0)
453 : {
454 0 : col_def->target_type = SWQ_TIMESTAMP;
455 : }
456 17 : else if (strcasecmp(pszTypeName, "date") == 0)
457 : {
458 0 : col_def->target_type = SWQ_DATE;
459 : }
460 17 : else if (strcasecmp(pszTypeName, "time") == 0)
461 : {
462 0 : col_def->target_type = SWQ_TIME;
463 : }
464 17 : else if (strcasecmp(pszTypeName, "geometry") == 0)
465 : {
466 14 : col_def->target_type = SWQ_GEOMETRY;
467 : }
468 : else
469 : {
470 3 : CPLError(CE_Failure, CPLE_AppDefined,
471 : "Unrecognized typename %s in CAST operator.", pszTypeName);
472 3 : CPLFree(col_def->table_name);
473 3 : col_def->table_name = nullptr;
474 3 : CPLFree(col_def->field_name);
475 3 : col_def->field_name = nullptr;
476 3 : CPLFree(col_def->field_alias);
477 3 : col_def->field_alias = nullptr;
478 3 : column_defs.pop_back();
479 3 : return FALSE;
480 : }
481 :
482 39 : if (col_def->target_type == SWQ_GEOMETRY)
483 : {
484 14 : if (poExpr->nSubExprCount > 2)
485 : {
486 7 : if (poExpr->papoSubExpr[2]->field_type != SWQ_STRING)
487 : {
488 1 : CPLError(CE_Failure, CPLE_AppDefined,
489 : "First argument of CAST operator should be "
490 : "a geometry type identifier.");
491 1 : CPLFree(col_def->table_name);
492 1 : col_def->table_name = nullptr;
493 1 : CPLFree(col_def->field_name);
494 1 : col_def->field_name = nullptr;
495 1 : CPLFree(col_def->field_alias);
496 1 : col_def->field_alias = nullptr;
497 1 : column_defs.pop_back();
498 1 : return FALSE;
499 : }
500 :
501 6 : col_def->eGeomType =
502 6 : OGRFromOGCGeomType(poExpr->papoSubExpr[2]->string_value);
503 :
504 : // SRID
505 6 : if (poExpr->nSubExprCount > 3)
506 : {
507 1 : col_def->nSRID =
508 1 : static_cast<int>(poExpr->papoSubExpr[3]->int_value);
509 : }
510 : }
511 : }
512 : else
513 : {
514 : // field width.
515 25 : if (poExpr->nSubExprCount > 2)
516 : {
517 6 : if (poExpr->papoSubExpr[2]->field_type != SWQ_INTEGER)
518 : {
519 0 : CPLError(CE_Failure, CPLE_AppDefined,
520 : "First argument of CAST operator should be of "
521 : "integer type.");
522 0 : CPLFree(col_def->table_name);
523 0 : col_def->table_name = nullptr;
524 0 : CPLFree(col_def->field_name);
525 0 : col_def->field_name = nullptr;
526 0 : CPLFree(col_def->field_alias);
527 0 : col_def->field_alias = nullptr;
528 0 : column_defs.pop_back();
529 0 : return FALSE;
530 : }
531 6 : col_def->field_length =
532 6 : static_cast<int>(poExpr->papoSubExpr[2]->int_value);
533 : }
534 :
535 : // field width.
536 25 : if (poExpr->nSubExprCount > 3 && parse_precision)
537 : {
538 2 : col_def->field_precision =
539 2 : static_cast<int>(poExpr->papoSubExpr[3]->int_value);
540 2 : if (col_def->field_precision == 0)
541 : {
542 1 : if (col_def->field_length < 10)
543 0 : col_def->target_type = SWQ_INTEGER;
544 1 : else if (col_def->field_length < 19)
545 1 : col_def->target_type = SWQ_INTEGER64;
546 : }
547 : }
548 : }
549 : }
550 :
551 : /* -------------------------------------------------------------------- */
552 : /* Do we have a special column function in play? */
553 : /* -------------------------------------------------------------------- */
554 3849 : if (poExpr->eNodeType == SNT_OPERATION &&
555 851 : static_cast<swq_op>(poExpr->nOperation) >= SWQ_AVG &&
556 607 : static_cast<swq_op>(poExpr->nOperation) <= SWQ_SUM)
557 : {
558 565 : if (poExpr->nSubExprCount != 1)
559 : {
560 4 : const swq_operation *poOp = swq_op_registrar::GetOperator(
561 2 : static_cast<swq_op>(poExpr->nOperation));
562 2 : CPLError(CE_Failure, CPLE_AppDefined,
563 : "Column Summary Function '%s' has "
564 : "wrong number of arguments.",
565 2 : poOp->pszName);
566 2 : CPLFree(col_def->table_name);
567 2 : col_def->table_name = nullptr;
568 2 : CPLFree(col_def->field_name);
569 2 : col_def->field_name = nullptr;
570 2 : CPLFree(col_def->field_alias);
571 2 : col_def->field_alias = nullptr;
572 2 : column_defs.pop_back();
573 2 : return FALSE;
574 : }
575 563 : else if (poExpr->papoSubExpr[0]->eNodeType != SNT_COLUMN)
576 : {
577 2 : const swq_operation *poOp = swq_op_registrar::GetOperator(
578 1 : static_cast<swq_op>(poExpr->nOperation));
579 1 : CPLError(CE_Failure, CPLE_AppDefined,
580 : "Argument of column Summary Function '%s' "
581 : "should be a column.",
582 1 : poOp->pszName);
583 1 : CPLFree(col_def->table_name);
584 1 : col_def->table_name = nullptr;
585 1 : CPLFree(col_def->field_name);
586 1 : col_def->field_name = nullptr;
587 1 : CPLFree(col_def->field_alias);
588 1 : col_def->field_alias = nullptr;
589 1 : column_defs.pop_back();
590 1 : return FALSE;
591 : }
592 : else
593 : {
594 562 : col_def->col_func = static_cast<swq_col_func>(poExpr->nOperation);
595 :
596 562 : swq_expr_node *poSubExpr = poExpr->papoSubExpr[0];
597 :
598 562 : poExpr->papoSubExpr[0] = nullptr;
599 562 : poExpr->nSubExprCount = 0;
600 562 : delete poExpr;
601 :
602 562 : poExpr = poSubExpr;
603 : }
604 : }
605 :
606 3846 : col_def->expr = poExpr;
607 :
608 3846 : return TRUE;
609 : }
610 :
611 16 : int swq_select::PushExcludeField(swq_expr_node *poExpr)
612 : {
613 16 : if (poExpr->eNodeType != SNT_COLUMN)
614 : {
615 0 : return FALSE;
616 : }
617 :
618 : // Check if this column has already been excluded
619 20 : for (const auto &col_def : m_exclude_fields[-1])
620 : {
621 5 : if (EQUAL(poExpr->string_value, col_def.field_name) &&
622 1 : EQUAL(poExpr->table_name ? poExpr->table_name : "",
623 : col_def.table_name))
624 : {
625 1 : CPLError(CE_Failure, CPLE_AppDefined,
626 : "Field %s.%s repeated in EXCEPT/EXCLUDE expression.",
627 1 : col_def.table_name, col_def.field_name);
628 :
629 1 : return FALSE;
630 : }
631 : }
632 :
633 15 : m_exclude_fields[-1].emplace_back();
634 15 : swq_col_def *col_def = &m_exclude_fields[-1].back();
635 15 : memset(col_def, 0, sizeof(swq_col_def));
636 :
637 15 : col_def->table_name =
638 15 : CPLStrdup(poExpr->table_name ? poExpr->table_name : "");
639 15 : col_def->field_name = CPLStrdup(poExpr->string_value);
640 15 : col_def->table_index = -1;
641 15 : col_def->field_index = -1;
642 :
643 15 : delete poExpr;
644 :
645 15 : return TRUE;
646 : }
647 :
648 : /************************************************************************/
649 : /* PushTableDef() */
650 : /************************************************************************/
651 :
652 2667 : int swq_select::PushTableDef(const char *pszDataSource, const char *pszName,
653 : const char *pszAlias)
654 :
655 : {
656 2667 : table_count++;
657 :
658 2667 : table_defs = static_cast<swq_table_def *>(
659 2667 : CPLRealloc(table_defs, sizeof(swq_table_def) * table_count));
660 :
661 2667 : if (pszDataSource != nullptr)
662 9 : table_defs[table_count - 1].data_source = CPLStrdup(pszDataSource);
663 : else
664 2658 : table_defs[table_count - 1].data_source = nullptr;
665 :
666 2667 : table_defs[table_count - 1].table_name = CPLStrdup(pszName);
667 :
668 2667 : if (pszAlias != nullptr)
669 28 : table_defs[table_count - 1].table_alias = CPLStrdup(pszAlias);
670 : else
671 2639 : table_defs[table_count - 1].table_alias = CPLStrdup(pszName);
672 :
673 2667 : return table_count - 1;
674 : }
675 :
676 : /************************************************************************/
677 : /* PushOrderBy() */
678 : /************************************************************************/
679 :
680 108 : void swq_select::PushOrderBy(const char *pszTableName, const char *pszFieldName,
681 : int bAscending)
682 :
683 : {
684 108 : order_specs++;
685 108 : order_defs = static_cast<swq_order_def *>(
686 108 : CPLRealloc(order_defs, sizeof(swq_order_def) * order_specs));
687 :
688 216 : order_defs[order_specs - 1].table_name =
689 108 : CPLStrdup(pszTableName ? pszTableName : "");
690 108 : order_defs[order_specs - 1].field_name = CPLStrdup(pszFieldName);
691 108 : order_defs[order_specs - 1].table_index = -1;
692 108 : order_defs[order_specs - 1].field_index = -1;
693 108 : order_defs[order_specs - 1].ascending_flag = bAscending;
694 108 : }
695 :
696 : /************************************************************************/
697 : /* PushJoin() */
698 : /************************************************************************/
699 :
700 72 : void swq_select::PushJoin(int iSecondaryTable, swq_expr_node *poExpr)
701 :
702 : {
703 72 : join_count++;
704 72 : join_defs = static_cast<swq_join_def *>(
705 72 : CPLRealloc(join_defs, sizeof(swq_join_def) * join_count));
706 :
707 72 : join_defs[join_count - 1].secondary_table = iSecondaryTable;
708 72 : join_defs[join_count - 1].poExpr = poExpr;
709 72 : }
710 :
711 : /************************************************************************/
712 : /* PushUnionAll() */
713 : /************************************************************************/
714 :
715 9 : void swq_select::PushUnionAll(swq_select *poOtherSelectIn)
716 : {
717 9 : CPLAssert(poOtherSelect == nullptr);
718 9 : poOtherSelect = poOtherSelectIn;
719 9 : }
720 :
721 : /************************************************************************/
722 : /* SetLimit() */
723 : /************************************************************************/
724 :
725 34 : void swq_select::SetLimit(GIntBig nLimit)
726 :
727 : {
728 34 : limit = nLimit;
729 34 : }
730 :
731 : /************************************************************************/
732 : /* SetOffset() */
733 : /************************************************************************/
734 :
735 18 : void swq_select::SetOffset(GIntBig nOffset)
736 :
737 : {
738 18 : offset = nOffset;
739 18 : }
740 :
741 : /************************************************************************/
742 : /* expand_wildcard() */
743 : /* */
744 : /* This function replaces the '*' in a "SELECT *" with the list */
745 : /* provided list of fields. It is used by swq_select::parse(), */
746 : /* but may be called in advance by applications wanting the */
747 : /* "default" field list to be different than the full list of */
748 : /* fields. */
749 : /************************************************************************/
750 :
751 4040 : CPLErr swq_select::expand_wildcard(swq_field_list *field_list,
752 : int bAlwaysPrefixWithTableName)
753 :
754 : {
755 4040 : int columns_added = 0;
756 :
757 : /* ==================================================================== */
758 : /* Check each pre-expansion field. */
759 : /* ==================================================================== */
760 32743 : for (int isrc = 0; isrc < result_columns(); isrc++)
761 : {
762 28705 : const char *src_tablename = column_defs[isrc].table_name;
763 28705 : const char *src_fieldname = column_defs[isrc].field_name;
764 : int itable;
765 :
766 28705 : if (*src_fieldname == '\0' ||
767 28123 : src_fieldname[strlen(src_fieldname) - 1] != '*')
768 27338 : continue;
769 :
770 : // Don't want to expand COUNT(*).
771 1947 : if (column_defs[isrc].col_func == SWQCF_COUNT)
772 580 : continue;
773 :
774 : // Parse out the table name and verify it
775 1367 : if (src_tablename[0] == 0 && strcmp(src_fieldname, "*") == 0)
776 : {
777 1350 : itable = -1;
778 : }
779 : else
780 : {
781 22 : for (itable = 0; itable < field_list->table_count; itable++)
782 : {
783 21 : if (EQUAL(src_tablename,
784 : field_list->table_defs[itable].table_alias))
785 16 : break;
786 : }
787 :
788 17 : if (itable == field_list->table_count)
789 : {
790 1 : CPLError(CE_Failure, CPLE_AppDefined,
791 : "Table %s not recognised from %s.%s definition.",
792 : src_tablename, src_tablename, src_fieldname);
793 2 : return CE_Failure;
794 : }
795 : }
796 :
797 : // Assign the selected fields. */
798 1366 : std::vector<swq_col_def> expanded_columns;
799 13946 : for (int i = 0; i < field_list->count; i++)
800 : {
801 12580 : bool compose = (itable != -1) || bAlwaysPrefixWithTableName;
802 :
803 : // Skip this field if it isn't in the target table.
804 12580 : if (itable != -1 && itable != field_list->table_ids[i])
805 43 : continue;
806 :
807 12537 : auto table_id = field_list->table_ids[i];
808 :
809 : // Skip this field if we've excluded it with SELECT * EXCEPT ()
810 12537 : if (IsFieldExcluded(isrc - columns_added,
811 12537 : field_list->table_defs[table_id].table_name,
812 12537 : field_list->names[i]))
813 : {
814 10 : if (field_list->types[i] == SWQ_GEOMETRY)
815 : {
816 : // Need to store the fact that we explicitly excluded
817 : // the geometry so we can prevent it from being implicitly
818 : // included by OGRGenSQLResultsLayer
819 2 : bExcludedGeometry = true;
820 : }
821 :
822 10 : continue;
823 : }
824 :
825 : // Set up some default values.
826 12527 : expanded_columns.emplace_back();
827 12527 : swq_col_def *def = &expanded_columns.back();
828 12527 : def->field_precision = -1;
829 12527 : def->target_type = SWQ_OTHER;
830 12527 : def->target_subtype = OFSTNone;
831 :
832 : // Does this field duplicate an earlier one?
833 12527 : if (field_list->table_ids[i] != 0 && !compose)
834 : {
835 228 : for (int other = 0; other < i; other++)
836 : {
837 198 : if (EQUAL(field_list->names[i], field_list->names[other]))
838 : {
839 17 : compose = true;
840 17 : break;
841 : }
842 : }
843 : }
844 :
845 12527 : int field_itable = field_list->table_ids[i];
846 12527 : const char *field_name = field_list->names[i];
847 12527 : const char *table_alias =
848 12527 : field_list->table_defs[field_itable].table_alias;
849 :
850 12527 : def->table_name = CPLStrdup(table_alias);
851 12527 : def->field_name = CPLStrdup(field_name);
852 12527 : if (!compose)
853 12299 : def->field_alias = CPLStrdup(field_list->names[i]);
854 :
855 : // All the other table info will be provided by the later
856 : // parse operation.
857 : }
858 :
859 : // Splice expanded_columns in at the position of '*'
860 1366 : CPLFree(column_defs[isrc].table_name);
861 1366 : CPLFree(column_defs[isrc].field_name);
862 1366 : CPLFree(column_defs[isrc].field_alias);
863 1366 : delete column_defs[isrc].expr;
864 1366 : auto pos = column_defs.erase(std::next(column_defs.begin(), isrc));
865 :
866 : column_defs.insert(pos, expanded_columns.begin(),
867 1366 : expanded_columns.end());
868 :
869 1366 : columns_added += static_cast<int>(expanded_columns.size()) - 1;
870 :
871 1366 : const auto it = m_exclude_fields.find(isrc);
872 1366 : if (it != m_exclude_fields.end())
873 : {
874 7 : if (!it->second.empty())
875 : {
876 1 : const auto &field = it->second.front();
877 1 : CPLError(
878 : CE_Failure, CPLE_AppDefined,
879 : "Field %s specified in EXCEPT/EXCLUDE expression not found",
880 1 : field.field_name);
881 1 : return CE_Failure;
882 : }
883 : }
884 : }
885 :
886 4038 : return CE_None;
887 : }
888 :
889 : /************************************************************************/
890 : /* CheckCompatibleJoinExpr() */
891 : /************************************************************************/
892 :
893 202 : static bool CheckCompatibleJoinExpr(swq_expr_node *poExpr, int secondary_table,
894 : swq_field_list *field_list)
895 : {
896 202 : if (poExpr->eNodeType == SNT_CONSTANT)
897 3 : return true;
898 :
899 199 : if (poExpr->eNodeType == SNT_COLUMN)
900 : {
901 128 : CPLAssert(poExpr->field_index != -1);
902 128 : CPLAssert(poExpr->table_index != -1);
903 128 : if (poExpr->table_index != 0 && poExpr->table_index != secondary_table)
904 : {
905 1 : if (poExpr->table_name)
906 1 : CPLError(CE_Failure, CPLE_AppDefined,
907 : "Field %s.%s in JOIN clause does not correspond to "
908 : "the primary table nor the joint (secondary) table.",
909 : poExpr->table_name, poExpr->string_value);
910 : else
911 0 : CPLError(CE_Failure, CPLE_AppDefined,
912 : "Field %s in JOIN clause does not correspond to the "
913 : "primary table nor the joint (secondary) table.",
914 : poExpr->string_value);
915 1 : return false;
916 : }
917 :
918 127 : return true;
919 : }
920 :
921 71 : if (poExpr->eNodeType == SNT_OPERATION)
922 : {
923 208 : for (int i = 0; i < poExpr->nSubExprCount; i++)
924 : {
925 138 : if (!CheckCompatibleJoinExpr(poExpr->papoSubExpr[i],
926 : secondary_table, field_list))
927 1 : return false;
928 : }
929 70 : return true;
930 : }
931 :
932 0 : return false;
933 : }
934 :
935 : /************************************************************************/
936 : /* parse() */
937 : /* */
938 : /* This method really does post-parse processing. */
939 : /************************************************************************/
940 :
941 2019 : CPLErr swq_select::parse(swq_field_list *field_list,
942 : swq_select_parse_options *poParseOptions)
943 : {
944 2019 : int bAlwaysPrefixWithTableName =
945 2019 : poParseOptions && poParseOptions->bAlwaysPrefixWithTableName;
946 2019 : CPLErr eError = expand_wildcard(field_list, bAlwaysPrefixWithTableName);
947 2019 : if (eError != CE_None)
948 0 : return eError;
949 :
950 2019 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
951 2019 : if (poParseOptions != nullptr)
952 42 : poCustomFuncRegistrar = poParseOptions->poCustomFuncRegistrar;
953 :
954 : /* -------------------------------------------------------------------- */
955 : /* Identify field information. */
956 : /* -------------------------------------------------------------------- */
957 16328 : for (int i = 0; i < result_columns(); i++)
958 : {
959 14335 : swq_col_def *def = &column_defs[i];
960 :
961 14335 : if (def->expr != nullptr && def->expr->eNodeType != SNT_COLUMN)
962 : {
963 303 : def->field_index = -1;
964 303 : def->table_index = -1;
965 :
966 303 : if (def->expr->Check(field_list, TRUE, FALSE,
967 303 : poCustomFuncRegistrar) == SWQ_ERROR)
968 15 : return CE_Failure;
969 :
970 288 : def->field_type = def->expr->field_type;
971 : }
972 : else
973 : {
974 : swq_field_type this_type;
975 :
976 : // Identify field.
977 14032 : def->field_index =
978 14032 : swq_identify_field(def->table_name, def->field_name, field_list,
979 : &this_type, &(def->table_index));
980 :
981 : // Record field type.
982 14032 : def->field_type = this_type;
983 :
984 14032 : if (def->field_index == -1 && def->col_func != SWQCF_COUNT)
985 : {
986 8 : CPLError(
987 : CE_Failure, CPLE_AppDefined, "Unrecognized field name %s.",
988 8 : def->table_name[0]
989 1 : ? CPLSPrintf("%s.%s", def->table_name, def->field_name)
990 : : def->field_name);
991 8 : return CE_Failure;
992 : }
993 : }
994 :
995 : // Identify column function if present.
996 14312 : if (((def->col_func == SWQCF_MIN || def->col_func == SWQCF_MAX ||
997 14279 : def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM) &&
998 45 : def->field_type == SWQ_GEOMETRY) ||
999 14311 : ((def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM) &&
1000 12 : def->field_type == SWQ_STRING))
1001 : {
1002 : // Possibly this is already enforced by the checker?
1003 6 : const swq_operation *op = swq_op_registrar::GetOperator(
1004 3 : static_cast<swq_op>(def->col_func));
1005 3 : CPLError(CE_Failure, CPLE_AppDefined,
1006 : "Use of field function %s() on %s field %s illegal.",
1007 3 : op->pszName, SWQFieldTypeToString(def->field_type),
1008 : def->field_name);
1009 3 : return CE_Failure;
1010 : }
1011 : }
1012 :
1013 : /* -------------------------------------------------------------------- */
1014 : /* Check if we are producing a one row summary result or a set */
1015 : /* of records. Generate an error if we get conflicting */
1016 : /* indications. */
1017 : /* -------------------------------------------------------------------- */
1018 :
1019 1993 : int bAllowDistinctOnMultipleFields =
1020 1993 : (poParseOptions && poParseOptions->bAllowDistinctOnMultipleFields);
1021 1993 : if (query_mode == SWQM_DISTINCT_LIST && result_columns() > 1 &&
1022 : !bAllowDistinctOnMultipleFields)
1023 : {
1024 3 : CPLError(CE_Failure, CPLE_NotSupported,
1025 : "SELECT DISTINCT not supported on multiple columns.");
1026 3 : return CE_Failure;
1027 : }
1028 :
1029 16285 : for (int i = 0; i < result_columns(); i++)
1030 : {
1031 14297 : swq_col_def *def = &column_defs[i];
1032 14297 : int this_indicator = -1;
1033 :
1034 14297 : if (query_mode == SWQM_DISTINCT_LIST && def->field_type == SWQ_GEOMETRY)
1035 : {
1036 3 : const bool bAllowDistinctOnGeometryField =
1037 3 : poParseOptions && poParseOptions->bAllowDistinctOnGeometryField;
1038 3 : if (!bAllowDistinctOnGeometryField)
1039 : {
1040 1 : CPLError(CE_Failure, CPLE_NotSupported,
1041 : "SELECT DISTINCT on a geometry not supported.");
1042 1 : return CE_Failure;
1043 : }
1044 : }
1045 :
1046 14296 : if (def->col_func == SWQCF_MIN || def->col_func == SWQCF_MAX ||
1047 14264 : def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM ||
1048 14254 : def->col_func == SWQCF_COUNT)
1049 : {
1050 350 : this_indicator = SWQM_SUMMARY_RECORD;
1051 350 : if (def->col_func == SWQCF_COUNT && def->distinct_flag &&
1052 8 : def->field_type == SWQ_GEOMETRY)
1053 : {
1054 1 : CPLError(CE_Failure, CPLE_AppDefined,
1055 : "SELECT COUNT DISTINCT on a geometry not supported.");
1056 1 : return CE_Failure;
1057 : }
1058 : }
1059 13946 : else if (def->col_func == SWQCF_NONE)
1060 : {
1061 13946 : if (query_mode == SWQM_DISTINCT_LIST)
1062 : {
1063 37 : def->distinct_flag = TRUE;
1064 37 : this_indicator = SWQM_DISTINCT_LIST;
1065 : }
1066 : else
1067 13909 : this_indicator = SWQM_RECORDSET;
1068 : }
1069 :
1070 14295 : if (this_indicator != query_mode && this_indicator != -1 &&
1071 1928 : query_mode != 0)
1072 : {
1073 0 : CPLError(CE_Failure, CPLE_AppDefined,
1074 : "Field list implies mixture of regular recordset mode, "
1075 : "summary mode or distinct field list mode.");
1076 0 : return CE_Failure;
1077 : }
1078 :
1079 14295 : if (this_indicator != -1)
1080 14295 : query_mode = this_indicator;
1081 : }
1082 :
1083 1988 : if (result_columns() == 0)
1084 : {
1085 33 : query_mode = SWQM_RECORDSET;
1086 : }
1087 :
1088 : /* -------------------------------------------------------------------- */
1089 : /* Process column names in JOIN specs. */
1090 : /* -------------------------------------------------------------------- */
1091 2051 : for (int i = 0; i < join_count; i++)
1092 : {
1093 68 : swq_join_def *def = join_defs + i;
1094 68 : if (def->poExpr->Check(field_list, TRUE, TRUE, poCustomFuncRegistrar) ==
1095 : SWQ_ERROR)
1096 4 : return CE_Failure;
1097 64 : if (!CheckCompatibleJoinExpr(def->poExpr, def->secondary_table,
1098 : field_list))
1099 1 : return CE_Failure;
1100 : }
1101 :
1102 : /* -------------------------------------------------------------------- */
1103 : /* Process column names in order specs. */
1104 : /* -------------------------------------------------------------------- */
1105 2051 : for (int i = 0; i < order_specs; i++)
1106 : {
1107 72 : swq_order_def *def = order_defs + i;
1108 :
1109 : // Identify field.
1110 : swq_field_type field_type;
1111 72 : def->field_index =
1112 72 : swq_identify_field(def->table_name, def->field_name, field_list,
1113 : &field_type, &(def->table_index));
1114 72 : if (def->field_index == -1)
1115 : {
1116 2 : CPLError(CE_Failure, CPLE_AppDefined,
1117 : "Unrecognized field name %s in ORDER BY.",
1118 2 : def->table_name[0]
1119 0 : ? CPLSPrintf("%s.%s", def->table_name, def->field_name)
1120 : : def->field_name);
1121 4 : return CE_Failure;
1122 : }
1123 :
1124 70 : if (def->table_index != 0)
1125 : {
1126 1 : CPLError(CE_Failure, CPLE_AppDefined,
1127 : "Cannot use field '%s' of a secondary table in "
1128 : "an ORDER BY clause",
1129 : def->field_name);
1130 1 : return CE_Failure;
1131 : }
1132 :
1133 69 : if (field_type == SWQ_GEOMETRY)
1134 : {
1135 1 : CPLError(CE_Failure, CPLE_AppDefined,
1136 : "Cannot use geometry field '%s' in an ORDER BY clause",
1137 : def->field_name);
1138 1 : return CE_Failure;
1139 : }
1140 : }
1141 :
1142 : /* -------------------------------------------------------------------- */
1143 : /* Post process the where clause, subbing in field indexes and */
1144 : /* doing final validation. */
1145 : /* -------------------------------------------------------------------- */
1146 1979 : int bAllowFieldsInSecondaryTablesInWhere = FALSE;
1147 1979 : if (poParseOptions != nullptr)
1148 42 : bAllowFieldsInSecondaryTablesInWhere =
1149 : poParseOptions->bAllowFieldsInSecondaryTablesInWhere;
1150 2832 : if (where_expr != nullptr &&
1151 853 : where_expr->Check(field_list, bAllowFieldsInSecondaryTablesInWhere,
1152 : FALSE, poCustomFuncRegistrar) == SWQ_ERROR)
1153 : {
1154 13 : return CE_Failure;
1155 : }
1156 :
1157 1966 : return CE_None;
1158 : }
1159 :
1160 12537 : bool swq_select::IsFieldExcluded(int src_index, const char *pszTableName,
1161 : const char *pszFieldName)
1162 : {
1163 12537 : auto list_it = m_exclude_fields.find(src_index);
1164 :
1165 12537 : if (list_it == m_exclude_fields.end())
1166 : {
1167 12506 : return false;
1168 : }
1169 :
1170 31 : auto &excluded_fields = list_it->second;
1171 :
1172 : auto it = std::partition(
1173 : excluded_fields.begin(), excluded_fields.end(),
1174 65 : [pszTableName, pszFieldName](const swq_col_def &exclude_field)
1175 : {
1176 32 : if (!(EQUAL(exclude_field.table_name, "") ||
1177 4 : EQUAL(pszTableName, exclude_field.table_name)))
1178 : {
1179 3 : return true;
1180 : }
1181 :
1182 29 : return !EQUAL(pszFieldName, exclude_field.field_name);
1183 31 : });
1184 :
1185 31 : if (it != excluded_fields.end())
1186 : {
1187 10 : CPLFree(it->table_name);
1188 10 : CPLFree(it->field_name);
1189 10 : CPLFree(it->field_alias);
1190 :
1191 10 : delete it->expr;
1192 :
1193 10 : excluded_fields.erase(it);
1194 10 : return true;
1195 : }
1196 :
1197 21 : return false;
1198 : }
1199 :
1200 : //! @endcond
|