Centralize (and privatize) handling of freetds driver/version detection
Peter Rabbitson [Fri, 23 Mar 2012 09:38:18 +0000 (10:38 +0100)]
lib/DBIx/Class/Storage/DBI/ODBC.pm
lib/DBIx/Class/Storage/DBI/ODBC/DB2_400_SQL.pm
lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm
lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm
lib/DBIx/Class/Storage/DBI/ODBC/SQL_Anywhere.pm
lib/DBIx/Class/Storage/DBI/Sybase.pm
lib/DBIx/Class/Storage/DBI/Sybase/ASE.pm
t/746mssql.t
t/746sybase.t

index fec6613..65bc811 100644 (file)
@@ -28,6 +28,29 @@ sub _rebless {
   }
 }
 
+# Whether or not we are connecting via the freetds ODBC driver.
+sub _using_freetds {
+  my $self = shift;
+
+  my $dsn = $self->_dbi_connect_info->[0];
+
+  return 1 if (
+    ( (! ref $dsn) and $dsn =~ /driver=FreeTDS/i)
+      or
+    ( ($self->_dbh_get_info('SQL_DRIVER_NAME')||'') =~ /tdsodbc/i )
+  );
+
+  return 0;
+}
+
+# Either returns the FreeTDS version via which we are connecting, 0 if can't
+# be determined, or undef otherwise
+sub _using_freetds_version {
+  my $self = shift;
+  return undef unless $self->_using_freetds;
+  return $self->_dbh_get_info('SQL_DRIVER_VER') || 0;
+}
+
 1;
 
 =head1 NAME
index 8888a8e..e17715c 100644 (file)
@@ -4,8 +4,8 @@ use strict;
 use warnings;
 
 use base qw/
-    DBIx::Class::Storage::DBI::DB2
     DBIx::Class::Storage::DBI::ODBC
+    DBIx::Class::Storage::DBI::DB2
 /;
 use mro 'c3';
 
index 133dcc1..9067290 100644 (file)
@@ -2,7 +2,10 @@ package DBIx::Class::Storage::DBI::ODBC::Firebird;
 
 use strict;
 use warnings;
-use base 'DBIx::Class::Storage::DBI::Firebird::Common';
+use base qw/
+  DBIx::Class::Storage::DBI::ODBC
+  DBIx::Class::Storage::DBI::Firebird::Common
+/;
 use mro 'c3';
 use Try::Tiny;
 use namespace::clean;
index afd51f3..c11634d 100644 (file)
@@ -2,7 +2,10 @@ 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;
@@ -124,7 +127,7 @@ sub connect_call_use_mars {
   }
 
   if ($dsn !~ /MARS_Connection=/) {
-    if ($self->using_freetds) {
+    if ($self->_using_freetds) {
       $self->throw_exception('FreeTDS does not support MARS at the time of '
                             .'writing.');
     }
@@ -226,7 +229,7 @@ sub _run_connection_actions {
         $self->throw_exception (
           'Your drivers do not seem to support dynamic cursors (odbc_cursortype => 2).'
          . (
-          $self->using_freetds
+          $self->_using_freetds
             ? ' If you are using FreeTDS, make sure to set tds_version to 8.0 or greater.'
             : ''
           )
@@ -235,7 +238,7 @@ sub _run_connection_actions {
 
       $self->_using_dynamic_cursors(1);
       $self->_identity_method('@@identity');
-      $self->_no_scope_identity_query($self->using_freetds);
+      $self->_no_scope_identity_query($self->_using_freetds);
     }
     else {
       $self->_using_dynamic_cursors(0);
@@ -247,11 +250,11 @@ sub _run_connection_actions {
   $self->next::method (@_);
 
   # freetds is too damn broken, some fixups
-  if ($self->using_freetds) {
+  if ($self->_using_freetds) {
 
     # no dynamic cursors starting from 0.83
     if ($self->_using_dynamic_cursors) {
-      my $fv = $self->_dbh_get_info('SQL_DRIVER_VER');
+      my $fv = $self->_using_freetds_version || 999;  # assume large if can't be determined
       $self->throw_exception(
         'Dynamic cursors (odbc_cursortype => 2) are not supported with FreeTDS > 0.82 '
       . "(you have $fv). Please hassle FreeTDS authors to fix the outstanding bugs in "
@@ -297,26 +300,6 @@ sub connect_call_use_server_cursors {
   $self->_get_dbh->{odbc_SQL_ROWSET_SIZE} = $sql_rowset_size;
 }
 
-=head2 using_freetds
-
-Tries to determine, to the best of our ability, whether or not you are using the
-FreeTDS driver with L<DBD::ODBC>.
-
-=cut
-
-sub using_freetds {
-  my $self = shift;
-
-  my $dsn = $self->_dbi_connect_info->[0];
-
-  $dsn = '' if ref $dsn eq 'CODE';
-
-  return 1 if $dsn =~ /driver=FreeTDS/i
-              || ($self->_dbh_get_info('SQL_DRIVER_NAME')||'') =~ /tdsodbc/i;
-
-  return 0;
-}
-
 1;
 
 =head1 AUTHOR
index d40029e..0a6bd1a 100644 (file)
@@ -2,7 +2,10 @@ package DBIx::Class::Storage::DBI::ODBC::SQL_Anywhere;
 
 use strict;
 use warnings;
-use base qw/DBIx::Class::Storage::DBI::SQLAnywhere/;
+use base qw/
+  DBIx::Class::Storage::DBI::ODBC
+  DBIx::Class::Storage::DBI::SQLAnywhere
+/;
 use mro 'c3';
 
 1;
index 901cf0a..32f7996 100644 (file)
@@ -49,7 +49,7 @@ sub _init {
   # once the driver is determined see if we need to insert the DBD::Sybase w/ FreeTDS fixups
   # this is a dirty version of "instance role application", \o/ DO WANT Moo \o/
   my $self = shift;
-  if (! $self->isa('DBIx::Class::Storage::DBI::Sybase::FreeTDS') and $self->using_freetds) {
+  if (! $self->isa('DBIx::Class::Storage::DBI::Sybase::FreeTDS') and $self->_using_freetds) {
     require DBIx::Class::Storage::DBI::Sybase::FreeTDS;
 
     my @isa = @{mro::get_linear_isa(ref $self)};
@@ -117,19 +117,21 @@ sub _set_max_connect {
   }
 }
 
-=head2 using_freetds
-
-Whether or not L<DBD::Sybase> was compiled against FreeTDS. If false, it means
-the Sybase OpenClient libraries were used.
-
-=cut
-
-sub using_freetds {
+# Whether or not DBD::Sybase was compiled against FreeTDS. If false, it means
+# the Sybase OpenClient libraries were used.
+sub _using_freetds {
   my $self = shift;
-
   return ($self->_get_dbh->{syb_oc_version}||'') =~ /freetds/i;
 }
 
+# Either returns the FreeTDS version against which DBD::Sybase was compiled,
+# 0 if can't be determined, or undef otherwise
+sub _using_freetds_version {
+  my $inf = shift->_get_dbh->{syb_oc_version};
+  return undef unless ($inf||'') =~ /freetds/i;
+  return $inf =~ /v([0-9\.]+)/ ? $1 : 0;
+}
+
 1;
 
 =head1 AUTHORS
index 25c407a..17a7690 100644 (file)
@@ -73,7 +73,7 @@ sub _rebless {
 
   my $no_bind_vars = __PACKAGE__ . '::NoBindVars';
 
-  if ($self->using_freetds) {
+  if ($self->_using_freetds) {
     carp_once <<'EOF' unless $ENV{DBIC_SYBASE_FREETDS_NOWARN};
 
 You are using FreeTDS with Sybase.
@@ -202,7 +202,7 @@ sub _run_connection_actions {
   }
 
   $self->_dbh->{syb_chained_txn} = 1
-    unless $self->using_freetds;
+    unless $self->_using_freetds;
 
   $self->next::method(@_);
 }
@@ -804,7 +804,7 @@ sub _insert_blobs {
       $sth->func('ct_finish_send') or die $sth->errstr;
     }
     catch {
-      if ($self->using_freetds) {
+      if ($self->_using_freetds) {
         $self->throw_exception (
           "TEXT/IMAGE operation failed, probably because you are using FreeTDS: $_"
         );
@@ -958,7 +958,7 @@ L<http://www.isug.com/Sybase_FAQ/ASE/section7.html>.
 Sybase ASE for Linux (which comes with the Open Client libraries) may be
 downloaded here: L<http://response.sybase.com/forms/ASE_Linux_Download>.
 
-To see if you're using FreeTDS check C<< $schema->storage->using_freetds >>, or run:
+To see if you're using FreeTDS run:
 
   perl -MDBI -le 'my $dbh = DBI->connect($dsn, $user, $pass); print $dbh->{syb_oc_version}'
 
index 403d75c..0193753 100644 (file)
@@ -58,7 +58,7 @@ my %opts = (
     { opts => { on_connect_call => 'use_mars' } },
   use_dynamic_cursors =>
     { opts => { on_connect_call => 'use_dynamic_cursors' },
-      required => $schema->storage->using_freetds ? 0 : 1,
+      required => $schema->storage->_using_freetds ? 0 : 1,
     },
   use_server_cursors =>
     { opts => { on_connect_call => 'use_server_cursors' } },
@@ -511,7 +511,7 @@ SQL
       TODO: {
         my $freetds_and_dynamic_cursors = 1
           if $opts_name eq 'use_dynamic_cursors' &&
-            $schema->storage->using_freetds;
+            $schema->storage->_using_freetds;
 
         local $TODO =
 'these tests fail on freetds with dynamic cursors for some reason'
index 5936e47..43e2ab5 100644 (file)
@@ -335,7 +335,7 @@ SQL
 # mostly stolen from the blob stuff Nniuq wrote for t/73oracle.t
   SKIP: {
     skip 'TEXT/IMAGE support does not work with FreeTDS', 22
-      if $schema->storage->using_freetds;
+      if $schema->storage->_using_freetds;
 
     my $dbh = $schema->storage->_dbh;
     {
@@ -359,7 +359,7 @@ SQL
 
     my $maxloblen = length $binstr{'large'};
 
-    if (not $schema->storage->using_freetds) {
+    if (not $schema->storage->_using_freetds) {
       $dbh->{'LongReadLen'} = $maxloblen * 2;
     } else {
       $dbh->do("set textsize ".($maxloblen * 2));