Here, the query that is constructed through interpolation has a syntax error. (Don't see it? Look again.)$name = "O'Reilly"; $sth = $db->prepare("SELECT * FROM emp WHERE name = '$name'"); $sth->execute();
Again, using bind variables:
Here, $name is correctly escaped by the appropriate quote() method supplied by the DBD in use, and everyone is happy.$name = "O'Reilly"; $sth = $db->prepare("SELECT * FROM emp WHERE name = ?"); $sth->execute($name);
Query preparation separate from execution allows the database to plan out execution of the query, and save the plan for reuse by multiple executions. This can be a big win, but some databases don't support it. For those that don't, DBI pretends that they do, remembers the query, and when execute() is invoked, constructs the query (from correctly quoted bind variables), and ships it to the database for execution. This pretending is actually a good thing. It allows you to write portable code that will work regardless of whether the underlying RDBMS supports separate query preparation. Oracle supports separate query preparation. Sybase, MS SQL (through 7.0, at least), and MySQL (as of now) do not.
The Pitfall
The lurking horror in this scheme is that DBI doesn't actually parse queries. If you're using a database that doesn't support separate preparation and you hand DBI a query with bind parameters in the wrong places, it will dutifully hold on to it, fill in the pieces when you pass arguments to execute(), and everything will appear to work. Until you try to support a different database. Then, KaBOOM. If you're developing against MySQL with the intent of eventually supporting Oracle, then watch out.
You can only reliably bind values, not field or table names.
Database that plan query execution won't accept this, because they need table and field names to make their query execution plans. Without knowing table and field names, how can the database construct a plan that calls for using indexes that might be available? (Answer: It can't.)
Where people screw themselves with query binding is in trying to do something like this:
This will work with several database, but only by an accidental side-effect of implementation. Move to Oracle, and KaBOOM. I've seen several code fragments like this in production code, and occassionally in PM posts.my $field = $old ? "olddata" : "newdata"; $sth = $db->prepare("SELECT * FROM ?"); $sth->execute($field);
If you want your code to survive migration to a new database, bind values in your queries, not field or table names.
In reply to A DBI Query Binding Pitfall by dws
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |