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