4

Often when using PDO I want to prepare a statement and then execute it only once. I do it this way so that I can be sure all my parameters are properly escaped.

As I understand it, by preparing a statement and then executing it you're sending 2 requests to the MySQL server, so this would actually be slower than manually escaping the parameters and sending one request via PDO::query.

Is there no way to send the parameterized query plus the parameter values in one swoop?


I wrote a little test,

$t = new WxTimer();
for($i=0; $i<1000; ++$i) {
    $db->prepare("SELECT user_id, $i FROM wx_user WHERE user_id=?")->execute($i)->fetch();
}
echo $t->elapsed().PHP_EOL;

and ran it with both ATTR_EMULATE_PREPARES on and off. With ATTR_EMULATE_PREPARES set to true (which does appear to be the default), it runs about twice as fast (295ms vs 639ms).

Curiously, this statement,

$db->query("SELECT user_id, $i FROM wx_user WHERE user_id=".$db->quote($i))->fetch();

Runs in about 633ms with emulate on, or 301ms with emulate off, despite not appearing to use prepared statements.

(If you're wondering about the syntax, I overrode a few methods in the PDO class)

mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • I'm sure you can run a prepared statement without parameter. That's not sure it would solve anything to send them at once, preparing probably does more than just processing the params. But I can't find proper support to backup my thoughts... – Sebas Jun 16 '13 at 19:48
  • 1
    When dealing with MySQL in PDO, you're not sending two queries unless you've set `PDO::ATTR_EMULATE_PREPARES` mode on - and it's turned off by default. Check [this docpage](http://php.net/manual/en/pdo.prepare.php) (and [this comment in particular](http://www.php.net/manual/en/pdo.prepare.php#107811)) for details – raina77ow Jun 16 '13 at 19:48
  • [How prepared statements can protect from SQL injection attacks?](http://stackoverflow.com/a/8265319/285587) – Your Common Sense Jun 16 '13 at 19:55
  • 1
    With all due respect, I'd rather refer the OP to [this question](http://stackoverflow.com/questions/535464/when-not-to-use-prepared-statements). ) – raina77ow Jun 16 '13 at 19:56
  • 1
    It doesn't send "two queries". It sends one query and an array of values, over the same open connection. "Sending one query" commonly implies a lot of overhead in MySQL, but that's not the same as *sending a prepared statement and its parameters according to protocol over an open database connection*. Yes, there may be a *little* overhead, but can you even measure the difference? – deceze Jun 16 '13 at 21:04
  • @deceze: I wrote "2 requests" not "two queries" -- not sure why you're trying to disagree with me on that point. Connection might still be open, but there must be some latency overhead involved, particularly if the MySQL server is physically located far from the web server. – mpen Jun 17 '13 at 00:12
  • @raina77ow: Don't you have that backwards? If that's `true`, then the parameters will be escaped by the driver and sent to MySQL as one request (statement w/ data). I wish I could validate your claim by it being "off" by default (which would mean it's using native prepared statements, i.e., two requests). However, when I try `$pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES)` I get "Driver does not support this function: driver does not support that attribute", even though if I call `setAttribute` on it, I get no such exception. Does this mean *emulation* is not supported? – mpen Jun 17 '13 at 00:20
  • 1
    @Mark Argh, but of course. ) It's the other way around: by default pdo-mysql emulates prepared queries, but one can turn this emulation off. – raina77ow Jun 17 '13 at 06:10

2 Answers2

1

This depends on the setting of PDO::ATTR_EMULATE_PREPARES,

If you use emulation of prepared statements, then the pdo will emulate the prepared statement for you, the escape process will be done with in the pdo. So this will send only one request to the database.

xdazz
  • 158,678
  • 38
  • 247
  • 274
  • `$pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES)` throws an exception "Driver does not support this function: driver does not support that attribute". Does that mean it's on or off? – mpen Jun 17 '13 at 01:24
  • 1
    @Mark neither. It's just a bug with getattribute. You don't need to get it though. Just set and go – Your Common Sense Jun 17 '13 at 04:36
  • I guess this is the route to go. I'm curious how it handles binary data though. In the past I've bin2hex'd my data and slapped a `0x` in front to avoid sending any weird characters through an SQL query, but that substantially bloats your data. With real prepared queries I'd imagine it could send the data pretty much as-is (no bloat); not sure what emulation does to escape it. In particular, I've noticed a substantial slow down once my queries reach the 1500 byte mark; query times jump from 1 to 100ms, so I think this is a legitimate concern. – mpen Jun 17 '13 at 07:23
-1

look here: http://php.net/manual/en/pdo.quote.php

example:

$pdo = new PDO ("mysql:host=$hostname;dbname=$dbname","$username","$pw");
$str = "gh'gh";
$str = $pdo->quote($str);
$pdo->query ("UPDATE table SET field=$str")

I asume it's what you want.

for:

$str = "gh'gh";
echo $pdo->quote($str);

the output will be:

'gh\'gh'
Dani-Br
  • 2,289
  • 5
  • 25
  • 32
  • I'm aware of `PDO::quote`. I was more interested in knowing if I could send the query and data as one packet and let MySQL handle it. – mpen Jun 17 '13 at 01:23
  • of course not. you should enclose the data to protect the query\command that been sent to MySQL. – Dani-Br Jun 17 '13 at 02:17
  • still, my solution is more quick then prepare and execute the statement. probably the quickest way to do that using PDO. – Dani-Br Jun 17 '13 at 02:20
  • Not if `PDO::ATTR_EMULATE_PREPARES` behaves how I think it does. It would essentially be doing this exact same thing, except you don't have to quote each parameter yourself, and it's implemented in C (AFAIK). – mpen Jun 17 '13 at 07:15