Add POD checker and fix a couple of POD errors
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator.pm
CommitLineData
16dc9970 1package SQL::Translator;
2
b346d8f1 3# ----------------------------------------------------------------------
478f608d 4# Copyright (C) 2002-2009 The SQLFairy Authors
1fd8c91f 5#
077ebf34 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.
ca10f295 9#
077ebf34 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.
ca10f295 14#
077ebf34 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
ca10f295 19# -------------------------------------------------------------------
20
16dc9970 21use strict;
478f608d 22use vars qw( $VERSION $DEFAULT_SUB $DEBUG $ERROR );
49e1eb70 23use base 'Class::Base';
c2d3a526 24
4b6a6341 25require 5.004;
26
ab0ec6e5 27$VERSION = '0.09004';
d529894e 28$DEBUG = 0 unless defined $DEBUG;
29$ERROR = "";
c2d3a526 30
31use Carp qw(carp);
16dc9970 32
841a3f1a 33use Data::Dumper;
3015bf96 34use File::Find;
c0c4aef9 35use File::Spec::Functions qw(catfile);
36use File::Basename qw(dirname);
37use IO::Dir;
3edb144c 38use SQL::Translator::Producer;
45ee6be0 39use SQL::Translator::Schema;
c0c4aef9 40
b346d8f1 41# ----------------------------------------------------------------------
42# The default behavior is to "pass through" values (note that the
43# SQL::Translator instance is the first value ($_[0]), and the stuff
44# to be parsed is the second value ($_[1])
45# ----------------------------------------------------------------------
05a56b57 46$DEFAULT_SUB = sub { $_[0]->schema } unless defined $DEFAULT_SUB;
16dc9970 47
b346d8f1 48# ----------------------------------------------------------------------
c2d3a526 49# init([ARGS])
b346d8f1 50# The constructor.
dfb4c915 51#
b346d8f1 52# new takes an optional hash of arguments. These arguments may
53# include a parser, specified with the keys "parser" or "from",
54# and a producer, specified with the keys "producer" or "to".
dfb4c915 55#
b346d8f1 56# The values that can be passed as the parser or producer are
57# given directly to the parser or producer methods, respectively.
58# See the appropriate method description below for details about
59# what each expects/accepts.
b346d8f1 60# ----------------------------------------------------------------------
c2d3a526 61sub init {
49e1eb70 62 my ( $self, $config ) = @_;
49e1eb70 63 #
b346d8f1 64 # Set the parser and producer.
ca10f295 65 #
b346d8f1 66 # If a 'parser' or 'from' parameter is passed in, use that as the
67 # parser; if a 'producer' or 'to' parameter is passed in, use that
68 # as the producer; both default to $DEFAULT_SUB.
49e1eb70 69 #
70 $self->parser ($config->{'parser'} || $config->{'from'} || $DEFAULT_SUB);
c2d3a526 71 $self->producer($config->{'producer'} || $config->{'to'} || $DEFAULT_SUB);
ca10f295 72
10f36920 73 #
74 # Set up callbacks for formatting of pk,fk,table,package names in producer
75 # MOVED TO PRODUCER ARGS
76 #
77 #$self->format_table_name($config->{'format_table_name'});
78 #$self->format_package_name($config->{'format_package_name'});
79 #$self->format_fk_name($config->{'format_fk_name'});
80 #$self->format_pk_name($config->{'format_pk_name'});
7d5bcab8 81
49e1eb70 82 #
e2158c40 83 # Set the parser_args and producer_args
49e1eb70 84 #
85 for my $pargs ( qw[ parser_args producer_args ] ) {
86 $self->$pargs( $config->{$pargs} ) if defined $config->{ $pargs };
e2158c40 87 }
88
49e1eb70 89 #
185c34d5 90 # Initialize the filters.
91 #
92 if ( $config->{filters} && ref $config->{filters} eq "ARRAY" ) {
93 $self->filters( @{$config->{filters}} )
94 || return $self->error('Error inititializing filters: '.$self->error);
95 }
96
97 #
9398955f 98 # Set the data source, if 'filename' or 'file' is provided.
49e1eb70 99 #
c2d3a526 100 $config->{'filename'} ||= $config->{'file'} || "";
49e1eb70 101 $self->filename( $config->{'filename'} ) if $config->{'filename'};
9398955f 102
49e1eb70 103 #
185c34d5 104 # Finally, if there is a 'data' parameter, use that in
49e1eb70 105 # preference to filename and file
106 #
107 if ( my $data = $config->{'data'} ) {
108 $self->data( $data );
9398955f 109 }
110
d529894e 111 #
112 # Set various other options.
113 #
49e1eb70 114 $self->{'debug'} = defined $config->{'debug'} ? $config->{'debug'} : $DEBUG;
ca10f295 115
96844cae 116 $self->add_drop_table( $config->{'add_drop_table'} );
185c34d5 117
d529894e 118 $self->no_comments( $config->{'no_comments'} );
119
96844cae 120 $self->show_warnings( $config->{'show_warnings'} );
121
122 $self->trace( $config->{'trace'} );
123
3f4af30d 124 $self->validate( $config->{'validate'} );
5e2c196a 125
126 $self->quote_table_names( (defined $config->{'quote_table_names'}
127 ? $config->{'quote_table_names'} : 1) );
128 $self->quote_field_names( (defined $config->{'quote_field_names'}
129 ? $config->{'quote_field_names'} : 1) );
3f4af30d 130
ca10f295 131 return $self;
dfb4c915 132}
1fd8c91f 133
0f3778d0 134# ----------------------------------------------------------------------
135# add_drop_table([$bool])
136# ----------------------------------------------------------------------
96844cae 137sub add_drop_table {
138 my $self = shift;
139 if ( defined (my $arg = shift) ) {
140 $self->{'add_drop_table'} = $arg ? 1 : 0;
141 }
142 return $self->{'add_drop_table'} || 0;
143}
144
0f3778d0 145# ----------------------------------------------------------------------
146# no_comments([$bool])
147# ----------------------------------------------------------------------
d529894e 148sub no_comments {
149 my $self = shift;
150 my $arg = shift;
151 if ( defined $arg ) {
152 $self->{'no_comments'} = $arg ? 1 : 0;
153 }
154 return $self->{'no_comments'} || 0;
155}
156
e2158c40 157
0f3778d0 158# ----------------------------------------------------------------------
5e2c196a 159# quote_table_names([$bool])
160# ----------------------------------------------------------------------
161sub quote_table_names {
162 my $self = shift;
163 if ( defined (my $arg = shift) ) {
164 $self->{'quote_table_names'} = $arg ? 1 : 0;
165 }
166 return $self->{'quote_table_names'} || 0;
167}
168
169# ----------------------------------------------------------------------
170# quote_field_names([$bool])
171# ----------------------------------------------------------------------
172sub quote_field_names {
173 my $self = shift;
174 if ( defined (my $arg = shift) ) {
175 $self->{'quote_field_names'} = $arg ? 1 : 0;
176 }
177 return $self->{'quote_field_names'} || 0;
178}
179
180# ----------------------------------------------------------------------
0f3778d0 181# producer([$producer_spec])
182#
183# Get or set the producer for the current translator.
184# ----------------------------------------------------------------------
ca10f295 185sub producer {
f4a59b6c 186 shift->_tool({
185c34d5 187 name => 'producer',
f4a59b6c 188 path => "SQL::Translator::Producer",
185c34d5 189 default_sub => "produce",
f4a59b6c 190 }, @_);
191}
077ebf34 192
7a8e1f51 193# ----------------------------------------------------------------------
0f3778d0 194# producer_type()
7a8e1f51 195#
e2158c40 196# producer_type is an accessor that allows producer subs to get
197# information about their origin. This is poptentially important;
ca251f03 198# since all producer subs are called as subroutine references, there is
e2158c40 199# no way for a producer to find out which package the sub lives in
200# originally, for example.
7a8e1f51 201# ----------------------------------------------------------------------
202sub producer_type { $_[0]->{'producer_type'} }
e2158c40 203
7a8e1f51 204# ----------------------------------------------------------------------
0f3778d0 205# producer_args([\%args])
7a8e1f51 206#
e2158c40 207# Arbitrary name => value pairs of paramters can be passed to a
208# producer using this method.
52b828e8 209#
0f3778d0 210# If the first argument passed in is undef, then the hash of arguments
211# is cleared; all subsequent elements are added to the hash of name,
212# value pairs stored as producer_args.
7a8e1f51 213# ----------------------------------------------------------------------
f4a59b6c 214sub producer_args { shift->_args("producer", @_); }
ca10f295 215
0f3778d0 216# ----------------------------------------------------------------------
217# parser([$parser_spec])
218# ----------------------------------------------------------------------
ca10f295 219sub parser {
f4a59b6c 220 shift->_tool({
185c34d5 221 name => 'parser',
f4a59b6c 222 path => "SQL::Translator::Parser",
185c34d5 223 default_sub => "parse",
f4a59b6c 224 }, @_);
16dc9970 225}
1fd8c91f 226
f4a59b6c 227sub parser_type { $_[0]->{'parser_type'}; }
e2158c40 228
f4a59b6c 229sub parser_args { shift->_args("parser", @_); }
96844cae 230
f4a59b6c 231# ----------------------------------------------------------------------
185c34d5 232# e.g.
233# $sqlt->filters => [
234# sub { },
235# [ "NormalizeNames", field => "lc", tabel => "ucfirst" ],
236# [
237# "DataTypeMap",
238# "TEXT" => "BIGTEXT",
239# ],
240# ],
241# ----------------------------------------------------------------------
242sub filters {
243 my $self = shift;
244 my $filters = $self->{filters} ||= [];
245 return @$filters unless @_;
246
44eb9098 247 # Set. Convert args to list of [\&code,@args]
185c34d5 248 foreach (@_) {
44eb9098 249 my ($filt,@args) = ref($_) eq "ARRAY" ? @$_ : $_;
250 if ( isa($filt,"CODE") ) {
251 push @$filters, [$filt,@args];
185c34d5 252 next;
253 }
254 else {
44eb9098 255 $self->debug("Adding $filt filter. Args:".Dumper(\@args)."\n");
256 $filt = _load_sub("$filt\::filter", "SQL::Translator::Filter")
257 || return $self->error(__PACKAGE__->error);
258 push @$filters, [$filt,@args];
185c34d5 259 }
260 }
261 return @$filters;
262}
263
264# ----------------------------------------------------------------------
96844cae 265sub show_warnings {
266 my $self = shift;
267 my $arg = shift;
268 if ( defined $arg ) {
269 $self->{'show_warnings'} = $arg ? 1 : 0;
270 }
271 return $self->{'show_warnings'} || 0;
272}
273
ca10f295 274
0f3778d0 275# filename - get or set the filename
276sub filename {
277 my $self = shift;
278 if (@_) {
279 my $filename = shift;
280 if (-d $filename) {
281 my $msg = "Cannot use directory '$filename' as input source";
282 return $self->error($msg);
f69e9da3 283 } elsif (ref($filename) eq 'ARRAY') {
284 $self->{'filename'} = $filename;
285 $self->debug("Got array of files: ".join(', ',@$filename)."\n");
0f3778d0 286 } elsif (-f _ && -r _) {
287 $self->{'filename'} = $filename;
288 $self->debug("Got filename: '$self->{'filename'}'\n");
289 } else {
290 my $msg = "Cannot use '$filename' as input source: ".
291 "file does not exist or is not readable.";
292 return $self->error($msg);
293 }
294 }
ca10f295 295
0f3778d0 296 $self->{'filename'};
297}
ca10f295 298
0f3778d0 299# ----------------------------------------------------------------------
300# data([$data])
301#
302# if $self->{'data'} is not set, but $self->{'filename'} is, then
303# $self->{'filename'} is opened and read, with the results put into
304# $self->{'data'}.
305# ----------------------------------------------------------------------
306sub data {
307 my $self = shift;
ca10f295 308
0f3778d0 309 # Set $self->{'data'} based on what was passed in. We will
310 # accept a number of things; do our best to get it right.
311 if (@_) {
312 my $data = shift;
313 if (isa($data, "SCALAR")) {
314 $self->{'data'} = $data;
315 }
316 else {
317 if (isa($data, 'ARRAY')) {
318 $data = join '', @$data;
319 }
320 elsif (isa($data, 'GLOB')) {
321 local $/;
322 $data = <$data>;
323 }
324 elsif (! ref $data && @_) {
325 $data = join '', $data, @_;
326 }
327 $self->{'data'} = \$data;
328 }
329 }
9398955f 330
7a8e1f51 331 # If we have a filename but no data yet, populate.
9398955f 332 if (not $self->{'data'} and my $filename = $self->filename) {
49e1eb70 333 $self->debug("Opening '$filename' to get contents.\n");
9398955f 334 local *FH;
335 local $/;
336 my $data;
337
f69e9da3 338 my @files = ref($filename) eq 'ARRAY' ? @$filename : ($filename);
9398955f 339
f69e9da3 340 foreach my $file (@files) {
960b4e55 341 unless (open FH, $file) {
342 return $self->error("Can't read file '$file': $!");
343 }
9398955f 344
960b4e55 345 $data .= <FH>;
95a2cfb6 346
960b4e55 347 unless (close FH) {
348 return $self->error("Can't close file '$file': $!");
349 }
f69e9da3 350 }
95a2cfb6 351
f69e9da3 352 $self->{'data'} = \$data;
9398955f 353 }
9398955f 354
355 return $self->{'data'};
7a8e1f51 356}
9398955f 357
45ee6be0 358# ----------------------------------------------------------------------
a57ce769 359sub reset {
360#
361# Deletes the existing Schema object so that future calls to translate
362# don't append to the existing.
363#
364 my $self = shift;
365 $self->{'schema'} = undef;
366 return 1;
367}
368
369# ----------------------------------------------------------------------
45ee6be0 370sub schema {
371#
372# Returns the SQL::Translator::Schema object
373#
374 my $self = shift;
375
376 unless ( defined $self->{'schema'} ) {
47fed978 377 $self->{'schema'} = SQL::Translator::Schema->new(
10f36920 378 translator => $self,
47fed978 379 );
45ee6be0 380 }
d529894e 381
45ee6be0 382 return $self->{'schema'};
383}
384
385# ----------------------------------------------------------------------
d529894e 386sub trace {
387 my $self = shift;
388 my $arg = shift;
389 if ( defined $arg ) {
390 $self->{'trace'} = $arg ? 1 : 0;
391 }
392 return $self->{'trace'} || 0;
393}
394
395# ----------------------------------------------------------------------
0f3778d0 396# translate([source], [\%args])
397#
398# translate does the actual translation. The main argument is the
399# source of the data to be translated, which can be a filename, scalar
400# reference, or glob reference.
401#
402# Alternatively, translate takes optional arguements, which are passed
403# to the appropriate places. Most notable of these arguments are
404# parser and producer, which can be used to set the parser and
405# producer, respectively. This is the applications last chance to set
406# these.
407#
408# translate returns a string.
409# ----------------------------------------------------------------------
ca251f03 410sub translate {
411 my $self = shift;
412 my ($args, $parser, $parser_type, $producer, $producer_type);
5e2c196a 413 my ($parser_output, $producer_output, @producer_output);
ca10f295 414
7a8e1f51 415 # Parse arguments
185c34d5 416 if (@_ == 1) {
7a8e1f51 417 # Passed a reference to a hash?
ca10f295 418 if (isa($_[0], 'HASH')) {
7a8e1f51 419 # yep, a hashref
49e1eb70 420 $self->debug("translate: Got a hashref\n");
ca10f295 421 $args = $_[0];
422 }
9398955f 423
0f3778d0 424 # Passed a GLOB reference, i.e., filehandle
425 elsif (isa($_[0], 'GLOB')) {
426 $self->debug("translate: Got a GLOB reference\n");
427 $self->data($_[0]);
428 }
429
7a8e1f51 430 # Passed a reference to a string containing the data
ca10f295 431 elsif (isa($_[0], 'SCALAR')) {
9398955f 432 # passed a ref to a string
49e1eb70 433 $self->debug("translate: Got a SCALAR reference (string)\n");
9398955f 434 $self->data($_[0]);
ca10f295 435 }
9398955f 436
7a8e1f51 437 # Not a reference; treat it as a filename
b346d8f1 438 elsif (! ref $_[0]) {
ca10f295 439 # Not a ref, it's a filename
49e1eb70 440 $self->debug("translate: Got a filename\n");
9398955f 441 $self->filename($_[0]);
ca10f295 442 }
9398955f 443
7a8e1f51 444 # Passed something else entirely.
b346d8f1 445 else {
446 # We're not impressed. Take your empty string and leave.
38254289 447 # return "";
448
7a8e1f51 449 # Actually, if data, parser, and producer are set, then we
450 # can continue. Too bad, because I like my comment
451 # (above)...
38254289 452 return "" unless ($self->data &&
453 $self->producer &&
454 $self->parser);
b346d8f1 455 }
16dc9970 456 }
457 else {
b346d8f1 458 # You must pass in a hash, or you get nothing.
459 return "" if @_ % 2;
ca10f295 460 $args = { @_ };
7a8e1f51 461 }
16dc9970 462
9398955f 463 # ----------------------------------------------------------------------
464 # Can specify the data to be transformed using "filename", "file",
7a8e1f51 465 # "data", or "datasource".
9398955f 466 # ----------------------------------------------------------------------
7a8e1f51 467 if (my $filename = ($args->{'filename'} || $args->{'file'})) {
9398955f 468 $self->filename($filename);
469 }
ca10f295 470
422298aa 471 if (my $data = ($args->{'data'} || $args->{'datasource'})) {
9398955f 472 $self->data($data);
16dc9970 473 }
ca10f295 474
9398955f 475 # ----------------------------------------------------------------
476 # Get the data.
477 # ----------------------------------------------------------------
478 my $data = $self->data;
077ebf34 479
9398955f 480 # ----------------------------------------------------------------
ca10f295 481 # Local reference to the parser subroutine
9398955f 482 # ----------------------------------------------------------------
ca10f295 483 if ($parser = ($args->{'parser'} || $args->{'from'})) {
484 $self->parser($parser);
16dc9970 485 }
7a8e1f51 486 $parser = $self->parser;
487 $parser_type = $self->parser_type;
16dc9970 488
9398955f 489 # ----------------------------------------------------------------
ca10f295 490 # Local reference to the producer subroutine
9398955f 491 # ----------------------------------------------------------------
ca10f295 492 if ($producer = ($args->{'producer'} || $args->{'to'})) {
493 $self->producer($producer);
16dc9970 494 }
7a8e1f51 495 $producer = $self->producer;
496 $producer_type = $self->producer_type;
16dc9970 497
9398955f 498 # ----------------------------------------------------------------
185c34d5 499 # Execute the parser, the filters and then execute the producer.
7a8e1f51 500 # Allowances are made for each piece to die, or fail to compile,
501 # since the referenced subroutines could be almost anything. In
502 # the future, each of these might happen in a Safe environment,
503 # depending on how paranoid we want to be.
9398955f 504 # ----------------------------------------------------------------
185c34d5 505
506 # Run parser
a57ce769 507 unless ( defined $self->{'schema'} ) {
508 eval { $parser_output = $parser->($self, $$data) };
509 if ($@ || ! $parser_output) {
510 my $msg = sprintf "translate: Error with parser '%s': %s",
511 $parser_type, ($@) ? $@ : " no results";
512 return $self->error($msg);
513 }
7a8e1f51 514 }
841a3f1a 515 $self->debug("Schema =\n", Dumper($self->schema), "\n");
516
185c34d5 517 # Validate the schema if asked to.
4b6a6341 518 if ($self->validate) {
3f4af30d 519 my $schema = $self->schema;
520 return $self->error('Invalid schema') unless $schema->is_valid;
521 }
522
185c34d5 523 # Run filters
524 my $filt_num = 0;
525 foreach ($self->filters) {
526 $filt_num++;
44eb9098 527 my ($code,@args) = @$_;
528 eval { $code->($self->schema, @args) };
185c34d5 529 my $err = $@ || $self->error || 0;
530 return $self->error("Error with filter $filt_num : $err") if $err;
531 }
532
533 # Run producer
5e2c196a 534 # Calling wantarray in the eval no work, wrong scope.
535 my $wantarray = wantarray ? 1 : 0;
a83ffc24 536 eval {
537 if ($wantarray) {
538 @producer_output = $producer->($self);
539 } else {
540 $producer_output = $producer->($self);
541 }
542 };
5e2c196a 543 if ($@ || !( $producer_output || @producer_output)) {
a5d57a52 544 my $err = $@ || $self->error || "no results";
545 my $msg = "translate: Error with producer '$producer_type': $err";
c2d3a526 546 return $self->error($msg);
7a8e1f51 547 }
548
5e2c196a 549 return wantarray ? @producer_output : $producer_output;
16dc9970 550}
ca10f295 551
d529894e 552# ----------------------------------------------------------------------
0f3778d0 553# list_parsers()
554#
555# Hacky sort of method to list all available parsers. This has
556# several problems:
557#
558# - Only finds things in the SQL::Translator::Parser namespace
559#
560# - Only finds things that are located in the same directory
561# as SQL::Translator::Parser. Yeck.
562#
563# This method will fail in several very likely cases:
564#
565# - Parser modules in different namespaces
566#
567# - Parser modules in the SQL::Translator::Parser namespace that
568# have any XS componenets will be installed in
569# arch_lib/SQL/Translator.
570#
571# ----------------------------------------------------------------------
572sub list_parsers {
ca1f2237 573 return shift->_list("parser");
0f3778d0 574}
575
576# ----------------------------------------------------------------------
577# list_producers()
578#
579# See notes for list_parsers(), above; all the problems apply to
580# list_producers as well.
581# ----------------------------------------------------------------------
c0c4aef9 582sub list_producers {
ca1f2237 583 return shift->_list("producer");
0f3778d0 584}
585
c0c4aef9 586
0f3778d0 587# ======================================================================
588# Private Methods
589# ======================================================================
c0c4aef9 590
0f3778d0 591# ----------------------------------------------------------------------
592# _args($type, \%args);
593#
594# Gets or sets ${type}_args. Called by parser_args and producer_args.
595# ----------------------------------------------------------------------
596sub _args {
597 my $self = shift;
598 my $type = shift;
599 $type = "${type}_args" unless $type =~ /_args$/;
600
601 unless (defined $self->{$type} && isa($self->{$type}, 'HASH')) {
602 $self->{$type} = { };
603 }
604
605 if (@_) {
606 # If the first argument is an explicit undef (remember, we
607 # don't get here unless there is stuff in @_), then we clear
608 # out the producer_args hash.
609 if (! defined $_[0]) {
610 shift @_;
611 %{$self->{$type}} = ();
612 }
613
614 my $args = isa($_[0], 'HASH') ? shift : { @_ };
615 %{$self->{$type}} = (%{$self->{$type}}, %$args);
616 }
617
618 $self->{$type};
c0c4aef9 619}
620
d529894e 621# ----------------------------------------------------------------------
f4a59b6c 622# Does the get/set work for parser and producer. e.g.
623# return $self->_tool({
624# name => 'producer',
625# path => "SQL::Translator::Producer",
626# default_sub => "produce",
627# }, @_);
628# ----------------------------------------------------------------------
629sub _tool {
630 my ($self,$args) = (shift, shift);
631 my $name = $args->{name};
da3a97b7 632 return $self->{$name} unless @_; # get accessor
633
634 my $path = $args->{path};
635 my $default_sub = $args->{default_sub};
f4a59b6c 636 my $tool = shift;
da3a97b7 637
f4a59b6c 638 # passed an anonymous subroutine reference
639 if (isa($tool, 'CODE')) {
640 $self->{$name} = $tool;
641 $self->{"$name\_type"} = "CODE";
642 $self->debug("Got $name: code ref\n");
da3a97b7 643 }
f4a59b6c 644
da3a97b7 645 # Module name was passed directly
646 # We try to load the name; if it doesn't load, there's a
647 # possibility that it has a function name attached to it,
648 # so we give it a go.
f4a59b6c 649 else {
f4a59b6c 650 $tool =~ s/-/::/g if $tool !~ /::/;
da3a97b7 651 my ($code,$sub);
652 ($code,$sub) = _load_sub("$tool\::$default_sub", $path);
9c0bc5a5 653 unless ($code) {
654 if ( __PACKAGE__->error =~ m/Can't find module/ ) {
655 # Mod not found so try sub
656 ($code,$sub) = _load_sub("$tool", $path) unless $code;
657 die "Can't load $name subroutine '$tool' : ".__PACKAGE__->error
658 unless $code;
659 }
660 else {
661 die "Can't load $name '$tool' : ".__PACKAGE__->error;
662 }
663 }
185c34d5 664
f4a59b6c 665 # get code reference and assign
da3a97b7 666 my (undef,$module,undef) = $sub =~ m/((.*)::)?(\w+)$/;
667 $self->{$name} = $code;
668 $self->{"$name\_type"} = $sub eq "CODE" ? "CODE" : $module;
669 $self->debug("Got $name: $sub\n");
670 }
f4a59b6c 671
672 # At this point, $self->{$name} contains a subroutine
673 # reference that is ready to run
674
675 # Anything left? If so, it's args
676 my $meth = "$name\_args";
677 $self->$meth(@_) if (@_);
678
679 return $self->{$name};
680}
681
682# ----------------------------------------------------------------------
0f3778d0 683# _list($type)
684# ----------------------------------------------------------------------
685sub _list {
3015bf96 686 my $self = shift;
687 my $type = shift || return ();
ca1f2237 688 my $uctype = ucfirst lc $type;
ca1f2237 689
3015bf96 690 #
691 # First find all the directories where SQL::Translator
692 # parsers or producers (the "type") appear to live.
693 #
ca1f2237 694 load("SQL::Translator::$uctype") or return ();
695 my $path = catfile "SQL", "Translator", $uctype;
3015bf96 696 my @dirs;
ca1f2237 697 for (@INC) {
698 my $dir = catfile $_, $path;
4b6a6341 699 $self->debug("_list_${type}s searching $dir\n");
ca1f2237 700 next unless -d $dir;
3015bf96 701 push @dirs, $dir;
ca1f2237 702 }
c0c4aef9 703
3015bf96 704 #
705 # Now use File::File::find to look recursively in those
706 # directories for all the *.pm files, then present them
707 # with the slashes turned into dashes.
708 #
709 my %found;
710 find(
711 sub {
712 if ( -f && m/\.pm$/ ) {
713 my $mod = $_;
714 $mod =~ s/\.pm$//;
715 my $cur_dir = $File::Find::dir;
04db8601 716 my $base_dir = quotemeta catfile 'SQL', 'Translator', $uctype;
3015bf96 717
718 #
719 # See if the current directory is below the base directory.
720 #
721 if ( $cur_dir =~ m/$base_dir(.*)/ ) {
722 $cur_dir = $1;
723 $cur_dir =~ s!^/!!; # kill leading slash
724 $cur_dir =~ s!/!-!g; # turn other slashes into dashes
725 }
726 else {
727 $cur_dir = '';
728 }
729
730 $found{ join '-', map { $_ || () } $cur_dir, $mod } = 1;
731 }
732 },
733 @dirs
734 );
735
736 return sort { lc $a cmp lc $b } keys %found;
c0c4aef9 737}
738
d529894e 739# ----------------------------------------------------------------------
f4a59b6c 740# load(MODULE [,PATH[,PATH]...])
0f3778d0 741#
742# Loads a Perl module. Short circuits if a module is already loaded.
f4a59b6c 743#
744# MODULE - is the name of the module to load.
745#
746# PATH - optional list of 'package paths' to look for the module in. e.g
017580f4 747# If you called load('Super::Foo' => 'My', 'Other') it will
748# try to load the mod Super::Foo then My::Super::Foo then Other::Super::Foo.
f4a59b6c 749#
750# Returns package name of the module actually loaded or false and sets error.
751#
185c34d5 752# Note, you can't load a name from the root namespace (ie one without '::' in
f4a59b6c 753# it), therefore a single word name without a path fails.
0f3778d0 754# ----------------------------------------------------------------------
ca10f295 755sub load {
f4a59b6c 756 my $name = shift;
757 my @path;
758 push @path, "" if $name =~ /::/; # Empty path to check name on its own first
759 push @path, @_ if @_;
760
761 foreach (@path) {
762 my $module = $_ ? "$_\::$name" : $name;
763 my $file = $module; $file =~ s[::][/]g; $file .= ".pm";
764 __PACKAGE__->debug("Loading $name as $file\n");
765 return $module if $INC{$file}; # Already loaded
185c34d5 766
f4a59b6c 767 eval { require $file };
768 next if $@ =~ /Can't locate $file in \@INC/;
617f79f6 769 eval { $module->import() } unless $@;
017580f4 770 return __PACKAGE__->error("Error loading $name as $module : $@")
771 if $@ && $@ !~ /"SQL::Translator::Producer" is not exported/;
f4a59b6c 772
773 return $module; # Module loaded ok
774 }
ca1f2237 775
9c0bc5a5 776 return __PACKAGE__->error("Can't find module $name. Path:".join(",",@path));
da3a97b7 777}
778
779# ----------------------------------------------------------------------
780# Load the sub name given (including package), optionally using a base package
781# path. Returns code ref and name of sub loaded, including its package.
782# (\&code, $sub) = load_sub( 'MySQL::produce', "SQL::Translator::Producer" );
783# (\&code, $sub) = load_sub( 'MySQL::produce', @path );
784# ----------------------------------------------------------------------
785sub _load_sub {
786 my ($tool, @path) = @_;
185c34d5 787
da3a97b7 788 my (undef,$module,$func_name) = $tool =~ m/((.*)::)?(\w+)$/;
789 if ( my $module = load($module => @path) ) {
790 my $sub = "$module\::$func_name";
185c34d5 791 return wantarray ? ( \&{ $sub }, $sub ) : \&$sub;
792 }
da3a97b7 793 return undef;
1fd8c91f 794}
16dc9970 795
67e5ff53 796# ----------------------------------------------------------------------
7d5bcab8 797sub format_table_name {
1ea530d4 798 return shift->_format_name('_format_table_name', @_);
7d5bcab8 799}
800
67e5ff53 801# ----------------------------------------------------------------------
7d5bcab8 802sub format_package_name {
1ea530d4 803 return shift->_format_name('_format_package_name', @_);
7d5bcab8 804}
805
67e5ff53 806# ----------------------------------------------------------------------
7d5bcab8 807sub format_fk_name {
1ea530d4 808 return shift->_format_name('_format_fk_name', @_);
7d5bcab8 809}
810
67e5ff53 811# ----------------------------------------------------------------------
7d5bcab8 812sub format_pk_name {
1ea530d4 813 return shift->_format_name('_format_pk_name', @_);
814}
815
816# ----------------------------------------------------------------------
185c34d5 817# The other format_*_name methods rely on this one. It optionally
1ea530d4 818# accepts a subroutine ref as the first argument (or uses an identity
819# sub if one isn't provided or it doesn't already exist), and applies
820# it to the rest of the arguments (if any).
821# ----------------------------------------------------------------------
822sub _format_name {
f9a0c3b5 823 my $self = shift;
1ea530d4 824 my $field = shift;
825 my @args = @_;
8a990c91 826
1ea530d4 827 if (ref($args[0]) eq 'CODE') {
828 $self->{$field} = shift @args;
8a990c91 829 }
1ea530d4 830 elsif (! exists $self->{$field}) {
831 $self->{$field} = sub { return shift };
8a990c91 832 }
833
1ea530d4 834 return @args ? $self->{$field}->(@args) : $self->{$field};
7d5bcab8 835}
836
d529894e 837# ----------------------------------------------------------------------
0f3778d0 838# isa($ref, $type)
839#
840# Calls UNIVERSAL::isa($ref, $type). I think UNIVERSAL::isa is ugly,
841# but I like function overhead.
842# ----------------------------------------------------------------------
843sub isa($$) {
844 my ($ref, $type) = @_;
845 return UNIVERSAL::isa($ref, $type);
846}
c2d3a526 847
3f4af30d 848# ----------------------------------------------------------------------
c314ec98 849# version
850#
851# Returns the $VERSION of the main SQL::Translator package.
852# ----------------------------------------------------------------------
853sub version {
854 my $self = shift;
855 return $VERSION;
856}
857
858# ----------------------------------------------------------------------
3f4af30d 859sub validate {
3f4af30d 860 my ( $self, $arg ) = @_;
861 if ( defined $arg ) {
862 $self->{'validate'} = $arg ? 1 : 0;
863 }
864 return $self->{'validate'} || 0;
865}
866
16dc9970 8671;
16dc9970 868
389b318c 869# ----------------------------------------------------------------------
870# Who killed the pork chops?
871# What price bananas?
872# Are you my Angel?
873# Allen Ginsberg
874# ----------------------------------------------------------------------
875
876=pod
0f3778d0 877
878=head1 NAME
879
954f31f1 880SQL::Translator - manipulate structured data definitions (SQL and more)
0f3778d0 881
882=head1 SYNOPSIS
883
884 use SQL::Translator;
885
67e5ff53 886 my $translator = SQL::Translator->new(
887 # Print debug info
888 debug => 1,
889 # Print Parse::RecDescent trace
185c34d5 890 trace => 0,
67e5ff53 891 # Don't include comments in output
185c34d5 892 no_comments => 0,
67e5ff53 893 # Print name mutations, conflicts
185c34d5 894 show_warnings => 0,
67e5ff53 895 # Add "drop table" statements
185c34d5 896 add_drop_table => 1,
5e2c196a 897 # to quote or not to quote, thats the question
898 quote_table_names => 1,
899 quote_field_names => 1,
67e5ff53 900 # Validate schema object
185c34d5 901 validate => 1,
f9a0c3b5 902 # Make all table names CAPS in producers which support this option
67e5ff53 903 format_table_name => sub {my $tablename = shift; return uc($tablename)},
f9a0c3b5 904 # Null-op formatting, only here for documentation's sake
7d5bcab8 905 format_package_name => sub {return shift},
906 format_fk_name => sub {return shift},
907 format_pk_name => sub {return shift},
0f3778d0 908 );
909
910 my $output = $translator->translate(
389b318c 911 from => 'MySQL',
912 to => 'Oracle',
f9a0c3b5 913 # Or an arrayref of filenames, i.e. [ $file1, $file2, $file3 ]
185c34d5 914 filename => $file,
0f3778d0 915 ) or die $translator->error;
916
917 print $output;
918
919=head1 DESCRIPTION
920
2d993495 921This documentation covers the API for SQL::Translator. For a more general
922discussion of how to use the modules and scripts, please see
923L<SQL::Translator::Manual>.
924
29efc9fd 925SQL::Translator is a group of Perl modules that converts
926vendor-specific SQL table definitions into other formats, such as
927other vendor-specific SQL, ER diagrams, documentation (POD and HTML),
928XML, and Class::DBI classes. The main focus of SQL::Translator is
929SQL, but parsers exist for other structured data formats, including
930Excel spreadsheets and arbitrarily delimited text files. Through the
931separation of the code into parsers and producers with an object model
932in between, it's possible to combine any parser with any producer, to
933plug in custom parsers or producers, or to manipulate the parsed data
934via the built-in object model. Presently only the definition parts of
935SQL are handled (CREATE, ALTER), not the manipulation of data (INSERT,
936UPDATE, DELETE).
0f3778d0 937
938=head1 CONSTRUCTOR
939
5760246d 940The constructor is called C<new>, and accepts a optional hash of options.
0f3778d0 941Valid options are:
942
943=over 4
944
ca251f03 945=item *
946
947parser / from
948
949=item *
950
951parser_args
0f3778d0 952
ca251f03 953=item *
0f3778d0 954
ca251f03 955producer / to
0f3778d0 956
ca251f03 957=item *
0f3778d0 958
ca251f03 959producer_args
0f3778d0 960
ca251f03 961=item *
962
185c34d5 963filters
964
965=item *
966
ca251f03 967filename / file
968
969=item *
970
971data
972
973=item *
0f3778d0 974
ca251f03 975debug
0f3778d0 976
389b318c 977=item *
978
979add_drop_table
980
981=item *
982
5e2c196a 983quote_table_names
984
985=item *
986
987quote_field_names
988
989=item *
990
389b318c 991no_comments
992
993=item *
994
995trace
996
997=item *
998
999validate
1000
0f3778d0 1001=back
1002
1003All options are, well, optional; these attributes can be set via
1004instance methods. Internally, they are; no (non-syntactical)
1005advantage is gained by passing options to the constructor.
1006
1007=head1 METHODS
1008
5760246d 1009=head2 add_drop_table
0f3778d0 1010
1011Toggles whether or not to add "DROP TABLE" statements just before the
1012create definitions.
1013
5e2c196a 1014=head2 quote_table_names
1015
1016Toggles whether or not to quote table names with " in DROP and CREATE
1017statements. The default (true) is to quote them.
1018
1019=head2 quote_field_names
1020
1021Toggles whether or not to quote field names with " in most
1022statements. The default (true), is to quote them.
1023
5760246d 1024=head2 no_comments
0f3778d0 1025
1026Toggles whether to print comments in the output. Accepts a true or false
1027value, returns the current value.
1028
5760246d 1029=head2 producer
0f3778d0 1030
5760246d 1031The C<producer> method is an accessor/mutator, used to retrieve or
0f3778d0 1032define what subroutine is called to produce the output. A subroutine
1033defined as a producer will be invoked as a function (I<not a method>)
8e1fc861 1034and passed its container C<SQL::Translator> instance, which it should
1035call the C<schema> method on, to get the C<SQL::Translator::Schema>
1036generated by the parser. It is expected that the function transform the
1037schema structure to a string. The C<SQL::Translator> instance is also useful
1038for informational purposes; for example, the type of the parser can be
5760246d 1039retrieved using the C<parser_type> method, and the C<error> and
1040C<debug> methods can be called when needed.
0f3778d0 1041
ca251f03 1042When defining a producer, one of several things can be passed in: A
5760246d 1043module name (e.g., C<My::Groovy::Producer>), a module name relative to
1044the C<SQL::Translator::Producer> namespace (e.g., C<MySQL>), a module
ca251f03 1045name and function combination (C<My::Groovy::Producer::transmogrify>),
0f3778d0 1046or a reference to an anonymous subroutine. If a full module name is
1047passed in (for the purposes of this method, a string containing "::"
1048is considered to be a module name), it is treated as a package, and a
ca251f03 1049function called "produce" will be invoked: C<$modulename::produce>.
1050If $modulename cannot be loaded, the final portion is stripped off and
0f3778d0 1051treated as a function. In other words, if there is no file named
ca251f03 1052F<My/Groovy/Producer/transmogrify.pm>, C<SQL::Translator> will attempt
5760246d 1053to load F<My/Groovy/Producer.pm> and use C<transmogrify> as the name of
1054the function, instead of the default C<produce>.
0f3778d0 1055
1056 my $tr = SQL::Translator->new;
1057
1058 # This will invoke My::Groovy::Producer::produce($tr, $data)
1059 $tr->producer("My::Groovy::Producer");
1060
1061 # This will invoke SQL::Translator::Producer::Sybase::produce($tr, $data)
1062 $tr->producer("Sybase");
1063
1064 # This will invoke My::Groovy::Producer::transmogrify($tr, $data),
1065 # assuming that My::Groovy::Producer::transmogrify is not a module
1066 # on disk.
1067 $tr->producer("My::Groovy::Producer::transmogrify");
1068
1069 # This will invoke the referenced subroutine directly, as
1070 # $subref->($tr, $data);
1071 $tr->producer(\&my_producer);
1072
5760246d 1073There is also a method named C<producer_type>, which is a string
1074containing the classname to which the above C<produce> function
0f3778d0 1075belongs. In the case of anonymous subroutines, this method returns
1076the string "CODE".
1077
5760246d 1078Finally, there is a method named C<producer_args>, which is both an
0f3778d0 1079accessor and a mutator. Arbitrary data may be stored in name => value
1080pairs for the producer subroutine to access:
1081
1082 sub My::Random::producer {
1083 my ($tr, $data) = @_;
1084 my $pr_args = $tr->producer_args();
1085
1086 # $pr_args is a hashref.
1087
5760246d 1088Extra data passed to the C<producer> method is passed to
1089C<producer_args>:
0f3778d0 1090
1091 $tr->producer("xSV", delimiter => ',\s*');
1092
1093 # In SQL::Translator::Producer::xSV:
1094 my $args = $tr->producer_args;
1095 my $delimiter = $args->{'delimiter'}; # value is ,\s*
1096
5760246d 1097=head2 parser
0f3778d0 1098
5760246d 1099The C<parser> method defines or retrieves a subroutine that will be
0f3778d0 1100called to perform the parsing. The basic idea is the same as that of
5760246d 1101C<producer> (see above), except the default subroutine name is
ca251f03 1102"parse", and will be invoked as C<$module_name::parse($tr, $data)>.
0f3778d0 1103Also, the parser subroutine will be passed a string containing the
1104entirety of the data to be parsed.
1105
1106 # Invokes SQL::Translator::Parser::MySQL::parse()
1107 $tr->parser("MySQL");
1108
1109 # Invokes My::Groovy::Parser::parse()
1110 $tr->parser("My::Groovy::Parser");
1111
1112 # Invoke an anonymous subroutine directly
1113 $tr->parser(sub {
1114 my $dumper = Data::Dumper->new([ $_[1] ], [ "SQL" ]);
1115 $dumper->Purity(1)->Terse(1)->Deepcopy(1);
1116 return $dumper->Dump;
1117 });
1118
5760246d 1119There is also C<parser_type> and C<parser_args>, which perform
1120analogously to C<producer_type> and C<producer_args>
0f3778d0 1121
185c34d5 1122=head2 filters
1123
1124Set or retreive the filters to run over the schema during the
1125translation, before the producer creates its output. Filters are sub
1126routines called, in order, with the schema object to filter as the 1st
44eb9098 1127arg and a hash of options (passed as a list) for the rest of the args.
1128They are free to do whatever they want to the schema object, which will be
1129handed to any following filters, then used by the producer.
185c34d5 1130
1131Filters are set as an array, which gives the order they run in.
1132Like parsers and producers, they can be defined by a module name, a
1133module name relative to the SQL::Translator::Filter namespace, a module
1134name and function name together or a reference to an anonymous subroutine.
1135When using a module name a function called C<filter> will be invoked in
44eb9098 1136that package to do the work.
1137
1138To pass args to the filter set it as an array ref with the 1st value giving
1139the filter (name or sub) and the rest its args. e.g.
185c34d5 1140
1141 $tr->filters(
1142 sub {
1143 my $schema = shift;
1144 # Do stuff to schema here!
1145 },
44eb9098 1146 DropFKeys,
1147 [ "Names", table => 'lc' ],
1148 [ "Foo", foo => "bar", hello => "world" ],
1149 [ "Filter5" ],
185c34d5 1150 );
1151
44eb9098 1152Although you normally set them in the constructor, which calls
185c34d5 1153through to filters. i.e.
1154
1155 my $translator = SQL::Translator->new(
1156 ...
1157 filters => [
1158 sub { ... },
44eb9098 1159 [ "Names", table => 'lc' ],
185c34d5 1160 ],
1161 ...
1162 );
1163
1164See F<t/36-filters.t> for more examples.
1165
1166Multiple set calls to filters are cumulative with new filters added to
1167the end of the current list.
1168
1169Returns the filters as a list of array refs, the 1st value being a
44eb9098 1170reference to the filter sub and the rest its args.
185c34d5 1171
5760246d 1172=head2 show_warnings
0f3778d0 1173
1174Toggles whether to print warnings of name conflicts, identifier
1175mutations, etc. Probably only generated by producers to let the user
1176know when something won't translate very smoothly (e.g., MySQL "enum"
1177fields into Oracle). Accepts a true or false value, returns the
1178current value.
1179
5760246d 1180=head2 translate
0f3778d0 1181
185c34d5 1182The C<translate> method calls the subroutine referenced by the
1183C<parser> data member, then calls any C<filters> and finally calls
1184the C<producer> sub routine (these members are described above).
1185It accepts as arguments a number of things, in key => value format,
1186including (potentially) a parser and a producer (they are passed
1187directly to the C<parser> and C<producer> methods).
0f3778d0 1188
5760246d 1189Here is how the parameter list to C<translate> is parsed:
0f3778d0 1190
1191=over
1192
1193=item *
1194
11951 argument means it's the data to be parsed; which could be a string
ca251f03 1196(filename) or a reference to a scalar (a string stored in memory), or a
0f3778d0 1197reference to a hash, which is parsed as being more than one argument
1198(see next section).
1199
1200 # Parse the file /path/to/datafile
1201 my $output = $tr->translate("/path/to/datafile");
1202
1203 # Parse the data contained in the string $data
1204 my $output = $tr->translate(\$data);
1205
1206=item *
1207
1208More than 1 argument means its a hash of things, and it might be
1209setting a parser, producer, or datasource (this key is named
1210"filename" or "file" if it's a file, or "data" for a SCALAR reference.
1211
1212 # As above, parse /path/to/datafile, but with different producers
1213 for my $prod ("MySQL", "XML", "Sybase") {
1214 print $tr->translate(
1215 producer => $prod,
1216 filename => "/path/to/datafile",
1217 );
1218 }
1219
1220 # The filename hash key could also be:
1221 datasource => \$data,
1222
1223You get the idea.
1224
1225=back
1226
5760246d 1227=head2 filename, data
0f3778d0 1228
5760246d 1229Using the C<filename> method, the filename of the data to be parsed
1230can be set. This method can be used in conjunction with the C<data>
1231method, below. If both the C<filename> and C<data> methods are
1232invoked as mutators, the data set in the C<data> method is used.
0f3778d0 1233
1234 $tr->filename("/my/data/files/create.sql");
1235
1236or:
1237
1238 my $create_script = do {
1239 local $/;
1240 open CREATE, "/my/data/files/create.sql" or die $!;
1241 <CREATE>;
1242 };
1243 $tr->data(\$create_script);
1244
5760246d 1245C<filename> takes a string, which is interpreted as a filename.
1246C<data> takes a reference to a string, which is used as the data to be
0f3778d0 1247parsed. If a filename is set, then that file is opened and read when
5760246d 1248the C<translate> method is called, as long as the data instance
0f3778d0 1249variable is not set.
1250
45ee6be0 1251=head2 schema
1252
1253Returns the SQL::Translator::Schema object.
1254
5760246d 1255=head2 trace
0f3778d0 1256
1257Turns on/off the tracing option of Parse::RecDescent.
1258
389b318c 1259=head2 validate
1260
1261Whether or not to validate the schema object after parsing and before
1262producing.
1263
c314ec98 1264=head2 version
1265
1266Returns the version of the SQL::Translator release.
1267
7a8e1f51 1268=head1 AUTHORS
16dc9970 1269
841a3f1a 1270The following people have contributed to the SQLFairy project:
1271
1272=over 4
1273
1274=item * Mark Addison <grommit@users.sourceforge.net>
1275
1276=item * Sam Angiuoli <angiuoli@users.sourceforge.net>
1277
5342f5c1 1278=item * Anders Nor Berle <berle@cpan.org>
1279
d09e5700 1280=item * Dave Cash <dave@gnofn.org>
1281
841a3f1a 1282=item * Darren Chamberlain <dlc@users.sourceforge.net>
1283
1284=item * Ken Y. Clark <kclark@cpan.org>
1285
1286=item * Allen Day <allenday@users.sourceforge.net>
1287
1288=item * Paul Harrington <phrrngtn@users.sourceforge.net>
1289
1290=item * Mikey Melillo <mmelillo@users.sourceforge.net>
1291
1292=item * Chris Mungall <cjm@fruitfly.org>
1293
1294=item * Ross Smith II <rossta@users.sf.net>
1295
1296=item * Gudmundur A. Thorisson <mummi@cshl.org>
1297
1298=item * Chris To <christot@users.sourceforge.net>
1299
1300=item * Jason Williams <smdwilliams@users.sourceforge.net>
1301
1302=item * Ying Zhang <zyolive@yahoo.com>
1303
ca1f9923 1304=item * Daniel Ruoso <daniel@ruoso.com>
1305
f5405d47 1306=item * Ryan D Johnson <ryan@innerfence.com>
1307
d3888c81 1308=item * Jonathan Yu <frequency@cpan.org>
1309
841a3f1a 1310=back
1311
1312If you would like to contribute to the project, you can send patches
1313to the developers mailing list:
1314
1315 sqlfairy-developers@lists.sourceforge.net
1316
1317Or send us a message (with your Sourceforge username) asking to be
1318added to the project and what you'd like to contribute.
1319
dfb4c915 1320
ca10f295 1321=head1 COPYRIGHT
16dc9970 1322
ca10f295 1323This program is free software; you can redistribute it and/or modify
1324it under the terms of the GNU General Public License as published by
1325the Free Software Foundation; version 2.
dfb4c915 1326
ca10f295 1327This program is distributed in the hope that it will be useful, but
1328WITHOUT ANY WARRANTY; without even the implied warranty of
1329MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1330General Public License for more details.
16dc9970 1331
ca10f295 1332You should have received a copy of the GNU General Public License
1333along with this program; if not, write to the Free Software
1334Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
1335USA
16dc9970 1336
87bf8a3a 1337=head1 BUGS
1338
841a3f1a 1339Please use L<http://rt.cpan.org/> for reporting bugs.
1340
1341=head1 PRAISE
1342
1343If you find this module useful, please use
1344L<http://cpanratings.perl.org/rate/?distribution=SQL-Translator> to rate it.
87bf8a3a 1345
16dc9970 1346=head1 SEE ALSO
1347
abfa405a 1348L<perl>,
1349L<SQL::Translator::Parser>,
1350L<SQL::Translator::Producer>,
389b318c 1351L<Parse::RecDescent>,
1352L<GD>,
1353L<GraphViz>,
1354L<Text::RecordParser>,
841a3f1a 1355L<Class::DBI>,
389b318c 1356L<XML::Writer>.