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 170 : static void swqerror( swq_parse_context *context, const char *msg )
46 : {
47 : CPLError( CE_Failure, CPLE_AppDefined,
48 170 : "SQL Expression Parsing Error: %s", msg );
49 170 : }
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 52 :
90 138 : %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 982 : %destructor { delete $$; } logical_expr value_expr_list field_value value_expr type_def string_or_identifier table_def
98 :
99 982 : %%
100 :
101 : input:
102 0 : SWQT_LOGICAL_START logical_expr
103 : {
104 0 : context->poRoot = $2;
105 : }
106 :
107 720 : | SWQT_VALUE_START value_expr
108 : {
109 720 : context->poRoot = $2;
110 : }
111 :
112 : | SWQT_SELECT_START select_statement
113 476 : {
114 476 : context->poRoot = $2;
115 476 : }
116 476 :
117 : logical_expr:
118 476 : logical_expr SWQT_AND logical_expr
119 : {
120 : $$ = new swq_expr_node( SWQ_AND );
121 12 : $$->field_type = SWQ_BOOLEAN;
122 12 : $$->PushSubExpression( $1 );
123 12 : $$->PushSubExpression( $3 );
124 12 : }
125 :
126 12 : | logical_expr SWQT_OR logical_expr
127 : {
128 : $$ = new swq_expr_node( SWQ_OR );
129 16 : $$->field_type = SWQ_BOOLEAN;
130 16 : $$->PushSubExpression( $1 );
131 16 : $$->PushSubExpression( $3 );
132 : }
133 16 :
134 : | SWQT_NOT logical_expr
135 : {
136 452 : $$ = new swq_expr_node( SWQ_NOT );
137 : $$->field_type = SWQ_BOOLEAN;
138 452 : $$->PushSubExpression( $2 );
139 : }
140 :
141 1074 : | '(' logical_expr ')'
142 1074 : {
143 1074 : $$ = $2;
144 1074 : }
145 :
146 1074 : | value_expr '=' value_expr
147 : {
148 : $$ = new swq_expr_node( SWQ_EQ );
149 184 : $$->field_type = SWQ_BOOLEAN;
150 184 : $$->PushSubExpression( $1 );
151 184 : $$->PushSubExpression( $3 );
152 184 : }
153 :
154 184 : | value_expr '<' '>' value_expr
155 : {
156 : $$ = new swq_expr_node( SWQ_NE );
157 8 : $$->field_type = SWQ_BOOLEAN;
158 8 : $$->PushSubExpression( $1 );
159 8 : $$->PushSubExpression( $4 );
160 8 : }
161 :
162 8 : | value_expr '!' '=' value_expr
163 : {
164 : $$ = new swq_expr_node( SWQ_NE );
165 122 : $$->field_type = SWQ_BOOLEAN;
166 122 : $$->PushSubExpression( $1 );
167 122 : $$->PushSubExpression( $4 );
168 122 : }
169 :
170 122 : | value_expr '<' value_expr
171 : {
172 : $$ = new swq_expr_node( SWQ_LT );
173 132 : $$->field_type = SWQ_BOOLEAN;
174 132 : $$->PushSubExpression( $1 );
175 132 : $$->PushSubExpression( $3 );
176 132 : }
177 :
178 132 : | value_expr '>' value_expr
179 : {
180 : $$ = new swq_expr_node( SWQ_GT );
181 64 : $$->field_type = SWQ_BOOLEAN;
182 64 : $$->PushSubExpression( $1 );
183 64 : $$->PushSubExpression( $3 );
184 64 : }
185 :
186 64 : | 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 64 : $$->field_type = SWQ_BOOLEAN;
206 64 : $$->PushSubExpression( $1 );
207 64 : $$->PushSubExpression( $4 );
208 64 : }
209 :
210 64 : | value_expr '>' '=' value_expr
211 : {
212 : $$ = new swq_expr_node( SWQ_GE );
213 16 : $$->field_type = SWQ_BOOLEAN;
214 16 : $$->PushSubExpression( $1 );
215 16 : $$->PushSubExpression( $4 );
216 16 : }
217 :
218 16 : | value_expr SWQT_LIKE value_expr
219 : {
220 : $$ = new swq_expr_node( SWQ_LIKE );
221 : $$->field_type = SWQ_BOOLEAN;
222 2 : $$->PushSubExpression( $1 );
223 2 : $$->PushSubExpression( $3 );
224 2 : }
225 2 :
226 : | value_expr SWQT_NOT SWQT_LIKE value_expr
227 4 : {
228 2 : swq_expr_node *like;
229 2 : like = new swq_expr_node( SWQ_LIKE );
230 : like->field_type = SWQ_BOOLEAN;
231 2 : like->PushSubExpression( $1 );
232 : like->PushSubExpression( $4 );
233 :
234 4 : $$ = new swq_expr_node( SWQ_NOT );
235 4 : $$->field_type = SWQ_BOOLEAN;
236 4 : $$->PushSubExpression( like );
237 4 : }
238 4 :
239 : | value_expr SWQT_LIKE value_expr SWQT_ESCAPE value_expr
240 4 : {
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 82 : $$ = new swq_expr_node( SWQ_NOT );
258 82 : $$->field_type = SWQ_BOOLEAN;
259 82 : $$->PushSubExpression( like );
260 82 : }
261 82 :
262 : | value_expr SWQT_IN '(' value_expr_list ')'
263 82 : {
264 : $$ = $4;
265 : $$->field_type = SWQ_BOOLEAN;
266 : $$->nOperation = SWQ_IN;
267 : $$->PushSubExpression( $1 );
268 2 : $$->ReverseSubExpressions();
269 2 : }
270 2 :
271 2 : | value_expr SWQT_NOT SWQT_IN '(' value_expr_list ')'
272 2 : {
273 : swq_expr_node *in;
274 2 :
275 2 : in = $5;
276 2 : in->field_type = SWQ_BOOLEAN;
277 : in->nOperation = SWQ_IN;
278 2 : in->PushSubExpression( $1 );
279 : in->ReverseSubExpressions();
280 :
281 66 : $$ = new swq_expr_node( SWQ_NOT );
282 66 : $$->field_type = SWQ_BOOLEAN;
283 66 : $$->PushSubExpression( in );
284 66 : }
285 66 :
286 : | value_expr SWQT_BETWEEN value_expr SWQT_AND value_expr
287 66 : {
288 : $$ = new swq_expr_node( SWQ_BETWEEN );
289 : $$->field_type = SWQ_BOOLEAN;
290 : $$->PushSubExpression( $1 );
291 2 : $$->PushSubExpression( $3 );
292 2 : $$->PushSubExpression( $5 );
293 2 : }
294 2 :
295 2 : | value_expr SWQT_NOT SWQT_BETWEEN value_expr SWQT_AND value_expr
296 : {
297 4 : swq_expr_node *between;
298 2 : between = new swq_expr_node( SWQ_BETWEEN );
299 2 : between->field_type = SWQ_BOOLEAN;
300 : between->PushSubExpression( $1 );
301 2 : between->PushSubExpression( $4 );
302 : between->PushSubExpression( $6 );
303 :
304 14 : $$ = new swq_expr_node( SWQ_NOT );
305 14 : $$->field_type = SWQ_BOOLEAN;
306 14 : $$->PushSubExpression( between );
307 : }
308 14 :
309 : | value_expr SWQT_IS SWQT_NULL
310 : {
311 : $$ = new swq_expr_node( SWQ_ISNULL );
312 : $$->field_type = SWQ_BOOLEAN;
313 4 : $$->PushSubExpression( $1 );
314 4 : }
315 4 :
316 : | value_expr SWQT_IS SWQT_NOT SWQT_NULL
317 8 : {
318 4 : swq_expr_node *isnull;
319 4 :
320 : isnull = new swq_expr_node( SWQ_ISNULL );
321 4 : isnull->field_type = SWQ_BOOLEAN;
322 : isnull->PushSubExpression( $1 );
323 :
324 : $$ = new swq_expr_node( SWQ_NOT );
325 80 : $$->field_type = SWQ_BOOLEAN;
326 80 : $$->PushSubExpression( isnull );
327 : }
328 80 :
329 : value_expr_list:
330 : value_expr ',' value_expr_list
331 154 : {
332 154 : $$ = $3;
333 : $3->PushSubExpression( $1 );
334 154 : }
335 :
336 : | value_expr
337 : {
338 3796 : $$ = new swq_expr_node( SWQ_UNKNOWN ); /* list */
339 3796 : $$->PushSubExpression( $1 );
340 3796 : }
341 :
342 3796 : field_value:
343 : SWQT_IDENTIFIER
344 : {
345 114 : $$ = $1; // validation deferred.
346 114 : $$->eNodeType = SNT_COLUMN;
347 114 : $$->field_index = $$->table_index = -1;
348 : }
349 :
350 : | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
351 114 : {
352 114 : $$ = $1; // validation deferred.
353 114 : $$->eNodeType = SNT_COLUMN;
354 114 : $$->field_index = $$->table_index = -1;
355 114 : $$->string_value = (char *)
356 : CPLRealloc( $$->string_value,
357 114 : strlen($$->string_value)
358 : + strlen($3->string_value) + 2 );
359 : strcat( $$->string_value, "." );
360 : strcat( $$->string_value, $3->string_value );
361 1886 : delete $3;
362 : $3 = NULL;
363 1886 : }
364 :
365 : value_expr:
366 664 : SWQT_NUMBER
367 : {
368 664 : $$ = $1;
369 : }
370 3708 :
371 : | SWQT_STRING
372 3708 : {
373 : $$ = $1;
374 : }
375 126 : | field_value
376 : {
377 126 : $$ = $1;
378 : }
379 :
380 10 : | '(' value_expr ')'
381 : {
382 10 : $$ = $2;
383 : }
384 :
385 10 : | SWQT_NULL
386 : {
387 8 : $$ = new swq_expr_node((const char*)NULL);
388 8 : }
389 8 :
390 : | '-' value_expr %prec SWQT_UMINUS
391 : {
392 : if ($2->eNodeType == SNT_CONSTANT)
393 2 : {
394 4 : $$ = $2;
395 2 : $$->int_value *= -1;
396 : $$->float_value *= -1;
397 : }
398 10 : else
399 : {
400 : $$ = new swq_expr_node( SWQ_MULTIPLY );
401 22 : $$->PushSubExpression( new swq_expr_node(-1) );
402 22 : $$->PushSubExpression( $2 );
403 22 : }
404 : }
405 22 :
406 : | value_expr '+' value_expr
407 : {
408 14 : $$ = new swq_expr_node( SWQ_ADD );
409 14 : $$->PushSubExpression( $1 );
410 14 : $$->PushSubExpression( $3 );
411 : }
412 14 :
413 : | value_expr '-' value_expr
414 : {
415 14 : $$ = new swq_expr_node( SWQ_SUBTRACT );
416 14 : $$->PushSubExpression( $1 );
417 14 : $$->PushSubExpression( $3 );
418 : }
419 14 :
420 : | value_expr '*' value_expr
421 : {
422 16 : $$ = new swq_expr_node( SWQ_MULTIPLY );
423 16 : $$->PushSubExpression( $1 );
424 16 : $$->PushSubExpression( $3 );
425 : }
426 16 :
427 : | value_expr '/' value_expr
428 : {
429 12 : $$ = new swq_expr_node( SWQ_DIVIDE );
430 12 : $$->PushSubExpression( $1 );
431 12 : $$->PushSubExpression( $3 );
432 : }
433 12 :
434 : | value_expr '%' value_expr
435 : {
436 : $$ = new swq_expr_node( SWQ_MODULUS );
437 64 : $$->PushSubExpression( $1 );
438 : $$->PushSubExpression( $3 );
439 64 : }
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 64 : $1->string_value );
451 64 : delete $1;
452 64 : delete $3;
453 64 : YYERROR;
454 64 : }
455 : else
456 : {
457 64 : $$ = $3;
458 : $$->eNodeType = SNT_OPERATION;
459 : $$->nOperation = poOp->eOperation;
460 66 : $$->ReverseSubExpressions();
461 66 : delete $1;
462 66 : }
463 : }
464 66 :
465 : | SWQT_CAST '(' value_expr SWQT_AS type_def ')'
466 : {
467 : $$ = $5;
468 58 : $$->PushSubExpression( $3 );
469 58 : $$->ReverseSubExpressions();
470 : }
471 58 :
472 : type_def:
473 : SWQT_IDENTIFIER
474 12 : {
475 12 : $$ = new swq_expr_node( SWQ_CAST );
476 12 : $$->PushSubExpression( $1 );
477 : }
478 12 :
479 : | SWQT_IDENTIFIER '(' SWQT_NUMBER ')'
480 : {
481 2 : $$ = new swq_expr_node( SWQ_CAST );
482 2 : $$->PushSubExpression( $3 );
483 2 : $$->PushSubExpression( $1 );
484 2 : }
485 :
486 2 : | SWQT_IDENTIFIER '(' SWQT_NUMBER ',' SWQT_NUMBER ')'
487 : {
488 : $$ = new swq_expr_node( SWQ_CAST );
489 : $$->PushSubExpression( $5 );
490 720 : $$->PushSubExpression( $3 );
491 : $$->PushSubExpression( $1 );
492 720 : }
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 36 : select_field_list:
501 : column_spec
502 0 : | column_spec ',' select_field_list
503 0 :
504 : column_spec:
505 : SWQT_DISTINCT field_value
506 36 : {
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 2292 : delete $2;
519 : YYERROR;
520 10 : }
521 10 : }
522 :
523 : | value_expr
524 2282 : {
525 : if( !context->poSelect->PushField( $1 ) )
526 : {
527 4 : delete $1;
528 : YYERROR;
529 0 : }
530 0 : }
531 0 :
532 : | SWQT_DISTINCT field_value SWQT_AS string_or_identifier
533 : {
534 4 : if( !context->poSelect->PushField( $2, $4->string_value, TRUE ))
535 : {
536 4 : delete $2;
537 : delete $4;
538 : YYERROR;
539 10 : }
540 :
541 0 : delete $4;
542 0 : }
543 0 :
544 : | value_expr SWQT_AS string_or_identifier
545 10 : {
546 : if( !context->poSelect->PushField( $1, $3->string_value ) )
547 10 : {
548 : delete $1;
549 : delete $3;
550 392 : YYERROR;
551 392 : }
552 392 : delete $3;
553 392 : }
554 :
555 392 : | '*'
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 392 :
562 : if( !context->poSelect->PushField( poNode ) )
563 : {
564 20 : delete poNode;
565 : YYERROR;
566 20 : }
567 20 : }
568 :
569 20 : | SWQT_IDENTIFIER '.' '*'
570 20 : {
571 : CPLString osQualifiedField;
572 20 :
573 20 : osQualifiedField = $1->string_value;
574 40 : osQualifiedField += ".*";
575 20 :
576 : delete $1;
577 20 : $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 20 :
584 : if( !context->poSelect->PushField( poNode ) )
585 : {
586 : delete poNode;
587 196 : YYERROR;
588 : }
589 : }
590 :
591 2 : | SWQT_IDENTIFIER '(' '*' ')'
592 2 : {
593 2 : // special case for COUNT(*), confirm it.
594 : if( !EQUAL($1->string_value,"COUNT") )
595 : {
596 194 : CPLError( CE_Failure, CPLE_AppDefined,
597 194 : "Syntax Error with %s(*).",
598 : $1->string_value );
599 194 : delete $1;
600 194 : YYERROR;
601 194 : }
602 194 :
603 : delete $1;
604 388 : $1 = NULL;
605 194 :
606 : swq_expr_node *poNode = new swq_expr_node();
607 194 : 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 194 :
614 : if( !context->poSelect->PushField( count ) )
615 : {
616 : delete count;
617 4 : YYERROR;
618 : }
619 : }
620 :
621 2 : | SWQT_IDENTIFIER '(' '*' ')' SWQT_AS string_or_identifier
622 2 : {
623 2 : // special case for COUNT(*), confirm it.
624 2 : if( !EQUAL($1->string_value,"COUNT") )
625 : {
626 : CPLError( CE_Failure, CPLE_AppDefined,
627 2 : "Syntax Error with %s(*).",
628 2 : $1->string_value );
629 : delete $1;
630 2 : delete $6;
631 2 : YYERROR;
632 2 : }
633 2 :
634 : delete $1;
635 4 : $1 = NULL;
636 2 :
637 : swq_expr_node *poNode = new swq_expr_node();
638 2 : 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 2 : if( !context->poSelect->PushField( count, $6->string_value ) )
646 : {
647 2 : delete count;
648 : delete $6;
649 : YYERROR;
650 : }
651 12 :
652 : delete $6;
653 : }
654 2 :
655 2 : | SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')'
656 2 : {
657 2 : // special case for COUNT(DISTINCT x), confirm it.
658 : if( !EQUAL($1->string_value,"COUNT") )
659 : {
660 10 : CPLError( CE_Failure, CPLE_AppDefined,
661 : "DISTINCT keyword can only be used in COUNT() operator." );
662 10 : delete $1;
663 10 : delete $4;
664 : YYERROR;
665 10 : }
666 :
667 0 : delete $1;
668 0 :
669 : swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
670 : count->PushSubExpression( $4 );
671 10 :
672 : if( !context->poSelect->PushField( count, NULL, TRUE ) )
673 : {
674 : delete count;
675 4 : YYERROR;
676 : }
677 : }
678 2 :
679 2 : | SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')' SWQT_AS string_or_identifier
680 2 : {
681 2 : // special case for COUNT(DISTINCT x), confirm it.
682 2 : if( !EQUAL($1->string_value,"COUNT") )
683 : {
684 : CPLError( CE_Failure, CPLE_AppDefined,
685 2 : "DISTINCT keyword can only be used in COUNT() operator." );
686 2 : delete $1;
687 : delete $4;
688 2 : 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 2 : {
697 2 : delete $1;
698 : delete count;
699 2 : delete $7;
700 : YYERROR;
701 : }
702 :
703 366 : delete $1;
704 : delete $7;
705 366 : }
706 :
707 : opt_where:
708 : | SWQT_WHERE logical_expr
709 4 : {
710 4 : context->poSelect->where_expr = $2;
711 12 : }
712 4 :
713 4 : opt_joins:
714 4 : | SWQT_JOIN table_def SWQT_ON field_value '=' field_value opt_joins
715 : {
716 4 : context->poSelect->PushJoin( $2->int_value,
717 : $4->string_value,
718 42 : $6->string_value );
719 42 : delete $2;
720 126 : delete $4;
721 42 : delete $6;
722 42 : }
723 42 : | SWQT_LEFT SWQT_JOIN table_def SWQT_ON field_value '=' field_value opt_joins
724 : {
725 42 : 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 10 : sort_spec_list:
737 10 : sort_spec ',' sort_spec_list
738 10 : | sort_spec
739 :
740 10 : sort_spec:
741 : field_value
742 22 : {
743 22 : context->poSelect->PushOrderBy( $1->string_value, TRUE );
744 22 : delete $1;
745 : $1 = NULL;
746 22 : }
747 : | field_value SWQT_ASC
748 18 : {
749 18 : context->poSelect->PushOrderBy( $1->string_value, TRUE );
750 18 : delete $1;
751 : $1 = NULL;
752 18 : }
753 : | field_value SWQT_DESC
754 : {
755 : context->poSelect->PushOrderBy( $1->string_value, FALSE );
756 790 : delete $1;
757 : $1 = NULL;
758 790 : }
759 :
760 48 : string_or_identifier:
761 : SWQT_IDENTIFIER
762 48 : {
763 : $$ = $1;
764 : }
765 : | SWQT_STRING
766 : {
767 782 : $$ = $1;
768 782 : }
769 782 :
770 : table_def:
771 782 : string_or_identifier
772 : {
773 782 : int iTable;
774 : iTable =context->poSelect->PushTableDef( NULL, $1->string_value,
775 : NULL );
776 : delete $1;
777 24 :
778 48 : $$ = new swq_expr_node( iTable );
779 24 : }
780 24 :
781 : | string_or_identifier SWQT_IDENTIFIER
782 24 : {
783 : int iTable;
784 24 : iTable = context->poSelect->PushTableDef( NULL, $1->string_value,
785 : $2->string_value );
786 : delete $1;
787 : delete $2;
788 2 :
789 4 : $$ = new swq_expr_node( iTable );
790 2 : }
791 2 :
792 : | SWQT_STRING '.' string_or_identifier
793 2 : {
794 : int iTable;
795 2 : iTable = context->poSelect->PushTableDef( $1->string_value,
796 : $3->string_value, NULL );
797 : delete $1;
798 : delete $3;
799 8 :
800 8 : $$ = new swq_expr_node( iTable );
801 24 : }
802 8 :
803 8 : | SWQT_STRING '.' string_or_identifier SWQT_IDENTIFIER
804 8 : {
805 : int iTable;
806 8 : 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 : }
|