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