Remove copyright headers from individual scripts
[dbsrgits/SQL-Translator.git] / script / sqlt-graph
1 #!/usr/bin/env perl
2
3 =head1 NAME 
4
5 sqlt-graph - Automatically create a graph from a database schema
6
7 =head1 SYNOPSIS
8
9   ./sqlt-graph -d|--db|-f|--from=db_parser [options] schema.sql
10
11   Options:
12
13     -l|--layout        Layout schema for GraphViz
14                        ("dot," "neato," "twopi"; default "dot")
15     -n|--node-shape    Shape of the nodes ("record," "plaintext," 
16                        "ellipse," "circle," "egg," "triangle," "box," 
17                        "diamond," "trapezium," "parallelogram," "house," 
18                        "hexagon," "octagon," default "record")
19     -o|--output        Output file name (default STDOUT)
20     -t|--output-type   Output file type ("canon", "text," "ps," "hpgl,"
21                        "pcl," "mif," "pic," "gd," "gd2," "gif," "jpeg,"
22                        "png," "wbmp," "cmap," "ismap," "imap," "vrml,"
23                        "vtx," "mp," "fig," "svg," "plain," default "png")
24     -c|--color         Add colors
25     --cluster          Cluster tables
26     --no-fields        Don't show field names
27     --height           Image height (in inches, default "11",
28                        set to "0" to undefine)
29     --width            Image width (in inches, default "8.5", 
30                        set to "0" to undefine)
31     --fontsize         custom font size for node and edge labels
32     --fontname         name of custom font (or full path to font file) for 
33                        node, edge, and graph labels
34     --nodeattr         attribute name and value (in key=val syntax) for
35                        nodes; this option may be repeated to specify 
36                        multiple node attributes
37     --edgeattr         same as --nodeattr, but for edge attributes
38     --graphattr        same as --nodeattr, but for graph attributes
39     --natural-join     Perform natural joins
40     --natural-join-pk  Perform natural joins from primary keys only
41     --show-datatypes   Show datatype of each field
42     --show-sizes       Show column sizes for VARCHAR and CHAR fields
43     --show-constraints Show list of constraints for each field
44     -s|--skip          Fields to skip in natural joins
45     --skip-tables      Comma-separated list of table names to exclude 
46     --skip-tables-like Comma-separated list of regexen to exclude tables
47     --debug            Print debugging information
48
49 =head1 DESCRIPTION
50
51 This script will create a graph of your schema.  Only the database
52 driver argument (for SQL::Translator) is required.  If no output file
53 name is given, then image will be printed to STDOUT, so you should
54 redirect the output into a file.
55
56 The default action is to assume the presence of foreign key
57 relationships defined via "REFERNCES" or "FOREIGN KEY" constraints on
58 the tables.  If you are parsing the schema of a file that does not
59 have these, you will find the natural join options helpful.  With
60 natural joins, like-named fields will be considered foreign keys.
61 This can prove too permissive, however, as you probably don't want a
62 field called "name" to be considered a foreign key, so you could
63 include it in the "skip" option, and all fields called "name" will be
64 excluded from natural joins.  A more efficient method, however, might
65 be to simply deduce the foriegn keys from primary keys to other fields
66 named the same in other tables.  Use the "natural-join-pk" option
67 to acheive this.
68
69 If the schema defines foreign keys, then the graph produced will be
70 directed showing the direction of the relationship.  If the foreign
71 keys are intuited via natural joins, the graph will be undirected.
72
73 Clustering of tables allows you to group and box tables according to 
74 function or domain or whatever criteria you choose.  The syntax for 
75 clustering tables is:
76
77   cluster1=table1,table2;cluster2=table3,table4
78
79 =cut
80
81 # -------------------------------------------------------------------
82
83 use strict;
84 use warnings;
85 use Data::Dumper;
86 use Getopt::Long;
87 use GraphViz;
88 use Pod::Usage;
89 use SQL::Translator;
90
91 use vars '$VERSION';
92 $VERSION = '1.59';
93
94 #
95 # Get arguments.
96 #
97 my ( 
98     $layout, $node_shape, $out_file, $output_type, $db_driver, $add_color, 
99     $natural_join, $join_pk_only, $skip_fields, $show_datatypes,
100     $show_sizes, $show_constraints, $debug, $help, $height, $width,
101     $no_fields, $fontsize, $fontname, $skip_tables, $skip_tables_like,
102     $cluster
103 );
104
105 # multi-valued options:
106 my %edgeattrs = ();
107 my %nodeattrs = ();
108 my %graphattrs = ();
109
110 GetOptions(
111     'd|db|f|from=s'      => \$db_driver,
112     'o|output:s'         => \$out_file,
113     'l|layout:s'         => \$layout,
114     'n|node-shape:s'     => \$node_shape,
115     't|output-type:s'    => \$output_type,
116     'height:f'           => \$height,
117     'width:f'            => \$width,
118     'fontsize=i'         => \$fontsize,
119     'fontname=s'         => \$fontname,
120     'nodeattr=s'         => \%nodeattrs,
121     'edgeattr=s'         => \%edgeattrs,
122     'graphattr=s'        => \%graphattrs,
123     'c|color'            => \$add_color,
124     'cluster:s'          => \$cluster,
125     'no-fields'          => \$no_fields,
126     'natural-join'       => \$natural_join,
127     'natural-join-pk'    => \$join_pk_only,
128     's|skip:s'           => \$skip_fields,
129     'skip-tables:s'      => \$skip_tables,
130     'skip-tables-like:s' => \$skip_tables_like,
131     'show-datatypes'     => \$show_datatypes,
132     'show-sizes'         => \$show_sizes,
133     'show-constraints'   => \$show_constraints,
134     'debug'              => \$debug,
135     'h|help'             => \$help,
136 ) or die pod2usage;
137 my @files = @ARGV; # the create script(s) for the original db
138
139 pod2usage(1) if $help;
140 pod2usage( -message => "No db driver specified" ) unless $db_driver;
141 pod2usage( -message => 'No input file'          ) unless @files;
142
143 my $translator           =  SQL::Translator->new( 
144     from                 => $db_driver,
145     to                   => 'GraphViz',
146     debug                => $debug || 0,
147     producer_args        => {
148         out_file         => $out_file,
149         layout           => $layout,
150         node_shape       => $node_shape,
151         output_type      => $output_type,
152         add_color        => $add_color,
153         natural_join     => $natural_join,
154         natural_join_pk  => $join_pk_only,
155         skip_fields      => $skip_fields,
156         skip_tables      => $skip_tables,
157         skip_tables_like => $skip_tables_like,
158         show_datatypes   => $show_datatypes,
159         show_sizes       => $show_sizes,
160         show_constraints => $show_constraints,
161         cluster          => $cluster,
162         height           => $height || 0,
163         width            => $width  || 0,
164         fontsize         => $fontsize,
165         fontname         => $fontname,
166         nodeattrs        => \%nodeattrs,
167         edgeattrs        => \%edgeattrs,
168         graphattrs       => \%graphattrs,
169         show_fields      => $no_fields ? 0 : 1,
170     },
171 ) or die SQL::Translator->error;
172
173 for my $file (@files) {
174     my $output = $translator->translate( $file ) or die
175                  "Error: " . $translator->error;
176     if ( $out_file ) {
177         print "Image written to '$out_file'.  Done.\n";
178     }
179     else {
180         print $output;
181     }
182 }
183
184 # -------------------------------------------------------------------
185
186 =pod
187
188 =head1 AUTHOR
189
190 Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>.
191
192 =head1 SEE ALSO
193
194 perl, SQL::Translator.
195
196 =cut