revert odbc/mssql code to trunk and move it to another branch
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / ODBC / Microsoft_SQL_Server.pm
CommitLineData
c1cac633 1package DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server;
2use strict;
3use warnings;
4
eb0323df 5use base qw/DBIx::Class::Storage::DBI::MSSQL/;
2ad62d97 6use mro 'c3';
ef131d82 7
87f5bd81 8use List::Util();
18ac986d 9
c7963907 10sub insert_bulk {
76212d30 11 my $self = shift;
12 my ($source, $cols, $data) = @_;
134a3bb9 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
05f7f61a 24 if ($identity_insert) {
893403c8 25 my $table = $source->from;
87f5bd81 26 $self->dbh->do("SET IDENTITY_INSERT $table ON");
05f7f61a 27 }
134a3bb9 28
76212d30 29 $self->next::method(@_);
134a3bb9 30
05f7f61a 31 if ($identity_insert) {
893403c8 32 my $table = $source->from;
87f5bd81 33 $self->dbh->do("SET IDENTITY_INSERT $table OFF");
05f7f61a 34 }
c7963907 35}
36
c1cac633 37sub _prep_for_execute {
259c0e40 38 my $self = shift;
39 my ($op, $extra_bind, $ident, $args) = @_;
40
d68f21ee 41# cast MONEY values properly
42 if ($op eq 'insert' || $op eq 'update') {
43 my $fields = $args->[0];
44 my $col_info = $self->_resolve_column_info($ident, [keys %$fields]);
45
34ff59bb 46 for my $col (keys %$fields) {
f6b185e1 47 if ($col_info->{$col}{data_type} =~ /^money\z/i) {
d68f21ee 48 my $val = $fields->{$col};
d68f21ee 49 $fields->{$col} = \['CAST(? AS MONEY)', [ $col => $val ]];
50 }
51 }
52 }
53
259c0e40 54 my ($sql, $bind) = $self->next::method (@_);
259c0e40 55
893403c8 56 if ($op eq 'insert') {
57 $sql .= ';SELECT SCOPE_IDENTITY()';
58
59 my $col_info = $self->_resolve_column_info($ident, [map $_->[0], @{$bind}]);
60 if (List::Util::first { $_->{is_auto_increment} } (values %$col_info) ) {
764a1b60 61
893403c8 62 my $table = $ident->from;
63 my $identity_insert_on = "SET IDENTITY_INSERT $table ON";
64 my $identity_insert_off = "SET IDENTITY_INSERT $table OFF";
65 $sql = "$identity_insert_on; $sql; $identity_insert_off";
259c0e40 66 }
67 }
c1cac633 68
259c0e40 69 return ($sql, $bind);
c1cac633 70}
71
2eebd801 72sub _execute {
73 my $self = shift;
74 my ($op) = @_;
c1cac633 75
2eebd801 76 my ($rv, $sth, @bind) = $self->dbh_do($self->can('_dbh_execute'), @_);
77af494b 77 if ($op eq 'insert') {
87f5bd81 78 $self->{_scope_identity} = $sth->fetchrow_array;
77af494b 79 $sth->finish;
80 }
c1cac633 81
2eebd801 82 return wantarray ? ($rv, $sth, @bind) : $rv;
c1cac633 83}
84
87f5bd81 85sub last_insert_id { shift->{_scope_identity} }
c1cac633 86
c1cac633 871;
88
87f5bd81 89__END__
90
91=head1 NAME
92
93DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific
94to Microsoft SQL Server over ODBC
95
96=head1 DESCRIPTION
97
98This class implements support specific to Microsoft SQL Server over ODBC,
99including auto-increment primary keys and SQL::Abstract::Limit dialect. It
100is loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it
101detects a MSSQL back-end.
c1cac633 102
87f5bd81 103=head1 IMPLEMENTATION NOTES
104
105Microsoft SQL Server supports three methods of retrieving the IDENTITY
106value for inserted row: IDENT_CURRENT, @@IDENTITY, and SCOPE_IDENTITY().
107SCOPE_IDENTITY is used here because it is the safest. However, it must
108be called is the same execute statement, not just the same connection.
109
110So, this implementation appends a SELECT SCOPE_IDENTITY() statement
111onto each INSERT to accommodate that requirement.
112
113=head1 AUTHORS
114
115Marc Mims C<< <marc@questright.com> >>
c1cac633 116
117=head1 LICENSE
118
119You may distribute this code under the same terms as Perl itself.
120
121=cut
259c0e40 122# vim: sw=2 sts=2