Added support for proper enums under pg (as of 8.3), with pg version check, and defer...
[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;
539 eval { $wantarray ? @producer_output = $producer->($self) :
540 $producer_output = $producer->($self) };
541 if ($@ || !( $producer_output || @producer_output)) {
a5d57a52 542 my $err = $@ || $self->error || "no results";
543 my $msg = "translate: Error with producer '$producer_type': $err";
c2d3a526 544 return $self->error($msg);
7a8e1f51 545 }
546
5e2c196a 547 return wantarray ? @producer_output : $producer_output;
16dc9970 548}
ca10f295 549
d529894e 550# ----------------------------------------------------------------------
0f3778d0 551# list_parsers()
552#
553# Hacky sort of method to list all available parsers. This has
554# several problems:
555#
556# - Only finds things in the SQL::Translator::Parser namespace
557#
558# - Only finds things that are located in the same directory
559# as SQL::Translator::Parser. Yeck.
560#
561# This method will fail in several very likely cases:
562#
563# - Parser modules in different namespaces
564#
565# - Parser modules in the SQL::Translator::Parser namespace that
566# have any XS componenets will be installed in
567# arch_lib/SQL/Translator.
568#
569# ----------------------------------------------------------------------
570sub list_parsers {
ca1f2237 571 return shift->_list("parser");
0f3778d0 572}
573
574# ----------------------------------------------------------------------
575# list_producers()
576#
577# See notes for list_parsers(), above; all the problems apply to
578# list_producers as well.
579# ----------------------------------------------------------------------
c0c4aef9 580sub list_producers {
ca1f2237 581 return shift->_list("producer");
0f3778d0 582}
583
c0c4aef9 584
0f3778d0 585# ======================================================================
586# Private Methods
587# ======================================================================
c0c4aef9 588
0f3778d0 589# ----------------------------------------------------------------------
590# _args($type, \%args);
591#
592# Gets or sets ${type}_args. Called by parser_args and producer_args.
593# ----------------------------------------------------------------------
594sub _args {
595 my $self = shift;
596 my $type = shift;
597 $type = "${type}_args" unless $type =~ /_args$/;
598
599 unless (defined $self->{$type} && isa($self->{$type}, 'HASH')) {
600 $self->{$type} = { };
601 }
602
603 if (@_) {
604 # If the first argument is an explicit undef (remember, we
605 # don't get here unless there is stuff in @_), then we clear
606 # out the producer_args hash.
607 if (! defined $_[0]) {
608 shift @_;
609 %{$self->{$type}} = ();
610 }
611
612 my $args = isa($_[0], 'HASH') ? shift : { @_ };
613 %{$self->{$type}} = (%{$self->{$type}}, %$args);
614 }
615
616 $self->{$type};
c0c4aef9 617}
618
d529894e 619# ----------------------------------------------------------------------
f4a59b6c 620# Does the get/set work for parser and producer. e.g.
621# return $self->_tool({
622# name => 'producer',
623# path => "SQL::Translator::Producer",
624# default_sub => "produce",
625# }, @_);
626# ----------------------------------------------------------------------
627sub _tool {
628 my ($self,$args) = (shift, shift);
629 my $name = $args->{name};
da3a97b7 630 return $self->{$name} unless @_; # get accessor
631
632 my $path = $args->{path};
633 my $default_sub = $args->{default_sub};
f4a59b6c 634 my $tool = shift;
da3a97b7 635
f4a59b6c 636 # passed an anonymous subroutine reference
637 if (isa($tool, 'CODE')) {
638 $self->{$name} = $tool;
639 $self->{"$name\_type"} = "CODE";
640 $self->debug("Got $name: code ref\n");
da3a97b7 641 }
f4a59b6c 642
da3a97b7 643 # Module name was passed directly
644 # We try to load the name; if it doesn't load, there's a
645 # possibility that it has a function name attached to it,
646 # so we give it a go.
f4a59b6c 647 else {
f4a59b6c 648 $tool =~ s/-/::/g if $tool !~ /::/;
da3a97b7 649 my ($code,$sub);
650 ($code,$sub) = _load_sub("$tool\::$default_sub", $path);
9c0bc5a5 651 unless ($code) {
652 if ( __PACKAGE__->error =~ m/Can't find module/ ) {
653 # Mod not found so try sub
654 ($code,$sub) = _load_sub("$tool", $path) unless $code;
655 die "Can't load $name subroutine '$tool' : ".__PACKAGE__->error
656 unless $code;
657 }
658 else {
659 die "Can't load $name '$tool' : ".__PACKAGE__->error;
660 }
661 }
185c34d5 662
f4a59b6c 663 # get code reference and assign
da3a97b7 664 my (undef,$module,undef) = $sub =~ m/((.*)::)?(\w+)$/;
665 $self->{$name} = $code;
666 $self->{"$name\_type"} = $sub eq "CODE" ? "CODE" : $module;
667 $self->debug("Got $name: $sub\n");
668 }
f4a59b6c 669
670 # At this point, $self->{$name} contains a subroutine
671 # reference that is ready to run
672
673 # Anything left? If so, it's args
674 my $meth = "$name\_args";
675 $self->$meth(@_) if (@_);
676
677 return $self->{$name};
678}
679
680# ----------------------------------------------------------------------
0f3778d0 681# _list($type)
682# ----------------------------------------------------------------------
683sub _list {
3015bf96 684 my $self = shift;
685 my $type = shift || return ();
ca1f2237 686 my $uctype = ucfirst lc $type;
ca1f2237 687
3015bf96 688 #
689 # First find all the directories where SQL::Translator
690 # parsers or producers (the "type") appear to live.
691 #
ca1f2237 692 load("SQL::Translator::$uctype") or return ();
693 my $path = catfile "SQL", "Translator", $uctype;
3015bf96 694 my @dirs;
ca1f2237 695 for (@INC) {
696 my $dir = catfile $_, $path;
4b6a6341 697 $self->debug("_list_${type}s searching $dir\n");
ca1f2237 698 next unless -d $dir;
3015bf96 699 push @dirs, $dir;
ca1f2237 700 }
c0c4aef9 701
3015bf96 702 #
703 # Now use File::File::find to look recursively in those
704 # directories for all the *.pm files, then present them
705 # with the slashes turned into dashes.
706 #
707 my %found;
708 find(
709 sub {
710 if ( -f && m/\.pm$/ ) {
711 my $mod = $_;
712 $mod =~ s/\.pm$//;
713 my $cur_dir = $File::Find::dir;
04db8601 714 my $base_dir = quotemeta catfile 'SQL', 'Translator', $uctype;
3015bf96 715
716 #
717 # See if the current directory is below the base directory.
718 #
719 if ( $cur_dir =~ m/$base_dir(.*)/ ) {
720 $cur_dir = $1;
721 $cur_dir =~ s!^/!!; # kill leading slash
722 $cur_dir =~ s!/!-!g; # turn other slashes into dashes
723 }
724 else {
725 $cur_dir = '';
726 }
727
728 $found{ join '-', map { $_ || () } $cur_dir, $mod } = 1;
729 }
730 },
731 @dirs
732 );
733
734 return sort { lc $a cmp lc $b } keys %found;
c0c4aef9 735}
736
d529894e 737# ----------------------------------------------------------------------
f4a59b6c 738# load(MODULE [,PATH[,PATH]...])
0f3778d0 739#
740# Loads a Perl module. Short circuits if a module is already loaded.
f4a59b6c 741#
742# MODULE - is the name of the module to load.
743#
744# PATH - optional list of 'package paths' to look for the module in. e.g
017580f4 745# If you called load('Super::Foo' => 'My', 'Other') it will
746# try to load the mod Super::Foo then My::Super::Foo then Other::Super::Foo.
f4a59b6c 747#
748# Returns package name of the module actually loaded or false and sets error.
749#
185c34d5 750# Note, you can't load a name from the root namespace (ie one without '::' in
f4a59b6c 751# it), therefore a single word name without a path fails.
0f3778d0 752# ----------------------------------------------------------------------
ca10f295 753sub load {
f4a59b6c 754 my $name = shift;
755 my @path;
756 push @path, "" if $name =~ /::/; # Empty path to check name on its own first
757 push @path, @_ if @_;
758
759 foreach (@path) {
760 my $module = $_ ? "$_\::$name" : $name;
761 my $file = $module; $file =~ s[::][/]g; $file .= ".pm";
762 __PACKAGE__->debug("Loading $name as $file\n");
763 return $module if $INC{$file}; # Already loaded
185c34d5 764
f4a59b6c 765 eval { require $file };
766 next if $@ =~ /Can't locate $file in \@INC/;
617f79f6 767 eval { $module->import() } unless $@;
017580f4 768 return __PACKAGE__->error("Error loading $name as $module : $@")
769 if $@ && $@ !~ /"SQL::Translator::Producer" is not exported/;
f4a59b6c 770
771 return $module; # Module loaded ok
772 }
ca1f2237 773
9c0bc5a5 774 return __PACKAGE__->error("Can't find module $name. Path:".join(",",@path));
da3a97b7 775}
776
777# ----------------------------------------------------------------------
778# Load the sub name given (including package), optionally using a base package
779# path. Returns code ref and name of sub loaded, including its package.
780# (\&code, $sub) = load_sub( 'MySQL::produce', "SQL::Translator::Producer" );
781# (\&code, $sub) = load_sub( 'MySQL::produce', @path );
782# ----------------------------------------------------------------------
783sub _load_sub {
784 my ($tool, @path) = @_;
185c34d5 785
da3a97b7 786 my (undef,$module,$func_name) = $tool =~ m/((.*)::)?(\w+)$/;
787 if ( my $module = load($module => @path) ) {
788 my $sub = "$module\::$func_name";
185c34d5 789 return wantarray ? ( \&{ $sub }, $sub ) : \&$sub;
790 }
da3a97b7 791 return undef;
1fd8c91f 792}
16dc9970 793
67e5ff53 794# ----------------------------------------------------------------------
7d5bcab8 795sub format_table_name {
1ea530d4 796 return shift->_format_name('_format_table_name', @_);
7d5bcab8 797}
798
67e5ff53 799# ----------------------------------------------------------------------
7d5bcab8 800sub format_package_name {
1ea530d4 801 return shift->_format_name('_format_package_name', @_);
7d5bcab8 802}
803
67e5ff53 804# ----------------------------------------------------------------------
7d5bcab8 805sub format_fk_name {
1ea530d4 806 return shift->_format_name('_format_fk_name', @_);
7d5bcab8 807}
808
67e5ff53 809# ----------------------------------------------------------------------
7d5bcab8 810sub format_pk_name {
1ea530d4 811 return shift->_format_name('_format_pk_name', @_);
812}
813
814# ----------------------------------------------------------------------
185c34d5 815# The other format_*_name methods rely on this one. It optionally
1ea530d4 816# accepts a subroutine ref as the first argument (or uses an identity
817# sub if one isn't provided or it doesn't already exist), and applies
818# it to the rest of the arguments (if any).
819# ----------------------------------------------------------------------
820sub _format_name {
f9a0c3b5 821 my $self = shift;
1ea530d4 822 my $field = shift;
823 my @args = @_;
8a990c91 824
1ea530d4 825 if (ref($args[0]) eq 'CODE') {
826 $self->{$field} = shift @args;
8a990c91 827 }
1ea530d4 828 elsif (! exists $self->{$field}) {
829 $self->{$field} = sub { return shift };
8a990c91 830 }
831
1ea530d4 832 return @args ? $self->{$field}->(@args) : $self->{$field};
7d5bcab8 833}
834
d529894e 835# ----------------------------------------------------------------------
0f3778d0 836# isa($ref, $type)
837#
838# Calls UNIVERSAL::isa($ref, $type). I think UNIVERSAL::isa is ugly,
839# but I like function overhead.
840# ----------------------------------------------------------------------
841sub isa($$) {
842 my ($ref, $type) = @_;
843 return UNIVERSAL::isa($ref, $type);
844}
c2d3a526 845
3f4af30d 846# ----------------------------------------------------------------------
c314ec98 847# version
848#
849# Returns the $VERSION of the main SQL::Translator package.
850# ----------------------------------------------------------------------
851sub version {
852 my $self = shift;
853 return $VERSION;
854}
855
856# ----------------------------------------------------------------------
3f4af30d 857sub validate {
3f4af30d 858 my ( $self, $arg ) = @_;
859 if ( defined $arg ) {
860 $self->{'validate'} = $arg ? 1 : 0;
861 }
862 return $self->{'validate'} || 0;
863}
864
16dc9970 8651;
16dc9970 866
389b318c 867# ----------------------------------------------------------------------
868# Who killed the pork chops?
869# What price bananas?
870# Are you my Angel?
871# Allen Ginsberg
872# ----------------------------------------------------------------------
873
874=pod
0f3778d0 875
876=head1 NAME
877
954f31f1 878SQL::Translator - manipulate structured data definitions (SQL and more)
0f3778d0 879
880=head1 SYNOPSIS
881
882 use SQL::Translator;
883
67e5ff53 884 my $translator = SQL::Translator->new(
885 # Print debug info
886 debug => 1,
887 # Print Parse::RecDescent trace
185c34d5 888 trace => 0,
67e5ff53 889 # Don't include comments in output
185c34d5 890 no_comments => 0,
67e5ff53 891 # Print name mutations, conflicts
185c34d5 892 show_warnings => 0,
67e5ff53 893 # Add "drop table" statements
185c34d5 894 add_drop_table => 1,
5e2c196a 895 # to quote or not to quote, thats the question
896 quote_table_names => 1,
897 quote_field_names => 1,
67e5ff53 898 # Validate schema object
185c34d5 899 validate => 1,
f9a0c3b5 900 # Make all table names CAPS in producers which support this option
67e5ff53 901 format_table_name => sub {my $tablename = shift; return uc($tablename)},
f9a0c3b5 902 # Null-op formatting, only here for documentation's sake
7d5bcab8 903 format_package_name => sub {return shift},
904 format_fk_name => sub {return shift},
905 format_pk_name => sub {return shift},
0f3778d0 906 );
907
908 my $output = $translator->translate(
389b318c 909 from => 'MySQL',
910 to => 'Oracle',
f9a0c3b5 911 # Or an arrayref of filenames, i.e. [ $file1, $file2, $file3 ]
185c34d5 912 filename => $file,
0f3778d0 913 ) or die $translator->error;
914
915 print $output;
916
917=head1 DESCRIPTION
918
2d993495 919This documentation covers the API for SQL::Translator. For a more general
920discussion of how to use the modules and scripts, please see
921L<SQL::Translator::Manual>.
922
29efc9fd 923SQL::Translator is a group of Perl modules that converts
924vendor-specific SQL table definitions into other formats, such as
925other vendor-specific SQL, ER diagrams, documentation (POD and HTML),
926XML, and Class::DBI classes. The main focus of SQL::Translator is
927SQL, but parsers exist for other structured data formats, including
928Excel spreadsheets and arbitrarily delimited text files. Through the
929separation of the code into parsers and producers with an object model
930in between, it's possible to combine any parser with any producer, to
931plug in custom parsers or producers, or to manipulate the parsed data
932via the built-in object model. Presently only the definition parts of
933SQL are handled (CREATE, ALTER), not the manipulation of data (INSERT,
934UPDATE, DELETE).
0f3778d0 935
936=head1 CONSTRUCTOR
937
5760246d 938The constructor is called C<new>, and accepts a optional hash of options.
0f3778d0 939Valid options are:
940
941=over 4
942
ca251f03 943=item *
944
945parser / from
946
947=item *
948
949parser_args
0f3778d0 950
ca251f03 951=item *
0f3778d0 952
ca251f03 953producer / to
0f3778d0 954
ca251f03 955=item *
0f3778d0 956
ca251f03 957producer_args
0f3778d0 958
ca251f03 959=item *
960
185c34d5 961filters
962
963=item *
964
ca251f03 965filename / file
966
967=item *
968
969data
970
971=item *
0f3778d0 972
ca251f03 973debug
0f3778d0 974
389b318c 975=item *
976
977add_drop_table
978
979=item *
980
5e2c196a 981quote_table_names
982
983=item *
984
985quote_field_names
986
987=item *
988
389b318c 989no_comments
990
991=item *
992
993trace
994
995=item *
996
997validate
998
0f3778d0 999=back
1000
1001All options are, well, optional; these attributes can be set via
1002instance methods. Internally, they are; no (non-syntactical)
1003advantage is gained by passing options to the constructor.
1004
1005=head1 METHODS
1006
5760246d 1007=head2 add_drop_table
0f3778d0 1008
1009Toggles whether or not to add "DROP TABLE" statements just before the
1010create definitions.
1011
5e2c196a 1012=head2 quote_table_names
1013
1014Toggles whether or not to quote table names with " in DROP and CREATE
1015statements. The default (true) is to quote them.
1016
1017=head2 quote_field_names
1018
1019Toggles whether or not to quote field names with " in most
1020statements. The default (true), is to quote them.
1021
5760246d 1022=head2 no_comments
0f3778d0 1023
1024Toggles whether to print comments in the output. Accepts a true or false
1025value, returns the current value.
1026
5760246d 1027=head2 producer
0f3778d0 1028
5760246d 1029The C<producer> method is an accessor/mutator, used to retrieve or
0f3778d0 1030define what subroutine is called to produce the output. A subroutine
1031defined as a producer will be invoked as a function (I<not a method>)
8e1fc861 1032and passed its container C<SQL::Translator> instance, which it should
1033call the C<schema> method on, to get the C<SQL::Translator::Schema>
1034generated by the parser. It is expected that the function transform the
1035schema structure to a string. The C<SQL::Translator> instance is also useful
1036for informational purposes; for example, the type of the parser can be
5760246d 1037retrieved using the C<parser_type> method, and the C<error> and
1038C<debug> methods can be called when needed.
0f3778d0 1039
ca251f03 1040When defining a producer, one of several things can be passed in: A
5760246d 1041module name (e.g., C<My::Groovy::Producer>), a module name relative to
1042the C<SQL::Translator::Producer> namespace (e.g., C<MySQL>), a module
ca251f03 1043name and function combination (C<My::Groovy::Producer::transmogrify>),
0f3778d0 1044or a reference to an anonymous subroutine. If a full module name is
1045passed in (for the purposes of this method, a string containing "::"
1046is considered to be a module name), it is treated as a package, and a
ca251f03 1047function called "produce" will be invoked: C<$modulename::produce>.
1048If $modulename cannot be loaded, the final portion is stripped off and
0f3778d0 1049treated as a function. In other words, if there is no file named
ca251f03 1050F<My/Groovy/Producer/transmogrify.pm>, C<SQL::Translator> will attempt
5760246d 1051to load F<My/Groovy/Producer.pm> and use C<transmogrify> as the name of
1052the function, instead of the default C<produce>.
0f3778d0 1053
1054 my $tr = SQL::Translator->new;
1055
1056 # This will invoke My::Groovy::Producer::produce($tr, $data)
1057 $tr->producer("My::Groovy::Producer");
1058
1059 # This will invoke SQL::Translator::Producer::Sybase::produce($tr, $data)
1060 $tr->producer("Sybase");
1061
1062 # This will invoke My::Groovy::Producer::transmogrify($tr, $data),
1063 # assuming that My::Groovy::Producer::transmogrify is not a module
1064 # on disk.
1065 $tr->producer("My::Groovy::Producer::transmogrify");
1066
1067 # This will invoke the referenced subroutine directly, as
1068 # $subref->($tr, $data);
1069 $tr->producer(\&my_producer);
1070
5760246d 1071There is also a method named C<producer_type>, which is a string
1072containing the classname to which the above C<produce> function
0f3778d0 1073belongs. In the case of anonymous subroutines, this method returns
1074the string "CODE".
1075
5760246d 1076Finally, there is a method named C<producer_args>, which is both an
0f3778d0 1077accessor and a mutator. Arbitrary data may be stored in name => value
1078pairs for the producer subroutine to access:
1079
1080 sub My::Random::producer {
1081 my ($tr, $data) = @_;
1082 my $pr_args = $tr->producer_args();
1083
1084 # $pr_args is a hashref.
1085
5760246d 1086Extra data passed to the C<producer> method is passed to
1087C<producer_args>:
0f3778d0 1088
1089 $tr->producer("xSV", delimiter => ',\s*');
1090
1091 # In SQL::Translator::Producer::xSV:
1092 my $args = $tr->producer_args;
1093 my $delimiter = $args->{'delimiter'}; # value is ,\s*
1094
5760246d 1095=head2 parser
0f3778d0 1096
5760246d 1097The C<parser> method defines or retrieves a subroutine that will be
0f3778d0 1098called to perform the parsing. The basic idea is the same as that of
5760246d 1099C<producer> (see above), except the default subroutine name is
ca251f03 1100"parse", and will be invoked as C<$module_name::parse($tr, $data)>.
0f3778d0 1101Also, the parser subroutine will be passed a string containing the
1102entirety of the data to be parsed.
1103
1104 # Invokes SQL::Translator::Parser::MySQL::parse()
1105 $tr->parser("MySQL");
1106
1107 # Invokes My::Groovy::Parser::parse()
1108 $tr->parser("My::Groovy::Parser");
1109
1110 # Invoke an anonymous subroutine directly
1111 $tr->parser(sub {
1112 my $dumper = Data::Dumper->new([ $_[1] ], [ "SQL" ]);
1113 $dumper->Purity(1)->Terse(1)->Deepcopy(1);
1114 return $dumper->Dump;
1115 });
1116
5760246d 1117There is also C<parser_type> and C<parser_args>, which perform
1118analogously to C<producer_type> and C<producer_args>
0f3778d0 1119
185c34d5 1120=head2 filters
1121
1122Set or retreive the filters to run over the schema during the
1123translation, before the producer creates its output. Filters are sub
1124routines called, in order, with the schema object to filter as the 1st
44eb9098 1125arg and a hash of options (passed as a list) for the rest of the args.
1126They are free to do whatever they want to the schema object, which will be
1127handed to any following filters, then used by the producer.
185c34d5 1128
1129Filters are set as an array, which gives the order they run in.
1130Like parsers and producers, they can be defined by a module name, a
1131module name relative to the SQL::Translator::Filter namespace, a module
1132name and function name together or a reference to an anonymous subroutine.
1133When using a module name a function called C<filter> will be invoked in
44eb9098 1134that package to do the work.
1135
1136To pass args to the filter set it as an array ref with the 1st value giving
1137the filter (name or sub) and the rest its args. e.g.
185c34d5 1138
1139 $tr->filters(
1140 sub {
1141 my $schema = shift;
1142 # Do stuff to schema here!
1143 },
44eb9098 1144 DropFKeys,
1145 [ "Names", table => 'lc' ],
1146 [ "Foo", foo => "bar", hello => "world" ],
1147 [ "Filter5" ],
185c34d5 1148 );
1149
44eb9098 1150Although you normally set them in the constructor, which calls
185c34d5 1151through to filters. i.e.
1152
1153 my $translator = SQL::Translator->new(
1154 ...
1155 filters => [
1156 sub { ... },
44eb9098 1157 [ "Names", table => 'lc' ],
185c34d5 1158 ],
1159 ...
1160 );
1161
1162See F<t/36-filters.t> for more examples.
1163
1164Multiple set calls to filters are cumulative with new filters added to
1165the end of the current list.
1166
1167Returns the filters as a list of array refs, the 1st value being a
44eb9098 1168reference to the filter sub and the rest its args.
185c34d5 1169
5760246d 1170=head2 show_warnings
0f3778d0 1171
1172Toggles whether to print warnings of name conflicts, identifier
1173mutations, etc. Probably only generated by producers to let the user
1174know when something won't translate very smoothly (e.g., MySQL "enum"
1175fields into Oracle). Accepts a true or false value, returns the
1176current value.
1177
5760246d 1178=head2 translate
0f3778d0 1179
185c34d5 1180The C<translate> method calls the subroutine referenced by the
1181C<parser> data member, then calls any C<filters> and finally calls
1182the C<producer> sub routine (these members are described above).
1183It accepts as arguments a number of things, in key => value format,
1184including (potentially) a parser and a producer (they are passed
1185directly to the C<parser> and C<producer> methods).
0f3778d0 1186
5760246d 1187Here is how the parameter list to C<translate> is parsed:
0f3778d0 1188
1189=over
1190
1191=item *
1192
11931 argument means it's the data to be parsed; which could be a string
ca251f03 1194(filename) or a reference to a scalar (a string stored in memory), or a
0f3778d0 1195reference to a hash, which is parsed as being more than one argument
1196(see next section).
1197
1198 # Parse the file /path/to/datafile
1199 my $output = $tr->translate("/path/to/datafile");
1200
1201 # Parse the data contained in the string $data
1202 my $output = $tr->translate(\$data);
1203
1204=item *
1205
1206More than 1 argument means its a hash of things, and it might be
1207setting a parser, producer, or datasource (this key is named
1208"filename" or "file" if it's a file, or "data" for a SCALAR reference.
1209
1210 # As above, parse /path/to/datafile, but with different producers
1211 for my $prod ("MySQL", "XML", "Sybase") {
1212 print $tr->translate(
1213 producer => $prod,
1214 filename => "/path/to/datafile",
1215 );
1216 }
1217
1218 # The filename hash key could also be:
1219 datasource => \$data,
1220
1221You get the idea.
1222
1223=back
1224
5760246d 1225=head2 filename, data
0f3778d0 1226
5760246d 1227Using the C<filename> method, the filename of the data to be parsed
1228can be set. This method can be used in conjunction with the C<data>
1229method, below. If both the C<filename> and C<data> methods are
1230invoked as mutators, the data set in the C<data> method is used.
0f3778d0 1231
1232 $tr->filename("/my/data/files/create.sql");
1233
1234or:
1235
1236 my $create_script = do {
1237 local $/;
1238 open CREATE, "/my/data/files/create.sql" or die $!;
1239 <CREATE>;
1240 };
1241 $tr->data(\$create_script);
1242
5760246d 1243C<filename> takes a string, which is interpreted as a filename.
1244C<data> takes a reference to a string, which is used as the data to be
0f3778d0 1245parsed. If a filename is set, then that file is opened and read when
5760246d 1246the C<translate> method is called, as long as the data instance
0f3778d0 1247variable is not set.
1248
45ee6be0 1249=head2 schema
1250
1251Returns the SQL::Translator::Schema object.
1252
5760246d 1253=head2 trace
0f3778d0 1254
1255Turns on/off the tracing option of Parse::RecDescent.
1256
389b318c 1257=head2 validate
1258
1259Whether or not to validate the schema object after parsing and before
1260producing.
1261
c314ec98 1262=head2 version
1263
1264Returns the version of the SQL::Translator release.
1265
7a8e1f51 1266=head1 AUTHORS
16dc9970 1267
841a3f1a 1268The following people have contributed to the SQLFairy project:
1269
1270=over 4
1271
1272=item * Mark Addison <grommit@users.sourceforge.net>
1273
1274=item * Sam Angiuoli <angiuoli@users.sourceforge.net>
1275
5342f5c1 1276=item * Anders Nor Berle <berle@cpan.org>
1277
d09e5700 1278=item * Dave Cash <dave@gnofn.org>
1279
841a3f1a 1280=item * Darren Chamberlain <dlc@users.sourceforge.net>
1281
1282=item * Ken Y. Clark <kclark@cpan.org>
1283
1284=item * Allen Day <allenday@users.sourceforge.net>
1285
1286=item * Paul Harrington <phrrngtn@users.sourceforge.net>
1287
1288=item * Mikey Melillo <mmelillo@users.sourceforge.net>
1289
1290=item * Chris Mungall <cjm@fruitfly.org>
1291
1292=item * Ross Smith II <rossta@users.sf.net>
1293
1294=item * Gudmundur A. Thorisson <mummi@cshl.org>
1295
1296=item * Chris To <christot@users.sourceforge.net>
1297
1298=item * Jason Williams <smdwilliams@users.sourceforge.net>
1299
1300=item * Ying Zhang <zyolive@yahoo.com>
1301
1302=back
1303
1304If you would like to contribute to the project, you can send patches
1305to the developers mailing list:
1306
1307 sqlfairy-developers@lists.sourceforge.net
1308
1309Or send us a message (with your Sourceforge username) asking to be
1310added to the project and what you'd like to contribute.
1311
dfb4c915 1312
ca10f295 1313=head1 COPYRIGHT
16dc9970 1314
ca10f295 1315This program is free software; you can redistribute it and/or modify
1316it under the terms of the GNU General Public License as published by
1317the Free Software Foundation; version 2.
dfb4c915 1318
ca10f295 1319This program is distributed in the hope that it will be useful, but
1320WITHOUT ANY WARRANTY; without even the implied warranty of
1321MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1322General Public License for more details.
16dc9970 1323
ca10f295 1324You should have received a copy of the GNU General Public License
1325along with this program; if not, write to the Free Software
1326Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
1327USA
16dc9970 1328
87bf8a3a 1329=head1 BUGS
1330
841a3f1a 1331Please use L<http://rt.cpan.org/> for reporting bugs.
1332
1333=head1 PRAISE
1334
1335If you find this module useful, please use
1336L<http://cpanratings.perl.org/rate/?distribution=SQL-Translator> to rate it.
87bf8a3a 1337
16dc9970 1338=head1 SEE ALSO
1339
abfa405a 1340L<perl>,
1341L<SQL::Translator::Parser>,
1342L<SQL::Translator::Producer>,
389b318c 1343L<Parse::RecDescent>,
1344L<GD>,
1345L<GraphViz>,
1346L<Text::RecordParser>,
841a3f1a 1347L<Class::DBI>,
389b318c 1348L<XML::Writer>.