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