Skip to content

Commit

Permalink
Centralize (and privatize) handling of freetds driver/version detection
Browse files Browse the repository at this point in the history
  • Loading branch information
ribasushi committed Mar 23, 2012
1 parent 25d3127 commit aca3b4c
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 47 deletions.
23 changes: 23 additions & 0 deletions lib/DBIx/Class/Storage/DBI/ODBC.pm
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/DBIx/Class/Storage/DBI/ODBC/DB2_400_SQL.pm
Expand Up @@ -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';

Expand Down
5 changes: 4 additions & 1 deletion lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm
Expand Up @@ -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;
Expand Down
35 changes: 9 additions & 26 deletions lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm
Expand Up @@ -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;
Expand Down Expand Up @@ -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.');
}
Expand Down Expand Up @@ -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.'
: ''
)
Expand All @@ -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);
Expand All @@ -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 "
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion lib/DBIx/Class/Storage/DBI/ODBC/SQL_Anywhere.pm
Expand Up @@ -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;
Expand Down
22 changes: 12 additions & 10 deletions lib/DBIx/Class/Storage/DBI/Sybase.pm
Expand Up @@ -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)};
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions lib/DBIx/Class/Storage/DBI/Sybase/ASE.pm
Expand Up @@ -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.
Expand Down Expand Up @@ -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(@_);
}
Expand Down Expand Up @@ -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: $_"
);
Expand Down Expand Up @@ -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}'
Expand Down
4 changes: 2 additions & 2 deletions t/746mssql.t
Expand Up @@ -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' } },
Expand Down Expand Up @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions t/746sybase.t
Expand Up @@ -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;
{
Expand All @@ -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));
Expand Down

0 comments on commit aca3b4c

Please sign in to comment.