Hack 25. Bind Database Columns


Use placeholders for data retrieved from the database, not just sent to it.

Experienced database programmers know the value of placeholders in queries. (Inexperienced database programmers will soon find out why they're important, when unquoted data breaks their programs.) When you execute a query and pass in values, the database automatically quotes and inserts them into the prepared query, usually making for faster, and always making for safer, code.

Perl's DBI module has a similar feature for retrieving data from the database. Instead of copying column after column into variables, you can bind variables to a statement, so that they will contain the appropriate values for each row fetch( )ed.

Of course, this technique appears less flexible than retrieving hashes from the DBI, as it relies on the order of data returned from a query and loads of scalar variables...or does it?

The Hack

Suppose that you have a templating application that needs to retrieve some fields from a table[1] and wants to contain the results in a hash. You could write a subroutine named bind_hash( ):

[1] Or, better, a view or stored procedure....

sub bind_hash {     my ($dbh, $hash_ref, $table, @fields) = @_;     my $sql = 'SELECT ' . join(', ', @fields) . " FROM $table";     my $sth = $dbh->prepare( $sql );     $sth->execute( );     $sth->bind_columns( \\@$hash_ref{ @{ $sth->{NAME_lc} } } );     return sub { $sth->fetch( ) }; }

The only really tricky part of the code is using the reference operator (\\) on a hash slice. When fed a list, this operator produces a list of references to the values in the listand a hash slice returns a list of the values, themselves scalars. The NAME_lc property of an active statement handle contains an anonymous array of lowercased field names that the statement will retrieve. This can improve portability.

Running the Hack

Suppose that you have a users table[2] and you want to retrieve the names, birthdays, and shoe sizes of all of the users, and print them nicely. That's easy:

[2] Or view or stored procedure....

# assume you already have $dbh connected my %user; my $user_fetch = bind_hash( $dbh, \\%user, qw( users name dob shoe_size ) ); while ($user_fetch->( )) {     print "$user{name}, born on $user{dob}, wears a size " .           "$user{shoe_size} shoe\\n"; }

This hack only works well when you're fetching a row at a time. It's also not the right way to build a quick and easy object-relational mapper, because by the time you need a new hash for each row, you've already bound it. That's okayit's still very fast and flexible and lends itself well to the iterator technique [Hack #26].



Perl Hacks
Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving
ISBN: 0596526741
EAN: 2147483647
Year: 2004
Pages: 141

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net