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   40 use strict;
  5         32  
  5         132  
92 5     5   22 use warnings;
  5         8  
  5         116  
93 5     5   2177 use Pod::Usage;
  5         219030  
  5         588  
94 5     5   2649 use Data::Dumper;
  5         25757  
  5         330  
95 5     5   2412 use SQL::Translator;
  5         17  
  5         154  
96 5     5   28 use SQL::Translator::Schema::Constants;
  5         10  
  5         349  
97              
98 5     5   26 use vars qw( $VERSION );
  5         7  
  5         22266  
99 5         17 $VERSION = '1.6_3';
100              
101 5         15 my ( @input, $list, $help, $debug );
102 5         13 for my $arg ( @ARGV ) {
103 10 50       94 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         54 push @input, { file => $1, parser => $2 };
114             }
115             else {
116 0         0 pod2usage( msg => "Unknown argument '$arg'" );
117             }
118             }
119              
120 5 50       17 pod2usage(1) if $help;
121 5 50       28 pod2usage('Please specify only two schemas to diff') if scalar @input > 2;
122 5 50       16 pod2usage('No input') if !@input;
123              
124 5 50 33     52 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         160 my $tr = SQL::Translator->new;
133 5         127 my @parsers = $tr->list_parsers;
134 5         31 my %valid_parsers = map { $_, 1 } @parsers;
  120         170  
135              
136 5 50       27 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       17 pod2usage( msg => 'Too many file args' ) if @input > 2;
143              
144 5         14 my ( $source_schema, $source_db, $target_schema, $target_db );
145              
146 5         10 my $i = 2;
147 5         14 for my $in ( @input ) {
148 10         34 my $file = $in->{'file'};
149 10         25 my $parser = $in->{'parser'};
150              
151 10 50       324 die "Unable to read file '$file'\n" unless -r $file;
152 10 50       43 die "'$parser' is an invalid parser\n" unless $valid_parsers{ $parser };
153              
154 10         295 my $t = SQL::Translator->new;
155 10         189 $t->debug( $debug );
156 10 50       193 $t->parser( $parser ) or die $tr->error;
157 10 50       50 my $out = $t->translate( $file ) or die $tr->error;
158 10         178 my $schema = $t->schema;
159 10 50       97 unless ( $schema->name ) {
160 10         41 $schema->name( $file );
161             }
162              
163 10 100       34 if ( $i == 1 ) {
164 5         14 $source_schema = $schema;
165 5         12 $source_db = $parser;
166             }
167             else {
168 5         11 $target_schema = $schema;
169 5         11 $target_db = $parser;
170             }
171 10         149 $i--;
172             }
173 5         16 my $case_insensitive = $target_db =~ /SQLServer/;
174              
175 5         28 my $s1_name = $source_schema->name;
176 5         38 my $s2_name = $target_schema->name;
177 5         47 my ( @new_tables, @diffs , @diffs_at_end);
178 5         48 for my $t1 ( $source_schema->get_tables ) {
179 11         203 my $t1_name = $t1->name;
180 11         246 my $t2 = $target_schema->get_table( $t1_name, $case_insensitive );
181              
182 11 50       36 warn "TABLE '$s1_name.$t1_name'\n" if $debug;
183 11 100       230 unless ( $t2 ) {
184 1 50       5 warn "Couldn't find table '$s1_name.$t1_name' in '$s2_name'\n"
185             if $debug;
186 1 50       4 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         4 next;
196             }
197              
198             # Go through our options
199 10         180 my $options_different = 0;
200 10         20 my %checkedOptions;
201             OPTION:
202 10         197 for my $t1_option_ref ( $t1->options ) {
203 4         13 my($key1, $value1) = %{$t1_option_ref};
  4         13  
204 4         64 for my $t2_option_ref ( $t2->options ) {
205 4         9 my($key2, $value2) = %{$t2_option_ref};
  4         13  
206 4 50       15 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         2 $options_different = 1;
213 1         4 last OPTION;
214             }
215 3         9 $checkedOptions{$key1} = 1;
216 3         10 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       29 unless ( $options_different ) {
224 9         159 for my $t2_option_ref ( $t2->options ) {
225 3         8 my($key, $value) = %{$t2_option_ref};
  3         10  
226 3 50       13 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         22 my @diffs_table_options;
233 10 100       29 if ( $options_different ) {
234 1         1 my @options = ();
235 1         17 foreach my $option_ref ( $t1->options ) {
236 1         3 my($key, $value) = %{$option_ref};
  1         4  
237 1 50       5 push(@options, defined $value ? "$key=$value" : $key);
238             }
239 1         4 my $options = join(' ', @options);
240 1         3 @diffs_table_options = ("ALTER TABLE $t1_name $options;");
241             }
242              
243 10         366 my $t2_name = $t2->name;
244 10         166 my(@diffs_table_adds, @diffs_table_changes);
245 10         42 for my $t1_field ( $t1->get_fields ) {
246 42         139 my $f1_type = $t1_field->data_type;
247 42         804 my $f1_size = $t1_field->size;
248 42         979 my $f1_name = $t1_field->name;
249 42         1295 my $f1_nullable = $t1_field->is_nullable;
250 42         2140 my $f1_default = $t1_field->default_value;
251 42         599 my $f1_auto_inc = $t1_field->is_auto_increment;
252 42         495 my $t2_field = $t2->get_field( $f1_name, $case_insensitive );
253 42         331 my $f1_full_name = "$s1_name.$t1_name.$t1_name";
254 42 50       97 warn "FIELD '$f1_full_name'\n" if $debug;
255              
256 42         109 my $f2_full_name = "$s2_name.$t2_name.$f1_name";
257              
258 42 100       319 unless ( $t2_field ) {
259 3 50       11 warn "Couldn't find field '$f2_full_name' in '$t2_name'\n"
260             if $debug;
261 3         6 my $temp_default_value = 0;
262 3 0 33     24 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     61 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       10 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         9 next;
303             }
304              
305 39         700 my $f2_type = $t2_field->data_type;
306 39   100     634 my $f2_size = $t2_field->size || '';
307 39         1003 my $f2_nullable = $t2_field->is_nullable;
308 39         1810 my $f2_default = $t2_field->default_value;
309 39         586 my $f2_auto_inc = $t2_field->is_auto_increment;
310 39 100       957 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     79 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       19 my $changeText = $target_db =~ /SQLServer/ ? 'ALTER COLUMN' :
    50          
330             $target_db =~ /Oracle/ ? 'MODIFY (' : 'CHANGE';
331 6 100       13 my $nullText = $f1_nullable ? '' : ' NOT NULL';
332 6 50 33     16 $nullText = '' if $target_db =~ /Oracle/ && $f1_nullable == $f2_nullable;
333 6 100 66     98 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     30 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         35 my(%checked_indices, @diffs_index_creates, @diffs_index_drops);
363             INDEX:
364 10         45 for my $i1 ( $t1->get_indices ) {
365 2         31 for my $i2 ( $t2->get_indices ) {
366 2 100       51 if ( $i1->equals($i2, $case_insensitive) ) {
367 1         5 $checked_indices{$i2} = 1;
368 1         5 next INDEX;
369             }
370             }
371 1 50       28 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         34 for my $i2 ( $t2->get_indices ) {
381 2 100       24 next if $checked_indices{$i2};
382 1         4 for my $i1 ( $t1->get_indices ) {
383 1 50       21 next INDEX2 if $i2->equals($i1, $case_insensitive);
384             }
385 1 50       26 $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         28 my(%checked_constraints, @diffs_constraint_drops);
391             CONSTRAINT:
392 10         37 for my $c1 ( $t1->get_constraints ) {
393 22 50 66     190 next if $source_db =~ /Oracle/ && $c1->type eq UNIQUE && $c1->name =~ /^SYS_/i;
      33        
394 22         104 for my $c2 ( $t2->get_constraints ) {
395 42 100       1231 if ( $c1->equals($c2, $case_insensitive) ) {
396 17         59 $checked_constraints{$c2} = 1;
397 17         66 next CONSTRAINT;
398             }
399             }
400 5         70 push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
401             constraint_to_string($c1, $source_schema).";";
402             }
403             CONSTRAINT2:
404 10         47 for my $c2 ( $t2->get_constraints ) {
405 22 100       160 next if $checked_constraints{$c2};
406 5         19 for my $c1 ( $t1->get_constraints ) {
407 13 50       326 next CONSTRAINT2 if $c2->equals($c1, $case_insensitive);
408             }
409 5 100       130 if ( $c2->type eq UNIQUE ) {
    50          
410 1         35 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       141 push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->type.
416             ($c2->type eq FOREIGN_KEY ? " ".$c2->name : '').";";
417             }
418             }
419              
420 10         63 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         33 for my $t2 ( $target_schema->get_tables ) {
426 11         242 my $t2_name = $t2->name;
427 11         207 my $t1 = $source_schema->get_table( $t2_name, $target_db =~ /SQLServer/ );
428              
429 11 100       40 unless ( $t1 ) {
430 1 50       7 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         21 push @diffs_at_end, "DROP TABLE $t2_name;";
437 1         4 next;
438             }
439              
440 10         189 for my $t2_field ( $t2->get_fields ) {
441 41         1088 my $f2_name = $t2_field->name;
442 41         657 my $t1_field = $t1->get_field( $f2_name );
443 41 100       633 unless ( $t1_field ) {
444 2 50       8 my $modifier = $target_db =~ /SQLServer/ ? "COLUMN " : '';
445 2         11 push @diffs, "ALTER TABLE $t2_name DROP $modifier$f2_name;";
446             }
447             }
448             }
449              
450 5 100       85 if ( @new_tables ) {
451 1         27 my $dummy_tr = SQL::Translator->new;
452 1         50 $dummy_tr->schema->add_table( $_ ) for @new_tables;
453 1         18 my $producer = $dummy_tr->producer( $target_db );
454 1         6 unshift @diffs, $producer->( $dummy_tr );
455             }
456 5         17 push(@diffs, @diffs_at_end);
457              
458 5 100       18 if ( @diffs ) {
459 3 100       228 if ( $source_db !~ /^(MySQL|SQLServer|Oracle)$/ ) {
460 1         7 unshift(@diffs, "-- Target database $target_db is untested/unsupported!!!");
461             }
462             }
463              
464 5 100       18 if ( @diffs ) {
465 3         44 print join( "\n",
466             "-- Convert schema '$s2_name' to '$s1_name':\n", @diffs, "\n"
467             );
468 3         869 exit(1);
469             }
470             else {
471 2         817 print "There were no differences.\n";
472             }
473              
474             sub constraint_to_string {
475 5     5   11 my $c = shift;
476 5 50       13 my $schema = shift or die "No schema given";
477 5 100       84 my @fields = $c->field_names or return '';
478              
479 4 50       65 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       37 if ( $target_db =~ /Oracle/ ) {
489 0 0       0 return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
490             'UNIQUE (' . join(', ', @fields). ')';
491             } else {
492 2 50       37 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       77 map { $_ || () } 'CONSTRAINT', $c->name, 'FOREIGN KEY'
  6         23  
500             );
501              
502 2         11 $def .= ' (' . join( ', ', @fields ) . ')';
503              
504 2         13 $def .= ' REFERENCES ' . $c->reference_table;
505              
506 2 50       37 my @rfields = map { $_ || () } $c->reference_fields;
  2         15  
507 2 50       9 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       8 if ( @rfields ) {
519 2         9 $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       40 if ( $c->match_type ) {
527 0 0       0 $def .= ' MATCH ' .
528             ( $c->match_type =~ /full/i ) ? 'FULL' : 'PARTIAL';
529             }
530              
531 2 100       76 if ( $c->on_delete ) {
532 1         17 $def .= ' ON DELETE '.join( ' ', $c->on_delete );
533             }
534              
535 2 50       35 if ( $c->on_update ) {
536 0         0 $def .= ' ON UPDATE '.join( ' ', $c->on_update );
537             }
538              
539 2         13 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