Hi,
While trying to track down a bug in .08 trunk that was causing an error on
mysql I discovered that the problem was due to a change in the way
DBIx::Class::Storage::DBI->select_single handled results that returned more
than a single row. In 0.08010 and earlier, if ->select_single was run against
SQL that returned more than a single row, only the first row was returned and
the remaining ones silently discarded. On DBIC trunk, a bit of code was added
that would carp out if more rows existed:
sub select_single {
my $self = shift;
my ($rv, $sth, @bind) = $self->_select(@_);
my @row = $sth->fetchrow_array;
carp "Query returned more than one row" if $sth->fetchrow_array;
# Need to call finish() to work round broken DBDs
$sth->finish();
return @row;
}
Now, from what I can see, the entire point of this method is to help optimise
$resultset->find by just returning a single row without creating a whole
cursor. However, DBIC::Storage::DBI->select_single is also publicly exposed as
$resultset->single and is documented as a optimised select for a single row.
Nothing in the docs or previous versions warned users that >single should only
be run against SQL that returns a single row. In fact, one would think that
->find is reserved for this purpose. So by adding this additional constraint
at that point I am very certain we are going to be breaking peoples code. I
know in fact $resultset->single is used in a few spots in our codebase in
places that will explode if the above carp is kept.
I was lead to this because the mysql error was due to the fact the line:
carp "Query returned more than one row" if $sth->fetchrow_array;
is going to die when the $sth is exhausted (which was generating 'fetch without
execute' errors). I could fix this to work properly, but I really feel it's
not such a good idea to change the API behavior like this without some sort of
deprecation cycle. In addition I am not certain why should change it. I can
see a need for a quick, "get me the first something you find" function.
However at the very least we should update the docs to reflect clarified
semantices between $resultset->first, ->single, and ->find.
So what do you all think? Our options are:
-1- Revert ->select_single to the old behavior but deprecate $resultset->single
so that we can eventually remove it from the API at some point, freeing us to
constraint ->select_single when it's no longer part of the public API
-2- Revert ->select_single to the old behavior and deprecate $resultset->single
for SQL that returns multiple rows. Change the carp to some sort of warn and
fix the 'fetch without execute' bug.
-3- Revert ->select_single to the old behavior and properly document the
existing behavior, in particular to clarify the differences between ->first,
->single, and ->find. This is basically reverting to the 0.08010 behavior,
documenting it, adding a test, etc.
-4-> Push this change through. Fix the 'fetch without excute bug' and tell
everyone they need to grep/ack through their code and replace ->single with
either ->first or ->find for the cases the underlying SQL could return more
than one row.
To be honest I prefer option 3, since that's the easiest thing for me and my
deployment. I really don't see much of a use for $resultset->single that only
is useful against SQL that is guaranteed to return a single row. Seems to me
that is what ->find is for. However I do see value in a cursorless form of
->first, since sometimes you just want to grab the first thing as fast as
possible.
Certainly at the minimum we should clarify the docs. I think we should push
people away from ->single if what they really want in ->first.
I'm ready to make these changes, fix up the docs, add a test. Let's just
decide so it's part of this next release.
--John
____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now.
http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/[EMAIL PROTECTED]