Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

DBI prepare() vs do() usage

by kiat (Vicar)
on Dec 21, 2003 at 13:06 UTC ( [id://316183]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings to all monks,

Just a quick question: Which of the following ways of executing UPDATE is the preferred method?

# clean sub not shown my $nick = clean(param('nick')); # Method 1 ( Use prepare ) -------------------------- $dbh = open_dbi(); my $sth = $dbh->prepare(qq{ UPDATE $table{'logins'} SET online='N' WHERE nick=? }); $sth->execute($nick) or bail_out("Cannot execute UPDATE"); # Close connection #Method 2 ( Use do() ) ---------------------- $dbh = open_dbi(); my $sql = qq{ UPDATE $table{'logins'} SET online='N' WHERE nick=$nick }); $dbh->do($sql) or bail_out("Cannot execute UPDATE"); # Close connection
Pretty mundane stuff but any advice will be greatly appreciated.

20040115 Edit by BazB: Changed title from 'perl dbi question...'

Replies are listed 'Best First'.
Re: DBI prepare() vs do() usage
by edan (Curate) on Dec 21, 2003 at 14:08 UTC

    It depends. If it's a one-shot deal, I (personally) would prefer do() since it's more straightforward, and that's pretty much what it's for. If, however, you plan to do this in a loop, for many updates, so then you'd want to prepare() once, then execute() many times. But, in any case, you should still use placeholders in your do:

    #Method 2 ( Use do() ) ---------------------- $dbh = open_dbi(); my $sql = qq{ UPDATE $table{'logins'} SET online='N' WHERE nick=? }); $dbh->do($sql, undef, $nick) or bail_out("Cannot execute UPDATE"); # Close connection
    --
    3dan

      Thanks, edan!

      I didn't know I could use a placeholder with do(). I'll definitely use do() for a one-off execution now that I now it's possible to use a placeholder.

      Btw, why do you need the 'undef' there? Is it compulsory?

        RTFM! At the top:
        $rv = $dbh->do($statement); $rv = $dbh->do($statement, \%attr); $rv = $dbh->do($statement, \%attr, @bind_values);
        Since @bind_values is the 3rd arg and you aren't specifying \%attr, you use either undef or {} in it's place:
        $rv = $dbh->do($statement, undef, @bind_values); $rv = $dbh->do($statement, {}, @bind_values);
        So, then what is \%attr used for? Well, search for that string in the docs and you will be lead to:
           Notation and Conventions
        
           The following conventions are used in this document:
              $dbh    Database handle object
              $sth    Statement handle object
        
              ... yadda yadda ...
        
              undef   NULL values are represented by undefined values in Perl
              \%attr  Reference to a hash of attribute values passed to methods
        
        Do a little more research first, then ask us. :)

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
Re: DBI prepare() vs do() usage
by liz (Monsignor) on Dec 21, 2003 at 14:11 UTC
    In this example, method 1, for one reason. Suppose the following assignment is made to $nick:
    $nick = "'something'; DELETE FROM existingtablename";
    and execute using method 2.

    Always make sure that the values you insert are quoted properly. Method 2 doesn't ensure that and therefore creates an SQL injection vulnerability.

    Of course, if you can be sure that $nick contains what you expect, you can always directly quote the value in the SQL expression, or use the $dbh->quote() method.

    Liz

      Liz,

      Actually I was concerned about this exact issue recently after reading an article on SQL injection tricks. I did some research and found that DBI (by default) does not support multiple SQL statements in a single statement. This can be overridden by the DBI driver though. Here is a quote from the DBI documentation:

      (In the "General Interface Rules & Caveats" section on this page)
      Multiple SQL statements may not be combined in a single statement handle ($sth), although some databases and drivers do support this (notably Sybase and SQL Server).

      Of course this is not excuse for not being a good paranoid programmer, but its nice to know anyway.

      -stvn
Re: DBI prepare() vs do() usage
by CountZero (Bishop) on Dec 21, 2003 at 14:09 UTC
    I would say the first one, but with a caveat: not all Database engines/drivers support "prepare". I don't mean it gives an error if you use it, simply it doesn't do anything with it and just waits for the "execute" to start looking at it.

    I always tend to use the "prepare" method if only because the parameters passing automatically takes care of all quoting issues (so I almost never use qq{  }).

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: DBI prepare() vs do() usage
by bradcathey (Prior) on Dec 21, 2003 at 14:34 UTC
    kiat, the main advantage of prepare over do is most apparent when executing multiple queries. Quoting from the DBI doc:
    The do() method can be used for non repeated non-SELECT statement (or with drivers that don't support placeholders).

    I have used both, but find prepare more versatile, especially when using placeholders. And because I want to be as consistent as possible in my coding style, I just stick to prepare for DBI queries. I'll be curious to see how other more XP'd monks reply--always educational.

    Check out Paul Dubois's book MySQL and Perl for the Web as he does discuss this topic a bit (I'd quote it, but it's at the office).

    Update:
    Okay, I stopped by the office, and with apologies to Dubois and New Riders, here's the take on do vs prepare:
    • you do have to use the undef as an argument when using placeholders (see jeffa's node above)
    prepare, because of it's reusable query plan, works best when inserting data into a table via a loop
    • also because of it's reusable query, prepare can give a performance boost
    • use of prepare makes transporting code to other databases easier and more efficient.

    But buy the book for all the details--it's invaluable--the title tells it all.

    —Brad
    "A little yeast leavens the whole dough."
Re: DBI prepare() vs do() usage
by jZed (Prior) on Dec 21, 2003 at 23:33 UTC
    do() just runs prepare() and execute() under the hood, it's only syntactic sugar on top of them. So a single do() performs exactly the same actions as a single prepre()+execute() combo. The reason it's usually bad for loops is that it does prepare()+execute() each time through the loop when what you usually want is one prepare() at the top and multiple execute()s inside the loop.

    The other difference is what's returned. For example if you want to know the names of the columns, you need to use prepare() to get an $sth to use with $sth->{NAME}.

    As others have said, do() supports placeholders, so that isn't a reason to avoid it.

Re: DBI prepare() vs do() usage
by perlygapes (Sexton) on Aug 01, 2020 at 01:02 UTC
    I came across this thread because I am looking for an answer to a problem I am having with the following code:

    # update using the dbh handle my ($query, @bind) = $sqla->update( 'mytable', { field2 => $field2_new2 }, { field2 => $field2_new1 }, ); $dbh->do($query, undef, @bind);

    Everytime I try to debug this in eclipse EPIC it keeps throwing this error:
    Can't call method "do" on an undefined value at C:/Users/user/eclipse- +workspace/myproject/example.pl line 73, <__ANONIO__> line 3.

    Given the use of undef is supposedly required, does anyone have any idea as to why I see this error?

    Grats
      please check if $dbh is defined .

      And it's unfortunate you replied to an mostly unrelated thread.

      New questions should start new threads.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://316183]
Approved by Thelonius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2024-04-26 00:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found