Just the fairy.
[dbsrgits/SQL-Translator.git] / bin / sqlt-dumper
CommitLineData
354b1807 1#!/usr/bin/perl
2
3# -------------------------------------------------------------------
daf4f623 4# $Id: sqlt-dumper,v 1.3 2004-02-06 17:48:16 kycl4rk Exp $
354b1807 5# -------------------------------------------------------------------
daf4f623 6# Copyright (C) 2002-4 SQLFairy Authors
354b1807 7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License as
10# published by the Free Software Foundation; version 2.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20# 02111-1307 USA
21# -------------------------------------------------------------------
22
23=head1 NAME
24
25sqlt-dumper - create a dumper script from a schema
26
27=head1 SYNOPSIS
28
29 sqlt-dumper -d Oracle [options] schema.sql > dumper.pl
30
31 ./dumper.pl > data.sql
32
33 Options:
34
35 -h|--help Show help and exit
36 --add-truncate Add "TRUNCATE TABLE" statements for each table
37 --skip=t1[,t2] Skip tables in comma-separated list
38 -u|--user Database username
39 -p|--password Database password
40 --dsn DSN for DBI
41
42=head1 DESCRIPTION
43
44This script uses SQL::Translator to parse the SQL schema and create a
45Perl script that can connect to the database and dump the data as
46INSERT statements a la mysqldump. If you enable "add-truncate" or
47specify tables to "skip," then the generated dumper script will have
48those hardcoded. However, these will also be options in the generated
49dumper, so you can wait to specify these options when you dump your
50database. The database username, password, and DSN can be hardcoded
51into the generated script, or part of the DSN can be intuited from the
52"database" argument.
53
54=cut
55
56# -------------------------------------------------------------------
57
58use strict;
59use Pod::Usage;
60use Getopt::Long;
61use SQL::Translator;
aba9fea4 62use File::Basename qw(basename);
354b1807 63
64use vars '$VERSION';
daf4f623 65$VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
354b1807 66
67my ( $help, $db, $add_truncate, $skip, $db_user, $db_pass, $dsn );
68GetOptions(
69 'h|help' => \$help,
70 'd|f|from|db=s' => \$db,
71 'add-truncate' => \$add_truncate,
72 'skip:s' => \$skip,
73 'u|user:s' => \$db_user,
74 'p|password:s' => \$db_pass,
75 'dsn:s' => \$dsn,
76) or pod2usage;
77
78pod2usage(0) if $help;
79pod2usage( 'No database driver specified' ) unless $db;
80$db_user ||= 'username';
81$db_pass ||= 'password';
82$dsn ||= "dbi:$db:_";
83
84my $file = shift @ARGV or pod2usage( -msg => 'No input file' );
85
86my $t = SQL::Translator->new;
87$t->parser( $db ) or die $t->error, "\n";
88$t->filename( $file ) or die $t->error, "\n";
89
90my %skip = map { $_, 1 } map { s/^\s+|\s+$//; $_ } split (/,/, $skip);
91my $parser = $t->parser or die $t->error;
92$parser->($t, $t->data);
93my $schema = $t->schema;
94my $now = localtime;
aba9fea4 95my $prog = basename $0;
354b1807 96
97my $out = <<"EOF";
98#!/usr/bin/perl
99
100#
101# Generated $now
aba9fea4 102# By $prog, part of the SQLFairy project
354b1807 103# For more info, see http://sqlfairy.sourceforge.net/
104#
105
106use strict;
107use DBI;
108use Getopt::Long;
109
110my ( \$help, \$add_truncate, \$skip );
111GetOptions(
112 'h|help' => \\\$help,
113 'add-truncate' => \\\$add_truncate,
114 'skip:s' => \\\$skip,
115);
116
117if ( \$help ) {
118 print <<"USAGE";
119Usage:
120 \$0 [options]
121
122 Options:
123 -h|--help Show help and exit
124 --add-truncate Add "TRUNCATE TABLE" statements
125 --skip=t1[,t2] Comma-separated list of tables to skip
126
127USAGE
128 exit(0);
129}
130
131my \%skip = map { \$_, 1 } map { s/^\\s+|\\s+\$//; \$_ } split (/,/, \$skip);
132my \$db = DBI->connect('$dsn', '$db_user', '$db_pass');
133
134EOF
135
136for my $table ( $schema->get_tables ) {
137 my $table_name = $table->name;
138 next if $skip{ $table_name };
139 my ( @field_names, %types );
140 for my $field ( $table->get_fields ) {
141 $types{ $field->name } = $field->data_type =~ m/(char|str|long|text)/
142 ? 'string' : 'number';
143 push @field_names, $field->name;
144 }
145
146 $out .= join('',
147 "#\n# Table: $table_name\n#\n{\n",
148 " next if \$skip{'$table_name'};\n",
149 " print \"--\\n-- Data for table '$table_name'\\n--\\n\";\n\n",
150 " if ( \$add_truncate ) {\n",
151 " print \"TRUNCATE TABLE $table_name;\\n\";\n",
152 " }\n\n",
153 );
154
155 my $insert = "INSERT INTO $table_name (". join(', ', @field_names).
156 ') VALUES (';
157
158 if ( $add_truncate ) {
159 $out .= " print \"TRUNCATE TABLE $table_name;\\n\";\n";
160 }
161
162 $out .= join('',
163 " my \%types = (\n",
164 join("\n", map { " $_ => '$types{ $_ }'," } @field_names),
165 "\n );\n\n",
166 " my \$data = \$db->selectall_arrayref(\n",
167 " 'select ", join(', ', @field_names), " from $table_name',\n",
168 " { Columns => {} },\n",
169 " );\n\n",
170 " for my \$rec ( \@{ \$data } ) {\n",
171 " my \@vals;\n",
172 " for my \$fld ( qw[", join(' ', @field_names), "] ) {\n",
173 " my \$val = \$rec->{ \$fld };\n",
174 " if ( \$types{ \$fld } eq 'string' ) {\n",
175 " \$val =~ s/'/\\'/g;\n",
176 " \$val = defined \$val ? qq['\$val'] : qq[''];\n",
177 " }\n",
178 " else {\n",
179 " \$val = defined \$val ? \$val : 'NULL';\n",
180 " }\n",
181 " push \@vals, \$val;\n",
182 " }\n",
183 " print \"$insert\", join(', ', \@vals), \");\\n\";\n",
184 " }\n",
185 " print \"\\n\";\n",
186 "}\n\n",
187 );
188}
189
190print $out;
191exit(0);
192
193# -------------------------------------------------------------------
194
195=pod
196
197=head1 AUTHOR
198
199Ken Y. Clark E<lt>kclark@cpan.orgE<gt>.
200
201=head1 SEE ALSO
202
203perl, SQL::Translator.
204
205=cut