Commit | Line | Data |
726c8f65 |
1 | package DBIx::Class::Storage::DBI::ADO::MS_Jet; |
2 | |
3 | use strict; |
4 | use warnings; |
5 | use base qw/ |
6 | DBIx::Class::Storage::DBI::ADO |
7 | DBIx::Class::Storage::DBI::ACCESS |
8 | /; |
9 | use mro 'c3'; |
10 | use DBIx::Class::Storage::DBI::ADO::MS_Jet::Cursor (); |
11 | |
12 | __PACKAGE__->cursor_class('DBIx::Class::Storage::DBI::ADO::MS_Jet::Cursor'); |
13 | |
14 | =head1 NAME |
15 | |
16 | DBIx::Class::Storage::DBI::ADO::MS_Jet - Support for MS Access over ADO |
17 | |
18 | =head1 DESCRIPTION |
19 | |
20 | This driver is a subclass of L<DBIx::Class::Storage::DBI::ADO> and |
21 | L<DBIx::Class::Storage::DBI::ACCESS> for connecting to MS Access via |
22 | L<DBD::ADO>. |
23 | |
24 | See the documentation for L<DBIx::Class::Storage::DBI::ACCESS> for |
25 | information on the MS Access driver for L<DBIx::Class>. |
26 | |
27 | This driver implements workarounds for C<TEXT/IMAGE/MEMO> columns, sets the |
28 | L<cursor_class|DBIx::Class::Storage::DBI/cursor_class> to |
29 | L<DBIx::Class::Storage::DBI::ADO::MS_Jet::Cursor> to normalize returned |
30 | C<GUID> values and provides L<DBIx::Class::InflateColumn::DateTime> support |
31 | for C<DATETIME> columns. |
32 | |
33 | =head1 EXAMPLE DSNs |
34 | |
35 | # older Access versions: |
36 | dbi:ADO:Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\rkitover\Documents\access_sample.accdb |
37 | |
38 | # newer Access versions: |
39 | dbi:ADO:Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\rkitover\Documents\access_sample.accdb;Persist Security Info=False' |
40 | |
41 | =head1 TEXT/IMAGE/MEMO COLUMNS |
42 | |
43 | The ADO driver does not suffer from the |
44 | L<problems|DBIx::Class::Storage::DBI::ODBC::ACCESS/"TEXT/IMAGE/MEMO COLUMNS"> |
45 | the L<ODBC|DBIx::Class::Storage::DBI::ODBC::ACCESS> driver has with these types |
46 | of columns. You can use them safely. |
47 | |
48 | When you execute a C<CREATE TABLE> statement over this driver with a C<TEXT> |
49 | column, it will be converted to C<MEMO>, while in the |
50 | L<ODBC|DBIx::Class::Storage::DBI::ODBC::ACCESS> driver it is converted to |
51 | C<VARCHAR(255)>. |
52 | |
53 | However, the caveat about L<LongReadLen|DBI/LongReadLen> having to be twice the |
54 | max size of your largest C<MEMO/TEXT> column C<+1> still applies. L<DBD::ADO> |
55 | sets L<LongReadLen|DBI/LongReadLen> to a large value by default, so it should be |
56 | safe to just leave it unset. If you do pass a L<LongReadLen|DBI/LongReadLen> in |
57 | your L<connect_info|DBIx::Class::Storage::DBI/connect_info>, it will be |
58 | multiplied by two and C<1> added, just as for the |
59 | L<ODBC|DBIx::Class::Storage::DBI::ODBC::ACCESS> driver. |
60 | |
61 | =cut |
62 | |
63 | # set LongReadLen = LongReadLen * 2 + 1 (see docs on MEMO) |
64 | sub _run_connection_actions { |
65 | my $self = shift; |
66 | |
67 | my $long_read_len = $self->_dbh->{LongReadLen}; |
68 | |
69 | # This is the DBD::ADO default. |
70 | if ($long_read_len != 2147483647) { |
71 | $self->_dbh->{LongReadLen} = $long_read_len * 2 + 1; |
72 | } |
73 | |
74 | return $self->next::method(@_); |
75 | } |
76 | |
77 | # AutoCommit does not get reset properly after transactions for some reason |
78 | # (probably because of my nested transaction hacks in ACCESS.pm) fix it up |
79 | # here. |
80 | |
90d7422f |
81 | sub _exec_txn_commit { |
726c8f65 |
82 | my $self = shift; |
83 | $self->next::method(@_); |
84 | $self->_dbh->{AutoCommit} = $self->_dbh_autocommit |
85 | if $self->{transaction_depth} == 1; |
86 | } |
87 | |
90d7422f |
88 | sub _exec_txn_rollback { |
726c8f65 |
89 | my $self = shift; |
90 | $self->next::method(@_); |
91 | $self->_dbh->{AutoCommit} = $self->_dbh_autocommit |
92 | if $self->{transaction_depth} == 1; |
93 | } |
94 | |
95 | # Fix up GUIDs for ->find, for cursors see the cursor_class above. |
96 | |
97 | sub select_single { |
98 | my $self = shift; |
99 | my ($ident, $select) = @_; |
100 | |
101 | my @row = $self->next::method(@_); |
102 | |
103 | return @row unless |
104 | $self->cursor_class->isa('DBIx::Class::Storage::DBI::ADO::MS_Jet::Cursor'); |
105 | |
106 | my $col_info = $self->_resolve_column_info($ident); |
107 | |
108 | for my $select_idx (0..$#$select) { |
109 | my $selected = $select->[$select_idx]; |
110 | |
111 | next if ref $selected; |
112 | |
113 | my $data_type = $col_info->{$selected}{data_type}; |
114 | |
115 | if ($self->_is_guid_type($data_type)) { |
116 | my $returned = $row[$select_idx]; |
117 | |
118 | $row[$select_idx] = substr($returned, 1, 36) |
119 | if substr($returned, 0, 1) eq '{'; |
120 | } |
121 | } |
122 | |
123 | return @row; |
124 | } |
125 | |
126 | sub datetime_parser_type { |
127 | 'DBIx::Class::Storage::DBI::ADO::MS_Jet::DateTime::Format' |
128 | } |
129 | |
130 | package # hide from PAUSE |
131 | DBIx::Class::Storage::DBI::ADO::MS_Jet::DateTime::Format; |
132 | |
133 | my $datetime_format = '%m/%d/%Y %I:%M:%S %p'; |
134 | my $datetime_parser; |
135 | |
136 | sub parse_datetime { |
137 | shift; |
138 | require DateTime::Format::Strptime; |
139 | $datetime_parser ||= DateTime::Format::Strptime->new( |
140 | pattern => $datetime_format, |
141 | on_error => 'croak', |
142 | ); |
143 | return $datetime_parser->parse_datetime(shift); |
144 | } |
145 | |
146 | sub format_datetime { |
147 | shift; |
148 | require DateTime::Format::Strptime; |
149 | $datetime_parser ||= DateTime::Format::Strptime->new( |
150 | pattern => $datetime_format, |
151 | on_error => 'croak', |
152 | ); |
153 | return $datetime_parser->format_datetime(shift); |
154 | } |
155 | |
156 | 1; |
157 | |
158 | =head1 AUTHOR |
159 | |
160 | See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>. |
161 | |
162 | =head1 LICENSE |
163 | |
164 | You may distribute this code under the same terms as Perl itself. |
165 | |
166 | =cut |
167 | # vim:sts=2 sw=2: |