bradcathey has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monasterians,
I'm learning new DBI schemes and have been working with fetchall_arrayref. It works fine as shown, but would like to know how to access the data (see example A), intercepting it, as it were, to manipulate it before committing it to $template -> param(...). The methods are not working and get output like "HASH(0x8301bb8)" and "Not an ARRAY reference." I found thisand this, but not getting any results. Aren't I just deferencing the array? Or is this acting like a hash? Is it even possible? Thanks all!

This works fine (I get populated drop downs in my HTML form):
my $stmt = "SELECT DISTINCT scene, title FROM catalog"; my $sth = my $dbh->prepare($stmt) or die ...r"; $sth->execute() or die ...r" my $data = $sth->fetchall_arrayref({}); my $template -> param ( selscene => $data );
Example A:
my $data = $sth->fetchall_arrayref({}); if ( $data->[1] eq "large" ) { #something like this or... ucase ( $data->[1] ); } print $data->[1],"\n"; #can I even print it $template->param(selscene => $data)
FYI, here's the HTML:
<select name="scenes"> <tmpl_loop name="selscene"> <option value="<tmpl_var scene>"><tmpl_var title></option> </tmpl_loop> </select>

—Brad
"A little yeast leavens the whole dough."

Replies are listed 'Best First'.
Re: Dereferencing fetchall_arrayref({})
by dragonchild (Archbishop) on Apr 25, 2004 at 20:34 UTC
    Y'all are completely wrong. Read the DBI POD before spouting. fetchall_arrayref() does return an array of arrays, but fetchall_arrayref({}) returns an array of hashes.

    The reason why the first code works is because the TMPL_LOOP selscene is expecting an array of hashes. When you work with it, $data->[1] is a hashref. So, what you want to do is:

    Example A, rewritten: my $data = $sth->fetchall_arrayref({}); if ($data->[0]{title} eq 'large') { ucase( $data->[0]{title} ); } print "First title: '$data->[0]{title}'\n"; $template->param( selscene => $data );

    A few comments, in no particular order:

    • You have a function called ucase(). What does it do that uc doesn't?
    • Pick a better name than $data. You might not need it now, but you will need it in 6 months.
    • prepare_cached() can provide a small, but noticeable, speedup with CGI scripts under mod_registry.
    • Look into using the RaiseError option in your DBI connect() statement. That way, you don't have to have the or die() after every line. You will want to wrap your entire DBI interaction in something like:
      eval { my $sth = $dbh->prepare_cached( ... ); $sth->execute; my $stuff = $sth->festchall_arrayref({}); $template->param( selscene => $data ); }; if ($@) { # Do some error handling here. }
      It's a lot easier to read and you still have all the error handling. You may want to turn PrintError off, if you do this.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

      Thanks dragonchild, ++'s all around. You were right. I tried your rewrite and worked like a charm. Great lesson in dereferencing the AoH. And thanks for the DBI tips--I will try them out. Again, thanks!

      —Brad
      "A little yeast leavens the whole dough."
Re: Dereferencing fetchall_arrayref({})
by Zaxo (Archbishop) on Apr 25, 2004 at 20:03 UTC

    DBI::fetchall_arrayref returns an array of arrays. You need two indexes to dereference a data element. Let your code read,

    if ( $data->[0][1] eq "large" ) { #something like this or... $data->[0][1] = uc ( $data->[0][1] ); }
    Note that ucase is spelled uc, and does not modify its argument in-place.

    After Compline,
    Zaxo

      Thanks Zaxo, I actually tried the $data[1][0] before the OP and was getting errors. So,I dropped in your code as is, but I still get the "is not an array reference" error. Data Dumper shows:

       $VAR1 = [  {  'title' => 'DRAGONFLY',  'scene' => 'DF'  },  {  'title' => 'HUMMINGBIRD',  'scene' => 'HB'  }  ];
      Any other ideas? And yes, I meant uc, but have been reading up on MySQL functions :-)

      —Brad
      "A little yeast leavens the whole dough."

        Try it with the dereferencing arrow, $data->[0][1]. What you show would apply to an AoA, not a reference to one.

        After Compline,
        Zaxo

        What about something like this?

        my $data; while ($_ = $sth->fetchall_arrayref()) { uc(${$_}{'title'}) if(${$_}{'title'} eq "large"); push @{$data}, $_; }
        --
        b10m

        All code is usually tested, but rarely trusted.
Re: Dereferencing fetchall_arrayref({})
by blue_cowdawg (Monsignor) on Apr 25, 2004 at 20:03 UTC

        but would like to know how to access the data (see example A),

    This is one of those moments when as an adjunct professor I always take time out to tell my students how the watch works before I tell them what time it is.

    First off a quick review of what an array reference is:

    # make an array reference: my $ref = \@rry; # # or an anoonymous array: my $ref2=[ "stuff", "things", "goodies"]; </ocde> If I have a function returning an arrey reference: <code> my $rows=$sth->fetchall_arrayref;
    Then to dereference it I would do the following:
    my @array=@{$sth->fetchall_arrayref};

    But wait! If I am passing an array to HTML::Template's param method then I'm going to want to pass an anoymous array such as:

    $template->param(selscene => [ @array ] );

    Hope my brain fried ramblings make sense and help...

When data structures differ from your expectations
by TomDLux (Vicar) on Apr 26, 2004 at 00:15 UTC

    Other people have provided the information you needed in this case, but you don't want to go seeking out help every time a reference doesn't work the way you imagine it should.

    When $data->[1] did not return the type of values you anticipated, the next step is to find out what it does contain .... if your visualization of relaity and the contents of the data structure disagree, only one of them can be right. The appropriate solution at that point is to use Data::Dumper:

    use Data::Dumper; print Dumper $data;

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

      TomDLux, you are absolutely right. I usually don't post until I have exhausted all avenues. I had forgotten about Data::Dumper, and once run, it showed me what I now understand is a AoH. I'm still working on understanding references (even after reading the Llama book).

      —Brad
      "A little yeast leavens the whole dough."

        When I got into Perl, although I had a degree and many years of programming experience, it took me a long time to get used to complex data structures and references. I was used to C, where you have the structure declaration to refer to; since Perl can generate complex structures without any indication of what the arrangement will be, it can be hard to figure out.

        For the first six months, I mostly used data structures and references when I had to; the next six months I had to code-and-debug, a bit at a time, to figure out the appropriate code. By the end of the year, it had become part of me, I prefered passing a reference instead of a list, and then naturally stored that reference in an array or hash, and then stored a reference to that in ....

        Like all good things, data structures and references look like a long struggle when you're looking up at the learning curve, but it's definitely worth the effort.

        TomDLux

        --
        TTTATCGGTCGTTATATAGATGTTTGCA

Re: Dereferencing fetchall_arrayref({})
by EdwardG (Vicar) on Apr 25, 2004 at 20:07 UTC

    Fetchall arrayref returns a reference to an Array of Arrays, so to reference an item of data you need an extra subscript, like this

    $data->[0]->[0]

    You can see this clearly by dumping the reference, either in the debugger or with Data::Dumper.

    It might help to conceptualise the referenced data as a set of rows, each row having a set of columns.

    Update: I'm wrong about the AoA, (nicely picked up by dragonchild) but advice about debugger (use 'x') and Data::Dumper still stand.