SCHEMA_LOADER_TESTS_EXTRA_ONLY tests data types too
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / DBI / InterBase.pm
CommitLineData
4cbddf8d 1package DBIx::Class::Schema::Loader::DBI::InterBase;
2
3use strict;
4use warnings;
4145a6f3 5use namespace::autoclean;
4cbddf8d 6use Class::C3;
7use base qw/DBIx::Class::Schema::Loader::DBI/;
8use Carp::Clan qw/^DBIx::Class/;
4145a6f3 9use List::Util 'first';
4cbddf8d 10
18e84656 11__PACKAGE__->mk_group_ro_accessors('simple', qw/
12 unquoted_ddl
13/);
14
2a8e93e9 15our $VERSION = '0.06000';
4cbddf8d 16
17=head1 NAME
18
19DBIx::Class::Schema::Loader::DBI::InterBase - DBIx::Class::Schema::Loader::DBI
20Firebird Implementation.
21
22=head1 DESCRIPTION
23
243c6ebc 24See L<DBIx::Class::Schema::Loader::Base> for available options.
4cbddf8d 25
18e84656 26By default column names from unquoted DDL will be generated in uppercase, as
27that is the only way they will work with quoting on.
28
29See the L</unquoted_ddl> option in this driver if you would like to have
30lowercase column names.
31
32=head1 DRIVER OPTIONS
33
34=head2 unquoted_ddl
35
36Set this loader option if your DDL uses unquoted identifiers and you will not
37use quoting (the L<quote_char|DBIx::Class::Storage::DBI/quote_char> option in
38L<connect_info|DBIx::Class::Storage::DBI/connect_info>.)
39
40This will generate lowercase column names (as opposed to the actual uppercase
41names) in your Result classes that will only work with quoting off.
42
43Mixed-case table and column names will be ignored when this option is on and
44will not work with quoting turned off.
45
4cbddf8d 46=cut
47
18e84656 48sub _is_case_sensitive {
49 my $self = shift;
50
51 return $self->unquoted_ddl ? 0 : 1;
52}
243c6ebc 53
ffb03c96 54sub _setup {
55 my $self = shift;
56
18e84656 57 $self->next::method;
58
ffb03c96 59 $self->schema->storage->sql_maker->name_sep('.');
18e84656 60
ec957051 61 if (not defined $self->unquoted_ddl) {
62 warn <<'EOF';
63
64WARNING: Assuming mixed-case Firebird DDL, see the unquoted_ddl option in
65perldoc DBIx::Class::Schema::Loader::DBI::InterBase
66for more information.
67
68EOF
69 }
70
18e84656 71 if (not $self->unquoted_ddl) {
72 $self->schema->storage->sql_maker->quote_char('"');
73 }
74 else {
75 $self->schema->storage->sql_maker->quote_char(undef);
76 }
77}
78
79sub _lc {
80 my ($self, $name) = @_;
81
82 return $self->unquoted_ddl ? lc($name) : $name;
83}
84
85sub _uc {
86 my ($self, $name) = @_;
87
88 return $self->unquoted_ddl ? uc($name) : $name;
ffb03c96 89}
90
4cbddf8d 91sub _table_pk_info {
92 my ($self, $table) = @_;
93
94 my $dbh = $self->schema->storage->dbh;
95 my $sth = $dbh->prepare(<<'EOF');
96SELECT iseg.rdb$field_name
97FROM rdb$relation_constraints rc
98JOIN rdb$index_segments iseg ON rc.rdb$index_name = iseg.rdb$index_name
99WHERE rc.rdb$constraint_type = 'PRIMARY KEY' and rc.rdb$relation_name = ?
100ORDER BY iseg.rdb$field_position
101EOF
102 $sth->execute($table);
103
104 my @keydata;
105
106 while (my ($col) = $sth->fetchrow_array) {
107 s/^\s+//, s/\s+\z// for $col;
108
18e84656 109 push @keydata, $self->_lc($col);
4cbddf8d 110 }
111
112 return \@keydata;
113}
114
115sub _table_fk_info {
116 my ($self, $table) = @_;
117
118 my ($local_cols, $remote_cols, $remote_table, @rels);
119 my $dbh = $self->schema->storage->dbh;
120 my $sth = $dbh->prepare(<<'EOF');
121SELECT rc.rdb$constraint_name fk, iseg.rdb$field_name local_col, ri.rdb$relation_name remote_tab, riseg.rdb$field_name remote_col
122FROM rdb$relation_constraints rc
123JOIN rdb$index_segments iseg ON rc.rdb$index_name = iseg.rdb$index_name
124JOIN rdb$indices li ON rc.rdb$index_name = li.rdb$index_name
125JOIN rdb$indices ri ON li.rdb$foreign_key = ri.rdb$index_name
126JOIN rdb$index_segments riseg ON iseg.rdb$field_position = riseg.rdb$field_position and ri.rdb$index_name = riseg.rdb$index_name
127WHERE rc.rdb$constraint_type = 'FOREIGN KEY' and rc.rdb$relation_name = ?
128ORDER BY iseg.rdb$field_position
129EOF
130 $sth->execute($table);
131
132 while (my ($fk, $local_col, $remote_tab, $remote_col) = $sth->fetchrow_array) {
133 s/^\s+//, s/\s+\z// for $fk, $local_col, $remote_tab, $remote_col;
134
18e84656 135 push @{$local_cols->{$fk}}, $self->_lc($local_col);
136 push @{$remote_cols->{$fk}}, $self->_lc($remote_col);
4cbddf8d 137 $remote_table->{$fk} = $remote_tab;
138 }
139
140 foreach my $fk (keys %$remote_table) {
141 push @rels, {
142 local_columns => $local_cols->{$fk},
143 remote_columns => $remote_cols->{$fk},
144 remote_table => $remote_table->{$fk},
145 };
146 }
147 return \@rels;
148}
149
150sub _table_uniq_info {
151 my ($self, $table) = @_;
152
153 my $dbh = $self->schema->storage->dbh;
154 my $sth = $dbh->prepare(<<'EOF');
155SELECT rc.rdb$constraint_name, iseg.rdb$field_name
156FROM rdb$relation_constraints rc
157JOIN rdb$index_segments iseg ON rc.rdb$index_name = iseg.rdb$index_name
158WHERE rc.rdb$constraint_type = 'UNIQUE' and rc.rdb$relation_name = ?
159ORDER BY iseg.rdb$field_position
160EOF
161 $sth->execute($table);
162
163 my $constraints;
164 while (my ($constraint_name, $column) = $sth->fetchrow_array) {
165 s/^\s+//, s/\s+\z// for $constraint_name, $column;
166
18e84656 167 push @{$constraints->{$constraint_name}}, $self->_lc($column);
4cbddf8d 168 }
169
170 my @uniqs = map { [ $_ => $constraints->{$_} ] } keys %$constraints;
171 return \@uniqs;
172}
173
45be2ce7 174sub _extra_column_info {
175 my ($self, $table, $column, $info, $dbi_info) = @_;
176 my %extra_info;
177
178 my $dbh = $self->schema->storage->dbh;
179
180 local $dbh->{LongReadLen} = 100000;
181 local $dbh->{LongTruncOk} = 1;
182
183 my $sth = $dbh->prepare(<<'EOF');
184SELECT t.rdb$trigger_source
185FROM rdb$triggers t
186WHERE t.rdb$relation_name = ?
93e8c513 187AND t.rdb$system_flag = 0 -- user defined
188AND t.rdb$trigger_type = 1 -- BEFORE INSERT
45be2ce7 189EOF
45be2ce7 190 $sth->execute($table);
191
192 while (my ($trigger) = $sth->fetchrow_array) {
243c6ebc 193 my @trig_cols = map {
194 /^"([^"]+)/ ? $1 : uc($1)
195 } $trigger =~ /new\.("?\w+"?)/ig;
196
197 my ($quoted, $generator) = $trigger =~
198/(?:gen_id\s* \( \s* |next \s* value \s* for \s*)(")?(\w+)/ix;
4145a6f3 199
0e0a4941 200 if ($generator) {
201 $generator = uc $generator unless $quoted;
202
18e84656 203 if (first { $self->_uc($_) eq $self->_uc($column) } @trig_cols) {
0e0a4941 204 $extra_info{is_auto_increment} = 1;
205 $extra_info{sequence} = $generator;
206 last;
207 }
45be2ce7 208 }
209 }
210
4145a6f3 211# fix up DT types, no idea which other types are fucked
212 if ($info->{data_type} eq '11') {
213 $extra_info{data_type} = 'TIMESTAMP';
214 }
215 elsif ($info->{data_type} eq '9') {
216 $extra_info{data_type} = 'DATE';
217 }
218
219# get default
220 $sth = $dbh->prepare(<<'EOF');
221SELECT rf.rdb$default_source
222FROM rdb$relation_fields rf
223WHERE rf.rdb$relation_name = ?
224AND rf.rdb$field_name = ?
225EOF
18e84656 226 $sth->execute($table, $self->_uc($column));
4145a6f3 227 my ($default_src) = $sth->fetchrow_array;
228
229 if ($default_src && (my ($def) = $default_src =~ /^DEFAULT \s+ (\S+)/ix)) {
230 if (my ($quoted) = $def =~ /^'(.*?)'\z/) {
231 $extra_info{default_value} = $quoted;
232 }
233 else {
234 $extra_info{default_value} = $def =~ /^\d/ ? $def : \$def;
235 }
236 }
237
45be2ce7 238 return \%extra_info;
239}
240
4cbddf8d 241=head1 SEE ALSO
242
243L<DBIx::Class::Schema::Loader>, L<DBIx::Class::Schema::Loader::Base>,
244L<DBIx::Class::Schema::Loader::DBI>
245
246=head1 AUTHOR
247
248See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
249
250=head1 LICENSE
251
252This library is free software; you can redistribute it and/or modify it under
253the same terms as Perl itself.
254
255=cut
256
2571;