See http://www.php.net/manual/en/pdo.prepare.php
Note:
Emulated prepared statements does not communicate with the database
server so PDO::prepare() does not check the statement.
(in fact real prepared statements are not sent immediately anyway, see answer to Q2 below)
Anyway you may issue:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
to get real prepared statements implemented with the SQL PREPARE command.
See http://www.php.net/manual/en/pdo.setattribute.php for more.
On further discussion and tests, two questions arise:
Q1. Why does pdo::getAttribute(PDO::ATTR_EMULATE_PREPARES)
yield an error?
Indeed setAttribute
doesn't error out but getAttribute(PDO::ATTR_EMULATE_PREPARES)
says:
'SQLSTATE[IM001]: Driver does not support this function: driver does
not support that attribute'
Looking at the documentation for pdo::getAttribute, it says The constants that apply to database connections are as follows, and a number of constants follow from PDO::ATTR_AUTOCOMMIT
to PDO::ATTR_TIMEOUT
, and it's remarkable that PDO::ATTR_EMULATE_PREPARES
is not in them. So strictly speaking, we should not expect getAttribute(PDO::ATTR_EMULATE_PREPARES)
to work, anyway.
Now looking at the source code to be sure, it appears that the pdo_pgsql
driver provides a pdo_pgsql_get_attribute
function that has a switch statement on:
- PDO_ATTR_CLIENT_VERSION
- PDO_ATTR_SERVER_VERSION
- PDO_ATTR_CONNECTION_STATUS
- PDO_ATTR_SERVER_INFO
and that's it. No trace of PDO_ATTR_EMULATE_PREPARES which is why ultimately this error appears.
On the other hand, the function pdo_pgsql_set_attr
has a switch statement on:
- PDO_ATTR_EMULATE_PREPARES
- PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT
which confirms that this attribute is actually taken into account when set.
So PDO is just inconsistent with getAttribute
that doesn't match setAttribute
.
Q2 - When prepare emulation is false, why doesn't a bogus statement immediately raise an error when prepared?
Consider this piece of code in pgsql_statement.c
:
if (!S->is_prepared) {
stmt_retry:
/* we deferred the prepare until now, because we didn't
* know anything about the parameter types; now we do */
S->result = PQprepare(H->server, S->stmt_name, S->query,
stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0,
S->param_types);
It shows that PQprepare
is used (so that's a "real" prepared statement), but also that the statement is not immediately sent to the server. That's why the dbo::prepare("bogus statement")
won't return false: it's actually not sent to the server for lack of parameter types.