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