LCOV - code coverage report
Current view: top level - ogr - swq_select.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 530 552 96.0 %
Date: 2024-05-03 15:49:35 Functions: 17 17 100.0 %

          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

Generated by: LCOV version 1.14