our
(
$DEFAULT_SUB
,
$DEBUG
,
$ERROR
);
our
$VERSION
=
'1.66'
;
$VERSION
=~
tr
/_//d;
$DEBUG
= 0
unless
defined
$DEBUG
;
$ERROR
=
""
;
$DEFAULT_SUB
=
sub
{
$_
[0]->schema }
unless
defined
$DEFAULT_SUB
;
with
qw(
SQL::Translator::Role::Error
SQL::Translator::Role::BuildArgs
)
;
around
BUILDARGS
=>
sub
{
my
$orig
=
shift
;
my
$self
=
shift
;
my
$config
=
$self
->
$orig
(
@_
);
$config
->{parser} ||=
$config
->{from}
if
defined
$config
->{from};
$config
->{producer} ||=
$config
->{to}
if
defined
$config
->{to};
$config
->{filename} ||=
$config
->{file}
if
defined
$config
->{file};
my
$quote
= normalize_quote_options(
$config
);
$config
->{quote_identifiers} =
$quote
if
defined
$quote
;
return
$config
;
};
sub
BUILD {
my
(
$self
) =
@_
;
foreach
my
$tool
(
qw(producer parser)
) {
$self
->
$tool
(
$self
->
$tool
);
}
}
has
$_
=> (
is
=>
'rw'
,
default
=> quote_sub(
q{ 0 }
),
coerce
=> quote_sub(
q{ $_[0] ? 1 : 0 }
),
)
foreach
qw(add_drop_table no_comments show_warnings trace validate)
;
has
quote_identifiers
=> (
is
=>
'rw'
,
default
=> quote_sub(
q{ '0E0' }
),
coerce
=> quote_sub(
q{ $_[0] || 0 }
),
);
sub
quote_table_names {
(
@_
> 1 and (
$_
[1] xor
$_
[0]->quote_identifiers))
? croak
'Using quote_table_names as a setter is no longer supported'
:
$_
[0]->quote_identifiers;
}
sub
quote_field_names {
(
@_
> 1 and (
$_
[1] xor
$_
[0]->quote_identifiers))
? croak
'Using quote_field_names as a setter is no longer supported'
:
$_
[0]->quote_identifiers;
}
after
quote_identifiers
=>
sub
{
if
(
@_
> 1) {
$_
[0]->{quote_table_names} =
$_
[0]->{quote_field_names} =
$_
[1] ? 1 : 0;
}
};
has
producer
=> (
is
=>
'rw'
,
default
=>
sub
{
$DEFAULT_SUB
});
around
producer
=>
sub
{
my
$orig
=
shift
;
shift
->_tool(
{
orig
=>
$orig
,
name
=>
'producer'
,
path
=>
"SQL::Translator::Producer"
,
default_sub
=>
"produce"
,
},
@_
);
};
has
producer_type
=> (
is
=>
'rwp'
,
init_arg
=>
undef
);
around
producer_type
=> carp_ro(
'producer_type'
);
has
producer_args
=> (
is
=>
'rw'
,
default
=> quote_sub(
q{ +{}
}));
around
producer_args
=>
sub
{
my
$orig
=
shift
;
shift
->_args(
$orig
,
@_
);
};
has
parser
=> (
is
=>
'rw'
,
default
=>
sub
{
$DEFAULT_SUB
});
around
parser
=>
sub
{
my
$orig
=
shift
;
shift
->_tool(
{
orig
=>
$orig
,
name
=>
'parser'
,
path
=>
"SQL::Translator::Parser"
,
default_sub
=>
"parse"
,
},
@_
);
};
has
parser_type
=> (
is
=>
'rwp'
,
init_arg
=>
undef
);
around
parser_type
=> carp_ro(
'parser_type'
);
has
parser_args
=> (
is
=>
'rw'
,
default
=> quote_sub(
q{ +{}
}));
around
parser_args
=>
sub
{
my
$orig
=
shift
;
shift
->_args(
$orig
,
@_
);
};
has
filters
=> (
is
=>
'rw'
,
default
=> quote_sub(
q{ [] }
),
coerce
=>
sub
{
my
@filters
;
foreach
(@{
$_
[0] || [] }) {
my
(
$filt
,
@args
) =
ref
(
$_
) eq
"ARRAY"
?
@$_
:
$_
;
if
(isa(
$filt
,
"CODE"
)) {
push
@filters
, [
$filt
,
@args
];
next
;
}
else
{
__PACKAGE__->debug(
"Adding $filt filter. Args:"
. Dumper(\
@args
) .
"\n"
)
if
__PACKAGE__->debugging;
$filt
= _load_sub(
"$filt\::filter"
,
"SQL::Translator::Filter"
)
|| throw(__PACKAGE__->error);
push
@filters
, [
$filt
,
@args
];
}
}
return
\
@filters
;
},
);
around
filters
=>
sub
{
my
$orig
=
shift
;
my
$self
=
shift
;
return
@{
$self
->
$orig
([ @{
$self
->
$orig
},
@_
]) }
if
@_
;
return
@{
$self
->
$orig
};
};
has
filename
=> (
is
=>
'rw'
,
isa
=>
sub
{
foreach
my
$filename
(
ref
(
$_
[0]) eq
'ARRAY'
? @{
$_
[0] } :
$_
[0]) {
if
(-d
$filename
) {
throw(
"Cannot use directory '$filename' as input source"
);
}
elsif
(not -f _ && -r _ ) {
throw(
"Cannot use '$filename' as input source: "
.
"file does not exist or is not readable."
);
}
}
},
);
around
filename
=> \
&ex2err
;
has
data
=> (
is
=>
'rw'
,
builder
=> 1,
lazy
=> 1,
coerce
=>
sub
{
my
$data
=
shift
;
if
(isa(
$data
,
'ARRAY'
)) {
$data
=
join
''
,
@$data
;
}
elsif
(isa(
$data
,
'GLOB'
)) {
seek
(
$data
, 0, 0)
if
eof
(
$data
);
local
$/;
$data
= <
$data
>;
}
return
isa(
$data
,
'SCALAR'
) ?
$data
: \
$data
;
},
);
around
data
=>
sub
{
my
$orig
=
shift
;
my
$self
=
shift
;
if
(
@_
> 1 && !
ref
$_
[0]) {
return
$self
->
$orig
(\
join
(
''
,
@_
));
}
elsif
(
@_
) {
return
$self
->
$orig
(
@_
);
}
return
ex2err(
$orig
,
$self
);
};
sub
_build_data {
my
$self
=
shift
;
if
(
my
$filename
=
$self
->filename) {
$self
->debug(
"Opening '$filename' to get contents.\n"
);
local
$/;
my
$data
;
my
@files
=
ref
(
$filename
) eq
'ARRAY'
?
@$filename
: (
$filename
);
foreach
my
$file
(
@files
) {
open
my
$fh
,
'<'
,
$file
or throw(
"Can't read file '$file': $!"
);
$data
.= <
$fh
>;
close
$fh
or throw(
"Can't close file '$file': $!"
);
}
return
\
$data
;
}
}
has
schema
=> (
is
=>
'lazy'
,
init_arg
=>
undef
,
clearer
=>
'reset'
,
predicate
=>
'_has_schema'
,
);
around
schema
=> carp_ro(
'schema'
);
around
reset
=>
sub
{
my
$orig
=
shift
;
my
$self
=
shift
;
$self
->
$orig
(
@_
);
return
1;
};
sub
_build_schema { SQL::Translator::Schema->new(
translator
=>
shift
) }
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
(
$self
->_has_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
->debugging;
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
$orig
=
shift
;
if
(
@_
) {
if
(!
defined
$_
[0]) {
shift
@_
;
$self
->
$orig
({});
}
my
$args
= isa(
$_
[0],
'HASH'
) ?
shift
: {
@_
};
return
$self
->
$orig
({ %{
$self
->
$orig
},
%$args
});
}
return
$self
->
$orig
;
}
sub
_tool {
my
(
$self
,
$args
) = (
shift
,
shift
);
my
$name
=
$args
->{name};
my
$orig
=
$args
->{orig};
return
$self
->{
$name
}
unless
@_
;
my
$path
=
$args
->{path};
my
$default_sub
=
$args
->{default_sub};
my
$tool
=
shift
;
if
(isa(
$tool
,
'CODE'
)) {
$self
->
$orig
(
$tool
);
$self
->${ \
"_set_${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
->
$orig
(
$code
);
$self
->${ \
"_set_$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
;
}
around
new
=> \
&ex2err
;
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_identifiers
=> 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
=head2 new
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_identifiers
=item *
quote_table_names (DEPRECATED)
=item *
quote_field_names (DEPRECATED)
=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_identifiers
Toggles whether or not to quote identifiers (table, column, constraint, etc.)
with
a quoting mechanism suitable
for
the chosen Producer. The
default
(true)
is to quote them.
=head2 quote_table_names
DEPRECATED - A legacy proxy to L</quote_identifiers>
=head2 quote_field_names
DEPRECATED - A legacy proxy to L</quote_identifiers>
=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 retrieve 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:
=head1 GETTING HELP/SUPPORT
If you are stuck
with
a problem or have doubts about a particular
approach
do
not hesitate to contact us via any of the following
options (the list is sorted by
"fastest response time"
):
=over
=item * IRC: irc.perl.org
=
for
html
=back
=head1 HOW TO CONTRIBUTE
Contributions are always welcome, in all usable forms (we especially
welcome documentation improvements). The delivery methods include git-
or unified-diff formatted patches, GitHub pull requests, or plain bug
reports either via RT or the Mailing list. Contributors are generally
granted access to the official repository
after
their first several
patches pass successful review. Don't hesitate to
L<contact|/GETTING HELP/SUPPORT> us
with
any further questions you may
have.
This project is maintained in a git repository. The code and related tools are
accessible at the following locations:
=over
=item * Authorized committers: L<ssh://dbsrgits
@git
.shadowcat.co.uk/sql-translator.git>
=
for
html
&
=back
=head1 COPYRIGHT
Copyright 2012 the SQL::Translator authors, as listed in L</AUTHORS>.
=head1 LICENSE
This library is free software and may be distributed under the same terms as
Perl 5 itself.
=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>.