1 %{
2 /******************************************************************************
3  *
4  * Component: OGR SQL Engine
5  * Purpose: expression and select parser grammar.
6  *          Requires Bison 2.4.0 or newer to process.  Use "make parser" target.
7  * Author: Frank Warmerdam <warmerdam@pobox.com>
8  *
9  ******************************************************************************
10  * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #include "cpl_port.h"
32 #include "ogr_swq.h"
33 
34 #include <cstdlib>
35 #include <cstring>
36 #include <limits>
37 
38 #include "cpl_conv.h"
39 #include "cpl_error.h"
40 #include "cpl_string.h"
41 #include "ogr_core.h"
42 #include "ogr_geometry.h"
43 
44 CPL_CVSID("$Id$")
45 
46 #define YYSTYPE swq_expr_node *
47 
48 /* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */
49 /* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */
50 /* increase YYINITDEPTH instead, but this will consume memory. */
51 /* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */
52 /* it appears to be a non documented feature of Bison */
53 #define YYSTYPE_IS_TRIVIAL 1
54 %}
55 
56 %define api.pure
57 /* if the next %define is commented out, Bison 2.4 should be sufficient */
58 /* but will produce less prettier error messages */
59 %define parse.error verbose
60 %require "3.0"
61 
62 %parse-param {swq_parse_context *context}
63 %lex-param {swq_parse_context *context}
64 
65 %token SWQT_INTEGER_NUMBER      "integer number"
66 %token SWQT_FLOAT_NUMBER        "floating point number"
67 %token SWQT_STRING              "string"
68 %token SWQT_IDENTIFIER          "identifier"
69 %token SWQT_IN                  "IN"
70 %token SWQT_LIKE                "LIKE"
71 %token SWQT_ILIKE               "ILIKE"
72 %token SWQT_ESCAPE              "ESCAPE"
73 %token SWQT_BETWEEN             "BETWEEN"
74 %token SWQT_NULL                "NULL"
75 %token SWQT_IS                  "IS"
76 %token SWQT_SELECT              "SELECT"
77 %token SWQT_LEFT                "LEFT"
78 %token SWQT_JOIN                "JOIN"
79 %token SWQT_WHERE               "WHERE"
80 %token SWQT_ON                  "ON"
81 %token SWQT_ORDER               "ORDER"
82 %token SWQT_BY                  "BY"
83 %token SWQT_FROM                "FROM"
84 %token SWQT_AS                  "AS"
85 %token SWQT_ASC                 "ASC"
86 %token SWQT_DESC                "DESC"
87 %token SWQT_DISTINCT            "DISTINCT"
88 %token SWQT_CAST                "CAST"
89 %token SWQT_UNION               "UNION"
90 %token SWQT_ALL                 "ALL"
91 %token SWQT_LIMIT               "LIMIT"
92 %token SWQT_OFFSET              "OFFSET"
93 
94 %token SWQT_VALUE_START
95 %token SWQT_SELECT_START
96 
97 %token END 0                    "end of string"
98 
99 %token SWQT_NOT                 "NOT"
100 %token SWQT_OR                  "OR"
101 %token SWQT_AND                 "AND"
102 
103 %left SWQT_OR
104 %left SWQT_AND
105 %left SWQT_NOT
106 
107 %left '=' '<' '>' '!' SWQT_BETWEEN SWQT_IN SWQT_LIKE SWQT_ILIKE SWQT_IS
108 %left SWQT_ESCAPE
109 
110 %left '+' '-'
111 %left '*' '/' '%'
112 %left SWQT_UMINUS
113 
114 %token SWQT_RESERVED_KEYWORD    "reserved keyword"
115 
116 /* Any grammar rule that does $$ = must be listed afterwards */
117 /* as well as SWQT_INTEGER_NUMBER SWQT_FLOAT_NUMBER SWQT_STRING SWQT_IDENTIFIER that are allocated by swqlex() */
118 %destructor { delete $$; } SWQT_INTEGER_NUMBER SWQT_FLOAT_NUMBER SWQT_STRING SWQT_IDENTIFIER
119 %destructor { delete $$; } value_expr_list field_value value_expr value_expr_non_logical type_def table_def
120 
121 %%
122 
123 input:
124     | SWQT_VALUE_START value_expr
125         {
126             context->poRoot = $2;
127             swq_fixup(context);
128         }
129 
130     | SWQT_SELECT_START select_statement
131         {
132             context->poRoot = $2;
133             swq_fixup(context);
134         }
135 
136 value_expr:
137     value_expr_non_logical
138         {
139             $$ = $1;
140         }
141 
142     | value_expr SWQT_AND value_expr
143         {
144             $$ = swq_create_and_or_or( SWQ_AND, $1, $3 );
145         }
146 
147     | value_expr SWQT_OR value_expr
148         {
149             $$ = swq_create_and_or_or( SWQ_OR, $1, $3 );
150         }
151 
152     | SWQT_NOT value_expr
153         {
154             $$ = new swq_expr_node( SWQ_NOT );
155             $$->field_type = SWQ_BOOLEAN;
156             $$->PushSubExpression( $2 );
157         }
158 
159     | value_expr '=' value_expr
160         {
161             $$ = new swq_expr_node( SWQ_EQ );
162             $$->field_type = SWQ_BOOLEAN;
163             $$->PushSubExpression( $1 );
164             $$->PushSubExpression( $3 );
165         }
166 
167     | value_expr '<' '>' value_expr
168         {
169             $$ = new swq_expr_node( SWQ_NE );
170             $$->field_type = SWQ_BOOLEAN;
171             $$->PushSubExpression( $1 );
172             $$->PushSubExpression( $4 );
173         }
174 
175     | value_expr '!' '=' value_expr
176         {
177             $$ = new swq_expr_node( SWQ_NE );
178             $$->field_type = SWQ_BOOLEAN;
179             $$->PushSubExpression( $1 );
180             $$->PushSubExpression( $4 );
181         }
182 
183     | value_expr '<' value_expr
184         {
185             $$ = new swq_expr_node( SWQ_LT );
186             $$->field_type = SWQ_BOOLEAN;
187             $$->PushSubExpression( $1 );
188             $$->PushSubExpression( $3 );
189         }
190 
191     | value_expr '>' value_expr
192         {
193             $$ = new swq_expr_node( SWQ_GT );
194             $$->field_type = SWQ_BOOLEAN;
195             $$->PushSubExpression( $1 );
196             $$->PushSubExpression( $3 );
197         }
198 
199     | value_expr '<' '=' value_expr
200         {
201             $$ = new swq_expr_node( SWQ_LE );
202             $$->field_type = SWQ_BOOLEAN;
203             $$->PushSubExpression( $1 );
204             $$->PushSubExpression( $4 );
205         }
206 
207     | value_expr '=' '<' value_expr
208         {
209             $$ = new swq_expr_node( SWQ_LE );
210             $$->field_type = SWQ_BOOLEAN;
211             $$->PushSubExpression( $1 );
212             $$->PushSubExpression( $4 );
213         }
214 
215     | value_expr '=' '>' value_expr
216         {
217             $$ = new swq_expr_node( SWQ_LE );
218             $$->field_type = SWQ_BOOLEAN;
219             $$->PushSubExpression( $1 );
220             $$->PushSubExpression( $4 );
221         }
222 
223     | value_expr '>' '=' value_expr
224         {
225             $$ = new swq_expr_node( SWQ_GE );
226             $$->field_type = SWQ_BOOLEAN;
227             $$->PushSubExpression( $1 );
228             $$->PushSubExpression( $4 );
229         }
230 
231     | value_expr SWQT_LIKE value_expr
232         {
233             $$ = new swq_expr_node( SWQ_LIKE );
234             $$->field_type = SWQ_BOOLEAN;
235             $$->PushSubExpression( $1 );
236             $$->PushSubExpression( $3 );
237         }
238 
239     | value_expr SWQT_NOT SWQT_LIKE value_expr
240         {
241             swq_expr_node *like = new swq_expr_node( SWQ_LIKE );
242             like->field_type = SWQ_BOOLEAN;
243             like->PushSubExpression( $1 );
244             like->PushSubExpression( $4 );
245 
246             $$ = new swq_expr_node( SWQ_NOT );
247             $$->field_type = SWQ_BOOLEAN;
248             $$->PushSubExpression( like );
249         }
250 
251     | value_expr SWQT_LIKE value_expr SWQT_ESCAPE value_expr
252         {
253             $$ = new swq_expr_node( SWQ_LIKE );
254             $$->field_type = SWQ_BOOLEAN;
255             $$->PushSubExpression( $1 );
256             $$->PushSubExpression( $3 );
257             $$->PushSubExpression( $5 );
258         }
259 
260     | value_expr SWQT_NOT SWQT_LIKE value_expr SWQT_ESCAPE value_expr
261         {
262             swq_expr_node *like = new swq_expr_node( SWQ_LIKE );
263             like->field_type = SWQ_BOOLEAN;
264             like->PushSubExpression( $1 );
265             like->PushSubExpression( $4 );
266             like->PushSubExpression( $6 );
267 
268             $$ = new swq_expr_node( SWQ_NOT );
269             $$->field_type = SWQ_BOOLEAN;
270             $$->PushSubExpression( like );
271         }
272 
273     | value_expr SWQT_ILIKE value_expr
274         {
275             $$ = new swq_expr_node( SWQ_ILIKE );
276             $$->field_type = SWQ_BOOLEAN;
277             $$->PushSubExpression( $1 );
278             $$->PushSubExpression( $3 );
279         }
280 
281     | value_expr SWQT_NOT SWQT_ILIKE value_expr
282         {
283             swq_expr_node *like = new swq_expr_node( SWQ_ILIKE );
284             like->field_type = SWQ_BOOLEAN;
285             like->PushSubExpression( $1 );
286             like->PushSubExpression( $4 );
287 
288             $$ = new swq_expr_node( SWQ_NOT );
289             $$->field_type = SWQ_BOOLEAN;
290             $$->PushSubExpression( like );
291         }
292 
293     | value_expr SWQT_ILIKE value_expr SWQT_ESCAPE value_expr
294         {
295             $$ = new swq_expr_node( SWQ_ILIKE );
296             $$->field_type = SWQ_BOOLEAN;
297             $$->PushSubExpression( $1 );
298             $$->PushSubExpression( $3 );
299             $$->PushSubExpression( $5 );
300         }
301 
302     | value_expr SWQT_NOT SWQT_ILIKE value_expr SWQT_ESCAPE value_expr
303         {
304             swq_expr_node *like = new swq_expr_node( SWQ_ILIKE );
305             like->field_type = SWQ_BOOLEAN;
306             like->PushSubExpression( $1 );
307             like->PushSubExpression( $4 );
308             like->PushSubExpression( $6 );
309 
310             $$ = new swq_expr_node( SWQ_NOT );
311             $$->field_type = SWQ_BOOLEAN;
312             $$->PushSubExpression( like );
313         }
314 
315     | value_expr SWQT_IN '(' value_expr_list ')'
316         {
317             $$ = $4;
318             $$->field_type = SWQ_BOOLEAN;
319             $$->nOperation = SWQ_IN;
320             $$->PushSubExpression( $1 );
321             $$->ReverseSubExpressions();
322         }
323 
324     | value_expr SWQT_NOT SWQT_IN '(' value_expr_list ')'
325         {
326             swq_expr_node *in = $5;
327             in->field_type = SWQ_BOOLEAN;
328             in->nOperation = SWQ_IN;
329             in->PushSubExpression( $1 );
330             in->ReverseSubExpressions();
331 
332             $$ = new swq_expr_node( SWQ_NOT );
333             $$->field_type = SWQ_BOOLEAN;
334             $$->PushSubExpression( in );
335         }
336 
337     | value_expr SWQT_BETWEEN value_expr_non_logical SWQT_AND value_expr_non_logical
338         {
339             $$ = new swq_expr_node( SWQ_BETWEEN );
340             $$->field_type = SWQ_BOOLEAN;
341             $$->PushSubExpression( $1 );
342             $$->PushSubExpression( $3 );
343             $$->PushSubExpression( $5 );
344         }
345 
346     | value_expr SWQT_NOT SWQT_BETWEEN value_expr_non_logical SWQT_AND value_expr_non_logical
347         {
348             swq_expr_node *between = new swq_expr_node( SWQ_BETWEEN );
349             between->field_type = SWQ_BOOLEAN;
350             between->PushSubExpression( $1 );
351             between->PushSubExpression( $4 );
352             between->PushSubExpression( $6 );
353 
354             $$ = new swq_expr_node( SWQ_NOT );
355             $$->field_type = SWQ_BOOLEAN;
356             $$->PushSubExpression( between );
357         }
358 
359     | value_expr SWQT_IS SWQT_NULL
360         {
361             $$ = new swq_expr_node( SWQ_ISNULL );
362             $$->field_type = SWQ_BOOLEAN;
363             $$->PushSubExpression( $1 );
364         }
365 
366     | value_expr SWQT_IS SWQT_NOT SWQT_NULL
367         {
368             swq_expr_node *isnull = new swq_expr_node( SWQ_ISNULL );
369             isnull->field_type = SWQ_BOOLEAN;
370             isnull->PushSubExpression( $1 );
371 
372             $$ = new swq_expr_node( SWQ_NOT );
373             $$->field_type = SWQ_BOOLEAN;
374             $$->PushSubExpression( isnull );
375         }
376 
377 value_expr_list:
378     value_expr ',' value_expr_list
379         {
380             $$ = $3;
381             $3->PushSubExpression( $1 );
382         }
383 
384     | value_expr
385             {
386             $$ = new swq_expr_node( SWQ_ARGUMENT_LIST ); /* temporary value */
387             $$->PushSubExpression( $1 );
388         }
389 
390 field_value:
391     SWQT_IDENTIFIER
392         {
393             $$ = $1;  // validation deferred.
394             $$->eNodeType = SNT_COLUMN;
395             $$->field_index = -1;
396             $$->table_index = -1;
397         }
398 
399     | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
400         {
401             $$ = $1;  // validation deferred.
402             $$->eNodeType = SNT_COLUMN;
403             $$->field_index = -1;
404             $$->table_index = -1;
405             $$->table_name = $$->string_value;
406             $$->string_value = CPLStrdup($3->string_value);
407             delete $3;
408             $3 = nullptr;
409         }
410 
411 value_expr_non_logical:
412     SWQT_INTEGER_NUMBER
413         {
414             $$ = $1;
415         }
416 
417     | SWQT_FLOAT_NUMBER
418         {
419             $$ = $1;
420         }
421 
422     | SWQT_STRING
423         {
424             $$ = $1;
425         }
426     | field_value
427         {
428             $$ = $1;
429         }
430 
431     | '(' value_expr ')'
432         {
433             $$ = $2;
434         }
435 
436     | SWQT_NULL
437         {
438             $$ = new swq_expr_node(static_cast<const char*>(nullptr));
439         }
440 
441     | '-' value_expr_non_logical %prec SWQT_UMINUS
442         {
443             if ($2->eNodeType == SNT_CONSTANT)
444             {
445                 if( $2->field_type == SWQ_FLOAT &&
446                     $2->string_value &&
447                     strcmp($2->string_value, "9223372036854775808") == 0 )
448                 {
449                     $$ = $2;
450                     $$->field_type = SWQ_INTEGER64;
451                     $$->int_value = std::numeric_limits<GIntBig>::min();
452                     $$->float_value = static_cast<double>(std::numeric_limits<GIntBig>::min());
453                 }
454                 // - (-9223372036854775808) cannot be represented on int64
455                 // the classic overflow is that its negation is itself.
456                 else if( $2->field_type == SWQ_INTEGER64 &&
457                          $2->int_value == std::numeric_limits<GIntBig>::min() )
458                 {
459                     $$ = $2;
460                 }
461                 else
462                 {
463                     $$ = $2;
464                     $$->int_value *= -1;
465                     $$->float_value *= -1;
466                 }
467             }
468             else
469             {
470                 $$ = new swq_expr_node( SWQ_MULTIPLY );
471                 $$->PushSubExpression( new swq_expr_node(-1) );
472                 $$->PushSubExpression( $2 );
473             }
474         }
475 
476     | value_expr_non_logical '+' value_expr_non_logical
477         {
478             $$ = new swq_expr_node( SWQ_ADD );
479             $$->PushSubExpression( $1 );
480             $$->PushSubExpression( $3 );
481         }
482 
483     | value_expr_non_logical '-' value_expr_non_logical
484         {
485             $$ = new swq_expr_node( SWQ_SUBTRACT );
486             $$->PushSubExpression( $1 );
487             $$->PushSubExpression( $3 );
488         }
489 
490     | value_expr_non_logical '*' value_expr_non_logical
491         {
492             $$ = new swq_expr_node( SWQ_MULTIPLY );
493             $$->PushSubExpression( $1 );
494             $$->PushSubExpression( $3 );
495         }
496 
497     | value_expr_non_logical '/' value_expr_non_logical
498         {
499             $$ = new swq_expr_node( SWQ_DIVIDE );
500             $$->PushSubExpression( $1 );
501             $$->PushSubExpression( $3 );
502         }
503 
504     | value_expr_non_logical '%' value_expr_non_logical
505         {
506             $$ = new swq_expr_node( SWQ_MODULUS );
507             $$->PushSubExpression( $1 );
508             $$->PushSubExpression( $3 );
509         }
510 
511     | SWQT_IDENTIFIER '(' value_expr_list ')'
512         {
513             const swq_operation *poOp =
514                     swq_op_registrar::GetOperator( $1->string_value );
515 
516             if( poOp == nullptr )
517             {
518                 if( context->bAcceptCustomFuncs )
519                 {
520                     $$ = $3;
521                     $$->eNodeType = SNT_OPERATION;
522                     $$->nOperation = SWQ_CUSTOM_FUNC;
523                     $$->string_value = CPLStrdup($1->string_value);
524                     $$->ReverseSubExpressions();
525                     delete $1;
526                 }
527                 else
528                 {
529                     CPLError( CE_Failure, CPLE_AppDefined,
530                                     "Undefined function '%s' used.",
531                                     $1->string_value );
532                     delete $1;
533                     delete $3;
534                     YYERROR;
535                 }
536             }
537             else
538             {
539                 $$ = $3;
540                 $$->eNodeType = SNT_OPERATION;
541                 $$->nOperation = poOp->eOperation;
542                 $$->ReverseSubExpressions();
543                 delete $1;
544             }
545         }
546 
547     | SWQT_CAST '(' value_expr SWQT_AS type_def ')'
548         {
549             $$ = $5;
550             $$->PushSubExpression( $3 );
551             $$->ReverseSubExpressions();
552         }
553 
554 type_def:
555     SWQT_IDENTIFIER
556     {
557         $$ = new swq_expr_node( SWQ_CAST );
558         $$->PushSubExpression( $1 );
559     }
560 
561     | SWQT_IDENTIFIER '(' SWQT_INTEGER_NUMBER ')'
562     {
563         $$ = new swq_expr_node( SWQ_CAST );
564         $$->PushSubExpression( $3 );
565         $$->PushSubExpression( $1 );
566     }
567 
568     | SWQT_IDENTIFIER '(' SWQT_INTEGER_NUMBER ',' SWQT_INTEGER_NUMBER ')'
569     {
570         $$ = new swq_expr_node( SWQ_CAST );
571         $$->PushSubExpression( $5 );
572         $$->PushSubExpression( $3 );
573         $$->PushSubExpression( $1 );
574     }
575 
576     /* e.g. GEOMETRY(POINT) */
577     | SWQT_IDENTIFIER '(' SWQT_IDENTIFIER ')'
578     {
579         OGRwkbGeometryType eType = OGRFromOGCGeomType($3->string_value);
580         if( !EQUAL($1->string_value, "GEOMETRY") ||
581             (wkbFlatten(eType) == wkbUnknown &&
582             !STARTS_WITH_CI($3->string_value, "GEOMETRY")) )
583         {
584             yyerror (context, "syntax error");
585             delete $1;
586             delete $3;
587             YYERROR;
588         }
589         $$ = new swq_expr_node( SWQ_CAST );
590         $$->PushSubExpression( $3 );
591         $$->PushSubExpression( $1 );
592     }
593 
594     /* e.g. GEOMETRY(POINT,4326) */
595     | SWQT_IDENTIFIER '(' SWQT_IDENTIFIER ',' SWQT_INTEGER_NUMBER ')'
596     {
597         OGRwkbGeometryType eType = OGRFromOGCGeomType($3->string_value);
598         if( !EQUAL($1->string_value, "GEOMETRY") ||
599             (wkbFlatten(eType) == wkbUnknown &&
600             !STARTS_WITH_CI($3->string_value, "GEOMETRY")) )
601         {
602             yyerror (context, "syntax error");
603             delete $1;
604             delete $3;
605             delete $5;
606             YYERROR;
607         }
608         $$ = new swq_expr_node( SWQ_CAST );
609         $$->PushSubExpression( $5 );
610         $$->PushSubExpression( $3 );
611         $$->PushSubExpression( $1 );
612     }
613 
614 select_statement:
615     select_core opt_union_all
616     | '(' select_core ')' opt_union_all
617 
618 select_core:
619     SWQT_SELECT select_field_list SWQT_FROM table_def opt_joins opt_where opt_order_by opt_limit opt_offset
620     {
621         delete $4;
622     }
623 
624     | SWQT_SELECT SWQT_DISTINCT select_field_list SWQT_FROM table_def opt_joins opt_where opt_order_by opt_limit opt_offset
625     {
626         context->poCurSelect->query_mode = SWQM_DISTINCT_LIST;
627         delete $5;
628     }
629 
630 opt_union_all:
631     | union_all select_statement
632 
633 union_all: SWQT_UNION SWQT_ALL
634     {
635         swq_select* poNewSelect = new swq_select();
636         context->poCurSelect->PushUnionAll(poNewSelect);
637         context->poCurSelect = poNewSelect;
638     }
639 
640 select_field_list:
641     column_spec
642     | column_spec ',' select_field_list
643 
644 column_spec:
645     value_expr
646         {
647             if( !context->poCurSelect->PushField( $1 ) )
648             {
649                 delete $1;
650                 YYERROR;
651             }
652         }
653 
654     | value_expr as_clause
655         {
656             if( !context->poCurSelect->PushField( $1, $2->string_value ) )
657             {
658                 delete $1;
659                 delete $2;
660                 YYERROR;
661             }
662             delete $2;
663         }
664 
665     | '*'
666         {
667             swq_expr_node *poNode = new swq_expr_node();
668             poNode->eNodeType = SNT_COLUMN;
669             poNode->string_value = CPLStrdup( "*" );
670             poNode->table_index = -1;
671             poNode->field_index = -1;
672 
673             if( !context->poCurSelect->PushField( poNode ) )
674             {
675                 delete poNode;
676                 YYERROR;
677             }
678         }
679 
680     | SWQT_IDENTIFIER '.' '*'
681         {
682             CPLString osTableName = $1->string_value;
683 
684             delete $1;
685             $1 = nullptr;
686 
687             swq_expr_node *poNode = new swq_expr_node();
688             poNode->eNodeType = SNT_COLUMN;
689             poNode->table_name = CPLStrdup(osTableName );
690             poNode->string_value = CPLStrdup( "*" );
691             poNode->table_index = -1;
692             poNode->field_index = -1;
693 
694             if( !context->poCurSelect->PushField( poNode ) )
695             {
696                 delete poNode;
697                 YYERROR;
698             }
699         }
700 
701     | SWQT_IDENTIFIER '(' '*' ')'
702         {
703                 // special case for COUNT(*), confirm it.
704             if( !EQUAL($1->string_value, "COUNT") )
705             {
706                 CPLError( CE_Failure, CPLE_AppDefined,
707                         "Syntax Error with %s(*).",
708                         $1->string_value );
709                 delete $1;
710                 YYERROR;
711             }
712 
713             delete $1;
714             $1 = nullptr;
715 
716             swq_expr_node *poNode = new swq_expr_node();
717             poNode->eNodeType = SNT_COLUMN;
718             poNode->string_value = CPLStrdup( "*" );
719             poNode->table_index = -1;
720             poNode->field_index = -1;
721 
722             swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
723             count->PushSubExpression( poNode );
724 
725             if( !context->poCurSelect->PushField( count ) )
726             {
727                 delete count;
728                 YYERROR;
729             }
730         }
731 
732     | SWQT_IDENTIFIER '(' '*' ')' as_clause
733         {
734                 // special case for COUNT(*), confirm it.
735             if( !EQUAL($1->string_value, "COUNT") )
736             {
737                 CPLError( CE_Failure, CPLE_AppDefined,
738                         "Syntax Error with %s(*).",
739                         $1->string_value );
740                 delete $1;
741                 delete $5;
742                 YYERROR;
743             }
744 
745             delete $1;
746             $1 = nullptr;
747 
748             swq_expr_node *poNode = new swq_expr_node();
749             poNode->eNodeType = SNT_COLUMN;
750             poNode->string_value = CPLStrdup( "*" );
751             poNode->table_index = -1;
752             poNode->field_index = -1;
753 
754             swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
755             count->PushSubExpression( poNode );
756 
757             if( !context->poCurSelect->PushField( count, $5->string_value ) )
758             {
759                 delete count;
760                 delete $5;
761                 YYERROR;
762             }
763 
764             delete $5;
765         }
766 
767     | SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')'
768         {
769                 // special case for COUNT(DISTINCT x), confirm it.
770             if( !EQUAL($1->string_value, "COUNT") )
771             {
772                 CPLError(
773                     CE_Failure, CPLE_AppDefined,
774                     "DISTINCT keyword can only be used in COUNT() operator." );
775                 delete $1;
776                 delete $4;
777                     YYERROR;
778             }
779 
780             delete $1;
781 
782             swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
783             count->PushSubExpression( $4 );
784 
785             if( !context->poCurSelect->PushField( count, nullptr, TRUE ) )
786             {
787                 delete count;
788                 YYERROR;
789             }
790         }
791 
792     | SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')' as_clause
793         {
794             // special case for COUNT(DISTINCT x), confirm it.
795             if( !EQUAL($1->string_value, "COUNT") )
796             {
797                 CPLError( CE_Failure, CPLE_AppDefined,
798                         "DISTINCT keyword can only be used in COUNT() operator." );
799                 delete $1;
800                 delete $4;
801                 delete $6;
802                 YYERROR;
803             }
804 
805             swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
806             count->PushSubExpression( $4 );
807 
808             if( !context->poCurSelect->PushField( count, $6->string_value, TRUE ) )
809             {
810                 delete $1;
811                 delete count;
812                 delete $6;
813                 YYERROR;
814             }
815 
816             delete $1;
817             delete $6;
818         }
819 
820 as_clause:
821     SWQT_AS SWQT_IDENTIFIER
822         {
823             delete $1;
824             $$ = $2;
825         }
826 
827     | SWQT_IDENTIFIER
828 
829 opt_where:
830     | SWQT_WHERE value_expr
831         {
832             context->poCurSelect->where_expr = $2;
833         }
834 
835 opt_joins:
836     | SWQT_JOIN table_def SWQT_ON value_expr opt_joins
837         {
838             context->poCurSelect->PushJoin( static_cast<int>($2->int_value),
839                                             $4 );
840             delete $2;
841         }
842     | SWQT_LEFT SWQT_JOIN table_def SWQT_ON value_expr opt_joins
843         {
844             context->poCurSelect->PushJoin( static_cast<int>($3->int_value),
845                                             $5 );
846             delete $3;
847         }
848 
849 opt_order_by:
850     | SWQT_ORDER SWQT_BY sort_spec_list
851 
852 sort_spec_list:
853     sort_spec ',' sort_spec_list
854     | sort_spec
855 
856 sort_spec:
857     field_value
858         {
859             context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, TRUE );
860             delete $1;
861             $1 = nullptr;
862         }
863     | field_value SWQT_ASC
864         {
865             context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, TRUE );
866             delete $1;
867             $1 = nullptr;
868         }
869     | field_value SWQT_DESC
870         {
871             context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, FALSE );
872             delete $1;
873             $1 = nullptr;
874         }
875 
876 opt_limit:
877     | SWQT_LIMIT SWQT_INTEGER_NUMBER
878     {
879         context->poCurSelect->SetLimit( $2->int_value );
880         delete $2;
881         $2 = nullptr;
882     }
883 
884 opt_offset:
885     | SWQT_OFFSET SWQT_INTEGER_NUMBER
886     {
887         context->poCurSelect->SetOffset( $2->int_value );
888         delete $2;
889         $2 = nullptr;
890     }
891 
892 table_def:
893     SWQT_IDENTIFIER
894     {
895         const int iTable =
896             context->poCurSelect->PushTableDef( nullptr, $1->string_value,
897                                                 nullptr );
898         delete $1;
899 
900         $$ = new swq_expr_node( iTable );
901     }
902 
903     | SWQT_IDENTIFIER as_clause
904     {
905         const int iTable =
906             context->poCurSelect->PushTableDef( nullptr, $1->string_value,
907                                                 $2->string_value );
908         delete $1;
909         delete $2;
910 
911         $$ = new swq_expr_node( iTable );
912     }
913 
914     | SWQT_STRING '.' SWQT_IDENTIFIER
915     {
916         const int iTable =
917             context->poCurSelect->PushTableDef( $1->string_value,
918                                                 $3->string_value, nullptr );
919         delete $1;
920         delete $3;
921 
922         $$ = new swq_expr_node( iTable );
923     }
924 
925     | SWQT_STRING '.' SWQT_IDENTIFIER as_clause
926     {
927         const int iTable =
928             context->poCurSelect->PushTableDef( $1->string_value,
929                                                 $3->string_value,
930                                                 $4->string_value );
931         delete $1;
932         delete $3;
933         delete $4;
934 
935         $$ = new swq_expr_node( iTable );
936     }
937 
938     | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
939     {
940         const int iTable =
941             context->poCurSelect->PushTableDef( $1->string_value,
942                                                 $3->string_value, nullptr );
943         delete $1;
944         delete $3;
945 
946         $$ = new swq_expr_node( iTable );
947     }
948 
949     | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER as_clause
950     {
951         const int iTable =
952             context->poCurSelect->PushTableDef( $1->string_value,
953                                                 $3->string_value,
954                                                 $4->string_value );
955         delete $1;
956         delete $3;
957         delete $4;
958 
959         $$ = new swq_expr_node( iTable );
960     }
961