File Coverage

blib/lib/DBIx/Class/Schema/Loader/DBI/ODBC/ACCESS.pm
Criterion Covered Total %
statement 21 170 12.3
branch 0 76 0.0
condition 0 21 0.0
subroutine 7 23 30.4
pod 1 1 100.0
total 29 291 9.9


line stmt bran cond sub pod time code
1             package DBIx::Class::Schema::Loader::DBI::ODBC::ACCESS;
2              
3 1     1   69847 use strict;
  1         12  
  1         29  
4 1     1   5 use warnings;
  1         2  
  1         27  
5 1     1   5 use base 'DBIx::Class::Schema::Loader::DBI::ODBC';
  1         1  
  1         517  
6 1     1   8 use mro 'c3';
  1         3  
  1         5  
7 1     1   27 use Try::Tiny;
  1         2  
  1         52  
8 1     1   6 use namespace::clean;
  1         2  
  1         5  
9 1     1   232 use DBIx::Class::Schema::Loader::Table ();
  1         2  
  1         2048  
10              
11             our $VERSION = '0.07051';
12              
13             __PACKAGE__->mk_group_accessors('simple', qw/
14             __ado_connection
15             __adox_catalog
16             /);
17              
18             =head1 NAME
19              
20             DBIx::Class::Schema::Loader::DBI::ODBC::ACCESS - Microsoft Access driver for
21             DBIx::Class::Schema::Loader
22              
23             =head1 DESCRIPTION
24              
25             See L for usage information.
26              
27             =cut
28              
29 0     0     sub _supports_db_schema { 0 }
30              
31             sub _db_path {
32 0     0     my $self = shift;
33              
34 0           $self->schema->storage->dbh->get_info(16);
35             }
36              
37             sub _open_ado_connection {
38 0     0     my ($self, $conn, $user, $pass) = @_;
39              
40 0           my @info = ({
41             provider => 'Microsoft.ACE.OLEDB.12.0',
42             dsn_extra => 'Persist Security Info=False',
43             }, {
44             provider => 'Microsoft.Jet.OLEDB.4.0',
45             });
46              
47 0           my $opened = 0;
48 0           my $exception;
49              
50 0           for my $info (@info) {
51 0           $conn->{Provider} = $info->{provider};
52              
53 0           my $dsn = 'Data Source='.($self->_db_path);
54 0 0         $dsn .= ";$info->{dsn_extra}" if exists $info->{dsn_extra};
55              
56             try {
57 0     0     $conn->Open($dsn, $user, $pass);
58 0           undef $exception;
59             }
60             catch {
61 0     0     $exception = $_;
62 0           };
63              
64 0 0         next if $exception;
65              
66 0           $opened = 1;
67 0           last;
68             }
69              
70 0           return ($opened, $exception);
71             }
72              
73              
74             sub _ado_connection {
75 0     0     my $self = shift;
76              
77 0 0         return $self->__ado_connection if $self->__ado_connection;
78              
79 0           my ($dsn, $user, $pass) = @{ $self->schema->storage->_dbi_connect_info };
  0            
80              
81 0           my $have_pass = 1;
82              
83 0 0         if (ref $dsn eq 'CODE') {
84 0           ($dsn, $user, $pass) = $self->_try_infer_connect_info_from_coderef($dsn);
85              
86 0 0         if (not $dsn) {
87 0           my $dbh = $self->schema->storage->dbh;
88 0           $dsn = $dbh->{Name};
89 0           $user = $dbh->{Username};
90 0           $have_pass = 0;
91             }
92             }
93              
94 0           require Win32::OLE;
95 0           my $conn = Win32::OLE->new('ADODB.Connection');
96              
97 0 0         $user = '' unless defined $user;
98 0 0 0       if ((not $have_pass) && exists $self->_passwords->{$dsn}{$user}) {
99 0           $pass = $self->_passwords->{$dsn}{$user};
100 0           $have_pass = 1;
101             }
102 0 0         $pass = '' unless defined $pass;
103              
104 0           my ($opened, $exception) = $self->_open_ado_connection($conn, $user, $pass);
105              
106 0 0 0       if ((not $opened) && (not $have_pass)) {
107 0 0         if (exists $ENV{DBI_PASS}) {
108 0           $pass = $ENV{DBI_PASS};
109              
110 0           ($opened, $exception) = $self->_open_ado_connection($conn, $user, $pass);
111              
112 0 0         if ($opened) {
113 0           $self->_passwords->{$dsn}{$user} = $pass;
114             }
115             else {
116 0           print "Enter database password for $user ($dsn): ";
117 0           chomp($pass = );
118              
119 0           ($opened, $exception) = $self->_open_ado_connection($conn, $user, $pass);
120              
121 0 0         if ($opened) {
122 0           $self->_passwords->{$dsn}{$user} = $pass;
123             }
124             }
125             }
126             else {
127 0           print "Enter database password for $user ($dsn): ";
128 0           chomp($pass = );
129              
130 0           ($opened, $exception) = $self->_open_ado_connection($conn, $user, $pass);
131              
132 0 0         if ($opened) {
133 0           $self->_passwords->{$dsn}{$user} = $pass;
134             }
135             }
136             }
137              
138 0 0         if (not $opened) {
139 0           die "Failed to open ADO connection: $exception";
140             }
141              
142 0           $self->__ado_connection($conn);
143              
144 0           return $conn;
145             }
146              
147             sub _adox_catalog {
148 0     0     my $self = shift;
149              
150 0 0         return $self->__adox_catalog if $self->__adox_catalog;
151              
152 0           require Win32::OLE;
153 0           my $cat = Win32::OLE->new('ADOX.Catalog');
154 0           $cat->{ActiveConnection} = $self->_ado_connection;
155              
156 0           $self->__adox_catalog($cat);
157              
158 0           return $cat;
159             }
160              
161             sub _adox_column {
162 0     0     my ($self, $table, $col) = @_;
163              
164 0           my $col_obj;
165              
166 0           my $cols = $self->_adox_catalog->Tables->Item($table->name)->Columns;
167              
168 0           for my $col_idx (0..$cols->Count-1) {
169 0           $col_obj = $cols->Item($col_idx);
170 0 0         if ($self->preserve_case) {
171 0 0         last if $col_obj->Name eq $col;
172             }
173             else {
174 0 0         last if lc($col_obj->Name) eq lc($col);
175             }
176             }
177              
178 0           return $col_obj;
179             }
180              
181             sub rescan {
182 0     0 1   my $self = shift;
183              
184 0 0         if ($self->__adox_catalog) {
185 0           $self->__ado_connection(undef);
186 0           $self->__adox_catalog(undef);
187             }
188              
189 0           return $self->next::method(@_);
190             }
191              
192             sub _table_pk_info {
193 0     0     my ($self, $table) = @_;
194              
195 0 0         return [] if $self->_disable_pk_detection;
196              
197 0           my @keydata;
198              
199             my $indexes = try {
200 0     0     $self->_adox_catalog->Tables->Item($table->name)->Indexes
201             }
202             catch {
203 0     0     warn "Could not retrieve indexes in table '$table', disabling primary key detection: $_\n";
204 0           return undef;
205 0           };
206              
207 0 0         if (not $indexes) {
208 0           $self->_disable_pk_detection(1);
209 0           return [];
210             }
211              
212 0           for my $idx_num (0..($indexes->Count-1)) {
213 0           my $idx = $indexes->Item($idx_num);
214 0 0         if ($idx->PrimaryKey) {
215 0           my $cols = $idx->Columns;
216 0           for my $col_idx (0..$cols->Count-1) {
217 0           push @keydata, $self->_lc($cols->Item($col_idx)->Name);
218             }
219             }
220             }
221              
222 0           return \@keydata;
223             }
224              
225             sub _table_fk_info {
226 0     0     my ($self, $table) = @_;
227              
228 0 0         return [] if $self->_disable_fk_detection;
229              
230             my $keys = try {
231 0     0     $self->_adox_catalog->Tables->Item($table->name)->Keys;
232             }
233             catch {
234 0     0     warn "Could not retrieve keys in table '$table', disabling relationship detection: $_\n";
235 0           return undef;
236 0           };
237              
238 0 0         if (not $keys) {
239 0           $self->_disable_fk_detection(1);
240 0           return [];
241             }
242              
243 0           my @rels;
244              
245 0           for my $key_idx (0..($keys->Count-1)) {
246 0           my $key = $keys->Item($key_idx);
247              
248 0 0         next unless $key->Type == 2;
249              
250 0           my $local_cols = $key->Columns;
251 0           my $remote_table = $key->RelatedTable;
252 0           my (@local_cols, @remote_cols);
253              
254 0           for my $col_idx (0..$local_cols->Count-1) {
255 0           my $col = $local_cols->Item($col_idx);
256 0           push @local_cols, $self->_lc($col->Name);
257 0           push @remote_cols, $self->_lc($col->RelatedColumn);
258             }
259              
260 0 0         push @rels, {
261             local_columns => \@local_cols,
262             remote_columns => \@remote_cols,
263             remote_table => DBIx::Class::Schema::Loader::Table->new(
264             loader => $self,
265             name => $remote_table,
266             ($self->db_schema ? (
267             schema => $self->db_schema->[0],
268             ignore_schema => 1,
269             ) : ()),
270             ),
271             };
272             }
273              
274 0           return \@rels;
275             }
276              
277             sub _columns_info_for {
278 0     0     my $self = shift;
279 0           my ($table) = @_;
280              
281 0           my $result = $self->next::method(@_);
282              
283 0           while (my ($col, $info) = each %$result) {
284 0           my $data_type = $info->{data_type};
285              
286 0           my $col_obj = $self->_adox_column($table, $col);
287              
288 0 0         $info->{is_nullable} = ($col_obj->Attributes & 2) == 2 ? 1 : 0;
289              
290 0 0         if ($data_type eq 'counter') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
291 0           $info->{data_type} = 'integer';
292 0           $info->{is_auto_increment} = 1;
293 0           delete $info->{size};
294             }
295             elsif ($data_type eq 'longbinary') {
296 0           $info->{data_type} = 'image';
297 0           $info->{original}{data_type} = 'longbinary';
298             }
299             elsif ($data_type eq 'longchar') {
300 0           $info->{data_type} = 'text';
301 0           $info->{original}{data_type} = 'longchar';
302             }
303             elsif ($data_type eq 'double') {
304 0           $info->{data_type} = 'double precision';
305 0           $info->{original}{data_type} = 'double';
306             }
307             elsif ($data_type eq 'guid') {
308 0           $info->{data_type} = 'uniqueidentifier';
309 0           $info->{original}{data_type} = 'guid';
310             }
311             elsif ($data_type eq 'byte') {
312 0           $info->{data_type} = 'tinyint';
313 0           $info->{original}{data_type} = 'byte';
314             }
315             elsif ($data_type eq 'currency') {
316 0           $info->{data_type} = 'money';
317 0           $info->{original}{data_type} = 'currency';
318              
319 0 0 0       if (ref $info->{size} eq 'ARRAY' && $info->{size}[0] == 19 && $info->{size}[1] == 4) {
      0        
320             # Actual money column via ODBC, otherwise we pass the sizes on to the ADO driver for
321             # decimal columns (which masquerade as money columns...)
322 0           delete $info->{size};
323             }
324             }
325             elsif ($data_type eq 'decimal') {
326 0 0 0       if (ref $info->{size} eq 'ARRAY' && $info->{size}[0] == 18 && $info->{size}[1] == 0) {
      0        
327 0           delete $info->{size};
328             }
329             }
330              
331             # Pass through currency (which can be decimal for ADO.)
332 0 0 0       if ($data_type !~ /^(?:(?:var)?(?:char|binary)|decimal)\z/ && $data_type ne 'currency') {
333 0           delete $info->{size};
334             }
335             }
336              
337 0           return $result;
338             }
339              
340             =head1 SEE ALSO
341              
342             L, L,
343             L
344              
345             =head1 AUTHORS
346              
347             See L.
348              
349             =head1 LICENSE
350              
351             This library is free software; you can redistribute it and/or modify it under
352             the same terms as Perl itself.
353              
354             =cut
355              
356             1;
357             # vim:et sts=4 sw=4 tw=0: