1 |
/* |
2 |
* This SQL Parser is copied from the O'Reilly Lex & Yacc book, 2nd Edition, |
3 |
* 1995, by John R. Levine, Tony Mason, and Doug Brown. I only copied the |
4 |
* query-related language subset. Added some stuff so it could interface w/ |
5 |
* Obj_Srvr.pm. |
6 |
* |
7 |
* Jeremy Hickerson, 5/21/2003 |
8 |
*/ |
9 |
|
10 |
%{ |
11 |
#define YYDEBUG 0 |
12 |
extern int yydebug = 0; /* jhjh */ |
13 |
|
14 |
#include <string.h> |
15 |
#include "obj_srvr.h" |
16 |
/* #include "flexdef.h" */ |
17 |
|
18 |
char fullname[255]; |
19 |
char temp[255]; |
20 |
char tmpstr[3]; |
21 |
char perl_op[31]; |
22 |
char tmp_str[31]; |
23 |
|
24 |
void yyerror(); |
25 |
char *alloca (); |
26 |
void end_sql(); |
27 |
%} |
28 |
|
29 |
/* symbolic tokens */ |
30 |
/* jhjh %union { |
31 |
int intval; |
32 |
double floatval; |
33 |
char *strval; |
34 |
int subtok; |
35 |
} */ |
36 |
|
37 |
%union { |
38 |
int intval; |
39 |
char *strval; |
40 |
double floatval; |
41 |
int subtok; |
42 |
} |
43 |
|
44 |
%token <strval> NAME |
45 |
%token <strval> STRING |
46 |
%token <strval> INTNUM APPROXNUM |
47 |
|
48 |
%type <strval> statement query_exp query_term query_spec opt_all_distinct |
49 |
%type <strval> selection table_exp opt_where_clause from_clause |
50 |
%type <strval> table_ref_commalist table_ref where_clause opt_order_by_clause |
51 |
%type <strval> opt_group_by_clause column_ref_commalist opt_having_clause |
52 |
%type <strval> search_condition predicate comparison_predicate between_predicate |
53 |
%type <strval> comparison |
54 |
%type <strval> like_predicate opt_escape test_for_null in_predicate atom_commalist |
55 |
%type <strval> all_or_any_predicate any_all_some existence_test subquery |
56 |
%type <strval> scalar_exp scalar_exp_commalist atom parameter_ref function_ref |
57 |
%type <strval> literal table column_ref column cursor parameter range_variable |
58 |
%type <strval> user sql when_action |
59 |
|
60 |
/* type for literals */ |
61 |
%type <strval> '(' ')' '.' |
62 |
|
63 |
/* operators */ |
64 |
%left <strval> OR |
65 |
%left <strval> AND |
66 |
%left <strval> NOT |
67 |
%left <strval> COMP_EQ /* = */ |
68 |
%left <strval> COMP_NE1 /* <> */ |
69 |
%left <strval> COMP_NE2 /* != */ |
70 |
%left <strval> COMP_LT /* < */ |
71 |
%left <strval> COMP_GT /* > */ |
72 |
%left <strval> COMP_LE /* <= */ |
73 |
%left <strval> COMP_GE /* >= */ |
74 |
%left <strval> '+' '-' |
75 |
%left <strval> '*' '/' |
76 |
%nonassoc <strval> UMINUS |
77 |
|
78 |
|
79 |
/* literal keyword tokens */ |
80 |
/* %token <strval> ALL AMMSC ANY AS ASC AUTHORIZATION BETWEEN BY CHARACTER */ |
81 |
%token <strval> ALL AMMSC AS ASC AUTHORIZATION BETWEEN BY CHARACTER |
82 |
%token <strval> CHECK CLOSE CONTINUE CURRENT CURSOR DECIMAL DECLARE DEFAULT |
83 |
%token <strval> DESC DISTINCT DOUBLE ESCAPE EXISTS FETCH FLOAT FOR FOREIGN |
84 |
%token <strval> FOUND FROM GOTO GROUP HAVING IN INDICATOR INTEGER INTO IS KEY |
85 |
%token <strval> LANGUAGE LIKE NULLX NUMERIC OF ON OPEN OPTION ORDER PARAMETER |
86 |
%token <strval> PRECISION PRIMARY PRIVILEGES PROCEDURE REAL REFERENCES SCHEMA |
87 |
%token <strval> SELECT SMALLINT SOME SQLCODE SQLERROR TO UNION UNIQUE USER |
88 |
%token <strval> VALUES WHENEVER WHERE WITH WORK |
89 |
|
90 |
%% |
91 |
|
92 |
statement: |
93 |
query_exp ';' { end_sql(); return 0; } |
94 |
| statement query_exp ';' { end_sql(); return 0; } |
95 |
; |
96 |
|
97 |
/* query expressions */ |
98 |
query_exp: |
99 |
query_term |
100 |
| query_exp UNION query_term |
101 |
| query_exp UNION ALL query_term |
102 |
; |
103 |
|
104 |
query_term: |
105 |
query_spec |
106 |
| '(' query_exp ')' |
107 |
; |
108 |
|
109 |
query_spec: |
110 |
SELECT opt_all_distinct selection table_exp { |
111 |
strcpy(parsed_sql.column_list, $3); |
112 |
} |
113 |
; |
114 |
|
115 |
opt_all_distinct: |
116 |
/* empty */ |
117 |
| ALL |
118 |
| DISTINCT |
119 |
; |
120 |
|
121 |
selection: |
122 |
scalar_exp_commalist |
123 |
| '*' |
124 |
; |
125 |
|
126 |
table_exp: |
127 |
from_clause |
128 |
opt_where_clause |
129 |
opt_order_by_clause opt_group_by_clause opt_having_clause |
130 |
; |
131 |
|
132 |
opt_where_clause: |
133 |
/* empty */ |
134 |
| where_clause |
135 |
; |
136 |
|
137 |
from_clause: |
138 |
FROM table_ref_commalist { |
139 |
strcpy(parsed_sql.table_list, $2); |
140 |
} |
141 |
; |
142 |
|
143 |
table_ref_commalist: |
144 |
table_ref |
145 |
| table_ref_commalist ',' table_ref { |
146 |
printf("Multiple-table query not handled\n"); glb_errflag = 1; |
147 |
} |
148 |
; |
149 |
|
150 |
table_ref: |
151 |
table |
152 |
| table range_variable |
153 |
; |
154 |
|
155 |
where_clause: |
156 |
WHERE search_condition { |
157 |
strcpy(parsed_sql.where_clause, $2); |
158 |
} |
159 |
; |
160 |
|
161 |
opt_order_by_clause: |
162 |
/* empty */ |
163 |
| ORDER BY column_ref_commalist { |
164 |
strcpy(parsed_sql.order_by, $3); |
165 |
} |
166 |
; |
167 |
|
168 |
opt_group_by_clause: |
169 |
/* empty */ |
170 |
| GROUP BY column_ref_commalist |
171 |
; |
172 |
|
173 |
column_ref_commalist: |
174 |
column_ref |
175 |
| column_ref_commalist ',' column_ref { |
176 |
strcpy($$, $1); |
177 |
strcat($$, ","); |
178 |
strcat($$, $3); |
179 |
} |
180 |
; |
181 |
|
182 |
opt_having_clause: |
183 |
/* empty */ |
184 |
| HAVING search_condition { |
185 |
printf("HAVING condition not handled\n"); glb_errflag = 1; |
186 |
} |
187 |
; |
188 |
|
189 |
|
190 |
/* search conditions */ |
191 |
search_condition: |
192 |
search_condition OR search_condition { |
193 |
strcpy($$, $1); |
194 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
195 |
strcat($$, $2); |
196 |
strcat($$, ","); |
197 |
strcat($$, $3); |
198 |
} |
199 |
| search_condition AND search_condition { |
200 |
strcpy($$, $1); |
201 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
202 |
strcat($$, $2); |
203 |
strcat($$, ","); |
204 |
strcat($$, $3); |
205 |
} |
206 |
| NOT search_condition { |
207 |
strcpy($$, $1); |
208 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
209 |
strcat($$, $2); |
210 |
} |
211 |
| '(' search_condition ')' { |
212 |
strcpy($$, $1); |
213 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
214 |
strcat($$, $2); |
215 |
strcat($$, ","); |
216 |
strcat($$, $3); |
217 |
} |
218 |
| predicate |
219 |
; |
220 |
|
221 |
predicate: |
222 |
comparison_predicate |
223 |
| between_predicate |
224 |
| like_predicate |
225 |
| test_for_null |
226 |
| in_predicate |
227 |
| all_or_any_predicate |
228 |
| existence_test |
229 |
; |
230 |
|
231 |
comparison_predicate: |
232 |
scalar_exp comparison scalar_exp { |
233 |
|
234 |
strcpy(perl_op, |
235 |
call_perl_tr_op(parsed_sql.table_list, $1, $2, $3) ); |
236 |
/* only one table allowed in "table_list" */ |
237 |
|
238 |
if ( strlen(perl_op) == 15 && |
239 |
perl_op[0] == 'd' && |
240 |
perl_op[1] == 'a' && |
241 |
perl_op[2] == 't' && |
242 |
perl_op[3] == 'e' && |
243 |
perl_op[4] == '_' && |
244 |
perl_op[5] == 'c' && |
245 |
perl_op[6] == 'o' && |
246 |
perl_op[7] == 'm' && |
247 |
perl_op[8] == 'p' && |
248 |
perl_op[9] == 'a' && |
249 |
perl_op[10] == 'r' && |
250 |
perl_op[11] == 'e' ) { |
251 |
|
252 |
strcpy(tmp_str, perl_op); |
253 |
perl_op[0] = tmp_str[13]; /* tmp_str[12] is '_' */ |
254 |
perl_op[1] = tmp_str[14]; |
255 |
perl_op[2] = '\0'; |
256 |
|
257 |
sprintf($$, "date_compare(,%s,\\\\,'%s'\\\\,%s)", |
258 |
$1, perl_op, $3); |
259 |
/* commas around 1st %s translate into spaces; */ |
260 |
/* need spaces so $subst_where will be correct */ |
261 |
/* double escape so perl will see as the */ |
262 |
/* character '\' rather than a perl escape */ |
263 |
} |
264 |
else { |
265 |
strcpy($$, $1); |
266 |
strcat($$, ","); /* use comma's for spaces because of |
267 |
obj_srvr.pm */ |
268 |
strcat($$, perl_op); |
269 |
strcat($$, ","); |
270 |
strcat($$, $3); |
271 |
} |
272 |
} |
273 |
| scalar_exp comparison subquery |
274 |
; |
275 |
|
276 |
comparison: |
277 |
COMP_EQ |
278 |
| COMP_NE1 |
279 |
| COMP_NE2 |
280 |
| COMP_LT |
281 |
| COMP_GT |
282 |
| COMP_LE |
283 |
| COMP_GE |
284 |
; |
285 |
|
286 |
between_predicate: |
287 |
scalar_exp NOT BETWEEN scalar_exp AND scalar_exp { |
288 |
|
289 |
strcpy(perl_op, |
290 |
call_perl_tr_op(parsed_sql.table_list, $1, ">=", $4) ); |
291 |
/* only one table allowed in "table_list" */ |
292 |
|
293 |
if ( strlen(perl_op) == 15 && |
294 |
perl_op[0] == 'd' && |
295 |
perl_op[1] == 'a' && |
296 |
perl_op[2] == 't' && |
297 |
perl_op[3] == 'e' && |
298 |
perl_op[4] == '_' && |
299 |
perl_op[5] == 'c' && |
300 |
perl_op[6] == 'o' && |
301 |
perl_op[7] == 'm' && |
302 |
perl_op[8] == 'p' && |
303 |
perl_op[9] == 'a' && |
304 |
perl_op[10] == 'r' && |
305 |
perl_op[11] == 'e' ) { |
306 |
|
307 |
sprintf($$, "!(date_compare(,%s,\\\\,'%s'\\\\,%s),and,date_compare(,%s,\\\\,'%s'\\\\,%s))", |
308 |
$1, ">=", $4, $1, "<=", $6); |
309 |
/* commas around 1st %s translate into spaces; */ |
310 |
/* need spaces so $subst_where will be correct */ |
311 |
/* double escape so perl will see as the */ |
312 |
/* character '\' rather than a perl escape */ |
313 |
} |
314 |
else { |
315 |
strcpy($$, "!("); |
316 |
strcat($$, $1); |
317 |
strcat($$, ","); /* use comma's for spaces because of |
318 |
obj_srvr.pm */ |
319 |
strcat($$, ">="); |
320 |
strcat($$, ","); |
321 |
strcat($$, $4); |
322 |
strcat($$, ",and,"); |
323 |
strcat($$, $1); |
324 |
strcat($$, ","); |
325 |
strcat($$, "<="); |
326 |
strcat($$, ","); |
327 |
strcat($$, $6); |
328 |
strcat($$, ")"); |
329 |
} |
330 |
} |
331 |
|
332 |
| scalar_exp BETWEEN scalar_exp AND scalar_exp { |
333 |
|
334 |
strcpy(perl_op, |
335 |
call_perl_tr_op(parsed_sql.table_list, $1, ">=", $3) ); |
336 |
/* only one table allowed in "table_list" */ |
337 |
|
338 |
if ( strlen(perl_op) == 15 && |
339 |
perl_op[0] == 'd' && |
340 |
perl_op[1] == 'a' && |
341 |
perl_op[2] == 't' && |
342 |
perl_op[3] == 'e' && |
343 |
perl_op[4] == '_' && |
344 |
perl_op[5] == 'c' && |
345 |
perl_op[6] == 'o' && |
346 |
perl_op[7] == 'm' && |
347 |
perl_op[8] == 'p' && |
348 |
perl_op[9] == 'a' && |
349 |
perl_op[10] == 'r' && |
350 |
perl_op[11] == 'e' ) { |
351 |
|
352 |
sprintf($$, "date_compare(,%s,\\\\,'%s'\\\\,%s),and,date_compare(,%s,\\\\,'%s'\\\\,%s)", |
353 |
$1, ">=", $3, $1, "<=", $5); |
354 |
/* commas around 1st %s translate into spaces; */ |
355 |
/* need spaces so $subst_where will be correct */ |
356 |
/* double escape so perl will see as the */ |
357 |
/* character '\' rather than a perl escape */ |
358 |
} |
359 |
else { |
360 |
strcpy($$, $1); |
361 |
strcat($$, ","); /* use comma's for spaces because of |
362 |
obj_srvr.pm */ |
363 |
strcat($$, ">="); |
364 |
strcat($$, ","); |
365 |
strcat($$, $3); |
366 |
strcat($$, ",and,"); |
367 |
strcat($$, $1); |
368 |
strcat($$, ","); |
369 |
strcat($$, "<="); |
370 |
strcat($$, ","); |
371 |
strcat($$, $5); |
372 |
} |
373 |
} |
374 |
; |
375 |
|
376 |
like_predicate: |
377 |
scalar_exp NOT LIKE atom opt_escape { |
378 |
strcpy($$, call_perl_like2re($1, $2, $3, $4) ); |
379 |
} |
380 |
| scalar_exp LIKE atom opt_escape { |
381 |
strcpy($$, call_perl_like2re($1, $2, $3, "") ); |
382 |
} |
383 |
; |
384 |
|
385 |
|
386 |
opt_escape: |
387 |
/* empty */ |
388 |
| ESCAPE atom { |
389 |
printf("Escape not handled\n"); glb_errflag = 1; |
390 |
} |
391 |
; |
392 |
|
393 |
test_for_null: |
394 |
column_ref IS NOT NULLX { |
395 |
strcpy($$, $1); |
396 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
397 |
strcat($$, $2); |
398 |
strcat($$, ","); |
399 |
strcat($$, $3); |
400 |
strcat($$, ","); |
401 |
strcat($$, $4); |
402 |
} |
403 |
| column_ref IS NULLX { |
404 |
strcpy($$, $1); |
405 |
strcat($$, ","); |
406 |
strcat($$, $2); |
407 |
strcat($$, ","); |
408 |
strcat($$, $3); |
409 |
} |
410 |
; |
411 |
|
412 |
in_predicate: |
413 |
scalar_exp NOT IN subquery { |
414 |
printf("Subquery not handled\n"); glb_errflag = 1; |
415 |
} |
416 |
| scalar_exp IN subquery { |
417 |
printf("Subquery not handled\n"); glb_errflag = 1; |
418 |
} |
419 |
| scalar_exp NOT IN '(' atom_commalist ')' { |
420 |
/* Translate into equivalent perl expression for reval in Obj_Srvr.pm */ |
421 |
/* (Use comma's for spaces because that's how Obj_Srvr.pm expects */ |
422 |
/* it. Obj_Srvr.pm will convert comma's to spaces before reval.) */ |
423 |
/* perl-escape foward slashes and parentheses to avoid screwing up */ |
424 |
/* first round of perl parsing (wh/ uses reg. exp's), before reval(). */ |
425 |
strcpy($$, "!grep \\/^"); |
426 |
strcat($$, $1); |
427 |
strcat($$, "$\\/\\\\, "); /* double escape so perl will see as the */ |
428 |
/* character '\' rather than a perl escape */ |
429 |
strcat($$, "\\("); |
430 |
strcat($$, $4); |
431 |
strcat($$, "\\)"); |
432 |
} |
433 |
| scalar_exp IN '(' atom_commalist ')' { |
434 |
/* Translate into equivalent perl expression for reval in Obj_Srvr.pm */ |
435 |
strcpy($$, "grep \\/^"); |
436 |
strcat($$, $1); |
437 |
strcat($$, "$\\/\\\\, "); |
438 |
strcat($$, "\\("); |
439 |
strcat($$, $4); |
440 |
strcat($$, "\\)"); |
441 |
} |
442 |
; |
443 |
|
444 |
atom_commalist: |
445 |
atom |
446 |
| atom_commalist ',' atom { |
447 |
strcpy($$, $1); |
448 |
strcat($$, "\\\\,"); /* save from perl-parse (see in_predicate:) */ |
449 |
strcat($$, $3); |
450 |
} |
451 |
; |
452 |
|
453 |
all_or_any_predicate: |
454 |
scalar_exp comparison any_all_some subquery { |
455 |
printf("Subquery not handled\n"); glb_errflag = 1; |
456 |
} |
457 |
; |
458 |
|
459 |
any_all_some: |
460 |
/* ANY */ |
461 |
| ALL |
462 |
| SOME |
463 |
; |
464 |
|
465 |
existence_test: |
466 |
EXISTS subquery |
467 |
{ printf("Subquery not handled\n"); glb_errflag = 1; } |
468 |
; |
469 |
|
470 |
/* jhjh - we won't handle subqueries; shouldn't need w/ a simple data model */ |
471 |
subquery: |
472 |
'(' SELECT opt_all_distinct selection table_exp ')' |
473 |
{ printf("Subquery not handled\n"); glb_errflag = 1; } |
474 |
; |
475 |
|
476 |
|
477 |
/* scalar expressions */ |
478 |
scalar_exp: |
479 |
scalar_exp '+' scalar_exp { |
480 |
strcpy($$, $1); |
481 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
482 |
strcat($$, $2); |
483 |
strcat($$, ","); |
484 |
strcat($$, $3); |
485 |
} |
486 |
| scalar_exp '-' scalar_exp { |
487 |
strcpy($$, $1); |
488 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
489 |
strcat($$, $2); |
490 |
strcat($$, ","); |
491 |
strcat($$, $3); |
492 |
} |
493 |
| scalar_exp '*' scalar_exp { |
494 |
strcpy($$, $1); |
495 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
496 |
strcat($$, $2); |
497 |
strcat($$, ","); |
498 |
strcat($$, $3); |
499 |
} |
500 |
| scalar_exp '/' scalar_exp { |
501 |
strcpy($$, $1); |
502 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
503 |
strcat($$, $2); |
504 |
strcat($$, ","); |
505 |
strcat($$, $3); |
506 |
} |
507 |
| '+' scalar_exp %prec UMINUS { /* jhjh - what is this */ |
508 |
strcpy($$, $1); |
509 |
strcat($$, ","); |
510 |
strcat($$, $2); |
511 |
} |
512 |
| '-' scalar_exp %prec UMINUS { /* jhjh - what is this */ |
513 |
strcpy($$, $1); |
514 |
strcat($$, ","); |
515 |
strcat($$, $2); |
516 |
} |
517 |
| atom /* jhjh - ignore multi-word possibilities here */ |
518 |
| column_ref |
519 |
| function_ref /* jhjh - ignore functions */ |
520 |
| '(' scalar_exp ')' { |
521 |
strcpy($$, $1); |
522 |
strcat($$, ","); /* use comma's for spaces because of obj_srvr.pm */ |
523 |
strcat($$, $2); |
524 |
strcat($$, ","); |
525 |
strcat($$, $3); |
526 |
} |
527 |
; |
528 |
|
529 |
scalar_exp_commalist: |
530 |
scalar_exp |
531 |
| scalar_exp_commalist ',' scalar_exp { |
532 |
strcpy($$, $1); |
533 |
strcat($$, ","); |
534 |
strcat($$, $3); |
535 |
} |
536 |
; |
537 |
atom: |
538 |
parameter_ref |
539 |
| literal |
540 |
| USER |
541 |
; |
542 |
|
543 |
parameter_ref: |
544 |
parameter |
545 |
| parameter parameter |
546 |
| parameter INDICATOR parameter |
547 |
; |
548 |
|
549 |
function_ref: |
550 |
AMMSC '(' '*' ')' |
551 |
| AMMSC '(' DISTINCT column_ref ')' |
552 |
| AMMSC '(' ALL scalar_exp ')' |
553 |
| AMMSC '(' scalar_exp ')' |
554 |
; |
555 |
|
556 |
literal: |
557 |
STRING |
558 |
| INTNUM |
559 |
| APPROXNUM |
560 |
; |
561 |
|
562 |
|
563 |
/* miscellaneous */ |
564 |
table: |
565 |
NAME |
566 |
|
567 |
| NAME '.' NAME |
568 |
; |
569 |
|
570 |
column_ref: |
571 |
INTNUM |
572 |
| NAME |
573 |
| NAME '.' NAME { strcpy($$, $3) } |
574 |
| NAME '.' NAME '.' NAME |
575 |
| column_ref NAME { |
576 |
printf("Multiple-table query not handled\n"); glb_errflag = 1; |
577 |
} |
578 |
; |
579 |
|
580 |
|
581 |
/* the various things you can name */ |
582 |
column: |
583 |
NAME |
584 |
; |
585 |
|
586 |
cursor: |
587 |
NAME |
588 |
; |
589 |
|
590 |
parameter: |
591 |
PARAMETER /* :name handled in parser */ |
592 |
; |
593 |
|
594 |
range_variable: |
595 |
NAME { |
596 |
printf("Table alias not handled\n"); glb_errflag = 1; |
597 |
} |
598 |
; |
599 |
|
600 |
user: |
601 |
NAME |
602 |
; |
603 |
|
604 |
|
605 |
/* embedded condition things */ |
606 |
sql: |
607 |
WHENEVER NOT FOUND when_action |
608 |
| WHENEVER SQLERROR when_action |
609 |
; |
610 |
|
611 |
when_action: |
612 |
GOTO NAME |
613 |
| CONTINUE |
614 |
; |
615 |
|
616 |
%% |
617 |
|