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

I am new to DBI and MySQL in general. I am trying to take this hash and stores the keys in a MySQL database using DBI.
$VAR14 = { 'image_medium' => 'http://ecx.images-amazon.com/images/I/51 +p2cN2yIML._SL160_.jpg', 'authors' => 'Tony Stubblebine', 'publication_date' => '2007-07-18', 'title' => 'Regular Expression Pocket Reference: Regular Ex +pressions for Perl, Ruby, PHP, Python, C, Java and .NET (Pocket Refer +ence (O\'Reilly))', 'isbn' => '0596514271', 'publisher' => 'O\'Reilly Media, Inc.', 'image_small' => 'http://ecx.images-amazon.com/images/I/51p +2cN2yIML._SL75_.jpg', 'url_amazon' => 'http://www.amazon.com/Regular-Expression-P +ocket-Reference-Expressions/dp/0596514271%3FSubscriptionId%3D1VD4TGW1 +VSXT1RE5Y2G2%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D1 +65953%26creativeASIN%3D0596514271', 'pages' => '126' };
When I try to add strings with quotes, I receive SQL syntax errors (i.e. the "Publisher" key and keys with "O'Reilly"). What is the best way to handle quotes in this scenario? This is how I am doing the insert
$insert = "INSERT into books ( id, title, authors, isbn, pages, publisher, publication_date, image_small, image_medium, url_amazon, createdAt) VALUES ( NULL, '" . $hash{$key}{'title'} . "', '" . $hash{$key}{'authors'} . "', '" . $hash{$key}{'isbn'} . "', '" . $hash{$key}{'pages'} . "', '" . $hash{$key}{'publisher'} . "', '" . $hash{$key}{'publication_date'} . "', + '" . $hash{$key}{'image_small'} . "', '" . $hash{$key}{'image_medium'} . "', '" . $hash{$key}{'url_amazon'} . "', NULL)"; $sth = $dbh->prepare($insert);
Thanks!

Replies are listed 'Best First'.
Re: Best way to deal with quotes in string with DBI
by psini (Deacon) on Jul 27, 2008 at 13:28 UTC

    Using placeholders. See this tutorial

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

Re: Best way to deal with quotes in string with DBI
by bradcathey (Prior) on Jul 27, 2008 at 15:02 UTC

    Indeed, psini is correct—placeholders should be your new best friend. Not only will they solve your quoting woes, more importantly they will provide a secure method of writing to a database, preventing such things as injection attacks.

    However, it might be good to see an example of how you can more concisely deal with a hash of data that you want to write to the database using DBI. This clever piece of code (that I borrowed from someone in the Monastery years ago) builds your query using the keys and values of your hash of data. Note the ? placeholders.

    my $stmt = qq/INSERT INTO books ( / . join(',', keys %hash) . qq/) VALUES (/ . join(',', ('?') x keys %hash) . qq/)/; my $sth = $dbh->prepare($stmt); $sth->execute(values %hash);

    Here's a simplified example (I use CGI::Application in my own work) of an entire subroutine I place in a common module

    sub write_to_db { my $table = shift; #pass in table name my $hash = shift; #pass in hash ref to data my ($stmt, $sth); #subroutine to connect to db my $dbh = dbconnect(server =>'master', db => 'member'); my %hash = %{ $hash }; #deref data if ($query->param('update')) { #set a hidden value in html form if + updating $stmt = qq/UPDATE $table SET updated_on = NOW(), / . join(' = ?, +', keys %hash) . qq/ = ? WHERE id = ?/; $sth = $dbh->prepare($stmt); $sth->execute(values %hash, $query->param('id')); #set a hidden +value } else { my $stmt = qq/INSERT INTO $table (created_on, / . join(',', keys + %hash) . qq/) VALUES (NOW(),/ . join(',', ('?') x keys %hash) . qq +/)/; my $sth = $dbh->prepare($stmt); $sth->execute(values %hash); } }

    <shameless plug> you should take a look at this short tutorial for CGI::Application. CGI::App is a great habit to get into, and will simplify your life, or coding</shameless plug>

      Keep in mind in this case that you cannot delete nor add any keys into the hash between the keys %hash and values %hash! If you can't guarantee that you'd rather do something like:

      my @keys = keys %hash; my $stmt = qq/INSERT INTO books ( / . join(',', @keys) . qq/) VALUES (/ . join(',', ('?') x @keys) . qq/)/; my $sth = $dbh->prepare($stmt); #... $sth->execute(@hash{@keys});
Re: Best way to deal with quotes in string with DBI
by Your Mother (Archbishop) on Jul 27, 2008 at 18:26 UTC

    Or maybe-

    use SQL::Abstract; my $sql = SQL::Abstract->new; my $book_data = {}; # your data from above my ( $stmt, @bind ) = $sql->insert("books", $book_data); print $stmt, "\n\n"; print join(" : ", @bind), "\n"; my $sth = $dbh->prepare($stmt); my $rv = $sth->execute(@bind); die "FAIL! DBI, ur doin it rong!" unless $rv == 1;

    SQL::Abstract is really quite nice and will save you from all kinds of weird contortions if you try to roll your own version.

    (Sidenote: unless something has changed in the Amazon dev agreement in the last couple years, it's against their TOS to save the data on your side in any persistent way.)

Re: Best way to deal with quotes in string with DBI
by ruzam (Curate) on Jul 28, 2008 at 00:30 UTC
    VALUES ( NULL, " . $dbh->quote($hash{$key}{'title'}) . ", " . $dbh->quote($hash{$key}{'authors'}) . ", " . $dbh->quote($hash{$key}{'isbn'}) . ", " . $dbh->quote($hash{$key}{'pages'}) . ", " . $dbh->quote($hash{$key}{'publisher'}) . ", " . $dbh->quote($hash{$key}{'publication_date'}) . ", " . $dbh->quote($hash{$key}{'image_small'}) . ", " . $dbh->quote($hash{$key}{'image_medium'}) . ", " . $dbh->quote($hash{$key}{'url_amazon'}) . ", NULL)";
      that code is pretty ugly and unnecessarily complicated. You can use placeholders as suggested before...
        It's not how I would write it, but the OP was having problems with quoting strings.

        It's no more complicated than the original code, and solves the quoting issues using the preferred DBI quoting interface. Placeholders aren't the one and only method of handling quoting issues and it's not my place to tell the OP how to code.