Commit | Line | Data |
f85aea79 |
1 | package SQL::Translator::Parser::DB2; |
bdf60588 |
2 | |
3 | use warnings; |
4 | use strict; |
5 | |
f85aea79 |
6 | use base qw(Exporter); |
bdf60588 |
7 | our @EXPORT_OK = qw(parse); |
8 | |
9 | our $DEBUG; |
10 | |
11 | use Data::Dumper; |
12 | use SQL::Translator::Utils qw/ddl_parser_instance/; |
13 | |
14 | our $GRAMMAR = <<'END_OF_GRAMMAR'; |
15 | |
16 | { |
17 | my ( %tables, $table_order, @table_comments, @views, @triggers ); |
18 | } |
19 | |
20 | # |
21 | # The "eofile" rule makes the parser fail if any "statement" rule |
22 | # fails. Otherwise, the first successful match by a "statement" |
23 | # won't cause the failure needed to know that the parse, as a whole, |
24 | # failed. -ky |
25 | # |
26 | startrule : statement(s) eofile { |
27 | $return = { |
28 | tables => \%tables, |
29 | views => \@views, |
30 | triggers => \@triggers, |
31 | } |
32 | } |
33 | |
34 | eofile : /^\Z/ |
35 | |
aee4b66e |
36 | statement : |
bdf60588 |
37 | comment |
38 | | create |
39 | | <error> |
40 | |
41 | comment : /^\s*-{2}.*\n/ |
42 | { |
43 | my $comment = $item[1]; |
44 | $comment =~ s/^\s*(-{2})\s*//; |
45 | $comment =~ s/\s*$//; |
46 | $return = $comment; |
47 | } |
48 | |
49 | |
50 | create: CREATE TRIGGER trigger_name before type /ON/i table_name reference_b(?) /FOR EACH ROW/i 'MODE DB2SQL' triggered_action |
51 | { |
52 | my $table_name = $item{'table_name'}{'name'}; |
53 | $return = { |
54 | table => $table_name, |
55 | schema => $item{'trigger_name'}{'schema'}, |
56 | name => $item{'trigger_name'}{'name'}, |
57 | when => 'before', |
58 | db_event => $item{'type'}->{'event'}, |
59 | fields => $item{'type'}{'fields'}, |
60 | condition => $item{'triggered_action'}{'condition'}, |
61 | reference => $item{'reference_b'}, |
62 | granularity => $item[9], |
63 | action => $item{'triggered_action'}{'statement'} |
64 | }; |
65 | |
66 | push @triggers, $return; |
67 | } |
68 | |
69 | create: CREATE TRIGGER trigger_name after type /ON/i table_name reference_a(?) /FOR EACH ROW|FOR EACH STATEMENT/i 'MODE DB2SQL' triggered_action |
70 | { |
71 | my $table_name = $item{'table_name'}{'name'}; |
72 | $return = { |
73 | table => $table_name, |
74 | schema => $item{'trigger_name'}{'schema'}, |
75 | name => $item{'trigger_name'}{'name'}, |
76 | when => 'after', |
77 | db_event => $item{'type'}{'event'}, |
78 | fields => $item{'type'}{'fields'}, |
79 | condition => $item{'triggered_action'}{'condition'}, |
80 | reference => $item{'reference_a'}, |
81 | granularity => $item[9], |
82 | action => $item{'triggered_action'}{'statement'} |
83 | }; |
84 | |
85 | push @triggers, $return; |
86 | } |
87 | |
88 | create: CREATE /FEDERATED|/i VIEW view_name column_list(?) /AS/i with_expression(?) SQL_procedure_statement |
89 | { |
90 | $return = { |
91 | name => $item{view_name}{name}, |
92 | sql => $item{SQL_procedure_statement}, |
93 | with => $item{'with_expression(?)'}, |
94 | fields => $item{'column_list(?)'} |
95 | }; |
96 | push @views, $return; |
97 | } |
98 | |
99 | # create: CREATE /FEDERATED/i VIEW view_name col_list_or_of(?) /AS/i with_expression(?) fullselect options(?) |
100 | |
101 | # col_list_or_of: column_list | /OF/i ( root_view_definition | subview_definition ) |
102 | |
103 | with_expression: /WITH/i common_table_expression(s /,/) |
104 | { |
105 | $return = $item{'common_table_expression'}; |
106 | } |
107 | |
108 | SQL_procedure_statement: /[^;]*/ /(;|\z)/ { $return = $item[1] . $item[2] } |
109 | |
110 | column_list: '(' column_name(s /,/) ')' |
111 | { |
112 | $return = join(' ', '(', @{$item[2]}, ')'); |
113 | } |
114 | |
115 | CREATE: /create/i |
116 | |
117 | TRIGGER: /trigger/i |
118 | |
119 | VIEW: /view/i |
120 | |
121 | INNER: /inner/i |
122 | |
123 | LEFT: /left/i |
124 | |
125 | RIGHT: /right/i |
126 | |
127 | FULL: /full/i |
128 | |
129 | OUTER: /outer/i |
130 | |
131 | WHERE: /where/i |
aee4b66e |
132 | |
bdf60588 |
133 | trigger_name: SCHEMA '.' NAME |
134 | { $return = { schema => $item[1], name => $item[3] } } |
135 | | NAME |
aee4b66e |
136 | { $return = { name => $item[1] } } |
bdf60588 |
137 | |
138 | table_name: SCHEMA '.' NAME |
139 | { $return = { schema => $item[1], name => $item[3] } } |
140 | | NAME |
aee4b66e |
141 | { $return = { name => $item[1] } } |
bdf60588 |
142 | |
143 | view_name: SCHEMA '.' NAME |
144 | { $return = { schema => $item[1], name => $item[3] } } |
145 | | NAME |
aee4b66e |
146 | { $return = { name => $item[1] } } |
bdf60588 |
147 | |
148 | column_name: NAME |
149 | |
150 | identifier: NAME |
151 | |
152 | correlation_name: NAME |
153 | |
154 | numeric_constant: /\d+/ |
155 | |
156 | SCHEMA: /\w+/ |
157 | |
158 | SCHEMA: /\w{1,128}/ |
159 | |
160 | NAME: /\w+/ |
161 | |
162 | NAME: /\w{1,18}/ |
aee4b66e |
163 | |
bdf60588 |
164 | options: /WITH/i ( /CASCADED/i | /LOCAL/i ) /CHECK\s+OPTION/i |
165 | |
166 | # root_view_definition: /MODE\s+DB2SQL/i '(' oid_column ( /,/ with_options )(?) ')' |
167 | |
168 | # subview_definition: /MODE\s+DB2SQL/i under_clause ( '(' with_options ')' )(?) /EXTEND/i(?) |
169 | |
170 | # oid_column: /REF\s+IS/i oid_column_name /USER\s+GENERATED\s+UNCHECKED/i(?) |
171 | |
172 | # with_options: ( column_name /WITH\s+OPTIONS/i ( /SCOPE/i ( typed_table_name | typed_view_name ) | /READ\s+ONLY/i )(s /,/) )(s /,/) |
173 | |
174 | # under_clause: /UNDER/i superview_name /INHERIT\s+SELECT\s+PRIVILEGES/i |
175 | |
176 | common_table_expression: table_name column_list /AS/i get_bracketed |
177 | { |
aee4b66e |
178 | $return = { name => $item{table_name}{name}, |
bdf60588 |
179 | query => $item[4] |
180 | }; |
181 | } |
182 | |
aee4b66e |
183 | get_bracketed: |
184 | { |
bdf60588 |
185 | extract_bracketed($text, '('); |
186 | } |
187 | |
188 | common_table_expression: table_name column_list /AS/i '(' fullselect ')' |
189 | |
190 | # fullselect: ( subselect | '(' fullselect ')' | values_clause ) ( ( /UNION/i | /UNION/i /ALL/i | /EXCEPT/i | /EXCEPT/i /ALL/i | /INTERSECT/i | /INTERSECT/i /ALL/i ) ( subselect | '(' fullselect ')' | values_clause ) )(s) |
191 | |
aee4b66e |
192 | # values_clause: /VALUES/i values_row(s /,/) |
bdf60588 |
193 | |
194 | # values_row: ( expression | /NULL/i ) | '(' ( expression | /NULL/i )(s /,/) ')' |
195 | |
196 | # subselect: select_clause from_clause where_clause(?) group_by_clause(?) having_clause(?) |
197 | |
198 | # select_clause: SELECT ( /ALL/i | /DISTINCT )(?) ( '*' | ( expression ( /AS|/i new_column_name )(?) | exposed_name '.*' )(s /,/) ) |
199 | |
200 | # from_clause: /FROM/i table_name(s /,/) |
201 | |
202 | # from_clause: /FROM/i table_reference(s /,/) |
203 | |
aee4b66e |
204 | # table_reference: |
205 | # ( |
206 | # ( nickname |
207 | # | table_name |
208 | # | view_name |
209 | # ) |
bdf60588 |
210 | # | ( /ONLY/i |
aee4b66e |
211 | # | /OUTER/i |
212 | # ) '(' |
213 | # ( table_name |
214 | # | view_name |
215 | # ) ')' |
216 | # ) correlation_clause(?) |
217 | # | TABLE '(' function_name '(' expression(s? /,/) ')' ')' correlation_clause |
218 | # | TABLE(?) '(' fullselect ')' correlation_clause |
219 | # | joined_table |
220 | |
bdf60588 |
221 | |
222 | # correlation_clause: /AS/i(?) correlation_name column_list(?) |
223 | |
aee4b66e |
224 | # joined_table: |
225 | # table_reference ( INNER |
226 | # | outer |
bdf60588 |
227 | # )(?) JOIN table_reference ON join_condition |
228 | # | '(' joined_table ')' |
aee4b66e |
229 | |
bdf60588 |
230 | # outer: ( LEFT | RIGHT | FULL ) OUTER(?) |
231 | |
232 | where_clause: WHERE search_condition |
233 | |
aee4b66e |
234 | # group_by_clause: /GROUP\s+BY/i ( grouping_expression |
bdf60588 |
235 | # | grouping_sets |
236 | # | super_groups |
237 | # )(s /,/) |
238 | |
239 | # grouping_expression: expression |
240 | |
241 | # orderby_clause: /ORDER\s+BY/i ( sort_key ( /ASC/i | /DESC/i)(?) )(s /,/) |
242 | |
243 | # sort_key: simple_column_name | simple_integer | sort_key_expression |
244 | |
245 | # # Name of one of the selected columns! |
246 | # simple_column_name: NAME |
f85aea79 |
247 | |
aee4b66e |
248 | # simple_integer: /\d+/ |
bdf60588 |
249 | # { $item[1] <= $numberofcolumns && $item[1] > 1 } |
f85aea79 |
250 | |
bdf60588 |
251 | # sort_key_expression: expression |
252 | # { expression from select columns list, grouping_expression, column function.. } |
253 | |
aee4b66e |
254 | # grouping_sets: /GROUPING\s+SETS/i '(' ( |
255 | # ( grouping_expression |
256 | # | super_groups |
257 | # ) |
258 | # | '(' ( grouping_expression |
259 | # | super_groups |
260 | # )(s /,/) ')' |
261 | # )(s /,/) ')' |
bdf60588 |
262 | |
aee4b66e |
263 | # super_groups: /ROLLUP/i '(' grouping_expression_list ')' |
bdf60588 |
264 | # | /CUBE/i '(' grouping_expression_list ')' |
265 | # | grand_total |
266 | |
aee4b66e |
267 | # grouping_expression_list: ( grouping_expression |
268 | # | '(' grouping_expression(s /,/) ')' |
bdf60588 |
269 | # )(s /,/) |
270 | |
271 | # grand_total: '(' ')' |
272 | |
273 | # having_clause: /HAVING/i search_condition |
274 | |
275 | when_clause: /WHEN/i '(' search_condition ')' {$return = $item[3]} |
276 | |
277 | triggered_action: when_clause(?) SQL_procedure_statement |
278 | { $return = { 'condition' => $item[1][0], |
279 | 'statement' => $item{'SQL_procedure_statement'} }; |
280 | } |
281 | |
282 | before: /NO CASCADE BEFORE/i |
283 | |
284 | after: /AFTER/i |
285 | |
aee4b66e |
286 | type: /UPDATE/i /OF/i column_name(s /,/) |
bdf60588 |
287 | { $return = { event => 'update_on', |
288 | fields => $item[3] } |
289 | } |
290 | |
291 | type: ( /INSERT/i | /DELETE/i | /UPDATE/i ) |
292 | { $return = { event => $item[1] } } |
293 | |
294 | reference_b: /REFERENCING/i old_new_corr(0..2) |
295 | { $return = join(' ', $item[1], join(' ', @{$item[2]}) ) } |
296 | |
aee4b66e |
297 | reference_a: /REFERENCING/i old_new_corr(0..2) old_new_table(0..2) |
bdf60588 |
298 | { $return = join(' ', $item[1], join(' ', @{$item[2]}), join(' ', @{$item[3]}) ) } |
299 | |
aee4b66e |
300 | old_new_corr: /OLD/i /(AS)?/i correlation_name |
bdf60588 |
301 | { $return = join(' ', @item[1..3] ) } |
302 | | /NEW/i /(AS)?/i correlation_name |
303 | { $return = join(' ', @item[1..3] ) } |
304 | |
305 | old_new_table: /OLD_TABLE/i /(AS)?/i identifier |
306 | { $return = join(' ', @item[1..3] ) } |
307 | | /NEW_TABLE/i /(AS)?/i identifier |
308 | { $return = join(' ', @item[1..3] ) } |
309 | |
310 | # Just parsing simple search conditions for now. |
311 | search_condition: /[^)]+/ |
312 | |
aee4b66e |
313 | expression: ( |
314 | ( '+' |
315 | | '-' |
316 | )(?) |
bdf60588 |
317 | ( function |
318 | | '(' expression ')' |
319 | | constant |
320 | | column_name |
321 | | host_variable |
322 | | special_register |
aee4b66e |
323 | | '(' scalar_fullselect ')' |
bdf60588 |
324 | | labeled_duration |
325 | | case_expression |
326 | | cast_specification |
327 | # | dereference_operation |
328 | | OLAP_function |
329 | | method_invocation |
330 | | subtype_treatment |
aee4b66e |
331 | | sequence_reference |
bdf60588 |
332 | ) |
333 | )(s /operator/) |
334 | |
aee4b66e |
335 | operator: ( /CONCAT/i | '||' ) | '/' | '*' | '+' | '-' |
bdf60588 |
336 | |
aee4b66e |
337 | function: ( /SYSIBM\.|/i sysibm_function |
bdf60588 |
338 | | /SYSFUN\.|/i sysfun_function |
aee4b66e |
339 | | userdefined_function |
bdf60588 |
340 | ) '(' func_args(s /,/) ')' |
341 | |
342 | constant: int_const | float_const | dec_const | char_const | hex_const | grastr_const |
343 | |
344 | func_args: expression |
345 | |
346 | sysibm_function: ( /ABS/i | /ABSVAL/i ) |
347 | | /AVG/i |
348 | | /BIGINT/i |
349 | | /BLOB/i |
350 | | /CHAR/i |
351 | | /CLOB/i |
352 | | /COALESCE/i |
353 | | ( /CONCAT/ | '||' ) |
354 | | ( /CORRELATION/i | /CORR/ ) |
355 | | /COUNT/i |
356 | | /COUNT_BIG/i |
357 | | (/COVARIANCE/i | /COVAR/i ) |
358 | | /DATE/i |
359 | | /DAY/i |
360 | | /DAYS/i |
361 | | /DBCLOB/i |
362 | | ( /DECIMAL/i | /DEC/i ) |
363 | | /DECRYPT_BIN/i |
364 | | /DECRYPT_CHAR/i |
365 | | /DEREF/i |
366 | | /DIGITS/i |
367 | | /DLCOMMENT/i |
368 | | /DLLINKTYPE/i |
369 | | /DLURLCOMPLETE/i |
370 | | /DLURLPATH/i |
371 | | /DLURLPATHONLY/i |
372 | | /DLURLSCHEME/i |
373 | | /DLURLSERVER/i |
374 | | /DLVALUE/i |
375 | | ( /DOUBLE/i | /DOUBLE_PRECISION/i ) |
376 | | /ENCRYPT/i |
377 | | /EVENT_MON_STATE/i |
378 | | /FLOAT/i |
379 | | /GETHINT/i |
380 | | /GENERATE_UNIQUE/i |
381 | | /GRAPHIC/i |
382 | | /GROUPING/i |
383 | | /HEX/i |
384 | | /HOUR/i |
385 | | /IDENTITY_VAL_LOCAL/i |
386 | | ( /INTEGER/i | /INT/ ) |
387 | | ( /LCASE/i | /LOWER/ ) |
388 | | /LENGTH/i |
389 | | /LONG_VARCHAR/i |
390 | | /LONG_VARGRAPHIC/i |
391 | | /LTRIM/i |
392 | | /MAX/i |
393 | | /MICROSECOND/i |
394 | | /MIN/i |
395 | | /MINUTE/i |
396 | | /MONTH/i |
397 | | /MULTIPLY_ACT/i |
398 | | /NODENUMBER/i |
399 | | /NULLIF/i |
400 | | /PARTITON/i |
401 | | /POSSTR/i |
402 | | /RAISE_ERROR/i |
403 | | /REAL/i |
404 | | /REC2XML/i |
405 | | /REGR_AVGX/i |
406 | | /REGR_AVGY/i |
407 | | /REGR_COUNT/i |
408 | | ( /REGR_INTERCEPT/i | /REGR_ICPT/i ) |
409 | | /REGR_R2/i |
410 | | /REGR_SLOPE/i |
411 | | /REGR_SXX/i |
412 | | /REGR_SXY/i |
413 | | /REGR_SYY/i |
414 | | /RTRIM/i |
415 | | /SECOND/i |
416 | | /SMALLINT/i |
417 | | /STDDEV/i |
418 | | /SUBSTR/i |
419 | | /SUM/i |
420 | | /TABLE_NAME/i |
421 | | /TABLE_SCHEMA/i |
422 | | /TIME/i |
423 | | /TIMESTAMP/i |
424 | | /TRANSLATE/i |
425 | | /TYPE_ID/i |
426 | | /TYPE_NAME/i |
427 | | /TYPE_SCHEMA/i |
428 | | ( /UCASE/i | /UPPER/i ) |
429 | | /VALUE/i |
430 | | /VARCHAR/i |
431 | | /VARGRAPHIC/i |
432 | | ( /VARIANCE/i | /VAR/i ) |
433 | | /YEAR/i |
434 | |
435 | sysfun: ( /ABS/i | /ABSVAL/i ) |
436 | | /ACOS/i |
437 | | /ASCII/i |
438 | | /ASIN/i |
439 | | /ATAN/i |
440 | | /ATAN2/i |
441 | | ( /CEIL/i | /CEILING/i ) |
442 | | /CHAR/i |
443 | | /CHR/i |
444 | | /COS/i |
445 | | /COT/i |
446 | | /DAYNAME/i |
447 | | /DAYOFWEEK/i |
448 | | /DAYOFWEEK_ISO/i |
449 | | /DAYOFYEAR/i |
450 | | /DEGREES/i |
451 | | /DIFFERENCE/i |
452 | | /DOUBLE/i |
453 | | /EXP/i |
454 | | /FLOOR/i |
455 | | /GET_ROUTINE_SAR/i |
456 | | /INSERT/i |
457 | | /JULIAN_DAY/i |
458 | | /LCASE/i |
459 | | /LEFT/i |
460 | | /LN/i |
461 | | /LOCATE/i |
462 | | /LOG/i |
463 | | /LOG10/i |
464 | | /LTRIM/i |
465 | | /MIDNIGHT_SECONDS/i |
466 | | /MOD/i |
467 | | /MONTHNAME/i |
468 | | /POWER/i |
469 | | /PUT_ROUTINE_SAR/i |
470 | | /QUARTER/i |
471 | | /RADIANS/i |
472 | | /RAND/i |
473 | | /REPEAT/i |
474 | | /REPLACE/i |
475 | | /RIGHT/i |
476 | | /ROUND/i |
477 | | /RTRIM/I |
478 | | /SIGN/i |
479 | | /SIN/i |
480 | | /SOUNDEX/i |
481 | | /SPACE/i |
482 | | /SQLCACHE_SNAPSHOT/i |
483 | | /SQRT/i |
484 | | /TAN/i |
485 | | /TIMESTAMP_ISO/i |
486 | | /TIMESTAMPDIFF/i |
487 | | ( /TRUNCATE/i | /TRUNC/i ) |
488 | | /UCASE/i |
489 | | /WEEK/i |
490 | | /WEEK_ISO/i |
491 | |
492 | scalar_fullselect: '(' fullselect ')' |
493 | |
494 | labeled_duration: ld_type ld_duration |
495 | |
aee4b66e |
496 | ld_type: function |
497 | | '(' expression ')' |
498 | | constant |
499 | | column_name |
bdf60588 |
500 | | host_variable |
501 | |
aee4b66e |
502 | ld_duration: /YEARS?/i |
503 | | /MONTHS?/i |
504 | | /DAYS?/i |
505 | | /HOURS?/i |
bdf60588 |
506 | | /MINUTES?/i |
507 | | /SECONDS?/i |
508 | | /MICROSECONDS?/i |
509 | |
aee4b66e |
510 | case_expression: /CASE/i ( searched_when_clause |
511 | | simple_when_clause |
512 | ) |
513 | ( /ELSE\s+NULL/i |
514 | | /ELSE/i result_expression |
bdf60588 |
515 | )(?) /END/i |
516 | |
aee4b66e |
517 | searched_when_clause: ( /WHEN/i search_condition /THEN/i |
518 | ( result_expression |
bdf60588 |
519 | | /NULL/i |
520 | ) |
521 | )(s) |
522 | |
aee4b66e |
523 | simple_when_clause: expression ( /WHEN/i search_condition /THEN/i |
524 | ( result_expression |
bdf60588 |
525 | | /NULL/i |
526 | ) |
527 | )(s) |
528 | |
aee4b66e |
529 | result_expression: expression |
bdf60588 |
530 | |
aee4b66e |
531 | cast_specification: /CAST/i '(' ( expression |
bdf60588 |
532 | | /NULL/i |
533 | | parameter_marker |
aee4b66e |
534 | ) /AS/i data_type |
535 | ( /SCOPE/ ( typed_table_name |
bdf60588 |
536 | | typed_view_name |
537 | ) |
538 | )(?) ')' |
539 | |
aee4b66e |
540 | dereference_operation: scoped_reference_expression '->' name1 |
bdf60588 |
541 | ( '(' expression(s) ')' )(?) |
542 | # ( '(' expression(s /,/) ')' )(?) |
543 | |
544 | |
545 | |
aee4b66e |
546 | scoped_reference_expression: expression |
547 | { # scoped, reference |
bdf60588 |
548 | } |
549 | |
550 | name1: NAME |
551 | |
aee4b66e |
552 | OLAP_function: ranking_function |
bdf60588 |
553 | | numbering_function |
554 | | aggregation_function |
555 | |
aee4b66e |
556 | ranking_function: ( /RANK/ '()' |
557 | | /DENSE_RANK|DENSERANK/i '()' |
bdf60588 |
558 | ) /OVER/i '(' window_partition_clause(?) window_order_clause ')' |
559 | |
aee4b66e |
560 | numbering_function: /ROW_NUMBER|ROWNUMBER/i '()' /OVER/i '(' window_partition_clause(?) |
561 | ( window_order_clause window_aggregation_group_clause(?) |
562 | )(?) |
563 | ( /RANGE\s+BETWEEN\s+UNBOUNDED\s+PRECEDING\s+AND\s+UNBBOUNDED\s+FOLLOWING/i |
bdf60588 |
564 | | window_aggregation_group_clause |
565 | )(?) ')' |
566 | |
567 | window_partition_clause: /PARTITION\s+BY/i partitioning_expression(s /,/) |
568 | |
aee4b66e |
569 | window_order_clause: /ORDER\s+BY/i |
570 | ( sort_key_expression |
571 | ( asc_option |
572 | | desc_option |
bdf60588 |
573 | )(?) |
574 | )(s /,/) |
575 | |
576 | asc_option: /ASC/i ( /NULLS\s+FIRST/i | /NULLS\s+LAST/i )(?) |
577 | |
578 | desc_option: /DESC/i ( /NULLS\s+FIRST/i | /NULLS\s+LAST/i )(?) |
579 | |
580 | window_aggregation_group_clause: ( /ROWS/i |
581 | | /RANGE/i |
aee4b66e |
582 | ) |
bdf60588 |
583 | ( group_start |
584 | | group_between |
585 | | group_end |
586 | ) |
587 | |
aee4b66e |
588 | group_start: /UNBOUNDED\s+PRECEDING/i |
bdf60588 |
589 | | unsigned_constant /PRECEDING/i |
590 | | /CURRENT\s+ROW/i |
591 | |
592 | group_between: /BETWEEN/i group_bound1 /AND/i group_bound2 |
593 | |
aee4b66e |
594 | group_bound1: /UNBOUNDED\s+PRECEDING/i |
bdf60588 |
595 | | unsigned_constant /PRECEDING/i |
596 | | unsigned_constant /FOLLOWING/i |
597 | | /CURRENT\s+ROW/i |
598 | |
aee4b66e |
599 | group_bound2: /UNBOUNDED\s+PRECEDING/i |
bdf60588 |
600 | | unsigned_constant /PRECEDING/i |
601 | | unsigned_constant /FOLLOWING/i |
602 | | /CURRENT\s+ROW/i |
603 | |
aee4b66e |
604 | group_end: /UNBOUNDED\s+PRECEDING/i |
605 | | unsigned_constant /FOLLOWING/i |
bdf60588 |
606 | |
607 | method_invocation: subject_expression '..' method_name |
aee4b66e |
608 | ( '(' expression(s) ')' |
609 | # ( '(' expression(s /,/) ')' |
bdf60588 |
610 | )(?) |
611 | |
612 | subject_expression: expression |
aee4b66e |
613 | { # with static result type that is a used-defined struct type |
bdf60588 |
614 | } |
615 | |
616 | method_name: NAME |
aee4b66e |
617 | { # must be a method of subject_expression |
bdf60588 |
618 | } |
619 | |
620 | subtype_treatment: /TREAT/i '(' expression /AS/i data_type ')' |
621 | |
622 | sequence_reference: nextval_expression |
623 | | prevval_expression |
624 | |
625 | nextval_expression: /NEXTVAL\s+FOR/i sequence_name |
626 | |
627 | prevval_expression: /PREVVAL\s+FOR/i sequence_name |
628 | |
629 | sequence_name: NAME |
630 | |
631 | |
632 | search_condition: /NOT|/i ( predicate ( /SELECTIVITY/i numeric_constant )(?) | '(' search_condition ')' ) cond(s?) |
633 | |
634 | cond: ( /AND/i | /OR/i ) /NOT|/i ( predicate ( /SELECTIVITY/i numeric_constant )(?) | '(' search_condition ')' ) |
635 | |
aee4b66e |
636 | predicate: basic_p | quantified_p | between_p | exists_p | in_p | like_p | null_p | type_p |
bdf60588 |
637 | |
638 | basic_p: expression /(=|<>|<|>|<=|=>|\^=|\^<|\^>|\!=)/ expression |
639 | |
640 | quantified_p: expression1 /(=|<>|<|>|<=|=>|\^=|\^<|\^>|\!=)/ /SOME|ANY|ALL/i '(' fullselect ')' |
641 | |
642 | END_OF_GRAMMAR |
f85aea79 |
643 | |
f85aea79 |
644 | sub parse { |
645 | my ( $translator, $data ) = @_; |
bdf60588 |
646 | |
647 | # Enable warnings within the Parse::RecDescent module. |
648 | local $::RD_ERRORS = 1 unless defined $::RD_ERRORS; # Make sure the parser dies when it encounters an error |
649 | local $::RD_WARN = 1 unless defined $::RD_WARN; # Enable warnings. This will warn on unused rules &c. |
650 | local $::RD_HINT = 1 unless defined $::RD_HINT; # Give out hints to help fix problems. |
f85aea79 |
651 | |
652 | local $::RD_TRACE = $translator->trace ? 1 : undef; |
653 | local $DEBUG = $translator->debug; |
654 | |
bdf60588 |
655 | my $parser = ddl_parser_instance('DB2'); |
f85aea79 |
656 | |
657 | my $result = $parser->startrule($data); |
658 | return $translator->error( "Parse failed." ) unless defined $result; |
659 | warn Dumper( $result ) if $DEBUG; |
660 | |
661 | my $schema = $translator->schema; |
ea93df61 |
662 | my @tables = |
f85aea79 |
663 | map { $_->[1] } |
ea93df61 |
664 | sort { $a->[0] <=> $b->[0] } |
f85aea79 |
665 | map { [ $result->{'tables'}{ $_ }->{'order'}, $_ ] } |
666 | keys %{ $result->{'tables'} }; |
667 | |
668 | for my $table_name ( @tables ) { |
669 | my $tdata = $result->{'tables'}{ $table_name }; |
ea93df61 |
670 | my $table = $schema->add_table( |
f85aea79 |
671 | name => $tdata->{'name'}, |
672 | ) or die $schema->error; |
673 | |
674 | $table->comments( $tdata->{'comments'} ); |
675 | |
676 | for my $fdata ( @{ $tdata->{'fields'} } ) { |
677 | my $field = $table->add_field( |
678 | name => $fdata->{'name'}, |
679 | data_type => $fdata->{'data_type'}, |
680 | size => $fdata->{'size'}, |
681 | default_value => $fdata->{'default'}, |
682 | is_auto_increment => $fdata->{'is_auto_inc'}, |
683 | is_nullable => $fdata->{'is_nullable'}, |
684 | comments => $fdata->{'comments'}, |
685 | ) or die $table->error; |
686 | |
687 | $table->primary_key( $field->name ) if $fdata->{'is_primary_key'}; |
688 | |
689 | for my $cdata ( @{ $fdata->{'constraints'} } ) { |
690 | next unless $cdata->{'type'} eq 'foreign_key'; |
691 | $cdata->{'fields'} ||= [ $field->name ]; |
692 | push @{ $tdata->{'constraints'} }, $cdata; |
693 | } |
694 | } |
695 | |
696 | for my $idata ( @{ $tdata->{'indices'} || [] } ) { |
697 | my $index = $table->add_index( |
698 | name => $idata->{'name'}, |
699 | type => uc $idata->{'type'}, |
700 | fields => $idata->{'fields'}, |
701 | ) or die $table->error; |
702 | } |
703 | |
704 | for my $cdata ( @{ $tdata->{'constraints'} || [] } ) { |
705 | my $constraint = $table->add_constraint( |
706 | name => $cdata->{'name'}, |
707 | type => $cdata->{'type'}, |
708 | fields => $cdata->{'fields'}, |
709 | reference_table => $cdata->{'reference_table'}, |
710 | reference_fields => $cdata->{'reference_fields'}, |
711 | match_type => $cdata->{'match_type'} || '', |
100684f3 |
712 | on_delete => $cdata->{'on_delete'} || $cdata->{'on_delete_do'}, |
713 | on_update => $cdata->{'on_update'} || $cdata->{'on_update_do'}, |
f85aea79 |
714 | ) or die $table->error; |
715 | } |
716 | } |
717 | |
718 | for my $def ( @{ $result->{'views'} || [] } ) { |
719 | my $view = $schema->add_view( |
720 | name => $def->{'name'}, |
721 | sql => $def->{'sql'}, |
722 | ); |
723 | } |
724 | |
725 | for my $def ( @{ $result->{'triggers'} || [] } ) { |
726 | my $trig = $schema->add_trigger( |
727 | name => $def->{'name'}, |
728 | perform_action_when => $def->{'when'}, |
729 | database_event => $def->{'db_event'}, |
730 | action => $def->{'action'}, |
731 | fields => $def->{'fields'}, |
732 | on_table => $def->{'table'} |
733 | ); |
734 | $trig->extra( reference => $def->{'reference'}, |
735 | condition => $def->{'condition'}, |
736 | granularity => $def->{'granularity'} ); |
737 | } |
738 | |
739 | return 1; |
740 | } |
741 | |
742 | 1; |