--- /dev/null
+#!/usr/bin/perl
+
+# -------------------------------------------------------------------
+# $Id: sqlt-dumper,v 1.1 2003-08-26 03:56:43 kycl4rk Exp $
+# -------------------------------------------------------------------
+# Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA
+# -------------------------------------------------------------------
+
+=head1 NAME
+
+sqlt-dumper - create a dumper script from a schema
+
+=head1 SYNOPSIS
+
+ sqlt-dumper -d Oracle [options] schema.sql > dumper.pl
+
+ ./dumper.pl > data.sql
+
+ Options:
+
+ -h|--help Show help and exit
+ --add-truncate Add "TRUNCATE TABLE" statements for each table
+ --skip=t1[,t2] Skip tables in comma-separated list
+ -u|--user Database username
+ -p|--password Database password
+ --dsn DSN for DBI
+
+=head1 DESCRIPTION
+
+This script uses SQL::Translator to parse the SQL schema and create a
+Perl script that can connect to the database and dump the data as
+INSERT statements a la mysqldump. If you enable "add-truncate" or
+specify tables to "skip," then the generated dumper script will have
+those hardcoded. However, these will also be options in the generated
+dumper, so you can wait to specify these options when you dump your
+database. The database username, password, and DSN can be hardcoded
+into the generated script, or part of the DSN can be intuited from the
+"database" argument.
+
+=cut
+
+# -------------------------------------------------------------------
+
+use strict;
+use Pod::Usage;
+use Getopt::Long;
+use SQL::Translator;
+
+use vars '$VERSION';
+$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
+
+my ( $help, $db, $add_truncate, $skip, $db_user, $db_pass, $dsn );
+GetOptions(
+ 'h|help' => \$help,
+ 'd|f|from|db=s' => \$db,
+ 'add-truncate' => \$add_truncate,
+ 'skip:s' => \$skip,
+ 'u|user:s' => \$db_user,
+ 'p|password:s' => \$db_pass,
+ 'dsn:s' => \$dsn,
+) or pod2usage;
+
+pod2usage(0) if $help;
+pod2usage( 'No database driver specified' ) unless $db;
+$db_user ||= 'username';
+$db_pass ||= 'password';
+$dsn ||= "dbi:$db:_";
+
+my $file = shift @ARGV or pod2usage( -msg => 'No input file' );
+
+my $t = SQL::Translator->new;
+$t->parser( $db ) or die $t->error, "\n";
+$t->filename( $file ) or die $t->error, "\n";
+
+my %skip = map { $_, 1 } map { s/^\s+|\s+$//; $_ } split (/,/, $skip);
+my $parser = $t->parser or die $t->error;
+$parser->($t, $t->data);
+my $schema = $t->schema;
+my $now = localtime;
+
+my $out = <<"EOF";
+#!/usr/bin/perl
+
+#
+# Generated $now
+# By sqlt-dumper.pl, part of the SQLFairy project
+# For more info, see http://sqlfairy.sourceforge.net/
+#
+
+use strict;
+use DBI;
+use Getopt::Long;
+
+my ( \$help, \$add_truncate, \$skip );
+GetOptions(
+ 'h|help' => \\\$help,
+ 'add-truncate' => \\\$add_truncate,
+ 'skip:s' => \\\$skip,
+);
+
+if ( \$help ) {
+ print <<"USAGE";
+Usage:
+ \$0 [options]
+
+ Options:
+ -h|--help Show help and exit
+ --add-truncate Add "TRUNCATE TABLE" statements
+ --skip=t1[,t2] Comma-separated list of tables to skip
+
+USAGE
+ exit(0);
+}
+
+my \%skip = map { \$_, 1 } map { s/^\\s+|\\s+\$//; \$_ } split (/,/, \$skip);
+my \$db = DBI->connect('$dsn', '$db_user', '$db_pass');
+
+EOF
+
+for my $table ( $schema->get_tables ) {
+ my $table_name = $table->name;
+ next if $skip{ $table_name };
+ my ( @field_names, %types );
+ for my $field ( $table->get_fields ) {
+ $types{ $field->name } = $field->data_type =~ m/(char|str|long|text)/
+ ? 'string' : 'number';
+ push @field_names, $field->name;
+ }
+
+ $out .= join('',
+ "#\n# Table: $table_name\n#\n{\n",
+ " next if \$skip{'$table_name'};\n",
+ " print \"--\\n-- Data for table '$table_name'\\n--\\n\";\n\n",
+ " if ( \$add_truncate ) {\n",
+ " print \"TRUNCATE TABLE $table_name;\\n\";\n",
+ " }\n\n",
+ );
+
+ my $insert = "INSERT INTO $table_name (". join(', ', @field_names).
+ ') VALUES (';
+
+ if ( $add_truncate ) {
+ $out .= " print \"TRUNCATE TABLE $table_name;\\n\";\n";
+ }
+
+ $out .= join('',
+ " my \%types = (\n",
+ join("\n", map { " $_ => '$types{ $_ }'," } @field_names),
+ "\n );\n\n",
+ " my \$data = \$db->selectall_arrayref(\n",
+ " 'select ", join(', ', @field_names), " from $table_name',\n",
+ " { Columns => {} },\n",
+ " );\n\n",
+ " for my \$rec ( \@{ \$data } ) {\n",
+ " my \@vals;\n",
+ " for my \$fld ( qw[", join(' ', @field_names), "] ) {\n",
+ " my \$val = \$rec->{ \$fld };\n",
+ " if ( \$types{ \$fld } eq 'string' ) {\n",
+ " \$val =~ s/'/\\'/g;\n",
+ " \$val = defined \$val ? qq['\$val'] : qq[''];\n",
+ " }\n",
+ " else {\n",
+ " \$val = defined \$val ? \$val : 'NULL';\n",
+ " }\n",
+ " push \@vals, \$val;\n",
+ " }\n",
+ " print \"$insert\", join(', ', \@vals), \");\\n\";\n",
+ " }\n",
+ " print \"\\n\";\n",
+ "}\n\n",
+ );
+}
+
+print $out;
+exit(0);
+
+# -------------------------------------------------------------------
+
+=pod
+
+=head1 AUTHOR
+
+Ken Y. Clark E<lt>kclark@cpan.orgE<gt>.
+
+=head1 SEE ALSO
+
+perl, SQL::Translator.
+
+=cut
--- /dev/null
+#!/usr/bin/perl
+
+# -------------------------------------------------------------------
+# $Id: sqlt-graph,v 1.1 2003-08-26 03:56:43 kycl4rk Exp $
+# -------------------------------------------------------------------
+# Copyright (C) 2002 Ken Y. Clark <kclark@cpan.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA
+# -------------------------------------------------------------------
+
+=head1 NAME
+
+sqlt-graph - Automatically create a graph from a database schema
+
+=head1 SYNOPSIS
+
+ ./sqlt-graph -d|--db|-f|--from=db_parser [options] schema.sql
+
+ Options:
+
+ -l|--layout Layout schema for GraphViz
+ ("dot," "neato," "twopi"; default "dot")
+ -n|--node-shape Shape of the nodes ("record," "plaintext,"
+ "ellipse," "circle," "egg," "triangle," "box,"
+ "diamond," "trapezium," "parallelogram," "house,"
+ "hexagon," "octagon," default "record")
+ -o|--output Output file name (default STDOUT)
+ -t|--output-type Output file type ("canon", "text," "ps," "hpgl,"
+ "pcl," "mif," "pic," "gd," "gd2," "gif," "jpeg,"
+ "png," "wbmp," "cmap," "ismap," "imap," "vrml,"
+ "vtx," "mp," "fig," "svg," "plain," default "png")
+ -c|--color Add colors
+ --no-fields Don't show field names
+ --height Image height (in inches, default "11",
+ set to "0" to undefine)
+ --width Image width (in inches, default "8.5",
+ set to "0" to undefine)
+ --natural-join Perform natural joins
+ --natural-join-pk Perform natural joins from primary keys only
+ -s|--skip Fields to skip in natural joins
+ --debug Print debugging information
+
+=head1 DESCRIPTION
+
+This script will create a graph of your schema. Only the database
+driver argument (for SQL::Translator) is required. If no output file
+name is given, then image will be printed to STDOUT, so you should
+redirect the output into a file.
+
+The default action is to assume the presence of foreign key
+relationships defined via "REFERNCES" or "FOREIGN KEY" constraints on
+the tables. If you are parsing the schema of a file that does not
+have these, you will find the natural join options helpful. With
+natural joins, like-named fields will be considered foreign keys.
+This can prove too permissive, however, as you probably don't want a
+field called "name" to be considered a foreign key, so you could
+include it in the "skip" option, and all fields called "name" will be
+excluded from natural joins. A more efficient method, however, might
+be to simply deduce the foriegn keys from primary keys to other fields
+named the same in other tables. Use the "natural-join-pk" option
+to acheive this.
+
+If the schema defines foreign keys, then the graph produced will be
+directed showing the direction of the relationship. If the foreign
+keys are intuited via natural joins, the graph will be undirected.
+
+=cut
+
+# -------------------------------------------------------------------
+
+use strict;
+use Data::Dumper;
+use Getopt::Long;
+use GraphViz;
+use Pod::Usage;
+use SQL::Translator;
+
+use vars '$VERSION';
+$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
+
+#
+# Get arguments.
+#
+my (
+ $layout, $node_shape, $out_file, $output_type, $db_driver, $add_color,
+ $natural_join, $join_pk_only, $skip_fields, $debug, $help, $height,
+ $width, $no_fields
+);
+
+GetOptions(
+ 'd|db|f|from=s' => \$db_driver,
+ 'o|output:s' => \$out_file,
+ 'l|layout:s' => \$layout,
+ 'n|node-shape:s' => \$node_shape,
+ 't|output-type:s' => \$output_type,
+ 'height:i' => \$height,
+ 'width:i' => \$width,
+ 'c|color' => \$add_color,
+ 'no-fields' => \$no_fields,
+ 'natural-join' => \$natural_join,
+ 'natural-join-pk' => \$join_pk_only,
+ 's|skip:s' => \$skip_fields,
+ 'debug' => \$debug,
+ 'h|help' => \$help,
+) or die pod2usage;
+my @files = @ARGV; # the create script(s) for the original db
+
+pod2usage(1) if $help;
+pod2usage( -message => "No db driver specified" ) unless $db_driver;
+pod2usage( -message => 'No input file' ) unless @files;
+
+my $translator = SQL::Translator->new(
+ from => $db_driver,
+ to => 'GraphViz',
+ debug => $debug || 0,
+ producer_args => {
+ out_file => $out_file,
+ layout => $layout,
+ node_shape => $node_shape,
+ output_type => $output_type,
+ add_color => $add_color,
+ natural_join => $natural_join,
+ natural_join_pk => $join_pk_only,
+ skip_fields => $skip_fields,
+ height => $height || 0,
+ width => $width || 0,
+ show_fields => $no_fields ? 0 : 1,
+ },
+) or die SQL::Translator->error;
+
+for my $file (@files) {
+ my $output = $translator->translate( $file ) or die
+ "Error: " . $translator->error;
+ if ( $out_file ) {
+ print "Image written to '$out_file'. Done.\n";
+ }
+ else {
+ print $output;
+ }
+}
+
+# -------------------------------------------------------------------
+
+=pod
+
+=head1 AUTHOR
+
+Ken Y. Clark E<lt>kclark@cpan.orgE<gt>.
+
+=head1 SEE ALSO
+
+perl, SQL::Translator.
+
+=cut