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