> This is arguably a bug in DBD::mysql, but as far as RDBO is concerned,
For what it is worth, I dont think it is strictly DBD::mysql's fault, it is Mysql itself. http://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html It might be fixed with mysql 5.0.2, but I do not have that version around to test with. Unfortunately I ran into this problem this weekend, and hunted around until I found the doc above. -Cory On Wednesday 17 January 2007 7:01 am, John Siracusa wrote: > I'm forwarding this private email thread to the list with the > permission of the (now anonymized) sender because it's about an > unexpected situation that many RDBO users may face. Yes, it revolves > around yet another fun feature of MySQL/DBD::mysql. How did you > guess? :) > > Anyway, here it is, for posterity, the list archives, and ultimately, > google. > > -John > > ---cut--- > > Subject: Rose::DB::Object::load question [ Version 0.758 ] > Date: Mon, 15 Jan 2007 23:24:32 +0100 > From: XXXX XXXXX <[EMAIL PROTECTED]> > > Dear John, > > I was not very happy with "DBIx::Class" and "Class::DBI", so because I > was already enjoying your module "Rose::HTML::Objects", I've decided to > try "Rose::DB::Object". (By the way, why HTML::Object*_s_* (with s) and > DB::Object (without s) ? ) > > My first impression is very good, congratulation! But I came on the > following issue: > > I have a table with 2 _unique_ keys having each 2 fields [[/x/, /y/], > [/x/, /z/]] plus a primary key (/id/). Everything is fine If I'm loading > an object with (/x,//y)/, but if I'm loading with (/x,z/), then the > "load" method seems to still try to use /x/ and /y/ ( y = '' ) and thus > does not find the object. > > I had a look at the code and the problem seems to be that the accessor > (used at line 173) never returns "undef"! I've made a small test and if > a field is not defined, the accessor returned the empty string, but not > "undef". So the first unique key always matches. > > 164:# Prefer unique keys where we have defined values for all > 165:# key calumns, but fall back to teh first unique key found > 166:# where we have at least one defined value. > 167:foreach my $cols ($meta->unique_keys_column_names) > 168:{ > 169: my $defined = 0; > 170: @key_columns = @$cols; > 171: @key_methods = map { $meta->column_accessor_method_name($_) } > @key_columns; > 172: @key_values = map { $defined++ if(defined $_); $_ } > 173: map { $self->$_() } @key_methods; > 174: > 175: if($defined == @key_columns) > 176: { > 177: $found_key = 1; > 178: last; > 189: } > > (By the way, note the 2 spelling errors at line 165). > > Even if the field is explicitly set to undef : "$o->y(undef)", $o->y()" > still returns the empty string. > / > (my code:)/ > > $pferd->Name($o{Pferdename}); > $pferd->PassNummer(undef); > print "Value is ", (defined $pferd->PassNummer ? "Defined" : "UNDEFINED"), > "\n"; print "and is '" . $pferd->PassNummer . "'\n"; > > gives: > > Value is Defined > and is '' > > > What should I do to make the accessor returning "undef" if the value of > the field is not defined, and so make the "load" method work correctly? > Is there a bug or did I do something wrong? > > > Thank you in advance for your support. > > Regards, > > -- XXXX XXXXX > > ---cut--- > > Subject: Re: Rose::DB::Object::load question [ Version 0.758 ] > To: "XXXX XXXXX" <[EMAIL PROTECTED]> > From: "John Siracusa" <[EMAIL PROTECTED]> > Date: Tue, 16 Jan 2007 10:08:31 -0500 > > On 1/15/07, XXXX XXXXX <[EMAIL PROTECTED]> wrote: > > $pferd->PassNummer(undef); > > print "Value is ", (defined $pferd->PassNummer ? "Defined" : > > "UNDEFINED"), "\n"; > > print "and is '" . $pferd->PassNummer . "'\n"; > > gives: > > Value is Defined and is '' > > What kind of column is PassNummer? Can you show me the database > definition for that column as well as the definition in your > RDBO-derived class? > > (I suspect that you're using MySQL, which tends to make the default > value for non-null (var)char columns an empty string. This default > value would be picked up by the Loader/auto_initalize() and would > cause the column to exhibit the behavior you describe.) > > -John > > ---cut--- > > Subject: Re: Rose::DB::Object::load question [ Version 0.758 ] > Date: Tue, 16 Jan 2007 17:28:22 +0100 > To: [EMAIL PROTECTED] > From: XXXX XXXXX <[EMAIL PROTECTED]> > > Hi John, > > Thank you very much for your answer. > > > So here is the definition of my table: > > CREATE TABLE `live_pferd` ( > `PferdId` int(11) NOT NULL auto_increment, > `VnummerSVPS` varchar(10) NOT NULL, > `PassNummer` decimal(10,0) NOT NULL, > `Name` varchar(26) NOT NULL, > ... > PRIMARY KEY (`PferdId`), > UNIQUE KEY `idx0` (`VnummerSVPS`,`PassNummer`), > UNIQUE KEY `idx1` (`VnummerSVPS`,`Name`) > ) > > ...and I'm using auto_initialize: > > package Hippique::DB::Live::Pferd; > > use strict; > use base qw(Hippique::DB::Live::Object); > > __PACKAGE__->meta->setup( > table => 'live_pferd', > auto_initialize => [], > ); > > ... and yes, I'm using MySQL! > > This is what I'm trying to do > > my $pferd = Hippique::DB::Live::Pferd->new( > VnummerSVPS => "1234", > ); > $pferd->Name("blabla"); > $pferd->load; # Ooops! > > and it fails to load the object "$pferd->PassNummer" is empty and not > "undef"; so it selects the wrong unique index (idx0 instead of idx1). > But actually MySQL has not yet be involved at this point; it's the > accessor of the "in-memory" object $pferd that returns "" instead of undef. > > I could explain the phenomenon by the "NOT NULL" in the column > definition of the database, but actually the columns are "NOT NULL". > It's just that I'm trying to load the object either by (VnummerSVP, > PassNummer) or by (VnummerSVPS, Name) depending on which field is > defined. In the database, the 3 fields are defined and are not-null: > > my $pferd = Hippique::DB::Live::Pferd->new( > VnummerSVPS => "1234", > ); > if (defined $horse_name) { > $pferd->Name($horse_name); > } else { > $pferd->PassNummer($horse_nr); > } > $pferd->load; > > > So maybe I'm using the "load" method in a wrong way and I should write > my own "SELECT" instead... But using the "load" methods seems much simpler! > > > I also have another issue: I have a case where the database is a SQLite > file and the file location is not known as compile time. Actually the > SQLite file name is given as an argument, so it is only known during the > run time. Is it still possible to use Rose::DB in this configuration? > > > Thank you very much for your support and for the great modules that you > are writing. > > > -- XXXX XXXXX > > ---cut--- > > Subject: Re: Rose::DB::Object::load question [ Version 0.758 ] > To: "XXXX XXXXX" <[EMAIL PROTECTED]> > From: "John Siracusa" <[EMAIL PROTECTED]> > Date: Tue, 16 Jan 2007 11:55:24 -0500 > > On 1/16/07, XXXX XXXXX <[EMAIL PROTECTED]> wrote: > > CREATE TABLE `live_pferd` ( > > `PferdId` int(11) NOT NULL auto_increment, > > `VnummerSVPS` varchar(10) NOT NULL, > > `PassNummer` decimal(10,0) NOT NULL, > > `Name` varchar(26) NOT NULL, > > ... > > PRIMARY KEY (`PferdId`), > > UNIQUE KEY `idx0` (`VnummerSVPS`,`PassNummer`), > > UNIQUE KEY `idx1` (`VnummerSVPS`,`Name`) > > ) > > > > ...and I'm using auto_initialize: > > ... and yes, I'm using MySQL! > > Do this: > > print Hippique::DB::Live::Pferd->meta->perl_class_definition; > > and I think you'll see that the VnummerSVPS column has a default value > of empty string: > > VnummerSVPS => { type => 'varchar', default => '', length => 10, > not_null => 1 }, > > That's why the VnummerSVPS() column accessor method always returns an > empty string, even when you set it to undef. This is happening > because DBI's column_info() method is returning an empty string as the > COLUMN_DEF value: > > 'COLUMN_DEF' => '' > > http://search.cpan.org/dist/DBI/DBI.pm#column_info > > This is arguably a bug in DBD::mysql, but as far as RDBO is concerned, > the VnummerSVPS column definition is a correct reflection of what's in > the database as determined by DBI. > > To work around this, you can set the default value to undef in a > pre_init_hook subroutine: > > __PACKAGE__->meta->setup( > table => 'live_pferd', > pre_init_hook => \&fixup_column_defaults, > auto_initialize => [], > ); > > sub fixup_column_defaults > { > my($meta) = shift; > > foreach my $column ($meta->columns) > { > $column->default(undef); > } > } > > If you then do this again: > > print Hippique::DB::Live::Pferd->meta->perl_class_definition; > > I think you'll see that the default => '' column attribute is gone. > > > So maybe I'm using the "load" method in a wrong way and I should write > > my own "SELECT" instead... But using the "load" methods seems much > > simpler! > > You're doing it right. MySQL and DBD::mysql just tend to do weird > things sometimes... > > > I also have another issue: I have a case where the database is a SQLite > > file and the file location is not known as compile time. Actually the > > SQLite file name is given as an argument, so it is only known during the > > run time. Is it still possible to use Rose::DB in this configuration? > > Sure, just call Rose::DB's modify_db() method to set the correct > information in your registered data source as soon as you know it. > > http://search.cpan.org/dist/Rose-DB/lib/Rose/DB.pm#modify_db > > -John > > ---cut--- > > Subject: Re: Rose::DB::Object::load question [ Version 0.758 ] > To: John Siracusa <[EMAIL PROTECTED]> > From: XXXX XXXXX <[EMAIL PROTECTED]> > Date: Tue, 16 Jan 2007 23:05:01 +0100 > > Thank you for your *great* support. > > actually, I've just changed the default for the columns in the unique keys: > > sub fixup_column_defaults { > my $meta = shift; > $meta->column("PassNummer")->default(undef); > $meta->column("Name")->default(undef); > } > > ... and YES! everything works as expected now. > > Actually it was OK (and even convenient) for me to leave "" as a default > for the other fields. > > So once again, a huge "Thank You" and congratulation for you job! Your > support is so efficient and this is your better selling argument :-) > It's decided, I'm dropping Class::DBI and DBIx::Class and I'm adopting > Rose::DB::Object! And after having read R. Schwartz's Column 86 (Oct > 2006) of the Linux Magazine, I'm even more convinced that this is the > right decision! > > Rose Rulez! > > Cheers, > > -- XXXX XXXXX > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share > your opinions on IT & business topics through brief surveys - and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Rose-db-object mailing list > Rose-db-object@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/rose-db-object ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Rose-db-object mailing list Rose-db-object@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/rose-db-object