File Coverage

script/sqlt-diff
Criterion Covered Total %
statement 57 62 91.9
branch 11 22 50.0
condition 13 23 56.5
subroutine 9 9 100.0
pod n/a
total 90 116 77.5


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, MAb
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=parser1 file_name2=parser2
39              
40             Options:
41              
42             -d|--debug Show debugging info
43             -t|--trace Turn on tracing for Parse::RecDescent
44             -c|--case-insensitive Compare tables/columns case-insensitively
45             --ignore-index-names Ignore index name differences
46             --ignore-constraint-names Ignore constraint name differences
47             --mysql_parser_version=<#####> Specify a target MySQL parser version
48             for dealing with /*! comments
49             --output-db= This Producer will be used instead of one
50             corresponding to parser1 to format output
51             for new tables
52             --ignore-view-sql Ignore view SQL differences
53             --ignore-proc-sql Ignore procedure SQL differences
54             --no-batch-alters Do not clump multile alters to the same table into a
55             single ALTER TABLE statement where possible.
56             --quote= Use to quote all table and field
57             names in statements
58              
59             =head1 DESCRIPTION
60              
61             sqlt-diff is a utility for creating a file of SQL commands necessary to
62             transform the first schema provided to the second. While not yet
63             exhaustive in its ability to mutate the entire schema, it will report the
64             following
65              
66             =over
67              
68             =item * New tables
69              
70             Using the Producer class of the target (second) schema, any tables missing
71             in the first schema will be generated in their entirety (fields, constraints,
72             indices).
73              
74             =item * Missing/altered fields
75              
76             Any fields missing or altered between the two schemas will be reported
77             as:
78              
79             ALTER TABLE
80             [DROP ]
81             [CHANGE ()] ;
82              
83             =item * Missing/altered indices
84              
85             Any indices missing or of a different type or on different fields will be
86             indicated. Indices that should be dropped will be reported as such:
87              
88             DROP INDEX ON ;
89              
90             An index of a different type or on different fields will be reported as a
91             new index as such:
92              
93             CREATE [] INDEX [] ON
94             ( [,] ) ;
95              
96             =back
97              
98             ALTER, CREATE, DROP statements are created by
99             SQL::Translator::Producer::*, see there for support/problems.
100              
101             Currently (v0.0900), only MySQL is supported by this code.
102              
103             =cut
104              
105             # -------------------------------------------------------------------
106              
107 3     3   20 use strict;
  3         19  
  3         74  
108 3     3   13 use warnings;
  3         4  
  3         60  
109 3     3   1311 use Pod::Usage;
  3         133550  
  3         331  
110 3     3   1493 use Data::Dumper;
  3         15271  
  3         145  
111 3     3   1856 use Getopt::Long;
  3         25497  
  3         11  
112 3     3   1533 use SQL::Translator;
  3         11  
  3         89  
113 3     3   1118 use SQL::Translator::Diff;
  3         7  
  3         82  
114 3     3   18 use SQL::Translator::Schema::Constants;
  3         4  
  3         147  
115              
116 3     3   14 use vars qw( $VERSION );
  3         6  
  3         5810  
117 3         13 $VERSION = '1.6_3';
118              
119 3         13 my ( @input, $list, $help, $debug, $trace, $caseopt, $ignore_index_names,
120             $ignore_constraint_names, $output_db, $mysql_parser_version,
121             $ignore_view_sql, $ignore_proc_sql, $no_batch_alters, $quote
122             );
123              
124 3 50       24 GetOptions(
125             'l|list' => \$list,
126             'h|help' => \$help,
127             'd|debug' => \$debug,
128             't|trace' => \$trace,
129             'c|case-insensitive' => \$caseopt,
130             'ignore-index-names' => \$ignore_index_names,
131             'ignore-constraint-names' => \$ignore_constraint_names,
132             'mysql_parser_version:s' => \$mysql_parser_version,
133             'output-db:s' => \$output_db,
134             'ignore-view-sql' => \$ignore_view_sql,
135             'ignore-proc-sql' => \$ignore_proc_sql,
136             'quote:s' => \$quote,
137             'no-batch-alters' => \$no_batch_alters,
138             ) or pod2usage(2);
139              
140 3         2565 for my $arg ( @ARGV ) {
141 6 50       39 if ( $arg =~ m/^([^=]+)=(.+)$/ ) {
142 6         26 push @input, { file => $1, parser => $2 };
143             }
144             }
145              
146 3         81 my $tr = SQL::Translator->new;
147 3         87 my @parsers = $tr->list_parsers;
148 3         11 my %valid_parsers = map { $_, 1 } @parsers;
  72         97  
149              
150              
151 3 50       16 if ( $list ) {
152 0         0 print "\nParsers:\n", map { "\t$_\n" } sort @parsers;
  0         0  
153 0         0 print "\n";
154 0         0 exit(0);
155             }
156              
157 3 50 33     30 pod2usage(1) if $help || !@input;
158 3 50       10 pod2usage(msg => 'Please specify two schemas to diff') if scalar @input != 2;
159              
160             my ( $source_schema, $source_db, $target_schema, $target_db ) = map {
161 3         8 my $file = $_->{'file'};
  6         20  
162 6         21 my $parser = $_->{'parser'};
163              
164 6 50       221 die "Unable to read file '$file'\n" unless -r $file;
165 6 50       30 die "'$parser' is an invalid parser\n" unless $valid_parsers{ $parser };
166              
167 6         177 my $t = SQL::Translator->new(parser_args => {
168             mysql_parser_version => $mysql_parser_version
169             });
170 6         123 $t->debug( $debug );
171 6         117 $t->trace( $trace );
172 6 50       229 $t->parser( $parser ) or die $tr->error;
173 6 50       27 my $out = $t->translate( $file ) or die $tr->error;
174 6         96 my $schema = $t->schema;
175 6 50       71 unless ( $schema->name ) {
176 6         25 $schema->name( $file );
177             }
178              
179 6         113 ($schema, $parser);
180             } @input;
181              
182 3   50     186 my $result = SQL::Translator::Diff::schema_diff(
      50        
      50        
      50        
      50        
      50        
      50        
      50        
      100        
      100        
183             $source_schema, $source_db,
184             $target_schema, $target_db,
185             {
186             caseopt => $caseopt || 0,
187             ignore_index_names => $ignore_index_names || 0,
188             ignore_constraint_names => $ignore_constraint_names || 0,
189             ignore_view_sql => $ignore_view_sql || 0,
190             ignore_proc_sql => $ignore_proc_sql || 0,
191             output_db => $output_db,
192             no_batch_alters => $no_batch_alters || 0,
193             debug => $debug || 0,
194             trace => $trace || 0,
195             sqlt_args => {
196             quote_table_names => $quote || '',
197             quote_field_names => $quote || '',
198             },
199             }
200             );
201              
202 3 50       68 if($result)
203             {
204 3         1051 print $result;
205             }
206             else
207             {
208 0         0 print "No differences found.";
209             }
210              
211             # -------------------------------------------------------------------
212             # Bring out number weight & measure in a year of dearth.
213             # William Blake
214             # -------------------------------------------------------------------
215              
216             =pod
217              
218             =head1 AUTHOR
219              
220             Ken Youens-Clark Ekclark@cpan.orgE.
221              
222             =head1 SEE ALSO
223              
224             SQL::Translator, L.
225              
226             =cut