LCOV - code coverage report
Current view: top level - ogr - swq.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 448 480 93.3 %
Date: 2024-05-03 15:49:35 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Component: OGDI Driver Support Library
       4             :  * Purpose: Generic SQL WHERE Expression Implementation.
       5             :  * Author: Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (C) 2001 Information Interoperability Institute (3i)
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission to use, copy, modify and distribute this software and
      12             :  * its documentation for any purpose and without fee is hereby granted,
      13             :  * provided that the above copyright notice appear in all copies, that
      14             :  * both the copyright notice and this permission notice appear in
      15             :  * supporting documentation, and that the name of 3i not be used
      16             :  * in advertising or publicity pertaining to distribution of the software
      17             :  * without specific, written prior permission.  3i makes no
      18             :  * representations about the suitability of this software for any purpose.
      19             :  * It is provided "as is" without express or implied warranty.
      20             :  ****************************************************************************/
      21             : 
      22             : #include "cpl_port.h"
      23             : #include "ogr_swq.h"
      24             : 
      25             : #include <cassert>
      26             : #include <cctype>
      27             : #include <cmath>
      28             : #include <cstddef>
      29             : #include <cstdlib>
      30             : #include <cstring>
      31             : #include <ctime>
      32             : 
      33             : #include <algorithm>
      34             : #include <limits>
      35             : #include <queue>
      36             : #include <string>
      37             : 
      38             : #include "cpl_error.h"
      39             : #include "cpl_multiproc.h"
      40             : #include "cpl_time.h"
      41             : #include "swq_parser.hpp"
      42             : 
      43             : #define YYSTYPE swq_expr_node *
      44             : 
      45             : /************************************************************************/
      46             : /*                               swqlex()                               */
      47             : /************************************************************************/
      48             : 
      49         189 : void swqerror(swq_parse_context *context, const char *msg)
      50             : {
      51         378 :     CPLString osMsg;
      52         189 :     osMsg.Printf("SQL Expression Parsing Error: %s. Occurred around :\n", msg);
      53             : 
      54         189 :     int n = static_cast<int>(context->pszLastValid - context->pszInput);
      55             : 
      56        4685 :     for (int i = std::max(0, n - 40);
      57        4685 :          i < n + 40 && context->pszInput[i] != '\0'; i++)
      58        4496 :         osMsg += context->pszInput[i];
      59         189 :     osMsg += "\n";
      60        2618 :     for (int i = 0; i < std::min(n, 40); i++)
      61        2429 :         osMsg += " ";
      62         189 :     osMsg += "^";
      63             : 
      64         189 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", osMsg.c_str());
      65         189 : }
      66             : 
      67             : /************************************************************************/
      68             : /*                               swqlex()                               */
      69             : /*                                                                      */
      70             : /*      Read back a token from the input.                               */
      71             : /************************************************************************/
      72             : 
      73       73934 : int swqlex(YYSTYPE *ppNode, swq_parse_context *context)
      74             : {
      75       73934 :     const char *pszInput = context->pszNext;
      76             : 
      77       73934 :     *ppNode = nullptr;
      78             : 
      79             :     /* -------------------------------------------------------------------- */
      80             :     /*      Do we have a start symbol to return?                            */
      81             :     /* -------------------------------------------------------------------- */
      82       73934 :     if (context->nStartToken != 0)
      83             :     {
      84        7384 :         int nRet = context->nStartToken;
      85        7384 :         context->nStartToken = 0;
      86        7384 :         return nRet;
      87             :     }
      88             : 
      89             :     /* -------------------------------------------------------------------- */
      90             :     /*      Skip white space.                                               */
      91             :     /* -------------------------------------------------------------------- */
      92      106560 :     while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 ||
      93       66550 :            *pszInput == 13)
      94       40010 :         pszInput++;
      95             : 
      96       66550 :     context->pszLastValid = pszInput;
      97             : 
      98       66550 :     if (*pszInput == '\0')
      99             :     {
     100        7241 :         context->pszNext = pszInput;
     101        7241 :         return EOF;
     102             :     }
     103             : 
     104             :     /* -------------------------------------------------------------------- */
     105             :     /*      Handle string constants.                                        */
     106             :     /* -------------------------------------------------------------------- */
     107       59309 :     if (*pszInput == '"' || *pszInput == '\'')
     108             :     {
     109        2951 :         char chQuote = *pszInput;
     110        2951 :         bool bFoundEndQuote = false;
     111             : 
     112        2951 :         int nRet = *pszInput == '"' ? SWQT_IDENTIFIER : SWQT_STRING;
     113             : 
     114        2951 :         pszInput++;
     115             : 
     116        2951 :         char *token = static_cast<char *>(CPLMalloc(strlen(pszInput) + 1));
     117        2951 :         int i_token = 0;
     118             : 
     119       40355 :         while (*pszInput != '\0')
     120             :         {
     121       40353 :             if (chQuote == '"' && *pszInput == '\\' && pszInput[1] == '"')
     122           0 :                 pszInput++;
     123       40353 :             else if (chQuote == '\'' && *pszInput == '\\' &&
     124           2 :                      pszInput[1] == '\'')
     125           1 :                 pszInput++;
     126       40352 :             else if (chQuote == '\'' && *pszInput == '\'' &&
     127        1593 :                      pszInput[1] == '\'')
     128           3 :                 pszInput++;
     129       40349 :             else if (*pszInput == chQuote)
     130             :             {
     131        2949 :                 pszInput++;
     132        2949 :                 bFoundEndQuote = true;
     133        2949 :                 break;
     134             :             }
     135             : 
     136       37404 :             token[i_token++] = *(pszInput++);
     137             :         }
     138        2951 :         token[i_token] = '\0';
     139             : 
     140        2951 :         if (!bFoundEndQuote)
     141             :         {
     142           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     143             :                      "Did not find end-of-string character");
     144           2 :             CPLFree(token);
     145           2 :             return 0;
     146             :         }
     147             : 
     148        2949 :         *ppNode = new swq_expr_node(token);
     149        2949 :         CPLFree(token);
     150             : 
     151        2949 :         context->pszNext = pszInput;
     152             : 
     153        2949 :         return nRet;
     154             :     }
     155             : 
     156             :     /* -------------------------------------------------------------------- */
     157             :     /*      Handle numbers.                                                 */
     158             :     /* -------------------------------------------------------------------- */
     159       56358 :     else if (*pszInput >= '0' && *pszInput <= '9')
     160             :     {
     161       23896 :         CPLString osToken;
     162       11948 :         const char *pszNext = pszInput + 1;
     163             : 
     164       11948 :         osToken += *pszInput;
     165             : 
     166             :         // collect non-decimal part of number
     167       20616 :         while (*pszNext >= '0' && *pszNext <= '9')
     168        8668 :             osToken += *(pszNext++);
     169             : 
     170             :         // collect decimal places.
     171       11948 :         if (*pszNext == '.')
     172             :         {
     173         408 :             osToken += *(pszNext++);
     174        1984 :             while (*pszNext >= '0' && *pszNext <= '9')
     175        1576 :                 osToken += *(pszNext++);
     176             :         }
     177             : 
     178             :         // collect exponent
     179       11948 :         if (*pszNext == 'e' || *pszNext == 'E')
     180             :         {
     181           9 :             osToken += *(pszNext++);
     182           9 :             if (*pszNext == '-' || *pszNext == '+')
     183           9 :                 osToken += *(pszNext++);
     184          34 :             while (*pszNext >= '0' && *pszNext <= '9')
     185          25 :                 osToken += *(pszNext++);
     186             :         }
     187             : 
     188       11948 :         context->pszNext = pszNext;
     189             : 
     190       23479 :         if (strstr(osToken, ".") || strstr(osToken, "e") ||
     191       11531 :             strstr(osToken, "E"))
     192             :         {
     193         417 :             *ppNode = new swq_expr_node(CPLAtof(osToken));
     194         417 :             return SWQT_FLOAT_NUMBER;
     195             :         }
     196             :         else
     197             :         {
     198       23089 :             if (osToken.size() > 19 ||
     199       11558 :                 (osToken.size() >= 19 && osToken > "9223372036854775807"))
     200             :             {
     201          12 :                 *ppNode = new swq_expr_node(CPLAtof(osToken));
     202          12 :                 if (osToken == "9223372036854775808")
     203          11 :                     (*ppNode)->string_value = CPLStrdup(osToken);
     204          12 :                 return SWQT_FLOAT_NUMBER;
     205             :             }
     206             : 
     207       11519 :             GIntBig nVal = CPLAtoGIntBig(osToken);
     208       11519 :             if (CPL_INT64_FITS_ON_INT32(nVal))
     209       11426 :                 *ppNode = new swq_expr_node(static_cast<int>(nVal));
     210             :             else
     211          93 :                 *ppNode = new swq_expr_node(nVal);
     212       11519 :             return SWQT_INTEGER_NUMBER;
     213             :         }
     214             :     }
     215             : 
     216             :     /* -------------------------------------------------------------------- */
     217             :     /*      Handle alpha-numerics.                                          */
     218             :     /* -------------------------------------------------------------------- */
     219       44410 :     else if (isalnum(static_cast<unsigned char>(*pszInput)))
     220             :     {
     221       24546 :         int nReturn = SWQT_IDENTIFIER;
     222       24546 :         CPLString osToken;
     223       24546 :         const char *pszNext = pszInput + 1;
     224             : 
     225       24546 :         osToken += *pszInput;
     226             : 
     227             :         // collect text characters
     228       84019 :         while (isalnum(static_cast<unsigned char>(*pszNext)) ||
     229      108565 :                *pszNext == '_' || static_cast<unsigned char>(*pszNext) > 127)
     230       84019 :             osToken += *(pszNext++);
     231             : 
     232       24546 :         context->pszNext = pszNext;
     233             : 
     234       24546 :         if (EQUAL(osToken, "IN"))
     235          87 :             nReturn = SWQT_IN;
     236       24459 :         else if (EQUAL(osToken, "LIKE"))
     237          43 :             nReturn = SWQT_LIKE;
     238       24416 :         else if (EQUAL(osToken, "ILIKE"))
     239          22 :             nReturn = SWQT_ILIKE;
     240       24394 :         else if (EQUAL(osToken, "ESCAPE"))
     241           3 :             nReturn = SWQT_ESCAPE;
     242       24391 :         else if (EQUAL(osToken, "EXCEPT"))
     243          14 :             nReturn = SWQT_EXCEPT;
     244       24377 :         else if (EQUAL(osToken, "EXCLUDE"))
     245           1 :             nReturn = SWQT_EXCLUDE;
     246       24376 :         else if (EQUAL(osToken, "NULL"))
     247         155 :             nReturn = SWQT_NULL;
     248       24221 :         else if (EQUAL(osToken, "IS"))
     249         139 :             nReturn = SWQT_IS;
     250       24082 :         else if (EQUAL(osToken, "NOT"))
     251         107 :             nReturn = SWQT_NOT;
     252       23975 :         else if (EQUAL(osToken, "AND"))
     253        2446 :             nReturn = SWQT_AND;
     254       21529 :         else if (EQUAL(osToken, "OR"))
     255        2243 :             nReturn = SWQT_OR;
     256       19286 :         else if (EQUAL(osToken, "BETWEEN"))
     257          29 :             nReturn = SWQT_BETWEEN;
     258       19257 :         else if (EQUAL(osToken, "SELECT"))
     259        2677 :             nReturn = SWQT_SELECT;
     260       16580 :         else if (EQUAL(osToken, "LEFT"))
     261          31 :             nReturn = SWQT_LEFT;
     262       16549 :         else if (EQUAL(osToken, "JOIN"))
     263          74 :             nReturn = SWQT_JOIN;
     264       16475 :         else if (EQUAL(osToken, "WHERE"))
     265        1069 :             nReturn = SWQT_WHERE;
     266       15406 :         else if (EQUAL(osToken, "ON"))
     267          72 :             nReturn = SWQT_ON;
     268       15334 :         else if (EQUAL(osToken, "ORDER"))
     269         101 :             nReturn = SWQT_ORDER;
     270       15233 :         else if (EQUAL(osToken, "BY"))
     271         101 :             nReturn = SWQT_BY;
     272       15132 :         else if (EQUAL(osToken, "FROM"))
     273        2630 :             nReturn = SWQT_FROM;
     274       12502 :         else if (EQUAL(osToken, "AS"))
     275         168 :             nReturn = SWQT_AS;
     276       12334 :         else if (EQUAL(osToken, "ASC"))
     277          20 :             nReturn = SWQT_ASC;
     278       12314 :         else if (EQUAL(osToken, "DESC"))
     279          20 :             nReturn = SWQT_DESC;
     280       12294 :         else if (EQUAL(osToken, "DISTINCT"))
     281          54 :             nReturn = SWQT_DISTINCT;
     282       12240 :         else if (EQUAL(osToken, "CAST"))
     283         107 :             nReturn = SWQT_CAST;
     284       12133 :         else if (EQUAL(osToken, "UNION"))
     285          10 :             nReturn = SWQT_UNION;
     286       12123 :         else if (EQUAL(osToken, "ALL"))
     287           9 :             nReturn = SWQT_ALL;
     288       12114 :         else if (EQUAL(osToken, "LIMIT"))
     289          34 :             nReturn = SWQT_LIMIT;
     290       12080 :         else if (EQUAL(osToken, "OFFSET"))
     291          18 :             nReturn = SWQT_OFFSET;
     292             : 
     293             :         // Unhandled by OGR SQL.
     294       12062 :         else if (EQUAL(osToken, "OUTER") || EQUAL(osToken, "INNER"))
     295           0 :             nReturn = SWQT_RESERVED_KEYWORD;
     296             : 
     297             :         else
     298             :         {
     299       12062 :             *ppNode = new swq_expr_node(osToken);
     300       12062 :             nReturn = SWQT_IDENTIFIER;
     301             :         }
     302             : 
     303       24546 :         return nReturn;
     304             :     }
     305             : 
     306             :     /* -------------------------------------------------------------------- */
     307             :     /*      Handle special tokens.                                          */
     308             :     /* -------------------------------------------------------------------- */
     309             :     else
     310             :     {
     311       19864 :         context->pszNext = pszInput + 1;
     312       19864 :         return *pszInput;
     313             :     }
     314             : }
     315             : 
     316             : /************************************************************************/
     317             : /*                        swq_select_summarize()                        */
     318             : /************************************************************************/
     319             : 
     320         427 : const char *swq_select_summarize(swq_select *select_info, int dest_column,
     321             :                                  const char *value)
     322             : 
     323             : {
     324             :     /* -------------------------------------------------------------------- */
     325             :     /*      Do various checking.                                            */
     326             :     /* -------------------------------------------------------------------- */
     327         427 :     if (select_info->query_mode == SWQM_RECORDSET)
     328           0 :         return "swq_select_summarize() called on non-summary query.";
     329             : 
     330         854 :     if (dest_column < 0 ||
     331         427 :         dest_column >= static_cast<int>(select_info->column_defs.size()))
     332           0 :         return "dest_column out of range in swq_select_summarize().";
     333             : 
     334         427 :     swq_col_def *def = &select_info->column_defs[dest_column];
     335         427 :     if (def->col_func == SWQCF_NONE && !def->distinct_flag)
     336           0 :         return nullptr;
     337             : 
     338         427 :     if (select_info->query_mode == SWQM_DISTINCT_LIST &&
     339         222 :         select_info->order_specs > 0)
     340             :     {
     341         207 :         if (select_info->order_specs > 1)
     342           1 :             return "Can't ORDER BY a DISTINCT list by more than one key.";
     343             : 
     344         412 :         if (select_info->order_defs[0].field_index !=
     345         206 :             select_info->column_defs[0].field_index)
     346           1 :             return "Only selected DISTINCT field can be used for ORDER BY.";
     347             :     }
     348             : 
     349             :     /* -------------------------------------------------------------------- */
     350             :     /*      Create the summary information if this is the first row         */
     351             :     /*      being processed.                                                */
     352             :     /* -------------------------------------------------------------------- */
     353         425 :     if (select_info->column_summary.empty())
     354             :     {
     355          45 :         select_info->column_summary.resize(select_info->column_defs.size());
     356         121 :         for (std::size_t i = 0; i < select_info->column_defs.size(); i++)
     357             :         {
     358          76 :             if (def->distinct_flag)
     359             :             {
     360          25 :                 swq_summary::Comparator oComparator;
     361          25 :                 if (select_info->order_specs > 0)
     362             :                 {
     363          17 :                     CPLAssert(select_info->order_specs == 1);
     364          17 :                     CPLAssert(select_info->column_defs.size() == 1);
     365          17 :                     oComparator.bSortAsc =
     366          17 :                         CPL_TO_BOOL(select_info->order_defs[0].ascending_flag);
     367             :                 }
     368          43 :                 if (select_info->column_defs[i].field_type == SWQ_INTEGER ||
     369          18 :                     -select_info->column_defs[i].field_type == SWQ_INTEGER64)
     370             :                 {
     371           7 :                     oComparator.eType = SWQ_INTEGER64;
     372             :                 }
     373          18 :                 else if (select_info->column_defs[i].field_type == SWQ_FLOAT)
     374             :                 {
     375           3 :                     oComparator.eType = SWQ_FLOAT;
     376             :                 }
     377             :                 else
     378             :                 {
     379          15 :                     oComparator.eType = SWQ_STRING;
     380             :                 }
     381          25 :                 select_info->column_summary[i].oSetDistinctValues =
     382          50 :                     std::set<CPLString, swq_summary::Comparator>(oComparator);
     383             :             }
     384          76 :             select_info->column_summary[i].min =
     385          76 :                 std::numeric_limits<double>::infinity();
     386         152 :             select_info->column_summary[i].max =
     387          76 :                 -std::numeric_limits<double>::infinity();
     388          76 :             select_info->column_summary[i].osMin = "9999/99/99 99:99:99";
     389          76 :             select_info->column_summary[i].osMax = "0000/00/00 00:00:00";
     390             :         }
     391          45 :         assert(!select_info->column_summary.empty());
     392             :     }
     393             : 
     394             :     /* -------------------------------------------------------------------- */
     395             :     /*      If distinct processing is on, process that now.                 */
     396             :     /* -------------------------------------------------------------------- */
     397         425 :     swq_summary &summary = select_info->column_summary[dest_column];
     398             : 
     399         425 :     if (def->distinct_flag)
     400             :     {
     401         242 :         if (value == nullptr)
     402          19 :             value = SZ_OGR_NULL;
     403             :         try
     404             :         {
     405         242 :             if (summary.oSetDistinctValues.find(value) ==
     406         484 :                 summary.oSetDistinctValues.end())
     407             :             {
     408         110 :                 summary.oSetDistinctValues.insert(value);
     409         110 :                 if (select_info->order_specs == 0)
     410             :                 {
     411             :                     // If not sorted, keep values in their original order
     412          25 :                     summary.oVectorDistinctValues.emplace_back(value);
     413             :                 }
     414         110 :                 summary.count++;
     415             :             }
     416             :         }
     417           0 :         catch (std::bad_alloc &)
     418             :         {
     419           0 :             return "Out of memory";
     420             :         }
     421             : 
     422         242 :         return nullptr;
     423             :     }
     424             : 
     425             :     /* -------------------------------------------------------------------- */
     426             :     /*      Process various options.                                        */
     427             :     /* -------------------------------------------------------------------- */
     428             : 
     429         183 :     switch (def->col_func)
     430             :     {
     431          47 :         case SWQCF_MIN:
     432          47 :             if (value != nullptr && value[0] != '\0')
     433             :             {
     434          43 :                 if (def->field_type == SWQ_DATE ||
     435          40 :                     def->field_type == SWQ_TIME ||
     436          37 :                     def->field_type == SWQ_TIMESTAMP ||
     437          29 :                     def->field_type == SWQ_STRING)
     438             :                 {
     439          17 :                     if (summary.count == 0 || strcmp(value, summary.osMin) < 0)
     440             :                     {
     441          13 :                         summary.osMin = value;
     442             :                     }
     443             :                 }
     444             :                 else
     445             :                 {
     446          26 :                     double df_val = CPLAtof(value);
     447          26 :                     if (df_val < summary.min)
     448           9 :                         summary.min = df_val;
     449             :                 }
     450          43 :                 summary.count++;
     451             :             }
     452          47 :             break;
     453          46 :         case SWQCF_MAX:
     454          46 :             if (value != nullptr && value[0] != '\0')
     455             :             {
     456          42 :                 if (def->field_type == SWQ_DATE ||
     457          39 :                     def->field_type == SWQ_TIME ||
     458          36 :                     def->field_type == SWQ_TIMESTAMP ||
     459          28 :                     def->field_type == SWQ_STRING)
     460             :                 {
     461          17 :                     if (summary.count == 0 || strcmp(value, summary.osMax) > 0)
     462             :                     {
     463           9 :                         summary.osMax = value;
     464             :                     }
     465             :                 }
     466             :                 else
     467             :                 {
     468          25 :                     double df_val = CPLAtof(value);
     469          25 :                     if (df_val > summary.max)
     470          15 :                         summary.max = df_val;
     471             :                 }
     472          42 :                 summary.count++;
     473             :             }
     474          46 :             break;
     475          40 :         case SWQCF_AVG:
     476             :         case SWQCF_SUM:
     477          40 :             if (value != nullptr && value[0] != '\0')
     478             :             {
     479          29 :                 if (def->field_type == SWQ_DATE ||
     480          29 :                     def->field_type == SWQ_TIME ||
     481          29 :                     def->field_type == SWQ_TIMESTAMP)
     482             :                 {
     483             :                     OGRField sField;
     484           2 :                     if (OGRParseDate(value, &sField, 0))
     485             :                     {
     486             :                         struct tm brokendowntime;
     487           2 :                         brokendowntime.tm_year = sField.Date.Year - 1900;
     488           2 :                         brokendowntime.tm_mon = sField.Date.Month - 1;
     489           2 :                         brokendowntime.tm_mday = sField.Date.Day;
     490           2 :                         brokendowntime.tm_hour = sField.Date.Hour;
     491           2 :                         brokendowntime.tm_min = sField.Date.Minute;
     492           2 :                         brokendowntime.tm_sec =
     493           2 :                             static_cast<int>(sField.Date.Second);
     494           2 :                         summary.count++;
     495           2 :                         summary.sum += CPLYMDHMSToUnixTime(&brokendowntime);
     496           2 :                         summary.sum +=
     497           2 :                             fmod(static_cast<double>(sField.Date.Second), 1.0);
     498           2 :                     }
     499             :                 }
     500             :                 else
     501             :                 {
     502          27 :                     summary.count++;
     503          27 :                     summary.sum += CPLAtof(value);
     504             :                 }
     505             :             }
     506          40 :             break;
     507             : 
     508          50 :         case SWQCF_COUNT:
     509          50 :             if (value != nullptr)
     510          50 :                 summary.count++;
     511          50 :             break;
     512             : 
     513           0 :         case SWQCF_NONE:
     514           0 :             break;
     515             : 
     516           0 :         case SWQCF_CUSTOM:
     517           0 :             return "swq_select_summarize() called on custom field function.";
     518             : 
     519           0 :         default:
     520           0 :             return "swq_select_summarize() - unexpected col_func";
     521             :     }
     522             : 
     523         183 :     return nullptr;
     524             : }
     525             : 
     526             : /************************************************************************/
     527             : /*                      sort comparison functions.                      */
     528             : /************************************************************************/
     529             : 
     530        1069 : static bool Compare(swq_field_type eType, const CPLString &a,
     531             :                     const CPLString &b)
     532             : {
     533        1069 :     if (a == SZ_OGR_NULL)
     534          52 :         return b != SZ_OGR_NULL;
     535        1017 :     else if (b == SZ_OGR_NULL)
     536          24 :         return false;
     537             :     else
     538             :     {
     539         993 :         if (eType == SWQ_INTEGER64)
     540         160 :             return CPLAtoGIntBig(a) < CPLAtoGIntBig(b);
     541         833 :         else if (eType == SWQ_FLOAT)
     542         538 :             return CPLAtof(a) < CPLAtof(b);
     543         295 :         else if (eType == SWQ_STRING)
     544         295 :             return a < b;
     545             :         else
     546             :         {
     547           0 :             CPLAssert(false);
     548             :             return false;
     549             :         }
     550             :     }
     551             : }
     552             : 
     553             : #ifndef DOXYGEN_SKIP
     554        1069 : bool swq_summary::Comparator::operator()(const CPLString &a,
     555             :                                          const CPLString &b) const
     556             : {
     557        1069 :     if (bSortAsc)
     558             :     {
     559         728 :         return Compare(eType, a, b);
     560             :     }
     561             :     else
     562             :     {
     563         341 :         return Compare(eType, b, a);
     564             :     }
     565             : }
     566             : #endif
     567             : 
     568             : /************************************************************************/
     569             : /*                         swq_identify_field()                         */
     570             : /************************************************************************/
     571             : int swq_identify_field_internal(const char *table_name, const char *field_token,
     572             :                                 swq_field_list *field_list,
     573             :                                 swq_field_type *this_type, int *table_id,
     574             :                                 int bOneMoreTimeOK);
     575             : 
     576       22026 : int swq_identify_field(const char *table_name, const char *field_token,
     577             :                        swq_field_list *field_list, swq_field_type *this_type,
     578             :                        int *table_id)
     579             : 
     580             : {
     581       22026 :     return swq_identify_field_internal(table_name, field_token, field_list,
     582       22026 :                                        this_type, table_id, TRUE);
     583             : }
     584             : 
     585       22032 : int swq_identify_field_internal(const char *table_name, const char *field_token,
     586             :                                 swq_field_list *field_list,
     587             :                                 swq_field_type *this_type, int *table_id,
     588             :                                 int bOneMoreTimeOK)
     589             : 
     590             : {
     591       22032 :     if (table_name == nullptr)
     592        7770 :         table_name = "";
     593             : 
     594             :     int tables_enabled;
     595             : 
     596       22032 :     if (field_list->table_count > 0 && field_list->table_ids != nullptr)
     597       14592 :         tables_enabled = TRUE;
     598             :     else
     599        7440 :         tables_enabled = FALSE;
     600             : 
     601             :     /* -------------------------------------------------------------------- */
     602             :     /*      Search for matching field.                                      */
     603             :     /* -------------------------------------------------------------------- */
     604       24042 :     for (int pass = 0; pass < 2; ++pass)
     605             :     {
     606      194825 :         for (int i = 0; i < field_list->count; i++)
     607             :         {
     608      192815 :             if ((pass == 0 && strcmp(field_list->names[i], field_token) != 0) ||
     609        7342 :                 (pass == 1 && !EQUAL(field_list->names[i], field_token)))
     610             :             {
     611      171011 :                 continue;
     612             :             }
     613             : 
     614       21804 :             int t_id = 0;
     615             : 
     616             :             // Do the table specifications match?/
     617       21804 :             if (tables_enabled)
     618             :             {
     619       14365 :                 t_id = field_list->table_ids[i];
     620       14365 :                 if (table_name[0] != '\0' &&
     621       12794 :                     !EQUAL(table_name,
     622             :                            field_list->table_defs[t_id].table_alias))
     623          87 :                     continue;
     624             : 
     625             :                 // if( t_id != 0 && table_name[0] == '\0' )
     626             :                 //     continue;
     627             :             }
     628        7439 :             else if (table_name[0] != '\0')
     629           0 :                 break;
     630             : 
     631             :             // We have a match, return various information.
     632       21717 :             if (this_type != nullptr)
     633             :             {
     634       21717 :                 if (field_list->types != nullptr)
     635       21717 :                     *this_type = field_list->types[i];
     636             :                 else
     637           0 :                     *this_type = SWQ_OTHER;
     638             :             }
     639             : 
     640       21717 :             if (table_id != nullptr)
     641       21717 :                 *table_id = t_id;
     642             : 
     643       21717 :             if (field_list->ids == nullptr)
     644        7439 :                 return i;
     645             :             else
     646       14278 :                 return field_list->ids[i];
     647             :         }
     648             :     }
     649             : 
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      When there is no ambiguity, try to accept quoting errors...     */
     652             :     /* -------------------------------------------------------------------- */
     653         629 :     if (bOneMoreTimeOK &&
     654         314 :         !CPLTestBool(CPLGetConfigOption("OGR_SQL_STRICT", "FALSE")))
     655             :     {
     656         314 :         if (table_name[0])
     657             :         {
     658             :             CPLString osAggregatedName(
     659           7 :                 CPLSPrintf("%s.%s", table_name, field_token));
     660             : 
     661             :             // Check there's no table called table_name, or a field called with
     662             :             // the aggregated name.
     663           7 :             int i = 0;  // Used after for.
     664          38 :             for (; i < field_list->count; i++)
     665             :             {
     666          36 :                 if (tables_enabled)
     667             :                 {
     668          36 :                     int t_id = field_list->table_ids[i];
     669          36 :                     if (EQUAL(table_name,
     670             :                               field_list->table_defs[t_id].table_alias))
     671           5 :                         break;
     672             :                 }
     673             :             }
     674           7 :             if (i == field_list->count)
     675             :             {
     676           2 :                 int ret = swq_identify_field_internal(nullptr, osAggregatedName,
     677             :                                                       field_list, this_type,
     678             :                                                       table_id, FALSE);
     679           2 :                 if (ret >= 0)
     680             :                 {
     681           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
     682             :                              "Passed field name %s.%s should have been "
     683             :                              "surrounded by double quotes. "
     684             :                              "Accepted since there is no ambiguity...",
     685             :                              table_name, field_token);
     686             :                 }
     687           2 :                 return ret;
     688             :             }
     689             :         }
     690             :         else
     691             :         {
     692             :             // If the fieldname is a.b (and there's no . in b), then
     693             :             // it might be an error in providing it as being quoted where it
     694             :             // should not have been quoted.
     695         307 :             const char *pszDot = strchr(field_token, '.');
     696         307 :             if (pszDot && strchr(pszDot + 1, '.') == nullptr)
     697             :             {
     698           8 :                 CPLString osTableName(field_token);
     699           4 :                 osTableName.resize(pszDot - field_token);
     700           4 :                 CPLString osFieldName(pszDot + 1);
     701             : 
     702           4 :                 int ret = swq_identify_field_internal(osTableName, osFieldName,
     703             :                                                       field_list, this_type,
     704             :                                                       table_id, FALSE);
     705           4 :                 if (ret >= 0)
     706             :                 {
     707           4 :                     CPLError(CE_Warning, CPLE_AppDefined,
     708             :                              "Passed field name %s should NOT have been "
     709             :                              "surrounded by double quotes. "
     710             :                              "Accepted since there is no ambiguity...",
     711             :                              field_token);
     712             :                 }
     713           4 :                 return ret;
     714             :             }
     715             :         }
     716             :     }
     717             : 
     718             :     /* -------------------------------------------------------------------- */
     719             :     /*      No match, return failure.                                       */
     720             :     /* -------------------------------------------------------------------- */
     721         309 :     if (this_type != nullptr)
     722         309 :         *this_type = SWQ_OTHER;
     723             : 
     724         309 :     if (table_id != nullptr)
     725         309 :         *table_id = 0;
     726             : 
     727         309 :     return -1;
     728             : }
     729             : 
     730             : /************************************************************************/
     731             : /*                          swq_expr_compile()                          */
     732             : /************************************************************************/
     733             : 
     734        4624 : CPLErr swq_expr_compile(const char *where_clause, int field_count,
     735             :                         char **field_names, swq_field_type *field_types,
     736             :                         int bCheck,
     737             :                         swq_custom_func_registrar *poCustomFuncRegistrar,
     738             :                         swq_expr_node **expr_out)
     739             : 
     740             : {
     741             :     swq_field_list field_list;
     742             : 
     743        4624 :     field_list.count = field_count;
     744        4624 :     field_list.names = field_names;
     745        4624 :     field_list.types = field_types;
     746        4624 :     field_list.table_ids = nullptr;
     747        4624 :     field_list.ids = nullptr;
     748             : 
     749        4624 :     field_list.table_count = 0;
     750        4624 :     field_list.table_defs = nullptr;
     751             : 
     752        4624 :     return swq_expr_compile2(where_clause, &field_list, bCheck,
     753        9248 :                              poCustomFuncRegistrar, expr_out);
     754             : }
     755             : 
     756             : /************************************************************************/
     757             : /*                       swq_fixup_expression()                         */
     758             : /************************************************************************/
     759             : 
     760       10325 : static void swq_fixup_expression(swq_expr_node *node)
     761             : {
     762       20650 :     std::queue<swq_expr_node *> nodes;
     763       10325 :     nodes.push(node);
     764       41919 :     while (!nodes.empty())
     765             :     {
     766       31594 :         node = nodes.front();
     767       31594 :         nodes.pop();
     768       31594 :         if (node->eNodeType == SNT_OPERATION)
     769             :         {
     770       10848 :             const swq_op eOp = node->nOperation;
     771       10848 :             if ((eOp == SWQ_OR || eOp == SWQ_AND) && node->nSubExprCount > 2)
     772             :             {
     773         320 :                 std::vector<swq_expr_node *> exprs;
     774        4815 :                 for (int i = 0; i < node->nSubExprCount; i++)
     775             :                 {
     776        4655 :                     swq_fixup_expression(node->papoSubExpr[i]);
     777        4655 :                     exprs.push_back(node->papoSubExpr[i]);
     778             :                 }
     779         160 :                 node->nSubExprCount = 0;
     780         160 :                 CPLFree(node->papoSubExpr);
     781         160 :                 node->papoSubExpr = nullptr;
     782             : 
     783         374 :                 while (exprs.size() > 2)
     784             :                 {
     785         428 :                     std::vector<swq_expr_node *> new_exprs;
     786        4706 :                     for (size_t i = 0; i < exprs.size(); i++)
     787             :                     {
     788        4492 :                         if (i + 1 < exprs.size())
     789             :                         {
     790        4335 :                             auto cur_expr = new swq_expr_node(eOp);
     791        4335 :                             cur_expr->field_type = SWQ_BOOLEAN;
     792        4335 :                             cur_expr->PushSubExpression(exprs[i]);
     793        4335 :                             cur_expr->PushSubExpression(exprs[i + 1]);
     794        4335 :                             i++;
     795        4335 :                             new_exprs.push_back(cur_expr);
     796             :                         }
     797             :                         else
     798             :                         {
     799         157 :                             new_exprs.push_back(exprs[i]);
     800             :                         }
     801             :                     }
     802         214 :                     exprs = std::move(new_exprs);
     803             :                 }
     804         160 :                 CPLAssert(exprs.size() == 2);
     805         160 :                 node->PushSubExpression(exprs[0]);
     806         320 :                 node->PushSubExpression(exprs[1]);
     807             :             }
     808             :             else
     809             :             {
     810       31957 :                 for (int i = 0; i < node->nSubExprCount; i++)
     811             :                 {
     812       21269 :                     nodes.push(node->papoSubExpr[i]);
     813             :                 }
     814             :             }
     815             :         }
     816             :     }
     817       10325 : }
     818             : 
     819             : /************************************************************************/
     820             : /*                       swq_fixup_expression()                         */
     821             : /************************************************************************/
     822             : 
     823        7182 : void swq_fixup(swq_parse_context *psParseContext)
     824             : {
     825        7182 :     if (psParseContext->poRoot)
     826             :     {
     827        4622 :         swq_fixup_expression(psParseContext->poRoot);
     828             :     }
     829        7182 :     auto psSelect = psParseContext->poCurSelect;
     830        9747 :     while (psSelect)
     831             :     {
     832        2565 :         if (psSelect->where_expr)
     833             :         {
     834        1048 :             swq_fixup_expression(psSelect->where_expr);
     835             :         }
     836        2565 :         psSelect = psSelect->poOtherSelect;
     837             :     }
     838        7182 : }
     839             : 
     840             : /************************************************************************/
     841             : /*                       swq_create_and_or_or()                         */
     842             : /************************************************************************/
     843             : 
     844        4659 : swq_expr_node *swq_create_and_or_or(swq_op op, swq_expr_node *left,
     845             :                                     swq_expr_node *right)
     846             : {
     847        4659 :     auto poNode = new swq_expr_node(op);
     848        4659 :     poNode->field_type = SWQ_BOOLEAN;
     849             : 
     850        4659 :     if (left->eNodeType == SNT_OPERATION && left->nOperation == op)
     851             :     {
     852             :         // Temporary non-binary formulation
     853        4320 :         if (right->eNodeType == SNT_OPERATION && right->nOperation == op)
     854             :         {
     855           7 :             poNode->nSubExprCount = left->nSubExprCount + right->nSubExprCount;
     856           7 :             poNode->papoSubExpr = static_cast<swq_expr_node **>(
     857          14 :                 CPLRealloc(left->papoSubExpr,
     858           7 :                            sizeof(swq_expr_node *) * poNode->nSubExprCount));
     859           7 :             memcpy(poNode->papoSubExpr + left->nSubExprCount,
     860           7 :                    right->papoSubExpr,
     861           7 :                    right->nSubExprCount * sizeof(swq_expr_node *));
     862             : 
     863           7 :             right->nSubExprCount = 0;
     864           7 :             CPLFree(right->papoSubExpr);
     865           7 :             right->papoSubExpr = nullptr;
     866           7 :             delete right;
     867             :         }
     868             :         else
     869             :         {
     870        4313 :             poNode->nSubExprCount = left->nSubExprCount;
     871        4313 :             poNode->papoSubExpr = left->papoSubExpr;
     872        4313 :             poNode->PushSubExpression(right);
     873             :         }
     874             : 
     875        4320 :         left->nSubExprCount = 0;
     876        4320 :         left->papoSubExpr = nullptr;
     877        4320 :         delete left;
     878             :     }
     879         339 :     else if (right->eNodeType == SNT_OPERATION && right->nOperation == op)
     880             :     {
     881             :         // Temporary non-binary formulation
     882           8 :         poNode->nSubExprCount = right->nSubExprCount;
     883           8 :         poNode->papoSubExpr = right->papoSubExpr;
     884           8 :         poNode->PushSubExpression(left);
     885             : 
     886           8 :         right->nSubExprCount = 0;
     887           8 :         right->papoSubExpr = nullptr;
     888           8 :         delete right;
     889             :     }
     890             :     else
     891             :     {
     892         331 :         poNode->PushSubExpression(left);
     893         331 :         poNode->PushSubExpression(right);
     894             :     }
     895             : 
     896        4659 :     return poNode;
     897             : }
     898             : 
     899             : /************************************************************************/
     900             : /*                         swq_expr_compile2()                          */
     901             : /************************************************************************/
     902             : 
     903        4624 : CPLErr swq_expr_compile2(const char *where_clause, swq_field_list *field_list,
     904             :                          int bCheck,
     905             :                          swq_custom_func_registrar *poCustomFuncRegistrar,
     906             :                          swq_expr_node **expr_out)
     907             : 
     908             : {
     909        4624 :     swq_parse_context context;
     910             : 
     911        4624 :     context.pszInput = where_clause;
     912        4624 :     context.pszNext = where_clause;
     913        4624 :     context.pszLastValid = where_clause;
     914        4624 :     context.nStartToken = SWQT_VALUE_START;
     915        4624 :     context.bAcceptCustomFuncs = poCustomFuncRegistrar != nullptr;
     916             : 
     917        9244 :     if (swqparse(&context) == 0 && bCheck &&
     918        4620 :         context.poRoot->Check(field_list, FALSE, FALSE,
     919             :                               poCustomFuncRegistrar) != SWQ_ERROR)
     920             :     {
     921        4590 :         *expr_out = context.poRoot;
     922             : 
     923        4590 :         return CE_None;
     924             :     }
     925             :     else
     926             :     {
     927          34 :         delete context.poRoot;
     928          34 :         *expr_out = nullptr;
     929          34 :         return CE_Failure;
     930             :     }
     931             : }
     932             : 
     933             : /************************************************************************/
     934             : /*                        swq_is_reserved_keyword()                     */
     935             : /************************************************************************/
     936             : 
     937             : static const char *const apszSQLReservedKeywords[] = {
     938             :     "OR",    "AND",      "NOT",    "LIKE",   "IS",   "NULL", "IN",    "BETWEEN",
     939             :     "CAST",  "DISTINCT", "ESCAPE", "SELECT", "LEFT", "JOIN", "WHERE", "ON",
     940             :     "ORDER", "BY",       "FROM",   "AS",     "ASC",  "DESC", "UNION", "ALL"};
     941             : 
     942        1236 : int swq_is_reserved_keyword(const char *pszStr)
     943             : {
     944       30846 :     for (const auto &pszKeyword : apszSQLReservedKeywords)
     945             :     {
     946       29619 :         if (EQUAL(pszStr, pszKeyword))
     947           9 :             return TRUE;
     948             :     }
     949        1227 :     return FALSE;
     950             : }
     951             : 
     952             : /************************************************************************/
     953             : /*                          SWQFieldTypeToString()                      */
     954             : /************************************************************************/
     955             : 
     956           4 : const char *SWQFieldTypeToString(swq_field_type field_type)
     957             : {
     958           4 :     switch (field_type)
     959             :     {
     960           1 :         case SWQ_INTEGER:
     961           1 :             return "integer";
     962           0 :         case SWQ_INTEGER64:
     963           0 :             return "bigint";
     964           0 :         case SWQ_FLOAT:
     965           0 :             return "float";
     966           2 :         case SWQ_STRING:
     967           2 :             return "string";
     968           0 :         case SWQ_BOOLEAN:
     969           0 :             return "boolean";
     970           0 :         case SWQ_DATE:
     971           0 :             return "date";
     972           0 :         case SWQ_TIME:
     973           0 :             return "time";
     974           0 :         case SWQ_TIMESTAMP:
     975           0 :             return "timestamp";
     976           1 :         case SWQ_GEOMETRY:
     977           1 :             return "geometry";
     978           0 :         case SWQ_NULL:
     979           0 :             return "null";
     980           0 :         default:
     981           0 :             return "unknown";
     982             :     }
     983             : }

Generated by: LCOV version 1.14