FW: [PATCH] Class::DBI with case sensitive columns

Ivor Williams <[email protected]>
Newsgroups gmane.comp.lang.perl.modules.dbi.sybase
Message-ID <[email protected]>
Cross posted from cDBI mailing list:

-----Original Message-----
From: Ivor Williams 
Sent: 03 March 2005 13:59
To: [email protected]
Subject: Re: [PATCH] using Class::DBI with Sybase

> On Mon, 21 Feb 2005 19:01:50 +0000, Tony Bowden wrote:

>> I'm not likely to apply either as they currently stand.
>> 
>> Mainly this is because they don't seem like the right thing, but this
>> may be in part because there's no test case that shows what's going on.
>> 
>> Even a little more explanation would be helpful.

> I agree that posting a patch was a tad premature.

> The purpose of the post(s) is to let people know that I am working on getting 
> Class::DBI to work with Sybase. 

> When I have everything working completely, I will include a test case.

Here comes: 

test case for Sybase or MSSQL (which both have case sensitive column names)

test.sql==============================================
create table TEST
(
  Nurgle  integer,
  fooBar  varchar(20),
  Foobar  varchar(20)
)

create unique index dongle on TEST (Nurgle)

insert into TEST (Nurgle,fooBar,Foobar)
values (1, 'Dingbat', 'Blurch')

test.pl===============================================
#!/usr/local/bin/perl

use warnings;

package Test::DBI;
use strict;
use base 'Class::DBI::Sybase';

$Class::DBI::Column::FetchHashKeyName = "NAME";

__PACKAGE__->connection('dbi:Sybase:server=SYBSRV;database=TST2','tst2','tst2', {
        RaiseError => 1,
        FetchHashKeyName => 'NAME',
        } );

__PACKAGE__->set_up_table('TEST');

package main;
use strict;


my $foo = Test::DBI->search( Nurgle => 1);
my $fobj = $foo->next;


for (qw/nurgle fooBar Foobar/) {
        print $fobj->$_,"\n";
}

======================================================

Try running this and you get the following result:

ct_result(ct_dynamic(CS_PREPARE)) returned -205 at /home/williami/lib/sun4-solaris/DBD/Sybase.pm line 133.
DBD::Sybase::db prepare_cached failed: Server message number=207 severity=16 state=4 line=1 server=SYBSRV procedure=DBD1 text=Invalid column name 'nurgle'.
Server message number=207 severity=16 state=4 line=1 server=SYBSRV procedure=DBD1 text=Invalid column name 'nurgle'.
 [for Statement "SELECT nurgle
FROM   TEST
WHERE  nurgle = ?
"] at /home/williami/lib/Ima/DBI.pm line 391.

Note that you also get a warning about $Class::DBI::Column::FetchHashKeyName
being only used once. But this is new functionality in my patch :).

Apply the patch and get the following output:

1
Dingbat
Blurch

I am looking to provide this as tests using Test::More and DBD::Mock
(so as to demonstrate the problem without needing a case sensitive DBD).

Patches follow:

--- Class-DBI-0.96/lib/Class/DBI.pm 
+++ lib/Class/DBI.pm 
@@ -1122,9 +1122,14 @@
        my (%data, @rows);
        eval {
                $sth->execute(@$args) unless $sth->{Active};
-               $sth->bind_columns(\(@data{ @{ $sth->{NAME_lc} } }));
+               $sth->bind_columns(\(@data{ @{ $sth->{$sth->{FetchHashKeyName}} } }));
                push @rows, {%data} while $sth->fetch;
        };
+       eval {
+               $sth->execute(@$args);
+               $sth->bind_columns(\(@data{ @{ $sth->{$sth->{FetchHashKeyName}} } }));
+               push @rows, {%data} while $sth->fetch;
+       } if $@;
        return $class->_croak("$class can't $sth->{Statement}: $@", err => $@)
                if $@;
        return $class->_ids_to_objects(\@rows);


--- Class-DBI-0.96/lib/Class/DBI/Column.pm 
+++ lib/Class/DBI/Column.pm 
@@ -56,7 +56,20 @@
        );
 }
 
-sub name_lc { lc shift->name }
+our $FetchHashKeyName = 'NAME_lc';
+ 
+sub name_lc { 
+       my $name = shift->name;
+       if ($FetchHashKeyName eq 'NAME_lc') {
+               lc $name;
+       }
+       elsif ($FetchHashKeyName eq 'NAME_uc') {
+               uc $name;
+       }
+       else {
+               $name;
+       }
+ }
 
 sub add_group {
        my ($self, $group) = @_;


--- Class-DBI-0.96/lib/Class/DBI/ColumnGrouper.pm 
+++ lib/Class/DBI/ColumnGrouper.pm 
@@ -77,16 +77,25 @@
 
 =cut
 
+sub _normalise {
+       my $name = shift;
+
+       my $fhkn = $Class::DBI::Column::FetchHashKeyName;
+
+       ($fhkn eq 'NAME') ? $name :
+       ($fhkn eq 'NAME_uc') ? uc($name) : lc($name);
+};
+
 sub add_column {
        my ($self, $name) = @_;
        return $name if ref $name;
-       $self->{_allcol}->{ lc $name } ||= Class::DBI::Column->new($name);
+       $self->{_allcol}->{ _normalise $name } ||= Class::DBI::Column->new($name);
 }
 
 sub find_column {
        my ($self, $name) = @_;
        return $name if ref $name;
-       return unless $self->{_allcol}->{ lc $name };
+       return unless $self->{_allcol}->{ _normalise $name };
 }
 
 =head2 add_group
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.