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