Changes + Reverts for 0.11000, see Changes file for info
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / DBI / Sybase.pm
CommitLineData
86ee0658 1package SQL::Translator::Parser::DBI::Sybase;
2
587a99b0 3# -------------------------------------------------------------------
478f608d 4# Copyright (C) 2002-2009 SQLFairy Authors
587a99b0 5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License as
8# published by the Free Software Foundation; version 2.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18# 02111-1307 USA
19# -------------------------------------------------------------------
86ee0658 20
21=head1 NAME
22
23SQL::Translator::Parser::DBI::Sybase - parser for DBD::Sybase
24
25=head1 SYNOPSIS
26
27See SQL::Translator::Parser::DBI.
28
29=head1 DESCRIPTION
30
31Uses DBI Catalog Methods.
32
33=cut
34
35use strict;
36use DBI;
37use SQL::Translator::Schema;
38use Data::Dumper;
39
da06ac74 40use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
11ad2df9 41$VERSION = '1.59';
86ee0658 42$DEBUG = 0 unless defined $DEBUG;
43
44no strict 'refs';
45
46# -------------------------------------------------------------------
47sub parse {
48 my ( $tr, $dbh ) = @_;
49
50 if ($dbh->{FetchHashKeyName} ne 'NAME_uc') {
51 warn "setting dbh attribute {FetchHashKeyName} to NAME_uc";
52 $dbh->{FetchHashKeyName} = 'NAME_uc';
53 }
54
55 if ($dbh->{ChopBlanks} != 1) {
56 warn "setting dbh attribute {ChopBlanks} to 1";
57 $dbh->{ChopBlanks} = 1;
58 }
59
60 my $schema = $tr->schema;
61
62 my ($sth, @tables, $columns);
63 my $stuff;
64
65 ### Columns
66
67 # it is much quicker to slurp back everything all at once rather
68 # than make repeated calls
69
546dad3b 70 $sth = $dbh->column_info(undef, undef, undef, undef);
86ee0658 71
72
73 foreach my $c (@{$sth->fetchall_arrayref({})}) {
74 $columns
75 ->{$c->{TABLE_CAT}}
76 ->{$c->{TABLE_SCHEM}}
77 ->{$c->{TABLE_NAME}}
78 ->{columns}
79 ->{$c->{COLUMN_NAME}}= $c;
80 }
81
82 ### Tables and views
83
84 # Get a list of the tables and views.
85 $sth = $dbh->table_info();
86 @tables = @{$sth->fetchall_arrayref({})};
87
88 my $h = $dbh->selectall_arrayref(q{
89SELECT o.name, colid,colid2,c.text
90 FROM syscomments c
91 JOIN sysobjects o
92 ON c.id = o.id
93 WHERE o.type ='V'
94ORDER BY o.name,
95 c.colid,
96 c.colid2
97}
98);
99
100 # View text
101 # I had always thought there was something 'hard' about
e36f4eac 102 # reconstructing text from syscomments ..
86ee0658 103 # this seems to work fine and is certainly not complicated!
104
105 foreach (@{$h}) {
106 $stuff->{view}->{$_->[0]}->{text} .= $_->[3];
107 }
108
109 #### objects with indexes.
110 map {
111 $stuff->{indexes}->{$_->[0]}++
112 if defined;
1eb8ea88 113 } @{$dbh->selectall_arrayref("SELECT DISTINCT object_name(id) AS name
114 FROM sysindexes
115 WHERE indid > 0")};
86ee0658 116
117 ## slurp objects
118 map {
119 $stuff->{$_->[1]}->{$_->[0]} = $_;
1eb8ea88 120 } @{$dbh->selectall_arrayref("SELECT name,type, id FROM sysobjects")};
86ee0658 121
122
123 ### Procedures
1eb8ea88 124
125 # This gets legitimate procedures by used the 'supported' API: sp_stored_procedures
126 map {
127 my $n = $_->{PROCEDURE_NAME};
128 $n =~ s/;\d+$//; # Ignore versions for now
129 $_->{name} = $n;
130 $stuff->{procedures}->{$n} = $_;
131 } values %{$dbh->selectall_hashref("sp_stored_procedures", 'PROCEDURE_NAME')};
132
133
134 # And this blasts in the text of 'legit' stored procedures. Do
135 # this rather than calling sp_helptext in a loop.
136
137 $h = $dbh->selectall_arrayref(q{
138SELECT o.name, colid,colid2,c.text
139 FROM syscomments c
140 JOIN sysobjects o
141 ON c.id = o.id
142 WHERE o.type ='P'
143ORDER BY o.name,
144 c.colid,
145 c.colid2
146}
147);
148
149 foreach (@{$h}) {
150 $stuff->{procedures}->{$_->[0]}->{text} .= $_->[3]
151 if (defined($stuff->{procedures}->{$_->[0]}));
152 }
153
86ee0658 154 ### Defaults
155 ### Rules
156 ### Bind Defaults
157 ### Bind Rules
158
159 ### Triggers
1eb8ea88 160 # Since the 'target' of the trigger is defined in the text, we will
161 # just create them independently for now rather than associating them
162 # with a table.
163
164 $h = $dbh->selectall_arrayref(q{
165SELECT o.name, colid,colid2,c.text
166 FROM syscomments c
167 JOIN sysobjects o
168 ON c.id = o.id
169 JOIN sysobjects o1
170 ON (o.id = o1.instrig OR o.id = o1.deltrig or o.id = o1.updtrig)
171 WHERE o.type ='TR'
172ORDER BY o.name,
173 c.colid,
174 c.colid2
175}
176);
177 foreach (@{$h}) {
178 $stuff->{triggers}->{$_->[0]}->{text} .= $_->[3];
179 }
86ee0658 180
181 ### References
182 ### Keys
183
184 ### Types
1eb8ea88 185 # Not sure what to do with these?
86ee0658 186 $stuff->{type_info_all} = $dbh->type_info_all;
187
188 ### Tables
189 # According to the DBI docs, these can be
190
191 # "TABLE"
192 # "VIEW"
193 # "SYSTEM TABLE"
194 # "GLOBAL TEMPORARY",
195 # "LOCAL TEMPORARY"
196 # "ALIAS"
197 # "SYNONYM"
198
199 foreach my $table_info (@tables) {
200 next
201 unless (defined($table_info->{TABLE_TYPE}));
202
203 if ($table_info->{TABLE_TYPE} =~ /TABLE/) {
204 my $table = $schema->add_table(
205 name =>
206$table_info->{TABLE_NAME},
207 type =>
208$table_info->{TABLE_TYPE},
209 ) || die $schema->error;
210
211 # find the associated columns
212
213 my $cols =
214 $columns->{$table_info->{TABLE_QUALIFIER}}
215 ->{$table_info->{TABLE_OWNER}}
216 ->{$table_info->{TABLE_NAME}}
217 ->{columns};
218
219 foreach my $c (values %{$cols}) {
1eb8ea88 220 my $f = $table->add_field(
221 name => $c->{COLUMN_NAME},
222 data_type => $c->{TYPE_NAME},
223 order => $c->{ORDINAL_POSITION},
224 size => $c->{COLUMN_SIZE},
86ee0658 225 ) || die $table->error;
1eb8ea88 226
86ee0658 227 $f->is_nullable(1)
228 if ($c->{NULLABLE} == 1);
229 }
230
231 # add in primary key
232 my $h = $dbh->selectall_hashref("sp_pkeys
233$table_info->{TABLE_NAME}", 'COLUMN_NAME');
234 if (scalar keys %{$h} > 1) {
235 my @c = map {
236 $_->{COLUMN_NAME}
237 } sort {
238 $a->{KEY_SEQ} <=> $b->{KEY_SEQ}
239 } values %{$h};
240
241 $table->primary_key(@c)
242 if (scalar @c);
243 }
244
245 # add in any indexes ... how do we tell if the index has
246 # already been created as part of a primary key or other
247 # constraint?
248
1eb8ea88 249 if (defined($stuff->{indexes}->{$table_info->{TABLE_NAME}})){
86ee0658 250 my $h = $dbh->selectall_hashref("sp_helpindex
251$table_info->{TABLE_NAME}", 'INDEX_NAME');
252 foreach (values %{$h}) {
253 my $fields = $_->{'INDEX_KEYS'};
254 $fields =~ s/\s*//g;
255 my $i = $table->add_index(
256 name =>
257$_->{INDEX_NAME},
258 fields => $fields,
259 );
260 if ($_->{'INDEX_DESCRIPTION'} =~ /unique/i) {
261 $i->type('unique');
262
263 # we could make this a primary key if there
264 # isn't already one defined and if there
265 # aren't any nullable columns in thisindex.
266
267 if (!defined($table->primary_key())) {
268 $table->primary_key($fields)
269 unless grep {
270 $table->get_field($_)->is_nullable()
271 } split(/,\s*/, $fields);
272 }
273 }
274 }
275 }
276 } elsif ($table_info->{TABLE_TYPE} eq 'VIEW') {
277 my $view = $schema->add_view(
278 name =>
279$table_info->{TABLE_NAME},
280 );
281
1eb8ea88 282
86ee0658 283 my $cols =
284 $columns->{$table_info->{TABLE_QUALIFIER}}
285 ->{$table_info->{TABLE_OWNER}}
286 ->{$table_info->{TABLE_NAME}}
287 ->{columns};
288
289 $view->fields(map {
290 $_->{COLUMN_NAME}
291 } sort {
292 $a->{ORDINAL_POSITION} <=> $b->{ORDINAL_POSITION}
293 } values %{$cols}
294 );
295
1eb8ea88 296 $view->sql($stuff->{view}->{$table_info->{TABLE_NAME}}->{text})
297 if (defined($stuff->{view}->{$table_info->{TABLE_NAME}}->{text}));
86ee0658 298 }
299 }
1eb8ea88 300
301 foreach my $p (values %{$stuff->{procedures}}) {
302 my $proc = $schema->add_procedure(
303 name => $p->{name},
304 owner => $p->{PROCEDURE_OWNER},
305 comments => $p->{REMARKS},
306 sql => $p->{text},
307 );
308
309 }
587a99b0 310
86ee0658 311 ### Permissions
312 ### Groups
313 ### Users
314 ### Aliases
315 ### Logins
587a99b0 316 return 1;
86ee0658 317}
318
3191;
320
587a99b0 321# -------------------------------------------------------------------
322
86ee0658 323=pod
324
325=head1 AUTHOR
326
587a99b0 327Paul Harrington E<lt>harringp@deshaw.comE<gt>.
86ee0658 328
329=head1 SEE ALSO
330
331DBI, DBD::Sybase, SQL::Translator::Schema.
332
333=cut