From: Rafael Kitover <rkitover@cpan.org> Date: Fri, 24 Jul 2009 05:52:33 +0000 (+0000) Subject: revert odbc/mssql code to trunk and move it to another branch X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=87f5bd814474ed1ca0b3b46d9b7dce29b4e419ce;p=dbsrgits%2FDBIx-Class-Historic.git revert odbc/mssql code to trunk and move it to another branch --- diff --git a/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm b/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm index 9757eca..48f281b 100644 --- a/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm +++ b/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm @@ -4,146 +4,8 @@ use warnings; use base qw/DBIx::Class::Storage::DBI::MSSQL/; use mro 'c3'; -use Carp::Clan qw/^DBIx::Class/; -use List::Util(); - -__PACKAGE__->mk_group_accessors(simple => qw/ - _identity _using_dynamic_cursors -/); - -=head1 NAME - -DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific -to Microsoft SQL Server over ODBC - -=head1 DESCRIPTION - -This class implements support specific to Microsoft SQL Server over ODBC, -including auto-increment primary keys and SQL::Abstract::Limit dialect. It -is loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it -detects a MSSQL back-end. - -=head1 IMPLEMENTATION NOTES - -Microsoft SQL Server supports three methods of retrieving the C<IDENTITY> -value for inserted row: C<IDENT_CURRENT>, C<@@IDENTITY>, and C<SCOPE_IDENTITY()>. -C<SCOPE_IDENTITY()> is used here because it is the safest. However, it must -be called is the same execute statement, not just the same connection. - -So, this implementation appends a C<SELECT SCOPE_IDENTITY()> statement -onto each C<INSERT> to accommodate that requirement. - -If you use dynamic cursors with C<< odbc_cursortype => 2 >> or -L</on_connect_call_use_dynamic_cursors> then the less accurate -C<SELECT @@IDENTITY> is used instead. - -=head1 MULTIPLE ACTIVE STATEMENTS - -The following options are alternative ways to enable concurrent executing -statement support. Each has its own advantages and drawbacks. - -=head2 connect_call_use_dynamic_cursors - -Use as: - - on_connect_call => 'use_dynamic_cursors' - -in your L<DBIx::Class::Storage::DBI/connect_info> as one way to enable multiple -concurrent statements. - -Will add C<< odbc_cursortype => 2 >> to your DBI connection attributes. See -L<DBD::ODBC/odbc_cursortype> for more information. - -This will not work with CODE ref connect_info's and will do nothing if you set -C<odbc_cursortype> yourself. - -B<WARNING:> this will break C<SCOPE_IDENTITY()>, and C<SELECT @@IDENTITY> will -be used instead, which on SQL Server 2005 and later will return erroneous -results on tables which have an on insert trigger that inserts into another -table with an C<IDENTITY> column. - -=cut - -sub connect_call_use_dynamic_cursors { - my $self = shift; - - if (ref($self->_dbi_connect_info->[0]) eq 'CODE') { - croak 'cannot set DBI attributes on a CODE ref connect_info'; - } - - my $dbi_attrs = $self->_dbi_connect_info->[-1]; - $dbi_attrs ||= {}; - - if (not exists $dbi_attrs->{odbc_cursortype}) { - # turn on support for multiple concurrent statements, unless overridden - $self->_dbi_connect_info->[-1] = { %$dbi_attrs, odbc_cursortype => 2 }; - my $connected = defined $self->_dbh; - $self->disconnect; - $self->ensure_connected if $connected; - $self->_using_dynamic_cursors(1); - } -} - -sub _rebless { - no warnings 'uninitialized'; - my $self = shift; - - if (ref($self->_dbi_connect_info->[0]) ne 'CODE' && - $self->_dbi_connect_info->[-1]{odbc_cursortype} == 2) { - $self->_using_dynamic_cursors(1); - return; - } - - $self->_using_dynamic_cursors(0); -} -=head2 connect_call_use_server_cursors - -Use as: - - on_connect_call => 'use_server_cursors' - -May allow multiple active select statements. See -L<DBD::ODBC/odbc_SQL_ROWSET_SIZE> for more information. - -Takes an optional parameter for the value to set the attribute to, default is -C<2>. - -B<WARNING>: this does not work on all versions of SQL Server, and may lock up -your database! - -=cut - -=head2 connect_call_use_mars - -Use as: - - on_connect_call => 'use_mars' - -Use to enable a feature of SQL Server 2005 and later, "Multiple Active Result -Sets". See L<DBD::ODBC::FAQ/Does DBD::ODBC support Multiple Active Statements?> -for more information. - -B<WARNING>: This has implications for the way transactions are handled. - -=cut - -sub connect_call_use_mars { - my $self = shift; - - my $dsn = $self->_dbi_connect_info->[0]; - - if (ref($dsn) eq 'CODE') { - croak 'cannot change the DBI DSN on a CODE ref connect_info'; - } - - if ($dsn !~ /MARS_Connection=/) { - $self->_dbi_connect_info->[0] = "$dsn;MARS_Connection=Yes"; - my $connected = defined $self->_dbh; - $self->disconnect; - $self->ensure_connected if $connected; - } -} +use List::Util(); sub insert_bulk { my $self = shift; @@ -161,14 +23,14 @@ sub insert_bulk { if ($identity_insert) { my $table = $source->from; - $self->_get_dbh->do("SET IDENTITY_INSERT $table ON"); + $self->dbh->do("SET IDENTITY_INSERT $table ON"); } $self->next::method(@_); if ($identity_insert) { my $table = $source->from; - $self->_get_dbh->do("SET IDENTITY_INSERT $table OFF"); + $self->dbh->do("SET IDENTITY_INSERT $table OFF"); } } @@ -213,31 +75,48 @@ sub _execute { my ($rv, $sth, @bind) = $self->dbh_do($self->can('_dbh_execute'), @_); if ($op eq 'insert') { - my ($identity) = $sth->fetchrow_array; + $self->{_scope_identity} = $sth->fetchrow_array; $sth->finish; - - if ((not defined $identity) && $self->_using_dynamic_cursors) { - ($identity) = $self->_dbh->selectrow_array('select @@identity'); - } - - $self->_identity($identity); } return wantarray ? ($rv, $sth, @bind) : $rv; } -sub last_insert_id { shift->_identity() } +sub last_insert_id { shift->{_scope_identity} } 1; -=head1 AUTHOR +__END__ + +=head1 NAME + +DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific +to Microsoft SQL Server over ODBC + +=head1 DESCRIPTION + +This class implements support specific to Microsoft SQL Server over ODBC, +including auto-increment primary keys and SQL::Abstract::Limit dialect. It +is loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it +detects a MSSQL back-end. -See L<DBIx::Class/CONTRIBUTORS>. +=head1 IMPLEMENTATION NOTES + +Microsoft SQL Server supports three methods of retrieving the IDENTITY +value for inserted row: IDENT_CURRENT, @@IDENTITY, and SCOPE_IDENTITY(). +SCOPE_IDENTITY is used here because it is the safest. However, it must +be called is the same execute statement, not just the same connection. + +So, this implementation appends a SELECT SCOPE_IDENTITY() statement +onto each INSERT to accommodate that requirement. + +=head1 AUTHORS + +Marc Mims C<< <marc@questright.com> >> =head1 LICENSE You may distribute this code under the same terms as Perl itself. =cut - # vim: sw=2 sts=2