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