File Coverage

script/sqlt-diff
Criterion Covered Total %
statement 60 65 92.3
branch 11 22 50.0
condition 13 23 56.5
subroutine 10 10 100.0
pod n/a
total 94 120 78.3


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         5  
  3         114  
108 3     3   17 use warnings;
  3         6  
  3         160  
109 3     3   2167 use Pod::Usage;
  3         296999  
  3         482  
110 3     3   2167 use Data::Dumper;
  3         30801  
  3         296  
111 3     3   2537 use Getopt::Long;
  3         54615  
  3         23  
112 3     3   3122 use SQL::Translator;
  3         21  
  3         147  
113 3     3   2020 use SQL::Translator::Diff;
  3         18  
  3         146  
114 3     3   26 use SQL::Translator::Schema::Constants;
  3         9  
  3         303  
115              
116 3     3   22 use vars qw( $VERSION );
  3         8  
  3         9082  
117 3         941168 $VERSION = '1.66';
118              
119 3         12 my (@input, $list, $help, $debug, $trace, $caseopt, $ignore_index_names, $ignore_constraint_names, $output_db,
120             $mysql_parser_version, $ignore_view_sql, $ignore_proc_sql, $no_batch_alters, $quote);
121              
122 3 50       38 GetOptions(
123             'l|list' => \$list,
124             'h|help' => \$help,
125             'd|debug' => \$debug,
126             't|trace' => \$trace,
127             'c|case-insensitive' => \$caseopt,
128             'ignore-index-names' => \$ignore_index_names,
129             'ignore-constraint-names' => \$ignore_constraint_names,
130             'mysql_parser_version:s' => \$mysql_parser_version,
131             'output-db:s' => \$output_db,
132             'ignore-view-sql' => \$ignore_view_sql,
133             'ignore-proc-sql' => \$ignore_proc_sql,
134             'quote:s' => \$quote,
135             'no-batch-alters' => \$no_batch_alters,
136             ) or pod2usage(2);
137              
138 3         6324 for my $arg (@ARGV) {
139 6 50       46 if ($arg =~ m/^([^=]+)=(.+)$/) {
140 6         42 push @input, { file => $1, parser => $2 };
141             }
142             }
143              
144 3         197 my $tr = SQL::Translator->new;
145 3         115 my @parsers = $tr->list_parsers;
146 3         14 my %valid_parsers = map { $_, 1 } @parsers;
  72         156  
147              
148 3 50       20 if ($list) {
149 0         0 print "\nParsers:\n", map {"\t$_\n"} sort @parsers;
  0         0  
150 0         0 print "\n";
151 0         0 exit(0);
152             }
153              
154 3 50 33     34 pod2usage(1) if $help || !@input;
155 3 50       50 pod2usage(msg => 'Please specify two schemas to diff') if scalar @input != 2;
156              
157             my ($source_schema, $source_db, $target_schema, $target_db) = map {
158 3         11 my $file = $_->{'file'};
  6         29  
159 6         17 my $parser = $_->{'parser'};
160              
161 6 50       299 die "Unable to read file '$file'\n" unless -r $file;
162 6 50       32 die "'$parser' is an invalid parser\n" unless $valid_parsers{$parser};
163              
164 6         269 my $t = SQL::Translator->new(parser_args => {
165             mysql_parser_version => $mysql_parser_version
166             });
167 6         176 $t->debug($debug);
168 6         178 $t->trace($trace);
169 6 50       350 $t->parser($parser) or die $tr->error;
170 6 50       31 my $out = $t->translate($file) or die $tr->error;
171 6         204 my $schema = $t->schema;
172              
173 6 50       88 unless ($schema->name) {
174 6         58 $schema->name($file);
175             }
176              
177 6         209 ($schema, $parser);
178             } @input;
179              
180 3   50     1225 my $result = SQL::Translator::Diff::schema_diff(
      50        
      50        
      50        
      50        
      50        
      50        
      50        
      100        
      100        
181             $source_schema,
182             $source_db,
183             $target_schema,
184             $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       121 if ($result) {
203 3         1432 print $result;
204             } else {
205 0         0 print "No differences found.";
206             }
207              
208             # -------------------------------------------------------------------
209             # Bring out number weight & measure in a year of dearth.
210             # William Blake
211             # -------------------------------------------------------------------
212              
213             =pod
214              
215             =head1 AUTHOR
216              
217             Ken Youens-Clark Ekclark@cpan.orgE.
218              
219             =head1 SEE ALSO
220              
221             SQL::Translator, L.
222              
223             =cut