fix another Informix default parsing bug
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / DBI / Informix.pm
CommitLineData
bc5afe55 1package DBIx::Class::Schema::Loader::DBI::Informix;
2
3use strict;
4use warnings;
5use Class::C3;
6use base qw/DBIx::Class::Schema::Loader::DBI/;
7use namespace::autoclean;
8use Carp::Clan qw/^DBIx::Class/;
9use Scalar::Util 'looks_like_number';
10
11our $VERSION = '0.07000';
12
13=head1 NAME
14
15DBIx::Class::Schema::Loader::DBI::Informix - DBIx::Class::Schema::Loader::DBI
16Informix Implementation.
17
18=head1 DESCRIPTION
19
20See L<DBIx::Class::Schema::Loader> and L<DBIx::Class::Schema::Loader::Base>.
21
22=cut
23
24sub _setup {
25 my $self = shift;
26
27 $self->next::method(@_);
28
29 if (not defined $self->preserve_case) {
30 $self->preserve_case(0);
31 }
32}
33
34sub _tables_list {
35 my ($self, $opts) = @_;
36
37 my $dbh = $self->schema->storage->dbh;
38 my $sth = $dbh->prepare(<<'EOF');
39select tabname from systables t
40where t.owner <> 'informix' and t.owner <> '' and t.tabname <> ' VERSION'
41EOF
42 $sth->execute;
43
44 my @tables = map @$_, @{ $sth->fetchall_arrayref };
45
46 return $self->_filter_tables(\@tables, $opts);
47}
48
49sub _constraints_for {
50 my ($self, $table, $type) = @_;
51
52 my $dbh = $self->schema->storage->dbh;
53 local $dbh->{FetchHashKeyName} = 'NAME_lc';
54
55 my $sth = $dbh->prepare(<<'EOF');
56select c.constrname, i.*
57from sysconstraints c
58join systables t on t.tabid = c.tabid
59join sysindexes i on c.idxname = i.idxname
60where t.tabname = ? and c.constrtype = ?
61EOF
62 $sth->execute($table, $type);
63 my $indexes = $sth->fetchall_hashref('constrname');
64 $sth->finish;
65
66 my $cols = $self->_colnames_by_colno($table);
67
68 my $constraints;
69 while (my ($constr_name, $idx_def) = each %$indexes) {
70 $constraints->{$constr_name} = $self->_idx_colnames($idx_def, $cols);
71 }
72
73 return $constraints;
74}
75
76sub _idx_colnames {
77 my ($self, $idx_info, $table_cols_by_colno) = @_;
78
79 return [ map $self->_lc($table_cols_by_colno->{$_}), grep $_, map $idx_info->{$_}, map "part$_", (1..16) ];
80}
81
82sub _colnames_by_colno {
83 my ($self, $table) = @_;
84
85 my $dbh = $self->schema->storage->dbh;
86 local $dbh->{FetchHashKeyName} = 'NAME_lc';
87
88 my $sth = $dbh->prepare(<<'EOF');
89select c.colname, c.colno
90from syscolumns c
91join systables t on c.tabid = t.tabid
92where t.tabname = ?
93EOF
94 $sth->execute($table);
95 my $cols = $sth->fetchall_hashref('colno');
96 $cols = { map +($_, $cols->{$_}{colname}), keys %$cols };
97
98 return $cols;
99}
100
101sub _table_pk_info {
102 my ($self, $table) = @_;
103
104 my $pk = (values %{ $self->_constraints_for($table, 'P') || {} })[0];
105
106 return $pk;
107}
108
109sub _table_uniq_info {
110 my ($self, $table) = @_;
111
112 my $constraints = $self->_constraints_for($table, 'U');
113
114 my @uniqs = map { [ $_ => $constraints->{$_} ] } keys %$constraints;
115 return \@uniqs;
116}
117
118sub _table_fk_info {
119 my ($self, $table) = @_;
120
121 my $local_columns = $self->_constraints_for($table, 'R');
122
123 my $dbh = $self->schema->storage->dbh;
124 local $dbh->{FetchHashKeyName} = 'NAME_lc';
125
126 my $sth = $dbh->prepare(<<'EOF');
127select c.constrname local_constraint, rt.tabname remote_table, rc.constrname remote_constraint, ri.*
128from sysconstraints c
129join systables t on c.tabid = t.tabid
130join sysreferences r on c.constrid = r.constrid
131join sysconstraints rc on rc.constrid = r.primary
132join systables rt on r.ptabid = rt.tabid
133join sysindexes ri on rc.idxname = ri.idxname
134where t.tabname = ? and c.constrtype = 'R'
135EOF
136 $sth->execute($table);
137 my $remotes = $sth->fetchall_hashref('local_constraint');
138 $sth->finish;
139
140 my @rels;
141
142 while (my ($local_constraint, $remote_info) = each %$remotes) {
143 push @rels, {
144 local_columns => $local_columns->{$local_constraint},
145 remote_columns => $self->_idx_colnames($remote_info, $self->_colnames_by_colno($remote_info->{remote_table})),
146 remote_table => $remote_info->{remote_table},
147 };
148 }
149
150 return \@rels;
151}
152
153sub _columns_info_for {
154 my $self = shift;
155 my ($table) = @_;
156
157 my $result = $self->next::method(@_);
158
159 my $dbh = $self->schema->storage->dbh;
160 local $dbh->{FetchHashKeyName} = 'NAME_lc';
161
162 my $sth = $dbh->prepare(<<'EOF');
163select c.colname, c.coltype, d.type deflt_type, d.default deflt
164from syscolumns c
165join systables t on c.tabid = t.tabid
166left join sysdefaults d on t.tabid = d.tabid and c.colno = d.colno
167where t.tabname = ?
168EOF
169 $sth->execute($table);
170 my $cols = $sth->fetchall_hashref('colname');
171 $sth->finish;
172
173 while (my ($col, $info) = each %$cols) {
174 my $type = $info->{coltype} % 256;
175
176 if ($type == 6) { # SERIAL
177 $result->{$col}{is_auto_increment} = 1;
178 }
179
180 if (looks_like_number $result->{$col}{data_type}) {
181 if ($type == 7) {
182 $result->{$col}{data_type} = 'date';
183 }
184 elsif ($type == 10) {
185 $result->{$col}{data_type} = 'datetime';
186 }
187 }
188
189 my ($default_type, $default) = @{$info}{qw/deflt_type deflt/};
190
191 next unless $default_type;
192
193 if ($default_type eq 'C') {
194 my $current = 'CURRENT YEAR TO FRACTION(5)';
195 $result->{$col}{default_value} = \$current;
196 }
197 elsif ($default_type eq 'T') {
198 my $today = 'TODAY';
199 $result->{$col}{default_value} = \$today;
200 }
201 else {
5cd983b7 202 $default = (split ' ', $default, 2)[-1];
25e1e7bf 203
204 $default =~ s/\s+\z// if looks_like_number $default;
bc5afe55 205
206 # remove trailing 0s in floating point defaults
5cd983b7 207 $default =~ s/0+\z// if $default =~ /^\d+\.\d+\z/;
bc5afe55 208
209 $result->{$col}{default_value} = $default;
210 }
211 }
212
213 return $result;
214}
215
216=head1 SEE ALSO
217
218L<DBIx::Class::Schema::Loader>, L<DBIx::Class::Schema::Loader::Base>,
219L<DBIx::Class::Schema::Loader::DBI>
220
221=head1 AUTHOR
222
223See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
224
225=head1 LICENSE
226
227This library is free software; you can redistribute it and/or modify it under
228the same terms as Perl itself.
229
230=cut
231
2321;
233# vim:et sw=4 sts=4 tw=0: