Another overhaul of transaction/savepoint handling
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / ACCESS.pm
CommitLineData
726c8f65 1package DBIx::Class::Storage::DBI::ACCESS;
2
3use strict;
4use warnings;
5use base 'DBIx::Class::Storage::DBI::UniqueIdentifier';
6use mro 'c3';
7
8use List::Util 'first';
9use namespace::clean;
10
11__PACKAGE__->sql_limit_dialect ('Top');
12__PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::ACCESS');
13__PACKAGE__->sql_quote_char ([qw/[ ]/]);
14
15sub sqlt_type { 'ACCESS' }
16
17__PACKAGE__->new_guid(undef);
18
19=head1 NAME
20
21DBIx::Class::Storage::DBI::ACCESS - Support specific to MS Access
22
23=head1 DESCRIPTION
24
25This is the base class for Microsoft Access support.
26
27This driver supports L<last_insert_id|DBIx::Class::Storage::DBI/last_insert_id>,
28empty inserts for tables with C<AUTOINCREMENT> columns, nested transactions via
29L<auto_savepoint|DBIx::Class::Storage::DBI/auto_savepoint>, C<GUID> columns via
30L<DBIx::Class::Storage::DBI::UniqueIdentifier>.
31
32=head1 SUPPORTED VERSIONS
33
34This module has currently only been tested on MS Access 2010.
35
36Information about how well it works on different version of MS Access is welcome
37(write the mailing list, or submit a ticket to RT if you find bugs.)
38
39=head1 USING GUID COLUMNS
40
41If you have C<GUID> PKs or other C<GUID> columns with
42L<auto_nextval|DBIx::Class::ResultSource/auto_nextval> you will need to set a
43L<new_guid|DBIx::Class::Storage::DBI::UniqueIdentifier/new_guid> callback, like
44so:
45
46 $schema->storage->new_guid(sub { Data::GUID->new->as_string });
47
48Under L<Catalyst> you can use code similar to this in your
49L<Catalyst::Model::DBIC::Schema> C<Model.pm>:
50
51 after BUILD => sub {
52 my $self = shift;
53 $self->storage->new_guid(sub { Data::GUID->new->as_string });
54 };
55
56=cut
57
58sub _dbh_last_insert_id { $_[1]->selectrow_array('select @@identity') }
59
60# support empty insert
61sub insert {
62 my $self = shift;
63 my ($source, $to_insert) = @_;
64
65 my $columns_info = $source->columns_info;
66
67 if (keys %$to_insert == 0) {
68 my $autoinc_col = first {
69 $columns_info->{$_}{is_auto_increment}
70 } keys %$columns_info;
71
72 if (not $autoinc_col) {
73 $self->throw_exception(
74'empty insert only supported for tables with an autoincrement column'
75 );
76 }
77
78 my $table = $source->from;
79 $table = $$table if ref $table;
80
81 $to_insert->{$autoinc_col} = \"dmax('${autoinc_col}', '${table}')+1";
82 }
83
84 return $self->next::method(@_);
85}
86
87sub bind_attribute_by_data_type {
88 my $self = shift;
89 my ($data_type) = @_;
90
91 my $attributes = $self->next::method(@_) || {};
92
93 if ($self->_is_text_lob_type($data_type)) {
94 $attributes->{TYPE} = DBI::SQL_LONGVARCHAR;
95 }
96 elsif ($self->_is_binary_lob_type($data_type)) {
97 $attributes->{TYPE} = DBI::SQL_LONGVARBINARY;
98 }
99
100 return $attributes;
101}
102
103# savepoints are not supported, but nested transactions are.
104# Unfortunately DBI does not support nested transactions.
105# WARNING: this code uses the undocumented 'BegunWork' DBI attribute.
106
90d7422f 107sub _exec_svp_begin {
726c8f65 108 my ($self, $name) = @_;
109
726c8f65 110 local $self->_dbh->{AutoCommit} = 1;
111 local $self->_dbh->{BegunWork} = 0;
90d7422f 112 $self->_exec_txn_begin;
726c8f65 113}
114
115# A new nested transaction on the same level releases the previous one.
90d7422f 116sub _exec_svp_release { 1 }
726c8f65 117
90d7422f 118sub _exec_svp_rollback {
726c8f65 119 my ($self, $name) = @_;
120
726c8f65 121 local $self->_dbh->{AutoCommit} = 0;
122 local $self->_dbh->{BegunWork} = 1;
90d7422f 123 $self->_exec_txn_rollback;
726c8f65 124}
125
1261;
127
128=head1 AUTHOR
129
130See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
131
132=head1 LICENSE
133
134You may distribute this code under the same terms as Perl itself.
135
136=cut
137# vim:sts=2 sw=2: