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

Hey all,
I have this message board I am working on (http://dhoss.perlmonk.org/ethereal) that uses HTML::Template and DBI to generate the pages for my site.
My dillemma:
I am retrieving the sql from a sub called selectMsgFromDb that selects the proper sql query from a configuration module that has all the sql queries in a hash (Security problems???) and executes it, returning the data from the db. It does that just fine, sorta, but it returns 14 (the number of threads in my messages table) EVERY TIME instead of the $sth->{hash_value} values.
Any ideas? Here is the source:
# select sub sub selectMsgFromDb { my ($self, %params) = @_; $self->checkRequiredParams(%params); my $sth = $dbh->prepare( $cfg->{retrieve_from_sql}->{msg} ); $sth->execute( ); my @msgs; while ( my $thread = $sth->fetchrow_hashref() ){ my (@data) = q[$thread->{id}, $thread->{name}, $thread->{date}, $thread->{subj}, $thread->{day_rate}, $thread->{msg}]; push @msgs, @data; } return @msgs; # code for returning the page my ($content); push @{$content}, $params{-content}; $template->param( MAIN_CONTENT=>$content ); return $template->output; # hash for sql my %sql = ( msg =>'SELECT id, name, date, subj, day_rate, msg FROM mes +sages ORDER BY DATE DESC', reply =>'SELECT id, name, date, subj, day_rate, msg FROM m +essages ORDER BY DATE DESC', insert =>'INSERT INTO ethereal VALUES(0, ?, ?, ?, NOW(), ? +)' );

Thanks in advance,

dhoss

"and I wonder, when I sing along with you if everything could ever feel this real forever? if anything could ever be this good again? the only thing I'll ever ask of you, you've gotta promise not to stop when I say 'when'", she sang

Replies are listed 'Best First'.
Re: HTML::Template problems
by Coruscate (Sexton) on Dec 31, 2003 at 23:25 UTC

    I think your main problem is in this snippet:

    my (@data) = q[$thread->{id}, $thread->{name}, $thread->{date}, $thread->{subj}, $thread->{day_rate}, $thread->{msg}];

    You're creating an array with only one element. Your snippet is equivalent to the following. Note that q() is equivalent to the single-quote operator, so the values won't even be interpolated into the string.

    my @data = '$thread->{id}, $thread->{name}, ' . '$thread->{date}, $thread->{subj}, ' . '$thread->{day_rate}, $thread->{msg}';

    Perhaps you meant something like:

    my @data = ( $thread->{id}, $thread->{name}, $thread->{date}, $thread->{subj}, $thread->{day_rate}, $thread->{msg} );

    Update: Fixed the 'equivalent' example to single quotes and added explanation (originally was concatenating with double quotes which would not be the same).

      Ahhhh, of course. I'll try it and get back to this.
      Thanks,
      -dhoss

      "and I wonder, when I sing along with you if everything could ever feel this real forever? if anything could ever be this good again? the only thing I'll ever ask of you, you've gotta promise not to stop when I say 'when'", she sang
        Ahh, now instead of 14, it's returning 84.....?

        "and I wonder, when I sing along with you if everything could ever feel this real forever? if anything could ever be this good again? the only thing I'll ever ask of you, you've gotta promise not to stop when I say 'when'", she sang
Re: HTML::Template problems
by tilly (Archbishop) on Dec 31, 2003 at 23:52 UTC
    The fact that you have 14 returned is probably due to the fact that you return @msgs. If that is returned in scalar context then you get @msgs in scalar context, which tells you how many things are in @msgs.

    Furthermore I suspect that you are seriously mangling your attempt to deal with references to arrays. It may be time to re-read references quick reference, and then replace your while loop with something like this:

    while ( my $thread = $sth->fetchrow_hashref() ){ push @msgs, [$thread->{id}, $thread->{name}, $thread->{date}, $thread->{subj}, $thread->{day_rate}, $thread->{msg}]; }
    Though personally I would be inclined to keep an anonymous hash data structure like this:
    while ( my $thread = $sth->fetchrow_hashref() ){ # I duplicate the data because DBI says that it may # choose to reuse the reference that it returns. push @msgs, { %$thread }; }
    (I would also indent differently, but that is cosmetic.)
Re: HTML::Template problems
by cLive ;-) (Prior) on Jan 01, 2004 at 00:11 UTC
    Without seeing the code in question that calls the sub (and taking on board other comments), my guess is context:
    # this should work my @messages = selectMsgFromDb(); # or, if you want to use references my $messages = selectMsgFromDb(); # and amend last line of selectMsgFromDb sub to: return \@msgs;

    (I'm assuming you forgot to finish the sub } here in the snippet shown :)

    Also, Data::Dumper is your friend. Use it, and dump variables as you go to check you're getting what you expected.

    .02

    cLive ;-)

Re: HTML::Template problems
by cees (Curate) on Jan 01, 2004 at 21:28 UTC

    Since your main question has been adequately answered, I thought I would comment on the sub question you threw in there.

    I am retrieving the sql from a sub called selectMsgFromDb that selects the proper sql query from a configuration module that has all the sql queries in a hash (Security problems???) and executes it, returning the data from the db.

    There is nothing wrong with gathering all your SQL calls in one location and having the code pull them in when they are needed. Some would say that this is the proper way to handle SQL calls, since it leads to reuse of SQL statements, and less clutter in the code.

    If you are looking for some direction in how this can be achieved easily and safely, then I would recommend you have a look at the Ima::DBI module which was built exactly for this purpose. It may be overkill if your script is small, but I think it is worth a look for ideas and direction regardless of whether you choose to use it.

    Also, as the Ima::DBI docs suggest, have a look at Class::DBI which heavily uses the Ima::DBI and hides most of it's complexity. Again, it might be overkill for a small script, but it does wonders for organizing your Database access into clean and maintainable modules. You may even be able to avoid writing any SQL at all when using Class::DBI, as it is able to handle many of the most common ways a developer accesses data from a database.

    - Cees