X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI%2FODBC%2FMicrosoft_SQL_Server.pm;h=17131388892cf3b852d8a4b578ffcfcd61950882;hb=a2bd379666d729133d65c85dc775627937084b18;hp=4383e4dc6c1068397d90af06501a80831d11cce8;hpb=134a3bb99c31b216ef74f50264458db6c09ba61f;p=dbsrgits%2FDBIx-Class.git 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 4383e4d..1713138 100644 --- a/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm +++ b/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm @@ -2,109 +2,325 @@ package DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server; use strict; use warnings; -use base qw/DBIx::Class::Storage::DBI::MSSQL/; +use base qw/ + DBIx::Class::Storage::DBI::ODBC + DBIx::Class::Storage::DBI::MSSQL +/; +use mro 'c3'; +use Scalar::Util 'reftype'; +use Try::Tiny; +use DBIx::Class::Carp; +use namespace::clean; + +__PACKAGE__->mk_group_accessors(simple => qw/ + _using_dynamic_cursors +/); -sub insert_bulk { - my ($self, $source, $cols, $data) = @_; +=head1 NAME - my $identity_insert = 0; +DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific +to Microsoft SQL Server over ODBC - COLUMNS: - foreach my $col (@{$cols}) { - if ($source->column_info($col)->{is_auto_increment}) { - $identity_insert = 1; - last COLUMNS; - } - } +=head1 DESCRIPTION - my $table = $source->from; - $source->storage->dbh_do(sub { - my ($storage, $dbh, @cols) = @_; - $dbh->do("SET IDENTITY_INSERT $table ON;"); - }); +This class implements support specific to Microsoft SQL Server over ODBC. It is +loaded automatically by DBIx::Class::Storage::DBI::ODBC when it detects a +MSSQL back-end. - next::method(@_); +Most of the functionality is provided from the superclass +L. - $source->storage->dbh_do(sub { - my ($storage, $dbh, @cols) = @_; - $dbh->do("SET IDENTITY_INSERT $table OFF;"); - }); +=head1 USAGE NOTES -} +=head2 Basic Linux Setup (Debian) + + sudo aptitude install tdsodbc libdbd-odbc-perl unixodbc + +In case it is not already there put the following (adjust for non-64bit arch) in +C: + + [FreeTDS] + Description = FreeTDS + Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so + Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so + UsageCount = 1 + +Set your C<$dsn> in L as follows: + + dbi:ODBC:server=;port=1433;driver=FreeTDS;tds_version=8.0 + +If you use the EasySoft driver (L): + + dbi:ODBC:server=;port=1433;driver=Easysoft ODBC-SQL Server + +=head2 Basic Windows Setup + +Use the following C<$dsn> for the Microsoft ODBC driver: + + dbi:ODBC:driver={SQL Server};server=SERVER\SQL_SERVER_INSTANCE_NAME + +And for the Native Client: + + dbi:ODBC:driver={SQL Server Native Client 10.0};server=SERVER\SQL_SERVER_INSTANCE_NAME + +Go into Control Panel -> System and Security -> Administrative Tools -> Data +Sources (ODBC) to check driver names and to set up data sources. + +Use System DSNs, not User DSNs if you want to use DSNs. + +If you set up a DSN, use the following C<$dsn> for +L: + + dbi:ODBC:dsn=MY_DSN -sub _prep_for_execute { +=head1 MULTIPLE ACTIVE STATEMENTS + +The following options are alternative ways to enable concurrent executing +statement support. Each has its own advantages and drawbacks and works on +different platforms. Read each section carefully. + +For more details about using MAS in MSSQL over DBD::ODBC see this excellent +document provided by EasySoft: +L. + +In order of preference, they are: + +=over 8 + +=item * L + +=item * L + +=item * L + +=back + +=head1 METHODS + +=head2 connect_call_use_mars + +Use as: + + on_connect_call => 'use_mars' + +in your connection info, or alternatively specify it directly: + + Your::Schema->connect ( + $original_dsn . '; MARS_Connection=Yes', + $user, + $pass, + \%attrs, + ) + +Use to enable a feature of SQL Server 2005 and later, "Multiple Active Result +Sets". See L +for more information. + +This does not work on FreeTDS drivers at the time of this writing, and only +works with the Native Client, later versions of the Windows MS ODBC driver, and +the Easysoft driver. + +=cut + +sub connect_call_use_mars { my $self = shift; - my ($op, $extra_bind, $ident, $args) = @_; - my ($sql, $bind) = $self->next::method (@_); - $sql .= ';SELECT SCOPE_IDENTITY()' if $op eq 'insert'; + my $dsn = $self->_dbi_connect_info->[0]; - my %identity_insert_tables; - my $col_info = $self->_resolve_column_info($ident, [map $_->[0], @{$bind}]); + if (ref($dsn) eq 'CODE') { + $self->throw_exception('cannot change the DBI DSN on a CODE ref connect_info'); + } + + if ($dsn !~ /MARS_Connection=/) { + if ($self->_using_freetds) { + $self->throw_exception('FreeTDS does not support MARS at the time of ' + .'writing.'); + } - foreach my $bound (@{$bind}) { - my $col = $bound->[0]; - if ($col_info->{$col}->{is_auto_increment}) { - my $table = $col_info->{$col}->{-result_source}->from; - $identity_insert_tables{$table} = 1; + if (exists $self->_server_info->{normalized_dbms_version} && + $self->_server_info->{normalized_dbms_version} < 9) { + $self->throw_exception('SQL Server 2005 or later required to use MARS.'); } + + if (my ($data_source) = $dsn =~ /^dbi:ODBC:([\w-]+)\z/i) { # prefix with DSN + carp_unique "Bare DSN in ODBC connect string, rewriting as 'dsn=$data_source'" + ." for MARS\n"; + $dsn = "dbi:ODBC:dsn=$data_source"; + } + + $self->_dbi_connect_info->[0] = "$dsn;MARS_Connection=Yes"; + $self->disconnect; + $self->ensure_connected; } +} + +sub connect_call_use_MARS { + carp "'connect_call_use_MARS' has been deprecated, use " + ."'connect_call_use_mars' instead."; + shift->connect_call_use_mars(@_) +} + +=head2 connect_call_use_dynamic_cursors + +Use as: + + on_connect_call => 'use_dynamic_cursors' + +Which will add C<< odbc_cursortype => 2 >> to your DBI connection +attributes, or alternatively specify the necessary flag directly: + + Your::Schema->connect (@dsn, { ... odbc_cursortype => 2 }) + +See L for more information. + +If you're using FreeTDS, C must be set to at least C<8.0>. + +This will not work with CODE ref connect_info's. + +B on FreeTDS (and maybe some other drivers) this will break +C, and C