in reply to Why is my code assigning the last-retrieved value to all elements in my hash?

My guess is there's a reference somewhere you're not expecting. For example, if %booklist_l is initialized this way:

my %booklist_l; @booklist_l{ @book_id_list } = ( { title => 'empty', update_id => 'missing' } ) x scalar @book_id_list;

...then every item in %booklist_l has the same reference to an "empty" record.

Also, DBI, when it returns things from fetchrow_hashref, always returns the same reference (as a performance optimization). As such, if you do this:

$booklist_l{ $book_id } = $sth->fetchrow_hashref;

...again, you'll have the same reference everywhere. In that case, you can get a copy of what it returns like this:

$booklist_l{ $book_id } = { %{$sth->fetchrow_hashref} };

That doesn't look like what you're doing, but I can't run your example code, so I'm suspicious.

Update: I think I didn't explain my suspicion very well. Each $booklist_l{ $book_id } is a reference to a hash. I suspect they're all the same reference. How that happened, I'm not sure, but I give a couple of possibilities above. An easy way to check whether they're all the same reference is to stringify them. Your ending debugging loop could be:

foreach $book_id (keys %booklist_1) { my $r = $booklist_l{$book_id}; print "XXX $book_id > $r->{'update_id'} -- from $r\n"; }

Replies are listed 'Best First'.
Re^2: Why is my code assigning the last-retrieved value to all elements in my hash?
by punch_card_don (Curate) on Jul 09, 2008 at 18:37 UTC
    Hmmm...several fingers pointed at referencing the hash so far in this thread...

    The %booklist_1 hash is populated from a previous query, like this:

    $sql = "SELECT book_id FROM booklist_table WHERE (expected_publcn_date + >= '".$start_date."' AND expected_publcn_date <= '".$end_date."')"; $sth = $dbh->prepare($sql) or die("Could not prepare!" . $dbh->errstr) +; $sth->execute() or die("Could not execute!" . $dbh->errstr); while ($book_id = $sth->fetchrow_array()) { $booklist_1{$book_id} = 1; } $sth->finish;



    Time flies like an arrow. Fruit flies like a banana.

      Use strict and warnings!!!

      use Data::Dumper; my %booklist_l; $booklist_l{ 'foo' } = 1; $booklist_l{ 'bar' } = 1; $booklist_l{ 'foo' }{ 'update_id' } = 'update_id 1'; $booklist_l{ 'foo' }{ 'title' } = 'title 1'; $booklist_l{ 'bar' }{ 'update_id' } = 'update_id 2'; $booklist_l{ 'bar' }{ 'title' } = 'title 2'; print Dumper \%booklist_l; print Dumper \%1; __END__ $VAR1 = { 'bar' => 1, 'foo' => 1 }; $VAR1 = { 'update_id' => 'update_id 2', 'title' => 'title 2' };

      That number '1' you put into every entry is being treated as a symbolic reference to the variable %1.

        Excellent.

        So, since the '1' just serves to give a value that allows the element to exist, setting to something, anything, else should serve teh same purpose and avoid the undesired symbolic reference to %1.

        Went ahead and changed it to

        while ($book_id = $sth->fetchrow_array()) { $booklist_1{$book_id} = "ok"; }
        but it made no difference. Same output.

        I really appreciate the attention to my prob, though. Did I miss-apply what you were trying to say?




        Time flies like an arrow. Fruit flies like a banana.
      I think the bug is here. Try to write something like
      while ( ($book_id) = $sth->fetchrow_array() ) { $booklist_1{$book_id} = 1; }
      (note the extra parenthesis in order to enforce list context)

      or

      while ( $book_id = $sth->fetchrow_arrayref() ) { $booklist_1{ $book_id->[0] } = 1; }

      Code is not tested

      Best regards

      UPDATE:. I have overseen the kyle suggestion. It seems that the right code regarding the second loop will be:

      while ( ($book_id) = $sth->fetchrow_array() ) { $booklist_1{$book_id} = {}; }