Re: DBI and fetchall_arrayref with max_rows?

"Martin J. Evans" <[email protected]>
Newsgroups gmane.comp.lang.perl.modules.dbi.sybase.devel
Organization Easysoft Limited
Message-ID <[email protected]>
On 06/12/10 16:12, Jonathan Leffler wrote:
> 
> On Mon, Dec 6, 2010 at 07:20, Tim Bunce <[email protected] <mailto:[email protected]>> wrote:
> 
>     On Mon, Dec 06, 2010 at 12:54:57AM -0800, Jonathan Leffler wrote:
>     > Two related questions (prompted by a question from people using
>     > DBD::Informix):
>     >
>     > 1.  Are there any known problems with $sth->fetchall_arrayref({}, 50);?
> 
>     Nope.
> 
> 
> OK - thanks for the quick look, Tim (and Martin).  That quickly isolates the problem to DBD::Informix.
>  
> 
>     > 2.  Are there any requirements on a DBD module to make the limit on
>     > fetchall_arrayref({}, 50) notation work, or is it purely a DBI feature?
> 
>     The DBI provides a default fetchall_arrayref method in DBI.pm that
>     implements fetching, slicing and maxrows.
> 
>     There's also a fetchall_arrayref method in Driver.xst for added speed.
>     That one falls-back to the perl version if a slice is specified, but
>     otherwise expects dbdxst_fetchall_arrayref() to handle maxrows.
>     dbdxst_fetchall_arrayref() is defined in Driver_xst.h
> 
> 
> AFAIK, I'm using the DBI-provided fetchall; the only reference to fetchall in Informix.pm is in POD.  It appears in Informix.xsi and Informix.c, but that is stuff from DBI and the driver support code.
> 
> I've attached the output of:
> 
>     DBI_TRACE=9 perl fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl>
> 
> The fetchall_arrayref call was:
> 
>     fetchall_arrayref(undef, 50);
> 
> I'm not sure how many problems that is revealing.  The most immediately relevant section looks like:
> 
>     >> execute     DISPATCH (DBI::st=HASH(0x1009177a8) rc1/1 @1 g2 ima1041 pid#74162) at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 8
>     -> execute for DBD::Informix::st (DBI::st=HASH(0x1009177a8)~0x1009176d0)
>     -->> DBD::Informix::dbd_ix_st_execute()
>     -->> DBD::Informix::dbd_ix_open()
>     <<-- DBD::Informix::dbd_ix_open()
>     <<-- DBD::Informix::dbd_ix_st_execute()
>     <- execute= ( '0E0' ) [1 items] at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 8
>     >> fetchall_arrayref DISPATCH (DBI::st=HASH(0x1009177a8) rc1/1 @3 g2 ima1 pid#74162) at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 16
>     -> fetchall_arrayref for DBD::Informix::st (DBI::st=HASH(0x1009177a8)~0x1009176d0 undef 50)

dbd_st_fetch should get called here via $sth->fetch.

The code in DBI seems fairly straight forward:

    sub fetchall_arrayref {	# ALSO IN Driver.xst
	my ($sth, $slice, $max_rows) = @_;

        # when batch fetching with $max_rows were very likely to try to
        # fetch the 'next batch' after the previous batch returned
        # <=$max_rows. So don't treat that as an error.
        return undef if $max_rows and not $sth->FETCH('Active');

	my $mode = ref($slice) || 'ARRAY';
	my @rows;
	my $row;
	if ($mode eq 'ARRAY') {
	    # we copy the array here because fetch (currently) always
	    # returns the same array ref. XXX
	    if ($slice && @$slice) {
                $max_rows = -1 unless defined $max_rows;
		push @rows, [ @{$row}[ @$slice] ]
		    while($max_rows-- and $row = $sth->fetch);
	    }
	    elsif (defined $max_rows) {
		push @rows, [ @$row ]
		    while($max_rows-- and $row = $sth->fetch); <---- why didn't you get here?
	    }
	    else {
		push @rows, [ @$row ] while($row = $sth->fetch);
	    }
	}

Is your $sth Active?

>     <- fetchall_arrayref= ( undef ) [1 items] row-1 at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 16
>     >> disconnect  DISPATCH (DBI::db=HASH(0x1009175c8) rc1/1 @1 g2 ima10c01 pid#74162) at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 30
>     -> disconnect for DBD::Informix::db (DBI::db=HASH(0x1009175c8)~0x1009174c0)
> 
> It seems that the DISPATCH code is doing something, but not reaching DBD::Informix code (the DBD::Informix debugging usually has the double-headed arrows (-->> or <<--) but it doesn't show any activity.
> 
> By contrast, when I used the variant with just a slice (fetchall_arrayref([0,1,2])), I get to see:
> 
>     <- execute= ( '0E0' ) [1 items] at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 8
>     >> fetchall_arrayref DISPATCH (DBI::st=HASH(0x1009177d8) rc1/1 @2 g2 ima1 pid#74507) at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 12
>     -> fetchall_arrayref for DBD::Informix::st (DBI::st=HASH(0x1009177d8)~0x100917700 ARRAY(0x1009174a8))
>     >> fetch       DISPATCH (DBI::st=HASH(0x100917700) rc1/2 @1 g2 ima0 pid#74507) at /Users/jleffler/perl/v5.13.4/lib/site_perl/5.13.4/darwin-2level/DBI.pm line 2016 via  at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 12
> 1   -> fetch for DBD::Informix::st (DBI::st=HASH(0x100917700)~INNER)
>         -->> DBD::Informix::dbd_ix_st_fetch()
>         -->> DBD::Informix::dbd_ix_blobs()
>         ---- dbd_ix_blobs(): 0 BYTE/TEXT blobs
>         <<-- DBD::Informix::dbd_ix_blobs()
>         ---- dbd_ix_st_fetch: FETCH c_000000000 into d_000000000
>     dbih_setup_fbav alloc for 7 fields
>     dbih_setup_fbav now 7 fields
>         ---- dbd_ix_st_fetch colno 1: coltype = 2
>         ---- dbd_ix_st_fetch colno 2: coltype = 0
>         ---- dbd_ix_st_fetch colno 3: coltype = 0
>         ---- dbd_ix_st_fetch colno 4: coltype = 5
>         ---- dbd_ix_st_fetch colno 5: coltype = 1
>         ---- dbd_ix_st_fetch colno 6: coltype = 0
>         ---- dbd_ix_st_fetch colno 7: coltype = 0
>         <<-- DBD::Informix::dbd_ix_st_fetch()
> 1   <- fetch= ( [ '1' 'H  ' 'Hydrogen            ' '1.0079' '1' '1 ' 'Y' ] ) [1 items] row1 at /Users/jleffler/perl/v5.13.4/lib/site_perl/5.13.4/darwin-2level/DBI.pm line 2016 via  at fetchall_maxrows_bug.pl <http://fetchall_maxrows_bug.pl> line 12
> 
> Can you see anything to indicate what I've got mis-initialized that is causing the breakage, Tim (or anyone)?  Superficially, it looks like DBI decided not to call the DBD::Informix fetch functions when maxrows was in effect.  There must be a reason, but I've no idea what to look for.

Also double-check you rebuilt DBD::Informix after installing DBI 1.615 -
although I think DBI catches that now.

> 
>     p.s. I took a quick look at DBD::Informix source and ran away fast! :)
> 
> 
> Fair enough...it probably needs a complete rewrite.
> 
> I had been going to release a new DBD::Informix with support for Perl 5.13 / 5.14.  I probably need to hold off until I've resolved this problem.
> 
> Strictly, I'm using DBD::Informix version 2010.0914.20100929; however, it is essentially the same as DBD::Informix 2008.0513 - especially in this area.
>  
> 
>     > my $dbh = DBI->connect('dbi:Informix:stores', '', '') or die "Horribly 1";
>     > my $sth = $dbh->prepare(q{SELECT * FROM Elements}) or die "Horribly 2";
>     > $sth->execute;
>     >
>     > #my $res = $sth->fetchall_arrayref;        # Works
>     > #my $res = $sth->fetchall_arrayref({}, 50);    # Fails: no data
>     > #my $res = $sth->fetchall_arrayref([], 50);    # Fails: no data
>     > #my $res = $sth->fetchall_arrayref([0,1,2]);    # Works
>     > my $res = $sth->fetchall_arrayref([0,1,2], 50);   # Fails: no data
>     > #my $res = $sth->fetchall_arrayref({});    # Works
>     > #my $res = $sth->fetchall_arrayref(undef, 50);  # Fails: no data
>     > foreach my $row (@{$res})
>     > {
>     >     # Use this section for printing arrays
>     >     foreach my $value (@{$row})
>     >     {
>     >         printf "%s ", $value;
>     >     }
>     >     print "\n";
>     >     # Use this section for printing hashes
>     >     #foreach my $key (sort keys %{$row})
>     >     #{
>     >     #    printf "%-15s = %s\n", $key, $row->{$key};
>     >     #}
>     > }
>     >
>     > $dbh->disconnect;
>     >
>     > Choose your own driver and database, etc; choose your own table (my table of
>     > elements has entries for hydrogen through ununoctium - 1..118; 50 is about
>     > half the table).  It seems that fetchall_arrayref() works fine with no
>     > arguments and with slice arguments, but none of the slice versions with a
>     > maximum count does anything.
>     >
>     > Am I missing something?  Or is there a bug?
>     >
>     > Perl 5.13.4 on MacOS X 10.6.5; DBI 1.615, DBD::Informix 2008.0513.
> 
> 
> 
> -- 
> Jonathan Leffler <[email protected] <mailto:[email protected]>>  #include <disclaimer.h>
> Guardian of DBD::Informix - v2008.0513 - http://dbi.perl.org
> "Blessed are we who can laugh at ourselves, for we shall never cease to be amused."

Martin
-- 
Martin J. Evans
Easysoft Limited
http://www.easysoft.com
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.