This commit was manufactured by cvs2svn to create branch 'darren-1_0'.
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator.pm
CommitLineData
16dc9970 1package SQL::Translator;
2
3#-----------------------------------------------------
4aa87c9f 4# $Id: Translator.pm,v 1.3 2002-03-07 14:11:40 dlc Exp $
16dc9970 5#
6# File : SQL/Translator.pm
7# Programmer : Ken Y. Clark, kclark@logsoft.com
8# Created : 2002/02/27
9# Purpose : convert schema from one database to another
10#-----------------------------------------------------
11
12use strict;
13use vars qw( $VERSION );
4aa87c9f 14$VERSION = (qw$Revision: 1.3 $)[-1];
16dc9970 15
16use Data::Dumper;
17
18use SQL::Translator::Parser::MySQL;
19use SQL::Translator::Parser::Sybase;
20use SQL::Translator::Producer::Oracle;
21use SQL::Translator::Producer::XML;
22
23#
24# These are the inputs we can parse.
25#
26my %parsers = (
27 mysql => 'MySQL',
28 sybase => 'Sybase',
29);
30
31#
32# These are the formats we can produce.
33#
34my %producers = (
35 oracle => 'Oracle',
36 xml => 'XML',
37);
38
39#-----------------------------------------------------
40sub new {
41#
42# Makes a new object. Intentionally made very bare as
43# it is used by all subclasses (unless they override,
44# of course).
45#
46 my $class = shift;
47 my %args = @_;
48 my $self = { %args };
49 return bless $self, $class;
50}
51
52#-----------------------------------------------------
53sub error {
54#
55# Return the last error.
56#
57 return shift()->{'error'} || '';
58}
59
60#-----------------------------------------------------
61sub error_out {
62#
63# Record the error and return undef.
64#
65 my $self = shift;
66 if ( my $error = shift ) {
67 $self->{'error'} = $error;
68 }
69 return;
70}
71
72#-----------------------------------------------------
73sub translate {
74#
75# Translates any number of given files.
76#
77 my ( $self, %args ) = @_;
78 my $from = $args{'from'} || '';
79 my $to = $args{'to'} || '';
80 my $input = $args{'input'} || [];
81 my $verbose = $args{'verbose'} || 0;
82 my $no_comments = $args{'no_comments'} || 0;
83
84 if ( exists $parsers{ $from } ) {
85 $self->{'from'} = $from;
86 warn "Using parser '$from.'\n" if $verbose;
87 }
88 else {
89 my $msg = "The parsers '$from' is not valid.\n" .
90 "Please choose from the following list:\n";
91 $msg .= " $_\n" for sort keys %parsers;
92 return $self->error_out( $msg );
93 }
94
95 if ( exists $producers{ $to } ) {
96 $self->{'to'} = $to;
97 warn "Using producer '$to.'\n" if $verbose;
98 }
99 else {
100 my $msg = "The producer '$to' is not valid.\n" .
101 "Please choose from the following list:\n";
102 $msg .= " $_\n" for sort keys %producers;
103 return $self->error_out( $msg );
104 }
105
106 #
107 # Slurp the entire text file we're parsing.
108 #
109 my $parser = $self->parser;
110 my $producer = $self->producer;
111 my $data;
112 for my $file ( @$input ) {
113 warn "Parsing file '$file.'\n" if $verbose;
114 open my $fh, $file or return $self->error_out( "Can't read $file: $!" );
115 local $/;
116 $data = $parser->parse( <$fh> );
117 }
118
119 warn "Data =\n", Dumper( $data ) if $verbose;
120 my $output = $producer->translate( $data );
121}
122
123#-----------------------------------------------------
124sub parser {
125#
126# Figures out which module to load based on the "from" argument
127#
128 my $self = shift;
129 unless ( $self->{'parser'} ) {
130 my $parser_module =
131 'SQL::Translator::Parser::'.$parsers{ $self->{'from'} };
132 $self->{'parser'} = $parser_module->new;
133 }
134 return $self->{'parser'};
135}
136
137#-----------------------------------------------------
138sub producer {
139#
140# Figures out which module to load based on the "to" argument
141#
142 my $self = shift;
143 unless ( $self->{'producer'} ) {
144 my $from = $parsers{ $self->{'from'} };
145 my $producer_module =
146 'SQL::Translator::Producer::'.$producers{ $self->{'to'} };
147 $self->{'producer'} = $producer_module->new( from => $from );
148 }
149 return $self->{'producer'};
150}
151
1521;
153
154#-----------------------------------------------------
155# Rescue the drowning and tie your shoestrings.
156# Henry David Thoreau
157#-----------------------------------------------------
158
159=head1 NAME
160
161SQL::Translator - convert schema from one database to another
162
163=head1 SYNOPSIS
164
165 use SQL::Translator;
166 my $translator = SQL::Translator->new;
167 my $output = $translator->translate(
168 from => 'mysql',
169 to => 'oracle',
170 file => $file,
171 ) or die $translator->error;
172 print $output;
173
174=head1 DESCRIPTION
175
176This module attempts to simplify the task of converting one database
177create syntax to another through the use of Parsers and Producers.
178The idea is that any Parser can be used with any Producer in the
179conversion process. So, if you wanted PostgreSQL-to-Oracle, you could
180just write the PostgreSQL parser and use an existing Oracle producer.
181
182Currently, the existing parsers use Parse::RecDescent, and the
183producers are just printing formatted output of the parsed data
184structure. New parsers don't necessarily have to use
185Parse::RecDescent, however, as long as the data structure conforms to
186what the producers are expecting. With this separation of code, it is
187hoped that developers will find it easy to add more database dialects
188by using what's written, writing only what they need, and then
189contributing their parsers or producers back to the project.
190
191=head1 AUTHOR
192
193Ken Y. Clark, kclark@logsoft.com
194
195=head1 SEE ALSO
196
197perl(1).
198
199=cut