X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI%2FODBC%2FACCESS.pm;h=2a0624fdc1164d391cfe0ed0363dd7bbd3dcaf2e;hb=726c8f65;hp=b41b1f33b29c7e77cf3f30f9170e5483d3d6e7c5;hpb=86b234150d8ab7b49520deb14428df15c3b9e60d;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm b/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm index b41b1f3..2a0624f 100644 --- a/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm +++ b/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm @@ -1,131 +1,154 @@ package DBIx::Class::Storage::DBI::ODBC::ACCESS; + use strict; use warnings; - -use base qw/DBIx::Class::Storage::DBI/; +use base qw/ + DBIx::Class::Storage::DBI::ODBC + DBIx::Class::Storage::DBI::ACCESS +/; use mro 'c3'; -use DBI; - -my $ERR_MSG_START = __PACKAGE__ . ' failed: '; +__PACKAGE__->mk_group_accessors(inherited => + 'disable_sth_caching_for_image_insert_or_update' +); -__PACKAGE__->sql_limit_dialect ('Top'); -__PACKAGE__->sql_quote_char ([qw/[ ]/]); - -sub insert { - my $self = shift; - my ( $source, $to_insert ) = @_; +__PACKAGE__->disable_sth_caching_for_image_insert_or_update(1); - my ( undef, $sth ) = $self->_execute( 'insert', $source, $to_insert ); - - #store the identity here since @@IDENTITY is connection global and this prevents - #possibility that another insert to a different table overwrites it for this resultsource - my $identity = 'SELECT @@IDENTITY'; - my $max_sth = $self->{ _dbh }->prepare( $identity ) - or $self->throw_exception( $ERR_MSG_START . $self->{ _dbh }->errstr() ); - $max_sth->execute() or $self->throw_exception( $ERR_MSG_START . $max_sth->errstr ); - - my $row = $max_sth->fetchrow_arrayref() - or $self->throw_exception( $ERR_MSG_START . "$identity did not return any result." ); - - $self->{ last_pk }->{ $source->name() } = $row; +=head1 NAME - return $to_insert; -} +DBIx::Class::Storage::DBI::ODBC::ACCESS - Support specific to MS Access over ODBC -sub last_insert_id { - my $self = shift; - my ( $result_source ) = @_; +=head1 DESCRIPTION - return @{ $self->{ last_pk }->{ $result_source->name() } }; -} +This class implements support specific to Microsoft Access over ODBC. -sub bind_attribute_by_data_type { - my $self = shift; +It is a subclass of L and +L, see those classes for more +information. - my ( $data_type ) = @_; +It is loaded automatically by by L when it +detects a MS Access back-end. - return { TYPE => $data_type } if $data_type == DBI::SQL_LONGVARCHAR; +This driver implements workarounds for C and C columns, and +L support for C columns. - return; -} +=head1 EXAMPLE DSN -sub sqlt_type { 'ACCESS' } + dbi:ODBC:driver={Microsoft Access Driver (*.mdb, *.accdb)};dbq=C:\Users\rkitover\Documents\access_sample.accdb -1; +=head1 TEXT/IMAGE/MEMO COLUMNS -=head1 NAME +Avoid using C columns as they will be truncated to 255 bytes. Some other +drivers (like L) will automatically +convert C columns to C, but the ODBC driver does not. -DBIx::Class::Storage::DBI::ODBC::ACCESS - Support specific to MS Access over ODBC +C columns work correctly, but the statements for inserting or updating an +C column will not be L, due to a bug in the +Access ODBC driver. -=head1 WARNING +C columns work correctly as well, but you must take care to set +L to C<$max_memo_size * 2 + 1>. This is done for +you automatically if you pass L in your +L; but if you set this +attribute directly on the C<$dbh>, keep this limitation in mind. -I am not a DBI, DBIx::Class or MS Access guru. Use this module with that in -mind. +=cut -This module is currently considered alpha software and can change without notice. +# set LongReadLen = LongReadLen * 2 + 1 (see docs on MEMO) +sub _run_connection_actions { + my $self = shift; -=head1 DESCRIPTION + my $long_read_len = $self->_dbh->{LongReadLen}; -This class implements support specific to Microsoft Access over ODBC. + # 80 is another default (just like 0) on some drivers + if ($long_read_len != 0 && $long_read_len != 80) { + $self->_dbh->{LongReadLen} = $long_read_len * 2 + 1; + } -It is loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it -detects a MS Access back-end. + return $self->next::method(@_); +} -=head1 SUPPORTED VERSIONS +sub insert { + my $self = shift; + my ($source, $to_insert) = @_; -This module have currently only been tested on MS Access 2003 using the Jet 4.0 engine. + my $columns_info = $source->columns_info; -As far as my knowledge it should work on MS Access 2000 or later, but that have not been tested. -Information about support for different version of MS Access is welcome. + my $is_image_insert = 0; -=head1 IMPLEMENTATION NOTES + for my $col (keys %$to_insert) { + if ($self->_is_binary_lob_type($columns_info->{$col}{data_type})) { + $is_image_insert = 1; + last; + } + } -MS Access supports the @@IDENTITY function for retrieving the id of the latest inserted row. -@@IDENTITY is global to the connection, so to support the possibility of getting the last inserted -id for different tables, the insert() function stores the inserted id on a per table basis. -last_insert_id() then just returns the stored value. + local $self->{disable_sth_caching} = 1 if $is_image_insert + && $self->disable_sth_caching_for_image_insert_or_update; -=head1 KNOWN ACCESS PROBLEMS + return $self->next::method(@_); +} -=over +sub update { + my $self = shift; + my ($source, $fields) = @_; -=item Invalid precision value + my $columns_info = $source->columns_info; -This error message is received when trying to store more than 255 characters in a MEMO field. -The problem is (to my knowledge) an error in the MS Access ODBC driver. The problem is fixed -by setting the C of the column to C in C. -C is a constant in the C module. + my $is_image_insert = 0; -=back + for my $col (keys %$fields) { + if ($self->_is_binary_lob_type($columns_info->{$col}{data_type})) { + $is_image_insert = 1; + last; + } + } -=head1 IMPLEMENTED FUNCTIONS + local $self->{disable_sth_caching} = 1 if $is_image_insert + && $self->disable_sth_caching_for_image_insert_or_update; -=head2 bind_attribute_by_data_type + return $self->next::method(@_); +} -This function currently supports the SQL_LONGVARCHAR column type. +sub datetime_parser_type { + 'DBIx::Class::Storage::DBI::ODBC::ACCESS::DateTime::Format' +} -=head2 insert +package # hide from PAUSE + DBIx::Class::Storage::DBI::ODBC::ACCESS::DateTime::Format; -=head2 last_insert_id +my $datetime_format = '%Y-%m-%d %H:%M:%S'; # %F %T, no fractional part +my $datetime_parser; -=head2 sqlt_type +sub parse_datetime { + shift; + require DateTime::Format::Strptime; + $datetime_parser ||= DateTime::Format::Strptime->new( + pattern => $datetime_format, + on_error => 'croak', + ); + return $datetime_parser->parse_datetime(shift); +} -=head1 BUGS +sub format_datetime { + shift; + require DateTime::Format::Strptime; + $datetime_parser ||= DateTime::Format::Strptime->new( + pattern => $datetime_format, + on_error => 'croak', + ); + return $datetime_parser->format_datetime(shift); +} -Most likely. Bug reports are welcome. +1; -=head1 AUTHORS +=head1 AUTHOR -Øystein Torget C<< >> +See L and L. -=head1 COPYRIGHT +=head1 LICENSE You may distribute this code under the same terms as Perl itself. -Det Norske Veritas AS (DNV) - -http://www.dnv.com - =cut - +# vim:sts=2 sw=2: