6

Given something like

DB()->prepare("SELECT * FROM mysql.general_log WHERE user_host LIKE ?");

$statement->execute( array('%console%') );

foreach($statement as $record){
    var_dump($record);
}

Contents of general_log is

*************************** 1. row ***************************
event_time: 2011-04-20 14:27:59
user_host: REDACTED[REDACTED] @ REDACTED [192.168.56.101]
thread_id: 30
server_id: 0
command_type: Connect
argument: REDACTED@REDACTED on REDACTED
*************************** 2. row ***************************
event_time: 2011-04-20 14:27:59
user_host: REDACTED[REDACTED] @ REDACTED [192.168.56.101]
thread_id: 30
server_id: 0
command_type: Query
argument: SELECT * FROM mysql.general_log WHERE user_host LIKE '%console%'

I'm working inside of an abomination framework ( no unit-tests, no documentation, no ryhme or reason ) so is it possible that somewhere someone explicitly disabled MySQL prepared statements forcing PDO to use emulated mode... or is this expected behavior?

PHP is PHP Version 5.2.10-2ubuntu6 PDO Driver for MySQL, client library version 5.1.41

Update: PDO() is constructed with the the following attributes

PDO::ATTR_PERSISTENT => false
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true

I went through the PDO documentation, but unfortunately there doesn't seem to be mention of a flag like the one written about in this similar question

Community
  • 1
  • 1
David
  • 17,673
  • 10
  • 68
  • 97
  • Maybe I missed something, but you seem to have forgotten to tell us what is actually going wrong. If you're worried about emulation mode, check `PDO::ATTR_EMULATE_PREPARES` -- it's well-hidden. – Charles Apr 21 '11 at 22:46
  • 1
    My apologies, the issue is that PDO is not actually calling MySQL and preparing the statement, it seems to be automatically using emulation mode. I've confirmed this both by watching the general_log for my dev server and by tracing communication via WireShark. – David Apr 22 '11 at 01:26
  • @Charles if you want some points, add the PDO::ATR_EMULATE_PREPARES as the solution. Set that to false and now it's using MySQL/server side prepares over the emulation layer. – David Apr 22 '11 at 02:30
  • breaking out Wireshark is hardcore research, well-done! I've posted the attribute as an answer, and added some important notes that might make you reconsider turning emulation off under certain specific conditions. – Charles Apr 22 '11 at 03:03
  • @Charles, strace and Wireshark are very good friends of mine... they come in handy in the weirdest of cases, plus I wanted to make absolutely certain MySQL wasn't being instructed to prepare the statements. – David Apr 22 '11 at 03:33

2 Answers2

12

Some PDO drivers don't support native prepared statements, so PDO performs emulation of the prepare. It also lets you manually enable this emulation.

Check the PDO::ATTR_EMULATE_PREPARES attribute. It's poorly documented in the current PDO manual. By poorly documented, I mean that it appears only in comments on the site, not in the manual itself.

Generally you want to use native prepared statements whenever possible. In the case of MySQL, if you are taking advantage of the query cache, you might actually want to disable native prepared statements in PDO! The MySQL manual has more information, but the short version is that versions prior to 5.1.17 don't run prepared statements through the query cache, and subsequent versions only use the query cache under certain specific (but common) conditions.

(Some people recommend turning off the query cache entirely. Using large cache sizes can actually be a major performance hit.)

Charles
  • 50,943
  • 13
  • 104
  • 142
  • Glad you added that last line, when I put on my DBA hat, first thing I do is disable Query Cache. Usually there are better places to throw RAM. – David Apr 22 '11 at 03:31
  • By the way. Query caching is gone anyway: The query cache is deprecated as of MySQL 5.7.20, and is removed in MySQL 8.0. https://dev.mysql.com/doc/refman/5.7/en/query-cache.html – mikep Jan 07 '19 at 18:54
5

By default, PDO_MYSQL emulates the prepared statements. To use the native server-side prepared statements, one should explicitely set

$PDO->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);