File Coverage

script/sqlt-diff-old
Criterion Covered Total %
statement 204 248 82.2
branch 117 218 53.6
condition 21 41 51.2
subroutine 8 8 100.0
pod n/a
total 350 515 67.9


line stmt bran cond sub pod time code
1             #!perl
2             # vim: set ft=perl:
3              
4             # -------------------------------------------------------------------
5             # Copyright (C) 2002-2009 The SQLFairy Authors
6             #
7             # This program is free software; you can redistribute it and/or
8             # modify it under the terms of the GNU General Public License as
9             # published by the Free Software Foundation; version 2.
10             #
11             # This program is distributed in the hope that it will be useful, but
12             # WITHOUT ANY WARRANTY; without even the implied warranty of
13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14             # General Public License for more details.
15             #
16             # You should have received a copy of the GNU General Public License
17             # along with this program; if not, write to the Free Software
18             # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19             # 02110-1301 USA.
20             # -------------------------------------------------------------------
21              
22             =head1 NAME
23              
24             sqlt-diff - find the differences b/w two schemas
25              
26             =head1 SYNOPSIS
27              
28             For help:
29              
30             sqlt-diff -h|--help
31              
32             For a list of all valid parsers:
33              
34             sqlt -l|--list
35              
36             To diff two schemas:
37              
38             sqlt-diff [options] file_name1=parser file_name2=parser
39              
40             Options:
41              
42             -d|--debug Show debugging info
43              
44             =head1 DESCRIPTION
45              
46             sqlt-diff is a utility for creating a file of SQL commands necessary to
47             transform the first schema provided to the second. While not yet
48             exhaustive in its ability to mutate the entire schema, it will report the
49             following
50              
51             =over
52              
53             =item * New tables
54              
55             Using the Producer class of the target (second) schema, any tables missing
56             in the first schema will be generated in their entirety (fields, constraints,
57             indices).
58              
59             =item * Missing/altered fields
60              
61             Any fields missing or altered between the two schemas will be reported
62             as:
63              
64             ALTER TABLE
65             [DROP ]
66             [CHANGE ()] ;
67              
68             =item * Missing/altered indices
69              
70             Any indices missing or of a different type or on different fields will be
71             indicated. Indices that should be dropped will be reported as such:
72              
73             DROP INDEX ON ;
74              
75             An index of a different type or on different fields will be reported as a
76             new index as such:
77              
78             CREATE [] INDEX [] ON
79             ( [,] ) ;
80              
81             =back
82              
83             "ALTER/DROP TABLE" and "CREATE INDEX" statements B generated by
84             the Producer, unfortunately, and may require massaging before being passed to
85             your target database.
86              
87             =cut
88              
89             # -------------------------------------------------------------------
90              
91 5     5   38 use strict;
  5         38  
  5         152  
92 5     5   24 use warnings;
  5         10  
  5         118  
93 5     5   2812 use Pod::Usage;
  5         271044  
  5         583  
94 5     5   3160 use Data::Dumper;
  5         31204  
  5         303  
95 5     5   2786 use SQL::Translator;
  5         27  
  5         201  
96 5     5   50 use SQL::Translator::Schema::Constants;
  5         12  
  5         385  
97              
98 5     5   57 use vars qw( $VERSION );
  5         11  
  5         27422  
99 5         23 $VERSION = '1.63';
100              
101 5         17 my ( @input, $list, $help, $debug );
102 5         20 for my $arg ( @ARGV ) {
103 10 50       114 if ( $arg =~ m/^-?-l(ist)?$/ ) {
    50          
    50          
    50          
104 0         0 $list = 1;
105             }
106             elsif ( $arg =~ m/^-?-h(elp)?$/ ) {
107 0         0 $help = 1;
108             }
109             elsif ( $arg =~ m/^-?-d(ebug)?$/ ) {
110 0         0 $debug = 1;
111             }
112             elsif ( $arg =~ m/^([^=]+)=(.+)$/ ) {
113 10         65 push @input, { file => $1, parser => $2 };
114             }
115             else {
116 0         0 pod2usage( msg => "Unknown argument '$arg'" );
117             }
118             }
119              
120 5 50       22 pod2usage(1) if $help;
121 5 50       33 pod2usage('Please specify only two schemas to diff') if scalar @input > 2;
122 5 50       20 pod2usage('No input') if !@input;
123              
124 5 50 33     67 if ( my $interactive = -t STDIN && -t STDOUT ) {
125 0         0 print STDERR join("\n",
126             "sqlt-diff-old is deprecated. Please sqlt-diff, and tell us ",
127             "about any problems or patch SQL::Translator::Diff",
128             '',
129             );
130             }
131              
132 5         188 my $tr = SQL::Translator->new;
133 5         190 my @parsers = $tr->list_parsers;
134 5         18 my %valid_parsers = map { $_, 1 } @parsers;
  120         208  
135              
136 5 50       30 if ( $list ) {
137 0         0 print "\nParsers:\n", map { "\t$_\n" } sort @parsers;
  0         0  
138 0         0 print "\n";
139 0         0 exit(0);
140             }
141              
142 5 50       21 pod2usage( msg => 'Too many file args' ) if @input > 2;
143              
144 5         15 my ( $source_schema, $source_db, $target_schema, $target_db );
145              
146 5         12 my $i = 2;
147 5         14 for my $in ( @input ) {
148 10         41 my $file = $in->{'file'};
149 10         30 my $parser = $in->{'parser'};
150              
151 10 50       395 die "Unable to read file '$file'\n" unless -r $file;
152 10 50       57 die "'$parser' is an invalid parser\n" unless $valid_parsers{ $parser };
153              
154 10         319 my $t = SQL::Translator->new;
155 10         245 $t->debug( $debug );
156 10 50       258 $t->parser( $parser ) or die $tr->error;
157 10 50       60 my $out = $t->translate( $file ) or die $tr->error;
158 10         212 my $schema = $t->schema;
159 10 50       187 unless ( $schema->name ) {
160 10         55 $schema->name( $file );
161             }
162              
163 10 100       42 if ( $i == 1 ) {
164 5         15 $source_schema = $schema;
165 5         14 $source_db = $parser;
166             }
167             else {
168 5         13 $target_schema = $schema;
169 5         13 $target_db = $parser;
170             }
171 10         179 $i--;
172             }
173 5         20 my $case_insensitive = $target_db =~ /SQLServer/;
174              
175 5         31 my $s1_name = $source_schema->name;
176 5         44 my $s2_name = $target_schema->name;
177 5         34 my ( @new_tables, @diffs , @diffs_at_end);
178 5         60 for my $t1 ( $source_schema->get_tables ) {
179 11         233 my $t1_name = $t1->name;
180 11         320 my $t2 = $target_schema->get_table( $t1_name, $case_insensitive );
181              
182 11 50       40 warn "TABLE '$s1_name.$t1_name'\n" if $debug;
183 11 100       262 unless ( $t2 ) {
184 1 50       6 warn "Couldn't find table '$s1_name.$t1_name' in '$s2_name'\n"
185             if $debug;
186 1 50       5 if ( $target_db =~ /(SQLServer|Oracle)/ ) {
187 0         0 for my $constraint ( $t1->get_constraints ) {
188 0 0       0 next if $constraint->type ne FOREIGN_KEY;
189 0         0 push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
190             constraint_to_string($constraint, $source_schema).";";
191 0         0 $t1->drop_constraint($constraint);
192             }
193             }
194 1         3 push @new_tables, $t1;
195 1         3 next;
196             }
197              
198             # Go through our options
199 10         211 my $options_different = 0;
200 10         29 my %checkedOptions;
201             OPTION:
202 10         221 for my $t1_option_ref ( $t1->options ) {
203 4         15 my($key1, $value1) = %{$t1_option_ref};
  4         18  
204 4         136 for my $t2_option_ref ( $t2->options ) {
205 4         12 my($key2, $value2) = %{$t2_option_ref};
  4         18  
206 4 50       17 if ( $key1 eq $key2 ) {
207 4 50       14 if ( defined $value1 != defined $value2 ) {
208 0         0 $options_different = 1;
209 0         0 last OPTION;
210             }
211 4 100 66     25 if ( defined $value1 && $value1 ne $value2 ) {
212 1         3 $options_different = 1;
213 1         6 last OPTION;
214             }
215 3         9 $checkedOptions{$key1} = 1;
216 3         12 next OPTION;
217             }
218             }
219 0         0 $options_different = 1;
220 0         0 last OPTION;
221             }
222             # Go through the other table's options
223 10 100       38 unless ( $options_different ) {
224 9         204 for my $t2_option_ref ( $t2->options ) {
225 3         9 my($key, $value) = %{$t2_option_ref};
  3         14  
226 3 50       15 next if $checkedOptions{$key};
227 0         0 $options_different = 1;
228 0         0 last;
229             }
230             }
231             # If there's a difference, just re-set all the options
232 10         31 my @diffs_table_options;
233 10 100       35 if ( $options_different ) {
234 1         4 my @options = ();
235 1         20 foreach my $option_ref ( $t1->options ) {
236 1         3 my($key, $value) = %{$option_ref};
  1         5  
237 1 50       10 push(@options, defined $value ? "$key=$value" : $key);
238             }
239 1         6 my $options = join(' ', @options);
240 1         7 @diffs_table_options = ("ALTER TABLE $t1_name $options;");
241             }
242              
243 10         401 my $t2_name = $t2->name;
244 10         220 my(@diffs_table_adds, @diffs_table_changes);
245 10         57 for my $t1_field ( $t1->get_fields ) {
246 42         181 my $f1_type = $t1_field->data_type;
247 42         1003 my $f1_size = $t1_field->size;
248 42         1178 my $f1_name = $t1_field->name;
249 42         1625 my $f1_nullable = $t1_field->is_nullable;
250 42         2592 my $f1_default = $t1_field->default_value;
251 42         666 my $f1_auto_inc = $t1_field->is_auto_increment;
252 42         582 my $t2_field = $t2->get_field( $f1_name, $case_insensitive );
253 42         402 my $f1_full_name = "$s1_name.$t1_name.$t1_name";
254 42 50       154 warn "FIELD '$f1_full_name'\n" if $debug;
255              
256 42         118 my $f2_full_name = "$s2_name.$t2_name.$f1_name";
257              
258 42 100       356 unless ( $t2_field ) {
259 3 50       13 warn "Couldn't find field '$f2_full_name' in '$t2_name'\n"
260             if $debug;
261 3         5 my $temp_default_value = 0;
262 3 0 33     14 if ( $target_db =~ /SQLServer/ && !$f1_nullable && !defined $f1_default ) {
      33        
263             # SQL Server doesn't allow adding non-nullable, non-default columns
264             # so we add it with a default value, then remove the default value
265 0         0 $temp_default_value = 1;
266 0         0 my(@numeric_types) = qw(decimal numeric float real int bigint smallint tinyint);
267 0 0       0 $f1_default = grep($_ eq $f1_type, @numeric_types) ? 0 : '';
268             }
269 3 50 100     77 push @diffs_table_adds, sprintf( "ALTER TABLE %s ADD %s%s %s%s%s%s%s%s;",
    100          
    50          
    50          
    100          
    50          
    50          
    50          
270             $t1_name, $target_db =~ /Oracle/ ? '(' : '',
271             $f1_name, $f1_type,
272             ($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
273             !defined $f1_default ? ''
274             : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
275             : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
276             : " DEFAULT '$f1_default'",
277             $f1_nullable ? '' : ' NOT NULL',
278             $f1_auto_inc ? ' AUTO_INCREMENT' : '',
279             $target_db =~ /Oracle/ ? ')' : '',
280             );
281 3 50       11 if ( $temp_default_value ) {
282 0         0 undef $f1_default;
283 0         0 push @diffs_table_adds, sprintf( <
284             DECLARE \@defname VARCHAR(100), \@cmd VARCHAR(1000)
285             SET \@defname =
286             (SELECT name
287             FROM sysobjects so JOIN sysconstraints sc
288             ON so.id = sc.constid
289             WHERE object_name(so.parent_obj) = '%s'
290             AND so.xtype = 'D'
291             AND sc.colid =
292             (SELECT colid FROM syscolumns
293             WHERE id = object_id('%s') AND
294             name = '%s'))
295             SET \@cmd = 'ALTER TABLE %s DROP CONSTRAINT '
296             + \@defname
297             EXEC(\@cmd)
298             END
299             , $t1_name, $t1_name, $f1_name, $t1_name,
300             );
301             }
302 3         11 next;
303             }
304              
305 39         869 my $f2_type = $t2_field->data_type;
306 39   100     749 my $f2_size = $t2_field->size || '';
307 39         1177 my $f2_nullable = $t2_field->is_nullable;
308 39         2201 my $f2_default = $t2_field->default_value;
309 39         615 my $f2_auto_inc = $t2_field->is_auto_increment;
310 39 100       1524 if ( !$t1_field->equals($t2_field, $case_insensitive) ) {
311             # SQLServer timestamp fields can't be altered, so we drop and add instead
312 6 50 33     125 if ( $target_db =~ /SQLServer/ && $f2_type eq "timestamp" ) {
313 0         0 push @diffs_table_changes, "ALTER TABLE $t1_name DROP COLUMN $f1_name;";
314 0 0 0     0 push @diffs_table_changes, sprintf( "ALTER TABLE %s ADD %s%s %s%s%s%s%s%s;",
    0          
    0          
    0          
    0          
    0          
    0          
    0          
315             $t1_name, $target_db =~ /Oracle/ ? '(' : '',
316             $f1_name, $f1_type,
317             ($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
318             !defined $f1_default ? ''
319             : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
320             : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
321             : " DEFAULT '$f1_default'",
322             $f1_nullable ? '' : ' NOT NULL',
323             $f1_auto_inc ? ' AUTO_INCREMENT' : '',
324             $target_db =~ /Oracle/ ? ')' : '',
325             );
326 0         0 next;
327             }
328              
329 6 50       22 my $changeText = $target_db =~ /SQLServer/ ? 'ALTER COLUMN' :
    50          
330             $target_db =~ /Oracle/ ? 'MODIFY (' : 'CHANGE';
331 6 100       15 my $nullText = $f1_nullable ? '' : ' NOT NULL';
332 6 50 33     23 $nullText = '' if $target_db =~ /Oracle/ && $f1_nullable == $f2_nullable;
333 6 100 66     139 push @diffs_table_changes, sprintf( "ALTER TABLE %s %s %s%s %s%s%s%s%s%s;",
    100 66        
    50          
    50          
    100          
    100          
    50          
334             $t1_name, $changeText,
335             $f1_name, $target_db =~ /MySQL/ ? " $f1_name" : '',
336             $f1_type, ($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
337             $nullText,
338             !defined $f1_default || $target_db =~ /SQLServer/ ? ''
339             : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
340             : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
341             : " DEFAULT '$f1_default'",
342             $f1_auto_inc ? ' AUTO_INCREMENT' : '',
343             $target_db =~ /Oracle/ ? ')' : '',
344             );
345 6 50 66     38 if ( defined $f1_default && $target_db =~ /SQLServer/ ) {
346             # Adding a column with a default value for SQL Server means adding a
347             # constraint and setting existing NULLs to the default value
348 0 0       0 push @diffs_table_changes, sprintf( "ALTER TABLE %s ADD CONSTRAINT DF_%s_%s %s FOR %s;",
    0          
349             $t1_name, $t1_name, $f1_name, uc $f1_default eq 'NULL' ? 'DEFAULT NULL'
350             : uc $f1_default eq 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP'
351             : "DEFAULT '$f1_default'", $f1_name,
352             );
353 0 0       0 push @diffs_table_changes, sprintf( "UPDATE %s SET %s = %s WHERE %s IS NULL;",
    0          
354             $t1_name, $f1_name, uc $f1_default eq 'NULL' ? 'NULL'
355             : uc $f1_default eq 'CURRENT_TIMESTAMP' ? 'CURRENT_TIMESTAMP'
356             : "'$f1_default'", $f1_name,
357             );
358             }
359             }
360             }
361              
362 10         43 my(%checked_indices, @diffs_index_creates, @diffs_index_drops);
363             INDEX:
364 10         45 for my $i1 ( $t1->get_indices ) {
365 2         42 for my $i2 ( $t2->get_indices ) {
366 2 100       76 if ( $i1->equals($i2, $case_insensitive) ) {
367 1         5 $checked_indices{$i2} = 1;
368 1         6 next INDEX;
369             }
370             }
371 1 50       51 push @diffs_index_creates, sprintf(
    50          
372             "CREATE %sINDEX%s ON %s (%s);",
373             $i1->type eq NORMAL ? '' : $i1->type." ",
374             $i1->name ? " ".$i1->name : '',
375             $t1_name,
376             join(",", $i1->fields),
377             );
378             }
379             INDEX2:
380 10         42 for my $i2 ( $t2->get_indices ) {
381 2 100       60 next if $checked_indices{$i2};
382 1         21 for my $i1 ( $t1->get_indices ) {
383 1 50       46 next INDEX2 if $i2->equals($i1, $case_insensitive);
384             }
385 1 50       48 $target_db =~ /SQLServer/
386             ? push @diffs_index_drops, "DROP INDEX $t1_name.".$i2->name.";"
387             : push @diffs_index_drops, "DROP INDEX ".$i2->name." on $t1_name;";
388             }
389              
390 10         64 my(%checked_constraints, @diffs_constraint_drops);
391             CONSTRAINT:
392 10         39 for my $c1 ( $t1->get_constraints ) {
393 22 50 66     244 next if $source_db =~ /Oracle/ && $c1->type eq UNIQUE && $c1->name =~ /^SYS_/i;
      33        
394 22         147 for my $c2 ( $t2->get_constraints ) {
395 42 100       1312 if ( $c1->equals($c2, $case_insensitive) ) {
396 17         67 $checked_constraints{$c2} = 1;
397 17         92 next CONSTRAINT;
398             }
399             }
400 5         98 push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
401             constraint_to_string($c1, $source_schema).";";
402             }
403             CONSTRAINT2:
404 10         75 for my $c2 ( $t2->get_constraints ) {
405 22 100       199 next if $checked_constraints{$c2};
406 5         34 for my $c1 ( $t1->get_constraints ) {
407 13 50       371 next CONSTRAINT2 if $c2->equals($c1, $case_insensitive);
408             }
409 5 100       165 if ( $c2->type eq UNIQUE ) {
    50          
410 1         38 push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP INDEX ".
411             $c2->name.";";
412             } elsif ( $target_db =~ /SQLServer/ ) {
413 0         0 push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->name.";";
414             } else {
415 4 100       179 push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->type.
416             ($c2->type eq FOREIGN_KEY ? " ".$c2->name : '').";";
417             }
418             }
419              
420 10         72 push @diffs, @diffs_index_drops, @diffs_constraint_drops,
421             @diffs_table_options, @diffs_table_adds,
422             @diffs_table_changes, @diffs_index_creates;
423             }
424              
425 5         35 for my $t2 ( $target_schema->get_tables ) {
426 11         297 my $t2_name = $t2->name;
427 11         253 my $t1 = $source_schema->get_table( $t2_name, $target_db =~ /SQLServer/ );
428              
429 11 100       42 unless ( $t1 ) {
430 1 50       15 if ( $target_db =~ /SQLServer/ ) {
431 0         0 for my $constraint ( $t2->get_constraints ) {
432 0 0       0 next if $constraint->type eq PRIMARY_KEY;
433 0         0 push @diffs, "ALTER TABLE $t2_name DROP ".$constraint->name.";";
434             }
435             }
436 1         22 push @diffs_at_end, "DROP TABLE $t2_name;";
437 1         7 next;
438             }
439              
440 10         237 for my $t2_field ( $t2->get_fields ) {
441 41         1298 my $f2_name = $t2_field->name;
442 41         825 my $t1_field = $t1->get_field( $f2_name );
443 41 100       353 unless ( $t1_field ) {
444 2 50       9 my $modifier = $target_db =~ /SQLServer/ ? "COLUMN " : '';
445 2         12 push @diffs, "ALTER TABLE $t2_name DROP $modifier$f2_name;";
446             }
447             }
448             }
449              
450 5 100       120 if ( @new_tables ) {
451 1         36 my $dummy_tr = SQL::Translator->new;
452 1         43 $dummy_tr->schema->add_table( $_ ) for @new_tables;
453 1         23 my $producer = $dummy_tr->producer( $target_db );
454 1         5 unshift @diffs, $producer->( $dummy_tr );
455             }
456 5         25 push(@diffs, @diffs_at_end);
457              
458 5 100       23 if ( @diffs ) {
459 3 100       261 if ( $source_db !~ /^(MySQL|SQLServer|Oracle)$/ ) {
460 1         9 unshift(@diffs, "-- Target database $target_db is untested/unsupported!!!");
461             }
462             }
463              
464 5 100       38 if ( @diffs ) {
465 3         63 print join( "\n",
466             "-- Convert schema '$s2_name' to '$s1_name':\n", @diffs, "\n"
467             );
468 3         1048 exit(1);
469             }
470             else {
471 2         958 print "There were no differences.\n";
472             }
473              
474             sub constraint_to_string {
475 5     5   25 my $c = shift;
476 5 50       16 my $schema = shift or die "No schema given";
477 5 100       105 my @fields = $c->field_names or return '';
478              
479 4 50       78 if ( $c->type eq PRIMARY_KEY ) {
    100          
    50          
480 0 0       0 if ( $target_db =~ /Oracle/ ) {
481 0 0       0 return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
482             'PRIMARY KEY (' . join(', ', @fields). ')';
483             } else {
484 0         0 return 'PRIMARY KEY (' . join(', ', @fields). ')';
485             }
486             }
487             elsif ( $c->type eq UNIQUE ) {
488 2 50       51 if ( $target_db =~ /Oracle/ ) {
489 0 0       0 return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
490             'UNIQUE (' . join(', ', @fields). ')';
491             } else {
492 2 50       66 return 'UNIQUE '.
493             (defined $c->name ? $c->name.' ' : '').
494             '(' . join(', ', @fields). ')';
495             }
496             }
497             elsif ( $c->type eq FOREIGN_KEY ) {
498             my $def = join(' ',
499 2 50       93 map { $_ || () } 'CONSTRAINT', $c->name, 'FOREIGN KEY'
  6         25  
500             );
501              
502 2         9 $def .= ' (' . join( ', ', @fields ) . ')';
503              
504 2         18 $def .= ' REFERENCES ' . $c->reference_table;
505              
506 2 50       44 my @rfields = map { $_ || () } $c->reference_fields;
  2         16  
507 2 50       11 unless ( @rfields ) {
508 0         0 my $rtable_name = $c->reference_table;
509 0 0       0 if ( my $ref_table = $schema->get_table( $rtable_name ) ) {
510 0         0 push @rfields, $ref_table->primary_key;
511             }
512             else {
513 0         0 warn "Can't find reference table '$rtable_name' " .
514             "in schema\n";
515             }
516             }
517              
518 2 50       7 if ( @rfields ) {
519 2         11 $def .= ' (' . join( ', ', @rfields ) . ')';
520             }
521             else {
522 0         0 warn "FK constraint on " . 'some table' . '.' .
523             join('', @fields) . " has no reference fields\n";
524             }
525              
526 2 50       48 if ( $c->match_type ) {
527 0 0       0 $def .= ' MATCH ' .
528             ( $c->match_type =~ /full/i ) ? 'FULL' : 'PARTIAL';
529             }
530              
531 2 100       105 if ( $c->on_delete ) {
532 1         19 $def .= ' ON DELETE '.join( ' ', $c->on_delete );
533             }
534              
535 2 50       48 if ( $c->on_update ) {
536 0         0 $def .= ' ON UPDATE '.join( ' ', $c->on_update );
537             }
538              
539 2         14 return $def;
540             }
541             }
542              
543             # -------------------------------------------------------------------
544             # Bring out number weight & measure in a year of dearth.
545             # William Blake
546             # -------------------------------------------------------------------
547              
548             =pod
549              
550             =head1 AUTHOR
551              
552             Ken Youens-Clark Ekclark@cpan.orgE.
553              
554             =head1 SEE ALSO
555              
556             SQL::Translator, L.
557              
558             =cut