Tab/WS crusade
[dbsrgits/SQL-Translator.git] / script / sqlt-diff
CommitLineData
969049ba 1#!/usr/bin/env perl
e12ca55a 2# vim: set ft=perl:
3
44659089 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., 59 Temple Place, Suite 330, Boston, MA
19# 02111-1307 USA
20# -------------------------------------------------------------------
21
e12ca55a 22=head1 NAME
23
24sqlt-diff - find the differences b/w two schemas
25
26=head1 SYNOPSIS
27
28For help:
29
30 sqlt-diff -h|--help
31
32For a list of all valid parsers:
33
34 sqlt -l|--list
35
36To diff two schemas:
37
fb5ab406 38 sqlt-diff [options] file_name1=parser1 file_name2=parser2
e12ca55a 39
40Options:
41
42 -d|--debug Show debugging info
51ffe5ee 43 -t|--trace Turn on tracing for Parse::RecDescent
0b1b149e 44 -c|--case-insensitive Compare tables/columns case-insensitively
d990d84b 45 --ignore-index-names Ignore index name differences
46 --ignore-constraint-names Ignore constraint name differences
0b1b149e 47 --mysql_parser_version=<#####> Specify a target MySQL parser version
48 for dealing with /*! comments
49 --output-db=<Producer> This Producer will be used instead of one
50 corresponding to parser1 to format output
51 for new tables
d1a895ce 52 --ignore-view-sql Ignore view SQL differences
53 --ignore-proc-sql Ignore procedure SQL differences
54b6e490 54 --no-batch-alters Do not clump multile alters to the same table into a
55 single ALTER TABLE statement where possible.
e12ca55a 56
57=head1 DESCRIPTION
58
942485ea 59sqlt-diff is a utility for creating a file of SQL commands necessary to
aee4b66e 60transform the first schema provided to the second. While not yet
61exhaustive in its ability to mutate the entire schema, it will report the
942485ea 62following
63
64=over
65
66=item * New tables
67
68Using the Producer class of the target (second) schema, any tables missing
69in the first schema will be generated in their entirety (fields, constraints,
70indices).
71
72=item * Missing/altered fields
73
aee4b66e 74Any fields missing or altered between the two schemas will be reported
942485ea 75as:
76
aee4b66e 77 ALTER TABLE <table_name>
78 [DROP <field_name>]
942485ea 79 [CHANGE <field_name> <datatype> (<size>)] ;
80
81=item * Missing/altered indices
82
83Any indices missing or of a different type or on different fields will be
84indicated. Indices that should be dropped will be reported as such:
aee4b66e 85
942485ea 86 DROP INDEX <index_name> ON <table_name> ;
87
aee4b66e 88An index of a different type or on different fields will be reported as a
942485ea 89new index as such:
90
aee4b66e 91 CREATE [<index_type>] INDEX [<index_name>] ON <table_name>
942485ea 92 ( <field_name>[,<field_name>] ) ;
93
94=back
95
da5a1bae 96ALTER, CREATE, DROP statements are created by
97SQL::Translator::Producer::*, see there for support/problems.
98
99Currently (v0.0900), only MySQL is supported by this code.
e12ca55a 100
101=cut
102
103# -------------------------------------------------------------------
104
105use strict;
969049ba 106use warnings;
e12ca55a 107use Pod::Usage;
108use Data::Dumper;
109use SQL::Translator;
51ffe5ee 110use SQL::Translator::Diff;
942485ea 111use SQL::Translator::Schema::Constants;
e12ca55a 112
da06ac74 113use vars qw( $VERSION );
11ad2df9 114$VERSION = '1.59';
da06ac74 115
aee4b66e 116my ( @input, $list, $help, $debug, $trace, $caseopt, $ignore_index_names,
117 $ignore_constraint_names, $output_db, $mysql_parser_version,
118 $ignore_view_sql, $ignore_proc_sql, $no_batch_alters );
e12ca55a 119for my $arg ( @ARGV ) {
120 if ( $arg =~ m/^-?-l(ist)?$/ ) {
121 $list = 1;
122 }
123 elsif ( $arg =~ m/^-?-h(elp)?$/ ) {
124 $help = 1;
125 }
126 elsif ( $arg =~ m/^-?-d(ebug)?$/ ) {
aee4b66e 127 $debug = 1;
e12ca55a 128 }
51ffe5ee 129 elsif ( $arg =~ m/^-?-t(race)?$/ ) {
aee4b66e 130 $trace = 1;
51ffe5ee 131 }
d990d84b 132 elsif ( $arg =~ m/^-?-c(ase-insensitive)?$/ ) {
aee4b66e 133 $caseopt = 1;
51ffe5ee 134 }
d990d84b 135 elsif ( $arg =~ m/^--ignore-index-names$/ ) {
aee4b66e 136 $ignore_index_names = 1;
d990d84b 137 }
fb5ab406 138 elsif ( $arg =~ m/^--ignore-constraint-names$/ ) {
aee4b66e 139 $ignore_constraint_names = 1;
d990d84b 140 }
0b1b149e 141 elsif ( $arg =~ m/^--mysql-parser-version=(.+)$/ ) {
aee4b66e 142 $mysql_parser_version = $1;
0b1b149e 143 }
fb5ab406 144 elsif ( $arg =~ m/^--output-db=(.+)$/ ) {
aee4b66e 145 $output_db = $1;
fb5ab406 146 }
d1a895ce 147 elsif ( $arg =~ m/^--ignore-view-sql$/ ) {
aee4b66e 148 $ignore_view_sql = 1;
d1a895ce 149 }
150 elsif ( $arg =~ m/^--ignore-proc-sql$/ ) {
aee4b66e 151 $ignore_proc_sql = 1;
d1a895ce 152 }
e12ca55a 153 elsif ( $arg =~ m/^([^=]+)=(.+)$/ ) {
154 push @input, { file => $1, parser => $2 };
155 }
54b6e490 156 elsif ( $arg =~ m/^--no-batch-alters$/ ) {
157 $no_batch_alters = 1;
158 }
e12ca55a 159 else {
160 pod2usage( msg => "Unknown argument '$arg'" );
161 }
162}
163
54b6e490 164print STDERR <<'EOM';
aee4b66e 165This code is experimental, currently the new code only supports MySQL or
54b6e490 166SQLite diffing. To add support for other databases, please patch the relevant
167SQL::Translator::Producer:: module. If you need compatibility with the old
168sqlt-diff, please use sqlt-diff-old, and look into helping us make this one
169work for you
170EOM
da5a1bae 171
51ffe5ee 172pod2usage(1) if $help || !@ARGV;
942485ea 173pod2usage('Please specify only two schemas to diff') if scalar @input > 2;
e12ca55a 174
175my $tr = SQL::Translator->new;
176my @parsers = $tr->list_parsers;
177my %valid_parsers = map { $_, 1 } @parsers;
178
179if ( $list ) {
180 print "\nParsers:\n", map { "\t$_\n" } sort @parsers;
181 print "\n";
182 exit(0);
183}
184
185pod2usage( msg => 'Too many file args' ) if @input > 2;
186
51ffe5ee 187my ( $source_schema, $source_db, $target_schema, $target_db ) = map {
188 my $file = $_->{'file'};
189 my $parser = $_->{'parser'};
e12ca55a 190
191 die "Unable to read file '$file'\n" unless -r $file;
192 die "'$parser' is an invalid parser\n" unless $valid_parsers{ $parser };
193
d1a895ce 194 my $t = SQL::Translator->new(parser_args => {mysql_parser_version => $mysql_parser_version});
e12ca55a 195 $t->debug( $debug );
51ffe5ee 196 $t->trace( $trace );
e12ca55a 197 $t->parser( $parser ) or die $tr->error;
e12ca55a 198 my $out = $t->translate( $file ) or die $tr->error;
199 my $schema = $t->schema;
200 unless ( $schema->name ) {
201 $schema->name( $file );
202 }
203
51ffe5ee 204 ($schema, $parser);
205} @input;
206
aee4b66e 207my $result = SQL::Translator::Diff::schema_diff($source_schema, $source_db,
51ffe5ee 208 $target_schema, $target_db,
d990d84b 209 { caseopt => $caseopt,
210 ignore_index_names => $ignore_index_names,
211 ignore_constraint_names => $ignore_constraint_names,
d1a895ce 212 ignore_view_sql => $ignore_view_sql,
213 ignore_proc_sql => $ignore_proc_sql,
2d4796c7 214 output_db => $output_db,
54b6e490 215 no_batch_alters => $no_batch_alters,
d990d84b 216 debug => $debug,
217 trace => $trace });
51ffe5ee 218if($result)
219{
220 print $result;
e12ca55a 221}
51ffe5ee 222else
223{
224 print "No differences found.";
e12ca55a 225}
226
227# -------------------------------------------------------------------
228# Bring out number weight & measure in a year of dearth.
229# William Blake
230# -------------------------------------------------------------------
231
232=pod
233
234=head1 AUTHOR
235
969049ba 236Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>.
e12ca55a 237
238=head1 SEE ALSO
239
240SQL::Translator, L<http://sqlfairy.sourceforge.net>.
241
242=cut