use
vars
qw( $VERSION $DEFAULT_SUB $DEBUG $ERROR )
;
require
5.005;
$VERSION
=
'0.09005_05'
;
$DEBUG
= 0
unless
defined
$DEBUG
;
$ERROR
=
""
;
$DEFAULT_SUB
=
sub
{
$_
[0]->schema }
unless
defined
$DEFAULT_SUB
;
sub
init {
my
(
$self
,
$config
) =
@_
;
$self
->parser (
$config
->{
'parser'
} ||
$config
->{
'from'
} ||
$DEFAULT_SUB
);
$self
->producer(
$config
->{
'producer'
} ||
$config
->{
'to'
} ||
$DEFAULT_SUB
);
for
my
$pargs
(
qw[ parser_args producer_args ]
) {
$self
->
$pargs
(
$config
->{
$pargs
} )
if
defined
$config
->{
$pargs
};
}
if
(
$config
->{filters} &&
ref
$config
->{filters} eq
"ARRAY"
) {
$self
->filters( @{
$config
->{filters}} )
||
return
$self
->error(
'Error inititializing filters: '
.
$self
->error);
}
$config
->{
'filename'
} ||=
$config
->{
'file'
} ||
""
;
$self
->filename(
$config
->{
'filename'
} )
if
$config
->{
'filename'
};
if
(
my
$data
=
$config
->{
'data'
} ) {
$self
->data(
$data
);
}
$self
->{
'debug'
} =
defined
$config
->{
'debug'
} ?
$config
->{
'debug'
} :
$DEBUG
;
$self
->add_drop_table(
$config
->{
'add_drop_table'
} );
$self
->no_comments(
$config
->{
'no_comments'
} );
$self
->show_warnings(
$config
->{
'show_warnings'
} );
$self
->trace(
$config
->{
'trace'
} );
$self
->validate(
$config
->{
'validate'
} );
$self
->quote_table_names( (
defined
$config
->{
'quote_table_names'
}
?
$config
->{
'quote_table_names'
} : 1) );
$self
->quote_field_names( (
defined
$config
->{
'quote_field_names'
}
?
$config
->{
'quote_field_names'
} : 1) );
return
$self
;
}
sub
add_drop_table {
my
$self
=
shift
;
if
(
defined
(
my
$arg
=
shift
) ) {
$self
->{
'add_drop_table'
} =
$arg
? 1 : 0;
}
return
$self
->{
'add_drop_table'
} || 0;
}
sub
no_comments {
my
$self
=
shift
;
my
$arg
=
shift
;
if
(
defined
$arg
) {
$self
->{
'no_comments'
} =
$arg
? 1 : 0;
}
return
$self
->{
'no_comments'
} || 0;
}
sub
quote_table_names {
my
$self
=
shift
;
if
(
defined
(
my
$arg
=
shift
) ) {
$self
->{
'quote_table_names'
} =
$arg
? 1 : 0;
}
return
$self
->{
'quote_table_names'
} || 0;
}
sub
quote_field_names {
my
$self
=
shift
;
if
(
defined
(
my
$arg
=
shift
) ) {
$self
->{
'quote_field_names'
} =
$arg
? 1 : 0;
}
return
$self
->{
'quote_field_names'
} || 0;
}
sub
producer {
shift
->_tool({
name
=>
'producer'
,
path
=>
"SQL::Translator::Producer"
,
default_sub
=>
"produce"
,
},
@_
);
}
sub
producer_type {
$_
[0]->{
'producer_type'
} }
sub
producer_args {
shift
->_args(
"producer"
,
@_
); }
sub
parser {
shift
->_tool({
name
=>
'parser'
,
path
=>
"SQL::Translator::Parser"
,
default_sub
=>
"parse"
,
},
@_
);
}
sub
parser_type {
$_
[0]->{
'parser_type'
}; }
sub
parser_args {
shift
->_args(
"parser"
,
@_
); }
sub
filters {
my
$self
=
shift
;
my
$filters
=
$self
->{filters} ||= [];
return
@$filters
unless
@_
;
foreach
(
@_
) {
my
(
$filt
,
@args
) =
ref
(
$_
) eq
"ARRAY"
?
@$_
:
$_
;
if
( isa(
$filt
,
"CODE"
) ) {
push
@$filters
, [
$filt
,
@args
];
next
;
}
else
{
$self
->debug(
"Adding $filt filter. Args:"
.Dumper(\
@args
).
"\n"
);
$filt
= _load_sub(
"$filt\::filter"
,
"SQL::Translator::Filter"
)
||
return
$self
->error(__PACKAGE__->error);
push
@$filters
, [
$filt
,
@args
];
}
}
return
@$filters
;
}
sub
show_warnings {
my
$self
=
shift
;
my
$arg
=
shift
;
if
(
defined
$arg
) {
$self
->{
'show_warnings'
} =
$arg
? 1 : 0;
}
return
$self
->{
'show_warnings'
} || 0;
}
sub
filename {
my
$self
=
shift
;
if
(
@_
) {
my
$filename
=
shift
;
if
(-d
$filename
) {
my
$msg
=
"Cannot use directory '$filename' as input source"
;
return
$self
->error(
$msg
);
}
elsif
(
ref
(
$filename
) eq
'ARRAY'
) {
$self
->{
'filename'
} =
$filename
;
$self
->debug(
"Got array of files: "
.
join
(
', '
,
@$filename
).
"\n"
);
}
elsif
(-f _ && -r _) {
$self
->{
'filename'
} =
$filename
;
$self
->debug(
"Got filename: '$self->{'filename'}'\n"
);
}
else
{
my
$msg
=
"Cannot use '$filename' as input source: "
.
"file does not exist or is not readable."
;
return
$self
->error(
$msg
);
}
}
$self
->{
'filename'
};
}
sub
data {
my
$self
=
shift
;
if
(
@_
) {
my
$data
=
shift
;
if
(isa(
$data
,
"SCALAR"
)) {
$self
->{
'data'
} =
$data
;
}
else
{
if
(isa(
$data
,
'ARRAY'
)) {
$data
=
join
''
,
@$data
;
}
elsif
(isa(
$data
,
'GLOB'
)) {
seek
(
$data
, 0, 0)
if
eof
(
$data
);
local
$/;
$data
= <
$data
>;
}
elsif
(!
ref
$data
&&
@_
) {
$data
=
join
''
,
$data
,
@_
;
}
$self
->{
'data'
} = \
$data
;
}
}
if
(not
$self
->{
'data'
} and
my
$filename
=
$self
->filename) {
$self
->debug(
"Opening '$filename' to get contents.\n"
);
local
*FH
;
local
$/;
my
$data
;
my
@files
=
ref
(
$filename
) eq
'ARRAY'
?
@$filename
: (
$filename
);
foreach
my
$file
(
@files
) {
unless
(
open
FH,
$file
) {
return
$self
->error(
"Can't read file '$file': $!"
);
}
$data
.= <FH>;
unless
(
close
FH) {
return
$self
->error(
"Can't close file '$file': $!"
);
}
}
$self
->{
'data'
} = \
$data
;
}
return
$self
->{
'data'
};
}
sub
reset
{
my
$self
=
shift
;
$self
->{
'schema'
} =
undef
;
return
1;
}
sub
schema {
my
$self
=
shift
;
unless
(
defined
$self
->{
'schema'
} ) {
$self
->{
'schema'
} = SQL::Translator::Schema->new(
translator
=>
$self
,
);
}
return
$self
->{
'schema'
};
}
sub
trace {
my
$self
=
shift
;
my
$arg
=
shift
;
if
(
defined
$arg
) {
$self
->{
'trace'
} =
$arg
? 1 : 0;
}
return
$self
->{
'trace'
} || 0;
}
sub
translate {
my
$self
=
shift
;
my
(
$args
,
$parser
,
$parser_type
,
$producer
,
$producer_type
);
my
(
$parser_output
,
$producer_output
,
@producer_output
);
if
(
@_
== 1) {
if
(isa(
$_
[0],
'HASH'
)) {
$self
->debug(
"translate: Got a hashref\n"
);
$args
=
$_
[0];
}
elsif
(isa(
$_
[0],
'GLOB'
)) {
$self
->debug(
"translate: Got a GLOB reference\n"
);
$self
->data(
$_
[0]);
}
elsif
(isa(
$_
[0],
'SCALAR'
)) {
$self
->debug(
"translate: Got a SCALAR reference (string)\n"
);
$self
->data(
$_
[0]);
}
elsif
(!
ref
$_
[0]) {
$self
->debug(
"translate: Got a filename\n"
);
$self
->filename(
$_
[0]);
}
else
{
return
""
unless
(
$self
->data &&
$self
->producer &&
$self
->parser);
}
}
else
{
return
""
if
@_
% 2;
$args
= {
@_
};
}
if
(
my
$filename
= (
$args
->{
'filename'
} ||
$args
->{
'file'
})) {
$self
->filename(
$filename
);
}
if
(
my
$data
= (
$args
->{
'data'
} ||
$args
->{
'datasource'
})) {
$self
->data(
$data
);
}
my
$data
=
$self
->data;
if
(
$parser
= (
$args
->{
'parser'
} ||
$args
->{
'from'
})) {
$self
->parser(
$parser
);
}
$parser
=
$self
->parser;
$parser_type
=
$self
->parser_type;
if
(
$producer
= (
$args
->{
'producer'
} ||
$args
->{
'to'
})) {
$self
->producer(
$producer
);
}
$producer
=
$self
->producer;
$producer_type
=
$self
->producer_type;
unless
(
defined
$self
->{
'schema'
} ) {
eval
{
$parser_output
=
$parser
->(
$self
,
$$data
) };
if
($@ || !
$parser_output
) {
my
$msg
=
sprintf
"translate: Error with parser '%s': %s"
,
$parser_type
, ($@) ? $@ :
" no results"
;
return
$self
->error(
$msg
);
}
}
$self
->debug(
"Schema =\n"
, Dumper(
$self
->schema),
"\n"
);
if
(
$self
->validate) {
my
$schema
=
$self
->schema;
return
$self
->error(
'Invalid schema'
)
unless
$schema
->is_valid;
}
my
$filt_num
= 0;
foreach
(
$self
->filters) {
$filt_num
++;
my
(
$code
,
@args
) =
@$_
;
eval
{
$code
->(
$self
->schema,
@args
) };
my
$err
= $@ ||
$self
->error || 0;
return
$self
->error(
"Error with filter $filt_num : $err"
)
if
$err
;
}
my
$wantarray
=
wantarray
? 1 : 0;
eval
{
if
(
$wantarray
) {
@producer_output
=
$producer
->(
$self
);
}
else
{
$producer_output
=
$producer
->(
$self
);
}
};
if
($@ || !(
$producer_output
||
@producer_output
)) {
my
$err
= $@ ||
$self
->error ||
"no results"
;
my
$msg
=
"translate: Error with producer '$producer_type': $err"
;
return
$self
->error(
$msg
);
}
return
wantarray
?
@producer_output
:
$producer_output
;
}
sub
list_parsers {
return
shift
->_list(
"parser"
);
}
sub
list_producers {
return
shift
->_list(
"producer"
);
}
sub
_args {
my
$self
=
shift
;
my
$type
=
shift
;
$type
=
"${type}_args"
unless
$type
=~ /_args$/;
unless
(
defined
$self
->{
$type
} && isa(
$self
->{
$type
},
'HASH'
)) {
$self
->{
$type
} = { };
}
if
(
@_
) {
if
(!
defined
$_
[0]) {
shift
@_
;
%{
$self
->{
$type
}} = ();
}
my
$args
= isa(
$_
[0],
'HASH'
) ?
shift
: {
@_
};
%{
$self
->{
$type
}} = (%{
$self
->{
$type
}},
%$args
);
}
$self
->{
$type
};
}
sub
_tool {
my
(
$self
,
$args
) = (
shift
,
shift
);
my
$name
=
$args
->{name};
return
$self
->{
$name
}
unless
@_
;
my
$path
=
$args
->{path};
my
$default_sub
=
$args
->{default_sub};
my
$tool
=
shift
;
if
(isa(
$tool
,
'CODE'
)) {
$self
->{
$name
} =
$tool
;
$self
->{
"$name\_type"
} =
"CODE"
;
$self
->debug(
"Got $name: code ref\n"
);
}
else
{
$tool
=~ s/-/::/g
if
$tool
!~ /::/;
my
(
$code
,
$sub
);
(
$code
,
$sub
) = _load_sub(
"$tool\::$default_sub"
,
$path
);
unless
(
$code
) {
if
( __PACKAGE__->error =~ m/Can't find module/ ) {
(
$code
,
$sub
) = _load_sub(
"$tool"
,
$path
)
unless
$code
;
die
"Can't load $name subroutine '$tool' : "
.__PACKAGE__->error
unless
$code
;
}
else
{
die
"Can't load $name '$tool' : "
.__PACKAGE__->error;
}
}
my
(
undef
,
$module
,
undef
) =
$sub
=~ m/((.*)::)?(\w+)$/;
$self
->{
$name
} =
$code
;
$self
->{
"$name\_type"
} =
$sub
eq
"CODE"
?
"CODE"
:
$module
;
$self
->debug(
"Got $name: $sub\n"
);
}
my
$meth
=
"$name\_args"
;
$self
->
$meth
(
@_
)
if
(
@_
);
return
$self
->{
$name
};
}
sub
_list {
my
$self
=
shift
;
my
$type
=
shift
||
return
();
my
$uctype
=
ucfirst
lc
$type
;
load(
"SQL::Translator::$uctype"
) or
return
();
my
$path
= catfile
"SQL"
,
"Translator"
,
$uctype
;
my
@dirs
;
for
(
@INC
) {
my
$dir
= catfile
$_
,
$path
;
$self
->debug(
"_list_${type}s searching $dir\n"
);
next
unless
-d
$dir
;
push
@dirs
,
$dir
;
}
my
%found
;
find(
sub
{
if
( -f && m/\.pm$/ ) {
my
$mod
=
$_
;
$mod
=~ s/\.pm$//;
my
$cur_dir
=
$File::Find::dir
;
my
$base_dir
=
quotemeta
catfile
'SQL'
,
'Translator'
,
$uctype
;
if
(
$cur_dir
=~ m/
$base_dir
(.*)/ ) {
$cur_dir
= $1;
$cur_dir
=~ s!^/!!;
$cur_dir
=~ s!/!-!g;
}
else
{
$cur_dir
=
''
;
}
$found
{
join
'-'
,
map
{
$_
|| () }
$cur_dir
,
$mod
} = 1;
}
},
@dirs
);
return
sort
{
lc
$a
cmp
lc
$b
}
keys
%found
;
}
sub
load {
my
$name
=
shift
;
my
@path
;
push
@path
,
""
if
$name
=~ /::/;
push
@path
,
@_
if
@_
;
foreach
(
@path
) {
my
$module
=
$_
?
"$_\::$name"
:
$name
;
my
$file
=
$module
;
$file
=~ s[::][/]g;
$file
.=
".pm"
;
__PACKAGE__->debug(
"Loading $name as $file\n"
);
return
$module
if
$INC
{
$file
};
eval
{
require
$file
};
next
if
$@ =~ /Can't locate
$file
in \
@INC
/;
eval
{
$module
->
import
() }
unless
$@;
return
__PACKAGE__->error(
"Error loading $name as $module : $@"
)
if
$@ && $@ !~ /
"SQL::Translator::Producer"
is not exported/;
return
$module
;
}
return
__PACKAGE__->error(
"Can't find module $name. Path:"
.
join
(
","
,
@path
));
}
sub
_load_sub {
my
(
$tool
,
@path
) =
@_
;
my
(
undef
,
$module
,
$func_name
) =
$tool
=~ m/((.*)::)?(\w+)$/;
if
(
my
$module
= load(
$module
=>
@path
) ) {
my
$sub
=
"$module\::$func_name"
;
return
wantarray
? ( \&{
$sub
},
$sub
) : \
&$sub
;
}
return
undef
;
}
sub
format_table_name {
return
shift
->_format_name(
'_format_table_name'
,
@_
);
}
sub
format_package_name {
return
shift
->_format_name(
'_format_package_name'
,
@_
);
}
sub
format_fk_name {
return
shift
->_format_name(
'_format_fk_name'
,
@_
);
}
sub
format_pk_name {
return
shift
->_format_name(
'_format_pk_name'
,
@_
);
}
sub
_format_name {
my
$self
=
shift
;
my
$field
=
shift
;
my
@args
=
@_
;
if
(
ref
(
$args
[0]) eq
'CODE'
) {
$self
->{
$field
} =
shift
@args
;
}
elsif
(!
exists
$self
->{
$field
}) {
$self
->{
$field
} =
sub
{
return
shift
};
}
return
@args
?
$self
->{
$field
}->(
@args
) :
$self
->{
$field
};
}
sub
isa($$) {
my
(
$ref
,
$type
) =
@_
;
return
UNIVERSAL::isa(
$ref
,
$type
);
}
sub
version {
my
$self
=
shift
;
return
$VERSION
;
}
sub
validate {
my
(
$self
,
$arg
) =
@_
;
if
(
defined
$arg
) {
$self
->{
'validate'
} =
$arg
? 1 : 0;
}
return
$self
->{
'validate'
} || 0;
}
1;
=pod
=head1 NAME
SQL::Translator - manipulate structured data definitions (SQL and more)
=head1 SYNOPSIS
my
$translator
= SQL::Translator->new(
debug
=> 1,
trace
=> 0,
no_comments
=> 0,
show_warnings
=> 0,
add_drop_table
=> 1,
quote_table_names
=> 1,
quote_field_names
=> 1,
validate
=> 1,
format_table_name
=>
sub
{
my
$tablename
=
shift
;
return
uc
(
$tablename
)},
format_package_name
=>
sub
{
return
shift
},
format_fk_name
=>
sub
{
return
shift
},
format_pk_name
=>
sub
{
return
shift
},
);
my
$output
=
$translator
->translate(
from
=>
'MySQL'
,
to
=>
'Oracle'
,
filename
=>
$file
,
) or
die
$translator
->error;
print
$output
;
=head1 DESCRIPTION
This documentation covers the API
for
SQL::Translator. For a more general
discussion of how to
use
the modules and scripts, please see
L<SQL::Translator::Manual>.
SQL::Translator is a group of Perl modules that converts
vendor-specific SQL table definitions into other formats, such as
other vendor-specific SQL, ER diagrams, documentation (POD and HTML),
XML, and Class::DBI classes. The main focus of SQL::Translator is
SQL, but parsers exist
for
other structured data formats, including
Excel spreadsheets and arbitrarily delimited text files. Through the
separation of the code into parsers and producers
with
an object model
in between, it's possible to combine any parser
with
any producer, to
plug in custom parsers or producers, or to manipulate the parsed data
via the built-in object model. Presently only the definition parts of
SQL are handled (CREATE, ALTER), not the manipulation of data (INSERT,
UPDATE, DELETE).
=head1 CONSTRUCTOR
The constructor is called C<new>, and accepts a optional hash of options.
Valid options are:
=over 4
=item *
parser / from
=item *
parser_args
=item *
producer / to
=item *
producer_args
=item *
filters
=item *
filename / file
=item *
data
=item *
debug
=item *
add_drop_table
=item *
quote_table_names
=item *
quote_field_names
=item *
no_comments
=item *
trace
=item *
validate
=back
All options are, well, optional; these attributes can be set via
instance methods. Internally, they are;
no
(non-syntactical)
advantage is gained by passing options to the constructor.
=head1 METHODS
=head2 add_drop_table
Toggles whether or not to add
"DROP TABLE"
statements just
before
the
create definitions.
=head2 quote_table_names
Toggles whether or not to quote table names
with
" in DROP and CREATE
statements. The
default
(true) is to quote them.
=head2 quote_field_names
Toggles whether or not to quote field names
with
" in most
statements. The
default
(true), is to quote them.
=head2 no_comments
Toggles whether to
print
comments in the output. Accepts a true or false
value, returns the current value.
=head2 producer
The C<producer> method is an accessor/mutator, used to retrieve or
define what subroutine is called to produce the output. A subroutine
defined
as a producer will be invoked as a function (I<not a method>)
and passed its container C<SQL::Translator> instance, which it should
call the C<schema> method on, to get the C<SQL::Translator::Schema>
generated by the parser. It is expected that the function transform the
schema structure to a string. The C<SQL::Translator> instance is also useful
for
informational purposes;
for
example, the type of the parser can be
retrieved using the C<parser_type> method, and the C<error> and
C<debug> methods can be called
when
needed.
When defining a producer, one of several things can be passed in: A
module name (e.g., C<My::Groovy::Producer>), a module name relative to
the C<SQL::Translator::Producer> namespace (e.g., C<MySQL>), a module
name and function combination (C<My::Groovy::Producer::transmogrify>),
or a reference to an anonymous subroutine. If a full module name is
passed in (
for
the purposes of this method, a string containing
"::"
is considered to be a module name), it is treated as a
package
, and a
function called
"produce"
will be invoked: C<
$modulename::produce
>.
If
$modulename
cannot be loaded, the final portion is stripped off and
treated as a function. In other words,
if
there is
no
file named
F<My/Groovy/Producer/transmogrify.pm>, C<SQL::Translator> will attempt
to load F<My/Groovy/Producer.pm> and
use
C<transmogrify> as the name of
the function, instead of the
default
C<produce>.
my
$tr
= SQL::Translator->new;
$tr
->producer(
"My::Groovy::Producer"
);
$tr
->producer(
"Sybase"
);
$tr
->producer(
"My::Groovy::Producer::transmogrify"
);
$tr
->producer(\
&my_producer
);
There is also a method named C<producer_type>, which is a string
containing the classname to which the above C<produce> function
belongs. In the case of anonymous subroutines, this method returns
the string
"CODE"
.
Finally, there is a method named C<producer_args>, which is both an
accessor and a mutator. Arbitrary data may be stored in
name
=> value
pairs
for
the producer subroutine to access:
sub
My::Random::producer {
my
(
$tr
,
$data
) =
@_
;
my
$pr_args
=
$tr
->producer_args();
Extra data passed to the C<producer> method is passed to
C<producer_args>:
$tr
->producer(
"xSV"
,
delimiter
=>
',\s*'
);
my
$args
=
$tr
->producer_args;
my
$delimiter
=
$args
->{
'delimiter'
};
=head2 parser
The C<parser> method defines or retrieves a subroutine that will be
called to perform the parsing. The basic idea is the same as that of
C<producer> (see above), except the
default
subroutine name is
"parse"
, and will be invoked as C<
$module_name::parse
(
$tr
,
$data
)>.
Also, the parser subroutine will be passed a string containing the
entirety of the data to be parsed.
$tr
->parser(
"MySQL"
);
$tr
->parser(
"My::Groovy::Parser"
);
$tr
->parser(
sub
{
my
$dumper
= Data::Dumper->new([
$_
[1] ], [
"SQL"
]);
$dumper
->Purity(1)->Terse(1)->Deepcopy(1);
return
$dumper
->Dump;
});
There is also C<parser_type> and C<parser_args>, which perform
analogously to C<producer_type> and C<producer_args>
=head2 filters
Set or retreive the filters to run over the schema during the
translation,
before
the producer creates its output. Filters are
sub
routines called, in order,
with
the schema object to filter as the 1st
arg and a hash of options (passed as a list)
for
the rest of the args.
They are free to
do
whatever they want to the schema object, which will be
handed to any following filters, then used by the producer.
Filters are set as an array, which gives the order they run in.
Like parsers and producers, they can be
defined
by a module name, a
module name relative to the SQL::Translator::Filter namespace, a module
name and function name together or a reference to an anonymous subroutine.
When using a module name a function called C<filter> will be invoked in
that
package
to
do
the work.
To pass args to the filter set it as an array
ref
with
the 1st value giving
the filter (name or
sub
) and the rest its args. e.g.
$tr
->filters(
sub
{
my
$schema
=
shift
;
},
DropFKeys,
[
"Names"
,
table
=>
'lc'
],
[
"Foo"
,
foo
=>
"bar"
,
hello
=>
"world"
],
[
"Filter5"
],
);
Although you normally set them in the constructor, which calls
through to filters. i.e.
my
$translator
= SQL::Translator->new(
...
filters
=> [
sub
{ ... },
[
"Names"
,
table
=>
'lc'
],
],
...
);
See F<t/36-filters.t>
for
more examples.
Multiple set calls to filters are cumulative
with
new filters added to
the end of the current list.
Returns the filters as a list of array refs, the 1st value being a
reference to the filter
sub
and the rest its args.
=head2 show_warnings
Toggles whether to
print
warnings of name conflicts, identifier
mutations, etc. Probably only generated by producers to let the user
know
when
something won't translate very smoothly (e.g., MySQL
"enum"
fields into Oracle). Accepts a true or false value, returns the
current value.
=head2 translate
The C<translate> method calls the subroutine referenced by the
C<parser> data member, then calls any C<filters> and
finally
calls
the C<producer>
sub
routine (these members are described above).
It accepts as arguments a number of things, in
key
=> value
format
,
including (potentially) a parser and a producer (they are passed
directly to the C<parser> and C<producer> methods).
Here is how the parameter list to C<translate> is parsed:
=over
=item *
1 argument means it's the data to be parsed; which could be a string
(filename) or a reference to a
scalar
(a string stored in memory), or a
reference to a hash, which is parsed as being more than one argument
(see
next
section).
my
$output
=
$tr
->translate(
"/path/to/datafile"
);
my
$output
=
$tr
->translate(\
$data
);
=item *
More than 1 argument means its a hash of things, and it might be
setting a parser, producer, or datasource (this key is named
"filename"
or
"file"
if
it's a file, or
"data"
for
a SCALAR reference.
for
my
$prod
(
"MySQL"
,
"XML"
,
"Sybase"
) {
print
$tr
->translate(
producer
=>
$prod
,
filename
=>
"/path/to/datafile"
,
);
}
datasource
=> \
$data
,
You get the idea.
=back
=head2 filename, data
Using the C<filename> method, the filename of the data to be parsed
can be set. This method can be used in conjunction
with
the C<data>
method, below. If both the C<filename> and C<data> methods are
invoked as mutators, the data set in the C<data> method is used.
$tr
->filename(
"/my/data/files/create.sql"
);
or:
my
$create_script
=
do
{
local
$/;
open
CREATE,
"/my/data/files/create.sql"
or
die
$!;
<CREATE>;
};
$tr
->data(\
$create_script
);
C<filename> takes a string, which is interpreted as a filename.
C<data> takes a reference to a string, which is used as the data to be
parsed. If a filename is set, then that file is opened and
read
when
the C<translate> method is called, as long as the data instance
variable is not set.
=head2 schema
Returns the SQL::Translator::Schema object.
=head2 trace
Turns on/off the tracing option of Parse::RecDescent.
=head2 validate
Whether or not to validate the schema object
after
parsing and
before
producing.
=head2 version
Returns the version of the SQL::Translator release.
=head1 AUTHORS
See the included AUTHORS file:
If you would like to contribute to the project, you can
send
patches
to the developers mailing list:
sqlfairy-developers
@lists
.sourceforge.net
Or
send
us a message (
with
your Sourceforge username) asking to be
added to the project and what you'd like to contribute.
=head1 COPYRIGHT
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License
for
more details.
You should have received a copy of the GNU General Public License
along
with
this program;
if
not,
write
to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
=head1 BUGS
=head1 PRAISE
If you find this module useful, please
use
=head1 SEE ALSO
L<perl>,
L<SQL::Translator::Parser>,
L<SQL::Translator::Producer>,
L<Parse::RecDescent>,
L<GD>,
L<GraphViz>,
L<Text::RecordParser>,
L<Class::DBI>,
L<XML::Writer>.