On 06/12/10 16:37, Martin J. Evans wrote:
> On 06/12/10 16:12, Jonathan Leffler wrote:
>>
>> On Mon, Dec 6, 2010 at 07:20, Tim Bunce <tim.bu...@pobox.com 
>> <mailto:tim.bu...@pobox.com>> 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);
>           }
>       }

By here I really meant the equivalent in Driver_xst.h

#ifndef dbd_fetchall_arrayref
static SV *
dbdxst_fetchall_arrayref(SV *sth, SV *slice, SV *batch_row_count)
{
    dTHX;
    D_imp_sth(sth);
    SV *rows_rvav;
    if (SvOK(slice)) {  /* should never get here */
        char errmsg[99];
        sprintf(errmsg,"slice param not supported by XS version of 
fetchall_arrayref");
        sv_setpv(DBIc_ERRSTR(imp_sth), errmsg);
        sv_setiv(DBIc_ERR(imp_sth), (IV)-1);
        return &PL_sv_undef;
    }
    else {
        IV maxrows = SvOK(batch_row_count) ? SvIV(batch_row_count) : -1;
        AV *fetched_av;
        AV *rows_av = newAV();
        if ( !DBIc_ACTIVE(imp_sth) && maxrows>0 ) {
            /* to simplify application logic we return undef without an error   
*/
            /* if we've fetched all the rows and called with a batch_row_count  
*/
            return &PL_sv_undef;
        }
        av_extend(rows_av, (maxrows>0) ? maxrows : 31);
        while ( (maxrows < 0 || maxrows-- > 0)
            && (fetched_av = dbd_st_fetch(sth, imp_sth))  <---- here
        ) {
            AV *copy_row_av = av_make(AvFILL(fetched_av)+1, 
AvARRAY(fetched_av));
            av_push(rows_av, newRV_noinc((SV*)copy_row_av));
        }
        rows_rvav = sv_2mortal(newRV_noinc((SV *)rows_av));
    }
    return rows_rvav;
}
#endif

> Is your $sth Active?

still looks suspicious

>>     <- 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 <jonathan.leff...@gmail.com 
>> <mailto:jonathan.leff...@gmail.com>>  #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
-- 
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to