Adding new files.
[dbsrgits/SQL-Translator.git] / bin / sqlt-dumper
1 #!/usr/bin/perl
2
3 # -------------------------------------------------------------------
4 # $Id: sqlt-dumper,v 1.1 2003-08-26 03:56:43 kycl4rk Exp $
5 # -------------------------------------------------------------------
6 # Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>
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
25 sqlt-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
44 This script uses SQL::Translator to parse the SQL schema and create a
45 Perl script that can connect to the database and dump the data as
46 INSERT statements a la mysqldump.  If you enable "add-truncate" or
47 specify tables to "skip," then the generated dumper script will have
48 those hardcoded.  However, these will also be options in the generated
49 dumper, so you can wait to specify these options when you dump your
50 database.  The database username, password, and DSN can be hardcoded
51 into the generated script, or part of the DSN can be intuited from the
52 "database" argument.
53
54 =cut
55
56 # -------------------------------------------------------------------
57
58 use strict;
59 use Pod::Usage;
60 use Getopt::Long;
61 use SQL::Translator;
62
63 use vars '$VERSION';
64 $VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
65
66 my ( $help, $db, $add_truncate, $skip, $db_user, $db_pass, $dsn );
67 GetOptions(
68     'h|help'        => \$help,
69     'd|f|from|db=s' => \$db,
70     'add-truncate'  => \$add_truncate,
71     'skip:s'        => \$skip,
72     'u|user:s'      => \$db_user,
73     'p|password:s'  => \$db_pass,
74     'dsn:s'         => \$dsn,
75 ) or pod2usage;
76
77 pod2usage(0) if $help;
78 pod2usage( 'No database driver specified' ) unless $db;
79 $db_user ||= 'username';
80 $db_pass ||= 'password';
81 $dsn     ||= "dbi:$db:_";
82
83 my $file = shift @ARGV or pod2usage( -msg => 'No input file' );
84
85 my $t = SQL::Translator->new;
86 $t->parser( $db ) or die $t->error, "\n";
87 $t->filename( $file ) or die $t->error, "\n";
88
89 my %skip = map { $_, 1 } map { s/^\s+|\s+$//; $_ } split (/,/, $skip);
90 my $parser = $t->parser or die $t->error;
91 $parser->($t, $t->data);
92 my $schema = $t->schema;
93 my $now    = localtime;
94
95 my $out = <<"EOF";
96 #!/usr/bin/perl
97
98 #
99 # Generated $now
100 # By sqlt-dumper.pl, part of the SQLFairy project
101 # For more info, see http://sqlfairy.sourceforge.net/
102 #
103
104 use strict;
105 use DBI;
106 use Getopt::Long;
107
108 my ( \$help, \$add_truncate, \$skip );
109 GetOptions(
110     'h|help'        => \\\$help,
111     'add-truncate'  => \\\$add_truncate,
112     'skip:s'        => \\\$skip,
113 );
114
115 if ( \$help ) {
116     print <<"USAGE";
117 Usage:
118   \$0 [options]
119
120   Options:
121     -h|--help       Show help and exit
122     --add-truncate  Add "TRUNCATE TABLE" statements
123     --skip=t1[,t2]  Comma-separated list of tables to skip
124
125 USAGE
126     exit(0);
127 }
128
129 my \%skip = map { \$_, 1 } map { s/^\\s+|\\s+\$//; \$_ } split (/,/, \$skip);
130 my \$db = DBI->connect('$dsn', '$db_user', '$db_pass');
131
132 EOF
133
134 for my $table ( $schema->get_tables ) {
135     my $table_name  = $table->name;
136     next if $skip{ $table_name };
137     my ( @field_names, %types );
138     for my $field ( $table->get_fields ) {
139         $types{ $field->name } = $field->data_type =~ m/(char|str|long|text)/
140             ? 'string' : 'number';
141         push @field_names, $field->name;
142     }
143
144     $out .= join('',
145         "#\n# Table: $table_name\n#\n{\n",
146         "    next if \$skip{'$table_name'};\n",
147         "    print \"--\\n-- Data for table '$table_name'\\n--\\n\";\n\n",
148         "    if ( \$add_truncate ) {\n",
149         "        print \"TRUNCATE TABLE $table_name;\\n\";\n",
150         "    }\n\n",
151     );
152
153     my $insert = "INSERT INTO $table_name (". join(', ', @field_names).
154             ') VALUES (';
155
156     if ( $add_truncate ) {
157         $out .= "    print \"TRUNCATE TABLE $table_name;\\n\";\n";
158     }
159
160     $out .= join('',
161         "    my \%types = (\n",
162         join("\n", map { "        $_ => '$types{ $_ }'," } @field_names), 
163         "\n    );\n\n",
164         "    my \$data  = \$db->selectall_arrayref(\n",
165         "        'select ", join(', ', @field_names), " from $table_name',\n",
166         "        { Columns => {} },\n",
167         "    );\n\n",
168         "    for my \$rec ( \@{ \$data } ) {\n",
169         "        my \@vals;\n",
170         "        for my \$fld ( qw[", join(' ', @field_names), "] ) {\n",
171         "            my \$val = \$rec->{ \$fld };\n",
172         "            if ( \$types{ \$fld } eq 'string' ) {\n",
173         "                \$val =~ s/'/\\'/g;\n",
174         "                \$val = defined \$val ? qq['\$val'] : qq[''];\n",
175         "            }\n",
176         "            else {\n",
177         "                \$val = defined \$val ? \$val : 'NULL';\n",
178         "            }\n",
179         "            push \@vals, \$val;\n",
180         "        }\n",
181         "        print \"$insert\", join(', ', \@vals), \");\\n\";\n",
182         "    }\n",
183         "    print \"\\n\";\n",
184         "}\n\n",
185     );
186 }
187
188 print $out;
189 exit(0);
190
191 # -------------------------------------------------------------------
192
193 =pod
194
195 =head1 AUTHOR
196
197 Ken Y. Clark E<lt>kclark@cpan.orgE<gt>.
198
199 =head1 SEE ALSO
200
201 perl, SQL::Translator.
202
203 =cut