Added ON DELETE and ON UPDATE clauses to FK output
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / DB2.pm
CommitLineData
04bc93b6 1package SQL::Translator::Producer::DB2;
2
3# -------------------------------------------------------------------
4# $Id: DB2.pm,v 1.1 2005-09-18 20:06:31 schiffbruechige Exp $
5# -------------------------------------------------------------------
6# Copyright (C) 2002-4 SQLFairy Authors
7#
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.
11#
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.
16#
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
21# -------------------------------------------------------------------
22
23=head1 NAME
24
25SQL::Translator::Producer::DB2 - DB2 SQL producer
26
27=head1 SYNOPSIS
28
29 use SQL::Translator;
30
31 my $t = SQL::Translator->new( parser => '...', producer => 'DB2' );
32 print $translator->translate( $file );
33
34=head1 DESCRIPTION
35
36Creates an SQL DDL suitable for DB.
37
38=cut
39
40use strict;
41use vars qw[ $VERSION $DEBUG $WARN ];
42$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
43$DEBUG = 0 unless defined $DEBUG;
44
45use SQL::Translator::Schema::Constants;
46use SQL::Translator::Utils qw(header_comment);
47
48
49# http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/ad/r0006844.htm
50
51# This is a terrible WTDI, each Parser should parse down to some standard set
52# of SQL data types, with field->extra entries being used to convert back to
53# weird types like "polygon" if needed (IMO anyway)
54
55my %translate = (
56 #
57 # MySQL types
58 #
59 int => 'integer',
60 mediumint => 'integer',
61 tinyint => 'smallint',
62 char => 'char',
63 tinyblob => 'blob',
64 mediumblob => 'blob',
65 longblob => 'long varchar for bit data',
66 tinytext => 'varchar',
67 text => 'clob',
68 longtext => 'clob',
69 mediumtext => 'clob',
70 enum => 'varchar',
71 set => 'varchar',
72 date => 'date',
73 datetime => 'timestamp',
74 time => 'time',
75 year => 'date',
76
77 #
78 # PostgreSQL types
79 #
80 'double precision' => 'double',
81 serial => 'integer',
82 bigserial => 'integer',
83 money => 'double',
84 character => 'char',
85 'character varying' => 'varchar',
86 bytea => 'BLOB',
87 interval => 'integer',
88 boolean => 'smallint',
89 point => 'integer',
90 line => 'integer',
91 lseg => 'integer',
92 box => 'integer',
93 path => 'integer',
94 polygon => 'integer',
95 circle => 'integer',
96 cidr => 'integer',
97 inet => 'varchar',
98 macaddr => 'varchar',
99 bit => 'number',
100 'bit varying' => 'number',
101
102 #
103 # DB types
104 #
105 number => 'integer',
106 varchar2 => 'varchar',
107 long => 'clob',
108);
109
110my %db2_reserved = map { $_ => 1} qw/
111ADD DETERMINISTIC LEAVE RESTART
112AFTER DISALLOW LEFT RESTRICT
113ALIAS DISCONNECT LIKE RESULT
114ALL DISTINCT LINKTYPE RESULT_SET_LOCATOR
115ALLOCATE DO LOCAL RETURN
116ALLOW DOUBLE LOCALE RETURNS
117ALTER DROP LOCATOR REVOKE
118AND DSNHATTR LOCATORS RIGHT
119ANY DSSIZE LOCK ROLLBACK
120APPLICATION DYNAMIC LOCKMAX ROUTINE
121AS EACH LOCKSIZE ROW
122ASSOCIATE EDITPROC LONG ROWS
123ASUTIME ELSE LOOP RRN
124AUDIT ELSEIF MAXVALUE RUN
125AUTHORIZATION ENCODING MICROSECOND SAVEPOINT
126AUX END MICROSECONDS SCHEMA
127AUXILIARY END-EXEC MINUTE SCRATCHPAD
128BEFORE END-EXEC1 MINUTES SECOND
129BEGIN ERASE MINVALUE SECONDS
130BETWEEN ESCAPE MODE SECQTY
131BINARY EXCEPT MODIFIES SECURITY
132BUFFERPOOL EXCEPTION MONTH SELECT
133BY EXCLUDING MONTHS SENSITIVE
134CACHE EXECUTE NEW SET
135CALL EXISTS NEW_TABLE SIGNAL
136CALLED EXIT NO SIMPLE
137CAPTURE EXTERNAL NOCACHE SOME
138CARDINALITY FENCED NOCYCLE SOURCE
139CASCADED FETCH NODENAME SPECIFIC
140CASE FIELDPROC NODENUMBER SQL
141CAST FILE NOMAXVALUE SQLID
142CCSID FINAL NOMINVALUE STANDARD
143CHAR FOR NOORDER START
144CHARACTER FOREIGN NOT STATIC
145CHECK FREE NULL STAY
146CLOSE FROM NULLS STOGROUP
147CLUSTER FULL NUMPARTS STORES
148COLLECTION FUNCTION OBID STYLE
149COLLID GENERAL OF SUBPAGES
150COLUMN GENERATED OLD SUBSTRING
151COMMENT GET OLD_TABLE SYNONYM
152COMMIT GLOBAL ON SYSFUN
153CONCAT GO OPEN SYSIBM
154CONDITION GOTO OPTIMIZATION SYSPROC
155CONNECT GRANT OPTIMIZE SYSTEM
156CONNECTION GRAPHIC OPTION TABLE
157CONSTRAINT GROUP OR TABLESPACE
158CONTAINS HANDLER ORDER THEN
159CONTINUE HAVING OUT TO
160COUNT HOLD OUTER TRANSACTION
161COUNT_BIG HOUR OVERRIDING TRIGGER
162CREATE HOURS PACKAGE TRIM
163CROSS IDENTITY PARAMETER TYPE
164CURRENT IF PART UNDO
165CURRENT_DATE IMMEDIATE PARTITION UNION
166CURRENT_LC_CTYPE IN PATH UNIQUE
167CURRENT_PATH INCLUDING PIECESIZE UNTIL
168CURRENT_SERVER INCREMENT PLAN UPDATE
169CURRENT_TIME INDEX POSITION USAGE
170CURRENT_TIMESTAMP INDICATOR PRECISION USER
171CURRENT_TIMEZONE INHERIT PREPARE USING
172CURRENT_USER INNER PRIMARY VALIDPROC
173CURSOR INOUT PRIQTY VALUES
174CYCLE INSENSITIVE PRIVILEGES VARIABLE
175DATA INSERT PROCEDURE VARIANT
176DATABASE INTEGRITY PROGRAM VCAT
177DAY INTO PSID VIEW
178DAYS IS QUERYNO VOLUMES
179DB2GENERAL ISOBID READ WHEN
180DB2GENRL ISOLATION READS WHERE
181DB2SQL ITERATE RECOVERY WHILE
182DBINFO JAR REFERENCES WITH
183DECLARE JAVA REFERENCING WLM
184DEFAULT JOIN RELEASE WRITE
185DEFAULTS KEY RENAME YEAR
186DEFINITION LABEL REPEAT YEARS
187DELETE LANGUAGE RESET
188DESCRIPTOR LC_CTYPE RESIGNAL
189/;
190
191#------------------------------------------------------------------------------
192
193sub produce
194{
195 my ($translator) = @_;
196 $DEBUG = $translator->debug;
197 $WARN = $translator->show_warnings;
198 my $no_comments = $translator->no_comments;
199 my $add_drop_table = $translator->add_drop_table;
200 my $schema = $translator->schema;
201 my $output = '';
202 my $indent = ' ';
203
204 $output .= header_comment unless($no_comments);
205 my (@table_defs);
206 foreach my $table ($schema->get_tables)
207 {
208 my $table_name = check_name($table->name, 'tables', 18);
209
210 my (@field_defs, @comments);
211 push @comments, "--\n-- Table: $table_name\n--" unless $no_comments;
212 foreach my $field ($table->get_fields)
213 {
214 my $field_name = check_name($field->name, 'fields', 30);
215 my $data_type = uc($translate{lc($field->data_type)} || $field->data_type);
216 my $size = $field->size();
217
218 my $field_def = "$field_name $data_type";
219 $field_def .= $field->is_auto_increment ?
220 ' GENERATED BY DEFAULT AS IDENTITY' : '';
221 $field_def .= $data_type =~ /CHAR/i ? "(${size})" : '';
222 $field_def .= !$field->is_nullable ? ' NOT NULL':'';
223 $field_def .= $field->is_primary_key ? ' PRIMARY KEY':'';
224 $field_def .= $field->default_value ? ' DEFAULT ' . $field->default_value : '';
225
226 push @field_defs, "${indent}${field_def}";
227 }
228
229
230 my $tablespace = $table->extra()->{'TABLESPACE'} || '';
231 my $table_def = "CREATE TABLE $table_name (\n";
232 $table_def .= join (",\n", @field_defs);
233 $table_def .= "\n)";
234 $table_def .= $tablespace ? "IN $tablespace;" : ';';
235
236 push @table_defs, "DROP TABLE $table_name;\n" if $add_drop_table;
237 push @table_defs, $table_def;
238 }
239
240 $output .= join("\n\n", @table_defs);
241}
242
243{ my %objnames;
244
245 sub check_name
246 {
247 my ($name, $type, $length) = @_;
248
249 my $newname = $name;
250 if(length($name) > $length) ## Maximum table name length is 18
251 {
252 warn "Table name $name is longer than $length characters, truncated" if $WARN;
253 if(grep {$_ eq substr($name, 0, $length) }
254 values(%{$objnames{$type}}))
255 {
256 die "Got multiple matching table names when truncated";
257 }
258 $objnames{$type}{$name} = substr($name, 0,$length);
259 $newname = $objnames{$type}{$name};
260 }
261
262 if($db2_reserved{uc($newname)})
263 {
264 warn "$newname is a reserved word in DB2!" if $WARN;
265 }
266
267 return sprintf("%-*s", $length-5, $newname);
268 }
269}
270
2711;