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 :
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 : #include "swq.h"
35 :
36 : #define YYSTYPE swq_expr_node*
37 :
38 : /* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */
39 : /* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */
40 : /* increase YYINITDEPTH instead, but this will consume memory. */
41 : /* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */
42 : /* it appears to be a non documented feature of Bison */
43 : #define YYSTYPE_IS_TRIVIAL 1
44 :
45 81 : static void swqerror( swq_parse_context *context, const char *msg )
46 : {
47 : CPLError( CE_Failure, CPLE_AppDefined,
48 81 : "SQL Expression Parsing Error: %s", msg );
49 81 : }
50 :
51 : %}
52 :
53 : %define api.pure
54 : %require "2.4.0"
55 :
56 : %parse-param {swq_parse_context *context}
57 : %lex-param {swq_parse_context *context}
58 :
59 : %token SWQT_NUMBER
60 : %token SWQT_STRING
61 : %token SWQT_IDENTIFIER
62 : %token SWQT_IN
63 : %token SWQT_LIKE
64 : %token SWQT_ESCAPE
65 : %token SWQT_BETWEEN
66 : %token SWQT_NULL
67 : %token SWQT_IS
68 : %token SWQT_SELECT
69 : %token SWQT_LEFT
70 : %token SWQT_JOIN
71 : %token SWQT_WHERE
72 : %token SWQT_ON
73 : %token SWQT_ORDER
74 : %token SWQT_BY
75 : %token SWQT_FROM
76 : %token SWQT_AS
77 : %token SWQT_ASC
78 : %token SWQT_DESC
79 : %token SWQT_DISTINCT
80 : %token SWQT_CAST
81 :
82 : %token SWQT_LOGICAL_START
83 : %token SWQT_VALUE_START
84 : %token SWQT_SELECT_START
85 :
86 : %left SWQT_NOT
87 : %left SWQT_OR
88 : %left SWQT_AND
89 22 :
90 69 : %left '+' '-'
91 : %left '*' '/' '%'
92 : %left SWQT_UMINUS
93 :
94 : /* Any grammar rule that does $$ = must be listed afterwards */
95 : /* as well as SWQT_NUMBER SWQT_STRING SWQT_IDENTIFIER that are allocated by swqlex() */
96 : %destructor { delete $$; } SWQT_NUMBER SWQT_STRING SWQT_IDENTIFIER
97 338 : %destructor { delete $$; } logical_expr value_expr_list field_value value_expr type_def string_or_identifier table_def
98 :
99 338 : %%
100 :
101 : input:
102 0 : SWQT_LOGICAL_START logical_expr
103 : {
104 0 : context->poRoot = $2;
105 : }
106 :
107 216 : | SWQT_VALUE_START value_expr
108 : {
109 216 : context->poRoot = $2;
110 : }
111 :
112 : | SWQT_SELECT_START select_statement
113 37 : {
114 37 : context->poRoot = $2;
115 37 : }
116 37 :
117 : logical_expr:
118 37 : logical_expr SWQT_AND logical_expr
119 : {
120 : $$ = new swq_expr_node( SWQ_AND );
121 6 : $$->field_type = SWQ_BOOLEAN;
122 6 : $$->PushSubExpression( $1 );
123 6 : $$->PushSubExpression( $3 );
124 6 : }
125 :
126 6 : | logical_expr SWQT_OR logical_expr
127 : {
128 : $$ = new swq_expr_node( SWQ_OR );
129 8 : $$->field_type = SWQ_BOOLEAN;
130 8 : $$->PushSubExpression( $1 );
131 8 : $$->PushSubExpression( $3 );
132 : }
133 8 :
134 : | SWQT_NOT logical_expr
135 : {
136 24 : $$ = new swq_expr_node( SWQ_NOT );
137 : $$->field_type = SWQ_BOOLEAN;
138 24 : $$->PushSubExpression( $2 );
139 : }
140 :
141 253 : | '(' logical_expr ')'
142 253 : {
143 253 : $$ = $2;
144 253 : }
145 :
146 253 : | value_expr '=' value_expr
147 : {
148 : $$ = new swq_expr_node( SWQ_EQ );
149 52 : $$->field_type = SWQ_BOOLEAN;
150 52 : $$->PushSubExpression( $1 );
151 52 : $$->PushSubExpression( $3 );
152 52 : }
153 :
154 52 : | value_expr '<' '>' value_expr
155 : {
156 : $$ = new swq_expr_node( SWQ_NE );
157 4 : $$->field_type = SWQ_BOOLEAN;
158 4 : $$->PushSubExpression( $1 );
159 4 : $$->PushSubExpression( $4 );
160 4 : }
161 :
162 4 : | value_expr '!' '=' value_expr
163 : {
164 : $$ = new swq_expr_node( SWQ_NE );
165 34 : $$->field_type = SWQ_BOOLEAN;
166 34 : $$->PushSubExpression( $1 );
167 34 : $$->PushSubExpression( $4 );
168 34 : }
169 :
170 34 : | value_expr '<' value_expr
171 : {
172 : $$ = new swq_expr_node( SWQ_LT );
173 35 : $$->field_type = SWQ_BOOLEAN;
174 35 : $$->PushSubExpression( $1 );
175 35 : $$->PushSubExpression( $3 );
176 35 : }
177 :
178 35 : | value_expr '>' value_expr
179 : {
180 : $$ = new swq_expr_node( SWQ_GT );
181 6 : $$->field_type = SWQ_BOOLEAN;
182 6 : $$->PushSubExpression( $1 );
183 6 : $$->PushSubExpression( $3 );
184 6 : }
185 :
186 6 : | value_expr '<' '=' value_expr
187 : {
188 : $$ = new swq_expr_node( SWQ_LE );
189 0 : $$->field_type = SWQ_BOOLEAN;
190 0 : $$->PushSubExpression( $1 );
191 0 : $$->PushSubExpression( $4 );
192 0 : }
193 :
194 0 : | value_expr '=' '<' value_expr
195 : {
196 : $$ = new swq_expr_node( SWQ_LE );
197 0 : $$->field_type = SWQ_BOOLEAN;
198 0 : $$->PushSubExpression( $1 );
199 0 : $$->PushSubExpression( $4 );
200 0 : }
201 :
202 0 : | value_expr '=' '>' value_expr
203 : {
204 : $$ = new swq_expr_node( SWQ_LE );
205 7 : $$->field_type = SWQ_BOOLEAN;
206 7 : $$->PushSubExpression( $1 );
207 7 : $$->PushSubExpression( $4 );
208 7 : }
209 :
210 7 : | value_expr '>' '=' value_expr
211 : {
212 : $$ = new swq_expr_node( SWQ_GE );
213 9 : $$->field_type = SWQ_BOOLEAN;
214 9 : $$->PushSubExpression( $1 );
215 9 : $$->PushSubExpression( $4 );
216 9 : }
217 :
218 9 : | value_expr SWQT_LIKE value_expr
219 : {
220 : $$ = new swq_expr_node( SWQ_LIKE );
221 : $$->field_type = SWQ_BOOLEAN;
222 1 : $$->PushSubExpression( $1 );
223 1 : $$->PushSubExpression( $3 );
224 1 : }
225 1 :
226 : | value_expr SWQT_NOT SWQT_LIKE value_expr
227 2 : {
228 1 : swq_expr_node *like;
229 1 : like = new swq_expr_node( SWQ_LIKE );
230 : like->field_type = SWQ_BOOLEAN;
231 1 : like->PushSubExpression( $1 );
232 : like->PushSubExpression( $4 );
233 :
234 2 : $$ = new swq_expr_node( SWQ_NOT );
235 2 : $$->field_type = SWQ_BOOLEAN;
236 2 : $$->PushSubExpression( like );
237 2 : }
238 2 :
239 : | value_expr SWQT_LIKE value_expr SWQT_ESCAPE value_expr
240 2 : {
241 : $$ = new swq_expr_node( SWQ_LIKE );
242 : $$->field_type = SWQ_BOOLEAN;
243 : $$->PushSubExpression( $1 );
244 0 : $$->PushSubExpression( $3 );
245 0 : $$->PushSubExpression( $5 );
246 0 : }
247 0 :
248 0 : | value_expr SWQT_NOT SWQT_LIKE value_expr SWQT_ESCAPE value_expr
249 : {
250 0 : swq_expr_node *like;
251 0 : like = new swq_expr_node( SWQ_LIKE );
252 0 : like->field_type = SWQ_BOOLEAN;
253 : like->PushSubExpression( $1 );
254 0 : like->PushSubExpression( $4 );
255 : like->PushSubExpression( $6 );
256 :
257 29 : $$ = new swq_expr_node( SWQ_NOT );
258 29 : $$->field_type = SWQ_BOOLEAN;
259 29 : $$->PushSubExpression( like );
260 29 : }
261 29 :
262 : | value_expr SWQT_IN '(' value_expr_list ')'
263 29 : {
264 : $$ = $4;
265 : $$->field_type = SWQ_BOOLEAN;
266 : $$->nOperation = SWQ_IN;
267 : $$->PushSubExpression( $1 );
268 1 : $$->ReverseSubExpressions();
269 1 : }
270 1 :
271 1 : | value_expr SWQT_NOT SWQT_IN '(' value_expr_list ')'
272 1 : {
273 : swq_expr_node *in;
274 1 :
275 1 : in = $5;
276 1 : in->field_type = SWQ_BOOLEAN;
277 : in->nOperation = SWQ_IN;
278 1 : in->PushSubExpression( $1 );
279 : in->ReverseSubExpressions();
280 :
281 3 : $$ = new swq_expr_node( SWQ_NOT );
282 3 : $$->field_type = SWQ_BOOLEAN;
283 3 : $$->PushSubExpression( in );
284 3 : }
285 3 :
286 : | value_expr SWQT_BETWEEN value_expr SWQT_AND value_expr
287 3 : {
288 : $$ = new swq_expr_node( SWQ_BETWEEN );
289 : $$->field_type = SWQ_BOOLEAN;
290 : $$->PushSubExpression( $1 );
291 1 : $$->PushSubExpression( $3 );
292 1 : $$->PushSubExpression( $5 );
293 1 : }
294 1 :
295 1 : | value_expr SWQT_NOT SWQT_BETWEEN value_expr SWQT_AND value_expr
296 : {
297 2 : swq_expr_node *between;
298 1 : between = new swq_expr_node( SWQ_BETWEEN );
299 1 : between->field_type = SWQ_BOOLEAN;
300 : between->PushSubExpression( $1 );
301 1 : between->PushSubExpression( $4 );
302 : between->PushSubExpression( $6 );
303 :
304 7 : $$ = new swq_expr_node( SWQ_NOT );
305 7 : $$->field_type = SWQ_BOOLEAN;
306 7 : $$->PushSubExpression( between );
307 : }
308 7 :
309 : | value_expr SWQT_IS SWQT_NULL
310 : {
311 : $$ = new swq_expr_node( SWQ_ISNULL );
312 : $$->field_type = SWQ_BOOLEAN;
313 3 : $$->PushSubExpression( $1 );
314 3 : }
315 3 :
316 : | value_expr SWQT_IS SWQT_NOT SWQT_NULL
317 6 : {
318 3 : swq_expr_node *isnull;
319 3 :
320 : isnull = new swq_expr_node( SWQ_ISNULL );
321 3 : isnull->field_type = SWQ_BOOLEAN;
322 : isnull->PushSubExpression( $1 );
323 :
324 : $$ = new swq_expr_node( SWQ_NOT );
325 27 : $$->field_type = SWQ_BOOLEAN;
326 27 : $$->PushSubExpression( isnull );
327 : }
328 27 :
329 : value_expr_list:
330 : value_expr ',' value_expr_list
331 63 : {
332 63 : $$ = $3;
333 : $3->PushSubExpression( $1 );
334 63 : }
335 :
336 : | value_expr
337 : {
338 1619 : $$ = new swq_expr_node( SWQ_UNKNOWN ); /* list */
339 1619 : $$->PushSubExpression( $1 );
340 1619 : }
341 :
342 1619 : field_value:
343 : SWQT_IDENTIFIER
344 : {
345 53 : $$ = $1; // validation deferred.
346 53 : $$->eNodeType = SNT_COLUMN;
347 53 : $$->field_index = $$->table_index = -1;
348 : }
349 :
350 : | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
351 53 : {
352 53 : $$ = $1; // validation deferred.
353 53 : $$->eNodeType = SNT_COLUMN;
354 53 : $$->field_index = $$->table_index = -1;
355 53 : $$->string_value = (char *)
356 : CPLRealloc( $$->string_value,
357 53 : strlen($$->string_value)
358 : + strlen($3->string_value) + 2 );
359 : strcat( $$->string_value, "." );
360 : strcat( $$->string_value, $3->string_value );
361 329 : delete $3;
362 : $3 = NULL;
363 329 : }
364 :
365 : value_expr:
366 189 : SWQT_NUMBER
367 : {
368 189 : $$ = $1;
369 : }
370 1579 :
371 : | SWQT_STRING
372 1579 : {
373 : $$ = $1;
374 : }
375 21 : | field_value
376 : {
377 21 : $$ = $1;
378 : }
379 :
380 5 : | '(' value_expr ')'
381 : {
382 5 : $$ = $2;
383 : }
384 :
385 5 : | SWQT_NULL
386 : {
387 4 : $$ = new swq_expr_node((const char*)NULL);
388 4 : }
389 4 :
390 : | '-' value_expr %prec SWQT_UMINUS
391 : {
392 : if ($2->eNodeType == SNT_CONSTANT)
393 1 : {
394 2 : $$ = $2;
395 1 : $$->int_value *= -1;
396 : $$->float_value *= -1;
397 : }
398 5 : else
399 : {
400 : $$ = new swq_expr_node( SWQ_MULTIPLY );
401 7 : $$->PushSubExpression( new swq_expr_node(-1) );
402 7 : $$->PushSubExpression( $2 );
403 7 : }
404 : }
405 7 :
406 : | value_expr '+' value_expr
407 : {
408 3 : $$ = new swq_expr_node( SWQ_ADD );
409 3 : $$->PushSubExpression( $1 );
410 3 : $$->PushSubExpression( $3 );
411 : }
412 3 :
413 : | value_expr '-' value_expr
414 : {
415 3 : $$ = new swq_expr_node( SWQ_SUBTRACT );
416 3 : $$->PushSubExpression( $1 );
417 3 : $$->PushSubExpression( $3 );
418 : }
419 3 :
420 : | value_expr '*' value_expr
421 : {
422 4 : $$ = new swq_expr_node( SWQ_MULTIPLY );
423 4 : $$->PushSubExpression( $1 );
424 4 : $$->PushSubExpression( $3 );
425 : }
426 4 :
427 : | value_expr '/' value_expr
428 : {
429 2 : $$ = new swq_expr_node( SWQ_DIVIDE );
430 2 : $$->PushSubExpression( $1 );
431 2 : $$->PushSubExpression( $3 );
432 : }
433 2 :
434 : | value_expr '%' value_expr
435 : {
436 : $$ = new swq_expr_node( SWQ_MODULUS );
437 30 : $$->PushSubExpression( $1 );
438 : $$->PushSubExpression( $3 );
439 30 : }
440 :
441 : | SWQT_IDENTIFIER '(' value_expr_list ')'
442 : {
443 0 : const swq_operation *poOp =
444 0 : swq_op_registrar::GetOperator( $1->string_value );
445 0 :
446 0 : if( poOp == NULL )
447 : {
448 : CPLError( CE_Failure, CPLE_AppDefined,
449 : "Undefined function '%s' used.",
450 30 : $1->string_value );
451 30 : delete $1;
452 30 : delete $3;
453 30 : YYERROR;
454 30 : }
455 : else
456 : {
457 30 : $$ = $3;
458 : $$->eNodeType = SNT_OPERATION;
459 : $$->nOperation = poOp->eOperation;
460 33 : $$->ReverseSubExpressions();
461 33 : delete $1;
462 33 : }
463 : }
464 33 :
465 : | SWQT_CAST '(' value_expr SWQT_AS type_def ')'
466 : {
467 : $$ = $5;
468 29 : $$->PushSubExpression( $3 );
469 29 : $$->ReverseSubExpressions();
470 : }
471 29 :
472 : type_def:
473 : SWQT_IDENTIFIER
474 6 : {
475 6 : $$ = new swq_expr_node( SWQ_CAST );
476 6 : $$->PushSubExpression( $1 );
477 : }
478 6 :
479 : | SWQT_IDENTIFIER '(' SWQT_NUMBER ')'
480 : {
481 1 : $$ = new swq_expr_node( SWQ_CAST );
482 1 : $$->PushSubExpression( $3 );
483 1 : $$->PushSubExpression( $1 );
484 1 : }
485 :
486 1 : | SWQT_IDENTIFIER '(' SWQT_NUMBER ',' SWQT_NUMBER ')'
487 : {
488 : $$ = new swq_expr_node( SWQ_CAST );
489 : $$->PushSubExpression( $5 );
490 216 : $$->PushSubExpression( $3 );
491 : $$->PushSubExpression( $1 );
492 216 : }
493 :
494 : select_statement:
495 : SWQT_SELECT select_field_list SWQT_FROM table_def opt_joins opt_where opt_order_by
496 : {
497 : delete $4;
498 : }
499 :
500 16 : select_field_list:
501 : column_spec
502 0 : | column_spec ',' select_field_list
503 0 :
504 : column_spec:
505 : SWQT_DISTINCT field_value
506 16 : {
507 : if( !context->poSelect->PushField( $2, NULL, TRUE ) )
508 : {
509 0 : delete $2;
510 : YYERROR;
511 0 : }
512 0 : }
513 :
514 : | SWQT_DISTINCT SWQT_STRING
515 0 : {
516 : if( !context->poSelect->PushField( $2, NULL, TRUE ) )
517 : {
518 1124 : delete $2;
519 : YYERROR;
520 5 : }
521 5 : }
522 :
523 : | value_expr
524 1119 : {
525 : if( !context->poSelect->PushField( $1 ) )
526 : {
527 2 : delete $1;
528 : YYERROR;
529 0 : }
530 0 : }
531 0 :
532 : | SWQT_DISTINCT field_value SWQT_AS string_or_identifier
533 : {
534 2 : if( !context->poSelect->PushField( $2, $4->string_value, TRUE ))
535 : {
536 2 : delete $2;
537 : delete $4;
538 : YYERROR;
539 5 : }
540 :
541 0 : delete $4;
542 0 : }
543 0 :
544 : | value_expr SWQT_AS string_or_identifier
545 5 : {
546 : if( !context->poSelect->PushField( $1, $3->string_value ) )
547 5 : {
548 : delete $1;
549 : delete $3;
550 94 : YYERROR;
551 94 : }
552 94 : delete $3;
553 94 : }
554 :
555 94 : | '*'
556 : {
557 0 : swq_expr_node *poNode = new swq_expr_node();
558 0 : poNode->eNodeType = SNT_COLUMN;
559 : poNode->string_value = CPLStrdup( "*" );
560 : poNode->table_index = poNode->field_index = -1;
561 94 :
562 : if( !context->poSelect->PushField( poNode ) )
563 : {
564 10 : delete poNode;
565 : YYERROR;
566 10 : }
567 10 : }
568 :
569 10 : | SWQT_IDENTIFIER '.' '*'
570 10 : {
571 : CPLString osQualifiedField;
572 10 :
573 10 : osQualifiedField = $1->string_value;
574 20 : osQualifiedField += ".*";
575 10 :
576 : delete $1;
577 10 : $1 = NULL;
578 :
579 0 : swq_expr_node *poNode = new swq_expr_node();
580 : poNode->eNodeType = SNT_COLUMN;
581 : poNode->string_value = CPLStrdup( osQualifiedField );
582 0 : poNode->table_index = poNode->field_index = -1;
583 10 :
584 : if( !context->poSelect->PushField( poNode ) )
585 : {
586 : delete poNode;
587 79 : YYERROR;
588 : }
589 : }
590 :
591 1 : | SWQT_IDENTIFIER '(' '*' ')'
592 1 : {
593 1 : // special case for COUNT(*), confirm it.
594 : if( !EQUAL($1->string_value,"COUNT") )
595 : {
596 78 : CPLError( CE_Failure, CPLE_AppDefined,
597 78 : "Syntax Error with %s(*).",
598 : $1->string_value );
599 78 : delete $1;
600 78 : YYERROR;
601 78 : }
602 78 :
603 : delete $1;
604 156 : $1 = NULL;
605 78 :
606 : swq_expr_node *poNode = new swq_expr_node();
607 78 : poNode->eNodeType = SNT_COLUMN;
608 : poNode->string_value = CPLStrdup( "*" );
609 0 : poNode->table_index = poNode->field_index = -1;
610 0 :
611 : swq_expr_node *count = new swq_expr_node( (swq_op)SWQ_COUNT );
612 : count->PushSubExpression( poNode );
613 78 :
614 : if( !context->poSelect->PushField( count ) )
615 : {
616 : delete count;
617 2 : YYERROR;
618 : }
619 : }
620 :
621 1 : | SWQT_IDENTIFIER '(' '*' ')' SWQT_AS string_or_identifier
622 1 : {
623 1 : // special case for COUNT(*), confirm it.
624 1 : if( !EQUAL($1->string_value,"COUNT") )
625 : {
626 : CPLError( CE_Failure, CPLE_AppDefined,
627 1 : "Syntax Error with %s(*).",
628 1 : $1->string_value );
629 : delete $1;
630 1 : delete $6;
631 1 : YYERROR;
632 1 : }
633 1 :
634 : delete $1;
635 2 : $1 = NULL;
636 1 :
637 : swq_expr_node *poNode = new swq_expr_node();
638 1 : poNode->eNodeType = SNT_COLUMN;
639 : poNode->string_value = CPLStrdup( "*" );
640 0 : poNode->table_index = poNode->field_index = -1;
641 0 :
642 0 : swq_expr_node *count = new swq_expr_node( (swq_op)SWQ_COUNT );
643 : count->PushSubExpression( poNode );
644 :
645 1 : if( !context->poSelect->PushField( count, $6->string_value ) )
646 : {
647 1 : delete count;
648 : delete $6;
649 : YYERROR;
650 : }
651 6 :
652 : delete $6;
653 : }
654 1 :
655 1 : | SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')'
656 1 : {
657 1 : // special case for COUNT(DISTINCT x), confirm it.
658 : if( !EQUAL($1->string_value,"COUNT") )
659 : {
660 5 : CPLError( CE_Failure, CPLE_AppDefined,
661 : "DISTINCT keyword can only be used in COUNT() operator." );
662 5 : delete $1;
663 5 : delete $4;
664 : YYERROR;
665 5 : }
666 :
667 0 : delete $1;
668 0 :
669 : swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
670 : count->PushSubExpression( $4 );
671 5 :
672 : if( !context->poSelect->PushField( count, NULL, TRUE ) )
673 : {
674 : delete count;
675 2 : YYERROR;
676 : }
677 : }
678 1 :
679 1 : | SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')' SWQT_AS string_or_identifier
680 1 : {
681 1 : // special case for COUNT(DISTINCT x), confirm it.
682 1 : if( !EQUAL($1->string_value,"COUNT") )
683 : {
684 : CPLError( CE_Failure, CPLE_AppDefined,
685 1 : "DISTINCT keyword can only be used in COUNT() operator." );
686 1 : delete $1;
687 : delete $4;
688 1 : delete $7;
689 : YYERROR;
690 0 : }
691 0 :
692 0 : swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
693 0 : count->PushSubExpression( $4 );
694 :
695 : if( !context->poSelect->PushField( count, $7->string_value, TRUE ) )
696 1 : {
697 1 : delete $1;
698 : delete count;
699 1 : delete $7;
700 : YYERROR;
701 : }
702 :
703 64 : delete $1;
704 : delete $7;
705 64 : }
706 :
707 : opt_where:
708 : | SWQT_WHERE logical_expr
709 0 : {
710 0 : context->poSelect->where_expr = $2;
711 0 : }
712 0 :
713 0 : opt_joins:
714 0 : | SWQT_JOIN table_def SWQT_ON field_value '=' field_value opt_joins
715 : {
716 0 : context->poSelect->PushJoin( $2->int_value,
717 : $4->string_value,
718 21 : $6->string_value );
719 21 : delete $2;
720 63 : delete $4;
721 21 : delete $6;
722 21 : }
723 21 : | SWQT_LEFT SWQT_JOIN table_def SWQT_ON field_value '=' field_value opt_joins
724 : {
725 21 : context->poSelect->PushJoin( $3->int_value,
726 : $5->string_value,
727 : $7->string_value );
728 : delete $3;
729 : delete $5;
730 : delete $7;
731 : }
732 :
733 : opt_order_by:
734 : | SWQT_ORDER SWQT_BY sort_spec_list
735 :
736 5 : sort_spec_list:
737 5 : sort_spec ',' sort_spec_list
738 5 : | sort_spec
739 :
740 5 : sort_spec:
741 : field_value
742 11 : {
743 11 : context->poSelect->PushOrderBy( $1->string_value, TRUE );
744 11 : delete $1;
745 : $1 = NULL;
746 11 : }
747 : | field_value SWQT_ASC
748 7 : {
749 7 : context->poSelect->PushOrderBy( $1->string_value, TRUE );
750 7 : delete $1;
751 : $1 = NULL;
752 7 : }
753 : | field_value SWQT_DESC
754 : {
755 : context->poSelect->PushOrderBy( $1->string_value, FALSE );
756 251 : delete $1;
757 : $1 = NULL;
758 251 : }
759 :
760 22 : string_or_identifier:
761 : SWQT_IDENTIFIER
762 22 : {
763 : $$ = $1;
764 : }
765 : | SWQT_STRING
766 : {
767 245 : $$ = $1;
768 245 : }
769 245 :
770 : table_def:
771 245 : string_or_identifier
772 : {
773 245 : int iTable;
774 : iTable =context->poSelect->PushTableDef( NULL, $1->string_value,
775 : NULL );
776 : delete $1;
777 12 :
778 24 : $$ = new swq_expr_node( iTable );
779 12 : }
780 12 :
781 : | string_or_identifier SWQT_IDENTIFIER
782 12 : {
783 : int iTable;
784 12 : iTable = context->poSelect->PushTableDef( NULL, $1->string_value,
785 : $2->string_value );
786 : delete $1;
787 : delete $2;
788 1 :
789 2 : $$ = new swq_expr_node( iTable );
790 1 : }
791 1 :
792 : | SWQT_STRING '.' string_or_identifier
793 1 : {
794 : int iTable;
795 1 : iTable = context->poSelect->PushTableDef( $1->string_value,
796 : $3->string_value, NULL );
797 : delete $1;
798 : delete $3;
799 4 :
800 4 : $$ = new swq_expr_node( iTable );
801 12 : }
802 4 :
803 4 : | SWQT_STRING '.' string_or_identifier SWQT_IDENTIFIER
804 4 : {
805 : int iTable;
806 4 : iTable = context->poSelect->PushTableDef( $1->string_value,
807 : $3->string_value,
808 : $4->string_value );
809 : delete $1;
810 : delete $3;
811 : delete $4;
812 :
813 : $$ = new swq_expr_node( iTable );
814 : }
|