Switch to C3 mro throughout the ::Storage hierarchy (DBIx::Class brings in MRO::Compa...
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / ODBC / Microsoft_SQL_Server.pm
1 package DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server;
2 use strict;
3 use warnings;
4
5 use base qw/DBIx::Class::Storage::DBI::MSSQL/;
6 use mro 'c3';
7
8 use List::Util();
9
10 sub insert_bulk {
11   my $self = shift;
12   my ($source, $cols, $data) = @_;
13
14   my $identity_insert = 0;
15
16   COLUMNS:
17   foreach my $col (@{$cols}) {
18     if ($source->column_info($col)->{is_auto_increment}) {
19       $identity_insert = 1;
20       last COLUMNS;
21     }
22   }
23
24   if ($identity_insert) {
25     my $table = $source->from;
26     $self->dbh->do("SET IDENTITY_INSERT $table ON");
27   }
28
29   $self->next::method(@_);
30
31   if ($identity_insert) {
32     my $table = $source->from;
33     $self->dbh->do("SET IDENTITY_INSERT $table OFF");
34   }
35 }
36
37 sub _prep_for_execute {
38   my $self = shift;
39   my ($op, $extra_bind, $ident, $args) = @_;
40
41   my ($sql, $bind) = $self->next::method (@_);
42
43   if ($op eq 'insert') {
44     $sql .= ';SELECT SCOPE_IDENTITY()';
45
46     my $col_info = $self->_resolve_column_info($ident, [map $_->[0], @{$bind}]);
47     if (List::Util::first { $_->{is_auto_increment} } (values %$col_info) ) {
48
49       my $table = $ident->from;
50       my $identity_insert_on = "SET IDENTITY_INSERT $table ON";
51       my $identity_insert_off = "SET IDENTITY_INSERT $table OFF";
52       $sql = "$identity_insert_on; $sql; $identity_insert_off";
53     }
54   }
55
56   return ($sql, $bind);
57 }
58
59 sub _execute {
60     my $self = shift;
61     my ($op) = @_;
62
63     my ($rv, $sth, @bind) = $self->dbh_do($self->can('_dbh_execute'), @_);
64     if ($op eq 'insert') {
65       $self->{_scope_identity} = $sth->fetchrow_array;
66       $sth->finish;
67     }
68
69     return wantarray ? ($rv, $sth, @bind) : $rv;
70 }
71
72 sub last_insert_id { shift->{_scope_identity} }
73
74 1;
75
76 __END__
77
78 =head1 NAME
79
80 DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific
81 to Microsoft SQL Server over ODBC
82
83 =head1 DESCRIPTION
84
85 This class implements support specific to Microsoft SQL Server over ODBC,
86 including auto-increment primary keys and SQL::Abstract::Limit dialect.  It
87 is loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it
88 detects a MSSQL back-end.
89
90 =head1 IMPLEMENTATION NOTES
91
92 Microsoft SQL Server supports three methods of retrieving the IDENTITY
93 value for inserted row: IDENT_CURRENT, @@IDENTITY, and SCOPE_IDENTITY().
94 SCOPE_IDENTITY is used here because it is the safest.  However, it must
95 be called is the same execute statement, not just the same connection.
96
97 So, this implementation appends a SELECT SCOPE_IDENTITY() statement
98 onto each INSERT to accommodate that requirement.
99
100 =head1 AUTHORS
101
102 Marc Mims C<< <marc@questright.com> >>
103
104 =head1 LICENSE
105
106 You may distribute this code under the same terms as Perl itself.
107
108 =cut
109 # vim: sw=2 sts=2