LCOV - code coverage report
Current view: top level - ogr - swq_select.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 531 581 91.4 %
Date: 2024-11-21 22:18:42 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             :  * 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

Generated by: LCOV version 1.14