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